diff options
Diffstat (limited to 'drivers/staging/rtl8192ee')
64 files changed, 50425 insertions, 0 deletions
diff --git a/drivers/staging/rtl8192ee/Kconfig b/drivers/staging/rtl8192ee/Kconfig new file mode 100644 index 00000000000..beb07ac24e8 --- /dev/null +++ b/drivers/staging/rtl8192ee/Kconfig @@ -0,0 +1,15 @@ +config R8192EE +	tristate "Realtek RTL8192EE Wireless Network Adapter" +	depends on PCI && WLAN && MAC80211 +	depends on m +	select WIRELESS_EXT +	select WEXT_PRIV +	select EEPROM_93CX6 +	select CRYPTO +	select FW_LOADER +	default N +	---help--- +	This is the driver for Realtek RTL8192EE 802.11 PCIe +	wireless network adapters. + +	If you choose to build it as a module, it will be called r8192ee diff --git a/drivers/staging/rtl8192ee/Makefile b/drivers/staging/rtl8192ee/Makefile new file mode 100644 index 00000000000..31708620d7e --- /dev/null +++ b/drivers/staging/rtl8192ee/Makefile @@ -0,0 +1,40 @@ + +PCI_MAIN_OBJS	:= base.o	\ +		cam.o	\ +		core.o	\ +		debug.o	\ +		efuse.o	\ +		pci.o	\ +		ps.o	\ +		rc.o	\ +		regd.o	\ +		stats.o + +PCI_8192EE_HAL_OBJS:=		\ +	rtl8192ee/dm.o		\ +	rtl8192ee/fw.o		\ +	rtl8192ee/hw.o		\ +	rtl8192ee/led.o		\ +	rtl8192ee/phy.o		\ +	rtl8192ee/pwrseq.o	\ +	rtl8192ee/pwrseqcmd.o	\ +	rtl8192ee/rf.o		\ +	rtl8192ee/sw.o		\ +	rtl8192ee/table.o	\ +	rtl8192ee/trx.o + + + +BT_COEXIST_OBJS:=	btcoexist/halbtc8192e2ant.o\ +			btcoexist/halbtc8723b1ant.o\ +			btcoexist/halbtc8723b2ant.o\ +			btcoexist/halbtc8821a1ant.o\ +			btcoexist/halbtc8821a2ant.o\ +			btcoexist/halbtcoutsrc.o\ +			btcoexist/rtl_btc.o + +r8192ee-objs += $(PCI_MAIN_OBJS) $(PCI_8192EE_HAL_OBJS) $(BT_COEXIST_OBJS) + +obj-$(CONFIG_R8192EE) += r8192ee.o + +ccflags-y += -D__CHECK_ENDIAN__ diff --git a/drivers/staging/rtl8192ee/TODO b/drivers/staging/rtl8192ee/TODO new file mode 100644 index 00000000000..162092a0316 --- /dev/null +++ b/drivers/staging/rtl8192ee/TODO @@ -0,0 +1,12 @@ +TODO: +- convert any remaining unusual variable types +- find codes that can use %pM and %Nph formatting +- checkpatch.pl fixes - most of the remaining ones are lines too long. Many +  of them will require refactoring +- merge Realtek's bugfixes and new features into the driver +- Convert the versions of rtlwifi and btcoexist in drivers/net/wireless/rtlwifi/... +  to work with the RTL8192EE +- move this driver to drivers/net/wireless/rtlwifi + +Please send any patches to Greg Kroah-Hartman <gregkh@linux.com>, +and Larry Finger <Larry.Finger@lwfinger.net>. diff --git a/drivers/staging/rtl8192ee/base.c b/drivers/staging/rtl8192ee/base.c new file mode 100644 index 00000000000..64ade216a15 --- /dev/null +++ b/drivers/staging/rtl8192ee/base.c @@ -0,0 +1,1852 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010  Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#include <linux/ip.h> +#include <linux/module.h> +#include "wifi.h" +#include "rc.h" +#include "base.h" +#include "efuse.h" +#include "cam.h" +#include "ps.h" +#include "regd.h" +#include "pci.h" + +/* + *NOTICE!!!: This file will be very big, we hsould + *keep it clear under follwing roles: + * + *This file include follwing part, so, if you add new + *functions into this file, please check which part it + *should includes. or check if you should add new part + *for this file: + * + *1) mac80211 init functions + *2) tx information functions + *3) functions called by core.c + *4) wq & timer callback functions + *5) frame process functions + *6) IOT functions + *7) sysfs functions + *8) vif functions + *9) ... + */ + +/********************************************************* + * + * mac80211 init functions + * + *********************************************************/ +static struct ieee80211_channel rtl_channeltable_2g[] = { +	{.center_freq = 2412, .hw_value = 1,}, +	{.center_freq = 2417, .hw_value = 2,}, +	{.center_freq = 2422, .hw_value = 3,}, +	{.center_freq = 2427, .hw_value = 4,}, +	{.center_freq = 2432, .hw_value = 5,}, +	{.center_freq = 2437, .hw_value = 6,}, +	{.center_freq = 2442, .hw_value = 7,}, +	{.center_freq = 2447, .hw_value = 8,}, +	{.center_freq = 2452, .hw_value = 9,}, +	{.center_freq = 2457, .hw_value = 10,}, +	{.center_freq = 2462, .hw_value = 11,}, +	{.center_freq = 2467, .hw_value = 12,}, +	{.center_freq = 2472, .hw_value = 13,}, +	{.center_freq = 2484, .hw_value = 14,}, +}; + +static struct ieee80211_channel rtl_channeltable_5g[] = { +	{.center_freq = 5180, .hw_value = 36,}, +	{.center_freq = 5200, .hw_value = 40,}, +	{.center_freq = 5220, .hw_value = 44,}, +	{.center_freq = 5240, .hw_value = 48,}, +	{.center_freq = 5260, .hw_value = 52,}, +	{.center_freq = 5280, .hw_value = 56,}, +	{.center_freq = 5300, .hw_value = 60,}, +	{.center_freq = 5320, .hw_value = 64,}, +	{.center_freq = 5500, .hw_value = 100,}, +	{.center_freq = 5520, .hw_value = 104,}, +	{.center_freq = 5540, .hw_value = 108,}, +	{.center_freq = 5560, .hw_value = 112,}, +	{.center_freq = 5580, .hw_value = 116,}, +	{.center_freq = 5600, .hw_value = 120,}, +	{.center_freq = 5620, .hw_value = 124,}, +	{.center_freq = 5640, .hw_value = 128,}, +	{.center_freq = 5660, .hw_value = 132,}, +	{.center_freq = 5680, .hw_value = 136,}, +	{.center_freq = 5700, .hw_value = 140,}, +	{.center_freq = 5745, .hw_value = 149,}, +	{.center_freq = 5765, .hw_value = 153,}, +	{.center_freq = 5785, .hw_value = 157,}, +	{.center_freq = 5805, .hw_value = 161,}, +	{.center_freq = 5825, .hw_value = 165,}, +}; + +static struct ieee80211_rate rtl_ratetable_2g[] = { +	{.bitrate = 10, .hw_value = 0x00,}, +	{.bitrate = 20, .hw_value = 0x01,}, +	{.bitrate = 55, .hw_value = 0x02,}, +	{.bitrate = 110, .hw_value = 0x03,}, +	{.bitrate = 60, .hw_value = 0x04,}, +	{.bitrate = 90, .hw_value = 0x05,}, +	{.bitrate = 120, .hw_value = 0x06,}, +	{.bitrate = 180, .hw_value = 0x07,}, +	{.bitrate = 240, .hw_value = 0x08,}, +	{.bitrate = 360, .hw_value = 0x09,}, +	{.bitrate = 480, .hw_value = 0x0a,}, +	{.bitrate = 540, .hw_value = 0x0b,}, +}; + +static struct ieee80211_rate rtl_ratetable_5g[] = { +	{.bitrate = 60, .hw_value = 0x04,}, +	{.bitrate = 90, .hw_value = 0x05,}, +	{.bitrate = 120, .hw_value = 0x06,}, +	{.bitrate = 180, .hw_value = 0x07,}, +	{.bitrate = 240, .hw_value = 0x08,}, +	{.bitrate = 360, .hw_value = 0x09,}, +	{.bitrate = 480, .hw_value = 0x0a,}, +	{.bitrate = 540, .hw_value = 0x0b,}, +}; + +static const struct ieee80211_supported_band rtl_band_2ghz = { +	.band = IEEE80211_BAND_2GHZ, + +	.channels = rtl_channeltable_2g, +	.n_channels = ARRAY_SIZE(rtl_channeltable_2g), + +	.bitrates = rtl_ratetable_2g, +	.n_bitrates = ARRAY_SIZE(rtl_ratetable_2g), + +	.ht_cap = {0}, +}; + +static struct ieee80211_supported_band rtl_band_5ghz = { +	.band = IEEE80211_BAND_5GHZ, + +	.channels = rtl_channeltable_5g, +	.n_channels = ARRAY_SIZE(rtl_channeltable_5g), + +	.bitrates = rtl_ratetable_5g, +	.n_bitrates = ARRAY_SIZE(rtl_ratetable_5g), + +	.ht_cap = {0}, +}; + +static const u8 tid_to_ac[] = { +	2, /* IEEE80211_AC_BE */ +	3, /* IEEE80211_AC_BK */ +	3, /* IEEE80211_AC_BK */ +	2, /* IEEE80211_AC_BE */ +	1, /* IEEE80211_AC_VI */ +	1, /* IEEE80211_AC_VI */ +	0, /* IEEE80211_AC_VO */ +	0, /* IEEE80211_AC_VO */ +}; + +u8 rtl92e_tid_to_ac(struct ieee80211_hw *hw, u8 tid) +{ +	return tid_to_ac[tid]; +} + +static void _rtl_init_hw_ht_capab(struct ieee80211_hw *hw, +				  struct ieee80211_sta_ht_cap *ht_cap) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); + +	ht_cap->ht_supported = true; +	ht_cap->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 | +	    IEEE80211_HT_CAP_SGI_40 | +	    IEEE80211_HT_CAP_SGI_20 | +	    IEEE80211_HT_CAP_DSSSCCK40 | IEEE80211_HT_CAP_MAX_AMSDU; + +	if (rtlpriv->rtlhal.disable_amsdu_8k) +		ht_cap->cap &= ~IEEE80211_HT_CAP_MAX_AMSDU; + +	/* +	 *Maximum length of AMPDU that the STA can receive. +	 *Length = 2 ^ (13 + max_ampdu_length_exp) - 1 (octets) +	 */ +	ht_cap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; + +	/*Minimum MPDU start spacing , */ +	ht_cap->ampdu_density = IEEE80211_HT_MPDU_DENSITY_16; + +	ht_cap->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; + +	/* +	 *hw->wiphy->bands[IEEE80211_BAND_2GHZ] +	 *base on ant_num +	 *rx_mask: RX mask +	 *if rx_ant =1 rx_mask[0]=0xff;==>MCS0-MCS7 +	 *if rx_ant =2 rx_mask[1]=0xff;==>MCS8-MCS15 +	 *if rx_ant >=3 rx_mask[2]=0xff; +	 *if BW_40 rx_mask[4]=0x01; +	 *highest supported RX rate +	 */ +	if (rtlpriv->dm.supp_phymode_switch) { +		RT_TRACE(COMP_INIT, DBG_EMERG, ("Support phy mode switch\n")); + +		ht_cap->mcs.rx_mask[0] = 0xFF; +		ht_cap->mcs.rx_mask[1] = 0xFF; +		ht_cap->mcs.rx_mask[4] = 0x01; + +		ht_cap->mcs.rx_highest = cpu_to_le16(MAX_BIT_RATE_40MHZ_MCS15); +	} else { +		if (get_rf_type(rtlphy) == RF_1T2R || +		    get_rf_type(rtlphy) == RF_2T2R) { +			RT_TRACE(COMP_INIT, DBG_DMESG, ("1T2R or 2T2R\n")); + +			ht_cap->mcs.rx_mask[0] = 0xFF; +			ht_cap->mcs.rx_mask[1] = 0xFF; +			ht_cap->mcs.rx_mask[4] = 0x01; + +			ht_cap->mcs.rx_highest = cpu_to_le16(MAX_BIT_RATE_40MHZ_MCS15); +		} else if (get_rf_type(rtlphy) == RF_1T1R) { +			RT_TRACE(COMP_INIT, DBG_DMESG, ("1T1R\n")); + +			ht_cap->mcs.rx_mask[0] = 0xFF; +			ht_cap->mcs.rx_mask[1] = 0x00; +			ht_cap->mcs.rx_mask[4] = 0x01; + +			ht_cap->mcs.rx_highest = cpu_to_le16(MAX_BIT_RATE_40MHZ_MCS7); +		} +	} +} + +static void _rtl_init_hw_vht_capab(struct ieee80211_hw *hw, +				   struct ieee80211_sta_vht_cap *vht_cap) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + +	if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) { +		u16 mcs_map; +		vht_cap->vht_supported = true; +		vht_cap->cap = +			IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895 | +			IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991 | +			IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 | +			IEEE80211_VHT_CAP_SHORT_GI_80 | +			IEEE80211_VHT_CAP_TXSTBC | +			IEEE80211_VHT_CAP_RXSTBC_1 | +			IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE | +			IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE | +			IEEE80211_VHT_CAP_HTC_VHT | +			IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK | +			IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN | +			IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN | +			0; + +		mcs_map = IEEE80211_VHT_MCS_SUPPORT_0_9 << 0 | +			IEEE80211_VHT_MCS_SUPPORT_0_9 << 2 | +			IEEE80211_VHT_MCS_NOT_SUPPORTED << 4 | +			IEEE80211_VHT_MCS_NOT_SUPPORTED << 6 | +			IEEE80211_VHT_MCS_NOT_SUPPORTED << 8 | +			IEEE80211_VHT_MCS_NOT_SUPPORTED << 10 | +			IEEE80211_VHT_MCS_NOT_SUPPORTED << 12 | +			IEEE80211_VHT_MCS_NOT_SUPPORTED << 14; + +		vht_cap->vht_mcs.rx_mcs_map = cpu_to_le16(mcs_map); +		vht_cap->vht_mcs.rx_highest = +			cpu_to_le16(MAX_BIT_RATE_SHORT_GI_2NSS_80MHZ_MCS9); +		vht_cap->vht_mcs.tx_mcs_map = cpu_to_le16(mcs_map); +		vht_cap->vht_mcs.tx_highest = +			cpu_to_le16(MAX_BIT_RATE_SHORT_GI_2NSS_80MHZ_MCS9); +	} else if (rtlhal->hw_type == HARDWARE_TYPE_RTL8821AE) { +		u16 mcs_map; + +		vht_cap->vht_supported = true; +		vht_cap->cap = +			IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895 | +			IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991 | +			IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 | +			IEEE80211_VHT_CAP_SHORT_GI_80 | +			IEEE80211_VHT_CAP_TXSTBC | +			IEEE80211_VHT_CAP_RXSTBC_1 | +			IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE | +			IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE | +			IEEE80211_VHT_CAP_HTC_VHT | +			IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK | +			IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN | +			IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN | +			0; + +		mcs_map = IEEE80211_VHT_MCS_SUPPORT_0_9 << 0 | +			IEEE80211_VHT_MCS_NOT_SUPPORTED << 2 | +			IEEE80211_VHT_MCS_NOT_SUPPORTED << 4 | +			IEEE80211_VHT_MCS_NOT_SUPPORTED << 6 | +			IEEE80211_VHT_MCS_NOT_SUPPORTED << 8 | +			IEEE80211_VHT_MCS_NOT_SUPPORTED << 10 | +			IEEE80211_VHT_MCS_NOT_SUPPORTED << 12 | +			IEEE80211_VHT_MCS_NOT_SUPPORTED << 14; + +		vht_cap->vht_mcs.rx_mcs_map = cpu_to_le16(mcs_map); +		vht_cap->vht_mcs.rx_highest = +			cpu_to_le16(MAX_BIT_RATE_SHORT_GI_1NSS_80MHZ_MCS9); +		vht_cap->vht_mcs.tx_mcs_map = cpu_to_le16(mcs_map); +		vht_cap->vht_mcs.tx_highest = +			cpu_to_le16(MAX_BIT_RATE_SHORT_GI_1NSS_80MHZ_MCS9); +	} +} + +static void _rtl_init_mac80211(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_hal *rtlhal = rtl_hal(rtlpriv); +	struct rtl_mac *rtlmac = rtl_mac(rtl_priv(hw)); +	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); +	struct ieee80211_supported_band *sband; + + +	if (rtlhal->macphymode == SINGLEMAC_SINGLEPHY && +	    rtlhal->bandset == BAND_ON_BOTH) { +		/* 1: 2.4 G bands */ +		/* <1> use  mac->bands as mem for hw->wiphy->bands */ +		sband = &(rtlmac->bands[IEEE80211_BAND_2GHZ]); + +		/* <2> set hw->wiphy->bands[IEEE80211_BAND_2GHZ] +		 * to default value(1T1R) */ +		memcpy(&(rtlmac->bands[IEEE80211_BAND_2GHZ]), &rtl_band_2ghz, +		       sizeof(struct ieee80211_supported_band)); + +		/* <3> init ht cap base on ant_num */ +		_rtl_init_hw_ht_capab(hw, &sband->ht_cap); + +		/* <4> set mac->sband to wiphy->sband */ +		hw->wiphy->bands[IEEE80211_BAND_2GHZ] = sband; + +		/* 2: 5 G bands */ +		/* <1> use  mac->bands as mem for hw->wiphy->bands */ +		sband = &(rtlmac->bands[IEEE80211_BAND_5GHZ]); + +		/* <2> set hw->wiphy->bands[IEEE80211_BAND_5GHZ] +		 * to default value(1T1R) */ +		memcpy(&(rtlmac->bands[IEEE80211_BAND_5GHZ]), &rtl_band_5ghz, +		       sizeof(struct ieee80211_supported_band)); + +		/* <3> init ht cap base on ant_num */ +		_rtl_init_hw_ht_capab(hw, &sband->ht_cap); + +		_rtl_init_hw_vht_capab(hw, &sband->vht_cap); + +		/* <4> set mac->sband to wiphy->sband */ +		hw->wiphy->bands[IEEE80211_BAND_5GHZ] = sband; +	} else { +		if (rtlhal->current_bandtype == BAND_ON_2_4G) { +			/* <1> use  mac->bands as mem for hw->wiphy->bands */ +			sband = &(rtlmac->bands[IEEE80211_BAND_2GHZ]); + +			/* <2> set hw->wiphy->bands[IEEE80211_BAND_2GHZ] +			 * to default value(1T1R) */ +			memcpy(&(rtlmac->bands[IEEE80211_BAND_2GHZ]), +			       &rtl_band_2ghz, +			       sizeof(struct ieee80211_supported_band)); + +			/* <3> init ht cap base on ant_num */ +			_rtl_init_hw_ht_capab(hw, &sband->ht_cap); + +			/* <4> set mac->sband to wiphy->sband */ +			hw->wiphy->bands[IEEE80211_BAND_2GHZ] = sband; +		} else if (rtlhal->current_bandtype == BAND_ON_5G) { +			/* <1> use  mac->bands as mem for hw->wiphy->bands */ +			sband = &(rtlmac->bands[IEEE80211_BAND_5GHZ]); + +			/* <2> set hw->wiphy->bands[IEEE80211_BAND_5GHZ] +			 * to default value(1T1R) */ +			memcpy(&(rtlmac->bands[IEEE80211_BAND_5GHZ]), +			       &rtl_band_5ghz, +			       sizeof(struct ieee80211_supported_band)); + +			/* <3> init ht cap base on ant_num */ +			_rtl_init_hw_ht_capab(hw, &sband->ht_cap); + +			_rtl_init_hw_vht_capab(hw, &sband->vht_cap); + +			/* <4> set mac->sband to wiphy->sband */ +			hw->wiphy->bands[IEEE80211_BAND_5GHZ] = sband; +		} else { +			RT_TRACE(COMP_INIT, DBG_EMERG, +				 ("Err BAND %d\n", rtlhal->current_bandtype)); +		} +	} +	/* <5> set hw caps */ +	hw->flags = IEEE80211_HW_SIGNAL_DBM | +	    IEEE80211_HW_RX_INCLUDES_FCS | +	    IEEE80211_HW_AMPDU_AGGREGATION | +	    IEEE80211_HW_REPORTS_TX_ACK_STATUS | +	    IEEE80211_HW_CONNECTION_MONITOR | +	    /* IEEE80211_HW_SUPPORTS_CQM_RSSI | */ +	    IEEE80211_HW_MFP_CAPABLE | 0; + +	/* swlps or hwlps has been set in diff chip in init_sw_vars */ +	if (rtlpriv->psc.b_swctrl_lps) +		hw->flags |= IEEE80211_HW_SUPPORTS_PS | +			IEEE80211_HW_PS_NULLFUNC_STACK | +			/* IEEE80211_HW_SUPPORTS_DYNAMIC_PS | */ +			0; +/*<delete in kernel start>*/ +	hw->wiphy->interface_modes = +		BIT(NL80211_IFTYPE_AP) | +		BIT(NL80211_IFTYPE_STATION) | +		BIT(NL80211_IFTYPE_ADHOC) | +		BIT(NL80211_IFTYPE_MESH_POINT) | +		BIT(NL80211_IFTYPE_P2P_CLIENT) | +		BIT(NL80211_IFTYPE_P2P_GO); +	hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; + +	hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; + +	hw->wiphy->rts_threshold = 2347; + +	hw->queues = AC_MAX; +	hw->extra_tx_headroom = RTL_TX_HEADER_SIZE; + +	/* TODO: Correct this value for our hw */ +	/* TODO: define these hard code value */ +	/* hw->channel_change_time = 100; kernel does not use it*/ +	hw->max_listen_interval = 10; +	hw->max_rate_tries = 4; +	/* hw->max_rates = 1; */ +	hw->sta_data_size = sizeof(struct rtl_sta_info); + +/* wowlan is not supported by kernel if CONFIG_PM is not defined */ +#ifdef CONFIG_PM +	if (rtlpriv->psc.wo_wlan_mode) { +		if (rtlpriv->psc.wo_wlan_mode & WAKE_ON_MAGIC_PACKET) +			rtlpriv->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT; +		if (rtlpriv->psc.wo_wlan_mode & WAKE_ON_PATTERN_MATCH) { +			rtlpriv->wowlan.n_patterns = +				MAX_SUPPORT_WOL_PATTERN_NUM; +			rtlpriv->wowlan.pattern_min_len = MIN_WOL_PATTERN_SIZE; +			rtlpriv->wowlan.pattern_max_len = MAX_WOL_PATTERN_SIZE; +		} +		hw->wiphy->wowlan = &(rtlpriv->wowlan); +	} +#endif + +	/* <6> mac address */ +	if (is_valid_ether_addr(rtlefuse->dev_addr)) { +		SET_IEEE80211_PERM_ADDR(hw, rtlefuse->dev_addr); +	} else { +		u8 rtlmac[] = { 0x00, 0xe0, 0x4c, 0x81, 0x92, 0x00 }; +		get_random_bytes((rtlmac + (ETH_ALEN - 1)), 1); +		SET_IEEE80211_PERM_ADDR(hw, rtlmac); +	} +} + +static void _rtl_init_deferred_work(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); + +	/* <1> timer */ +	init_timer(&rtlpriv->works.watchdog_timer); +	setup_timer(&rtlpriv->works.watchdog_timer, +		    rtl92e_watch_dog_timer_callback, (unsigned long)hw); +	init_timer(&rtlpriv->works.dualmac_easyconcurrent_retrytimer); +	setup_timer(&rtlpriv->works.dualmac_easyconcurrent_retrytimer, +		    rtl92e_easy_concurrent_retrytimer_callback, (unsigned long)hw); +	/* <2> work queue */ +	rtlpriv->works.hw = hw; +	rtlpriv->works.rtl_wq = alloc_workqueue(rtlpriv->cfg->name, 0, 0); +	INIT_DELAYED_WORK(&rtlpriv->works.watchdog_wq, +			  (void *)rtl92e_watchdog_wq_callback); +	INIT_DELAYED_WORK(&rtlpriv->works.ips_nic_off_wq, +			  (void *)rtl92e_ips_nic_off_wq_callback); +	INIT_DELAYED_WORK(&rtlpriv->works.ps_work, +			  (void *)rtl92e_swlps_wq_callback); +	INIT_DELAYED_WORK(&rtlpriv->works.ps_rfon_wq, +			  (void *)rtl92e_swlps_rfon_wq_callback); +	INIT_DELAYED_WORK(&rtlpriv->works.fwevt_wq, +			  (void *)rtl92e_fwevt_wq_callback); +} + +void rtl92e_deinit_deferred_work(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); + +	del_timer_sync(&rtlpriv->works.watchdog_timer); + +	cancel_delayed_work(&rtlpriv->works.watchdog_wq); +	cancel_delayed_work(&rtlpriv->works.ips_nic_off_wq); +	cancel_delayed_work(&rtlpriv->works.ps_work); +	cancel_delayed_work(&rtlpriv->works.ps_rfon_wq); +	cancel_delayed_work(&rtlpriv->works.fwevt_wq); +} + +void rtl92e_init_rfkill(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); + +	bool radio_state; +	bool blocked; +	u8 valid = 0; + +	/*set init state to on */ +	rtlpriv->rfkill.rfkill_state = 1; +	wiphy_rfkill_set_hw_state(hw->wiphy, 0); + +	radio_state = rtlpriv->cfg->ops->radio_onoff_checking(hw, &valid); + +	if (valid) { +		pr_info("rtlwifi: wireless switch is %s\n", +			rtlpriv->rfkill.rfkill_state ? "on" : "off"); + +		rtlpriv->rfkill.rfkill_state = radio_state; + +		blocked = (rtlpriv->rfkill.rfkill_state == 1) ? 0 : 1; +		wiphy_rfkill_set_hw_state(hw->wiphy, blocked); +	} + +	wiphy_rfkill_start_polling(hw->wiphy); +} + +void rtl92e_deinit_rfkill(struct ieee80211_hw *hw) +{ +	wiphy_rfkill_stop_polling(hw->wiphy); +} + +#ifdef VIF_TODO +static void rtl_init_vif(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); + +	INIT_LIST_HEAD(&rtlpriv->vif_priv.vif_list); + +	rtlpriv->vif_priv.vifs = 0; +} +#endif + +int rtl92e_init_core(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_mac *rtlmac = rtl_mac(rtl_priv(hw)); + +	/* <1> init mac80211 */ +	_rtl_init_mac80211(hw); +	rtlmac->hw = hw; +	rtlmac->link_state = MAC80211_NOLINK; + +	/* <2> rate control register */ +	hw->rate_control_algorithm = "rtl_rc"; + +	/* +	 * <3> init CRDA must come after init +	 * mac80211 hw  in _rtl_init_mac80211. +	 */ +	if (rtl92e_regd_init(hw, rtl92e_reg_notifier)) { +		RT_TRACE(COMP_ERR, DBG_EMERG, ("REGD init failed\n")); +		return 1; +	} + +	/* <4> locks */ +	mutex_init(&rtlpriv->locks.conf_mutex); +	spin_lock_init(&rtlpriv->locks.ips_lock); +	spin_lock_init(&rtlpriv->locks.irq_th_lock); +	spin_lock_init(&rtlpriv->locks.h2c_lock); +	spin_lock_init(&rtlpriv->locks.rf_ps_lock); +	spin_lock_init(&rtlpriv->locks.rf_lock); +	spin_lock_init(&rtlpriv->locks.lps_lock); +	spin_lock_init(&rtlpriv->locks.waitq_lock); +	spin_lock_init(&rtlpriv->locks.entry_list_lock); +	spin_lock_init(&rtlpriv->locks.cck_and_rw_pagea_lock); +	spin_lock_init(&rtlpriv->locks.check_sendpkt_lock); +	spin_lock_init(&rtlpriv->locks.fw_ps_lock); +	spin_lock_init(&rtlpriv->locks.iqk_lock); +	/* <5> init list */ +	INIT_LIST_HEAD(&rtlpriv->entry_list); + +	/* <6> init deferred work */ +	_rtl_init_deferred_work(hw); + +	/* <7> */ +#ifdef VIF_TODO +	rtl_init_vif(hw); +#endif + +	return 0; +} + +void rtl92e_deinit_core(struct ieee80211_hw *hw) +{ +} + +void rtl92e_init_rx_config(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + +	rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_RCR, (u8 *)(&mac->rx_conf)); +} + +/********************************************************* + * + * tx information functions + * + *********************************************************/ +static void _rtl_qurey_shortpreamble_mode(struct ieee80211_hw *hw, +					  struct rtl_tcb_desc *tcb_desc, +					  struct ieee80211_tx_info *info) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u8 rate_flag = info->control.rates[0].flags; + +	tcb_desc->use_shortpreamble = false; + +	/* 1M can only use Long Preamble. 11B spec */ +	if (tcb_desc->hw_rate == rtlpriv->cfg->maps[RTL_RC_CCK_RATE1M]) +		return; +	else if (rate_flag & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) +		tcb_desc->use_shortpreamble = true; + +	return; +} + +static void _rtl_query_shortgi(struct ieee80211_hw *hw, +			       struct ieee80211_sta *sta, +			       struct rtl_tcb_desc *tcb_desc, +			       struct ieee80211_tx_info *info) +{ +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +	u8 rate_flag = info->control.rates[0].flags; +	u8 sgi_40 = 0, sgi_20 = 0, bw_40 = 0; +	u8 sgi_80 = 0, bw_80 = 0; +	tcb_desc->use_shortgi = false; + +	if (sta == NULL) +		return; + +	sgi_40 = sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40; +	sgi_20 = sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20; +	sgi_80 = sta->vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_80; + +	if (!(sta->ht_cap.ht_supported) && !(sta->vht_cap.vht_supported)) +		return; + +	if (!sgi_40 && !sgi_20) +		return; + +	if (mac->opmode == NL80211_IFTYPE_STATION) { +		bw_40 = mac->bw_40; +		bw_80 = mac->bw_80; +	} else if (mac->opmode == NL80211_IFTYPE_AP || +		   mac->opmode == NL80211_IFTYPE_ADHOC || +		   mac->opmode == NL80211_IFTYPE_MESH_POINT) { +		bw_40 = sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40; +		bw_80 = sta->vht_cap.vht_supported; +	} + +	if (bw_80) { +		if (sgi_80) +			tcb_desc->use_shortgi = true; +		else +			tcb_desc->use_shortgi = false; +	} else { +		if (bw_40 && sgi_40) +			tcb_desc->use_shortgi = true; +		else if (!bw_40 && sgi_20) +			tcb_desc->use_shortgi = true; +	} + +	if (!(rate_flag & IEEE80211_TX_RC_SHORT_GI)) +		tcb_desc->use_shortgi = false; +} + +static void _rtl_query_protection_mode(struct ieee80211_hw *hw, +				       struct rtl_tcb_desc *tcb_desc, +				       struct ieee80211_tx_info *info) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u8 rate_flag = info->control.rates[0].flags; + +	/* Common Settings */ +	tcb_desc->b_rts_stbc = false; +	tcb_desc->b_cts_enable = false; +	tcb_desc->rts_sc = 0; +	tcb_desc->b_rts_bw = false; +	tcb_desc->b_rts_use_shortpreamble = false; +	tcb_desc->b_rts_use_shortgi = false; + +	if (rate_flag & IEEE80211_TX_RC_USE_CTS_PROTECT) { +		/* Use CTS-to-SELF in protection mode. */ +		tcb_desc->b_rts_enable = true; +		tcb_desc->b_cts_enable = true; +		tcb_desc->rts_rate = rtlpriv->cfg->maps[RTL_RC_OFDM_RATE24M]; +	} else if (rate_flag & IEEE80211_TX_RC_USE_RTS_CTS) { +		/* Use RTS-CTS in protection mode. */ +		tcb_desc->b_rts_enable = true; +		tcb_desc->rts_rate = rtlpriv->cfg->maps[RTL_RC_OFDM_RATE24M]; +	} +} + +static void _rtl_txrate_selectmode(struct ieee80211_hw *hw, +				   struct ieee80211_sta *sta, +				   struct rtl_tcb_desc *tcb_desc) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +	struct rtl_sta_info *sta_entry = NULL; +	u8 ratr_index = 7; + +	if (sta) { +		sta_entry = (struct rtl_sta_info *)sta->drv_priv; +		ratr_index = sta_entry->ratr_index; +	} +	if (!tcb_desc->disable_ratefallback || !tcb_desc->use_driver_rate) { +		if (mac->opmode == NL80211_IFTYPE_STATION) { +			tcb_desc->ratr_index = 0; +		} else if (mac->opmode == NL80211_IFTYPE_ADHOC || +				mac->opmode == NL80211_IFTYPE_MESH_POINT) { +			if (tcb_desc->b_multicast || tcb_desc->b_broadcast) { +				tcb_desc->hw_rate = +				    rtlpriv->cfg->maps[RTL_RC_CCK_RATE2M]; +				tcb_desc->use_driver_rate = 1; +				tcb_desc->ratr_index = RATR_INX_WIRELESS_MC; +			} else { +				tcb_desc->ratr_index = ratr_index; +			} +		} else if (mac->opmode == NL80211_IFTYPE_AP) { +			tcb_desc->ratr_index = ratr_index; +		} +	} + +	if (rtlpriv->dm.b_useramask) { +		tcb_desc->ratr_index = ratr_index; +		/* TODO we will differentiate adhoc and station futrue  */ +		if (mac->opmode == NL80211_IFTYPE_STATION || +		    mac->opmode == NL80211_IFTYPE_MESH_POINT) { +			tcb_desc->mac_id = 0; + +			if (mac->mode == WIRELESS_MODE_AC_5G) +				tcb_desc->ratr_index = +					RATR_INX_WIRELESS_AC_5N; +			else if (mac->mode == WIRELESS_MODE_AC_24G) +				tcb_desc->ratr_index = +					RATR_INX_WIRELESS_AC_24N; +			else if (mac->mode == WIRELESS_MODE_N_24G) +				tcb_desc->ratr_index = RATR_INX_WIRELESS_NGB; +			else if (mac->mode == WIRELESS_MODE_N_5G) +				tcb_desc->ratr_index = RATR_INX_WIRELESS_NG; +			else if (mac->mode & WIRELESS_MODE_G) +				tcb_desc->ratr_index = RATR_INX_WIRELESS_GB; +			else if (mac->mode & WIRELESS_MODE_B) +				tcb_desc->ratr_index = RATR_INX_WIRELESS_B; +			else if (mac->mode & WIRELESS_MODE_A) +				tcb_desc->ratr_index = RATR_INX_WIRELESS_G; + +		} else if (mac->opmode == NL80211_IFTYPE_AP || +			   mac->opmode == NL80211_IFTYPE_ADHOC) { +			if (sta) { +				if (sta->aid > 0) +					tcb_desc->mac_id = sta->aid + 1; +				else +					tcb_desc->mac_id = 1; +			} else { +				tcb_desc->mac_id = 0; +			} +		} +	} +} + +static void _rtl_query_bandwidth_mode(struct ieee80211_hw *hw, +				      struct ieee80211_sta *sta, +				      struct rtl_tcb_desc *tcb_desc) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + +	tcb_desc->packet_bw = 0; +	if (!sta) +		return; +	if (mac->opmode == NL80211_IFTYPE_AP || +	    mac->opmode == NL80211_IFTYPE_ADHOC || +	    mac->opmode == NL80211_IFTYPE_MESH_POINT) { +		if (!(sta->ht_cap.ht_supported) || +		    !(sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)) +			return; +	} else if (mac->opmode == NL80211_IFTYPE_STATION) { +		if (!mac->bw_40 || !(sta->ht_cap.ht_supported)) +			return; +	} +	if (tcb_desc->b_multicast || tcb_desc->b_broadcast) +		return; + +	/*use legency rate, shall use 20MHz */ +	if (tcb_desc->hw_rate <= rtlpriv->cfg->maps[RTL_RC_OFDM_RATE54M]) +		return; + +	tcb_desc->packet_bw = HT_CHANNEL_WIDTH_20_40; + +	if (rtlpriv->rtlhal.hw_type == HARDWARE_TYPE_RTL8812AE || +	    rtlpriv->rtlhal.hw_type == HARDWARE_TYPE_RTL8821AE) { +		if (mac->opmode == NL80211_IFTYPE_AP || +		    mac->opmode == NL80211_IFTYPE_ADHOC || +		    mac->opmode == NL80211_IFTYPE_MESH_POINT) { +			if (!(sta->vht_cap.vht_supported)) { +				return; +			} else if (mac->opmode == NL80211_IFTYPE_STATION) { +				if (!mac->bw_80 || +				    !(sta->vht_cap.vht_supported)) +					return; +			} +		} +		if (tcb_desc->hw_rate <= +			rtlpriv->cfg->maps[RTL_RC_HT_RATEMCS15]) +			return; +		tcb_desc->packet_bw = HT_CHANNEL_WIDTH_80; +	} +} + +static u8 _rtl_get_vht_highest_n_rate(struct ieee80211_hw *hw, +				      struct ieee80211_sta *sta) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	u8 hw_rate; +	u16 map = le16_to_cpu(sta->vht_cap.vht_mcs.tx_mcs_map); + +	if ((get_rf_type(rtlphy) == RF_2T2R) && +	    (map & 0x000c) != 0x000c0) { +		if ((map & 0x000c) >> 2 == IEEE80211_VHT_MCS_SUPPORT_0_7) +			hw_rate = +			rtlpriv->cfg->maps[RTL_RC_VHT_RATE_2SS_MCS7]; +		else if ((map  & 0x000c) >> 2 == IEEE80211_VHT_MCS_SUPPORT_0_8) +			hw_rate = rtlpriv->cfg->maps[RTL_RC_VHT_RATE_2SS_MCS9]; +		else +			hw_rate = rtlpriv->cfg->maps[RTL_RC_VHT_RATE_2SS_MCS9]; +	} else { +		if ((map  & 0x0003) == IEEE80211_VHT_MCS_SUPPORT_0_7) +			hw_rate = rtlpriv->cfg->maps[RTL_RC_VHT_RATE_1SS_MCS7]; +		else if ((map  & 0x0003) == IEEE80211_VHT_MCS_SUPPORT_0_8) +			hw_rate = rtlpriv->cfg->maps[RTL_RC_VHT_RATE_1SS_MCS9]; +		else +			hw_rate = rtlpriv->cfg->maps[RTL_RC_VHT_RATE_1SS_MCS9]; +	} + +	return hw_rate; +} + +static u8 _rtl_get_highest_n_rate(struct ieee80211_hw *hw, +				  struct ieee80211_sta *sta) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	u8 hw_rate; + +	if ((get_rf_type(rtlphy) == RF_2T2R) && +	    (sta->ht_cap.mcs.rx_mask[1] != 0)) +		hw_rate = rtlpriv->cfg->maps[RTL_RC_HT_RATEMCS15]; +	else +		hw_rate = rtlpriv->cfg->maps[RTL_RC_HT_RATEMCS7]; + +	return hw_rate; +} + +void stg_rtl_get_tcb_desc(struct ieee80211_hw *hw, +			  struct ieee80211_tx_info *info, +			  struct ieee80211_sta *sta, +			  struct sk_buff *skb, struct rtl_tcb_desc *tcb_desc) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_mac *rtlmac = rtl_mac(rtl_priv(hw)); +	struct ieee80211_hdr *hdr = rtl_get_hdr(skb); +	struct ieee80211_rate *txrate; +	__le16 fc = rtl_get_fc(skb); + +	txrate = ieee80211_get_tx_rate(hw, info); +	if (txrate != NULL) +		tcb_desc->hw_rate = txrate->hw_value; + +	if (ieee80211_is_data(fc)) { +		/* +		 *we set data rate INX 0 +		 *in rtl_rc.c   if skb is special data or +		 *mgt which need low data rate. +		 */ + +		/* +		 *So tcb_desc->hw_rate is just used for +		 *special data and mgt frames +		 */ +		if (info->control.rates[0].idx == 0 || +		    ieee80211_is_nullfunc(fc)) { +			tcb_desc->use_driver_rate = true; +			tcb_desc->ratr_index = RATR_INX_WIRELESS_MC; + +			tcb_desc->disable_ratefallback = 1; +		} else { +			/* +			 *because hw will nerver use hw_rate +			 *when tcb_desc->use_driver_rate = false +			 *so we never set highest N rate here, +			 *and N rate will all be controled by FW +			 *when tcb_desc->use_driver_rate = false +			 */ +			if (sta && sta->vht_cap.vht_supported) { +				tcb_desc->hw_rate = +				_rtl_get_vht_highest_n_rate(hw, sta); +			} else if (sta && (sta->ht_cap.ht_supported)) { +				tcb_desc->hw_rate = +					_rtl_get_highest_n_rate(hw, sta); +			} else { +				if (rtlmac->mode == WIRELESS_MODE_B) { +					tcb_desc->hw_rate = +					    rtlpriv->cfg->maps[RTL_RC_CCK_RATE11M]; +				} else { +					tcb_desc->hw_rate = +					    rtlpriv->cfg->maps[RTL_RC_OFDM_RATE54M]; +				} +			} +		} + +		if (is_multicast_ether_addr(ieee80211_get_DA(hdr))) +			tcb_desc->b_multicast = 1; +		else if (is_broadcast_ether_addr(ieee80211_get_DA(hdr))) +			tcb_desc->b_broadcast = 1; + +		_rtl_txrate_selectmode(hw, sta, tcb_desc); +		_rtl_query_bandwidth_mode(hw, sta, tcb_desc); +		_rtl_qurey_shortpreamble_mode(hw, tcb_desc, info); +		_rtl_query_shortgi(hw, sta, tcb_desc, info); +		_rtl_query_protection_mode(hw, tcb_desc, info); +	} else { +		tcb_desc->use_driver_rate = true; +		tcb_desc->ratr_index = RATR_INX_WIRELESS_MC; +		tcb_desc->disable_ratefallback = 1; +		tcb_desc->mac_id = 0; +		tcb_desc->packet_bw = 0; +	} +} +EXPORT_SYMBOL(stg_rtl_get_tcb_desc); + +bool rtl92e_tx_mgmt_proc(struct ieee80211_hw *hw, struct sk_buff *skb) +{ +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	__le16 fc = rtl_get_fc(skb); + +	if (rtlpriv->dm.supp_phymode_switch && +	    mac->link_state < MAC80211_LINKED && +	    (ieee80211_is_auth(fc) || ieee80211_is_probe_req(fc))) { +		if (rtlpriv->cfg->ops->check_switch_to_dmdp) +			rtlpriv->cfg->ops->check_switch_to_dmdp(hw); +	} +	if (ieee80211_is_auth(fc)) { +		RT_TRACE(COMP_SEND, DBG_DMESG, ("MAC80211_LINKING\n")); +		rtl92e_ips_nic_on(hw); + +		mac->link_state = MAC80211_LINKING; +		/* Dul mac */ +		rtlpriv->phy.b_need_iqk = true; +	} +	return true; +} + +struct sk_buff *rtl92e_make_del_ba(struct ieee80211_hw *hw, u8 *sa, +				   u8 *bssid, u16 tid); + +bool rtl92e_action_proc(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx) +{ +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +	struct ieee80211_hdr *hdr = rtl_get_hdr(skb); +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	__le16 fc = rtl_get_fc(skb); +	u8 *act = (u8 *)(((u8 *)skb->data + MAC80211_3ADDR_LEN)); +	u8 category; + +	if (!ieee80211_is_action(fc)) +		return true; + +	category = *act; +	act++; +	switch (category) { +	case ACT_CAT_BA: +		switch (*act) { +		case ACT_ADDBAREQ: +			if (mac->act_scanning) +				return false; + +			RT_TRACE((COMP_SEND | COMP_RECV), DBG_DMESG, +				 ("%s ACT_ADDBAREQ From:%pM\n", +				is_tx ? "Tx" : "Rx", hdr->addr2)); +			RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_DMESG, "req\n", +				      skb->data, skb->len); +			if (!is_tx) { +				struct ieee80211_sta *sta = NULL; +				struct rtl_sta_info *sta_entry = NULL; +				struct ieee80211_mgmt *mgmt = (void *)skb->data; +				u16 capab = 0, tid = 0; +				struct rtl_tid_data *tid_data; +				struct sk_buff *skb_delba = NULL; +				struct ieee80211_rx_status rx_status = { 0 }; + +				rcu_read_lock(); +				sta = rtl_find_sta(hw, hdr->addr3); +				if (sta == NULL) { +					RT_TRACE((COMP_SEND | COMP_RECV), +						 DBG_TRACE, ("sta is NULL\n")); +					rcu_read_unlock(); +					return true; +				} + +				sta_entry = +					(struct rtl_sta_info *)sta->drv_priv; +				if (!sta_entry) { +					rcu_read_unlock(); +					return true; +				} +				capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab); +				tid = (capab & +					IEEE80211_ADDBA_PARAM_TID_MASK) >> 2; +				tid_data = &sta_entry->tids[tid]; +				if (tid_data->agg.rx_agg_state == +				    RTL_RX_AGG_START) { +					skb_delba = rtl92e_make_del_ba(hw, +								    hdr->addr2, +								    hdr->addr3, +								    tid); +					if (skb_delba) { +						rx_status.freq = +							hw->conf.chandef.chan->center_freq; +						rx_status.band = +							hw->conf.chandef.chan->band; +						rx_status.flag |= RX_FLAG_DECRYPTED; +						rx_status.flag |= RX_FLAG_MACTIME_MPDU; +						rx_status.rate_idx = 0; +						rx_status.signal = 50 + 10; +						memcpy(IEEE80211_SKB_RXCB(skb_delba), +						       &rx_status, sizeof(rx_status)); +						RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_DMESG, +							      "fake del\n", +							      skb_delba->data, skb_delba->len); +						ieee80211_rx_irqsafe(hw, skb_delba); +					} +				} +				rcu_read_unlock(); +			} +			break; +		case ACT_ADDBARSP: +			RT_TRACE((COMP_SEND | COMP_RECV), DBG_DMESG, +				 ("%s ACT_ADDBARSP From :%pM\n", +				  is_tx ? "Tx" : "Rx", hdr->addr2)); +			break; +		case ACT_DELBA: +			RT_TRACE((COMP_SEND | COMP_RECV), DBG_DMESG, +				 ("ACT_ADDBADEL From :%pM\n", hdr->addr2)); +			break; +		} +		break; +	default: +		break; +	} + +	return true; +} + +/*should call before software enc*/ +u8 rtl92e_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, +			  u8 is_tx) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); +	__le16 fc = rtl_get_fc(skb); +	u16 ether_type; +	u8 mac_hdr_len = ieee80211_get_hdrlen_from_skb(skb); +	const struct iphdr *ip; + +	if (!ieee80211_is_data(fc)) +		goto end; + +	ip = (struct iphdr *)((u8 *)skb->data + mac_hdr_len + +			      SNAP_SIZE + PROTOC_TYPE_SIZE); +	ether_type = be16_to_cpup((__be16 *) +				  (skb->data + mac_hdr_len + SNAP_SIZE)); + +	if (ETH_P_IP == ether_type) { +		if (IPPROTO_UDP == ip->protocol) { +			struct udphdr *udp = (struct udphdr *)((u8 *)ip + +							       (ip->ihl << 2)); +			if (((((u8 *)udp)[1] == 68) && +			     (((u8 *)udp)[3] == 67)) || +			    ((((u8 *)udp)[1] == 67) && +			     (((u8 *)udp)[3] == 68))) { +				/* +				 * 68 : UDP BOOTP client +				 * 67 : UDP BOOTP server +				 */ +				RT_TRACE((COMP_SEND | COMP_RECV), +					 DBG_DMESG, ("dhcp %s !!\n", +						     (is_tx) ? "Tx" : "Rx")); + +				if (is_tx) { +					rtlpriv->ra.is_special_data = true; +					if (rtlpriv->cfg->ops->get_btc_status()) +						rtlpriv->btcoexist.btc_ops->btc_special_packet_notify( +									rtlpriv, 1); +					rtl92e_lps_leave(hw); +					ppsc->last_delaylps_stamp_jiffies = +									jiffies; +				} + +				return true; +			} +		} +	} else if (ETH_P_ARP == ether_type) { +		if (is_tx) { +			rtlpriv->ra.is_special_data = true; +			if (rtlpriv->cfg->ops->get_btc_status()) +				rtlpriv->btcoexist.btc_ops->btc_special_packet_notify( +							rtlpriv, 1); +			rtl92e_lps_leave(hw); +			ppsc->last_delaylps_stamp_jiffies = jiffies; +		} + +		return true; +	} else if (ETH_P_PAE == ether_type) { +		RT_TRACE((COMP_SEND | COMP_RECV), DBG_DMESG, +			 ("802.1X %s EAPOL pkt!!\n", (is_tx) ? "Tx" : "Rx")); + +		if (is_tx) { +			rtlpriv->ra.is_special_data = true; +			rtl92e_lps_leave(hw); +			ppsc->last_delaylps_stamp_jiffies = jiffies; +		} + +		return true; +	} else if (0x86DD == ether_type) { +		return true; +	} + +end: +	rtlpriv->ra.is_special_data = false; +	return false; +} + +/********************************************************* + * + * functions called by core.c + * + *********************************************************/ +int rtl92e_tx_agg_start(struct ieee80211_hw *hw, struct ieee80211_vif *vif, +			struct ieee80211_sta *sta, u16 tid, u16 *ssn) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_tid_data *tid_data; +	struct rtl_sta_info *sta_entry = NULL; + +	if (sta == NULL) +		return -EINVAL; + +	if (unlikely(tid >= MAX_TID_COUNT)) +		return -EINVAL; + +	sta_entry = (struct rtl_sta_info *)sta->drv_priv; +	if (!sta_entry) +		return -ENXIO; +	tid_data = &sta_entry->tids[tid]; + +	RT_TRACE(COMP_SEND, DBG_DMESG, +		 ("on ra = %pM tid = %d seq:%d\n", sta->addr, tid, +		  tid_data->seq_number)); + +	*ssn = tid_data->seq_number; +	tid_data->agg.agg_state = RTL_AGG_START; + +	ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); +	return 0; +} + +int rtl92e_tx_agg_stop(struct ieee80211_hw *hw, struct ieee80211_vif *vif, +		       struct ieee80211_sta *sta, u16 tid) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_tid_data *tid_data; +	struct rtl_sta_info *sta_entry = NULL; + +	if (sta == NULL) +		return -EINVAL; + +	/* Comparing an array to null is not useful */ +	/*if (!sta->addr) { +		RT_TRACE(COMP_ERR, DBG_EMERG, ("ra = NULL\n")); +		return -EINVAL; +	}*/ + +	RT_TRACE(COMP_SEND, DBG_DMESG, +		 ("on ra = %pM tid = %d\n", sta->addr, tid)); + +	if (unlikely(tid >= MAX_TID_COUNT)) +		return -EINVAL; + +	sta_entry = (struct rtl_sta_info *)sta->drv_priv; +	tid_data = &sta_entry->tids[tid]; +	sta_entry->tids[tid].agg.agg_state = RTL_AGG_STOP; + +	ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); +	return 0; +} + +int rtl92e_rx_agg_start(struct ieee80211_hw *hw, +			struct ieee80211_sta *sta, u16 tid) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_tid_data *tid_data; +	struct rtl_sta_info *sta_entry = NULL; + +	if (sta == NULL) +		return -EINVAL; + +	if (unlikely(tid >= MAX_TID_COUNT)) +		return -EINVAL; + +	sta_entry = (struct rtl_sta_info *)sta->drv_priv; +	if (!sta_entry) +		return -ENXIO; +	tid_data = &sta_entry->tids[tid]; + +	RT_TRACE(COMP_RECV, DBG_DMESG, +		 ("on ra = %pM tid = %d seq:%d\n", sta->addr, tid, +		 tid_data->seq_number)); + +	tid_data->agg.rx_agg_state = RTL_RX_AGG_START; +	return 0; +} + +int rtl92e_rx_agg_stop(struct ieee80211_hw *hw, +		       struct ieee80211_sta *sta, u16 tid) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_tid_data *tid_data; +	struct rtl_sta_info *sta_entry = NULL; + +	if (sta == NULL) +		return -EINVAL; + +	/* Comparing an array to null is not useful */ +	/*if (!sta->addr) { +		RT_TRACE(COMP_ERR, DBG_EMERG, ("ra = NULL\n")); +		return -EINVAL; +	}*/ + +	RT_TRACE(COMP_SEND, DBG_DMESG, +		 ("on ra = %pM tid = %d\n", sta->addr, tid)); + +	if (unlikely(tid >= MAX_TID_COUNT)) +		return -EINVAL; + +	sta_entry = (struct rtl_sta_info *)sta->drv_priv; +	tid_data = &sta_entry->tids[tid]; +	sta_entry->tids[tid].agg.rx_agg_state = RTL_RX_AGG_STOP; + +	return 0; +} + +int rtl92e_tx_agg_oper(struct ieee80211_hw *hw, +		       struct ieee80211_sta *sta, u16 tid) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_tid_data *tid_data; +	struct rtl_sta_info *sta_entry = NULL; + +	if (sta == NULL) +		return -EINVAL; + +	/* Comparing an array to null is not useful */ +	/*if (!sta->addr) { +		RT_TRACE(COMP_ERR, DBG_EMERG, ("ra = NULL\n")); +		return -EINVAL; +	}*/ + +	RT_TRACE(COMP_SEND, DBG_DMESG, +		 ("on ra = %pM tid = %d\n", sta->addr, tid)); + +	if (unlikely(tid >= MAX_TID_COUNT)) +		return -EINVAL; + +	sta_entry = (struct rtl_sta_info *)sta->drv_priv; +	tid_data = &sta_entry->tids[tid]; +	sta_entry->tids[tid].agg.agg_state = RTL_AGG_OPERATIONAL; + +	return 0; +} + +/********************************************************* + * + * wq & timer callback functions + * + *********************************************************/ +/* this function is used for roaming */ +void rtl92e_beacon_statistic(struct ieee80211_hw *hw, struct sk_buff *skb) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + +	if (rtlpriv->mac80211.opmode != NL80211_IFTYPE_STATION) +		return; + +	if (rtlpriv->mac80211.link_state < MAC80211_LINKED) +		return; + +	/* check if this really is a beacon */ +	if (!ieee80211_is_beacon(hdr->frame_control) && +	    !ieee80211_is_probe_resp(hdr->frame_control)) +		return; + +	/* min. beacon length + FCS_LEN */ +	if (skb->len <= 40 + FCS_LEN) +		return; + +	/* and only beacons from the associated BSSID, please */ +	if (!ether_addr_equal(hdr->addr3, rtlpriv->mac80211.bssid)) +		return; + +	rtlpriv->link_info.bcn_rx_inperiod++; +} + +void rtl92e_watchdog_wq_callback(void *data) +{ +	struct rtl_works *rtlworks = container_of_dwork_rtl(data, +							    struct rtl_works, +							    watchdog_wq); +	struct ieee80211_hw *hw = rtlworks->hw; +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +	bool b_busytraffic = false; +	bool b_tx_busy_traffic = false; +	bool b_rx_busy_traffic = false; +	bool b_higher_busytraffic = false; +	bool b_higher_busyrxtraffic = false; +	u8 idx, tid; +	u32 rx_cnt_inp4eriod = 0; +	u32 tx_cnt_inp4eriod = 0; +	u32 aver_rx_cnt_inperiod = 0; +	u32 aver_tx_cnt_inperiod = 0; +	u32 aver_tidtx_inperiod[MAX_TID_COUNT] = {0}; +	u32 tidtx_inp4eriod[MAX_TID_COUNT] = {0}; +	bool benter_ps = false; + +	if (is_hal_stop(rtlhal)) +		return; + +	/* <1> Determine if action frame is allowed */ +	if (mac->link_state > MAC80211_NOLINK) { +		if (mac->cnt_after_linked < 20) +			mac->cnt_after_linked++; +	} else { +		mac->cnt_after_linked = 0; +	} + +	/* <2> to check if traffic busy, if +	 * busytraffic we don't change channel */ +	if (mac->link_state >= MAC80211_LINKED) { +		/* (1) get aver_rx_cnt_inperiod & aver_tx_cnt_inperiod */ +		for (idx = 0; idx <= 2; idx++) { +			rtlpriv->link_info.num_rx_in4period[idx] = +			    rtlpriv->link_info.num_rx_in4period[idx + 1]; +			rtlpriv->link_info.num_tx_in4period[idx] = +			    rtlpriv->link_info.num_tx_in4period[idx + 1]; +		} +		rtlpriv->link_info.num_rx_in4period[3] = +		    rtlpriv->link_info.num_rx_inperiod; +		rtlpriv->link_info.num_tx_in4period[3] = +		    rtlpriv->link_info.num_tx_inperiod; +		for (idx = 0; idx <= 3; idx++) { +			rx_cnt_inp4eriod += +			    rtlpriv->link_info.num_rx_in4period[idx]; +			tx_cnt_inp4eriod += +			    rtlpriv->link_info.num_tx_in4period[idx]; +		} +		aver_rx_cnt_inperiod = rx_cnt_inp4eriod / 4; +		aver_tx_cnt_inperiod = tx_cnt_inp4eriod / 4; + +		/* (2) check traffic busy */ +		if (aver_rx_cnt_inperiod > 100 || aver_tx_cnt_inperiod > 100) { +			b_busytraffic = true; +			if (aver_rx_cnt_inperiod > aver_tx_cnt_inperiod) +				b_rx_busy_traffic = true; +			else +				b_tx_busy_traffic = false; +		} + +		/* Higher Tx/Rx data. */ +		if (aver_rx_cnt_inperiod > 4000 || +		    aver_tx_cnt_inperiod > 4000) { +			b_higher_busytraffic = true; + +			/* Extremely high Rx data. */ +			if (aver_rx_cnt_inperiod > 5000) +				b_higher_busyrxtraffic = true; +		} + +		/* check every tid's tx traffic */ +		for (tid = 0; tid <= 7; tid++) { +			for (idx = 0; idx <= 2; idx++) +				rtlpriv->link_info.tidtx_in4period[tid][idx] = +					rtlpriv->link_info.tidtx_in4period[tid] +					[idx + 1]; +			rtlpriv->link_info.tidtx_in4period[tid][3] = +				rtlpriv->link_info.tidtx_inperiod[tid]; + +			for (idx = 0; idx <= 3; idx++) +				tidtx_inp4eriod[tid] += +				   rtlpriv->link_info.tidtx_in4period[tid][idx]; +			aver_tidtx_inperiod[tid] = tidtx_inp4eriod[tid] / 4; +			if (aver_tidtx_inperiod[tid] > 5000) +				rtlpriv->link_info.higher_busytxtraffic[tid] = +									true; +			else +				rtlpriv->link_info.higher_busytxtraffic[tid] = +									false; +		} + +		if (((rtlpriv->link_info.num_rx_inperiod + +		      rtlpriv->link_info.num_tx_inperiod) > 8) || +		    (rtlpriv->link_info.num_rx_inperiod > 2)) +			benter_ps = false; +		else +			benter_ps = true; + +		/* LeisurePS only work in infra mode. */ +		if (benter_ps) +			rtl92e_lps_enter(hw); +		else +			rtl92e_lps_leave(hw); +	} + +	rtlpriv->link_info.num_rx_inperiod = 0; +	rtlpriv->link_info.num_tx_inperiod = 0; +	for (tid = 0; tid <= 7; tid++) +		rtlpriv->link_info.tidtx_inperiod[tid] = 0; + +	rtlpriv->link_info.b_busytraffic = b_busytraffic; +	rtlpriv->link_info.b_rx_busy_traffic = b_rx_busy_traffic; +	rtlpriv->link_info.b_tx_busy_traffic = b_tx_busy_traffic; +	rtlpriv->link_info.b_higher_busytraffic = b_higher_busytraffic; +	rtlpriv->link_info.b_higher_busyrxtraffic = b_higher_busyrxtraffic; + +	/* <3> DM */ +	rtlpriv->cfg->ops->dm_watchdog(hw); + +	/* <4> roaming */ +	if (mac->link_state == MAC80211_LINKED && +	    mac->opmode == NL80211_IFTYPE_STATION) { +		if ((rtlpriv->link_info.bcn_rx_inperiod + +			rtlpriv->link_info.num_rx_inperiod) == 0) { +			rtlpriv->link_info.roam_times++; +			RT_TRACE(COMP_ERR, DBG_DMESG, +				 ("AP off for %d s\n", +				  (rtlpriv->link_info.roam_times * 2))); + +			/* if we can't recv beacon for 10s, +			* we should reconnect this AP */ +			if (rtlpriv->link_info.roam_times >= 5) { +				RT_TRACE(COMP_ERR, DBG_EMERG, +					 ("AP off, try to reconnect now\n")); +				rtlpriv->link_info.roam_times = 0; +				ieee80211_connection_loss( +					rtlpriv->mac80211.vif); +			} +		} else { +			rtlpriv->link_info.roam_times = 0; +		} +	} + +	if (rtlpriv->cfg->ops->get_btc_status()) +		rtlpriv->btcoexist.btc_ops->btc_periodical(rtlpriv); + +	rtlpriv->link_info.bcn_rx_inperiod = 0; +} + +void rtl92e_watch_dog_timer_callback(unsigned long data) +{ +	struct ieee80211_hw *hw = (struct ieee80211_hw *)data; +	struct rtl_priv *rtlpriv = rtl_priv(hw); + +	queue_delayed_work(rtlpriv->works.rtl_wq, +			   &rtlpriv->works.watchdog_wq, 0); + +	mod_timer(&rtlpriv->works.watchdog_timer, +		  jiffies + MSECS(RTL_WATCH_DOG_TIME)); +} +void rtl92e_fwevt_wq_callback(void *data) +{ +	struct rtl_works *rtlworks = +		container_of_dwork_rtl(data, struct rtl_works, fwevt_wq); +	struct ieee80211_hw *hw = rtlworks->hw; +	struct rtl_priv *rtlpriv = rtl_priv(hw); + +	rtlpriv->cfg->ops->c2h_command_handle(hw); +} +void rtl92e_easy_concurrent_retrytimer_callback(unsigned long data) +{ +	struct ieee80211_hw *hw = (struct ieee80211_hw *)data; +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_priv *buddy_priv = rtlpriv->buddy_priv; + +	if (buddy_priv == NULL) +		return; + +	rtlpriv->cfg->ops->dualmac_easy_concurrent(hw); +} +/********************************************************* + * + * frame process functions + * + *********************************************************/ +u8 *rtl92e_find_ie(u8 *data, unsigned int len, u8 ie) +{ +	struct ieee80211_mgmt *mgmt = (void *)data; +	u8 *pos, *end; + +	pos = (u8 *)mgmt->u.beacon.variable; +	end = data + len; +	while (pos < end) { +		if (pos + 2 + pos[1] > end) +			return NULL; + +		if (pos[0] == ie) +			return pos; + +		pos += 2 + pos[1]; +	} +	return NULL; +} + +/* when we use 2 rx ants we send IEEE80211_SMPS_OFF */ +/* when we use 1 rx ant we send IEEE80211_SMPS_STATIC */ +static struct sk_buff *rtl_make_smps_action(struct ieee80211_hw *hw, +					    enum ieee80211_smps_mode smps, +					    u8 *da, u8 *bssid) +{ +	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); +	struct sk_buff *skb; +	struct ieee80211_mgmt_compat *action_frame; + +	/* 27 = header + category + action + smps mode */ +	skb = dev_alloc_skb(27 + hw->extra_tx_headroom); +	if (!skb) +		return NULL; + +	skb_reserve(skb, hw->extra_tx_headroom); +	action_frame = (void *)skb_put(skb, 27); +	memset(action_frame, 0, 27); +	ether_addr_copy(action_frame->da, da); +	ether_addr_copy(action_frame->sa, rtlefuse->dev_addr); +	ether_addr_copy(action_frame->bssid, bssid); +	action_frame->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | +						  IEEE80211_STYPE_ACTION); +	action_frame->u.action.category = WLAN_CATEGORY_HT; +	action_frame->u.action.u.ht_smps.action = WLAN_HT_ACTION_SMPS; +	switch (smps) { +	case IEEE80211_SMPS_AUTOMATIC:/* 0 */ +	case IEEE80211_SMPS_NUM_MODES:/* 4 */ +		WARN_ON(1); +	/* Here will get a 'MISSING_BREAK' in Coverity Test, just ignore it. +	 * According to Kernel Code, here is right. +	 */ +	case IEEE80211_SMPS_OFF:/* 1 */ /*MIMO_PS_NOLIMIT*/ +		action_frame->u.action.u.ht_smps.smps_control = +				WLAN_HT_SMPS_CONTROL_DISABLED;/* 0 */ +		break; +	case IEEE80211_SMPS_STATIC:/* 2 */ /*MIMO_PS_STATIC*/ +		action_frame->u.action.u.ht_smps.smps_control = +				WLAN_HT_SMPS_CONTROL_STATIC;/* 1 */ +		break; +	case IEEE80211_SMPS_DYNAMIC:/* 3 */ /*MIMO_PS_DYNAMIC*/ +		action_frame->u.action.u.ht_smps.smps_control = +				WLAN_HT_SMPS_CONTROL_DYNAMIC;/* 3 */ +		break; +	} + +	return skb; +} + +int stg_rtl_send_smps_action(struct ieee80211_hw *hw, +			     struct ieee80211_sta *sta, +			     enum ieee80211_smps_mode smps) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); +	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); +	struct sk_buff *skb = NULL; +	struct rtl_tcb_desc tcb_desc; +	u8 bssid[ETH_ALEN] = {0}; + +	memset(&tcb_desc, 0, sizeof(struct rtl_tcb_desc)); + +	if (rtlpriv->mac80211.act_scanning) +		goto err_free; + +	if (!sta) +		goto err_free; + +	if (unlikely(is_hal_stop(rtlhal) || ppsc->rfpwr_state != ERFON)) +		goto err_free; + +	if (!test_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status)) +		goto err_free; + +	if (rtlpriv->mac80211.opmode == NL80211_IFTYPE_AP) +		ether_addr_copy(bssid, rtlpriv->efuse.dev_addr); +	else +		ether_addr_copy(bssid, rtlpriv->mac80211.bssid); + +	skb = rtl_make_smps_action(hw, smps, sta->addr, bssid); +	/* this is a type = mgmt * stype = action frame */ +	if (skb) { +		struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); +		struct rtl_sta_info *sta_entry = +			(struct rtl_sta_info *)sta->drv_priv; +		sta_entry->mimo_ps = smps; +		/* rtlpriv->cfg->ops->update_rate_tbl(hw, sta, 0); */ + +		info->control.rates[0].idx = 0; +		info->band = hw->conf.chandef.chan->band; +		rtlpriv->intf_ops->adapter_tx(hw, sta, skb, &tcb_desc); +	} +	return 1; + +err_free: +	return 0; +} +EXPORT_SYMBOL(stg_rtl_send_smps_action); + +/* because mac80211 have issues when can receive del ba + * so here we just make a fake del_ba if we receive a ba_req + * but rx_agg was opened to let mac80211 release some ba + * related resources, so please this del_ba for tx */ +struct sk_buff *rtl92e_make_del_ba(struct ieee80211_hw *hw, +				   u8 *sa, u8 *bssid, u16 tid) +{ +	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); +	struct sk_buff *skb; +	struct ieee80211_mgmt *action_frame; +	u16 params; + +	/* 27 = header + category + action + smps mode */ +	skb = dev_alloc_skb(34 + hw->extra_tx_headroom); +	if (!skb) +		return NULL; + +	skb_reserve(skb, hw->extra_tx_headroom); +	action_frame = (void *)skb_put(skb, 34); +	memset(action_frame, 0, 34); +	ether_addr_copy(action_frame->sa, sa); +	ether_addr_copy(action_frame->da, rtlefuse->dev_addr); +	ether_addr_copy(action_frame->bssid, bssid); +	action_frame->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | +						  IEEE80211_STYPE_ACTION); +	action_frame->u.action.category = WLAN_CATEGORY_BACK; +	action_frame->u.action.u.delba.action_code = WLAN_ACTION_DELBA; +	params = (u16)(1 << 11);	/* bit 11 initiator */ +	params |= (u16)(tid << 12);	/* bit 15:12 TID number */ + +	action_frame->u.action.u.delba.params = cpu_to_le16(params); +	action_frame->u.action.u.delba.reason_code = +		cpu_to_le16(WLAN_REASON_QSTA_TIMEOUT); + +	return skb; +} + +/********************************************************* + * + * IOT functions + * + *********************************************************/ +static bool rtl_chk_vendor_ouisub(struct ieee80211_hw *hw, +				  struct octet_string vendor_ie) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	bool matched = false; +	static u8 athcap_1[] = { 0x00, 0x03, 0x7F }; +	static u8 athcap_2[] = { 0x00, 0x13, 0x74 }; +	static u8 broadcap_1[] = { 0x00, 0x10, 0x18 }; +	static u8 broadcap_2[] = { 0x00, 0x0a, 0xf7 }; +	static u8 broadcap_3[] = { 0x00, 0x05, 0xb5 }; +	static u8 racap[] = { 0x00, 0x0c, 0x43 }; +	static u8 ciscocap[] = { 0x00, 0x40, 0x96 }; +	static u8 marvcap[] = { 0x00, 0x50, 0x43 }; + +	if (memcmp(vendor_ie.octet, athcap_1, 3) == 0 || +	    memcmp(vendor_ie.octet, athcap_2, 3) == 0) { +		rtlpriv->mac80211.vendor = PEER_ATH; +		matched = true; +	} else if (memcmp(vendor_ie.octet, broadcap_1, 3) == 0 || +		   memcmp(vendor_ie.octet, broadcap_2, 3) == 0 || +		   memcmp(vendor_ie.octet, broadcap_3, 3) == 0) { +		rtlpriv->mac80211.vendor = PEER_BROAD; +		matched = true; +	} else if (memcmp(vendor_ie.octet, racap, 3) == 0) { +		rtlpriv->mac80211.vendor = PEER_RAL; +		matched = true; +	} else if (memcmp(vendor_ie.octet, ciscocap, 3) == 0) { +		rtlpriv->mac80211.vendor = PEER_CISCO; +		matched = true; +	} else if (memcmp(vendor_ie.octet, marvcap, 3) == 0) { +		rtlpriv->mac80211.vendor = PEER_MARV; +		matched = true; +	} + +	return matched; +} + +static bool rtl_find_221_ie(struct ieee80211_hw *hw, u8 *data, unsigned int len) +{ +	struct ieee80211_mgmt *mgmt = (void *)data; +	struct octet_string vendor_ie; +	u8 *pos, *end; + +	pos = (u8 *)mgmt->u.beacon.variable; +	end = data + len; +	while (pos < end) { +		if (pos[0] == 221) { +			vendor_ie.length = pos[1]; +			vendor_ie.octet = &pos[2]; +			if (rtl_chk_vendor_ouisub(hw, vendor_ie)) +				return true; +		} + +		if (pos + 2 + pos[1] > end) +			return false; + +		pos += 2 + pos[1]; +	} +	return false; +} + +void rtl92e_recognize_peer(struct ieee80211_hw *hw, u8 *data, unsigned int len) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +	struct ieee80211_hdr *hdr = (void *)data; +	u32 vendor = PEER_UNKNOWN; + +	static u8 ap3_1[3] = { 0x00, 0x14, 0xbf }; +	static u8 ap3_2[3] = { 0x00, 0x1a, 0x70 }; +	static u8 ap3_3[3] = { 0x00, 0x1d, 0x7e }; +	static u8 ap4_1[3] = { 0x00, 0x90, 0xcc }; +	static u8 ap4_2[3] = { 0x00, 0x0e, 0x2e }; +	static u8 ap4_3[3] = { 0x00, 0x18, 0x02 }; +	static u8 ap4_4[3] = { 0x00, 0x17, 0x3f }; +	static u8 ap4_5[3] = { 0x00, 0x1c, 0xdf }; +	static u8 ap5_1[3] = { 0x00, 0x1c, 0xf0 }; +	static u8 ap5_2[3] = { 0x00, 0x21, 0x91 }; +	static u8 ap5_3[3] = { 0x00, 0x24, 0x01 }; +	static u8 ap5_4[3] = { 0x00, 0x15, 0xe9 }; +	static u8 ap5_5[3] = { 0x00, 0x17, 0x9A }; +	static u8 ap5_6[3] = { 0x00, 0x18, 0xE7 }; +	static u8 ap6_1[3] = { 0x00, 0x17, 0x94 }; +	static u8 ap7_1[3] = { 0x00, 0x14, 0xa4 }; + +	if (mac->opmode != NL80211_IFTYPE_STATION) +		return; + +	if (mac->link_state == MAC80211_NOLINK) { +		mac->vendor = PEER_UNKNOWN; +		return; +	} + +	if (mac->cnt_after_linked > 2) +		return; + +	/* check if this really is a beacon */ +	if (!ieee80211_is_beacon(hdr->frame_control)) +		return; + +	/* min. beacon length + FCS_LEN */ +	if (len <= 40 + FCS_LEN) +		return; + +	/* and only beacons from the associated BSSID, please */ +	if (!ether_addr_equal(hdr->addr3, rtlpriv->mac80211.bssid)) +		return; + +	if (rtl_find_221_ie(hw, data, len)) +		vendor = mac->vendor; + +	if ((memcmp(mac->bssid, ap5_1, 3) == 0) || +	    (memcmp(mac->bssid, ap5_2, 3) == 0) || +	    (memcmp(mac->bssid, ap5_3, 3) == 0) || +	    (memcmp(mac->bssid, ap5_4, 3) == 0) || +	    (memcmp(mac->bssid, ap5_5, 3) == 0) || +	    (memcmp(mac->bssid, ap5_6, 3) == 0) || +		vendor == PEER_ATH) { +		vendor = PEER_ATH; +		RT_TRACE(COMP_MAC80211, DBG_LOUD, ("=>ath find\n")); +	} else if ((memcmp(mac->bssid, ap4_4, 3) == 0) || +		   (memcmp(mac->bssid, ap4_5, 3) == 0) || +		   (memcmp(mac->bssid, ap4_1, 3) == 0) || +		   (memcmp(mac->bssid, ap4_2, 3) == 0) || +		   (memcmp(mac->bssid, ap4_3, 3) == 0) || +		vendor == PEER_RAL) { +		RT_TRACE(COMP_MAC80211, DBG_LOUD, ("=>ral findn\n")); +		vendor = PEER_RAL; +	} else if (memcmp(mac->bssid, ap6_1, 3) == 0 || +		vendor == PEER_CISCO) { +		vendor = PEER_CISCO; +		RT_TRACE(COMP_MAC80211, DBG_LOUD, ("=>cisco find\n")); +	} else if ((memcmp(mac->bssid, ap3_1, 3) == 0) || +		(memcmp(mac->bssid, ap3_2, 3) == 0) || +		(memcmp(mac->bssid, ap3_3, 3) == 0) || +		vendor == PEER_BROAD) { +		RT_TRACE(COMP_MAC80211, DBG_LOUD, ("=>broad find\n")); +		vendor = PEER_BROAD; +	} else if (memcmp(mac->bssid, ap7_1, 3) == 0 || +		vendor == PEER_MARV) { +		vendor = PEER_MARV; +		RT_TRACE(COMP_MAC80211, DBG_LOUD, ("=>marv find\n")); +	} + +	mac->vendor = vendor; +} + +/********************************************************* + * + * sysfs functions + * + *********************************************************/ +struct rtl_global_var global_var = {}; + +int  rtl_core_module_init(void) +{ +	static int here_once; + +	if (here_once++) +		return 0; + +	if (rtl92e_rate_control_register()) +		pr_debug("rtl: Unable to register rtl_rc, use default RC !!\n"); + +	/* init some global vars */ +	INIT_LIST_HEAD(&global_var.glb_priv_list); +	spin_lock_init(&global_var.glb_list_lock); + +	return 0; +} +void  rtl_core_module_exit(void) +{ +	/*RC*/ +	rtl92e_rate_control_unregister(); +} diff --git a/drivers/staging/rtl8192ee/base.h b/drivers/staging/rtl8192ee/base.h new file mode 100644 index 00000000000..c7929a7b02f --- /dev/null +++ b/drivers/staging/rtl8192ee/base.h @@ -0,0 +1,163 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010  Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __RTL_BASE_H__ +#define __RTL_BASE_H__ + +#include "compat.h" + +enum ap_peer { +	PEER_UNKNOWN = 0, +	PEER_RTL = 1, +	PEER_RTL_92SE = 2, +	PEER_BROAD = 3, +	PEER_RAL = 4, +	PEER_ATH = 5, +	PEER_CISCO = 6, +	PEER_MARV = 7, +	PEER_AIRGO = 9, +	PEER_MAX = 10, +}; + +#define RTL_DUMMY_OFFSET	0 +#define RTL_DUMMY_UNIT		8 +#define RTL_TX_DUMMY_SIZE	(RTL_DUMMY_OFFSET * RTL_DUMMY_UNIT) +#define RTL_TX_DESC_SIZE	32 +#define RTL_TX_HEADER_SIZE	(RTL_TX_DESC_SIZE + RTL_TX_DUMMY_SIZE) + +#define HT_AMSDU_SIZE_4K	3839 +#define HT_AMSDU_SIZE_8K	7935 + +#define MAX_BIT_RATE_40MHZ_MCS15	300	/* Mbps */ +#define MAX_BIT_RATE_40MHZ_MCS7		150	/* Mbps */ + +#define MAX_BIT_RATE_SHORT_GI_2NSS_80MHZ_MCS9	867	/* Mbps */ +#define MAX_BIT_RATE_SHORT_GI_2NSS_80MHZ_MCS7	650	/* Mbps */ +#define MAX_BIT_RATE_LONG_GI_2NSS_80MHZ_MCS9	780	/* Mbps */ +#define MAX_BIT_RATE_LONG_GI_2NSS_80MHZ_MCS7	585	/* Mbps */ + +#define MAX_BIT_RATE_SHORT_GI_1NSS_80MHZ_MCS9	434	/* Mbps */ +#define MAX_BIT_RATE_SHORT_GI_1NSS_80MHZ_MCS7	325	/* Mbps */ +#define MAX_BIT_RATE_LONG_GI_1NSS_80MHZ_MCS9	390	/* Mbps */ +#define MAX_BIT_RATE_LONG_GI_1NSS_80MHZ_MCS7	293	/* Mbps */ + + +#define RTL_RATE_COUNT_LEGACY		12 +#define RTL_CHANNEL_COUNT		14 + +#define FRAME_OFFSET_FRAME_CONTROL	0 +#define FRAME_OFFSET_DURATION		2 +#define FRAME_OFFSET_ADDRESS1		4 +#define FRAME_OFFSET_ADDRESS2		10 +#define FRAME_OFFSET_ADDRESS3		16 +#define FRAME_OFFSET_SEQUENCE		22 +#define FRAME_OFFSET_ADDRESS4		24 + +#define SET_80211_HDR_FRAME_CONTROL(_hdr, _val)		\ +	WRITEEF2BYTE(_hdr, _val) +#define SET_80211_HDR_TYPE_AND_SUBTYPE(_hdr, _val)	\ +	WRITEEF1BYTE(_hdr, _val) +#define SET_80211_HDR_PWR_MGNT(_hdr, _val)		\ +	SET_BITS_TO_LE_2BYTE(_hdr, 12, 1, _val) +#define SET_80211_HDR_TO_DS(_hdr, _val)			\ +	SET_BITS_TO_LE_2BYTE(_hdr, 8, 1, _val) + +#define SET_80211_PS_POLL_AID(_hdr, _val)		\ +	(*(u16 *)((u8 *)(_hdr) + 2) = _val) +#define SET_80211_PS_POLL_BSSID(_hdr, _val)		\ +	memcpy(((u8 *)(_hdr)) + 4, (u8 *)(_val), ETH_ALEN) +#define SET_80211_PS_POLL_TA(_hdr, _val)		\ +	memcpy(((u8 *)(_hdr)) + 10, (u8 *)(_val), ETH_ALEN) + +#define SET_80211_HDR_DURATION(_hdr, _val)	\ +	WRITEEF2BYTE((u8 *)(_hdr)+FRAME_OFFSET_DURATION, _val) +#define SET_80211_HDR_ADDRESS1(_hdr, _val)	\ +	CP_MACADDR((u8 *)(_hdr)+FRAME_OFFSET_ADDRESS1, (u8 *)(_val)) +#define SET_80211_HDR_ADDRESS2(_hdr, _val)	\ +	CP_MACADDR((u8 *)(_hdr)+FRAME_OFFSET_ADDRESS2, (u8 *)(_val)) +#define SET_80211_HDR_ADDRESS3(_hdr, _val)	\ +	CP_MACADDR((u8 *)(_hdr)+FRAME_OFFSET_ADDRESS3, (u8 *)(_val)) +#define SET_80211_HDR_FRAGMENT_SEQUENCE(_hdr, _val)  \ +	WRITEEF2BYTE((u8 *)(_hdr)+FRAME_OFFSET_SEQUENCE, _val) + +#define SET_BEACON_PROBE_RSP_TIME_STAMP_LOW(__phdr, __val)	\ +	WRITEEF4BYTE(((u8 *)(__phdr)) + 24, __val) +#define SET_BEACON_PROBE_RSP_TIME_STAMP_HIGH(__phdr, __val) \ +	WRITEEF4BYTE(((u8 *)(__phdr)) + 28, __val) +#define SET_BEACON_PROBE_RSP_BEACON_INTERVAL(__phdr, __val) \ +	WRITEEF2BYTE(((u8 *)(__phdr)) + 32, __val) +#define GET_BEACON_PROBE_RSP_CAPABILITY_INFO(__phdr)		\ +	READEF2BYTE(((u8 *)(__phdr)) + 34) +#define SET_BEACON_PROBE_RSP_CAPABILITY_INFO(__phdr, __val) \ +	WRITEEF2BYTE(((u8 *)(__phdr)) + 34, __val) +#define MASK_BEACON_PROBE_RSP_CAPABILITY_INFO(__phdr, __val) \ +	SET_BEACON_PROBE_RSP_CAPABILITY_INFO(__phdr, \ +	(GET_BEACON_PROBE_RSP_CAPABILITY_INFO(__phdr) & (~(__val)))) + +int rtl92e_init_core(struct ieee80211_hw *hw); +void rtl92e_deinit_core(struct ieee80211_hw *hw); +void rtl92e_init_rx_config(struct ieee80211_hw *hw); +void rtl92e_init_rfkill(struct ieee80211_hw *hw); +void rtl92e_deinit_rfkill(struct ieee80211_hw *hw); + +void rtl92e_watch_dog_timer_callback(unsigned long data); +void rtl92e_deinit_deferred_work(struct ieee80211_hw *hw); + +bool rtl92e_action_proc(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx); +bool rtl92e_tx_mgmt_proc(struct ieee80211_hw *hw, struct sk_buff *skb); +u8 rtl92e_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, +			  u8 is_tx); +void rtl92e_beacon_statistic(struct ieee80211_hw *hw, struct sk_buff *skb); +void rtl92e_watch_dog_timer_callback(unsigned long data); +int rtl92e_tx_agg_start(struct ieee80211_hw *hw, struct ieee80211_vif *vif, +		        struct ieee80211_sta *sta, u16 tid, u16 *ssn); +int rtl92e_tx_agg_stop(struct ieee80211_hw *hw, struct ieee80211_vif *vif, +		       struct ieee80211_sta *sta, u16 tid); +int rtl92e_tx_agg_oper(struct ieee80211_hw *hw, +		       struct ieee80211_sta *sta, u16 tid); +int rtl92e_rx_agg_start(struct ieee80211_hw *hw, +		        struct ieee80211_sta *sta, u16 tid); +int rtl92e_rx_agg_stop(struct ieee80211_hw *hw, +		       struct ieee80211_sta *sta, u16 tid); +void rtl92e_watchdog_wq_callback(void *data); +void rtl92e_fwevt_wq_callback(void *data); + +void stg_rtl_get_tcb_desc(struct ieee80211_hw *hw, +			  struct ieee80211_tx_info *info, +			  struct ieee80211_sta *sta, +			  struct sk_buff *skb, struct rtl_tcb_desc *tcb_desc); + +int stg_rtl_send_smps_action(struct ieee80211_hw *hw, +			     struct ieee80211_sta *sta, +			     enum ieee80211_smps_mode smps); +u8 *rtl92e_find_ie(u8 *data, unsigned int len, u8 ie); +void rtl92e_recognize_peer(struct ieee80211_hw *hw, u8 *data, unsigned int len); +u8 rtl92e_tid_to_ac(struct ieee80211_hw *hw, u8 tid); +void rtl92e_easy_concurrent_retrytimer_callback(unsigned long data); +extern struct rtl_global_var global_var; +int  rtl_core_module_init(void); +void  rtl_core_module_exit(void); + +#endif diff --git a/drivers/staging/rtl8192ee/btcoexist/halbt_precomp.h b/drivers/staging/rtl8192ee/btcoexist/halbt_precomp.h new file mode 100644 index 00000000000..56e6c465189 --- /dev/null +++ b/drivers/staging/rtl8192ee/btcoexist/halbt_precomp.h @@ -0,0 +1,50 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * + ******************************************************************************/ +#ifndef	__HALBT_PRECOMP_H__ +#define __HALBT_PRECOMP_H__ +/************************************************************* + * include files + *************************************************************/ +#include "../wifi.h" +#include "../efuse.h" +#include "../base.h" +#include "../regd.h" +#include "../cam.h" +#include "../ps.h" +#include "../pci.h" + +#include "halbtcoutsrc.h" + + +#include "halbtc8192e2ant.h" +#include "halbtc8723b1ant.h" +#include "halbtc8723b2ant.h" +#include "halbtc8821a2ant.h" +#include "halbtc8821a1ant.h" + +#define	MASKBYTE0			0xff +#define	MASKBYTE1			0xff00 +#define	MASKBYTE2			0xff0000 +#define	MASKBYTE3			0xff000000 +#define	MASKHWORD			0xffff0000 +#define	MASKLWORD			0x0000ffff +#define	MASKDWORD			0xffffffff +#define	MASK12BITS			0xfff +#define	MASKH4BITS			0xf0000000 +#define MASKOFDM_D			0xffc00000 +#define	MASKCCK				0x3f3f3f3f + +#endif	/* __HALBT_PRECOMP_H__ */ diff --git a/drivers/staging/rtl8192ee/btcoexist/halbtc8192e2ant.c b/drivers/staging/rtl8192ee/btcoexist/halbtc8192e2ant.c new file mode 100644 index 00000000000..ab2cc2fadd8 --- /dev/null +++ b/drivers/staging/rtl8192ee/btcoexist/halbtc8192e2ant.c @@ -0,0 +1,4110 @@ +/************************************************************** + * Description: + * + * This file is for RTL8192E Co-exist mechanism + * + * History + * 2012/11/15 Cosa first check in. + * + **************************************************************/ + +/************************************************************** + *   include files + **************************************************************/ +#include "halbt_precomp.h" +/************************************************************** + *   Global variables, these are static variables + **************************************************************/ +static struct coex_dm_8192e_2ant glcoex_dm_8192e_2ant; +static struct coex_dm_8192e_2ant *coex_dm = &glcoex_dm_8192e_2ant; +static struct coex_sta_8192e_2ant glcoex_sta_8192e_2ant; +static struct coex_sta_8192e_2ant *coex_sta = &glcoex_sta_8192e_2ant; + +static const char *const glbt_infosrc8192e2ant[] = { +	"BT Info[wifi fw]", +	"BT Info[bt rsp]", +	"BT Info[bt auto report]", +}; + +static u32 glcoex_ver_date_8192e_2ant = 20130902; +static u32 glcoex_ver_8192e_2ant = 0x34; + +/************************************************************** + *   local function proto type if needed + **************************************************************/ +/************************************************************** + *   local function start with halbtc8192e2ant_ + **************************************************************/ +static u8 halbtc8192e2ant_btrssi_state(u8 level_num, u8 rssi_thresh, +				       u8 rssi_thresh1) +{ +	int btrssi = 0; +	u8 btrssi_state = coex_sta->pre_bt_rssi_state; + +	btrssi = coex_sta->bt_rssi; + +	if (level_num == 2) { +		if ((coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_LOW) || +		    (coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_STAY_LOW)) { +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, +				  "BT Rssi pre state = LOW\n"); +			if (btrssi >= (rssi_thresh + +				       BTC_RSSI_COEX_THRESH_TOL_8192E_2ANT)) { +				btrssi_state = BTC_RSSI_STATE_HIGH; +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, +					  "BT Rssi state switch to High\n"); +			} else { +				btrssi_state = BTC_RSSI_STATE_STAY_LOW; +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, +					  "BT Rssi state stay at Low\n"); +			} +		} else { +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, +				  "BT Rssi pre state = HIGH\n"); +			if (btrssi < rssi_thresh) { +				btrssi_state = BTC_RSSI_STATE_LOW; +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, +					  "BT Rssi state switch to Low\n"); +			} else { +				btrssi_state = BTC_RSSI_STATE_STAY_HIGH; +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, +					  "BT Rssi state stay at High\n"); +			} +		} +	} else if (level_num == 3) { +		if (rssi_thresh > rssi_thresh1) { +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, +				  "BT Rssi thresh error!!\n"); +			return coex_sta->pre_bt_rssi_state; +		} + +		if ((coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_LOW) || +		    (coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_STAY_LOW)) { +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, +				  "BT Rssi pre state = LOW\n"); +			if (btrssi >= (rssi_thresh + +				      BTC_RSSI_COEX_THRESH_TOL_8192E_2ANT)) { +				btrssi_state = BTC_RSSI_STATE_MEDIUM; +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, +					  "BT Rssi state switch to Medium\n"); +			} else { +				btrssi_state = BTC_RSSI_STATE_STAY_LOW; +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, +					  "BT Rssi state stay at Low\n"); +			} +		} else if ((coex_sta->pre_bt_rssi_state == +			    BTC_RSSI_STATE_MEDIUM) || +			   (coex_sta->pre_bt_rssi_state == +			    BTC_RSSI_STATE_STAY_MEDIUM)) { +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, +				  "[BTCoex], BT Rssi pre state = MEDIUM\n"); +			if (btrssi >= (rssi_thresh1 + +				       BTC_RSSI_COEX_THRESH_TOL_8192E_2ANT)) { +				btrssi_state = BTC_RSSI_STATE_HIGH; +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, +					  "BT Rssi state switch to High\n"); +			} else if (btrssi < rssi_thresh) { +				btrssi_state = BTC_RSSI_STATE_LOW; +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, +					  "BT Rssi state switch to Low\n"); +			} else { +				btrssi_state = BTC_RSSI_STATE_STAY_MEDIUM; +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, +					  "BT Rssi state stay at Medium\n"); +			} +		} else { +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, +				  "BT Rssi pre state = HIGH\n"); +			if (btrssi < rssi_thresh1) { +				btrssi_state = BTC_RSSI_STATE_MEDIUM; +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, +					  "BT Rssi state switch to Medium\n"); +			} else { +				btrssi_state = BTC_RSSI_STATE_STAY_HIGH; +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, +					  "BT Rssi state stay at High\n"); +			} +		} +	} + +	coex_sta->pre_bt_rssi_state = btrssi_state; + +	return btrssi_state; +} + +static u8 halbtc8192e2ant_wifirssi_state(struct btc_coexist *btcoexist, +					 u8 index, u8 level_num, u8 rssi_thresh, +					 u8 rssi_thresh1) +{ +	int wifirssi = 0; +	u8 wifirssi_state = coex_sta->pre_wifi_rssi_state[index]; + +	btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifirssi); + +	if (level_num == 2) { +		if ((coex_sta->pre_wifi_rssi_state[index] == +		     BTC_RSSI_STATE_LOW) || +		    (coex_sta->pre_wifi_rssi_state[index] == +		     BTC_RSSI_STATE_STAY_LOW)) { +			if (wifirssi >= (rssi_thresh + +					 BTC_RSSI_COEX_THRESH_TOL_8192E_2ANT)) { +				wifirssi_state = BTC_RSSI_STATE_HIGH; +				BTC_PRINT(BTC_MSG_ALGORITHM, +					  ALGO_WIFI_RSSI_STATE, +					  "wifi RSSI state switch to High\n"); +			} else { +				wifirssi_state = BTC_RSSI_STATE_STAY_LOW; +				BTC_PRINT(BTC_MSG_ALGORITHM, +					  ALGO_WIFI_RSSI_STATE, +					  "wifi RSSI state stay at Low\n"); +			} +		} else { +			if (wifirssi < rssi_thresh) { +				wifirssi_state = BTC_RSSI_STATE_LOW; +				BTC_PRINT(BTC_MSG_ALGORITHM, +					  ALGO_WIFI_RSSI_STATE, +					  "wifi RSSI state switch to Low\n"); +			} else { +				wifirssi_state = BTC_RSSI_STATE_STAY_HIGH; +				BTC_PRINT(BTC_MSG_ALGORITHM, +					  ALGO_WIFI_RSSI_STATE, +					  "wifi RSSI state stay at High\n"); +			} +		} +	} else if (level_num == 3) { +		if (rssi_thresh > rssi_thresh1) { +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, +				  "wifi RSSI thresh error!!\n"); +			return coex_sta->pre_wifi_rssi_state[index]; +		} + +		if ((coex_sta->pre_wifi_rssi_state[index] == +		     BTC_RSSI_STATE_LOW) || +		    (coex_sta->pre_wifi_rssi_state[index] == +		     BTC_RSSI_STATE_STAY_LOW)) { +			if (wifirssi >= (rssi_thresh + +					 BTC_RSSI_COEX_THRESH_TOL_8192E_2ANT)) { +				wifirssi_state = BTC_RSSI_STATE_MEDIUM; +				BTC_PRINT(BTC_MSG_ALGORITHM, +					  ALGO_WIFI_RSSI_STATE, +					  "wifi RSSI state switch to Medium\n"); +			} else { +				wifirssi_state = BTC_RSSI_STATE_STAY_LOW; +				BTC_PRINT(BTC_MSG_ALGORITHM, +					  ALGO_WIFI_RSSI_STATE, +					  "wifi RSSI state stay at Low\n"); +			} +		} else if ((coex_sta->pre_wifi_rssi_state[index] == +			    BTC_RSSI_STATE_MEDIUM) || +			   (coex_sta->pre_wifi_rssi_state[index] == +			    BTC_RSSI_STATE_STAY_MEDIUM)) { +			if (wifirssi >= (rssi_thresh1 + +					 BTC_RSSI_COEX_THRESH_TOL_8192E_2ANT)) { +				wifirssi_state = BTC_RSSI_STATE_HIGH; +				BTC_PRINT(BTC_MSG_ALGORITHM, +					  ALGO_WIFI_RSSI_STATE, +					  "wifi RSSI state switch to High\n"); +			} else if (wifirssi < rssi_thresh) { +				wifirssi_state = BTC_RSSI_STATE_LOW; +				BTC_PRINT(BTC_MSG_ALGORITHM, +					  ALGO_WIFI_RSSI_STATE, +					  "wifi RSSI state switch to Low\n"); +			} else { +				wifirssi_state = BTC_RSSI_STATE_STAY_MEDIUM; +				BTC_PRINT(BTC_MSG_ALGORITHM, +					  ALGO_WIFI_RSSI_STATE, +					  "wifi RSSI state stay at Medium\n"); +			} +		} else { +			if (wifirssi < rssi_thresh1) { +				wifirssi_state = BTC_RSSI_STATE_MEDIUM; +				BTC_PRINT(BTC_MSG_ALGORITHM, +					  ALGO_WIFI_RSSI_STATE, +					  "wifi RSSI state switch to Medium\n"); +			} else { +				wifirssi_state = BTC_RSSI_STATE_STAY_HIGH; +				BTC_PRINT(BTC_MSG_ALGORITHM, +					  ALGO_WIFI_RSSI_STATE, +					  "wifi RSSI state stay at High\n"); +			} +		} +	} + +	coex_sta->pre_wifi_rssi_state[index] = wifirssi_state; + +	return wifirssi_state; +} + +static void halbtc_monitor_bt_enable_disable(struct btc_coexist *btcoexist) +{ +	static bool pre_bt_disabled; +	static u32 bt_disable_cnt; +	bool bt_active = true, bt_disabled = false; + +	/* This function check if bt is disabled */ + +	if (coex_sta->high_priority_tx == 0 && +	    coex_sta->high_priority_rx == 0 && +	    coex_sta->low_priority_tx == 0 && +	    coex_sta->low_priority_rx == 0) +		bt_active = false; + +	if (coex_sta->high_priority_tx == 0xffff && +	    coex_sta->high_priority_rx == 0xffff && +	    coex_sta->low_priority_tx == 0xffff && +	    coex_sta->low_priority_rx == 0xffff) +		bt_active = false; + +	if (bt_active) { +		bt_disable_cnt = 0; +		bt_disabled = false; +		btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_DISABLE, +				   &bt_disabled); +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, +			  "[BTCoex], BT is enabled !!\n"); +	} else { +		bt_disable_cnt++; +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, +			  "[BTCoex], bt all counters = 0, %d times!!\n", +			  bt_disable_cnt); +		if (bt_disable_cnt >= 2) { +			bt_disabled = true; +			btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_DISABLE, +					   &bt_disabled); +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, +				  "[BTCoex], BT is disabled !!\n"); +		} +	} +	if (pre_bt_disabled != bt_disabled) { +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, +			  "[BTCoex], BT is from %s to %s!!\n", +			  (pre_bt_disabled ? "disabled" : "enabled"), +			  (bt_disabled ? "disabled" : "enabled")); +		pre_bt_disabled = bt_disabled; +	} +} + +static u32 halbtc8192e2ant_decidera_mask(struct btc_coexist *btcoexist, +					 u8 sstype, u32 ra_masktype) +{ +	u32 disra_mask = 0x0; + +	switch (ra_masktype) { +	case 0: /* normal mode */ +		if (sstype == 2) +			disra_mask = 0x0;	/* enable 2ss */ +		else +			disra_mask = 0xfff00000;/* disable 2ss */ +		break; +	case 1: /* disable cck 1/2 */ +		if (sstype == 2) +			disra_mask = 0x00000003;/* enable 2ss */ +		else +			disra_mask = 0xfff00003;/* disable 2ss */ +		break; +	case 2: /* disable cck 1/2/5.5, ofdm 6/9/12/18/24, mcs 0/1/2/3/4 */ +		if (sstype == 2) +			disra_mask = 0x0001f1f7;/* enable 2ss */ +		else +			disra_mask = 0xfff1f1f7;/* disable 2ss */ +		break; +	default: +		break; +	} + +	return disra_mask; +} + +static void halbtc8192e2ant_updatera_mask(struct btc_coexist *btcoexist, +					  bool force_exec, u32 dis_ratemask) +{ +	coex_dm->curra_mask = dis_ratemask; + +	if (force_exec || (coex_dm->prera_mask != coex_dm->curra_mask)) +		btcoexist->btc_set(btcoexist, BTC_SET_ACT_UPDATE_ra_mask, +				   &coex_dm->curra_mask); +	coex_dm->prera_mask = coex_dm->curra_mask; +} + +static void autorate_fallback_retry(struct btc_coexist *btcoexist, +				    bool force_exec, u8 type) +{ +	bool wifi_under_bmode = false; + +	coex_dm->cur_arfrtype = type; + +	if (force_exec || (coex_dm->pre_arfrtype != coex_dm->cur_arfrtype)) { +		switch (coex_dm->cur_arfrtype) { +		case 0:	/* normal mode */ +			btcoexist->btc_write_4byte(btcoexist, 0x430, +						   coex_dm->backup_arfr_cnt1); +			btcoexist->btc_write_4byte(btcoexist, 0x434, +						   coex_dm->backup_arfr_cnt2); +			break; +		case 1: +			btcoexist->btc_get(btcoexist, +					   BTC_GET_BL_WIFI_UNDER_B_MODE, +					   &wifi_under_bmode); +			if (wifi_under_bmode) { +				btcoexist->btc_write_4byte(btcoexist, 0x430, +							   0x0); +				btcoexist->btc_write_4byte(btcoexist, 0x434, +							   0x01010101); +			} else { +				btcoexist->btc_write_4byte(btcoexist, 0x430, +							   0x0); +				btcoexist->btc_write_4byte(btcoexist, 0x434, +							   0x04030201); +			} +			break; +		default: +			break; +		} +	} + +	coex_dm->pre_arfrtype = coex_dm->cur_arfrtype; +} + +static void halbtc8192e2ant_retrylimit(struct btc_coexist *btcoexist, +				       bool force_exec, u8 type) +{ +	coex_dm->cur_retrylimit_type = type; + +	if (force_exec || (coex_dm->pre_retrylimit_type != +			   coex_dm->cur_retrylimit_type)) { +		switch (coex_dm->cur_retrylimit_type) { +		case 0:	/* normal mode */ +			btcoexist->btc_write_2byte(btcoexist, 0x42a, +					    coex_dm->backup_retrylimit); +			break; +		case 1:	/* retry limit = 8 */ +			btcoexist->btc_write_2byte(btcoexist, 0x42a, +						   0x0808); +			break; +		default: +			break; +		} +	} + +	coex_dm->pre_retrylimit_type = coex_dm->cur_retrylimit_type; +} + +static void halbtc8192e2ant_ampdu_maxtime(struct btc_coexist *btcoexist, +					  bool force_exec, u8 type) +{ +	coex_dm->cur_ampdutime_type = type; + +	if (force_exec || (coex_dm->pre_ampdutime_type != +			   coex_dm->cur_ampdutime_type)) { +		switch (coex_dm->cur_ampdutime_type) { +		case 0:	/* normal mode */ +			btcoexist->btc_write_1byte(btcoexist, 0x456, +						coex_dm->backup_ampdu_maxtime); +			break; +		case 1:	/* AMPDU timw = 0x38 * 32us */ +			btcoexist->btc_write_1byte(btcoexist, 0x456, 0x38); +			break; +		default: +			break; +		} +	} + +	coex_dm->pre_ampdutime_type = coex_dm->cur_ampdutime_type; +} + +static void halbtc8192e2ant_limited_tx(struct btc_coexist *btcoexist, +				       bool force_exec, u8 ra_masktype, +				       u8 arfr_type, u8 retrylimit_type, +				       u8 ampdutime_type) +{ +	u32 disra_mask = 0x0; + +	coex_dm->curra_masktype = ra_masktype; +	disra_mask = halbtc8192e2ant_decidera_mask(btcoexist, +						   coex_dm->cur_sstype, +						   ra_masktype); +	halbtc8192e2ant_updatera_mask(btcoexist, force_exec, disra_mask); + +	autorate_fallback_retry(btcoexist, force_exec, arfr_type); +	halbtc8192e2ant_retrylimit(btcoexist, force_exec, retrylimit_type); +	halbtc8192e2ant_ampdu_maxtime(btcoexist, force_exec, ampdutime_type); +} + +static void halbtc8192e2ant_limited_rx(struct btc_coexist *btcoexist, +				       bool force_exec, bool rej_ap_agg_pkt, +				       bool b_bt_ctrl_agg_buf_size, +				       u8 agg_buf_size) +{ +	bool reject_rx_agg = rej_ap_agg_pkt; +	bool bt_ctrl_rx_agg_size = b_bt_ctrl_agg_buf_size; +	u8 rx_agg_size = agg_buf_size; + +	/********************************************* +	 *	Rx Aggregation related setting +	 *********************************************/ +	btcoexist->btc_set(btcoexist, BTC_SET_BL_TO_REJ_AP_AGG_PKT, +			   &reject_rx_agg); +	/* decide BT control aggregation buf size or not */ +	btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_CTRL_AGG_SIZE, +			   &bt_ctrl_rx_agg_size); +	/* aggregation buf size, only work +	 * when BT control Rx aggregation size. */ +	btcoexist->btc_set(btcoexist, BTC_SET_U1_AGG_BUF_SIZE, &rx_agg_size); +	/* real update aggregation setting */ +	btcoexist->btc_set(btcoexist, BTC_SET_ACT_AGGREGATE_CTRL, NULL); +} + +static void halbtc8192e2ant_monitor_bt_ctr(struct btc_coexist *btcoexist) +{ +	u32 reg_hp_txrx, reg_lp_txrx, u32tmp; +	u32 reg_hp_tx = 0, reg_hp_rx = 0, reg_lp_tx = 0, reg_lp_rx = 0; + +	reg_hp_txrx = 0x770; +	reg_lp_txrx = 0x774; + +	u32tmp = btcoexist->btc_read_4byte(btcoexist, reg_hp_txrx); +	reg_hp_tx = u32tmp & MASKLWORD; +	reg_hp_rx = (u32tmp & MASKHWORD)>>16; + +	u32tmp = btcoexist->btc_read_4byte(btcoexist, reg_lp_txrx); +	reg_lp_tx = u32tmp & MASKLWORD; +	reg_lp_rx = (u32tmp & MASKHWORD)>>16; + +	coex_sta->high_priority_tx = reg_hp_tx; +	coex_sta->high_priority_rx = reg_hp_rx; +	coex_sta->low_priority_tx = reg_lp_tx; +	coex_sta->low_priority_rx = reg_lp_rx; + +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, +		  "[BTCoex] High Priority Tx/Rx (reg 0x%x) = 0x%x(%d)/0x%x(%d)\n", +		  reg_hp_txrx, reg_hp_tx, reg_hp_tx, reg_hp_rx, reg_hp_rx); +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, +		  "[BTCoex] Low Priority Tx/Rx (reg 0x%x) = 0x%x(%d)/0x%x(%d)\n", +		  reg_lp_txrx, reg_lp_tx, reg_lp_tx, reg_lp_rx, reg_lp_rx); + +	/* reset counter */ +	btcoexist->btc_write_1byte(btcoexist, 0x76e, 0xc); +} + +static void halbtc8192e2ant_querybt_info(struct btc_coexist *btcoexist) +{ +	u8 h2c_parameter[1] = {0}; + +	coex_sta->c2h_bt_info_req_sent = true; + +	h2c_parameter[0] |= BIT(0);	/* trigger */ + +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, +		  "[BTCoex], Query Bt Info, FW write 0x61 = 0x%x\n", +		  h2c_parameter[0]); + +	btcoexist->btc_fill_h2c(btcoexist, 0x61, 1, h2c_parameter); +} + +static void halbtc8192e2ant_update_btlink_info(struct btc_coexist *btcoexist) +{ +	struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; +	bool bt_hson = false; + +	btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hson); + +	bt_link_info->bt_link_exist = coex_sta->bt_link_exist; +	bt_link_info->sco_exist = coex_sta->sco_exist; +	bt_link_info->a2dp_exist = coex_sta->a2dp_exist; +	bt_link_info->pan_exist = coex_sta->pan_exist; +	bt_link_info->hid_exist = coex_sta->hid_exist; + +	/* work around for HS mode. */ +	if (bt_hson) { +		bt_link_info->pan_exist = true; +		bt_link_info->bt_link_exist = true; +	} + +	/* check if Sco only */ +	if (bt_link_info->sco_exist && +	    !bt_link_info->a2dp_exist && +	    !bt_link_info->pan_exist && +	    !bt_link_info->hid_exist) +		bt_link_info->sco_only = true; +	else +		bt_link_info->sco_only = false; + +	/* check if A2dp only */ +	if (!bt_link_info->sco_exist && +	    bt_link_info->a2dp_exist && +	    !bt_link_info->pan_exist && +	    !bt_link_info->hid_exist) +		bt_link_info->a2dp_only = true; +	else +		bt_link_info->a2dp_only = false; + +	/* check if Pan only */ +	if (!bt_link_info->sco_exist && +	    !bt_link_info->a2dp_exist && +	    bt_link_info->pan_exist && +	    !bt_link_info->hid_exist) +		bt_link_info->pan_only = true; +	else +		bt_link_info->pan_only = false; + +	/* check if Hid only */ +	if (!bt_link_info->sco_exist && +	    !bt_link_info->a2dp_exist && +	    !bt_link_info->pan_exist && +	    bt_link_info->hid_exist) +		bt_link_info->hid_only = true; +	else +		bt_link_info->hid_only = false; +} + +static u8 halbtc8192e2ant_action_algorithm(struct btc_coexist *btcoexist) +{ +	struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; +	struct btc_stack_info *stack_info = &btcoexist->stack_info; +	bool bt_hson = false; +	u8 algorithm = BT_8192E_2ANT_COEX_ALGO_UNDEFINED; +	u8 num_diffprofile = 0; + +	btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hson); + +	if (!bt_link_info->bt_link_exist) { +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +			  "No BT link exists!!!\n"); +		return algorithm; +	} + +	if (bt_link_info->sco_exist) +		num_diffprofile++; +	if (bt_link_info->hid_exist) +		num_diffprofile++; +	if (bt_link_info->pan_exist) +		num_diffprofile++; +	if (bt_link_info->a2dp_exist) +		num_diffprofile++; + +	if (num_diffprofile == 1) { +		if (bt_link_info->sco_exist) { +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +				  "SCO only\n"); +			algorithm = BT_8192E_2ANT_COEX_ALGO_SCO; +		} else { +			if (bt_link_info->hid_exist) { +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +					  "HID only\n"); +				algorithm = BT_8192E_2ANT_COEX_ALGO_HID; +			} else if (bt_link_info->a2dp_exist) { +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +					  "A2DP only\n"); +				algorithm = BT_8192E_2ANT_COEX_ALGO_A2DP; +			} else if (bt_link_info->pan_exist) { +				if (bt_hson) { +					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +						  "PAN(HS) only\n"); +					algorithm = +						BT_8192E_2ANT_COEX_ALGO_PANHS; +				} else { +					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +						  "PAN(EDR) only\n"); +					algorithm = +						BT_8192E_2ANT_COEX_ALGO_PANEDR; +				} +			} +		} +	} else if (num_diffprofile == 2) { +		if (bt_link_info->sco_exist) { +			if (bt_link_info->hid_exist) { +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +					  "SCO + HID\n"); +				algorithm = BT_8192E_2ANT_COEX_ALGO_SCO; +			} else if (bt_link_info->a2dp_exist) { +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +					  "SCO + A2DP ==> SCO\n"); +				algorithm = BT_8192E_2ANT_COEX_ALGO_PANEDR_HID; +			} else if (bt_link_info->pan_exist) { +				if (bt_hson) { +					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +						  "SCO + PAN(HS)\n"); +					algorithm = BT_8192E_2ANT_COEX_ALGO_SCO; +				} else { +					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +						  "SCO + PAN(EDR)\n"); +					algorithm = +						BT_8192E_2ANT_COEX_ALGO_SCO_PAN; +				} +			} +		} else { +			if (bt_link_info->hid_exist && +			    bt_link_info->a2dp_exist) { +				if (stack_info->num_of_hid >= 2) { +					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +						  "HID*2 + A2DP\n"); +					algorithm = +					BT_8192E_2ANT_COEX_ALGO_HID_A2DP_PANEDR; +				} else { +					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +						  "HID + A2DP\n"); +					algorithm = +					    BT_8192E_2ANT_COEX_ALGO_HID_A2DP; +				} +			} else if (bt_link_info->hid_exist && +				   bt_link_info->pan_exist) { +				if (bt_hson) { +					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +						  "HID + PAN(HS)\n"); +					algorithm = BT_8192E_2ANT_COEX_ALGO_HID; +				} else { +					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +						  "HID + PAN(EDR)\n"); +					algorithm = +					    BT_8192E_2ANT_COEX_ALGO_PANEDR_HID; +				} +			} else if (bt_link_info->pan_exist && +				   bt_link_info->a2dp_exist) { +				if (bt_hson) { +					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +						  "A2DP + PAN(HS)\n"); +					algorithm = +					    BT_8192E_2ANT_COEX_ALGO_A2DP_PANHS; +				} else { +					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +						  "A2DP + PAN(EDR)\n"); +					algorithm = +					    BT_8192E_2ANT_COEX_ALGO_PANEDR_A2DP; +				} +			} +		} +	} else if (num_diffprofile == 3) { +		if (bt_link_info->sco_exist) { +			if (bt_link_info->hid_exist && +			    bt_link_info->a2dp_exist) { +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +					  "SCO + HID + A2DP ==> HID\n"); +				algorithm = BT_8192E_2ANT_COEX_ALGO_PANEDR_HID; +			} else if (bt_link_info->hid_exist && +				   bt_link_info->pan_exist) { +				if (bt_hson) { +					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +						  "SCO + HID + PAN(HS)\n"); +					algorithm = BT_8192E_2ANT_COEX_ALGO_SCO; +				} else { +					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +						  "SCO + HID + PAN(EDR)\n"); +					algorithm = +						BT_8192E_2ANT_COEX_ALGO_SCO_PAN; +				} +			} else if (bt_link_info->pan_exist && +				   bt_link_info->a2dp_exist) { +				if (bt_hson) { +					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +						  "SCO + A2DP + PAN(HS)\n"); +					algorithm = BT_8192E_2ANT_COEX_ALGO_SCO; +				} else { +					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +						  "SCO + A2DP + PAN(EDR)\n"); +					algorithm = +					    BT_8192E_2ANT_COEX_ALGO_PANEDR_HID; +				} +			} +		} else { +			if (bt_link_info->hid_exist && +			    bt_link_info->pan_exist && +			    bt_link_info->a2dp_exist) { +				if (bt_hson) { +					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +						  "HID + A2DP + PAN(HS)\n"); +					algorithm = +					    BT_8192E_2ANT_COEX_ALGO_HID_A2DP; +				} else { +					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +						  "HID + A2DP + PAN(EDR)\n"); +					algorithm = +					BT_8192E_2ANT_COEX_ALGO_HID_A2DP_PANEDR; +				} +			} +		} +	} else if (num_diffprofile >= 3) { +		if (bt_link_info->sco_exist) { +			if (bt_link_info->hid_exist && +			    bt_link_info->pan_exist && +			    bt_link_info->a2dp_exist) { +				if (bt_hson) { +					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +						  "ErrorSCO+HID+A2DP+PAN(HS)\n"); + +				} else { +					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +						  "SCO+HID+A2DP+PAN(EDR)\n"); +					algorithm = +					    BT_8192E_2ANT_COEX_ALGO_PANEDR_HID; +				} +			} +		} +	} + +	return algorithm; +} + +static void halbtc8192e2ant_setfw_dac_swinglevel(struct btc_coexist *btcoexist, +						 u8 dac_swinglvl) +{ +	u8 h2c_parameter[1] = {0}; + +	/* There are several type of dacswing +	 * 0x18/ 0x10/ 0xc/ 0x8/ 0x4/ 0x6 */ +	h2c_parameter[0] = dac_swinglvl; + +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, +		  "[BTCoex], Set Dac Swing Level = 0x%x\n", dac_swinglvl); +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, +		  "[BTCoex], FW write 0x64 = 0x%x\n", h2c_parameter[0]); + +	btcoexist->btc_fill_h2c(btcoexist, 0x64, 1, h2c_parameter); +} + +static void halbtc8192e2ant_set_fwdec_btpwr(struct btc_coexist *btcoexist, +					    u8 dec_btpwr_lvl) +{ +	u8 h2c_parameter[1] = {0}; + +	h2c_parameter[0] = dec_btpwr_lvl; + +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, +		  "[BTCoex] decrease Bt Power level = %d, FW write 0x62 = 0x%x\n", +		  dec_btpwr_lvl, h2c_parameter[0]); + +	btcoexist->btc_fill_h2c(btcoexist, 0x62, 1, h2c_parameter); +} + +static void halbtc8192e2ant_dec_btpwr(struct btc_coexist *btcoexist, +				      bool force_exec, u8 dec_btpwr_lvl) +{ +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, +		  "[BTCoex], %s Dec BT power level = %d\n", +		  (force_exec ? "force to" : ""), dec_btpwr_lvl); +	coex_dm->cur_dec_bt_pwr = dec_btpwr_lvl; + +	if (!force_exec) { +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, +			  "[BTCoex], preBtDecPwrLvl =%d, curBtDecPwrLvl =%d\n", +			  coex_dm->pre_dec_bt_pwr, coex_dm->cur_dec_bt_pwr); +	} +	halbtc8192e2ant_set_fwdec_btpwr(btcoexist, coex_dm->cur_dec_bt_pwr); + +	coex_dm->pre_dec_bt_pwr = coex_dm->cur_dec_bt_pwr; +} + +static void halbtc8192e2ant_set_bt_autoreport(struct btc_coexist *btcoexist, +					      bool enable_autoreport) +{ +	u8 h2c_parameter[1] = {0}; + +	h2c_parameter[0] = 0; + +	if (enable_autoreport) +		h2c_parameter[0] |= BIT(0); + +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, +		  "[BTCoex], BT FW auto report : %s, FW write 0x68 = 0x%x\n", +		  (enable_autoreport ? "Enabled!!" : "Disabled!!"), +		  h2c_parameter[0]); + +	btcoexist->btc_fill_h2c(btcoexist, 0x68, 1, h2c_parameter); +} + +static void halbtc8192e2ant_bt_autoreport(struct btc_coexist *btcoexist, +					  bool force_exec, +					  bool enable_autoreport) +{ +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, +		  "[BTCoex], %s BT Auto report = %s\n", +		  (force_exec ? "force to" : ""), +		  ((enable_autoreport) ? "Enabled" : "Disabled")); +	coex_dm->cur_bt_auto_report = enable_autoreport; + +	if (!force_exec) { +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, +			  "[BTCoex] bPreBtAutoReport =%d, bCurBtAutoReport =%d\n", +			  coex_dm->pre_bt_auto_report, +			  coex_dm->cur_bt_auto_report); + +		if (coex_dm->pre_bt_auto_report == coex_dm->cur_bt_auto_report) +			return; +	} +	halbtc8192e2ant_set_bt_autoreport(btcoexist, +					  coex_dm->cur_bt_auto_report); + +	coex_dm->pre_bt_auto_report = coex_dm->cur_bt_auto_report; +} + +static void halbtc8192e2ant_fw_dac_swinglvl(struct btc_coexist *btcoexist, +					    bool force_exec, u8 fw_dac_swinglvl) +{ +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, +		  "[BTCoex], %s set FW Dac Swing level = %d\n", +		  (force_exec ? "force to" : ""), fw_dac_swinglvl); +	coex_dm->cur_fw_dac_swing_lvl = fw_dac_swinglvl; + +	if (!force_exec) { +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, +			  "[BTCoex] preFwDacSwingLvl =%d, curFwDacSwingLvl =%d\n", +			  coex_dm->pre_fw_dac_swing_lvl, +			  coex_dm->cur_fw_dac_swing_lvl); + +		if (coex_dm->pre_fw_dac_swing_lvl == +		    coex_dm->cur_fw_dac_swing_lvl) +			return; +	} + +	halbtc8192e2ant_setfw_dac_swinglevel(btcoexist, +					     coex_dm->cur_fw_dac_swing_lvl); + +	coex_dm->pre_fw_dac_swing_lvl = coex_dm->cur_fw_dac_swing_lvl; +} + +static void set_sw_rf_rx_lpf_corner(struct btc_coexist *btcoexist, +				    bool rx_rf_shrink_on) +{ +	if (rx_rf_shrink_on) { +		/* Shrink RF Rx LPF corner */ +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, +			  "[BTCoex], Shrink RF Rx LPF corner!!\n"); +		btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1e, +					  0xfffff, 0xffffc); +	} else { +		/* Resume RF Rx LPF corner +		 * After initialized, we can use coex_dm->btRf0x1eBackup */ +		if (btcoexist->initilized) { +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, +				  "[BTCoex], Resume RF Rx LPF corner!!\n"); +			btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1e, +						  0xfffff, +						  coex_dm->bt_rf0x1e_backup); +		} +	} +} + +static void halbtc8192e2ant_rf_shrink(struct btc_coexist *btcoexist, +				      bool force_exec, bool rx_rf_shrink_on) +{ +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, +		  "[BTCoex], %s turn Rx RF Shrink = %s\n", +		  (force_exec ? "force to" : ""), +		  ((rx_rf_shrink_on) ? "ON" : "OFF")); +	coex_dm->cur_rf_rx_lpf_shrink = rx_rf_shrink_on; + +	if (!force_exec) { +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, +			  "[BTCoex]bPreRfRxLpfShrink =%d, bCurRfRxLpfShrink =%d\n", +			  coex_dm->pre_rf_rx_lpf_shrink, +			  coex_dm->cur_rf_rx_lpf_shrink); + +		if (coex_dm->pre_rf_rx_lpf_shrink == +		    coex_dm->cur_rf_rx_lpf_shrink) +			return; +	} +	set_sw_rf_rx_lpf_corner(btcoexist, coex_dm->cur_rf_rx_lpf_shrink); + +	coex_dm->pre_rf_rx_lpf_shrink = coex_dm->cur_rf_rx_lpf_shrink; +} + +static void halbtc8192e2ant_set_dac_swingreg(struct btc_coexist *btcoexist, +					     u32 level) +{ +	u8 val = (u8)level; + +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, +		  "[BTCoex], Write SwDacSwing = 0x%x\n", level); +	btcoexist->btc_write_1byte_bitmask(btcoexist, 0x883, 0x3e, val); +} + +static void setsw_fulltime_dacswing(struct btc_coexist *btcoexist, +				    bool sw_dac_swingon, +				    u32 sw_dac_swinglvl) +{ +	if (sw_dac_swingon) +		halbtc8192e2ant_set_dac_swingreg(btcoexist, sw_dac_swinglvl); +	else +		halbtc8192e2ant_set_dac_swingreg(btcoexist, 0x18); +} + +static void halbtc8192e2ant_dacswing(struct btc_coexist *btcoexist, +				     bool force_exec, bool dac_swingon, +				     u32 dac_swinglvl) +{ +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, +		  "[BTCoex], %s turn DacSwing =%s, dac_swinglvl = 0x%x\n", +		  (force_exec ? "force to" : ""), +		  ((dac_swingon) ? "ON" : "OFF"), dac_swinglvl); +	coex_dm->cur_dac_swing_on = dac_swingon; +	coex_dm->cur_dac_swing_lvl = dac_swinglvl; + +	if (!force_exec) { +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, +			  "[BTCoex], bPreDacSwingOn =%d, preDacSwingLvl = 0x%x, ", +			  coex_dm->pre_dac_swing_on, +			  coex_dm->pre_dac_swing_lvl); +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, +			  "bCurDacSwingOn =%d, curDacSwingLvl = 0x%x\n", +			  coex_dm->cur_dac_swing_on, +			  coex_dm->cur_dac_swing_lvl); + +		if ((coex_dm->pre_dac_swing_on == coex_dm->cur_dac_swing_on) && +		    (coex_dm->pre_dac_swing_lvl == coex_dm->cur_dac_swing_lvl)) +			return; +	} +	mdelay(30); +	setsw_fulltime_dacswing(btcoexist, dac_swingon, dac_swinglvl); + +	coex_dm->pre_dac_swing_on = coex_dm->cur_dac_swing_on; +	coex_dm->pre_dac_swing_lvl = coex_dm->cur_dac_swing_lvl; +} + +static void halbtc8192e2ant_set_agc_table(struct btc_coexist *btcoexist, +					  bool agc_table_en) +{ +	/* BB AGC Gain Table */ +	if (agc_table_en) { +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, +			  "[BTCoex], BB Agc Table On!\n"); +		btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x0a1A0001); +		btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x091B0001); +		btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x081C0001); +		btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x071D0001); +		btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x061E0001); +		btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x051F0001); +	} else { +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, +			  "[BTCoex], BB Agc Table Off!\n"); +		btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xaa1A0001); +		btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xa91B0001); +		btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xa81C0001); +		btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xa71D0001); +		btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xa61E0001); +		btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xa51F0001); +	} +} + +static void halbtc8192e2ant_agctable(struct btc_coexist *btcoexist, +				     bool force_exec, bool agc_table_en) +{ +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, +		  "[BTCoex], %s %s Agc Table\n", +		  (force_exec ? "force to" : ""), +		  ((agc_table_en) ? "Enable" : "Disable")); +	coex_dm->cur_agc_table_en = agc_table_en; + +	if (!force_exec) { +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, +			  "[BTCoex], bPreAgcTableEn =%d, bCurAgcTableEn =%d\n", +			  coex_dm->pre_agc_table_en, coex_dm->cur_agc_table_en); + +		if (coex_dm->pre_agc_table_en == coex_dm->cur_agc_table_en) +			return; +	} +	halbtc8192e2ant_set_agc_table(btcoexist, agc_table_en); + +	coex_dm->pre_agc_table_en = coex_dm->cur_agc_table_en; +} + +static void halbtc8192e2ant_set_coex_table(struct btc_coexist *btcoexist, +					   u32 val0x6c0, u32 val0x6c4, +					   u32 val0x6c8, u8 val0x6cc) +{ +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, +		  "[BTCoex], set coex table, set 0x6c0 = 0x%x\n", val0x6c0); +	btcoexist->btc_write_4byte(btcoexist, 0x6c0, val0x6c0); + +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, +		  "[BTCoex], set coex table, set 0x6c4 = 0x%x\n", val0x6c4); +	btcoexist->btc_write_4byte(btcoexist, 0x6c4, val0x6c4); + +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, +		  "[BTCoex], set coex table, set 0x6c8 = 0x%x\n", val0x6c8); +	btcoexist->btc_write_4byte(btcoexist, 0x6c8, val0x6c8); + +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, +		  "[BTCoex], set coex table, set 0x6cc = 0x%x\n", val0x6cc); +	btcoexist->btc_write_1byte(btcoexist, 0x6cc, val0x6cc); +} + +static void halbtc_coex_table(struct btc_coexist *btcoexist, bool force_exec, +			      u32 val0x6c0, u32 val0x6c4, +			      u32 val0x6c8, u8 val0x6cc) +{ +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, +		  "[BTCoex], %s write Coex Table 0x6c0 = 0x%x, ", +		  (force_exec ? "force to" : ""), val0x6c0); +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, +		  "0x6c4 = 0x%x, 0x6c8 = 0x%x, 0x6cc = 0x%x\n", +		  val0x6c4, val0x6c8, val0x6cc); +	coex_dm->cur_val0x6c0 = val0x6c0; +	coex_dm->cur_val0x6c4 = val0x6c4; +	coex_dm->cur_val0x6c8 = val0x6c8; +	coex_dm->cur_val0x6cc = val0x6cc; + +	if (!force_exec) { +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, +			  "[BTCoex], preVal0x6c0 = 0x%x, preVal0x6c4 = 0x%x, ", +			  coex_dm->pre_val0x6c0, coex_dm->pre_val0x6c4); +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, +			  "preVal0x6c8 = 0x%x, preVal0x6cc = 0x%x!!\n", +			  coex_dm->pre_val0x6c8, coex_dm->pre_val0x6cc); +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, +			  "[BTCoex], curVal0x6c0 = 0x%x, curVal0x6c4 = 0x%x\n", +			  coex_dm->cur_val0x6c0, coex_dm->cur_val0x6c4); +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, +			  "curVal0x6c8 = 0x%x, curVal0x6cc = 0x%x !!\n", +			  coex_dm->cur_val0x6c8, coex_dm->cur_val0x6cc); + +		if ((coex_dm->pre_val0x6c0 == coex_dm->cur_val0x6c0) && +		    (coex_dm->pre_val0x6c4 == coex_dm->cur_val0x6c4) && +		    (coex_dm->pre_val0x6c8 == coex_dm->cur_val0x6c8) && +		    (coex_dm->pre_val0x6cc == coex_dm->cur_val0x6cc)) +			return; +	} +	halbtc8192e2ant_set_coex_table(btcoexist, val0x6c0, val0x6c4, +				       val0x6c8, val0x6cc); + +	coex_dm->pre_val0x6c0 = coex_dm->cur_val0x6c0; +	coex_dm->pre_val0x6c4 = coex_dm->cur_val0x6c4; +	coex_dm->pre_val0x6c8 = coex_dm->cur_val0x6c8; +	coex_dm->pre_val0x6cc = coex_dm->cur_val0x6cc; +} + +static void halbtc_coex_table_with_type(struct btc_coexist *btcoexist, +					bool force_exec, u8 type) +{ +	switch (type) { +	case 0: +		halbtc_coex_table(btcoexist, force_exec, 0x55555555, +				  0x5a5a5a5a, 0xffffff, 0x3); +		break; +	case 1: +		halbtc_coex_table(btcoexist, force_exec, 0x5a5a5a5a, +				  0x5a5a5a5a, 0xffffff, 0x3); +		break; +	case 2: +		halbtc_coex_table(btcoexist, force_exec, 0x55555555, +				  0x5ffb5ffb, 0xffffff, 0x3); +		break; +	case 3: +		halbtc_coex_table(btcoexist, force_exec, 0xdfffdfff, +				  0x5fdb5fdb, 0xffffff, 0x3); +		break; +	case 4: +		halbtc_coex_table(btcoexist, force_exec, 0xdfffdfff, +				  0x5ffb5ffb, 0xffffff, 0x3); +		break; +	default: +		break; +	} +} + +static void halbtc8192e2ant_set_fw_ignore_wlanact(struct btc_coexist *btcoexist, +						  bool enable) +{ +	u8 h2c_parameter[1] = {0}; + +	if (enable) +		h2c_parameter[0] |= BIT(0); /* function enable */ + +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, +		  "[BTCoex]set FW for BT Ignore Wlan_Act, FW write 0x63 = 0x%x\n", +		  h2c_parameter[0]); + +	btcoexist->btc_fill_h2c(btcoexist, 0x63, 1, h2c_parameter); +} + +static void halbtc8192e2ant_ignorewlanact(struct btc_coexist *btcoexist, +					  bool force_exec, bool enable) +{ +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, +		  "[BTCoex], %s turn Ignore WlanAct %s\n", +		  (force_exec ? "force to" : ""), (enable ? "ON" : "OFF")); +	coex_dm->cur_ignore_wlan_act = enable; + +	if (!force_exec) { +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, +			  "[BTCoex], bPreIgnoreWlanAct = %d ", +			  coex_dm->pre_ignore_wlan_act); +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, +			  "bCurIgnoreWlanAct = %d!!\n", +			  coex_dm->cur_ignore_wlan_act); + +		if (coex_dm->pre_ignore_wlan_act == +		    coex_dm->cur_ignore_wlan_act) +			return; +	} +	halbtc8192e2ant_set_fw_ignore_wlanact(btcoexist, enable); + +	coex_dm->pre_ignore_wlan_act = coex_dm->cur_ignore_wlan_act; +} + +static void halbtc8192e2ant_setfwpstdma(struct btc_coexist *btcoexist, u8 byte1, +					u8 byte2, u8 byte3, u8 byte4, u8 byte5) +{ +	u8 h2c_parameter[5]; + +	h2c_parameter[0] = byte1; +	h2c_parameter[1] = byte2; +	h2c_parameter[2] = byte3; +	h2c_parameter[3] = byte4; +	h2c_parameter[4] = byte5; + +	coex_dm->ps_tdma_para[0] = byte1; +	coex_dm->ps_tdma_para[1] = byte2; +	coex_dm->ps_tdma_para[2] = byte3; +	coex_dm->ps_tdma_para[3] = byte4; +	coex_dm->ps_tdma_para[4] = byte5; + +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, +		  "[BTCoex], FW write 0x60(5bytes) = 0x%x%08x\n", +		  h2c_parameter[0], +		  h2c_parameter[1] << 24 | h2c_parameter[2] << 16 | +		  h2c_parameter[3] << 8 | h2c_parameter[4]); + +	btcoexist->btc_fill_h2c(btcoexist, 0x60, 5, h2c_parameter); +} + +static void halbtc_sw_mechanism1(struct btc_coexist *btcoexist, +				 bool shrink_rx_lpf, bool low_penalty_ra, +				 bool limited_dig, bool btlan_constrain) +{ +	halbtc8192e2ant_rf_shrink(btcoexist, NORMAL_EXEC, shrink_rx_lpf); +} + +static void halbtc_sw_mechanism2(struct btc_coexist *btcoexist, +				 bool agc_table_shift, bool adc_backoff, +				 bool sw_dac_swing, u32 dac_swinglvl) +{ +	halbtc8192e2ant_agctable(btcoexist, NORMAL_EXEC, agc_table_shift); +	halbtc8192e2ant_dacswing(btcoexist, NORMAL_EXEC, sw_dac_swing, +				 dac_swinglvl); +} + +static void halbtc8192e2ant_ps_tdma(struct btc_coexist *btcoexist, +				    bool force_exec, bool turn_on, u8 type) +{ +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, +		  "[BTCoex], %s turn %s PS TDMA, type =%d\n", +		  (force_exec ? "force to" : ""), +		  (turn_on ? "ON" : "OFF"), type); +	coex_dm->cur_ps_tdma_on = turn_on; +	coex_dm->cur_ps_tdma = type; + +	if (!force_exec) { +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, +			  "[BTCoex], bPrePsTdmaOn = %d, bCurPsTdmaOn = %d!!\n", +			  coex_dm->pre_ps_tdma_on, coex_dm->cur_ps_tdma_on); +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, +			  "[BTCoex], prePsTdma = %d, curPsTdma = %d!!\n", +			  coex_dm->pre_ps_tdma, coex_dm->cur_ps_tdma); + +		if ((coex_dm->pre_ps_tdma_on == coex_dm->cur_ps_tdma_on) && +		    (coex_dm->pre_ps_tdma == coex_dm->cur_ps_tdma)) +			return; +	} +	if (turn_on) { +		switch (type) { +		case 1: +		default: +			halbtc8192e2ant_setfwpstdma(btcoexist, 0xe3, 0x1a, +						    0x1a, 0xe1, 0x90); +			break; +		case 2: +			halbtc8192e2ant_setfwpstdma(btcoexist, 0xe3, 0x12, +						    0x12, 0xe1, 0x90); +			break; +		case 3: +			halbtc8192e2ant_setfwpstdma(btcoexist, 0xe3, 0x1c, +						    0x3, 0xf1, 0x90); +			break; +		case 4: +			halbtc8192e2ant_setfwpstdma(btcoexist, 0xe3, 0x10, +						    0x3, 0xf1, 0x90); +			break; +		case 5: +			halbtc8192e2ant_setfwpstdma(btcoexist, 0xe3, 0x1a, +						    0x1a, 0x60, 0x90); +			break; +		case 6: +			halbtc8192e2ant_setfwpstdma(btcoexist, 0xe3, 0x12, +						    0x12, 0x60, 0x90); +			break; +		case 7: +			halbtc8192e2ant_setfwpstdma(btcoexist, 0xe3, 0x1c, +						    0x3, 0x70, 0x90); +			break; +		case 8: +			halbtc8192e2ant_setfwpstdma(btcoexist, 0xa3, 0x10, +						    0x3, 0x70, 0x90); +			break; +		case 9: +			halbtc8192e2ant_setfwpstdma(btcoexist, 0xe3, 0x1a, +						    0x1a, 0xe1, 0x10); +			break; +		case 10: +			halbtc8192e2ant_setfwpstdma(btcoexist, 0xe3, 0x12, +						    0x12, 0xe1, 0x10); +			break; +		case 11: +			halbtc8192e2ant_setfwpstdma(btcoexist, 0xe3, 0x1c, +						    0x3, 0xf1, 0x10); +			break; +		case 12: +			halbtc8192e2ant_setfwpstdma(btcoexist, 0xe3, 0x10, +						    0x3, 0xf1, 0x10); +			break; +		case 13: +			halbtc8192e2ant_setfwpstdma(btcoexist, 0xe3, 0x1a, +						    0x1a, 0xe0, 0x10); +			break; +		case 14: +			halbtc8192e2ant_setfwpstdma(btcoexist, 0xe3, 0x12, +						    0x12, 0xe0, 0x10); +			break; +		case 15: +			halbtc8192e2ant_setfwpstdma(btcoexist, 0xe3, 0x1c, +						    0x3, 0xf0, 0x10); +			break; +		case 16: +			halbtc8192e2ant_setfwpstdma(btcoexist, 0xe3, 0x12, +						    0x3, 0xf0, 0x10); +			break; +		case 17: +			halbtc8192e2ant_setfwpstdma(btcoexist, 0x61, 0x20, +						    0x03, 0x10, 0x10); +			break; +		case 18: +			halbtc8192e2ant_setfwpstdma(btcoexist, 0xe3, 0x5, +						    0x5, 0xe1, 0x90); +			break; +		case 19: +			halbtc8192e2ant_setfwpstdma(btcoexist, 0xe3, 0x25, +						    0x25, 0xe1, 0x90); +			break; +		case 20: +			halbtc8192e2ant_setfwpstdma(btcoexist, 0xe3, 0x25, +						    0x25, 0x60, 0x90); +			break; +		case 21: +			halbtc8192e2ant_setfwpstdma(btcoexist, 0xe3, 0x15, +						    0x03, 0x70, 0x90); +			break; +		case 71: +			halbtc8192e2ant_setfwpstdma(btcoexist, 0xe3, 0x1a, +						    0x1a, 0xe1, 0x90); +			break; +		} +	} else { +		/* disable PS tdma */ +		switch (type) { +		default: +		case 0: +			halbtc8192e2ant_setfwpstdma(btcoexist, 0x8, 0x0, 0x0, +						    0x0, 0x0); +			btcoexist->btc_write_1byte(btcoexist, 0x92c, 0x4); +			break; +		case 1: +			halbtc8192e2ant_setfwpstdma(btcoexist, 0x0, 0x0, 0x0, +						    0x8, 0x0); +			mdelay(5); +			btcoexist->btc_write_1byte(btcoexist, 0x92c, 0x20); +			break; +		} +	} + +	/* update pre state */ +	coex_dm->pre_ps_tdma_on = coex_dm->cur_ps_tdma_on; +	coex_dm->pre_ps_tdma = coex_dm->cur_ps_tdma; +} + +static void set_switch_sstype(struct btc_coexist *btcoexist, u8 sstype) +{ +	u8 mimops = BTC_MIMO_PS_DYNAMIC; +	u32 disra_mask = 0x0; + +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +		  "[BTCoex], REAL set SS Type = %d\n", sstype); + +	disra_mask = halbtc8192e2ant_decidera_mask(btcoexist, sstype, +						   coex_dm->curra_masktype); +	halbtc8192e2ant_updatera_mask(btcoexist, FORCE_EXEC, disra_mask); + +	if (sstype == 1) { +		halbtc8192e2ant_ps_tdma(btcoexist, FORCE_EXEC, false, 1); +		/* switch ofdm path */ +		btcoexist->btc_write_1byte(btcoexist, 0xc04, 0x11); +		btcoexist->btc_write_1byte(btcoexist, 0xd04, 0x1); +		btcoexist->btc_write_4byte(btcoexist, 0x90c, 0x81111111); +		/* switch cck patch */ +		btcoexist->btc_write_1byte_bitmask(btcoexist, 0xe77, 0x4, 0x1); +		btcoexist->btc_write_1byte(btcoexist, 0xa07, 0x81); +		mimops = BTC_MIMO_PS_STATIC; +	} else if (sstype == 2) { +		halbtc8192e2ant_ps_tdma(btcoexist, FORCE_EXEC, false, 0); +		btcoexist->btc_write_1byte(btcoexist, 0xc04, 0x33); +		btcoexist->btc_write_1byte(btcoexist, 0xd04, 0x3); +		btcoexist->btc_write_4byte(btcoexist, 0x90c, 0x81121313); +		btcoexist->btc_write_1byte_bitmask(btcoexist, 0xe77, 0x4, 0x0); +		btcoexist->btc_write_1byte(btcoexist, 0xa07, 0x41); +		mimops = BTC_MIMO_PS_DYNAMIC; +	} +	/* set rx 1ss or 2ss */ +	btcoexist->btc_set(btcoexist, BTC_SET_ACT_SEND_MIMO_PS, &mimops); +} + +static void halbtc8192e2ant_switch_sstype(struct btc_coexist *btcoexist, +					  bool force_exec, u8 new_sstype) +{ +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +		  "[BTCoex], %s Switch SS Type = %d\n", +		  (force_exec ? "force to" : ""), new_sstype); +	coex_dm->cur_sstype = new_sstype; + +	if (!force_exec) { +		if (coex_dm->pre_sstype == coex_dm->cur_sstype) +			return; +	} +	set_switch_sstype(btcoexist, coex_dm->cur_sstype); + +	coex_dm->pre_sstype = coex_dm->cur_sstype; +} + +static void halbtc8192e2ant_coex_alloff(struct btc_coexist *btcoexist) +{ +	/* fw all off */ +	halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1); +	halbtc8192e2ant_fw_dac_swinglvl(btcoexist, NORMAL_EXEC, 6); +	halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0); + +	/* sw all off */ +	halbtc_sw_mechanism1(btcoexist, false, false, false, false); +	halbtc_sw_mechanism2(btcoexist, false, false, false, 0x18); + +	/* hw all off */ +	halbtc_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); +} + +static void halbtc8192e2ant_init_coex_dm(struct btc_coexist *btcoexist) +{ +	/* force to reset coex mechanism */ + +	halbtc8192e2ant_ps_tdma(btcoexist, FORCE_EXEC, false, 1); +	halbtc8192e2ant_fw_dac_swinglvl(btcoexist, FORCE_EXEC, 6); +	halbtc8192e2ant_dec_btpwr(btcoexist, FORCE_EXEC, 0); + +	halbtc_coex_table_with_type(btcoexist, FORCE_EXEC, 0); +	halbtc8192e2ant_switch_sstype(btcoexist, FORCE_EXEC, 2); + +	halbtc_sw_mechanism1(btcoexist, false, false, false, false); +	halbtc_sw_mechanism2(btcoexist, false, false, false, 0x18); +} + +static void halbtc8192e2ant_action_bt_inquiry(struct btc_coexist *btcoexist) +{ +	bool low_pwr_disable = true; + +	btcoexist->btc_set(btcoexist, BTC_SET_ACT_DISABLE_LOW_POWER, +			   &low_pwr_disable); + +	halbtc8192e2ant_switch_sstype(btcoexist, NORMAL_EXEC, 1); + +	halbtc_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); +	halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 3); +	halbtc8192e2ant_fw_dac_swinglvl(btcoexist, NORMAL_EXEC, 6); +	halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0); + +	halbtc_sw_mechanism1(btcoexist, false, false, false, false); +	halbtc_sw_mechanism2(btcoexist, false, false, false, 0x18); +} + +static bool halbtc8192e2ant_is_common_action(struct btc_coexist *btcoexist) +{ +	struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; +	bool common = false, wifi_connected = false, wifi_busy = false; +	bool bt_hson = false, low_pwr_disable = false; + +	btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hson); +	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, +			   &wifi_connected); +	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + +	if (bt_link_info->sco_exist || bt_link_info->hid_exist) +		halbtc8192e2ant_limited_tx(btcoexist, NORMAL_EXEC, 1, 0, 0, 0); +	else +		halbtc8192e2ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0); + +	if (!wifi_connected) { +		low_pwr_disable = false; +		btcoexist->btc_set(btcoexist, BTC_SET_ACT_DISABLE_LOW_POWER, +				   &low_pwr_disable); + +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +			  "[BTCoex], Wifi non-connected idle!!\n"); + +		if ((BT_8192E_2ANT_BT_STATUS_NON_CONNECTED_IDLE == +		     coex_dm->bt_status) || +		    (BT_8192E_2ANT_BT_STATUS_CONNECTED_IDLE == +		     coex_dm->bt_status)) { +			halbtc8192e2ant_switch_sstype(btcoexist, NORMAL_EXEC, +						      2); +			halbtc_coex_table_with_type(btcoexist, +						    NORMAL_EXEC, 1); +			halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, +						0); +		} else { +			halbtc8192e2ant_switch_sstype(btcoexist, +						      NORMAL_EXEC, 1); +			halbtc_coex_table_with_type(btcoexist, +						    NORMAL_EXEC, 0); +			halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, +						false, 1); +		} + +		halbtc8192e2ant_fw_dac_swinglvl(btcoexist, NORMAL_EXEC, 6); +		halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0); + +		halbtc_sw_mechanism1(btcoexist, false, false, false, +				     false); +		halbtc_sw_mechanism2(btcoexist, false, false, false, +				     0x18); + +		common = true; +	} else { +		if (BT_8192E_2ANT_BT_STATUS_NON_CONNECTED_IDLE == +		    coex_dm->bt_status) { +			low_pwr_disable = false; +			btcoexist->btc_set(btcoexist, +					   BTC_SET_ACT_DISABLE_LOW_POWER, +					   &low_pwr_disable); + +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +				  "Wifi connected + BT non connected-idle!!\n"); + +			halbtc8192e2ant_switch_sstype(btcoexist, +						      NORMAL_EXEC, 2); +			halbtc_coex_table_with_type(btcoexist, +						    NORMAL_EXEC, 1); +			halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, +						false, 0); +			halbtc8192e2ant_fw_dac_swinglvl(btcoexist, NORMAL_EXEC, +							6); +			halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0); + +			halbtc_sw_mechanism1(btcoexist, false, false, +					     false, false); +			halbtc_sw_mechanism2(btcoexist, false, false, +					     false, 0x18); + +			common = true; +		} else if (BT_8192E_2ANT_BT_STATUS_CONNECTED_IDLE == +			   coex_dm->bt_status) { +			low_pwr_disable = true; +			btcoexist->btc_set(btcoexist, +					   BTC_SET_ACT_DISABLE_LOW_POWER, +					   &low_pwr_disable); + +			if (bt_hson) +				return false; +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +				  "Wifi connected + BT connected-idle!!\n"); + +			halbtc8192e2ant_switch_sstype(btcoexist, NORMAL_EXEC, +						      2); +			halbtc_coex_table_with_type(btcoexist, +						    NORMAL_EXEC, 1); +			halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, +						false, 0); +			halbtc8192e2ant_fw_dac_swinglvl(btcoexist, +							NORMAL_EXEC, 6); +			halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0); + +			halbtc_sw_mechanism1(btcoexist, true, false, +					     false, false); +			halbtc_sw_mechanism2(btcoexist, false, false, +					     false, 0x18); + +			common = true; +		} else { +			low_pwr_disable = true; +			btcoexist->btc_set(btcoexist, +					   BTC_SET_ACT_DISABLE_LOW_POWER, +					   &low_pwr_disable); + +			if (wifi_busy) { +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +					  "Wifi Connected-Busy + BT Busy!!\n"); +				common = false; +			} else { +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +					  "Wifi Connected-Idle + BT Busy!!\n"); + +				halbtc8192e2ant_switch_sstype(btcoexist, +							      NORMAL_EXEC, 1); +				halbtc_coex_table_with_type(btcoexist, +							    NORMAL_EXEC, 2); +				halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, +							true, 21); +				halbtc8192e2ant_fw_dac_swinglvl(btcoexist, +								NORMAL_EXEC, 6); +				halbtc8192e2ant_dec_btpwr(btcoexist, +							  NORMAL_EXEC, 0); +				halbtc_sw_mechanism1(btcoexist, false, +						     false, false, +						     false); +				halbtc_sw_mechanism2(btcoexist, false, +						     false, false, +						     0x18); +				common = true; +			} +		} +	} +	return common; +} + +static void halbtc8192e2ant_tdma_duration_adjust(struct btc_coexist *btcoexist, +						 bool sco_hid, bool tx_pause, +						 u8 max_interval) +{ +	static int up, dn, m, n, wait_cnt; +	/* 0: no change, +1: increase WiFi duration, +	 * -1: decrease WiFi duration */ +	int result; +	u8 retry_cnt = 0; + +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, +		  "[BTCoex], TdmaDurationAdjust()\n"); + +	if (!coex_dm->auto_tdma_adjust) { +		coex_dm->auto_tdma_adjust = true; +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, +			  "[BTCoex], first run TdmaDurationAdjust()!!\n"); +		if (sco_hid) { +			if (tx_pause) { +				if (max_interval == 1) { +					halbtc8192e2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 13); +					coex_dm->ps_tdma_du_adj_type = 13; +				} else if (max_interval == 2) { +					halbtc8192e2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 14); +					coex_dm->ps_tdma_du_adj_type = 14; +				} else if (max_interval == 3) { +					halbtc8192e2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 15); +					coex_dm->ps_tdma_du_adj_type = 15; +				} else { +					halbtc8192e2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 15); +					coex_dm->ps_tdma_du_adj_type = 15; +				} +			} else { +				if (max_interval == 1) { +					halbtc8192e2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 9); +					coex_dm->ps_tdma_du_adj_type = 9; +				} else if (max_interval == 2) { +					halbtc8192e2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 10); +					coex_dm->ps_tdma_du_adj_type = 10; +				} else if (max_interval == 3) { +					halbtc8192e2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 11); +					coex_dm->ps_tdma_du_adj_type = 11; +				} else { +					halbtc8192e2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 11); +					coex_dm->ps_tdma_du_adj_type = 11; +				} +			} +		} else { +			if (tx_pause) { +				if (max_interval == 1) { +					halbtc8192e2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 5); +					coex_dm->ps_tdma_du_adj_type = 5; +				} else if (max_interval == 2) { +					halbtc8192e2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 6); +					coex_dm->ps_tdma_du_adj_type = 6; +				} else if (max_interval == 3) { +					halbtc8192e2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 7); +					coex_dm->ps_tdma_du_adj_type = 7; +				} else { +					halbtc8192e2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 7); +					coex_dm->ps_tdma_du_adj_type = 7; +				} +			} else { +				if (max_interval == 1) { +					halbtc8192e2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 1); +					coex_dm->ps_tdma_du_adj_type = 1; +				} else if (max_interval == 2) { +					halbtc8192e2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 2); +					coex_dm->ps_tdma_du_adj_type = 2; +				} else if (max_interval == 3) { +					halbtc8192e2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 3); +					coex_dm->ps_tdma_du_adj_type = 3; +				} else { +					halbtc8192e2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 3); +					coex_dm->ps_tdma_du_adj_type = 3; +				} +			} +		} + +		up = 0; +		dn = 0; +		m = 1; +		n = 3; +		result = 0; +		wait_cnt = 0; +	} else { +		/* accquire the BT TRx retry count from BT_Info byte2 */ +		retry_cnt = coex_sta->bt_retry_cnt; +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, +			  "[BTCoex], retry_cnt = %d\n", retry_cnt); +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, +			  "[BTCoex], up =%d, dn =%d, m =%d, n =%d, wait_cnt =%d\n", +			  up, dn, m, n, wait_cnt); +		result = 0; +		wait_cnt++; +		/* no retry in the last 2-second duration */ +		if (retry_cnt == 0) { +			up++; +			dn--; + +			if (dn <= 0) +				dn = 0; + +			if (up >= n) { +				wait_cnt = 0; +				n = 3; +				up = 0; +				dn = 0; +				result = 1; +				BTC_PRINT(BTC_MSG_ALGORITHM, +					  ALGO_TRACE_FW_DETAIL, +					  "[BTCoex]Increase wifi duration!!\n"); +			} +		} else if (retry_cnt <= 3) { +			up--; +			dn++; + +			if (up <= 0) +				up = 0; + +			if (dn == 2) { +				if (wait_cnt <= 2) +					m++; +				else +					m = 1; + +				if (m >= 20) +					m = 20; + +				n = 3 * m; +				up = 0; +				dn = 0; +				wait_cnt = 0; +				result = -1; +				BTC_PRINT(BTC_MSG_ALGORITHM, +					  ALGO_TRACE_FW_DETAIL, +					  "Reduce wifi duration for retry<3\n"); +			} +		} else { +			if (wait_cnt == 1) +				m++; +			else +				m = 1; + +			if (m >= 20) +				m = 20; + +			n = 3*m; +			up = 0; +			dn = 0; +			wait_cnt = 0; +			result = -1; +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, +				  "Decrease wifi duration for retryCounter>3!!\n"); +		} + +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, +			  "[BTCoex], max Interval = %d\n", max_interval); +		if (max_interval == 1) { +			if (tx_pause) { +				BTC_PRINT(BTC_MSG_ALGORITHM, +					  ALGO_TRACE_FW_DETAIL, +					  "[BTCoex], TxPause = 1\n"); + +				if (coex_dm->cur_ps_tdma == 71) { +					halbtc8192e2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 5); +					coex_dm->ps_tdma_du_adj_type = 5; +				} else if (coex_dm->cur_ps_tdma == 1) { +					halbtc8192e2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 5); +					coex_dm->ps_tdma_du_adj_type = 5; +				} else if (coex_dm->cur_ps_tdma == 2) { +					halbtc8192e2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 6); +					coex_dm->ps_tdma_du_adj_type = 6; +				} else if (coex_dm->cur_ps_tdma == 3) { +					halbtc8192e2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 7); +					coex_dm->ps_tdma_du_adj_type = 7; +				} else if (coex_dm->cur_ps_tdma == 4) { +					halbtc8192e2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 8); +					coex_dm->ps_tdma_du_adj_type = 8; +				} +				if (coex_dm->cur_ps_tdma == 9) { +					halbtc8192e2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 13); +					coex_dm->ps_tdma_du_adj_type = 13; +				} else if (coex_dm->cur_ps_tdma == 10) { +					halbtc8192e2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 14); +					coex_dm->ps_tdma_du_adj_type = 14; +				} else if (coex_dm->cur_ps_tdma == 11) { +					halbtc8192e2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 15); +					coex_dm->ps_tdma_du_adj_type = 15; +				} else if (coex_dm->cur_ps_tdma == 12) { +					halbtc8192e2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 16); +					coex_dm->ps_tdma_du_adj_type = 16; +				} + +				if (result == -1) { +					if (coex_dm->cur_ps_tdma == 5) { +						halbtc8192e2ant_ps_tdma( +								    btcoexist, +								    NORMAL_EXEC, +								    true, 6); +						coex_dm->ps_tdma_du_adj_type = +									     6; +					} else if (coex_dm->cur_ps_tdma == 6) { +						halbtc8192e2ant_ps_tdma( +								    btcoexist, +								    NORMAL_EXEC, +								    true, 7); +						coex_dm->ps_tdma_du_adj_type = +									     7; +					} else if (coex_dm->cur_ps_tdma == 7) { +						halbtc8192e2ant_ps_tdma( +								    btcoexist, +								    NORMAL_EXEC, +								    true, 8); +						coex_dm->ps_tdma_du_adj_type = +									     8; +					} else if (coex_dm->cur_ps_tdma == 13) { +						halbtc8192e2ant_ps_tdma( +								    btcoexist, +								    NORMAL_EXEC, +								    true, 14); +						coex_dm->ps_tdma_du_adj_type = +									     14; +					} else if (coex_dm->cur_ps_tdma == 14) { +						halbtc8192e2ant_ps_tdma( +								    btcoexist, +								    NORMAL_EXEC, +								    true, 15); +						coex_dm->ps_tdma_du_adj_type = +									     15; +					} else if (coex_dm->cur_ps_tdma == 15) { +						halbtc8192e2ant_ps_tdma( +								    btcoexist, +								    NORMAL_EXEC, +								    true, 16); +						coex_dm->ps_tdma_du_adj_type = +									     16; +					} +				} else if (result == 1) { +					if (coex_dm->cur_ps_tdma == 8) { +						halbtc8192e2ant_ps_tdma( +								    btcoexist, +								    NORMAL_EXEC, +								    true, 7); +						coex_dm->ps_tdma_du_adj_type = +									     7; +					} else if (coex_dm->cur_ps_tdma == 7) { +						halbtc8192e2ant_ps_tdma( +								    btcoexist, +								    NORMAL_EXEC, +								    true, 6); +						coex_dm->ps_tdma_du_adj_type = +									     6; +					} else if (coex_dm->cur_ps_tdma == 6) { +						halbtc8192e2ant_ps_tdma( +								    btcoexist, +								    NORMAL_EXEC, +								    true, 5); +						coex_dm->ps_tdma_du_adj_type = +									     5; +					} else if (coex_dm->cur_ps_tdma == 16) { +						halbtc8192e2ant_ps_tdma( +								    btcoexist, +								    NORMAL_EXEC, +								    true, 15); +						coex_dm->ps_tdma_du_adj_type = +									     15; +					} else if (coex_dm->cur_ps_tdma == 15) { +						halbtc8192e2ant_ps_tdma( +								    btcoexist, +								    NORMAL_EXEC, +								    true, 14); +						coex_dm->ps_tdma_du_adj_type = +									     14; +					} else if (coex_dm->cur_ps_tdma == 14) { +						halbtc8192e2ant_ps_tdma( +								    btcoexist, +								    NORMAL_EXEC, +								    true, 13); +						coex_dm->ps_tdma_du_adj_type = +									     13; +					} +				} +			} else { +				BTC_PRINT(BTC_MSG_ALGORITHM, +					  ALGO_TRACE_FW_DETAIL, +					  "[BTCoex], TxPause = 0\n"); +				if (coex_dm->cur_ps_tdma == 5) { +					halbtc8192e2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 71); +					coex_dm->ps_tdma_du_adj_type = 71; +				} else if (coex_dm->cur_ps_tdma == 6) { +					halbtc8192e2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 2); +					coex_dm->ps_tdma_du_adj_type = 2; +				} else if (coex_dm->cur_ps_tdma == 7) { +					halbtc8192e2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 3); +					coex_dm->ps_tdma_du_adj_type = 3; +				} else if (coex_dm->cur_ps_tdma == 8) { +					halbtc8192e2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 4); +					coex_dm->ps_tdma_du_adj_type = 4; +				} +				if (coex_dm->cur_ps_tdma == 13) { +					halbtc8192e2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 9); +					coex_dm->ps_tdma_du_adj_type = 9; +				} else if (coex_dm->cur_ps_tdma == 14) { +					halbtc8192e2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 10); +					coex_dm->ps_tdma_du_adj_type = 10; +				} else if (coex_dm->cur_ps_tdma == 15) { +					halbtc8192e2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 11); +					coex_dm->ps_tdma_du_adj_type = 11; +				} else if (coex_dm->cur_ps_tdma == 16) { +					halbtc8192e2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 12); +					coex_dm->ps_tdma_du_adj_type = 12; +				} + +				if (result == -1) { +					if (coex_dm->cur_ps_tdma == 71) { +						halbtc8192e2ant_ps_tdma( +								    btcoexist, +								    NORMAL_EXEC, +								    true, 1); +						coex_dm->ps_tdma_du_adj_type = +									     1; +					} else if (coex_dm->cur_ps_tdma == 1) { +						halbtc8192e2ant_ps_tdma( +								    btcoexist, +								    NORMAL_EXEC, +								    true, 2); +						coex_dm->ps_tdma_du_adj_type = +									     2; +					} else if (coex_dm->cur_ps_tdma == 2) { +						halbtc8192e2ant_ps_tdma( +								    btcoexist, +								    NORMAL_EXEC, +								    true, 3); +						coex_dm->ps_tdma_du_adj_type = +									     3; +					} else if (coex_dm->cur_ps_tdma == 3) { +						halbtc8192e2ant_ps_tdma( +								    btcoexist, +								    NORMAL_EXEC, +								    true, 4); +						coex_dm->ps_tdma_du_adj_type = +									     4; +					} else if (coex_dm->cur_ps_tdma == 9) { +						halbtc8192e2ant_ps_tdma( +								    btcoexist, +								    NORMAL_EXEC, +								    true, 10); +						coex_dm->ps_tdma_du_adj_type = +									     10; +					} else if (coex_dm->cur_ps_tdma == 10) { +						halbtc8192e2ant_ps_tdma( +								    btcoexist, +								    NORMAL_EXEC, +								    true, 11); +						coex_dm->ps_tdma_du_adj_type = +									     11; +					} else if (coex_dm->cur_ps_tdma == 11) { +						halbtc8192e2ant_ps_tdma( +								    btcoexist, +								    NORMAL_EXEC, +								    true, 12); +						coex_dm->ps_tdma_du_adj_type = +									     12; +					} +				} else if (result == 1) { +					if (coex_dm->cur_ps_tdma == 4) { +						halbtc8192e2ant_ps_tdma( +								    btcoexist, +								    NORMAL_EXEC, +								    true, 3); +						coex_dm->ps_tdma_du_adj_type = +									     3; +					} else if (coex_dm->cur_ps_tdma == 3) { +						halbtc8192e2ant_ps_tdma( +								    btcoexist, +								    NORMAL_EXEC, +								    true, 2); +						coex_dm->ps_tdma_du_adj_type = +									     2; +					} else if (coex_dm->cur_ps_tdma == 2) { +						halbtc8192e2ant_ps_tdma( +								    btcoexist, +								    NORMAL_EXEC, +								    true, 1); +						coex_dm->ps_tdma_du_adj_type = +									     1; +					} else if (coex_dm->cur_ps_tdma == 1) { +						halbtc8192e2ant_ps_tdma( +								    btcoexist, +								    NORMAL_EXEC, +								    true, 71); +						coex_dm->ps_tdma_du_adj_type = +									     71; +					} else if (coex_dm->cur_ps_tdma == 12) { +						halbtc8192e2ant_ps_tdma( +								    btcoexist, +								    NORMAL_EXEC, +								    true, 11); +						coex_dm->ps_tdma_du_adj_type = +									     11; +					} else if (coex_dm->cur_ps_tdma == 11) { +						halbtc8192e2ant_ps_tdma( +								    btcoexist, +								    NORMAL_EXEC, +								    true, 10); +						coex_dm->ps_tdma_du_adj_type = +									     10; +					} else if (coex_dm->cur_ps_tdma == 10) { +						halbtc8192e2ant_ps_tdma( +								    btcoexist, +								    NORMAL_EXEC, +								    true, 9); +						coex_dm->ps_tdma_du_adj_type = +									     9; +					} +				} +			} +		} else if (max_interval == 2) { +			if (tx_pause) { +				BTC_PRINT(BTC_MSG_ALGORITHM, +					  ALGO_TRACE_FW_DETAIL, +					  "[BTCoex], TxPause = 1\n"); +				if (coex_dm->cur_ps_tdma == 1) { +					halbtc8192e2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 6); +					coex_dm->ps_tdma_du_adj_type = 6; +				} else if (coex_dm->cur_ps_tdma == 2) { +					halbtc8192e2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 6); +					coex_dm->ps_tdma_du_adj_type = 6; +				} else if (coex_dm->cur_ps_tdma == 3) { +					halbtc8192e2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 7); +					coex_dm->ps_tdma_du_adj_type = 7; +				} else if (coex_dm->cur_ps_tdma == 4) { +					halbtc8192e2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 8); +					coex_dm->ps_tdma_du_adj_type = 8; +				} +				if (coex_dm->cur_ps_tdma == 9) { +					halbtc8192e2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 14); +					coex_dm->ps_tdma_du_adj_type = 14; +				} else if (coex_dm->cur_ps_tdma == 10) { +					halbtc8192e2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 14); +					coex_dm->ps_tdma_du_adj_type = 14; +				} else if (coex_dm->cur_ps_tdma == 11) { +					halbtc8192e2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 15); +					coex_dm->ps_tdma_du_adj_type = 15; +				} else if (coex_dm->cur_ps_tdma == 12) { +					halbtc8192e2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 16); +					coex_dm->ps_tdma_du_adj_type = 16; +				} +				if (result == -1) { +					if (coex_dm->cur_ps_tdma == 5) { +						halbtc8192e2ant_ps_tdma( +								    btcoexist, +								    NORMAL_EXEC, +								    true, 6); +						coex_dm->ps_tdma_du_adj_type = +									     6; +					} else if (coex_dm->cur_ps_tdma == 6) { +						halbtc8192e2ant_ps_tdma( +								    btcoexist, +								    NORMAL_EXEC, +								    true, 7); +						coex_dm->ps_tdma_du_adj_type = +									     7; +					} else if (coex_dm->cur_ps_tdma == 7) { +						halbtc8192e2ant_ps_tdma( +								    btcoexist, +								    NORMAL_EXEC, +								    true, 8); +						coex_dm->ps_tdma_du_adj_type = +									     8; +					} else if (coex_dm->cur_ps_tdma == 13) { +						halbtc8192e2ant_ps_tdma( +								    btcoexist, +								    NORMAL_EXEC, +								    true, 14); +						coex_dm->ps_tdma_du_adj_type = +									     14; +					} else if (coex_dm->cur_ps_tdma == 14) { +						halbtc8192e2ant_ps_tdma( +								    btcoexist, +								    NORMAL_EXEC, +								    true, 15); +						coex_dm->ps_tdma_du_adj_type = +									     15; +					} else if (coex_dm->cur_ps_tdma == 15) { +						halbtc8192e2ant_ps_tdma( +								    btcoexist, +								    NORMAL_EXEC, +								    true, 16); +						coex_dm->ps_tdma_du_adj_type = +									     16; +					} +				} else if (result == 1) { +					if (coex_dm->cur_ps_tdma == 8) { +						halbtc8192e2ant_ps_tdma( +								    btcoexist, +								    NORMAL_EXEC, +								    true, 7); +						coex_dm->ps_tdma_du_adj_type = +									     7; +					} else if (coex_dm->cur_ps_tdma == 7) { +						halbtc8192e2ant_ps_tdma( +								    btcoexist, +								    NORMAL_EXEC, +								    true, 6); +						coex_dm->ps_tdma_du_adj_type = +									     6; +					} else if (coex_dm->cur_ps_tdma == 6) { +						halbtc8192e2ant_ps_tdma( +								    btcoexist, +								    NORMAL_EXEC, +								    true, 6); +						coex_dm->ps_tdma_du_adj_type = +									     6; +					} else if (coex_dm->cur_ps_tdma == 16) { +						halbtc8192e2ant_ps_tdma( +								    btcoexist, +								    NORMAL_EXEC, +								    true, 15); +						coex_dm->ps_tdma_du_adj_type = +									     15; +					} else if (coex_dm->cur_ps_tdma == 15) { +						halbtc8192e2ant_ps_tdma( +								    btcoexist, +								    NORMAL_EXEC, +								    true, 14); +						coex_dm->ps_tdma_du_adj_type = +									     14; +					} else if (coex_dm->cur_ps_tdma == 14) { +						halbtc8192e2ant_ps_tdma( +								    btcoexist, +								    NORMAL_EXEC, +								    true, 14); +						coex_dm->ps_tdma_du_adj_type = +									     14; +					} +				} +			} else { +				BTC_PRINT(BTC_MSG_ALGORITHM, +					  ALGO_TRACE_FW_DETAIL, +					  "[BTCoex], TxPause = 0\n"); +				if (coex_dm->cur_ps_tdma == 5) { +					halbtc8192e2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 2); +					coex_dm->ps_tdma_du_adj_type = 2; +				} else if (coex_dm->cur_ps_tdma == 6) { +					halbtc8192e2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 2); +					coex_dm->ps_tdma_du_adj_type = 2; +				} else if (coex_dm->cur_ps_tdma == 7) { +					halbtc8192e2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 3); +					coex_dm->ps_tdma_du_adj_type = 3; +				} else if (coex_dm->cur_ps_tdma == 8) { +					halbtc8192e2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 4); +					coex_dm->ps_tdma_du_adj_type = 4; +				} +				if (coex_dm->cur_ps_tdma == 13) { +					halbtc8192e2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 10); +					coex_dm->ps_tdma_du_adj_type = 10; +				} else if (coex_dm->cur_ps_tdma == 14) { +					halbtc8192e2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 10); +					coex_dm->ps_tdma_du_adj_type = 10; +				} else if (coex_dm->cur_ps_tdma == 15) { +					halbtc8192e2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 11); +					coex_dm->ps_tdma_du_adj_type = 11; +				} else if (coex_dm->cur_ps_tdma == 16) { +					halbtc8192e2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 12); +					coex_dm->ps_tdma_du_adj_type = 12; +				} +				if (result == -1) { +					if (coex_dm->cur_ps_tdma == 1) { +						halbtc8192e2ant_ps_tdma( +								    btcoexist, +								    NORMAL_EXEC, +								    true, 2); +						coex_dm->ps_tdma_du_adj_type = +									     2; +					} else if (coex_dm->cur_ps_tdma == 2) { +						halbtc8192e2ant_ps_tdma( +								    btcoexist, +								    NORMAL_EXEC, +								    true, 3); +						coex_dm->ps_tdma_du_adj_type = +									     3; +					} else if (coex_dm->cur_ps_tdma == 3) { +						halbtc8192e2ant_ps_tdma( +								    btcoexist, +								    NORMAL_EXEC, +								    true, 4); +						coex_dm->ps_tdma_du_adj_type = +									     4; +					} else if (coex_dm->cur_ps_tdma == 9) { +						halbtc8192e2ant_ps_tdma( +								    btcoexist, +								    NORMAL_EXEC, +								    true, 10); +						coex_dm->ps_tdma_du_adj_type = +									     10; +					} else if (coex_dm->cur_ps_tdma == 10) { +						halbtc8192e2ant_ps_tdma( +								    btcoexist, +								    NORMAL_EXEC, +								    true, 11); +						coex_dm->ps_tdma_du_adj_type = +									     11; +					} else if (coex_dm->cur_ps_tdma == 11) { +						halbtc8192e2ant_ps_tdma( +								    btcoexist, +								    NORMAL_EXEC, +								    true, 12); +						coex_dm->ps_tdma_du_adj_type = +									     12; +					} +				} else if (result == 1) { +					if (coex_dm->cur_ps_tdma == 4) { +						halbtc8192e2ant_ps_tdma( +								    btcoexist, +								    NORMAL_EXEC, +								    true, 3); +						coex_dm->ps_tdma_du_adj_type = +									     3; +					} else if (coex_dm->cur_ps_tdma == 3) { +						halbtc8192e2ant_ps_tdma( +								    btcoexist, +								    NORMAL_EXEC, +								    true, 2); +						coex_dm->ps_tdma_du_adj_type = +									     2; +					} else if (coex_dm->cur_ps_tdma == 2) { +						halbtc8192e2ant_ps_tdma( +								    btcoexist, +								    NORMAL_EXEC, +								    true, 2); +						coex_dm->ps_tdma_du_adj_type = +									     2; +					} else if (coex_dm->cur_ps_tdma == 12) { +						halbtc8192e2ant_ps_tdma( +								    btcoexist, +								    NORMAL_EXEC, +								    true, 11); +						coex_dm->ps_tdma_du_adj_type = +									     11; +					} else if (coex_dm->cur_ps_tdma == 11) { +						halbtc8192e2ant_ps_tdma( +								    btcoexist, +								    NORMAL_EXEC, +								    true, 10); +						coex_dm->ps_tdma_du_adj_type = +									     10; +					} else if (coex_dm->cur_ps_tdma == 10) { +						halbtc8192e2ant_ps_tdma( +								    btcoexist, +								    NORMAL_EXEC, +								    true, 10); +						coex_dm->ps_tdma_du_adj_type = +									     10; +					} +				} +			} +		} else if (max_interval == 3) { +			if (tx_pause) { +				BTC_PRINT(BTC_MSG_ALGORITHM, +					  ALGO_TRACE_FW_DETAIL, +					  "[BTCoex], TxPause = 1\n"); +				if (coex_dm->cur_ps_tdma == 1) { +					halbtc8192e2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 7); +					coex_dm->ps_tdma_du_adj_type = 7; +				} else if (coex_dm->cur_ps_tdma == 2) { +					halbtc8192e2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 7); +					coex_dm->ps_tdma_du_adj_type = 7; +				} else if (coex_dm->cur_ps_tdma == 3) { +					halbtc8192e2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 7); +					coex_dm->ps_tdma_du_adj_type = 7; +				} else if (coex_dm->cur_ps_tdma == 4) { +					halbtc8192e2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 8); +					coex_dm->ps_tdma_du_adj_type = 8; +				} +				if (coex_dm->cur_ps_tdma == 9) { +					halbtc8192e2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 15); +					coex_dm->ps_tdma_du_adj_type = 15; +				} else if (coex_dm->cur_ps_tdma == 10) { +					halbtc8192e2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 15); +					coex_dm->ps_tdma_du_adj_type = 15; +				} else if (coex_dm->cur_ps_tdma == 11) { +					halbtc8192e2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 15); +					coex_dm->ps_tdma_du_adj_type = 15; +				} else if (coex_dm->cur_ps_tdma == 12) { +					halbtc8192e2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 16); +					coex_dm->ps_tdma_du_adj_type = 16; +				} +				if (result == -1) { +					if (coex_dm->cur_ps_tdma == 5) { +						halbtc8192e2ant_ps_tdma( +								    btcoexist, +								    NORMAL_EXEC, +								    true, 7); +						coex_dm->ps_tdma_du_adj_type = +									     7; +					} else if (coex_dm->cur_ps_tdma == 6) { +						halbtc8192e2ant_ps_tdma( +								    btcoexist, +								    NORMAL_EXEC, +								    true, 7); +						coex_dm->ps_tdma_du_adj_type = +									     7; +					} else if (coex_dm->cur_ps_tdma == 7) { +						halbtc8192e2ant_ps_tdma( +								    btcoexist, +								    NORMAL_EXEC, +								    true, 8); +						coex_dm->ps_tdma_du_adj_type = +									     8; +					} else if (coex_dm->cur_ps_tdma == 13) { +						halbtc8192e2ant_ps_tdma( +								    btcoexist, +								    NORMAL_EXEC, +								    true, 15); +						coex_dm->ps_tdma_du_adj_type = +									     15; +					} else if (coex_dm->cur_ps_tdma == 14) { +						halbtc8192e2ant_ps_tdma( +								    btcoexist, +								    NORMAL_EXEC, +								    true, 15); +						coex_dm->ps_tdma_du_adj_type = +									     15; +					} else if (coex_dm->cur_ps_tdma == 15) { +						halbtc8192e2ant_ps_tdma( +								    btcoexist, +								    NORMAL_EXEC, +								    true, 16); +						coex_dm->ps_tdma_du_adj_type = +									     16; +					} +				} else if (result == 1) { +					if (coex_dm->cur_ps_tdma == 8) { +						halbtc8192e2ant_ps_tdma( +								    btcoexist, +								    NORMAL_EXEC, +								    true, 7); +						coex_dm->ps_tdma_du_adj_type = +									     7; +					} else if (coex_dm->cur_ps_tdma == 7) { +						halbtc8192e2ant_ps_tdma( +								    btcoexist, +								    NORMAL_EXEC, +								    true, 7); +						coex_dm->ps_tdma_du_adj_type = +									     7; +					} else if (coex_dm->cur_ps_tdma == 6) { +						halbtc8192e2ant_ps_tdma( +								    btcoexist, +								    NORMAL_EXEC, +								    true, 7); +						coex_dm->ps_tdma_du_adj_type = +									     7; +					} else if (coex_dm->cur_ps_tdma == 16) { +						halbtc8192e2ant_ps_tdma( +								    btcoexist, +								    NORMAL_EXEC, +								    true, 15); +						coex_dm->ps_tdma_du_adj_type = +									     15; +					} else if (coex_dm->cur_ps_tdma == 15) { +						halbtc8192e2ant_ps_tdma( +								    btcoexist, +								    NORMAL_EXEC, +								    true, 15); +						coex_dm->ps_tdma_du_adj_type = +									     15; +					} else if (coex_dm->cur_ps_tdma == 14) { +						halbtc8192e2ant_ps_tdma( +								    btcoexist, +								    NORMAL_EXEC, +								    true, 15); +						coex_dm->ps_tdma_du_adj_type = +									     15; +					} +				} +			} else { +				BTC_PRINT(BTC_MSG_ALGORITHM, +					  ALGO_TRACE_FW_DETAIL, +					  "[BTCoex], TxPause = 0\n"); +				if (coex_dm->cur_ps_tdma == 5) { +					halbtc8192e2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 3); +					coex_dm->ps_tdma_du_adj_type = 3; +				} else if (coex_dm->cur_ps_tdma == 6) { +					halbtc8192e2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 3); +					coex_dm->ps_tdma_du_adj_type = 3; +				} else if (coex_dm->cur_ps_tdma == 7) { +					halbtc8192e2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 3); +					coex_dm->ps_tdma_du_adj_type = 3; +				} else if (coex_dm->cur_ps_tdma == 8) { +					halbtc8192e2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 4); +					coex_dm->ps_tdma_du_adj_type = 4; +				} +				if (coex_dm->cur_ps_tdma == 13) { +					halbtc8192e2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 11); +					coex_dm->ps_tdma_du_adj_type = 11; +				} else if (coex_dm->cur_ps_tdma == 14) { +					halbtc8192e2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 11); +					coex_dm->ps_tdma_du_adj_type = 11; +				} else if (coex_dm->cur_ps_tdma == 15) { +					halbtc8192e2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 11); +					coex_dm->ps_tdma_du_adj_type = 11; +				} else if (coex_dm->cur_ps_tdma == 16) { +					halbtc8192e2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 12); +					coex_dm->ps_tdma_du_adj_type = 12; +				} +				if (result == -1) { +					if (coex_dm->cur_ps_tdma == 1) { +						halbtc8192e2ant_ps_tdma( +								    btcoexist, +								    NORMAL_EXEC, +								    true, 3); +						coex_dm->ps_tdma_du_adj_type = +									     3; +					} else if (coex_dm->cur_ps_tdma == 2) { +						halbtc8192e2ant_ps_tdma( +								    btcoexist, +								    NORMAL_EXEC, +								    true, 3); +						coex_dm->ps_tdma_du_adj_type = +									     3; +					} else if (coex_dm->cur_ps_tdma == 3) { +						halbtc8192e2ant_ps_tdma( +								    btcoexist, +								    NORMAL_EXEC, +								    true, 4); +						coex_dm->ps_tdma_du_adj_type = +									     4; +					} else if (coex_dm->cur_ps_tdma == 9) { +						halbtc8192e2ant_ps_tdma( +								    btcoexist, +								    NORMAL_EXEC, +								    true, 11); +						coex_dm->ps_tdma_du_adj_type = +									     11; +					} else if (coex_dm->cur_ps_tdma == 10) { +						halbtc8192e2ant_ps_tdma( +								    btcoexist, +								    NORMAL_EXEC, +								    true, 11); +						coex_dm->ps_tdma_du_adj_type = +									     11; +					} else if (coex_dm->cur_ps_tdma == 11) { +						halbtc8192e2ant_ps_tdma( +								    btcoexist, +								    NORMAL_EXEC, +								    true, 12); +						coex_dm->ps_tdma_du_adj_type = +									     12; +					} +				} else if (result == 1) { +					if (coex_dm->cur_ps_tdma == 4) { +						halbtc8192e2ant_ps_tdma( +								    btcoexist, +								    NORMAL_EXEC, +								    true, 3); +						coex_dm->ps_tdma_du_adj_type = +									     3; +					} else if (coex_dm->cur_ps_tdma == 3) { +						halbtc8192e2ant_ps_tdma( +								    btcoexist, +								    NORMAL_EXEC, +								    true, 3); +						coex_dm->ps_tdma_du_adj_type = +									     3; +					} else if (coex_dm->cur_ps_tdma == 2) { +						halbtc8192e2ant_ps_tdma( +								    btcoexist, +								    NORMAL_EXEC, +								    true, 3); +						coex_dm->ps_tdma_du_adj_type = +									     3; +					} else if (coex_dm->cur_ps_tdma == 12) { +						halbtc8192e2ant_ps_tdma( +								    btcoexist, +								    NORMAL_EXEC, +								    true, 11); +						coex_dm->ps_tdma_du_adj_type = +									     11; +					} else if (coex_dm->cur_ps_tdma == 11) { +						halbtc8192e2ant_ps_tdma( +								    btcoexist, +								    NORMAL_EXEC, +								    true, 11); +						coex_dm->ps_tdma_du_adj_type = +									     11; +					} else if (coex_dm->cur_ps_tdma == 10) { +						halbtc8192e2ant_ps_tdma( +								    btcoexist, +								    NORMAL_EXEC, +								    true, 11); +						coex_dm->ps_tdma_du_adj_type = +									     11; +					} +				} +			} +		} +	} + +	/* if current PsTdma not match with +	 * the recorded one (when scan, dhcp...), +	 * then we have to adjust it back to the previous record one. */ +	if (coex_dm->cur_ps_tdma != coex_dm->ps_tdma_du_adj_type) { +		bool scan = false, link = false, roam = false; +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, +			  "[BTCoex], PsTdma type dismatch!!!, "); +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, +			  "curPsTdma =%d, recordPsTdma =%d\n", +			  coex_dm->cur_ps_tdma, coex_dm->ps_tdma_du_adj_type); + +		btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan); +		btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link); +		btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam); + +		if (!scan && !link && !roam) +			halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, +						true, +						coex_dm->ps_tdma_du_adj_type); +		else +			BTC_PRINT(BTC_MSG_ALGORITHM, +				  ALGO_TRACE_FW_DETAIL, +				  "[BTCoex], roaming/link/scan is under progress, will adjust next time!!!\n"); +	} +} + +/* SCO only or SCO+PAN(HS) */ +static void halbtc8192e2ant_action_sco(struct btc_coexist *btcoexist) +{ +	u8 wifirssi_state, btrssi_state = BTC_RSSI_STATE_STAY_LOW; +	u32 wifi_bw; + +	wifirssi_state = halbtc8192e2ant_wifirssi_state(btcoexist, 0, 2, 15, 0); + +	halbtc8192e2ant_switch_sstype(btcoexist, NORMAL_EXEC, 1); +	halbtc8192e2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); + +	halbtc8192e2ant_fw_dac_swinglvl(btcoexist, NORMAL_EXEC, 6); + +	halbtc_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + +	btrssi_state = halbtc8192e2ant_btrssi_state(3, 34, 42); + +	if ((btrssi_state == BTC_RSSI_STATE_LOW) || +	    (btrssi_state == BTC_RSSI_STATE_STAY_LOW)) { +		halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0); +		halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 13); +	} else if ((btrssi_state == BTC_RSSI_STATE_MEDIUM) || +		   (btrssi_state == BTC_RSSI_STATE_STAY_MEDIUM)) { +		halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 2); +		halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 9); +	} else if ((btrssi_state == BTC_RSSI_STATE_HIGH) || +		   (btrssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +		halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 4); +		halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 9); +	} + +	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + +	/* sw mechanism */ +	if (BTC_WIFI_BW_HT40 == wifi_bw) { +		if ((wifirssi_state == BTC_RSSI_STATE_HIGH) || +		    (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +			halbtc_sw_mechanism1(btcoexist, true, true, +					     false, false); +			halbtc_sw_mechanism2(btcoexist, true, false, +					     false, 0x6); +		} else { +			halbtc_sw_mechanism1(btcoexist, true, true, +					     false, false); +			halbtc_sw_mechanism2(btcoexist, false, false, +					     false, 0x6); +		} +	} else { +		if ((wifirssi_state == BTC_RSSI_STATE_HIGH) || +		    (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +			halbtc_sw_mechanism1(btcoexist, false, true, +					     false, false); +			halbtc_sw_mechanism2(btcoexist, true, false, +					     false, 0x6); +		} else { +			halbtc_sw_mechanism1(btcoexist, false, true, +					     false, false); +			halbtc_sw_mechanism2(btcoexist, false, false, +					     false, 0x6); +		} +	} +} + +static void halbtc8192e2ant_action_sco_pan(struct btc_coexist *btcoexist) +{ +	u8 wifirssi_state, btrssi_state = BTC_RSSI_STATE_STAY_LOW; +	u32 wifi_bw; + +	wifirssi_state = halbtc8192e2ant_wifirssi_state(btcoexist, 0, 2, 15, 0); + +	halbtc8192e2ant_switch_sstype(btcoexist, NORMAL_EXEC, 1); +	halbtc8192e2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); + +	halbtc8192e2ant_fw_dac_swinglvl(btcoexist, NORMAL_EXEC, 6); + +	halbtc_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + +	btrssi_state = halbtc8192e2ant_btrssi_state(3, 34, 42); + +	if ((btrssi_state == BTC_RSSI_STATE_LOW) || +	    (btrssi_state == BTC_RSSI_STATE_STAY_LOW)) { +		halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0); +		halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 14); +	} else if ((btrssi_state == BTC_RSSI_STATE_MEDIUM) || +		   (btrssi_state == BTC_RSSI_STATE_STAY_MEDIUM)) { +		halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 2); +		halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 10); +	} else if ((btrssi_state == BTC_RSSI_STATE_HIGH) || +		   (btrssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +		halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 4); +		halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 10); +	} + +	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + +	/* sw mechanism */ +	if (BTC_WIFI_BW_HT40 == wifi_bw) { +		if ((wifirssi_state == BTC_RSSI_STATE_HIGH) || +		    (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +			halbtc_sw_mechanism1(btcoexist, true, true, +					     false, false); +			halbtc_sw_mechanism2(btcoexist, true, false, +					     false, 0x6); +		} else { +			halbtc_sw_mechanism1(btcoexist, true, true, +					     false, false); +			halbtc_sw_mechanism2(btcoexist, false, false, +					     false, 0x6); +		} +	} else { +		if ((wifirssi_state == BTC_RSSI_STATE_HIGH) || +		    (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +			halbtc_sw_mechanism1(btcoexist, false, true, +					     false, false); +			halbtc_sw_mechanism2(btcoexist, true, false, +					     false, 0x6); +		} else { +			halbtc_sw_mechanism1(btcoexist, false, true, +					     false, false); +			halbtc_sw_mechanism2(btcoexist, false, false, +					     false, 0x6); +		} +	} +} + +static void halbtc8192e2ant_action_hid(struct btc_coexist *btcoexist) +{ +	u8 wifirssi_state, btrssi_state = BTC_RSSI_STATE_HIGH; +	u32 wifi_bw; + +	wifirssi_state = halbtc8192e2ant_wifirssi_state(btcoexist, 0, 2, 15, 0); +	btrssi_state = halbtc8192e2ant_btrssi_state(3, 34, 42); + +	halbtc8192e2ant_switch_sstype(btcoexist, NORMAL_EXEC, 1); +	halbtc8192e2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); + +	halbtc8192e2ant_fw_dac_swinglvl(btcoexist, NORMAL_EXEC, 6); + +	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + +	halbtc_coex_table_with_type(btcoexist, NORMAL_EXEC, 3); + +	if ((btrssi_state == BTC_RSSI_STATE_LOW) || +	    (btrssi_state == BTC_RSSI_STATE_STAY_LOW)) { +		halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0); +		halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 13); +	} else if ((btrssi_state == BTC_RSSI_STATE_MEDIUM) || +		   (btrssi_state == BTC_RSSI_STATE_STAY_MEDIUM)) { +		halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 2); +		halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 9); +	} else if ((btrssi_state == BTC_RSSI_STATE_HIGH) || +		   (btrssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +		halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 4); +		halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 9); +	} + +	/* sw mechanism */ +	if (BTC_WIFI_BW_HT40 == wifi_bw) { +		if ((wifirssi_state == BTC_RSSI_STATE_HIGH) || +		    (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +			halbtc_sw_mechanism1(btcoexist, true, true, +					     false, false); +			halbtc_sw_mechanism2(btcoexist, true, false, +					     false, 0x18); +		} else { +			halbtc_sw_mechanism1(btcoexist, true, true, +					     false, false); +			halbtc_sw_mechanism2(btcoexist, false, false, +					     false, 0x18); +		} +	} else { +		if ((wifirssi_state == BTC_RSSI_STATE_HIGH) || +		    (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +			halbtc_sw_mechanism1(btcoexist, false, true, +					     false, false); +			halbtc_sw_mechanism2(btcoexist, true, false, +					     false, 0x18); +		} else { +			halbtc_sw_mechanism1(btcoexist, false, true, +					     false, false); +			halbtc_sw_mechanism2(btcoexist, false, false, +					     false, 0x18); +		} +	} +} + +/* A2DP only / PAN(EDR) only/ A2DP+PAN(HS) */ +static void halbtc8192e2ant_action_a2dp(struct btc_coexist *btcoexist) +{ +	u8 wifirssi_state, btrssi_state = BTC_RSSI_STATE_HIGH; +	u32 wifi_bw; +	bool long_dist = false; + +	wifirssi_state = halbtc8192e2ant_wifirssi_state(btcoexist, 0, 2, 15, 0); +	btrssi_state = halbtc8192e2ant_btrssi_state(3, 34, 42); + +	if ((btrssi_state == BTC_RSSI_STATE_LOW || +	     btrssi_state == BTC_RSSI_STATE_STAY_LOW) && +	    (wifirssi_state == BTC_RSSI_STATE_LOW || +	     wifirssi_state == BTC_RSSI_STATE_STAY_LOW)) { +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +			  "[BTCoex], A2dp, wifi/bt rssi both LOW!!\n"); +		long_dist = true; +	} +	if (long_dist) { +		halbtc8192e2ant_switch_sstype(btcoexist, NORMAL_EXEC, 2); +		halbtc8192e2ant_limited_rx(btcoexist, NORMAL_EXEC, false, true, +					   0x4); +	} else { +		halbtc8192e2ant_switch_sstype(btcoexist, NORMAL_EXEC, 1); +		halbtc8192e2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, +					   0x8); +	} + +	halbtc8192e2ant_fw_dac_swinglvl(btcoexist, NORMAL_EXEC, 6); + +	if (long_dist) +		halbtc_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); +	else +		halbtc_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); + +	if (long_dist) { +		halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 17); +		coex_dm->auto_tdma_adjust = false; +		halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0); +	} else { +		if ((btrssi_state == BTC_RSSI_STATE_LOW) || +		    (btrssi_state == BTC_RSSI_STATE_STAY_LOW)) { +			halbtc8192e2ant_tdma_duration_adjust(btcoexist, false, +							     true, 1); +			halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0); +		} else if ((btrssi_state == BTC_RSSI_STATE_MEDIUM) || +			   (btrssi_state == BTC_RSSI_STATE_STAY_MEDIUM)) { +			halbtc8192e2ant_tdma_duration_adjust(btcoexist, false, +							     false, 1); +			halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 2); +		} else if ((btrssi_state == BTC_RSSI_STATE_HIGH) || +			   (btrssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +			halbtc8192e2ant_tdma_duration_adjust(btcoexist, false, +							     false, 1); +			halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 4); +		} +	} + +	/* sw mechanism */ +	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); +	if (BTC_WIFI_BW_HT40 == wifi_bw) { +		if ((wifirssi_state == BTC_RSSI_STATE_HIGH) || +		    (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +			halbtc_sw_mechanism1(btcoexist, true, false, +					     false, false); +			halbtc_sw_mechanism2(btcoexist, true, false, +					     false, 0x18); +		} else { +			halbtc_sw_mechanism1(btcoexist, true, false, +					     false, false); +			halbtc_sw_mechanism2(btcoexist, false, false, +					     false, 0x18); +		} +	} else { +		if ((wifirssi_state == BTC_RSSI_STATE_HIGH) || +		    (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +			halbtc_sw_mechanism1(btcoexist, false, false, +					     false, false); +			halbtc_sw_mechanism2(btcoexist, true, false, +					     false, 0x18); +		} else { +			halbtc_sw_mechanism1(btcoexist, false, false, +					     false, false); +			halbtc_sw_mechanism2(btcoexist, false, false, +					     false, 0x18); +		} +	} +} + +static void halbtc8192e2ant_action_a2dp_pan_hs(struct btc_coexist *btcoexist) +{ +	u8 wifirssi_state, btrssi_state = BTC_RSSI_STATE_HIGH; +	u32 wifi_bw; + +	wifirssi_state = halbtc8192e2ant_wifirssi_state(btcoexist, 0, 2, 15, 0); +	btrssi_state = halbtc8192e2ant_btrssi_state(3, 34, 42); + +	halbtc8192e2ant_switch_sstype(btcoexist, NORMAL_EXEC, 1); +	halbtc8192e2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); + +	halbtc8192e2ant_fw_dac_swinglvl(btcoexist, NORMAL_EXEC, 6); +	halbtc_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); + +	if ((btrssi_state == BTC_RSSI_STATE_LOW) || +	    (btrssi_state == BTC_RSSI_STATE_STAY_LOW)) { +		halbtc8192e2ant_tdma_duration_adjust(btcoexist, false, true, 2); +		halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0); +	} else if ((btrssi_state == BTC_RSSI_STATE_MEDIUM) || +		   (btrssi_state == BTC_RSSI_STATE_STAY_MEDIUM)) { +		halbtc8192e2ant_tdma_duration_adjust(btcoexist, false, false, +						     2); +		halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 2); +	} else if ((btrssi_state == BTC_RSSI_STATE_HIGH) || +		   (btrssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +		halbtc8192e2ant_tdma_duration_adjust(btcoexist, false, false, +						     2); +		halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 4); +	} + +	/* sw mechanism */ +	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); +	if (BTC_WIFI_BW_HT40 == wifi_bw) { +		if ((wifirssi_state == BTC_RSSI_STATE_HIGH) || +		    (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +			halbtc_sw_mechanism1(btcoexist, true, false, +					     false, false); +			halbtc_sw_mechanism2(btcoexist, true, false, +					     true, 0x6); +		} else { +			halbtc_sw_mechanism1(btcoexist, true, false, +					     false, false); +			halbtc_sw_mechanism2(btcoexist, false, false, +					     true, 0x6); +		} +	} else { +		if ((wifirssi_state == BTC_RSSI_STATE_HIGH) || +		    (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +			halbtc_sw_mechanism1(btcoexist, false, false, +					     false, false); +			halbtc_sw_mechanism2(btcoexist, true, false, +					     true, 0x6); +		} else { +			halbtc_sw_mechanism1(btcoexist, false, false, +					     false, false); +			halbtc_sw_mechanism2(btcoexist, false, false, +					     true, 0x6); +		} +	} +} + +static void halbtc8192e2ant_action_pan_edr(struct btc_coexist *btcoexist) +{ +	u8 wifirssi_state, btrssi_state = BTC_RSSI_STATE_HIGH; +	u32 wifi_bw; + +	wifirssi_state = halbtc8192e2ant_wifirssi_state(btcoexist, 0, 2, 15, 0); +	btrssi_state = halbtc8192e2ant_btrssi_state(3, 34, 42); + +	halbtc8192e2ant_switch_sstype(btcoexist, NORMAL_EXEC, 1); +	halbtc8192e2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); + +	halbtc8192e2ant_fw_dac_swinglvl(btcoexist, NORMAL_EXEC, 6); + +	halbtc_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); + +	if ((btrssi_state == BTC_RSSI_STATE_LOW) || +	    (btrssi_state == BTC_RSSI_STATE_STAY_LOW)) { +		halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0); +		halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 5); +	} else if ((btrssi_state == BTC_RSSI_STATE_MEDIUM) || +		   (btrssi_state == BTC_RSSI_STATE_STAY_MEDIUM)) { +		halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 2); +		halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 1); +	} else if ((btrssi_state == BTC_RSSI_STATE_HIGH) || +		   (btrssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +		halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 4); +		halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 1); +	} + +	/* sw mechanism */ +	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); +	if (BTC_WIFI_BW_HT40 == wifi_bw) { +		if ((wifirssi_state == BTC_RSSI_STATE_HIGH) || +		    (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +			halbtc_sw_mechanism1(btcoexist, true, false, +					     false, false); +			halbtc_sw_mechanism2(btcoexist, true, false, +					     false, 0x18); +		} else { +			halbtc_sw_mechanism1(btcoexist, true, false, +					     false, false); +			halbtc_sw_mechanism2(btcoexist, false, false, +					     false, 0x18); +		} +	} else { +		if ((wifirssi_state == BTC_RSSI_STATE_HIGH) || +		    (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +			halbtc_sw_mechanism1(btcoexist, false, false, +					     false, false); +			halbtc_sw_mechanism2(btcoexist, true, false, +					     false, 0x18); +		} else { +			halbtc_sw_mechanism1(btcoexist, false, false, +					     false, false); +			halbtc_sw_mechanism2(btcoexist, false, false, +					     false, 0x18); +		} +	} +} + +/* PAN(HS) only */ +static void halbtc8192e2ant_action_pan_hs(struct btc_coexist *btcoexist) +{ +	u8 wifirssi_state, btrssi_state = BTC_RSSI_STATE_HIGH; +	u32 wifi_bw; + +	wifirssi_state = halbtc8192e2ant_wifirssi_state(btcoexist, 0, 2, 15, 0); +	btrssi_state = halbtc8192e2ant_btrssi_state(3, 34, 42); + +	halbtc8192e2ant_switch_sstype(btcoexist, NORMAL_EXEC, 1); +	halbtc8192e2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); + +	halbtc8192e2ant_fw_dac_swinglvl(btcoexist, NORMAL_EXEC, 6); + +	halbtc_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); + +	if ((btrssi_state == BTC_RSSI_STATE_LOW) || +	    (btrssi_state == BTC_RSSI_STATE_STAY_LOW)) { +		halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0); +	} else if ((btrssi_state == BTC_RSSI_STATE_MEDIUM) || +		   (btrssi_state == BTC_RSSI_STATE_STAY_MEDIUM)) { +		halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 2); +	} else if ((btrssi_state == BTC_RSSI_STATE_HIGH) || +		   (btrssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +		halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 4); +	} +	halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1); + +	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); +	if (BTC_WIFI_BW_HT40 == wifi_bw) { +		if ((wifirssi_state == BTC_RSSI_STATE_HIGH) || +		    (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +			halbtc_sw_mechanism1(btcoexist, true, false, +					     false, false); +			halbtc_sw_mechanism2(btcoexist, true, false, +					     false, 0x18); +		} else { +			halbtc_sw_mechanism1(btcoexist, true, false, +					     false, false); +			halbtc_sw_mechanism2(btcoexist, false, false, +					     false, 0x18); +		} +	} else { +		if ((wifirssi_state == BTC_RSSI_STATE_HIGH) || +		    (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +			halbtc_sw_mechanism1(btcoexist, false, false, +					     false, false); +			halbtc_sw_mechanism2(btcoexist, true, false, +					     false, 0x18); +		} else { +			halbtc_sw_mechanism1(btcoexist, false, false, +					     false, false); +			halbtc_sw_mechanism2(btcoexist, false, false, +					     false, 0x18); +		} +	} +} + +/* PAN(EDR)+A2DP */ +static void halbtc8192e2ant_action_pan_edr_a2dp(struct btc_coexist *btcoexist) +{ +	u8 wifirssi_state, btrssi_state = BTC_RSSI_STATE_HIGH; +	u32 wifi_bw; + +	wifirssi_state = halbtc8192e2ant_wifirssi_state(btcoexist, 0, 2, 15, 0); +	btrssi_state = halbtc8192e2ant_btrssi_state(3, 34, 42); + +	halbtc8192e2ant_switch_sstype(btcoexist, NORMAL_EXEC, 1); +	halbtc8192e2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); + +	halbtc8192e2ant_fw_dac_swinglvl(btcoexist, NORMAL_EXEC, 6); + +	halbtc_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); + +	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + +	if ((btrssi_state == BTC_RSSI_STATE_LOW) || +	    (btrssi_state == BTC_RSSI_STATE_STAY_LOW)) { +		halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0); +		halbtc8192e2ant_tdma_duration_adjust(btcoexist, false, true, 3); +	} else if ((btrssi_state == BTC_RSSI_STATE_MEDIUM) || +		   (btrssi_state == BTC_RSSI_STATE_STAY_MEDIUM)) { +		halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 2); +		halbtc8192e2ant_tdma_duration_adjust(btcoexist, false, false, +						     3); +	} else if ((btrssi_state == BTC_RSSI_STATE_HIGH) || +		   (btrssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +		halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 4); +		halbtc8192e2ant_tdma_duration_adjust(btcoexist, false, false, +						     3); +	} + +	/* sw mechanism	*/ +	if (BTC_WIFI_BW_HT40 == wifi_bw) { +		if ((wifirssi_state == BTC_RSSI_STATE_HIGH) || +		    (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +			halbtc_sw_mechanism1(btcoexist, true, false, +					     false, false); +			halbtc_sw_mechanism2(btcoexist, true, false, +					     false, 0x18); +		} else { +			halbtc_sw_mechanism1(btcoexist, true, false, +					     false, false); +			halbtc_sw_mechanism2(btcoexist, false, false, +					     false, 0x18); +		} +	} else { +		if ((wifirssi_state == BTC_RSSI_STATE_HIGH) || +		    (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +			halbtc_sw_mechanism1(btcoexist, false, false, +					     false, false); +			halbtc_sw_mechanism2(btcoexist, true, false, +					     false, 0x18); +		} else { +			halbtc_sw_mechanism1(btcoexist, false, false, +					     false, false); +			halbtc_sw_mechanism2(btcoexist, false, false, +					     false, 0x18); +		} +	} +} + +static void halbtc8192e2ant_action_pan_edr_hid(struct btc_coexist *btcoexist) +{ +	u8 wifirssi_state, btrssi_state = BTC_RSSI_STATE_HIGH; +	u32 wifi_bw; + +	wifirssi_state = halbtc8192e2ant_wifirssi_state(btcoexist, 0, 2, 15, 0); +	btrssi_state = halbtc8192e2ant_btrssi_state(3, 34, 42); + +	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + +	halbtc8192e2ant_switch_sstype(btcoexist, NORMAL_EXEC, 1); +	halbtc8192e2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); + +	halbtc8192e2ant_fw_dac_swinglvl(btcoexist, NORMAL_EXEC, 6); + +	halbtc_coex_table_with_type(btcoexist, NORMAL_EXEC, 3); + +	if ((btrssi_state == BTC_RSSI_STATE_LOW) || +	    (btrssi_state == BTC_RSSI_STATE_STAY_LOW)) { +		halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0); +		halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 14); +	} else if ((btrssi_state == BTC_RSSI_STATE_MEDIUM) || +		   (btrssi_state == BTC_RSSI_STATE_STAY_MEDIUM)) { +		halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 2); +		halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 10); +	} else if ((btrssi_state == BTC_RSSI_STATE_HIGH) || +		   (btrssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +		halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 4); +		halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 10); +	} + +	/* sw mechanism */ +	if (BTC_WIFI_BW_HT40 == wifi_bw) { +		if ((wifirssi_state == BTC_RSSI_STATE_HIGH) || +		    (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +			halbtc_sw_mechanism1(btcoexist, true, true, +					     false, false); +			halbtc_sw_mechanism2(btcoexist, true, false, +					     false, 0x18); +		} else { +			halbtc_sw_mechanism1(btcoexist, true, true, +					     false, false); +			halbtc_sw_mechanism2(btcoexist, false, false, +					     false, 0x18); +		} +	} else { +		if ((wifirssi_state == BTC_RSSI_STATE_HIGH) || +		    (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +			halbtc_sw_mechanism1(btcoexist, false, true, +					     false, false); +			halbtc_sw_mechanism2(btcoexist, true, false, +					     false, 0x18); +		} else { +			halbtc_sw_mechanism1(btcoexist, false, true, +					     false, false); +			halbtc_sw_mechanism2(btcoexist, false, false, +					     false, 0x18); +		} +	} +} + +/* HID+A2DP+PAN(EDR) */ +static void action_hid_a2dp_pan_edr(struct btc_coexist *btcoexist) +{ +	u8 wifirssi_state, btrssi_state = BTC_RSSI_STATE_HIGH; +	u32 wifi_bw; + +	wifirssi_state = halbtc8192e2ant_wifirssi_state(btcoexist, 0, 2, 15, 0); +	btrssi_state = halbtc8192e2ant_btrssi_state(3, 34, 42); + +	halbtc8192e2ant_switch_sstype(btcoexist, NORMAL_EXEC, 1); +	halbtc8192e2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); + +	halbtc8192e2ant_fw_dac_swinglvl(btcoexist, NORMAL_EXEC, 6); + +	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + +	halbtc_coex_table_with_type(btcoexist, NORMAL_EXEC, 3); + +	if ((btrssi_state == BTC_RSSI_STATE_LOW) || +	    (btrssi_state == BTC_RSSI_STATE_STAY_LOW)) { +		halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0); +		halbtc8192e2ant_tdma_duration_adjust(btcoexist, true, true, 3); +	} else if ((btrssi_state == BTC_RSSI_STATE_MEDIUM) || +		   (btrssi_state == BTC_RSSI_STATE_STAY_MEDIUM)) { +		halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 2); +		halbtc8192e2ant_tdma_duration_adjust(btcoexist, true, false, 3); +	} else if ((btrssi_state == BTC_RSSI_STATE_HIGH) || +		   (btrssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +		halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 4); +		halbtc8192e2ant_tdma_duration_adjust(btcoexist, true, false, 3); +	} + +	/* sw mechanism */ +	if (BTC_WIFI_BW_HT40 == wifi_bw) { +		if ((wifirssi_state == BTC_RSSI_STATE_HIGH) || +		    (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +			halbtc_sw_mechanism1(btcoexist, true, true, +					     false, false); +			halbtc_sw_mechanism2(btcoexist, true, false, +					     false, 0x18); +		} else { +			halbtc_sw_mechanism1(btcoexist, true, true, +					     false, false); +			halbtc_sw_mechanism2(btcoexist, false, false, +					     false, 0x18); +		} +	} else { +		if ((wifirssi_state == BTC_RSSI_STATE_HIGH) || +		    (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +			halbtc_sw_mechanism1(btcoexist, false, true, +					     false, false); +			halbtc_sw_mechanism2(btcoexist, true, false, +					     false, 0x18); +		} else { +			halbtc_sw_mechanism1(btcoexist, false, true, +					     false, false); +			halbtc_sw_mechanism2(btcoexist, false, false, +					     false, 0x18); +		} +	} +} + +static void halbtc8192e2ant_action_hid_a2dp(struct btc_coexist *btcoexist) +{ +	u8 wifirssi_state, btrssi_state = BTC_RSSI_STATE_HIGH; +	u32 wifi_bw; + +	wifirssi_state = halbtc8192e2ant_wifirssi_state(btcoexist, 0, 2, 15, 0); +	btrssi_state = halbtc8192e2ant_btrssi_state(3, 34, 42); + +	halbtc8192e2ant_switch_sstype(btcoexist, NORMAL_EXEC, 1); +	halbtc8192e2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); + +	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + +	halbtc_coex_table_with_type(btcoexist, NORMAL_EXEC, 3); + +	if ((btrssi_state == BTC_RSSI_STATE_LOW) || +	    (btrssi_state == BTC_RSSI_STATE_STAY_LOW)) { +		halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0); +		halbtc8192e2ant_tdma_duration_adjust(btcoexist, true, true, 2); +	} else if ((btrssi_state == BTC_RSSI_STATE_MEDIUM) || +		   (btrssi_state == BTC_RSSI_STATE_STAY_MEDIUM))	{ +		halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 2); +		halbtc8192e2ant_tdma_duration_adjust(btcoexist, true, false, 2); +	} else if ((btrssi_state == BTC_RSSI_STATE_HIGH) || +		   (btrssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +		halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 4); +		halbtc8192e2ant_tdma_duration_adjust(btcoexist, true, false, 2); +	} + +	/* sw mechanism */ +	if (BTC_WIFI_BW_HT40 == wifi_bw) { +		if ((wifirssi_state == BTC_RSSI_STATE_HIGH) || +		    (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +			halbtc_sw_mechanism1(btcoexist, true, true, +					     false, false); +			halbtc_sw_mechanism2(btcoexist, true, false, +					     false, 0x18); +		} else { +			halbtc_sw_mechanism1(btcoexist, true, true, +					     false, false); +			halbtc_sw_mechanism2(btcoexist, false, false, +					     false, 0x18); +		} +	} else { +		if ((wifirssi_state == BTC_RSSI_STATE_HIGH) || +		    (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +			halbtc_sw_mechanism1(btcoexist, false, true, +					     false, false); +			halbtc_sw_mechanism2(btcoexist, true, false, +					     false, 0x18); +		} else { +			halbtc_sw_mechanism1(btcoexist, false, true, +					     false, false); +			halbtc_sw_mechanism2(btcoexist, false, false, +					     false, 0x18); +		} +	} +} + +static void halbtc8192e2ant_run_coexist_mechanism(struct btc_coexist *btcoexist) +{ +	u8 algorithm = 0; + +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +		  "[BTCoex], RunCoexistMechanism() ===>\n"); + +	if (btcoexist->manual_control) { +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +			  "[BTCoex], return for Manual CTRL <===\n"); +		return; +	} + +	if (coex_sta->under_ips) { +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +			  "[BTCoex], wifi is under IPS !!!\n"); +		return; +	} + +	algorithm = halbtc8192e2ant_action_algorithm(btcoexist); +	if (coex_sta->c2h_bt_inquiry_page && +	    (BT_8192E_2ANT_COEX_ALGO_PANHS != algorithm)) { +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +			  "[BTCoex], BT is under inquiry/page scan !!\n"); +		halbtc8192e2ant_action_bt_inquiry(btcoexist); +		return; +	} + +	coex_dm->cur_algorithm = algorithm; +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +		  "[BTCoex], Algorithm = %d\n", coex_dm->cur_algorithm); + +	if (halbtc8192e2ant_is_common_action(btcoexist)) { +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +			  "[BTCoex], Action 2-Ant common.\n"); +		coex_dm->auto_tdma_adjust = false; +	} else { +		if (coex_dm->cur_algorithm != coex_dm->pre_algorithm) { +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +				  "[BTCoex] preAlgorithm =%d, curAlgorithm =%d\n", +				  coex_dm->pre_algorithm, +				  coex_dm->cur_algorithm); +			coex_dm->auto_tdma_adjust = false; +		} +		switch (coex_dm->cur_algorithm) { +		case BT_8192E_2ANT_COEX_ALGO_SCO: +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +				  "Action 2-Ant, algorithm = SCO.\n"); +			halbtc8192e2ant_action_sco(btcoexist); +			break; +		case BT_8192E_2ANT_COEX_ALGO_SCO_PAN: +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +				  "Action 2-Ant, algorithm = SCO+PAN(EDR).\n"); +			halbtc8192e2ant_action_sco_pan(btcoexist); +			break; +		case BT_8192E_2ANT_COEX_ALGO_HID: +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +				  "Action 2-Ant, algorithm = HID.\n"); +			halbtc8192e2ant_action_hid(btcoexist); +			break; +		case BT_8192E_2ANT_COEX_ALGO_A2DP: +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +				  "Action 2-Ant, algorithm = A2DP.\n"); +			halbtc8192e2ant_action_a2dp(btcoexist); +			break; +		case BT_8192E_2ANT_COEX_ALGO_A2DP_PANHS: +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +				  "Action 2-Ant, algorithm = A2DP+PAN(HS).\n"); +			halbtc8192e2ant_action_a2dp_pan_hs(btcoexist); +			break; +		case BT_8192E_2ANT_COEX_ALGO_PANEDR: +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +				  "Action 2-Ant, algorithm = PAN(EDR).\n"); +			halbtc8192e2ant_action_pan_edr(btcoexist); +			break; +		case BT_8192E_2ANT_COEX_ALGO_PANHS: +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +				  "Action 2-Ant, algorithm = HS mode.\n"); +			halbtc8192e2ant_action_pan_hs(btcoexist); +			break; +		case BT_8192E_2ANT_COEX_ALGO_PANEDR_A2DP: +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +				  "Action 2-Ant, algorithm = PAN+A2DP.\n"); +			halbtc8192e2ant_action_pan_edr_a2dp(btcoexist); +			break; +		case BT_8192E_2ANT_COEX_ALGO_PANEDR_HID: +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +				  "Action 2-Ant, algorithm = PAN(EDR)+HID.\n"); +			halbtc8192e2ant_action_pan_edr_hid(btcoexist); +			break; +		case BT_8192E_2ANT_COEX_ALGO_HID_A2DP_PANEDR: +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +				  "Action 2-Ant, algorithm = HID+A2DP+PAN.\n"); +			action_hid_a2dp_pan_edr(btcoexist); +			break; +		case BT_8192E_2ANT_COEX_ALGO_HID_A2DP: +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +				  "Action 2-Ant, algorithm = HID+A2DP.\n"); +			halbtc8192e2ant_action_hid_a2dp(btcoexist); +			break; +		default: +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +				  "Action 2-Ant, algorithm = unknown!!\n"); +			/* halbtc8192e2ant_coex_alloff(btcoexist); */ +			break; +		} +		coex_dm->pre_algorithm = coex_dm->cur_algorithm; +	} +} + +static void halbtc8192e2ant_init_hwconfig(struct btc_coexist *btcoexist, +					  bool backup) +{ +	u16 u16tmp = 0; +	u8 u8tmp = 0; + +	BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, +		  "[BTCoex], 2Ant Init HW Config!!\n"); + +	if (backup) { +		/* backup rf 0x1e value */ +		coex_dm->bt_rf0x1e_backup = +			btcoexist->btc_get_rf_reg(btcoexist, BTC_RF_A, +						  0x1e, 0xfffff); + +		coex_dm->backup_arfr_cnt1 = btcoexist->btc_read_4byte(btcoexist, +								      0x430); +		coex_dm->backup_arfr_cnt2 = btcoexist->btc_read_4byte(btcoexist, +								     0x434); +		coex_dm->backup_retrylimit = btcoexist->btc_read_2byte( +								    btcoexist, +								    0x42a); +		coex_dm->backup_ampdu_maxtime = btcoexist->btc_read_1byte( +								    btcoexist, +								    0x456); +	} + +	/* antenna sw ctrl to bt */ +	btcoexist->btc_write_1byte(btcoexist, 0x4f, 0x6); +	btcoexist->btc_write_1byte(btcoexist, 0x944, 0x24); +	btcoexist->btc_write_4byte(btcoexist, 0x930, 0x700700); +	btcoexist->btc_write_1byte(btcoexist, 0x92c, 0x20); +	if (btcoexist->chip_interface == BTC_INTF_USB) +		btcoexist->btc_write_4byte(btcoexist, 0x64, 0x30430004); +	else +		btcoexist->btc_write_4byte(btcoexist, 0x64, 0x30030004); + +	halbtc_coex_table_with_type(btcoexist, FORCE_EXEC, 0); + +	/* antenna switch control parameter */ +	btcoexist->btc_write_4byte(btcoexist, 0x858, 0x55555555); + +	/* coex parameters */ +	btcoexist->btc_write_1byte(btcoexist, 0x778, 0x3); +	/* 0x790[5:0] = 0x5 */ +	u8tmp = btcoexist->btc_read_1byte(btcoexist, 0x790); +	u8tmp &= 0xc0; +	u8tmp |= 0x5; +	btcoexist->btc_write_1byte(btcoexist, 0x790, u8tmp); + +	/* enable counter statistics */ +	btcoexist->btc_write_1byte(btcoexist, 0x76e, 0x4); + +	/* enable PTA */ +	btcoexist->btc_write_1byte(btcoexist, 0x40, 0x20); +	/* enable mailbox interface */ +	u16tmp = btcoexist->btc_read_2byte(btcoexist, 0x40); +	u16tmp |= BIT(9); +	btcoexist->btc_write_2byte(btcoexist, 0x40, u16tmp); + +	/* enable PTA I2C mailbox  */ +	u8tmp = btcoexist->btc_read_1byte(btcoexist, 0x101); +	u8tmp |= BIT(4); +	btcoexist->btc_write_1byte(btcoexist, 0x101, u8tmp); + +	/* enable bt clock when wifi is disabled. */ +	u8tmp = btcoexist->btc_read_1byte(btcoexist, 0x93); +	u8tmp |= BIT(0); +	btcoexist->btc_write_1byte(btcoexist, 0x93, u8tmp); +	/* enable bt clock when suspend. */ +	u8tmp = btcoexist->btc_read_1byte(btcoexist, 0x7); +	u8tmp |= BIT(0); +	btcoexist->btc_write_1byte(btcoexist, 0x7, u8tmp); +} + +/************************************************************* + *   work around function start with wa_halbtc8192e2ant_ + *************************************************************/ + +/************************************************************ + *   extern function start with EXhalbtc8192e2ant_ + ************************************************************/ + +void ex_halbtc8192e2ant_init_hwconfig(struct btc_coexist *btcoexist) +{ +	halbtc8192e2ant_init_hwconfig(btcoexist, true); +} + +void ex_halbtc8192e2ant_init_coex_dm(struct btc_coexist *btcoexist) +{ +	BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, +		  "[BTCoex], Coex Mechanism Init!!\n"); +	halbtc8192e2ant_init_coex_dm(btcoexist); +} + +void ex_halbtc8192e2ant_display_coex_info(struct btc_coexist *btcoexist) +{ +	struct btc_board_info *board_info = &btcoexist->board_info; +	struct btc_stack_info *stack_info = &btcoexist->stack_info; +	u8 *cli_buf = btcoexist->cli_buf; +	u8 u8tmp[4], i, bt_info_ext, ps_tdma_case = 0; +	u16 u16tmp[4]; +	u32 u32tmp[4]; +	bool roam = false, scan = false, link = false, wifi_under_5g = false; +	bool bt_hson = false, wifi_busy = false; +	int wifirssi = 0, bt_hs_rssi = 0; +	u32 wifi_bw, wifi_traffic_dir; +	u8 wifi_dot11_chnl, wifi_hs_chnl; +	u32 fw_ver = 0, bt_patch_ver = 0; + +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, +		   "\r\n ============[BT Coexist info] ============"); +	CL_PRINTF(cli_buf); + +	if (btcoexist->manual_control) { +		CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, +			   "\r\n ===========[Under Manual Control] ==========="); +		CL_PRINTF(cli_buf); +		CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, +			   "\r\n =========================================="); +		CL_PRINTF(cli_buf); +	} + +	if (!board_info->bt_exist) { +		CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n BT not exists !!!"); +		CL_PRINTF(cli_buf); +		return; +	} + +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, +		   "\r\n %-35s = %d/ %d ", "Ant PG number/ Ant mechanism: ", +		   board_info->pg_ant_num, board_info->btdm_ant_num); +	CL_PRINTF(cli_buf); + +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s / %d", +		   "BT stack/ hci ext ver", +		   ((stack_info->profile_notified) ? "Yes" : "No"), +		   stack_info->hci_version); +	CL_PRINTF(cli_buf); + +	btcoexist->btc_get(btcoexist, BTC_GET_U4_BT_PATCH_VER, &bt_patch_ver); +	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver); +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, +		   "\r\n %-35s = %d_%d/ 0x%x/ 0x%x(%d)", +		   "CoexVer/ FwVer/ PatchVer", +		   glcoex_ver_date_8192e_2ant, glcoex_ver_8192e_2ant, +		   fw_ver, bt_patch_ver, bt_patch_ver); +	CL_PRINTF(cli_buf); + +	btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hson); +	btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_DOT11_CHNL, +			   &wifi_dot11_chnl); +	btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_HS_CHNL, &wifi_hs_chnl); +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d / %d(%d)", +		   "Dot11 channel / HsMode(HsChnl)", +		   wifi_dot11_chnl, bt_hson, wifi_hs_chnl); +	CL_PRINTF(cli_buf); + +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x ", +		   "H2C Wifi inform bt chnl Info", coex_dm->wifi_chnl_info[0], +		   coex_dm->wifi_chnl_info[1], coex_dm->wifi_chnl_info[2]); +	CL_PRINTF(cli_buf); + +	btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifirssi); +	btcoexist->btc_get(btcoexist, BTC_GET_S4_HS_RSSI, &bt_hs_rssi); +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", +		   "Wifi rssi/ HS rssi", wifirssi, bt_hs_rssi); +	CL_PRINTF(cli_buf); + +	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan); +	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link); +	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam); +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d ", +		   "Wifi link/ roam/ scan", link, roam, scan); +	CL_PRINTF(cli_buf); + +	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); +	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); +	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); +	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_TRAFFIC_DIRECTION, +			   &wifi_traffic_dir); +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s / %s/ %s ", +		   "Wifi status", (wifi_under_5g ? "5G" : "2.4G"), +		   ((BTC_WIFI_BW_LEGACY == wifi_bw) ? "Legacy" : +			(((BTC_WIFI_BW_HT40 == wifi_bw) ? "HT40" : "HT20"))), +		   ((!wifi_busy) ? "idle" : +			((BTC_WIFI_TRAFFIC_TX == wifi_traffic_dir) ? +				"uplink" : "downlink"))); +	CL_PRINTF(cli_buf); + +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = [%s/ %d/ %d] ", +		   "BT [status/ rssi/ retryCnt]", +		   ((btcoexist->bt_info.bt_disabled) ? ("disabled") : +		    ((coex_sta->c2h_bt_inquiry_page) ? +		     ("inquiry/page scan") : +		      ((BT_8192E_2ANT_BT_STATUS_NON_CONNECTED_IDLE == +			coex_dm->bt_status) ? "non-connected idle" : +			 ((BT_8192E_2ANT_BT_STATUS_CONNECTED_IDLE == +			   coex_dm->bt_status) ? "connected-idle" : "busy")))), +		   coex_sta->bt_rssi, coex_sta->bt_retry_cnt); +	CL_PRINTF(cli_buf); + +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d / %d / %d / %d", +		   "SCO/HID/PAN/A2DP", stack_info->sco_exist, +		   stack_info->hid_exist, stack_info->pan_exist, +		   stack_info->a2dp_exist); +	CL_PRINTF(cli_buf); +	btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_BT_LINK_INFO); + +	bt_info_ext = coex_sta->bt_info_ext; +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s", +		   "BT Info A2DP rate", +		   (bt_info_ext & BIT(0)) ? "Basic rate" : "EDR rate"); +	CL_PRINTF(cli_buf); + +	for (i = 0; i < BT_INFO_SRC_8192E_2ANT_MAX; i++) { +		if (coex_sta->bt_info_c2h_cnt[i]) { +			CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, +				   "\r\n %-35s = %02x %02x %02x %02x ", +				   glbt_infosrc8192e2ant[i], +				   coex_sta->bt_info_c2h[i][0], +				   coex_sta->bt_info_c2h[i][1], +				   coex_sta->bt_info_c2h[i][2], +				   coex_sta->bt_info_c2h[i][3]); +			CL_PRINTF(cli_buf); +			CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, +				   "%02x %02x %02x(%d)", +				   coex_sta->bt_info_c2h[i][4], +				   coex_sta->bt_info_c2h[i][5], +				   coex_sta->bt_info_c2h[i][6], +				   coex_sta->bt_info_c2h_cnt[i]); +			CL_PRINTF(cli_buf); +		} +	} + +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s/%s", +		   "PS state, IPS/LPS", +		   ((coex_sta->under_ips ? "IPS ON" : "IPS OFF")), +		   ((coex_sta->under_lps ? "LPS ON" : "LPS OFF"))); +	CL_PRINTF(cli_buf); +	btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_FW_PWR_MODE_CMD); + +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x ", "SS Type", +		   coex_dm->cur_sstype); +	CL_PRINTF(cli_buf); + +	/* Sw mechanism	*/ +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", +		   "============[Sw mechanism] ============"); +	CL_PRINTF(cli_buf); +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d ", +		   "SM1[ShRf/ LpRA/ LimDig]", coex_dm->cur_rf_rx_lpf_shrink, +		   coex_dm->cur_low_penalty_ra, coex_dm->limited_dig); +	CL_PRINTF(cli_buf); +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d(0x%x) ", +		   "SM2[AgcT/ AdcB/ SwDacSwing(lvl)]", +		   coex_dm->cur_agc_table_en, coex_dm->cur_adc_back_off, +		   coex_dm->cur_dac_swing_on, coex_dm->cur_dac_swing_lvl); +	CL_PRINTF(cli_buf); + +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x ", "Rate Mask", +		   btcoexist->bt_info.ra_mask); +	CL_PRINTF(cli_buf); + +	/* Fw mechanism	*/ +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", +		   "============[Fw mechanism] ============"); +	CL_PRINTF(cli_buf); + +	ps_tdma_case = coex_dm->cur_ps_tdma; +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, +		   "\r\n %-35s = %02x %02x %02x %02x %02x case-%d (auto:%d)", +		   "PS TDMA", coex_dm->ps_tdma_para[0], +		   coex_dm->ps_tdma_para[1], coex_dm->ps_tdma_para[2], +		   coex_dm->ps_tdma_para[3], coex_dm->ps_tdma_para[4], +		   ps_tdma_case, coex_dm->auto_tdma_adjust); +	CL_PRINTF(cli_buf); + +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d ", +		   "DecBtPwr/ IgnWlanAct", +		   coex_dm->cur_dec_bt_pwr, coex_dm->cur_ignore_wlan_act); +	CL_PRINTF(cli_buf); + +	/* Hw setting */ +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", +		   "============[Hw setting] ============"); +	CL_PRINTF(cli_buf); + +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", +		   "RF-A, 0x1e initVal", coex_dm->bt_rf0x1e_backup); +	CL_PRINTF(cli_buf); + +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/0x%x/0x%x/0x%x", +		   "backup ARFR1/ARFR2/RL/AMaxTime", coex_dm->backup_arfr_cnt1, +		   coex_dm->backup_arfr_cnt2, coex_dm->backup_retrylimit, +		   coex_dm->backup_ampdu_maxtime); +	CL_PRINTF(cli_buf); + +	u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x430); +	u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x434); +	u16tmp[0] = btcoexist->btc_read_2byte(btcoexist, 0x42a); +	u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x456); +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/0x%x/0x%x/0x%x", +		   "0x430/0x434/0x42a/0x456", +		   u32tmp[0], u32tmp[1], u16tmp[0], u8tmp[0]); +	CL_PRINTF(cli_buf); + +	u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xc04); +	u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0xd04); +	u32tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0x90c); +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", +		   "0xc04/ 0xd04/ 0x90c", u32tmp[0], u32tmp[1], u32tmp[2]); +	CL_PRINTF(cli_buf); + +	u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x778); +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", "0x778", +		   u8tmp[0]); +	CL_PRINTF(cli_buf); + +	u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x92c); +	u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x930); +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", +		   "0x92c/ 0x930", (u8tmp[0]), u32tmp[0]); +	CL_PRINTF(cli_buf); + +	u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x40); +	u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0x4f); +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", +		   "0x40/ 0x4f", u8tmp[0], u8tmp[1]); +	CL_PRINTF(cli_buf); + +	u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x550); +	u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x522); +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", +		   "0x550(bcn ctrl)/0x522", u32tmp[0], u8tmp[0]); +	CL_PRINTF(cli_buf); + +	u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xc50); +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", "0xc50(dig)", +		   u32tmp[0]); +	CL_PRINTF(cli_buf); + +	u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x6c0); +	u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x6c4); +	u32tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0x6c8); +	u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x6cc); +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, +		   "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", +		   "0x6c0/0x6c4/0x6c8/0x6cc(coexTable)", +		   u32tmp[0], u32tmp[1], u32tmp[2], u8tmp[0]); +	CL_PRINTF(cli_buf); + +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", +		   "0x770(hp rx[31:16]/tx[15:0])", +		   coex_sta->high_priority_rx, coex_sta->high_priority_tx); +	CL_PRINTF(cli_buf); +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", +		   "0x774(lp rx[31:16]/tx[15:0])", +		   coex_sta->low_priority_rx, coex_sta->low_priority_tx); +	CL_PRINTF(cli_buf); +#if (BT_AUTO_REPORT_ONLY_8192E_2ANT == 1) +	halbtc8192e2ant_monitor_bt_ctr(btcoexist); +#endif +	btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_COEX_STATISTICS); +} + +void ex_halbtc8192e2ant_ips_notify(struct btc_coexist *btcoexist, u8 type) +{ +	if (BTC_IPS_ENTER == type) { +		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, +			  "[BTCoex], IPS ENTER notify\n"); +		coex_sta->under_ips = true; +		halbtc8192e2ant_coex_alloff(btcoexist); +	} else if (BTC_IPS_LEAVE == type) { +		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, +			  "[BTCoex], IPS LEAVE notify\n"); +		coex_sta->under_ips = false; +	} +} + +void ex_halbtc8192e2ant_lps_notify(struct btc_coexist *btcoexist, u8 type) +{ +	if (BTC_LPS_ENABLE == type) { +		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, +			  "[BTCoex], LPS ENABLE notify\n"); +		coex_sta->under_lps = true; +	} else if (BTC_LPS_DISABLE == type) { +		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, +			  "[BTCoex], LPS DISABLE notify\n"); +		coex_sta->under_lps = false; +	} +} + +void ex_halbtc8192e2ant_scan_notify(struct btc_coexist *btcoexist, u8 type) +{ +	if (BTC_SCAN_START == type) +		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, +			  "[BTCoex], SCAN START notify\n"); +	else if (BTC_SCAN_FINISH == type) +		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, +			  "[BTCoex], SCAN FINISH notify\n"); +} + +void ex_halbtc8192e2ant_connect_notify(struct btc_coexist *btcoexist, u8 type) +{ +	if (BTC_ASSOCIATE_START == type) +		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, +			  "[BTCoex], CONNECT START notify\n"); +	else if (BTC_ASSOCIATE_FINISH == type) +		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, +			  "[BTCoex], CONNECT FINISH notify\n"); +} + +void ex_halbtc8192e2ant_media_status_notify(struct btc_coexist *btcoexist, +					    u8 type) +{ +	u8 h2c_parameter[3] = {0}; +	u32 wifi_bw; +	u8 wifi_center_chnl; + +	if (btcoexist->manual_control || +	    btcoexist->stop_coex_dm || +	    btcoexist->bt_info.bt_disabled) +		return; + +	if (BTC_MEDIA_CONNECT == type) +		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, +			  "[BTCoex], MEDIA connect notify\n"); +	else +		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, +			  "[BTCoex], MEDIA disconnect notify\n"); + +	/* only 2.4G we need to inform bt the chnl mask */ +	btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_CENTRAL_CHNL, +			   &wifi_center_chnl); +	if ((BTC_MEDIA_CONNECT == type) && +	    (wifi_center_chnl <= 14)) { +		h2c_parameter[0] = 0x1; +		h2c_parameter[1] = wifi_center_chnl; +		btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); +		if (BTC_WIFI_BW_HT40 == wifi_bw) +			h2c_parameter[2] = 0x30; +		else +			h2c_parameter[2] = 0x20; +	} + +	coex_dm->wifi_chnl_info[0] = h2c_parameter[0]; +	coex_dm->wifi_chnl_info[1] = h2c_parameter[1]; +	coex_dm->wifi_chnl_info[2] = h2c_parameter[2]; + +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, +		  "[BTCoex], FW write 0x66 = 0x%x\n", +		  h2c_parameter[0] << 16 | h2c_parameter[1] << 8 | +		  h2c_parameter[2]); + +	btcoexist->btc_fill_h2c(btcoexist, 0x66, 3, h2c_parameter); +} + +void ex_halbtc8192e2ant_special_packet_notify(struct btc_coexist *btcoexist, +					      u8 type) +{ +	if (type == BTC_PACKET_DHCP) +		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, +			  "[BTCoex], DHCP Packet notify\n"); +} + +void ex_halbtc8192e2ant_bt_info_notify(struct btc_coexist *btcoexist, +				       u8 *tmp_buf, u8 length) +{ +	u8 bt_info = 0; +	u8 i, rspsource = 0; +	bool bt_busy = false, limited_dig = false; +	bool wifi_connected = false; + +	coex_sta->c2h_bt_info_req_sent = false; + +	rspsource = tmp_buf[0] & 0xf; +	if (rspsource >= BT_INFO_SRC_8192E_2ANT_MAX) +		rspsource = BT_INFO_SRC_8192E_2ANT_WIFI_FW; +	coex_sta->bt_info_c2h_cnt[rspsource]++; + +	BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, +		  "[BTCoex], Bt info[%d], length =%d, hex data =[", +		  rspsource, length); +	for (i = 0; i < length; i++) { +		coex_sta->bt_info_c2h[rspsource][i] = tmp_buf[i]; +		if (i == 1) +			bt_info = tmp_buf[i]; +		if (i == length-1) +			BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, +				  "0x%02x]\n", tmp_buf[i]); +		else +			BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, +				  "0x%02x, ", tmp_buf[i]); +	} + +	if (BT_INFO_SRC_8192E_2ANT_WIFI_FW != rspsource) { +		coex_sta->bt_retry_cnt =	/* [3:0] */ +			coex_sta->bt_info_c2h[rspsource][2] & 0xf; + +		coex_sta->bt_rssi = +			coex_sta->bt_info_c2h[rspsource][3] * 2 + 10; + +		coex_sta->bt_info_ext = +			coex_sta->bt_info_c2h[rspsource][4]; + +		/* Here we need to resend some wifi info to BT +		 * because bt is reset and loss of the info. */ +		if ((coex_sta->bt_info_ext & BIT(1))) { +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +				  "bit1, send wifi BW&Chnl to BT!!\n"); +			btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, +					   &wifi_connected); +			if (wifi_connected) +				ex_halbtc8192e2ant_media_status_notify( +							btcoexist, +							BTC_MEDIA_CONNECT); +			else +				ex_halbtc8192e2ant_media_status_notify( +							btcoexist, +							BTC_MEDIA_DISCONNECT); +		} + +		if ((coex_sta->bt_info_ext & BIT(3))) { +			if (!btcoexist->manual_control && +			    !btcoexist->stop_coex_dm) { +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +					  "bit3, BT NOT ignore Wlan active!\n"); +				halbtc8192e2ant_ignorewlanact(btcoexist, +							      FORCE_EXEC, +							      false); +			} +		} else { +			/* BT already NOT ignore Wlan active, +			 * do nothing here. */ +		} + +#if (BT_AUTO_REPORT_ONLY_8192E_2ANT == 0) +		if ((coex_sta->bt_info_ext & BIT(4))) { +			/* BT auto report already enabled, do nothing */ +		} else { +			halbtc8192e2ant_bt_autoreport(btcoexist, FORCE_EXEC, +						      true); +		} +#endif +	} + +	/* check BIT(2) first ==> check if bt is under inquiry or page scan */ +	if (bt_info & BT_INFO_8192E_2ANT_B_INQ_PAGE) +		coex_sta->c2h_bt_inquiry_page = true; +	else +		coex_sta->c2h_bt_inquiry_page = false; + +	/* set link exist status */ +	if (!(bt_info&BT_INFO_8192E_2ANT_B_CONNECTION)) { +		coex_sta->bt_link_exist = false; +		coex_sta->pan_exist = false; +		coex_sta->a2dp_exist = false; +		coex_sta->hid_exist = false; +		coex_sta->sco_exist = false; +	} else {/* connection exists */ +		coex_sta->bt_link_exist = true; +		if (bt_info & BT_INFO_8192E_2ANT_B_FTP) +			coex_sta->pan_exist = true; +		else +			coex_sta->pan_exist = false; +		if (bt_info & BT_INFO_8192E_2ANT_B_A2DP) +			coex_sta->a2dp_exist = true; +		else +			coex_sta->a2dp_exist = false; +		if (bt_info & BT_INFO_8192E_2ANT_B_HID) +			coex_sta->hid_exist = true; +		else +			coex_sta->hid_exist = false; +		if (bt_info & BT_INFO_8192E_2ANT_B_SCO_ESCO) +			coex_sta->sco_exist = true; +		else +			coex_sta->sco_exist = false; +	} + +	halbtc8192e2ant_update_btlink_info(btcoexist); + +	if (!(bt_info&BT_INFO_8192E_2ANT_B_CONNECTION)) { +		coex_dm->bt_status = BT_8192E_2ANT_BT_STATUS_NON_CONNECTED_IDLE; +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +			  "[BTCoex], BT Non-Connected idle!!!\n"); +	} else if (bt_info == BT_INFO_8192E_2ANT_B_CONNECTION) { +		coex_dm->bt_status = BT_8192E_2ANT_BT_STATUS_CONNECTED_IDLE; +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +			  "[BTCoex], bt_infoNotify(), BT Connected-idle!!!\n"); +	} else if ((bt_info&BT_INFO_8192E_2ANT_B_SCO_ESCO) || +		   (bt_info&BT_INFO_8192E_2ANT_B_SCO_BUSY)) { +		coex_dm->bt_status = BT_8192E_2ANT_BT_STATUS_SCO_BUSY; +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +			  "[BTCoex], bt_infoNotify(), BT SCO busy!!!\n"); +	} else if (bt_info&BT_INFO_8192E_2ANT_B_ACL_BUSY) { +		coex_dm->bt_status = BT_8192E_2ANT_BT_STATUS_ACL_BUSY; +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +			  "[BTCoex], bt_infoNotify(), BT ACL busy!!!\n"); +	} else { +		coex_dm->bt_status = BT_8192E_2ANT_BT_STATUS_MAX; +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +			  "[BTCoex]bt_infoNotify(), BT Non-Defined state!!!\n"); +	} + +	if ((BT_8192E_2ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) || +	    (BT_8192E_2ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) || +	    (BT_8192E_2ANT_BT_STATUS_ACL_SCO_BUSY == coex_dm->bt_status)) { +		bt_busy = true; +		limited_dig = true; +	} else { +		bt_busy = false; +		limited_dig = false; +	} + +	btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_TRAFFIC_BUSY, &bt_busy); + +	coex_dm->limited_dig = limited_dig; +	btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_LIMITED_DIG, &limited_dig); + +	halbtc8192e2ant_run_coexist_mechanism(btcoexist); +} + +void ex_halbtc8192e2ant_stack_operation_notify(struct btc_coexist *btcoexist, +					       u8 type) +{ +} + +void ex_halbtc8192e2ant_halt_notify(struct btc_coexist *btcoexist) +{ +	BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, "[BTCoex], Halt notify\n"); + +	halbtc8192e2ant_ignorewlanact(btcoexist, FORCE_EXEC, true); +	ex_halbtc8192e2ant_media_status_notify(btcoexist, BTC_MEDIA_DISCONNECT); +} + +void ex_halbtc8192e2ant_periodical(struct btc_coexist *btcoexist) +{ +	static u8 dis_ver_info_cnt; +	u32 fw_ver = 0, bt_patch_ver = 0; +	struct btc_board_info *board_info = &btcoexist->board_info; +	struct btc_stack_info *stack_info = &btcoexist->stack_info; + +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +		  "======================= Periodical =======================\n"); +	if (dis_ver_info_cnt <= 5) { +		dis_ver_info_cnt += 1; +		BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, +			  "************************************************\n"); +		BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, +			  "Ant PG Num/ Ant Mech/ Ant Pos = %d/ %d/ %d\n", +			  board_info->pg_ant_num, board_info->btdm_ant_num, +			  board_info->btdm_ant_pos); +		BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, +			  "BT stack/ hci ext ver = %s / %d\n", +			  ((stack_info->profile_notified) ? "Yes" : "No"), +			  stack_info->hci_version); +		btcoexist->btc_get(btcoexist, BTC_GET_U4_BT_PATCH_VER, +				   &bt_patch_ver); +		btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver); +		BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, +			  "CoexVer/ FwVer/ PatchVer = %d_%x/ 0x%x/ 0x%x(%d)\n", +			  glcoex_ver_date_8192e_2ant, glcoex_ver_8192e_2ant, +			  fw_ver, bt_patch_ver, bt_patch_ver); +		BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, +			  "************************************************\n"); +	} + +#if (BT_AUTO_REPORT_ONLY_8192E_2ANT == 0) +	halbtc8192e2ant_querybt_info(btcoexist); +	halbtc8192e2ant_monitor_bt_ctr(btcoexist); +	halbtc_monitor_bt_enable_disable(btcoexist); +#else +	if (halbtc8192e2ant_iswifi_status_changed(btcoexist) || +	    coex_dm->auto_tdma_adjust) +		halbtc8192e2ant_run_coexist_mechanism(btcoexist); +#endif +} diff --git a/drivers/staging/rtl8192ee/btcoexist/halbtc8192e2ant.h b/drivers/staging/rtl8192ee/btcoexist/halbtc8192e2ant.h new file mode 100644 index 00000000000..ece3e10e6df --- /dev/null +++ b/drivers/staging/rtl8192ee/btcoexist/halbtc8192e2ant.h @@ -0,0 +1,161 @@ +/***************************************************************** + *   The following is for 8192E 2Ant BT Co-exist definition + *****************************************************************/ +#define	BT_AUTO_REPORT_ONLY_8192E_2ANT			0 + +#define	BT_INFO_8192E_2ANT_B_FTP			BIT(7) +#define	BT_INFO_8192E_2ANT_B_A2DP			BIT(6) +#define	BT_INFO_8192E_2ANT_B_HID			BIT(5) +#define	BT_INFO_8192E_2ANT_B_SCO_BUSY			BIT(4) +#define	BT_INFO_8192E_2ANT_B_ACL_BUSY			BIT(3) +#define	BT_INFO_8192E_2ANT_B_INQ_PAGE			BIT(2) +#define	BT_INFO_8192E_2ANT_B_SCO_ESCO			BIT(1) +#define	BT_INFO_8192E_2ANT_B_CONNECTION			BIT(0) + +#define BTC_RSSI_COEX_THRESH_TOL_8192E_2ANT		2 + +enum bt_info_src_8192e_2ant { +	BT_INFO_SRC_8192E_2ANT_WIFI_FW			= 0x0, +	BT_INFO_SRC_8192E_2ANT_BT_RSP			= 0x1, +	BT_INFO_SRC_8192E_2ANT_BT_ACTIVE_SEND		= 0x2, +	BT_INFO_SRC_8192E_2ANT_MAX +}; + +enum bt_8192e_2ant_bt_status { +	BT_8192E_2ANT_BT_STATUS_NON_CONNECTED_IDLE	= 0x0, +	BT_8192E_2ANT_BT_STATUS_CONNECTED_IDLE		= 0x1, +	BT_8192E_2ANT_BT_STATUS_INQ_PAGE		= 0x2, +	BT_8192E_2ANT_BT_STATUS_ACL_BUSY		= 0x3, +	BT_8192E_2ANT_BT_STATUS_SCO_BUSY		= 0x4, +	BT_8192E_2ANT_BT_STATUS_ACL_SCO_BUSY		= 0x5, +	BT_8192E_2ANT_BT_STATUS_MAX +}; + +enum bt_8192e_2ant_coex_algo { +	BT_8192E_2ANT_COEX_ALGO_UNDEFINED		= 0x0, +	BT_8192E_2ANT_COEX_ALGO_SCO			= 0x1, +	BT_8192E_2ANT_COEX_ALGO_SCO_PAN			= 0x2, +	BT_8192E_2ANT_COEX_ALGO_HID			= 0x3, +	BT_8192E_2ANT_COEX_ALGO_A2DP			= 0x4, +	BT_8192E_2ANT_COEX_ALGO_A2DP_PANHS		= 0x5, +	BT_8192E_2ANT_COEX_ALGO_PANEDR			= 0x6, +	BT_8192E_2ANT_COEX_ALGO_PANHS			= 0x7, +	BT_8192E_2ANT_COEX_ALGO_PANEDR_A2DP		= 0x8, +	BT_8192E_2ANT_COEX_ALGO_PANEDR_HID		= 0x9, +	BT_8192E_2ANT_COEX_ALGO_HID_A2DP_PANEDR		= 0xa, +	BT_8192E_2ANT_COEX_ALGO_HID_A2DP		= 0xb, +	BT_8192E_2ANT_COEX_ALGO_MAX			= 0xc +}; + +struct coex_dm_8192e_2ant { +	/* fw mechanism */ +	u8 pre_dec_bt_pwr; +	u8 cur_dec_bt_pwr; +	u8 pre_fw_dac_swing_lvl; +	u8 cur_fw_dac_swing_lvl; +	bool cur_ignore_wlan_act; +	bool pre_ignore_wlan_act; +	u8 pre_ps_tdma; +	u8 cur_ps_tdma; +	u8 ps_tdma_para[5]; +	u8 ps_tdma_du_adj_type; +	bool reset_tdma_adjust; +	bool auto_tdma_adjust; +	bool pre_ps_tdma_on; +	bool cur_ps_tdma_on; +	bool pre_bt_auto_report; +	bool cur_bt_auto_report; + +	/* sw mechanism */ +	bool pre_rf_rx_lpf_shrink; +	bool cur_rf_rx_lpf_shrink; +	u32 bt_rf0x1e_backup; +	bool pre_low_penalty_ra; +	bool cur_low_penalty_ra; +	bool pre_dac_swing_on; +	u32 pre_dac_swing_lvl; +	bool cur_dac_swing_on; +	u32 cur_dac_swing_lvl; +	bool pre_adc_back_off; +	bool cur_adc_back_off; +	bool pre_agc_table_en; +	bool cur_agc_table_en; +	u32 pre_val0x6c0; +	u32 cur_val0x6c0; +	u32 pre_val0x6c4; +	u32 cur_val0x6c4; +	u32 pre_val0x6c8; +	u32 cur_val0x6c8; +	u8 pre_val0x6cc; +	u8 cur_val0x6cc; +	bool limited_dig; + +	u32 backup_arfr_cnt1;	/* Auto Rate Fallback Retry cnt */ +	u32 backup_arfr_cnt2;	/* Auto Rate Fallback Retry cnt */ +	u16 backup_retrylimit; +	u8 backup_ampdu_maxtime; + +	/* algorithm related */ +	u8 pre_algorithm; +	u8 cur_algorithm; +	u8 bt_status; +	u8 wifi_chnl_info[3]; + +	u8 pre_sstype; +	u8 cur_sstype; + +	u32 prera_mask; +	u32 curra_mask; +	u8 curra_masktype; +	u8 pre_arfrtype; +	u8 cur_arfrtype; +	u8 pre_retrylimit_type; +	u8 cur_retrylimit_type; +	u8 pre_ampdutime_type; +	u8 cur_ampdutime_type; +}; + +struct coex_sta_8192e_2ant { +	bool bt_link_exist; +	bool sco_exist; +	bool a2dp_exist; +	bool hid_exist; +	bool pan_exist; + +	bool under_lps; +	bool under_ips; +	u32 high_priority_tx; +	u32 high_priority_rx; +	u32 low_priority_tx; +	u32 low_priority_rx; +	u8 bt_rssi; +	u8 pre_bt_rssi_state; +	u8 pre_wifi_rssi_state[4]; +	bool c2h_bt_info_req_sent; +	u8 bt_info_c2h[BT_INFO_SRC_8192E_2ANT_MAX][10]; +	u32 bt_info_c2h_cnt[BT_INFO_SRC_8192E_2ANT_MAX]; +	bool c2h_bt_inquiry_page; +	u8 bt_retry_cnt; +	u8 bt_info_ext; +}; + +/**************************************************************** + *    The following is interface which will notify coex module. + ****************************************************************/ +void ex_halbtc8192e2ant_init_hwconfig(struct btc_coexist *btcoexist); +void ex_halbtc8192e2ant_init_coex_dm(struct btc_coexist *btcoexist); +void ex_halbtc8192e2ant_ips_notify(struct btc_coexist *btcoexist, u8 type); +void ex_halbtc8192e2ant_lps_notify(struct btc_coexist *btcoexist, u8 type); +void ex_halbtc8192e2ant_scan_notify(struct btc_coexist *btcoexist, u8 type); +void ex_halbtc8192e2ant_connect_notify(struct btc_coexist *btcoexist, u8 type); +void ex_halbtc8192e2ant_media_status_notify(struct btc_coexist *btcoexist, +					    u8 type); +void ex_halbtc8192e2ant_special_packet_notify(struct btc_coexist *btcoexist, +					      u8 type); +void ex_halbtc8192e2ant_bt_info_notify(struct btc_coexist *btcoexist, +				       u8 *tmpbuf, u8 length); +void ex_halbtc8192e2ant_stack_operation_notify(struct btc_coexist *btcoexist, +					       u8 type); +void ex_halbtc8192e2ant_halt_notify(struct btc_coexist *btcoexist); +void ex_halbtc8192e2ant_periodical(struct btc_coexist *btcoexist); +void ex_halbtc8192e2ant_display_coex_info(struct btc_coexist *btcoexist); diff --git a/drivers/staging/rtl8192ee/btcoexist/halbtc8723b1ant.c b/drivers/staging/rtl8192ee/btcoexist/halbtc8723b1ant.c new file mode 100644 index 00000000000..153048f6b4d --- /dev/null +++ b/drivers/staging/rtl8192ee/btcoexist/halbtc8723b1ant.c @@ -0,0 +1,3146 @@ +/*************************************************************** + * Description: + * + * This file is for RTL8723B Co-exist mechanism + * + * History + * 2012/11/15 Cosa first check in. + * + ***************************************************************/ + +/*************************************************************** + * include files + ***************************************************************/ +#include "halbt_precomp.h" +/*************************************************************** + * Global variables, these are static variables + ***************************************************************/ +static struct coex_dm_8723b_1ant glcoex_dm_8723b_1ant; +static struct coex_dm_8723b_1ant *coex_dm = &glcoex_dm_8723b_1ant; +static struct coex_sta_8723b_1ant glcoex_sta_8723b_1ant; +static struct coex_sta_8723b_1ant *coex_sta = &glcoex_sta_8723b_1ant; + +static const char *const glb_infosrc8723b1ant[] = { +	"BT Info[wifi fw]", +	"BT Info[bt rsp]", +	"BT Info[bt auto report]", +}; + +static u32 glcoex_ver_date_8723b_1ant = 20130918; +static u32 glcoex_ver_8723b_1ant = 0x47; + +/*************************************************************** + * local function proto type if needed + ***************************************************************/ +/*************************************************************** + * local function start with halbtc8723b1ant_ + ***************************************************************/ +static u8 halbtc8723b1ant_bt_rssi_state(u8 level_num, u8 rssi_thresh, +					u8 rssi_thresh1) +{ +	s32 bt_rssi = 0; +	u8 rssi_state = coex_sta->pre_bt_rssi_state; + +	bt_rssi = coex_sta->bt_rssi; + +	if (level_num == 2) { +		if ((coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_LOW) || +		    (coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_STAY_LOW)) { +			if (bt_rssi >= rssi_thresh + +					BTC_RSSI_COEX_THRESH_TOL_8723B_1ANT) { +				rssi_state = BTC_RSSI_STATE_HIGH; +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, +					  "[BTCoex], BT Rssi state switch to High\n"); +			} else { +				rssi_state = BTC_RSSI_STATE_STAY_LOW; +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, +					  "[BTCoex], BT Rssi state stay at Low\n"); +			} +		} else { +			if (bt_rssi < rssi_thresh) { +				rssi_state = BTC_RSSI_STATE_LOW; +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, +					  "[BTCoex], BT Rssi state switch to Low\n"); +			} else { +				rssi_state = BTC_RSSI_STATE_STAY_HIGH; +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, +					  "[BTCoex], BT Rssi state stay at High\n"); +			} +		} +	} else if (level_num == 3) { +		if (rssi_thresh > rssi_thresh1) { +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, +				  "[BTCoex], BT Rssi thresh error!!\n"); +			return coex_sta->pre_bt_rssi_state; +		} + +		if ((coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_LOW) || +		    (coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_STAY_LOW)) { +			if (bt_rssi >= rssi_thresh + +					BTC_RSSI_COEX_THRESH_TOL_8723B_1ANT) { +				rssi_state = BTC_RSSI_STATE_MEDIUM; +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, +					  "[BTCoex], BT Rssi state switch to Medium\n"); +			} else { +				rssi_state = BTC_RSSI_STATE_STAY_LOW; +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, +					  "[BTCoex], BT Rssi state stay at Low\n"); +			} +		} else if ((coex_sta->pre_bt_rssi_state == +					BTC_RSSI_STATE_MEDIUM) || +			  (coex_sta->pre_bt_rssi_state == +					BTC_RSSI_STATE_STAY_MEDIUM)) { +			if (bt_rssi >= rssi_thresh1 + +					BTC_RSSI_COEX_THRESH_TOL_8723B_1ANT) { +				rssi_state = BTC_RSSI_STATE_HIGH; +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, +					  "[BTCoex], BT Rssi state switch to High\n"); +			} else if (bt_rssi < rssi_thresh) { +				rssi_state = BTC_RSSI_STATE_LOW; +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, +					  "[BTCoex], BT Rssi state switch to Low\n"); +			} else { +				rssi_state = BTC_RSSI_STATE_STAY_MEDIUM; +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, +					  "[BTCoex], BT Rssi state stay at Medium\n"); +			} +		} else { +			if (bt_rssi < rssi_thresh1) { +				rssi_state = BTC_RSSI_STATE_MEDIUM; +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, +					  "[BTCoex], BT Rssi state switch to Medium\n"); +			} else { +				rssi_state = BTC_RSSI_STATE_STAY_HIGH; +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, +					  "[BTCoex], BT Rssi state stay at High\n"); +			} +		} +	} + +	coex_sta->pre_bt_rssi_state = rssi_state; + +	return rssi_state; +} + +static u8 halbtc8723b1ant_wifi_rssi_state(struct btc_coexist *btcoexist, +					  u8 index, u8 level_num, +					  u8 rssi_thresh, u8 rssi_thresh1) +{ +	s32 wifi_rssi = 0; +	u8 wifi_rssi_state = coex_sta->pre_wifi_rssi_state[index]; + +	btcoexist->btc_get(btcoexist, +		BTC_GET_S4_WIFI_RSSI, &wifi_rssi); + +	if (level_num == 2) { +		if ((coex_sta->pre_wifi_rssi_state[index] == +					BTC_RSSI_STATE_LOW) || +		    (coex_sta->pre_wifi_rssi_state[index] == +					BTC_RSSI_STATE_STAY_LOW)) { +			if (wifi_rssi >= rssi_thresh + +					BTC_RSSI_COEX_THRESH_TOL_8723B_1ANT) { +				wifi_rssi_state = BTC_RSSI_STATE_HIGH; +				BTC_PRINT(BTC_MSG_ALGORITHM, +					  ALGO_WIFI_RSSI_STATE, +					  "[BTCoex], wifi RSSI state switch to High\n"); +			} else { +				wifi_rssi_state = BTC_RSSI_STATE_STAY_LOW; +				BTC_PRINT(BTC_MSG_ALGORITHM, +					  ALGO_WIFI_RSSI_STATE, +					  "[BTCoex], wifi RSSI state stay at Low\n"); +			} +		} else { +			if (wifi_rssi < rssi_thresh) { +				wifi_rssi_state = BTC_RSSI_STATE_LOW; +				BTC_PRINT(BTC_MSG_ALGORITHM, +					  ALGO_WIFI_RSSI_STATE, +					  "[BTCoex], wifi RSSI state switch to Low\n"); +			} else { +				wifi_rssi_state = BTC_RSSI_STATE_STAY_HIGH; +				BTC_PRINT(BTC_MSG_ALGORITHM, +					  ALGO_WIFI_RSSI_STATE, +					  "[BTCoex], wifi RSSI state stay at High\n"); +			} +		} +	} else if (level_num == 3) { +		if (rssi_thresh > rssi_thresh1) { +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, +				  "[BTCoex], wifi RSSI thresh error!!\n"); +			return coex_sta->pre_wifi_rssi_state[index]; +		} + +		if ((coex_sta->pre_wifi_rssi_state[index] == +						BTC_RSSI_STATE_LOW) || +		    (coex_sta->pre_wifi_rssi_state[index] == +						BTC_RSSI_STATE_STAY_LOW)) { +			if (wifi_rssi >= rssi_thresh + +					 BTC_RSSI_COEX_THRESH_TOL_8723B_1ANT) { +				wifi_rssi_state = BTC_RSSI_STATE_MEDIUM; +				BTC_PRINT(BTC_MSG_ALGORITHM, +					  ALGO_WIFI_RSSI_STATE, +					  "[BTCoex], wifi RSSI state switch to Medium\n"); +			} else { +				wifi_rssi_state = BTC_RSSI_STATE_STAY_LOW; +				BTC_PRINT(BTC_MSG_ALGORITHM, +					  ALGO_WIFI_RSSI_STATE, +					  "[BTCoex], wifi RSSI state stay at Low\n"); +			} +		} else if ((coex_sta->pre_wifi_rssi_state[index] == +						BTC_RSSI_STATE_MEDIUM) || +			   (coex_sta->pre_wifi_rssi_state[index] == +						BTC_RSSI_STATE_STAY_MEDIUM)) { +			if (wifi_rssi >= rssi_thresh1 + +					 BTC_RSSI_COEX_THRESH_TOL_8723B_1ANT) { +				wifi_rssi_state = BTC_RSSI_STATE_HIGH; +				BTC_PRINT(BTC_MSG_ALGORITHM, +					  ALGO_WIFI_RSSI_STATE, +					  "[BTCoex], wifi RSSI state switch to High\n"); +			} else if (wifi_rssi < rssi_thresh) { +				wifi_rssi_state = BTC_RSSI_STATE_LOW; +				BTC_PRINT(BTC_MSG_ALGORITHM, +					  ALGO_WIFI_RSSI_STATE, +					  "[BTCoex], wifi RSSI state switch to Low\n"); +			} else { +				wifi_rssi_state = BTC_RSSI_STATE_STAY_MEDIUM; +				BTC_PRINT(BTC_MSG_ALGORITHM, +					  ALGO_WIFI_RSSI_STATE, +					  "[BTCoex], wifi RSSI state stay at Medium\n"); +			} +		} else { +			if (wifi_rssi < rssi_thresh1) { +				wifi_rssi_state = BTC_RSSI_STATE_MEDIUM; +				BTC_PRINT(BTC_MSG_ALGORITHM, +					  ALGO_WIFI_RSSI_STATE, +					  "[BTCoex], wifi RSSI state switch to Medium\n"); +			} else { +				wifi_rssi_state = BTC_RSSI_STATE_STAY_HIGH; +				BTC_PRINT(BTC_MSG_ALGORITHM, +					  ALGO_WIFI_RSSI_STATE, +					  "[BTCoex], wifi RSSI state stay at High\n"); +			} +		} +	} + +	coex_sta->pre_wifi_rssi_state[index] = wifi_rssi_state; + +	return wifi_rssi_state; +} + +static void halbtc8723b1ant_updatera_mask(struct btc_coexist *btcoexist, +					  bool force_exec, u32 dis_rate_mask) +{ +	coex_dm->curra_mask = dis_rate_mask; + +	if (force_exec || (coex_dm->prera_mask != coex_dm->curra_mask)) +		btcoexist->btc_set(btcoexist, BTC_SET_ACT_UPDATE_ra_mask, +				   &coex_dm->curra_mask); + +	coex_dm->prera_mask = coex_dm->curra_mask; +} + +static void auto_rate_fallback_retry(struct btc_coexist *btcoexist, +				     bool force_exec, u8 type) +{ +	bool wifi_under_bmode = false; + +	coex_dm->cur_arfr_type = type; + +	if (force_exec || (coex_dm->pre_arfr_type != coex_dm->cur_arfr_type)) { +		switch (coex_dm->cur_arfr_type) { +		case 0:	/* normal mode */ +			btcoexist->btc_write_4byte(btcoexist, 0x430, +						   coex_dm->backup_arfr_cnt1); +			btcoexist->btc_write_4byte(btcoexist, 0x434, +						   coex_dm->backup_arfr_cnt2); +			break; +		case 1: +			btcoexist->btc_get(btcoexist, +					   BTC_GET_BL_WIFI_UNDER_B_MODE, +					   &wifi_under_bmode); +			if (wifi_under_bmode) { +				btcoexist->btc_write_4byte(btcoexist, +							   0x430, 0x0); +				btcoexist->btc_write_4byte(btcoexist, +							   0x434, 0x01010101); +			} else { +				btcoexist->btc_write_4byte(btcoexist, +							   0x430, 0x0); +				btcoexist->btc_write_4byte(btcoexist, +							   0x434, 0x04030201); +			} +			break; +		default: +			break; +		} +	} + +	coex_dm->pre_arfr_type = coex_dm->cur_arfr_type; +} + +static void halbtc8723b1ant_retry_limit(struct btc_coexist *btcoexist, +					bool force_exec, u8 type) +{ +	coex_dm->cur_retry_limit_type = type; + +	if (force_exec || (coex_dm->pre_retry_limit_type != +			   coex_dm->cur_retry_limit_type)) { +		switch (coex_dm->cur_retry_limit_type) { +		case 0:	/* normal mode */ +			btcoexist->btc_write_2byte(btcoexist, 0x42a, +						   coex_dm->backup_retry_limit); +			break; +		case 1:	/* retry limit = 8 */ +			btcoexist->btc_write_2byte(btcoexist, 0x42a, 0x0808); +			break; +		default: +			break; +		} +	} + +	coex_dm->pre_retry_limit_type = coex_dm->cur_retry_limit_type; +} + +static void halbtc8723b1ant_ampdu_maxtime(struct btc_coexist *btcoexist, +					  bool force_exec, u8 type) +{ +	coex_dm->cur_ampdu_time_type = type; + +	if (force_exec || (coex_dm->pre_ampdu_time_type != +		coex_dm->cur_ampdu_time_type)) { +		switch (coex_dm->cur_ampdu_time_type) { +		case 0:	/* normal mode */ +			btcoexist->btc_write_1byte(btcoexist, 0x456, +					coex_dm->backup_ampdu_max_time); +			break; +		case 1:	/* AMPDU timw = 0x38 * 32us */ +			btcoexist->btc_write_1byte(btcoexist, +						   0x456, 0x38); +			break; +		default: +			break; +		} +	} + +	coex_dm->pre_ampdu_time_type = coex_dm->cur_ampdu_time_type; +} + +static void halbtc8723b1ant_limited_tx(struct btc_coexist *btcoexist, +				       bool force_exec, u8 ra_masktype, +				       u8 arfr_type, u8 retry_limit_type, +				       u8 ampdu_time_type) +{ +	switch (ra_masktype) { +	case 0:	/* normal mode */ +		halbtc8723b1ant_updatera_mask(btcoexist, force_exec, 0x0); +		break; +	case 1:	/* disable cck 1/2 */ +		halbtc8723b1ant_updatera_mask(btcoexist, force_exec, +					      0x00000003); +		break; +	/* disable cck 1/2/5.5, ofdm 6/9/12/18/24, mcs 0/1/2/3/4*/ +	case 2: +		halbtc8723b1ant_updatera_mask(btcoexist, force_exec, +					      0x0001f1f7); +		break; +	default: +		break; +	} + +	auto_rate_fallback_retry(btcoexist, force_exec, arfr_type); +	halbtc8723b1ant_retry_limit(btcoexist, force_exec, retry_limit_type); +	halbtc8723b1ant_ampdu_maxtime(btcoexist, force_exec, ampdu_time_type); +} + +static void halbtc8723b1ant_limited_rx(struct btc_coexist *btcoexist, +				       bool force_exec, bool rej_ap_agg_pkt, +				bool b_bt_ctrl_agg_buf_size, u8 agg_buf_size) +{ +	bool reject_rx_agg = rej_ap_agg_pkt; +	bool bt_ctrl_rx_agg_size = b_bt_ctrl_agg_buf_size; +	u8 rxaggsize = agg_buf_size; + +	/********************************************** +	 *	Rx Aggregation related setting +	 **********************************************/ +	btcoexist->btc_set(btcoexist, BTC_SET_BL_TO_REJ_AP_AGG_PKT, +			   &reject_rx_agg); +	/* decide BT control aggregation buf size or not  */ +	btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_CTRL_AGG_SIZE, +			   &bt_ctrl_rx_agg_size); +	/* aggregation buf size, only work +	 *when BT control Rx aggregation size.  */ +	btcoexist->btc_set(btcoexist, BTC_SET_U1_AGG_BUF_SIZE, &rxaggsize); +	/* real update aggregation setting  */ +	btcoexist->btc_set(btcoexist, BTC_SET_ACT_AGGREGATE_CTRL, NULL); +} + +static void halbtc8723b1ant_monitor_bt_ctr(struct btc_coexist *btcoexist) +{ +	u32 reg_hp_txrx, reg_lp_txrx, u32tmp; +	u32 reg_hp_tx = 0, reg_hp_rx = 0; +	u32 reg_lp_tx = 0, reg_lp_rx = 0; + +	reg_hp_txrx = 0x770; +	reg_lp_txrx = 0x774; + +	u32tmp = btcoexist->btc_read_4byte(btcoexist, reg_hp_txrx); +	reg_hp_tx = u32tmp & MASKLWORD; +	reg_hp_rx = (u32tmp & MASKHWORD) >> 16; + +	u32tmp = btcoexist->btc_read_4byte(btcoexist, reg_lp_txrx); +	reg_lp_tx = u32tmp & MASKLWORD; +	reg_lp_rx = (u32tmp & MASKHWORD) >> 16; + +	coex_sta->high_priority_tx = reg_hp_tx; +	coex_sta->high_priority_rx = reg_hp_rx; +	coex_sta->low_priority_tx = reg_lp_tx; +	coex_sta->low_priority_rx = reg_lp_rx; + +	/* reset counter */ +	btcoexist->btc_write_1byte(btcoexist, 0x76e, 0xc); +} + +static void halbtc8723b1ant_query_bt_info(struct btc_coexist *btcoexist) +{ +	u8 h2c_parameter[1] = {0}; + +	coex_sta->c2h_bt_info_req_sent = true; + +	h2c_parameter[0] |= BIT(0);	/* trigger*/ + +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, +		  "[BTCoex], Query Bt Info, FW write 0x61 = 0x%x\n", +		  h2c_parameter[0]); + +	btcoexist->btc_fill_h2c(btcoexist, 0x61, 1, h2c_parameter); +} + +static bool is_wifi_status_changed(struct btc_coexist *btcoexist) +{ +	static bool pre_wifi_busy; +	static bool pre_under_4way, pre_bt_hs_on; +	bool wifi_busy = false, under_4way = false, bt_hs_on = false; +	bool wifi_connected = false; + +	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, +			   &wifi_connected); +	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); +	btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); +	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS, +			   &under_4way); + +	if (wifi_connected) { +		if (wifi_busy != pre_wifi_busy) { +			pre_wifi_busy = wifi_busy; +			return true; +		} +		if (under_4way != pre_under_4way) { +			pre_under_4way = under_4way; +			return true; +		} +		if (bt_hs_on != pre_bt_hs_on) { +			pre_bt_hs_on = bt_hs_on; +			return true; +		} +	} + +	return false; +} + +static void halbtc8723b1ant_update_bt_link_info(struct btc_coexist *btcoexist) +{ +	struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; +	bool bt_hs_on = false; + +	btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + +	bt_link_info->bt_link_exist = coex_sta->bt_link_exist; +	bt_link_info->sco_exist = coex_sta->sco_exist; +	bt_link_info->a2dp_exist = coex_sta->a2dp_exist; +	bt_link_info->pan_exist = coex_sta->pan_exist; +	bt_link_info->hid_exist = coex_sta->hid_exist; + +	/* work around for HS mode. */ +	if (bt_hs_on) { +		bt_link_info->pan_exist = true; +		bt_link_info->bt_link_exist = true; +	} + +	/* check if Sco only */ +	if (bt_link_info->sco_exist && !bt_link_info->a2dp_exist && +	    !bt_link_info->pan_exist && !bt_link_info->hid_exist) +		bt_link_info->sco_only = true; +	else +		bt_link_info->sco_only = false; + +	/* check if A2dp only */ +	if (!bt_link_info->sco_exist && bt_link_info->a2dp_exist && +	    !bt_link_info->pan_exist && !bt_link_info->hid_exist) +		bt_link_info->a2dp_only = true; +	else +		bt_link_info->a2dp_only = false; + +	/* check if Pan only */ +	if (!bt_link_info->sco_exist && !bt_link_info->a2dp_exist && +	    bt_link_info->pan_exist && !bt_link_info->hid_exist) +		bt_link_info->pan_only = true; +	else +		bt_link_info->pan_only = false; + +	/* check if Hid only */ +	if (!bt_link_info->sco_exist && !bt_link_info->a2dp_exist && +	    !bt_link_info->pan_exist && bt_link_info->hid_exist) +		bt_link_info->hid_only = true; +	else +		bt_link_info->hid_only = false; +} + +static u8 halbtc8723b1ant_action_algorithm(struct btc_coexist *btcoexist) +{ +	struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; +	bool bt_hs_on = false; +	u8 algorithm = BT_8723B_1ANT_COEX_ALGO_UNDEFINED; +	u8 numofdiffprofile = 0; + +	btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + +	if (!bt_link_info->bt_link_exist) { +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +			  "[BTCoex], No BT link exists!!!\n"); +		return algorithm; +	} + +	if (bt_link_info->sco_exist) +		numofdiffprofile++; +	if (bt_link_info->hid_exist) +		numofdiffprofile++; +	if (bt_link_info->pan_exist) +		numofdiffprofile++; +	if (bt_link_info->a2dp_exist) +		numofdiffprofile++; + +	if (numofdiffprofile == 1) { +		if (bt_link_info->sco_exist) { +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +				  "[BTCoex], BT Profile = SCO only\n"); +			algorithm = BT_8723B_1ANT_COEX_ALGO_SCO; +		} else { +			if (bt_link_info->hid_exist) { +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +					  "[BTCoex], BT Profile = HID only\n"); +				algorithm = BT_8723B_1ANT_COEX_ALGO_HID; +			} else if (bt_link_info->a2dp_exist) { +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +					  "[BTCoex], BT Profile = A2DP only\n"); +				algorithm = BT_8723B_1ANT_COEX_ALGO_A2DP; +			} else if (bt_link_info->pan_exist) { +				if (bt_hs_on) { +					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +						  "[BTCoex], BT Profile = PAN(HS) only\n"); +					algorithm = +						BT_8723B_1ANT_COEX_ALGO_PANHS; +				} else { +					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +						  "[BTCoex], BT Profile = PAN(EDR) only\n"); +					algorithm = +						BT_8723B_1ANT_COEX_ALGO_PANEDR; +				} +			} +		} +	} else if (numofdiffprofile == 2) { +		if (bt_link_info->sco_exist) { +			if (bt_link_info->hid_exist) { +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +					  "[BTCoex], BT Profile = SCO + HID\n"); +				algorithm = BT_8723B_1ANT_COEX_ALGO_HID; +			} else if (bt_link_info->a2dp_exist) { +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +					  "[BTCoex], BT Profile = SCO + A2DP ==> SCO\n"); +				algorithm = BT_8723B_1ANT_COEX_ALGO_SCO; +			} else if (bt_link_info->pan_exist) { +				if (bt_hs_on) { +					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +						  "[BTCoex], BT Profile = SCO + PAN(HS)\n"); +					algorithm = BT_8723B_1ANT_COEX_ALGO_SCO; +				} else { +					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +						  "[BTCoex], BT Profile = SCO + PAN(EDR)\n"); +					algorithm = +					    BT_8723B_1ANT_COEX_ALGO_PANEDR_HID; +				} +			} +		} else { +			if (bt_link_info->hid_exist && +			    bt_link_info->a2dp_exist) { +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +					  "[BTCoex], BT Profile = HID + A2DP\n"); +				algorithm = BT_8723B_1ANT_COEX_ALGO_HID_A2DP; +			} else if (bt_link_info->hid_exist && +				   bt_link_info->pan_exist) { +				if (bt_hs_on) { +					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +						  "[BTCoex], BT Profile = HID + PAN(HS)\n"); +					algorithm = +					    BT_8723B_1ANT_COEX_ALGO_HID_A2DP; +				} else { +					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +						  "[BTCoex], BT Profile = HID + PAN(EDR)\n"); +					algorithm = +					    BT_8723B_1ANT_COEX_ALGO_PANEDR_HID; +				} +			} else if (bt_link_info->pan_exist && +				   bt_link_info->a2dp_exist) { +				if (bt_hs_on) { +					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +						  "[BTCoex], BT Profile = A2DP + PAN(HS)\n"); +					algorithm = +					    BT_8723B_1ANT_COEX_ALGO_A2DP_PANHS; +				} else { +					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +						  "[BTCoex], BT Profile = A2DP + PAN(EDR)\n"); +					algorithm = +					    BT_8723B_1ANT_COEX_ALGO_PANEDR_A2DP; +				} +			} +		} +	} else if (numofdiffprofile == 3) { +		if (bt_link_info->sco_exist) { +			if (bt_link_info->hid_exist && +			    bt_link_info->a2dp_exist) { +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +					  "[BTCoex], BT Profile = SCO + HID + A2DP ==> HID\n"); +				algorithm = BT_8723B_1ANT_COEX_ALGO_HID; +			} else if (bt_link_info->hid_exist && +				   bt_link_info->pan_exist) { +				if (bt_hs_on) { +					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +						  "[BTCoex], BT Profile = SCO + HID + PAN(HS)\n"); +					algorithm = +					    BT_8723B_1ANT_COEX_ALGO_HID_A2DP; +				} else { +					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +						  "[BTCoex], BT Profile = SCO + HID + PAN(EDR)\n"); +					algorithm = +					    BT_8723B_1ANT_COEX_ALGO_PANEDR_HID; +				} +			} else if (bt_link_info->pan_exist && +				   bt_link_info->a2dp_exist) { +				if (bt_hs_on) { +					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +						  "[BTCoex], BT Profile = SCO + A2DP + PAN(HS)\n"); +					algorithm = BT_8723B_1ANT_COEX_ALGO_SCO; +				} else { +					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +						  "[BTCoex], BT Profile = SCO + A2DP + PAN(EDR) ==> HID\n"); +					algorithm = +					    BT_8723B_1ANT_COEX_ALGO_PANEDR_HID; +				} +			} +		} else { +			if (bt_link_info->hid_exist && +			    bt_link_info->pan_exist && +			    bt_link_info->a2dp_exist) { +				if (bt_hs_on) { +					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +						  "[BTCoex], BT Profile = HID + A2DP + PAN(HS)\n"); +					algorithm = +					    BT_8723B_1ANT_COEX_ALGO_HID_A2DP; +				} else { +					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +						  "[BTCoex], BT Profile = HID + A2DP + PAN(EDR)\n"); +					algorithm = +					    BT_8723B_1ANT_COEX_ALGO_HID_A2DP_PANEDR; +				} +			} +		} +	} else if (numofdiffprofile >= 3) { +		if (bt_link_info->sco_exist) { +			if (bt_link_info->hid_exist && +			    bt_link_info->pan_exist && +			    bt_link_info->a2dp_exist) { +				if (bt_hs_on) { +					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +						  "[BTCoex], Error!!! BT Profile = SCO + HID + A2DP + PAN(HS)\n"); +				} else { +					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +						  "[BTCoex], BT Profile = SCO + HID + A2DP + PAN(EDR) ==>PAN(EDR)+HID\n"); +					algorithm = +					    BT_8723B_1ANT_COEX_ALGO_PANEDR_HID; +				} +			} +		} +	} + +	return algorithm; +} + +static void set_sw_penalty_tx_rate_adapt(struct btc_coexist *btcoexist, +					 bool low_penalty_ra) +{ +	u8 h2c_parameter[6] = {0}; + +	h2c_parameter[0] = 0x6;	/* opCode, 0x6 = Retry_Penalty */ + +	if (low_penalty_ra) { +		h2c_parameter[1] |= BIT(0); +		/*normal rate except MCS7/6/5, OFDM54/48/36 */ +		h2c_parameter[2] = 0x00; +		h2c_parameter[3] = 0xf7;  /*MCS7 or OFDM54 */ +		h2c_parameter[4] = 0xf8;  /*MCS6 or OFDM48 */ +		h2c_parameter[5] = 0xf9;  /*MCS5 or OFDM36 */ +	} + +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, +		  "[BTCoex], set WiFi Low-Penalty Retry: %s", +		  (low_penalty_ra ? "ON!!" : "OFF!!")); + +	btcoexist->btc_fill_h2c(btcoexist, 0x69, 6, h2c_parameter); +} + +static void halbtc8723b1ant_low_penalty_ra(struct btc_coexist *btcoexist, +					   bool force_exec, bool low_penalty_ra) +{ +	coex_dm->cur_low_penalty_ra = low_penalty_ra; + +	if (!force_exec) { +		if (coex_dm->pre_low_penalty_ra == coex_dm->cur_low_penalty_ra) +			return; +	} +	set_sw_penalty_tx_rate_adapt(btcoexist, coex_dm->cur_low_penalty_ra); + +	coex_dm->pre_low_penalty_ra = coex_dm->cur_low_penalty_ra; +} + +static void halbtc8723b1ant_set_coex_table(struct btc_coexist *btcoexist, +					   u32 val0x6c0, u32 val0x6c4, +					   u32 val0x6c8, u8 val0x6cc) +{ +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, +		  "[BTCoex], set coex table, set 0x6c0 = 0x%x\n", val0x6c0); +	btcoexist->btc_write_4byte(btcoexist, 0x6c0, val0x6c0); + +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, +		  "[BTCoex], set coex table, set 0x6c4 = 0x%x\n", val0x6c4); +	btcoexist->btc_write_4byte(btcoexist, 0x6c4, val0x6c4); + +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, +		  "[BTCoex], set coex table, set 0x6c8 = 0x%x\n", val0x6c8); +	btcoexist->btc_write_4byte(btcoexist, 0x6c8, val0x6c8); + +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, +		  "[BTCoex], set coex table, set 0x6cc = 0x%x\n", val0x6cc); +	btcoexist->btc_write_1byte(btcoexist, 0x6cc, val0x6cc); +} + +static void halbtc8723b1ant_coex_table(struct btc_coexist *btcoexist, +				       bool force_exec, u32 val0x6c0, +				       u32 val0x6c4, u32 val0x6c8, +				       u8 val0x6cc) +{ +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, +		  "[BTCoex], %s write Coex Table 0x6c0 = 0x%x, 0x6c4 = 0x%x, 0x6cc = 0x%x\n", +		  (force_exec ? "force to" : ""), +		  val0x6c0, val0x6c4, val0x6cc); +	coex_dm->cur_val0x6c0 = val0x6c0; +	coex_dm->cur_val0x6c4 = val0x6c4; +	coex_dm->cur_val0x6c8 = val0x6c8; +	coex_dm->cur_val0x6cc = val0x6cc; + +	if (!force_exec) { +		if ((coex_dm->pre_val0x6c0 == coex_dm->cur_val0x6c0) && +		    (coex_dm->pre_val0x6c4 == coex_dm->cur_val0x6c4) && +		    (coex_dm->pre_val0x6c8 == coex_dm->cur_val0x6c8) && +		    (coex_dm->pre_val0x6cc == coex_dm->cur_val0x6cc)) +			return; +	} +	halbtc8723b1ant_set_coex_table(btcoexist, val0x6c0, val0x6c4, +				       val0x6c8, val0x6cc); + +	coex_dm->pre_val0x6c0 = coex_dm->cur_val0x6c0; +	coex_dm->pre_val0x6c4 = coex_dm->cur_val0x6c4; +	coex_dm->pre_val0x6c8 = coex_dm->cur_val0x6c8; +	coex_dm->pre_val0x6cc = coex_dm->cur_val0x6cc; +} + +static void coex_table_with_type(struct btc_coexist *btcoexist, +				 bool force_exec, u8 type) +{ +	switch (type) { +	case 0: +		halbtc8723b1ant_coex_table(btcoexist, force_exec, 0x55555555, +					   0x55555555, 0xffffff, 0x3); +		break; +	case 1: +		halbtc8723b1ant_coex_table(btcoexist, force_exec, 0x55555555, +					   0x5a5a5a5a, 0xffffff, 0x3); +		break; +	case 2: +		halbtc8723b1ant_coex_table(btcoexist, force_exec, 0x5a5a5a5a, +					   0x5a5a5a5a, 0xffffff, 0x3); +		break; +	case 3: +		halbtc8723b1ant_coex_table(btcoexist, force_exec, 0x55555555, +					   0xaaaaaaaa, 0xffffff, 0x3); +		break; +	case 4: +		halbtc8723b1ant_coex_table(btcoexist, force_exec, 0x55555555, +					   0x5aaa5aaa, 0xffffff, 0x3); +		break; +	case 5: +		halbtc8723b1ant_coex_table(btcoexist, force_exec, 0x5a5a5a5a, +					   0xaaaa5a5a, 0xffffff, 0x3); +		break; +	case 6: +		halbtc8723b1ant_coex_table(btcoexist, force_exec, 0x55555555, +					   0xaaaa5a5a, 0xffffff, 0x3); +		break; +	case 7: +		halbtc8723b1ant_coex_table(btcoexist, force_exec, 0xaaaaaaaa, +					   0xaaaaaaaa, 0xffffff, 0x3); +		break; +	default: +		break; +	} +} + +static void set_fw_ignore_wlan_act(struct btc_coexist *btcoexist, +				   bool enable) +{ +	u8 h2c_parameter[1] = {0}; + +	if (enable) +		h2c_parameter[0] |= BIT(0);	/* function enable */ + +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, +		  "[BTCoex], set FW for BT Ignore Wlan_Act, FW write 0x63 = 0x%x\n", +		  h2c_parameter[0]); + +	btcoexist->btc_fill_h2c(btcoexist, 0x63, 1, h2c_parameter); +} + +static void halbtc8723b1ant_ignore_wlan_act(struct btc_coexist *btcoexist, +					    bool force_exec, bool enable) +{ +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, +		  "[BTCoex], %s turn Ignore WlanAct %s\n", +		  (force_exec ? "force to" : ""), (enable ? "ON" : "OFF")); +	coex_dm->cur_ignore_wlan_act = enable; + +	if (!force_exec) { +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, +			  "[BTCoex], bPreIgnoreWlanAct = %d, bCurIgnoreWlanAct = %d!!\n", +			  coex_dm->pre_ignore_wlan_act, +			  coex_dm->cur_ignore_wlan_act); + +		if (coex_dm->pre_ignore_wlan_act == +		    coex_dm->cur_ignore_wlan_act) +			return; +	} +	set_fw_ignore_wlan_act(btcoexist, enable); + +	coex_dm->pre_ignore_wlan_act = coex_dm->cur_ignore_wlan_act; +} + +static void halbtc8723b1ant_set_fw_ps_tdma(struct btc_coexist *btcoexist, +					   u8 byte1, u8 byte2, u8 byte3, +					   u8 byte4, u8 byte5) +{ +	u8 h2c_parameter[5] = {0}; +	u8 real_byte1 = byte1, real_byte5 = byte5; +	bool ap_enable = false; + +	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_AP_MODE_ENABLE, +			   &ap_enable); + +	if (ap_enable) { +		if ((byte1 & BIT(4)) && !(byte1 & BIT(5))) { +			BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, +				  "[BTCoex], FW for 1Ant AP mode\n"); +			real_byte1 &= ~BIT(4); +			real_byte1 |= BIT(5); + +			real_byte5 |= BIT(5); +			real_byte5 &= ~BIT(6); +		} +	} + +	h2c_parameter[0] = real_byte1; +	h2c_parameter[1] = byte2; +	h2c_parameter[2] = byte3; +	h2c_parameter[3] = byte4; +	h2c_parameter[4] = real_byte5; + +	coex_dm->ps_tdma_para[0] = real_byte1; +	coex_dm->ps_tdma_para[1] = byte2; +	coex_dm->ps_tdma_para[2] = byte3; +	coex_dm->ps_tdma_para[3] = byte4; +	coex_dm->ps_tdma_para[4] = real_byte5; + +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, +		  "[BTCoex], PS-TDMA H2C cmd = 0x%x%08x\n", +		  h2c_parameter[0], +		  h2c_parameter[1] << 24 | +		  h2c_parameter[2] << 16 | +		  h2c_parameter[3] << 8 | +		  h2c_parameter[4]); + +	btcoexist->btc_fill_h2c(btcoexist, 0x60, 5, h2c_parameter); +} + +static void halbtc8723b1ant_set_lps_rpwm(struct btc_coexist *btcoexist, +					 u8 lps_val, u8 rpwm_val) +{ +	u8 lps = lps_val; +	u8 rpwm = rpwm_val; + +	btcoexist->btc_set(btcoexist, BTC_SET_U1_LPS_VAL, &lps); +	btcoexist->btc_set(btcoexist, BTC_SET_U1_RPWM_VAL, &rpwm); +} + +static void halbtc8723b1ant_lpsrpwm(struct btc_coexist *btcoexist, +				    bool force_exec, +				    u8 lps_val, u8 rpwm_val) +{ +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, +		  "[BTCoex], %s set lps/rpwm = 0x%x/0x%x\n", +		  (force_exec ? "force to" : ""), lps_val, rpwm_val); +	coex_dm->cur_lps = lps_val; +	coex_dm->cur_rpwm = rpwm_val; + +	if (!force_exec) { +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, +			  "[BTCoex], LPS-RxBeaconMode = 0x%x, LPS-RPWM = 0x%x!!\n", +			  coex_dm->cur_lps, coex_dm->cur_rpwm); + +		if ((coex_dm->pre_lps == coex_dm->cur_lps) && +		    (coex_dm->pre_rpwm == coex_dm->cur_rpwm)) { +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, +				  "[BTCoex], LPS-RPWM_Last = 0x%x, LPS-RPWM_Now = 0x%x!!\n", +				  coex_dm->pre_rpwm, coex_dm->cur_rpwm); + +			return; +		} +	} +	halbtc8723b1ant_set_lps_rpwm(btcoexist, lps_val, rpwm_val); + +	coex_dm->pre_lps = coex_dm->cur_lps; +	coex_dm->pre_rpwm = coex_dm->cur_rpwm; +} + +static void halbtc8723b1ant_sw_mechanism(struct btc_coexist *btcoexist, +					 bool low_penalty_ra) +{ +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, +		  "[BTCoex], SM[LpRA] = %d\n", low_penalty_ra); + +	halbtc8723b1ant_low_penalty_ra(btcoexist, NORMAL_EXEC, low_penalty_ra); +} + +static void halbtc8723b1ant_setantpath(struct btc_coexist *btcoexist, +				       u8 ant_pos_type, bool init_hw_cfg, +				bool wifi_off) +{ +	struct btc_board_info *brd_info = &btcoexist->board_info; +	u32 fw_ver = 0, u32tmp = 0; +	bool pg_ext_switch = false; +	bool use_ext_switch = false; +	u8 h2c_parameter[2] = {0}; + +	btcoexist->btc_get(btcoexist, BTC_GET_BL_EXT_SWITCH, &pg_ext_switch); +	/* [31:16] = fw ver, [15:0] = fw sub ver */ +	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver); + +	if ((fw_ver < 0xc0000) || pg_ext_switch) +		use_ext_switch = true; + +	if (init_hw_cfg) { +		/*BT select s0/s1 is controlled by WiFi */ +		btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, 0x20, 0x1); + +		/*Force GNT_BT to Normal */ +		btcoexist->btc_write_1byte_bitmask(btcoexist, 0x765, 0x18, 0x0); +	} else if (wifi_off) { +		/*Force GNT_BT to High */ +		btcoexist->btc_write_1byte_bitmask(btcoexist, 0x765, 0x18, 0x3); +		/*BT select s0/s1 is controlled by BT */ +		btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, 0x20, 0x0); + +		/* 0x4c[24:23] = 00, Set Antenna control by BT_RFE_CTRL +		 * BT Vendor 0xac = 0xf002 */ +		u32tmp = btcoexist->btc_read_4byte(btcoexist, 0x4c); +		u32tmp &= ~BIT(23); +		u32tmp &= ~BIT(24); +		btcoexist->btc_write_4byte(btcoexist, 0x4c, u32tmp); +	} + +	if (use_ext_switch) { +		if (init_hw_cfg) { +			/* 0x4c[23] = 0, 0x4c[24] = 1  Antenna ctrl by WL/BT */ +			u32tmp = btcoexist->btc_read_4byte(btcoexist, 0x4c); +			u32tmp &= ~BIT(23); +			u32tmp |= BIT(24); +			btcoexist->btc_write_4byte(btcoexist, 0x4c, u32tmp); + +			if (brd_info->btdm_ant_pos == +			    BTC_ANTENNA_AT_MAIN_PORT) { +				/* Main Ant to  BT for IPS case 0x4c[23] = 1 */ +				btcoexist->btc_write_1byte_bitmask(btcoexist, +								   0x64, 0x1, +								   0x1); + +				/*tell firmware "no antenna inverse"*/ +				h2c_parameter[0] = 0; +				h2c_parameter[1] = 1;  /*ext switch type*/ +				btcoexist->btc_fill_h2c(btcoexist, 0x65, 2, +							h2c_parameter); +			} else { +				/*Aux Ant to  BT for IPS case 0x4c[23] = 1 */ +				btcoexist->btc_write_1byte_bitmask(btcoexist, +								   0x64, 0x1, +								   0x0); + +				/*tell firmware "antenna inverse"*/ +				h2c_parameter[0] = 1; +				h2c_parameter[1] = 1;  /*ext switch type*/ +				btcoexist->btc_fill_h2c(btcoexist, 0x65, 2, +							h2c_parameter); +			} +		} + +		/* fixed internal switch first*/ +		/* fixed internal switch S1->WiFi, S0->BT*/ +		if (brd_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT) +			btcoexist->btc_write_2byte(btcoexist, 0x948, 0x0); +		else/* fixed internal switch S0->WiFi, S1->BT*/ +			btcoexist->btc_write_2byte(btcoexist, 0x948, 0x280); + +		/* ext switch setting */ +		switch (ant_pos_type) { +		case BTC_ANT_PATH_WIFI: +			if (brd_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT) +				btcoexist->btc_write_1byte_bitmask(btcoexist, +								   0x92c, 0x3, +								   0x1); +			else +				btcoexist->btc_write_1byte_bitmask(btcoexist, +								   0x92c, 0x3, +								   0x2); +			break; +		case BTC_ANT_PATH_BT: +			if (brd_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT) +				btcoexist->btc_write_1byte_bitmask(btcoexist, +								   0x92c, 0x3, +								   0x2); +			else +				btcoexist->btc_write_1byte_bitmask(btcoexist, +								   0x92c, 0x3, +								   0x1); +			break; +		default: +		case BTC_ANT_PATH_PTA: +			if (brd_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT) +				btcoexist->btc_write_1byte_bitmask(btcoexist, +								   0x92c, 0x3, +								   0x1); +			else +				btcoexist->btc_write_1byte_bitmask(btcoexist, +								   0x92c, 0x3, +								   0x2); +			break; +		} + +	} else { +		if (init_hw_cfg) { +			/* 0x4c[23] = 1, 0x4c[24] = 0  Antenna control by 0x64*/ +			u32tmp = btcoexist->btc_read_4byte(btcoexist, 0x4c); +			u32tmp |= BIT(23); +			u32tmp &= ~BIT(24); +			btcoexist->btc_write_4byte(btcoexist, 0x4c, u32tmp); + +			if (brd_info->btdm_ant_pos == +			    BTC_ANTENNA_AT_MAIN_PORT) { +				/*Main Ant to  WiFi for IPS case 0x4c[23] = 1*/ +				btcoexist->btc_write_1byte_bitmask(btcoexist, +								   0x64, 0x1, +								   0x0); + +				/*tell firmware "no antenna inverse"*/ +				h2c_parameter[0] = 0; +				h2c_parameter[1] = 0;  /*internal switch type*/ +				btcoexist->btc_fill_h2c(btcoexist, 0x65, 2, +							h2c_parameter); +			} else { +				/*Aux Ant to  BT for IPS case 0x4c[23] = 1*/ +				btcoexist->btc_write_1byte_bitmask(btcoexist, +								   0x64, 0x1, +								   0x1); + +				/*tell firmware "antenna inverse"*/ +				h2c_parameter[0] = 1; +				h2c_parameter[1] = 0;  /*internal switch type*/ +				btcoexist->btc_fill_h2c(btcoexist, 0x65, 2, +							h2c_parameter); +			} +		} + +		/* fixed external switch first*/ +		/*Main->WiFi, Aux->BT*/ +		if (brd_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT) +			btcoexist->btc_write_1byte_bitmask(btcoexist, 0x92c, +							   0x3, 0x1); +		else/*Main->BT, Aux->WiFi */ +			btcoexist->btc_write_1byte_bitmask(btcoexist, 0x92c, +							   0x3, 0x2); + +		/* internal switch setting*/ +		switch (ant_pos_type) { +		case BTC_ANT_PATH_WIFI: +			if (brd_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT) +				btcoexist->btc_write_2byte(btcoexist, 0x948, +							   0x0); +			else +				btcoexist->btc_write_2byte(btcoexist, 0x948, +							   0x280); +			break; +		case BTC_ANT_PATH_BT: +			if (brd_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT) +				btcoexist->btc_write_2byte(btcoexist, 0x948, +							   0x280); +			else +				btcoexist->btc_write_2byte(btcoexist, 0x948, +							   0x0); +			break; +		default: +		case BTC_ANT_PATH_PTA: +			if (brd_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT) +				btcoexist->btc_write_2byte(btcoexist, 0x948, +							   0x200); +			else +				btcoexist->btc_write_2byte(btcoexist, 0x948, +							   0x80); +			break; +		} +	} +} + +static void halbtc8723b1ant_ps_tdma(struct btc_coexist *btcoexist, +				    bool force_exec, bool turn_on, u8 type) +{ +	bool wifi_busy = false; +	u8 rssi_adjust_val = 0; + +	coex_dm->cur_ps_tdma_on = turn_on; +	coex_dm->cur_ps_tdma = type; + +	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + +	if (!force_exec) { +		if (coex_dm->cur_ps_tdma_on) +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, +				  "[BTCoex], ******** TDMA(on, %d) *********\n", +				  coex_dm->cur_ps_tdma); +		else +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, +				  "[BTCoex], ******** TDMA(off, %d) ********\n", +				  coex_dm->cur_ps_tdma); + +		if ((coex_dm->pre_ps_tdma_on == coex_dm->cur_ps_tdma_on) && +		    (coex_dm->pre_ps_tdma == coex_dm->cur_ps_tdma)) +			return; +	} +	if (turn_on) { +		switch (type) { +		default: +			halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x1a, +						       0x1a, 0x0, 0x50); +			break; +		case 1: +			halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x3a, +						       0x03, 0x10, 0x50); + +			rssi_adjust_val = 11; +			break; +		case 2: +			halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x2b, +						       0x03, 0x10, 0x50); +			rssi_adjust_val = 14; +			break; +		case 3: +			halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x1d, +						       0x1d, 0x0, 0x52); +			break; +		case 4: +			halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x93, 0x15, +						       0x3, 0x14, 0x0); +			rssi_adjust_val = 17; +			break; +		case 5: +			halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x61, 0x15, +						       0x3, 0x11, 0x10); +			break; +		case 6: +			halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x61, 0x20, +						       0x3, 0x11, 0x13); +			break; +		case 7: +			halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x13, 0xc, +						       0x5, 0x0, 0x0); +			break; +		case 8: +			halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x93, 0x25, +						       0x3, 0x10, 0x0); +			break; +		case 9: +			halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x51,  0x21, +						       0x3, 0x10, 0x50); +			rssi_adjust_val = 18; +			break; +		case 10: +			halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x13, 0xa, +						       0xa, 0x0, 0x40); +			break; +		case 11: +			halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x15, +						       0x03, 0x10, 0x50); +			rssi_adjust_val = 20; +			break; +		case 12: +			halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x0a, +						       0x0a, 0x0, 0x50); +			break; +		case 13: +			halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x15, +						       0x15, 0x0, 0x50); +			break; +		case 14: +			halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x21, +						       0x3, 0x10, 0x52); +			break; +		case 15: +			halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x13, 0xa, +						       0x3, 0x8, 0x0); +			break; +		case 16: +			halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x93, 0x15, +						       0x3, 0x10, 0x0); +			rssi_adjust_val = 18; +			break; +		case 18: +			halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x93, 0x25, +						       0x3, 0x10, 0x0); +			rssi_adjust_val = 14; +			break; +		case 20: +			halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x61, 0x35, +						       0x03, 0x11, 0x10); +			break; +		case 21: +			halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x61, 0x25, +						       0x03, 0x11, 0x11); +			break; +		case 22: +			halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x61, 0x25, +						       0x03, 0x11, 0x10); +			break; +		case 23: +			halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x25, +						       0x3, 0x31, 0x18); +			rssi_adjust_val = 22; +			break; +		case 24: +			halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x15, +						       0x3, 0x31, 0x18); +			rssi_adjust_val = 22; +			break; +		case 25: +			halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0xe3, 0xa, +						       0x3, 0x31, 0x18); +			rssi_adjust_val = 22; +			break; +		case 26: +			halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0xe3, 0xa, +						       0x3, 0x31, 0x18); +			rssi_adjust_val = 22; +			break; +		case 27: +			halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x25, +						       0x3, 0x31, 0x98); +			rssi_adjust_val = 22; +			break; +		case 28: +			halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x69, 0x25, +						       0x3, 0x31, 0x0); +			break; +		case 29: +			halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0xab, 0x1a, +						       0x1a, 0x1, 0x10); +			break; +		case 30: +			halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x14, +						       0x3, 0x10, 0x50); +			break; +		case 31: +			halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0xd3, 0x1a, +						       0x1a, 0, 0x58); +			break; +		case 32: +			halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x61, 0xa, +						       0x3, 0x10, 0x0); +			break; +		case 33: +			halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0xa3, 0x25, +						       0x3, 0x30, 0x90); +			break; +		case 34: +			halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x53, 0x1a, +						       0x1a, 0x0, 0x10); +			break; +		case 35: +			halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x63, 0x1a, +						       0x1a, 0x0, 0x10); +			break; +		case 36: +			halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0xd3, 0x12, +						       0x3, 0x14, 0x50); +			break; +		/* SoftAP only with no sta associated, BT disable , +		 * TDMA mode for power saving +		 * here softap mode screen off will cost 70-80mA for phone */ +		case 40: +			halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x23, 0x18, +						       0x00, 0x10, 0x24); +			break; +		} +	} else { +		switch (type) { +		case 8: /*PTA Control */ +			halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x8, 0x0, +						       0x0, 0x0, 0x0); +			halbtc8723b1ant_setantpath(btcoexist, BTC_ANT_PATH_PTA, +						   false, false); +			break; +		case 0: +		default:  /*Software control, Antenna at BT side */ +			halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x0, 0x0, +						       0x0, 0x0, 0x0); +			halbtc8723b1ant_setantpath(btcoexist, BTC_ANT_PATH_BT, +						   false, false); +			break; +		case 9:   /*Software control, Antenna at WiFi side */ +			halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x0, 0x0, +						       0x0, 0x0, 0x0); +			halbtc8723b1ant_setantpath(btcoexist, BTC_ANT_PATH_WIFI, +						   false, false); +			break; +		} +	} +	rssi_adjust_val = 0; +	btcoexist->btc_set(btcoexist, +			   BTC_SET_U1_RSSI_ADJ_VAL_FOR_1ANT_COEX_TYPE, +			   &rssi_adjust_val); + +	/* update pre state */ +	coex_dm->pre_ps_tdma_on = coex_dm->cur_ps_tdma_on; +	coex_dm->pre_ps_tdma = coex_dm->cur_ps_tdma; +} + +static bool halbtc8723b1ant_is_common_action(struct btc_coexist *btcoexist) +{ +	bool commom = false, wifi_connected = false; +	bool wifi_busy = false; + +	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, +			   &wifi_connected); +	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + +	if (!wifi_connected && +	    BT_8723B_1ANT_BT_STATUS_NON_CONNECTED_IDLE == coex_dm->bt_status) { +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +			  "[BTCoex], Wifi non connected-idle + BT non connected-idle!!\n"); +		halbtc8723b1ant_sw_mechanism(btcoexist, false); +		commom = true; +	} else if (wifi_connected && +		   (BT_8723B_1ANT_BT_STATUS_NON_CONNECTED_IDLE == +		    coex_dm->bt_status)) { +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +			  "[BTCoex], Wifi connected + BT non connected-idle!!\n"); +		halbtc8723b1ant_sw_mechanism(btcoexist, false); +		commom = true; +	} else if (!wifi_connected && +		   (BT_8723B_1ANT_BT_STATUS_CONNECTED_IDLE == +		    coex_dm->bt_status)) { +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +			  "[BTCoex], Wifi non connected-idle + BT connected-idle!!\n"); +		halbtc8723b1ant_sw_mechanism(btcoexist, false); +		commom = true; +	} else if (wifi_connected && +		   (BT_8723B_1ANT_BT_STATUS_CONNECTED_IDLE == +		    coex_dm->bt_status)) { +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +			  "[BTCoex], Wifi connected + BT connected-idle!!\n"); +		halbtc8723b1ant_sw_mechanism(btcoexist, false); +		commom = true; +	} else if (!wifi_connected && +		   (BT_8723B_1ANT_BT_STATUS_CONNECTED_IDLE != +		    coex_dm->bt_status)) { +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +			  "[BTCoex], Wifi non connected-idle + BT Busy!!\n"); +		halbtc8723b1ant_sw_mechanism(btcoexist, false); +		commom = true; +	} else { +		if (wifi_busy) +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +				  "[BTCoex], Wifi Connected-Busy + BT Busy!!\n"); +		else +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +				  "[BTCoex], Wifi Connected-Idle + BT Busy!!\n"); + +		commom = false; +	} + +	return commom; +} + +static void tdma_duration_adjust_for_acl(struct btc_coexist *btcoexist, +					 u8 wifi_status) +{ +	static s32 up, dn, m, n, wait_count; +	/* 0: no change, +1: increase WiFi duration, +	 * -1: decrease WiFi duration */ +	s32 result; +	u8 retry_count = 0, bt_info_ext; +	bool wifi_busy = false; + +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, +		  "[BTCoex], TdmaDurationAdjustForAcl()\n"); + +	if (BT_8723B_1ANT_WIFI_STATUS_CONNECTED_BUSY == wifi_status) +		wifi_busy = true; +	else +		wifi_busy = false; + +	if ((BT_8723B_1ANT_WIFI_STATUS_NON_CONNECTED_ASSO_AUTH_SCAN == +							 wifi_status) || +	    (BT_8723B_1ANT_WIFI_STATUS_CONNECTED_SCAN == wifi_status) || +	    (BT_8723B_1ANT_WIFI_STATUS_CONNECTED_SPECIAL_PKT == wifi_status)) { +		if (coex_dm->cur_ps_tdma != 1 && coex_dm->cur_ps_tdma != 2 && +		    coex_dm->cur_ps_tdma != 3 && coex_dm->cur_ps_tdma != 9) { +			halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, +						true, 9); +			coex_dm->ps_tdma_du_adj_type = 9; + +			up = 0; +			dn = 0; +			m = 1; +			n = 3; +			result = 0; +			wait_count = 0; +		} +		return; +	} + +	if (!coex_dm->auto_tdma_adjust) { +		coex_dm->auto_tdma_adjust = true; +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, +			  "[BTCoex], first run TdmaDurationAdjust()!!\n"); + +		halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 2); +		coex_dm->ps_tdma_du_adj_type = 2; + +		up = 0; +		dn = 0; +		m = 1; +		n = 3; +		result = 0; +		wait_count = 0; +	} else { +		/*accquire the BT TRx retry count from BT_Info byte2 */ +		retry_count = coex_sta->bt_retry_cnt; +		bt_info_ext = coex_sta->bt_info_ext; +		result = 0; +		wait_count++; +		/* no retry in the last 2-second duration */ +		if (retry_count == 0) { +			up++; +			dn--; + +			if (dn <= 0) +				dn = 0; + +			if (up >= n) { +				wait_count = 0; +				n = 3; +				up = 0; +				dn = 0; +				result = 1; +				BTC_PRINT(BTC_MSG_ALGORITHM, +					  ALGO_TRACE_FW_DETAIL, +					  "[BTCoex], Increase wifi duration!!\n"); +			} +		} else if (retry_count <= 3) { +			up--; +			dn++; + +			if (up <= 0) +				up = 0; + +			if (dn == 2) { +				if (wait_count <= 2) +					m++; +				else +					m = 1; + +				if (m >= 20) +					m = 20; + +				n = 3 * m; +				up = 0; +				dn = 0; +				wait_count = 0; +				result = -1; +				BTC_PRINT(BTC_MSG_ALGORITHM, +					  ALGO_TRACE_FW_DETAIL, +					  "[BTCoex], Decrease wifi duration for retryCounter<3!!\n"); +			} +		} else { +			if (wait_count == 1) +				m++; +			else +				m = 1; + +			if (m >= 20) +				m = 20; + +			n = 3 * m; +			up = 0; +			dn = 0; +			wait_count = 0; +			result = -1; +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, +				  "[BTCoex], Decrease wifi duration for retryCounter>3!!\n"); +		} + +		if (result == -1) { +			if ((BT_INFO_8723B_1ANT_A2DP_BASIC_RATE(bt_info_ext)) && +			    ((coex_dm->cur_ps_tdma == 1) || +			     (coex_dm->cur_ps_tdma == 2))) { +				halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, +							true, 9); +				coex_dm->ps_tdma_du_adj_type = 9; +			} else if (coex_dm->cur_ps_tdma == 1) { +				halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, +							true, 2); +				coex_dm->ps_tdma_du_adj_type = 2; +			} else if (coex_dm->cur_ps_tdma == 2) { +				halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, +							true, 9); +				coex_dm->ps_tdma_du_adj_type = 9; +			} else if (coex_dm->cur_ps_tdma == 9) { +				halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, +							true, 11); +				coex_dm->ps_tdma_du_adj_type = 11; +			} +		} else if (result == 1) { +			if ((BT_INFO_8723B_1ANT_A2DP_BASIC_RATE(bt_info_ext)) && +			    ((coex_dm->cur_ps_tdma == 1) || +			     (coex_dm->cur_ps_tdma == 2))) { +				halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, +							true, 9); +				coex_dm->ps_tdma_du_adj_type = 9; +			} else if (coex_dm->cur_ps_tdma == 11) { +				halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, +							true, 9); +				coex_dm->ps_tdma_du_adj_type = 9; +			} else if (coex_dm->cur_ps_tdma == 9) { +				halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, +							true, 2); +				coex_dm->ps_tdma_du_adj_type = 2; +			} else if (coex_dm->cur_ps_tdma == 2) { +				halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, +							true, 1); +				coex_dm->ps_tdma_du_adj_type = 1; +			} +		} else {	  /*no change */ +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, +				  "[BTCoex],********* TDMA(on, %d) ********\n", +				  coex_dm->cur_ps_tdma); +		} + +		if (coex_dm->cur_ps_tdma != 1 && coex_dm->cur_ps_tdma != 2 && +		    coex_dm->cur_ps_tdma != 9 && coex_dm->cur_ps_tdma != 11) { +			/* recover to previous adjust type */ +			halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, +						coex_dm->ps_tdma_du_adj_type); +		} +	} +} + +static void pstdmacheckforpowersavestate(struct btc_coexist *btcoexist, +					 bool new_ps_state) +{ +	u8 lps_mode = 0x0; + +	btcoexist->btc_get(btcoexist, BTC_GET_U1_LPS_MODE, &lps_mode); + +	if (lps_mode) {	/* already under LPS state */ +		if (new_ps_state) { +			/* keep state under LPS, do nothing. */ +		} else { +			/* will leave LPS state, turn off psTdma first */ +			halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, +						false, 0); +		} +	} else {	/* NO PS state */ +		if (new_ps_state) { +			/* will enter LPS state, turn off psTdma first */ +			halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, +						false, 0); +		} else { +			/* keep state under NO PS state, do nothing. */ +		} +	} +} + +static void halbtc8723b1ant_power_save_state(struct btc_coexist *btcoexist, +					     u8 ps_type, u8 lps_val, +					     u8 rpwm_val) +{ +	bool low_pwr_disable = false; + +	switch (ps_type) { +	case BTC_PS_WIFI_NATIVE: +		/* recover to original 32k low power setting */ +		low_pwr_disable = false; +		btcoexist->btc_set(btcoexist, BTC_SET_ACT_DISABLE_LOW_POWER, +				   &low_pwr_disable); +		btcoexist->btc_set(btcoexist, BTC_SET_ACT_NORMAL_LPS, NULL); +		break; +	case BTC_PS_LPS_ON: +		pstdmacheckforpowersavestate(btcoexist, true); +		halbtc8723b1ant_lpsrpwm(btcoexist, NORMAL_EXEC, lps_val, +					rpwm_val); +		/* when coex force to enter LPS, do not enter 32k low power. */ +		low_pwr_disable = true; +		btcoexist->btc_set(btcoexist, BTC_SET_ACT_DISABLE_LOW_POWER, +				   &low_pwr_disable); +		/* power save must executed before psTdma.	 */ +		btcoexist->btc_set(btcoexist, BTC_SET_ACT_ENTER_LPS, NULL); +		break; +	case BTC_PS_LPS_OFF: +		pstdmacheckforpowersavestate(btcoexist, false); +		btcoexist->btc_set(btcoexist, BTC_SET_ACT_LEAVE_LPS, NULL); +		break; +	default: +		break; +	} +} + +/*************************************************** + * + *	Software Coex Mechanism start + * + ***************************************************/ +/* SCO only or SCO+PAN(HS) */ +static void halbtc8723b1ant_action_sco(struct btc_coexist *btcoexist) +{ +	halbtc8723b1ant_sw_mechanism(btcoexist, true); +} + +static void halbtc8723b1ant_action_hid(struct btc_coexist *btcoexist) +{ +	halbtc8723b1ant_sw_mechanism(btcoexist, true); +} + +/*A2DP only / PAN(EDR) only/ A2DP+PAN(HS) */ +static void halbtc8723b1ant_action_a2dp(struct btc_coexist *btcoexist) +{ +	halbtc8723b1ant_sw_mechanism(btcoexist, false); +} + +static void halbtc8723b1ant_action_a2dp_pan_hs(struct btc_coexist *btcoexist) +{ +	halbtc8723b1ant_sw_mechanism(btcoexist, false); +} + +static void halbtc8723b1ant_action_pan_edr(struct btc_coexist *btcoexist) +{ +	halbtc8723b1ant_sw_mechanism(btcoexist, false); +} + +/* PAN(HS) only */ +static void halbtc8723b1ant_action_pan_hs(struct btc_coexist *btcoexist) +{ +	halbtc8723b1ant_sw_mechanism(btcoexist, false); +} + +/*PAN(EDR)+A2DP */ +static void halbtc8723b1ant_action_pan_edr_a2dp(struct btc_coexist *btcoexist) +{ +	halbtc8723b1ant_sw_mechanism(btcoexist, false); +} + +static void halbtc8723b1ant_action_pan_edr_hid(struct btc_coexist *btcoexist) +{ +	halbtc8723b1ant_sw_mechanism(btcoexist, true); +} + +/* HID+A2DP+PAN(EDR) */ +static void action_hid_a2dp_pan_edr(struct btc_coexist *btcoexist) +{ +	halbtc8723b1ant_sw_mechanism(btcoexist, true); +} + +static void halbtc8723b1ant_action_hid_a2dp(struct btc_coexist *btcoexist) +{ +	halbtc8723b1ant_sw_mechanism(btcoexist, true); +} + +/***************************************************** + * + *	Non-Software Coex Mechanism start + * + *****************************************************/ +static void halbtc8723b1ant_action_wifi_multiport(struct btc_coexist *btcoexist) +{ +	halbtc8723b1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, +					 0x0, 0x0); + +	halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); +	coex_table_with_type(btcoexist, NORMAL_EXEC, 2); +} + +static void halbtc8723b1ant_action_hs(struct btc_coexist *btcoexist) +{ +	halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 5); +	coex_table_with_type(btcoexist, NORMAL_EXEC, 2); +} + +static void halbtc8723b1ant_action_bt_inquiry(struct btc_coexist *btcoexist) +{ +	struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; +	bool wifi_connected = false, ap_enable = false; + +	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_AP_MODE_ENABLE, +			   &ap_enable); +	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, +			   &wifi_connected); + +	if (!wifi_connected) { +		halbtc8723b1ant_power_save_state(btcoexist, +						 BTC_PS_WIFI_NATIVE, 0x0, 0x0); +		halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); +		coex_table_with_type(btcoexist, NORMAL_EXEC, 2); +	} else if (bt_link_info->sco_exist || bt_link_info->hid_only) { +		/* SCO/HID-only busy */ +		halbtc8723b1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, +						 0x0, 0x0); +		halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 32); +		coex_table_with_type(btcoexist, NORMAL_EXEC, 1); +	} else { +		if (ap_enable) +			halbtc8723b1ant_power_save_state(btcoexist, +							 BTC_PS_WIFI_NATIVE, +							 0x0, 0x0); +		else +			halbtc8723b1ant_power_save_state(btcoexist, +							 BTC_PS_LPS_ON, +							 0x50, 0x4); + +		halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 30); +		coex_table_with_type(btcoexist, NORMAL_EXEC, 1); +	} +} + +static void action_bt_sco_hid_only_busy(struct btc_coexist *btcoexist, +					u8 wifi_status) +{ +	struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; +	bool wifi_connected = false; + +	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, +			   &wifi_connected); + +	/* tdma and coex table */ + +	if (bt_link_info->sco_exist) { +		halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 5); +		coex_table_with_type(btcoexist, NORMAL_EXEC, 2); +	} else { /* HID */ +		halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 6); +		coex_table_with_type(btcoexist, NORMAL_EXEC, 5); +	} +} + +static void halbtc8723b1ant_action_wifi_connected_bt_acl_busy( +					struct btc_coexist *btcoexist, +					u8 wifi_status) +{ +	struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; +	u8 rssi_state; + +	rssi_state = halbtc8723b1ant_bt_rssi_state(2, 28, 0); + +	if (bt_link_info->hid_only) {  /*HID */ +		action_bt_sco_hid_only_busy(btcoexist, wifi_status); +		coex_dm->auto_tdma_adjust = false; +		return; +	} else if (bt_link_info->a2dp_only) { /*A2DP */ +		if (BT_8723B_1ANT_WIFI_STATUS_CONNECTED_IDLE == wifi_status) { +			halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, +						8); +			coex_table_with_type(btcoexist, NORMAL_EXEC, 2); +			coex_dm->auto_tdma_adjust = false; +		} else if ((rssi_state == BTC_RSSI_STATE_HIGH) || +			   (rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +			tdma_duration_adjust_for_acl(btcoexist, wifi_status); +			coex_table_with_type(btcoexist, NORMAL_EXEC, 1); +		} else { /*for low BT RSSI */ +			halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, +						true, 11); +			coex_table_with_type(btcoexist, NORMAL_EXEC, 1); +			coex_dm->auto_tdma_adjust = false; +		} +	} else if (bt_link_info->hid_exist && +		   bt_link_info->a2dp_exist) { /*HID+A2DP */ +		if ((rssi_state == BTC_RSSI_STATE_HIGH) || +		    (rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +			halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, +						true, 14); +			coex_dm->auto_tdma_adjust = false; +		} else { /*for low BT RSSI*/ +			halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, +						true, 14); +			coex_dm->auto_tdma_adjust = false; +		} + +		coex_table_with_type(btcoexist, NORMAL_EXEC, 6); +	 /*PAN(OPP, FTP), HID+PAN(OPP, FTP) */ +	} else if (bt_link_info->pan_only || +		   (bt_link_info->hid_exist && bt_link_info->pan_exist)) { +		halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 3); +		coex_table_with_type(btcoexist, NORMAL_EXEC, 6); +		coex_dm->auto_tdma_adjust = false; +	 /*A2DP+PAN(OPP, FTP), HID+A2DP+PAN(OPP, FTP)*/ +	} else if ((bt_link_info->a2dp_exist && bt_link_info->pan_exist) || +		   (bt_link_info->hid_exist && bt_link_info->a2dp_exist && +		    bt_link_info->pan_exist)) { +		halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 13); +		coex_table_with_type(btcoexist, NORMAL_EXEC, 1); +		coex_dm->auto_tdma_adjust = false; +	} else { +		halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 11); +		coex_table_with_type(btcoexist, NORMAL_EXEC, 1); +		coex_dm->auto_tdma_adjust = false; +	} +} + +static void action_wifi_not_connected(struct btc_coexist *btcoexist) +{ +	/* power save state */ +	halbtc8723b1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, +					 0x0, 0x0); + +	/* tdma and coex table */ +	halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); +	coex_table_with_type(btcoexist, NORMAL_EXEC, 0); +} + +static void action_wifi_not_connected_scan(struct btc_coexist *btcoexist) +{ +	struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; +	halbtc8723b1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, +					 0x0, 0x0); + +	/* tdma and coex table */ +	if (BT_8723B_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) { +		if (bt_link_info->a2dp_exist && bt_link_info->pan_exist) { +			halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, +						true, 22); +			coex_table_with_type(btcoexist, NORMAL_EXEC, 1); +		} else if (bt_link_info->pan_only) { +			halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, +						true, 20); +			coex_table_with_type(btcoexist, NORMAL_EXEC, 2); +		} else { +			halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, +						true, 20); +			coex_table_with_type(btcoexist, NORMAL_EXEC, 1); +		} +	} else if ((BT_8723B_1ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) || +		   (BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY == +		    coex_dm->bt_status)) { +		action_bt_sco_hid_only_busy(btcoexist, +				BT_8723B_1ANT_WIFI_STATUS_CONNECTED_SCAN); +	} else { +		halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); +		coex_table_with_type(btcoexist, NORMAL_EXEC, 2); +	} +} + +static void action_wifi_not_connected_asso_auth(struct btc_coexist *btcoexist) +{ +	struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + +	halbtc8723b1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, +					 0x0, 0x0); + +	if ((BT_8723B_1ANT_BT_STATUS_CONNECTED_IDLE == coex_dm->bt_status) || +	    (bt_link_info->sco_exist) || (bt_link_info->hid_only) || +	    (bt_link_info->a2dp_only) || (bt_link_info->pan_only)) { +		halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); +		coex_table_with_type(btcoexist, NORMAL_EXEC, 7); +	} else { +		halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 20); +		coex_table_with_type(btcoexist, NORMAL_EXEC, 1); +	} +} + +static void action_wifi_connected_scan(struct btc_coexist *btcoexist) +{ +	struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + +	halbtc8723b1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, +					 0x0, 0x0); + +	/* tdma and coex table */ +	if (BT_8723B_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) { +		if (bt_link_info->a2dp_exist && bt_link_info->pan_exist) { +			halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, +						true, 22); +			coex_table_with_type(btcoexist, NORMAL_EXEC, 1); +		} else if (bt_link_info->pan_only) { +			halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, +						true, 20); +			coex_table_with_type(btcoexist, NORMAL_EXEC, 2); +		} else { +			halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, +						true, 20); +			coex_table_with_type(btcoexist, NORMAL_EXEC, 1); +		} +	} else if ((BT_8723B_1ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) || +		   (BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY == +		    coex_dm->bt_status)) { +		action_bt_sco_hid_only_busy(btcoexist, +				BT_8723B_1ANT_WIFI_STATUS_CONNECTED_SCAN); +	} else { +		halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); +		coex_table_with_type(btcoexist, NORMAL_EXEC, 2); +	} +} + +static void action_wifi_connected_special_packet(struct btc_coexist *btcoexist) +{ +	bool hs_connecting = false; +	struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + +	btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_CONNECTING, &hs_connecting); + +	halbtc8723b1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, +					 0x0, 0x0); + +	/* tdma and coex table */ +	if ((BT_8723B_1ANT_BT_STATUS_CONNECTED_IDLE == coex_dm->bt_status) || +	    (bt_link_info->sco_exist) || (bt_link_info->hid_only) || +	    (bt_link_info->a2dp_only) || (bt_link_info->pan_only)) { +		halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); +		coex_table_with_type(btcoexist, NORMAL_EXEC, 7); +	} else { +		halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 20); +		coex_table_with_type(btcoexist, NORMAL_EXEC, 1); +	} +} + +static void halbtc8723b1ant_action_wifi_connected(struct btc_coexist *btcoexist) +{ +	bool wifi_busy = false; +	bool scan = false, link = false, roam = false; +	bool under_4way = false, ap_enable = false; + +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +		  "[BTCoex], CoexForWifiConnect() ===>\n"); + +	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS, +			   &under_4way); +	if (under_4way) { +		action_wifi_connected_special_packet(btcoexist); +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +			  "[BTCoex], CoexForWifiConnect(), return for wifi is under 4way<===\n"); +		return; +	} + +	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan); +	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link); +	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam); + +	if (scan || link || roam) { +		if (scan) +			action_wifi_connected_scan(btcoexist); +		else +			action_wifi_connected_special_packet(btcoexist); +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +			  "[BTCoex], CoexForWifiConnect(), return for wifi is under scan<===\n"); +		return; +	} + +	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_AP_MODE_ENABLE, +			   &ap_enable); +	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); +	/* power save state */ +	if (!ap_enable && +	    BT_8723B_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status && +	    !btcoexist->bt_link_info.hid_only) { +		if (!wifi_busy && btcoexist->bt_link_info.a2dp_only) +			halbtc8723b1ant_power_save_state(btcoexist, +							 BTC_PS_WIFI_NATIVE, +							 0x0, 0x0); +		else +			halbtc8723b1ant_power_save_state(btcoexist, +							 BTC_PS_LPS_ON, +							 0x50, 0x4); +	} else { +		halbtc8723b1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, +						 0x0, 0x0); +	} +	/* tdma and coex table */ +	if (!wifi_busy) { +		if (BT_8723B_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) { +			halbtc8723b1ant_action_wifi_connected_bt_acl_busy(btcoexist, +				      BT_8723B_1ANT_WIFI_STATUS_CONNECTED_IDLE); +		} else if ((BT_8723B_1ANT_BT_STATUS_SCO_BUSY == +						coex_dm->bt_status) || +			   (BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY == +						coex_dm->bt_status)) { +			action_bt_sco_hid_only_busy(btcoexist, +				     BT_8723B_1ANT_WIFI_STATUS_CONNECTED_IDLE); +		} else { +			halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, +						false, 8); +			coex_table_with_type(btcoexist, NORMAL_EXEC, 2); +		} +	} else { +		if (BT_8723B_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) { +			halbtc8723b1ant_action_wifi_connected_bt_acl_busy(btcoexist, +				    BT_8723B_1ANT_WIFI_STATUS_CONNECTED_BUSY); +		} else if ((BT_8723B_1ANT_BT_STATUS_SCO_BUSY == +			    coex_dm->bt_status) || +			   (BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY == +			    coex_dm->bt_status)) { +			action_bt_sco_hid_only_busy(btcoexist, +				    BT_8723B_1ANT_WIFI_STATUS_CONNECTED_BUSY); +		} else { +			halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); +			coex_table_with_type(btcoexist, NORMAL_EXEC, 2); +		} +	} +} + +static void run_sw_coexist_mechanism(struct btc_coexist *btcoexist) +{ +	u8 algorithm = 0; + +	algorithm = halbtc8723b1ant_action_algorithm(btcoexist); +	coex_dm->cur_algorithm = algorithm; + +	if (!halbtc8723b1ant_is_common_action(btcoexist)) { +		switch (coex_dm->cur_algorithm) { +		case BT_8723B_1ANT_COEX_ALGO_SCO: +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +				  "[BTCoex], Action algorithm = SCO.\n"); +			halbtc8723b1ant_action_sco(btcoexist); +			break; +		case BT_8723B_1ANT_COEX_ALGO_HID: +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +				  "[BTCoex], Action algorithm = HID.\n"); +			halbtc8723b1ant_action_hid(btcoexist); +			break; +		case BT_8723B_1ANT_COEX_ALGO_A2DP: +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +				  "[BTCoex], Action algorithm = A2DP.\n"); +			halbtc8723b1ant_action_a2dp(btcoexist); +			break; +		case BT_8723B_1ANT_COEX_ALGO_A2DP_PANHS: +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +				  "[BTCoex], Action algorithm = A2DP+PAN(HS).\n"); +			halbtc8723b1ant_action_a2dp_pan_hs(btcoexist); +			break; +		case BT_8723B_1ANT_COEX_ALGO_PANEDR: +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +				  "[BTCoex], Action algorithm = PAN(EDR).\n"); +			halbtc8723b1ant_action_pan_edr(btcoexist); +			break; +		case BT_8723B_1ANT_COEX_ALGO_PANHS: +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +				  "[BTCoex], Action algorithm = HS mode.\n"); +			halbtc8723b1ant_action_pan_hs(btcoexist); +			break; +		case BT_8723B_1ANT_COEX_ALGO_PANEDR_A2DP: +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +				  "[BTCoex], Action algorithm = PAN+A2DP.\n"); +			halbtc8723b1ant_action_pan_edr_a2dp(btcoexist); +			break; +		case BT_8723B_1ANT_COEX_ALGO_PANEDR_HID: +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +				  "[BTCoex], Action algorithm = PAN(EDR)+HID.\n"); +			halbtc8723b1ant_action_pan_edr_hid(btcoexist); +			break; +		case BT_8723B_1ANT_COEX_ALGO_HID_A2DP_PANEDR: +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +				  "[BTCoex], Action algorithm = HID+A2DP+PAN.\n"); +			action_hid_a2dp_pan_edr(btcoexist); +			break; +		case BT_8723B_1ANT_COEX_ALGO_HID_A2DP: +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +				  "[BTCoex], Action algorithm = HID+A2DP.\n"); +			halbtc8723b1ant_action_hid_a2dp(btcoexist); +			break; +		default: +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +				  "[BTCoex], Action algorithm = coexist All Off!!\n"); +			break; +		} +		coex_dm->pre_algorithm = coex_dm->cur_algorithm; +	} +} + +static void halbtc8723b1ant_run_coexist_mechanism(struct btc_coexist *btcoexist) +{ +	struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; +	bool wifi_connected = false, bt_hs_on = false; +	bool increase_scan_dev_num = false; +	bool b_bt_ctrl_agg_buf_size = false; +	u8 agg_buf_size = 5; +	u8 wifi_rssi_state = BTC_RSSI_STATE_HIGH; +	u32 wifi_link_status = 0; +	u32 num_of_wifi_link = 0; + +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +		  "[BTCoex], RunCoexistMechanism() ===>\n"); + +	if (btcoexist->manual_control) { +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +			  "[BTCoex], RunCoexistMechanism(), return for Manual CTRL <===\n"); +		return; +	} + +	if (btcoexist->stop_coex_dm) { +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +			  "[BTCoex], RunCoexistMechanism(), return for Stop Coex DM <===\n"); +		return; +	} + +	if (coex_sta->under_ips) { +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +			  "[BTCoex], wifi is under IPS !!!\n"); +		return; +	} + +	if ((BT_8723B_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) || +	    (BT_8723B_1ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) || +	    (BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY == coex_dm->bt_status)) +		increase_scan_dev_num = true; + +	btcoexist->btc_set(btcoexist, BTC_SET_BL_INC_SCAN_DEV_NUM, +			   &increase_scan_dev_num); + +	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, +			   &wifi_connected); + +	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_LINK_STATUS, +			   &wifi_link_status); +	num_of_wifi_link = wifi_link_status >> 16; +	if (num_of_wifi_link >= 2) { +		halbtc8723b1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0); +		halbtc8723b1ant_limited_rx(btcoexist, NORMAL_EXEC, false, +					   b_bt_ctrl_agg_buf_size, +					   agg_buf_size); +		halbtc8723b1ant_action_wifi_multiport(btcoexist); +		return; +	} + +	if (!bt_link_info->sco_exist && !bt_link_info->hid_exist) { +		halbtc8723b1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0); +	} else { +		if (wifi_connected) { +			wifi_rssi_state = +				halbtc8723b1ant_wifi_rssi_state(btcoexist, +								1, 2, 30, 0); +			if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || +			    (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +				halbtc8723b1ant_limited_tx(btcoexist, +							   NORMAL_EXEC, +							   1, 1, 1, 1); +			} else { +				halbtc8723b1ant_limited_tx(btcoexist, +							   NORMAL_EXEC, +							   1, 1, 1, 1); +			} +		} else { +			halbtc8723b1ant_limited_tx(btcoexist, NORMAL_EXEC, +						   0, 0, 0, 0); +		} +	} + +	if (bt_link_info->sco_exist) { +		b_bt_ctrl_agg_buf_size = true; +		agg_buf_size = 0x3; +	} else if (bt_link_info->hid_exist) { +		b_bt_ctrl_agg_buf_size = true; +		agg_buf_size = 0x5; +	} else if (bt_link_info->a2dp_exist || bt_link_info->pan_exist) { +		b_bt_ctrl_agg_buf_size = true; +		agg_buf_size = 0x8; +	} +	halbtc8723b1ant_limited_rx(btcoexist, NORMAL_EXEC, false, +				   b_bt_ctrl_agg_buf_size, agg_buf_size); + +	run_sw_coexist_mechanism(btcoexist); + +	btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + +	if (coex_sta->c2h_bt_inquiry_page) { +		halbtc8723b1ant_action_bt_inquiry(btcoexist); +		return; +	} else if (bt_hs_on) { +		halbtc8723b1ant_action_hs(btcoexist); +		return; +	} + +	if (!wifi_connected) { +		bool scan = false, link = false, roam = false; + +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +			  "[BTCoex], wifi is non connected-idle !!!\n"); + +		btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan); +		btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link); +		btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam); + +		if (scan || link || roam) { +			if (scan) +				action_wifi_not_connected_scan(btcoexist); +			else +				action_wifi_not_connected_asso_auth(btcoexist); +		} else { +			action_wifi_not_connected(btcoexist); +		} +	} else { /* wifi LPS/Busy */ +		halbtc8723b1ant_action_wifi_connected(btcoexist); +	} +} + +static void halbtc8723b1ant_init_coex_dm(struct btc_coexist *btcoexist) +{ +	/* sw all off */ +	halbtc8723b1ant_sw_mechanism(btcoexist, false); + +	halbtc8723b1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 8); +	coex_table_with_type(btcoexist, FORCE_EXEC, 0); +} + +static void init_hw_config(struct btc_coexist *btcoexist, bool backup) +{ +	u32 u32tmp = 0; +	u8 u8tmp = 0; +	u32 cnt_bt_cal_chk = 0; + +	BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, +		  "[BTCoex], 1Ant Init HW Config!!\n"); + +	if (backup) {/* backup rf 0x1e value */ +		coex_dm->backup_arfr_cnt1 = +			btcoexist->btc_read_4byte(btcoexist, 0x430); +		coex_dm->backup_arfr_cnt2 = +			btcoexist->btc_read_4byte(btcoexist, 0x434); +		coex_dm->backup_retry_limit = +			btcoexist->btc_read_2byte(btcoexist, 0x42a); +		coex_dm->backup_ampdu_max_time = +			btcoexist->btc_read_1byte(btcoexist, 0x456); +	} + +	/* WiFi goto standby while GNT_BT 0-->1 */ +	btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x780); +	/* BT goto standby while GNT_BT 1-->0 */ +	btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x2, 0xfffff, 0x500); + +	btcoexist->btc_write_1byte(btcoexist, 0x974, 0xff); +	btcoexist->btc_write_1byte_bitmask(btcoexist, 0x944, 0x3, 0x3); +	btcoexist->btc_write_1byte(btcoexist, 0x930, 0x77); + +	/* BT calibration check */ +	while (cnt_bt_cal_chk <= 20) { +		u32tmp = btcoexist->btc_read_4byte(btcoexist, 0x49d); +		cnt_bt_cal_chk++; +		if (u32tmp & BIT(0)) { +			BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, +				  "[BTCoex], ########### BT calibration(cnt =%d) ###########\n", +				  cnt_bt_cal_chk); +			mdelay(50); +		} else { +			BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, +				  "[BTCoex], ********** BT NOT calibration (cnt =%d)**********\n", +				  cnt_bt_cal_chk); +			break; +		} +	} + +	/* 0x790[5:0] = 0x5 */ +	u8tmp = btcoexist->btc_read_1byte(btcoexist, 0x790); +	u8tmp &= 0xc0; +	u8tmp |= 0x5; +	btcoexist->btc_write_1byte(btcoexist, 0x790, u8tmp); + +	/* Enable counter statistics */ +	/*0x76e[3] = 1, WLAN_Act control by PTA */ +	btcoexist->btc_write_1byte(btcoexist, 0x76e, 0xc); +	btcoexist->btc_write_1byte(btcoexist, 0x778, 0x1); +	btcoexist->btc_write_1byte_bitmask(btcoexist, 0x40, 0x20, 0x1); + +	/*Antenna config */ +	halbtc8723b1ant_setantpath(btcoexist, BTC_ANT_PATH_PTA, true, false); +	/* PTA parameter */ +	coex_table_with_type(btcoexist, FORCE_EXEC, 0); +} + +static void halbtc8723b1ant_wifi_off_hw_cfg(struct btc_coexist *btcoexist) +{ +	/* set wlan_act to low */ +	btcoexist->btc_write_1byte(btcoexist, 0x76e, 0x4); +} + +/************************************************************** + * work around function start with wa_halbtc8723b1ant_ + **************************************************************/ +/************************************************************** + * extern function start with EXhalbtc8723b1ant_ + **************************************************************/ + +void ex_halbtc8723b1ant_init_hwconfig(struct btc_coexist *btcoexist) +{ +	init_hw_config(btcoexist, true); +} + +void ex_halbtc8723b1ant_init_coex_dm(struct btc_coexist *btcoexist) +{ +	BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, +		  "[BTCoex], Coex Mechanism Init!!\n"); + +	btcoexist->stop_coex_dm = false; + +	halbtc8723b1ant_init_coex_dm(btcoexist); + +	halbtc8723b1ant_query_bt_info(btcoexist); +} + +void ex_halbtc8723b1ant_display_coex_info(struct btc_coexist *btcoexist) +{ +	struct btc_board_info *brd_info = &btcoexist->board_info; +	struct btc_stack_info *stack_info = &btcoexist->stack_info; +	struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; +	u8 *cli_buf = btcoexist->cli_buf; +	u8 u8tmp[4], i, bt_info_ext, stdmacase = 0; +	u16 u16tmp[4]; +	u32 u32tmp[4]; +	bool roam = false, scan = false; +	bool link = false, wifi_under_5g = false; +	bool bt_hs_on = false, wifi_busy = false; +	s32 wifi_rssi = 0, bt_hs_rssi = 0; +	u32 wifi_bw, wifi_traffic_dir, fa_ofdm, fa_cck, wifi_link_status; +	u8 wifi_dot11_chnl, wifi_hs_chnl; +	u32 fw_ver = 0, bt_patch_ver = 0; + +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, +		   "\r\n ============[BT Coexist info] ============"); +	CL_PRINTF(cli_buf); + +	if (btcoexist->manual_control) { +		CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, +			   "\r\n ============[Under Manual Control] =========="); +		CL_PRINTF(cli_buf); +		CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, +			   "\r\n =========================================="); +		CL_PRINTF(cli_buf); +	} +	if (btcoexist->stop_coex_dm) { +		CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, +			   "\r\n ============[Coex is STOPPED] ============"); +		CL_PRINTF(cli_buf); +		CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, +			   "\r\n =========================================="); +		CL_PRINTF(cli_buf); +	} + +	if (!brd_info->bt_exist) { +		CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n BT not exists !!!"); +		CL_PRINTF(cli_buf); +		return; +	} + +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d", +		   "Ant PG Num/ Ant Mech/ Ant Pos: ", +		   brd_info->pg_ant_num, brd_info->btdm_ant_num, +		   brd_info->btdm_ant_pos); +	CL_PRINTF(cli_buf); + +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s / %d", +		   "BT stack/ hci ext ver", +		   ((stack_info->profile_notified) ? "Yes" : "No"), +		   stack_info->hci_version); +	CL_PRINTF(cli_buf); + +	btcoexist->btc_get(btcoexist, BTC_GET_U4_BT_PATCH_VER, &bt_patch_ver); +	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver); +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, +		   "\r\n %-35s = %d_%x/ 0x%x/ 0x%x(%d)", +		   "CoexVer/ FwVer/ PatchVer", +		   glcoex_ver_date_8723b_1ant, glcoex_ver_8723b_1ant, +		   fw_ver, bt_patch_ver, bt_patch_ver); +	CL_PRINTF(cli_buf); + +	btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); +	btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_DOT11_CHNL, +			   &wifi_dot11_chnl); +	btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_HS_CHNL, &wifi_hs_chnl); +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d / %d(%d)", +		   "Dot11 channel / HsChnl(HsMode)", +		   wifi_dot11_chnl, wifi_hs_chnl, bt_hs_on); +	CL_PRINTF(cli_buf); + +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x ", +		   "H2C Wifi inform bt chnl Info", +		   coex_dm->wifi_chnl_info[0], coex_dm->wifi_chnl_info[1], +		   coex_dm->wifi_chnl_info[2]); +	CL_PRINTF(cli_buf); + +	btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifi_rssi); +	btcoexist->btc_get(btcoexist, BTC_GET_S4_HS_RSSI, &bt_hs_rssi); +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", +		   "Wifi rssi/ HS rssi", wifi_rssi, bt_hs_rssi); +	CL_PRINTF(cli_buf); + +	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan); +	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link); +	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam); +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d ", +		   "Wifi link/ roam/ scan", link, roam, scan); +	CL_PRINTF(cli_buf); + +	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, +			   &wifi_under_5g); +	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); +	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); +	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_TRAFFIC_DIRECTION, +			   &wifi_traffic_dir); + +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s / %s/ %s ", +		   "Wifi status", (wifi_under_5g ? "5G" : "2.4G"), +		   ((BTC_WIFI_BW_LEGACY == wifi_bw) ? "Legacy" : +			(((BTC_WIFI_BW_HT40 == wifi_bw) ? "HT40" : "HT20"))), +		   ((!wifi_busy) ? "idle" : +			((BTC_WIFI_TRAFFIC_TX == wifi_traffic_dir) ? +				"uplink" : "downlink"))); +	CL_PRINTF(cli_buf); + +	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_LINK_STATUS, +			   &wifi_link_status); +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d/ %d/ %d", +		   "sta/vwifi/hs/p2pGo/p2pGc", +		   ((wifi_link_status & WIFI_STA_CONNECTED) ? 1 : 0), +		   ((wifi_link_status & WIFI_AP_CONNECTED) ? 1 : 0), +		   ((wifi_link_status & WIFI_HS_CONNECTED) ? 1 : 0), +		   ((wifi_link_status & WIFI_P2P_GO_CONNECTED) ? 1 : 0), +		   ((wifi_link_status & WIFI_P2P_GC_CONNECTED) ? 1 : 0)); +	CL_PRINTF(cli_buf); + +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = [%s/ %d/ %d] ", +		   "BT [status/ rssi/ retryCnt]", +		   ((btcoexist->bt_info.bt_disabled) ? ("disabled") : +		    ((coex_sta->c2h_bt_inquiry_page) ? ("inquiry/page scan") : +		     ((BT_8723B_1ANT_BT_STATUS_NON_CONNECTED_IDLE == coex_dm->bt_status) ? +		      "non-connected idle" : +		      ((BT_8723B_1ANT_BT_STATUS_CONNECTED_IDLE == coex_dm->bt_status) ? +		       "connected-idle" : "busy")))), +		       coex_sta->bt_rssi, coex_sta->bt_retry_cnt); +	CL_PRINTF(cli_buf); + +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d / %d / %d / %d", +		"SCO/HID/PAN/A2DP", bt_link_info->sco_exist, +		bt_link_info->hid_exist, bt_link_info->pan_exist, +		bt_link_info->a2dp_exist); +	CL_PRINTF(cli_buf); +	btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_BT_LINK_INFO); + +	bt_info_ext = coex_sta->bt_info_ext; +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s", +		   "BT Info A2DP rate", +		   (bt_info_ext & BIT(0)) ? "Basic rate" : "EDR rate"); +	CL_PRINTF(cli_buf); + +	for (i = 0; i < BT_INFO_SRC_8723B_1ANT_MAX; i++) { +		if (coex_sta->bt_info_c2h_cnt[i]) { +			CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, +				   "\r\n %-35s = %02x %02x %02x %02x %02x %02x %02x(%d)", +				   glb_infosrc8723b1ant[i], +				   coex_sta->bt_info_c2h[i][0], +				   coex_sta->bt_info_c2h[i][1], +				   coex_sta->bt_info_c2h[i][2], +				   coex_sta->bt_info_c2h[i][3], +				   coex_sta->bt_info_c2h[i][4], +				   coex_sta->bt_info_c2h[i][5], +				   coex_sta->bt_info_c2h[i][6], +				   coex_sta->bt_info_c2h_cnt[i]); +			CL_PRINTF(cli_buf); +		} +	} +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, +		   "\r\n %-35s = %s/%s, (0x%x/0x%x)", +		   "PS state, IPS/LPS, (lps/rpwm)", +		   ((coex_sta->under_ips ? "IPS ON" : "IPS OFF")), +		   ((coex_sta->under_lps ? "LPS ON" : "LPS OFF")), +		   btcoexist->bt_info.lps_val, +		   btcoexist->bt_info.rpwm_val); +	CL_PRINTF(cli_buf); +	btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_FW_PWR_MODE_CMD); + +	if (!btcoexist->manual_control) { +		/* Sw mechanism	*/ +		CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", +			   "============[Sw mechanism] ============"); +		CL_PRINTF(cli_buf); + +		CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/", +			   "SM[LowPenaltyRA]", coex_dm->cur_low_penalty_ra); +		CL_PRINTF(cli_buf); + +		CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s/ %s/ %d ", +			   "DelBA/ BtCtrlAgg/ AggSize", +			   (btcoexist->bt_info.reject_agg_pkt ? "Yes" : "No"), +			   (btcoexist->bt_info.b_bt_ctrl_buf_size ? "Yes" : "No"), +			   btcoexist->bt_info.agg_buf_size); +		CL_PRINTF(cli_buf); + +		CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x ", +			   "Rate Mask", btcoexist->bt_info.ra_mask); +		CL_PRINTF(cli_buf); + +		/* Fw mechanism	*/ +		CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", +			   "============[Fw mechanism] ============"); +		CL_PRINTF(cli_buf); + +		stdmacase = coex_dm->cur_ps_tdma; +		CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, +			   "\r\n %-35s = %02x %02x %02x %02x %02x case-%d (auto:%d)", +			   "PS TDMA", coex_dm->ps_tdma_para[0], +			   coex_dm->ps_tdma_para[1], coex_dm->ps_tdma_para[2], +			   coex_dm->ps_tdma_para[3], coex_dm->ps_tdma_para[4], +			   stdmacase, coex_dm->auto_tdma_adjust); +		CL_PRINTF(cli_buf); + +		CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d ", +			   "IgnWlanAct", coex_dm->cur_ignore_wlan_act); +		CL_PRINTF(cli_buf); + +		CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x ", +			   "Latest error condition(should be 0)", +			   coex_dm->error_condition); +		CL_PRINTF(cli_buf); +	} + +	/* Hw setting */ +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", +		   "============[Hw setting] ============"); +	CL_PRINTF(cli_buf); + +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/0x%x/0x%x/0x%x", +		   "backup ARFR1/ARFR2/RL/AMaxTime", coex_dm->backup_arfr_cnt1, +		   coex_dm->backup_arfr_cnt2, coex_dm->backup_retry_limit, +		   coex_dm->backup_ampdu_max_time); +	CL_PRINTF(cli_buf); + +	u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x430); +	u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x434); +	u16tmp[0] = btcoexist->btc_read_2byte(btcoexist, 0x42a); +	u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x456); +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/0x%x/0x%x/0x%x", +		   "0x430/0x434/0x42a/0x456", +		   u32tmp[0], u32tmp[1], u16tmp[0], u8tmp[0]); +	CL_PRINTF(cli_buf); + +	u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x778); +	u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x6cc); +	u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x880); +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", +		   "0x778/0x6cc/0x880[29:25]", u8tmp[0], u32tmp[0], +		   (u32tmp[1] & 0x3e000000) >> 25); +	CL_PRINTF(cli_buf); + +	u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x948); +	u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x67); +	u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0x765); +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\n %-35s = 0x%x/ 0x%x/ 0x%x", +		   "0x948/ 0x67[5] / 0x765", +		   u32tmp[0], ((u8tmp[0] & 0x20) >> 5), u8tmp[1]); +	CL_PRINTF(cli_buf); + +	u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x92c); +	u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x930); +	u32tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0x944); +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", +		   "0x92c[1:0]/ 0x930[7:0]/0x944[1:0]", +		   u32tmp[0] & 0x3, u32tmp[1] & 0xff, u32tmp[2] & 0x3); +	CL_PRINTF(cli_buf); + +	u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x39); +	u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0x40); +	u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x4c); +	u8tmp[2] = btcoexist->btc_read_1byte(btcoexist, 0x64); +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, +		   "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", +		   "0x38[11]/0x40/0x4c[24:23]/0x64[0]", +		   ((u8tmp[0] & 0x8)>>3), u8tmp[1], +		   ((u32tmp[0] & 0x01800000) >> 23), u8tmp[2] & 0x1); +	CL_PRINTF(cli_buf); + +	u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x550); +	u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x522); +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", +		   "0x550(bcn ctrl)/0x522", u32tmp[0], u8tmp[0]); +	CL_PRINTF(cli_buf); + +	u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xc50); +	u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x49c); +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", +		   "0xc50(dig)/0x49c(null-drop)", u32tmp[0] & 0xff, u8tmp[0]); +	CL_PRINTF(cli_buf); + +	u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xda0); +	u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0xda4); +	u32tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0xda8); +	u32tmp[3] = btcoexist->btc_read_4byte(btcoexist, 0xcf0); + +	u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0xa5b); +	u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0xa5c); + +	fa_ofdm = ((u32tmp[0] & 0xffff0000) >> 16) + +		  ((u32tmp[1] & 0xffff0000) >> 16) + +		   (u32tmp[1] & 0xffff) + +		   (u32tmp[2] & 0xffff) + +		  ((u32tmp[3] & 0xffff0000) >> 16) + +		   (u32tmp[3] & 0xffff); +	fa_cck = (u8tmp[0] << 8) + u8tmp[1]; + +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", +		   "OFDM-CCA/OFDM-FA/CCK-FA", +		   u32tmp[0] & 0xffff, fa_ofdm, fa_cck); +	CL_PRINTF(cli_buf); + +	u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x6c0); +	u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x6c4); +	u32tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0x6c8); +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", +		   "0x6c0/0x6c4/0x6c8(coexTable)", +		   u32tmp[0], u32tmp[1], u32tmp[2]); +	CL_PRINTF(cli_buf); + +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", +		   "0x770(high-pri rx/tx)", coex_sta->high_priority_rx, +		   coex_sta->high_priority_tx); +	CL_PRINTF(cli_buf); +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", +		   "0x774(low-pri rx/tx)", coex_sta->low_priority_rx, +		   coex_sta->low_priority_tx); +	CL_PRINTF(cli_buf); +#if (BT_AUTO_REPORT_ONLY_8723B_1ANT == 1) +	halbtc8723b1ant_monitor_bt_ctr(btcoexist); +#endif +	btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_COEX_STATISTICS); +} + +void ex_halbtc8723b1ant_ips_notify(struct btc_coexist *btcoexist, u8 type) +{ +	if (btcoexist->manual_control || btcoexist->stop_coex_dm) +		return; + +	if (BTC_IPS_ENTER == type) { +		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, +			  "[BTCoex], IPS ENTER notify\n"); +		coex_sta->under_ips = true; + +		halbtc8723b1ant_setantpath(btcoexist, BTC_ANT_PATH_BT, +					   false, true); +		/* set PTA control */ +		halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); +		coex_table_with_type(btcoexist, +						     NORMAL_EXEC, 0); +		halbtc8723b1ant_wifi_off_hw_cfg(btcoexist); +	} else if (BTC_IPS_LEAVE == type) { +		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, +			  "[BTCoex], IPS LEAVE notify\n"); +		coex_sta->under_ips = false; + +		init_hw_config(btcoexist, false); +		halbtc8723b1ant_init_coex_dm(btcoexist); +		halbtc8723b1ant_query_bt_info(btcoexist); +	} +} + +void ex_halbtc8723b1ant_lps_notify(struct btc_coexist *btcoexist, u8 type) +{ +	if (btcoexist->manual_control || btcoexist->stop_coex_dm) +		return; + +	if (BTC_LPS_ENABLE == type) { +		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, +			  "[BTCoex], LPS ENABLE notify\n"); +		coex_sta->under_lps = true; +	} else if (BTC_LPS_DISABLE == type) { +		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, +			  "[BTCoex], LPS DISABLE notify\n"); +		coex_sta->under_lps = false; +	} +} + +void ex_halbtc8723b1ant_scan_notify(struct btc_coexist *btcoexist, u8 type) +{ +	bool wifi_connected = false, bt_hs_on = false; +	u32 wifi_link_status = 0; +	u32 num_of_wifi_link = 0; +	bool bt_ctrl_agg_buf_size = false; +	u8 agg_buf_size = 5; + +	if (btcoexist->manual_control || btcoexist->stop_coex_dm || +	    btcoexist->bt_info.bt_disabled) +		return; + +	btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); +	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, +			   &wifi_connected); + +	halbtc8723b1ant_query_bt_info(btcoexist); + +	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_LINK_STATUS, +			   &wifi_link_status); +	num_of_wifi_link = wifi_link_status >> 16; +	if (num_of_wifi_link >= 2) { +		halbtc8723b1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0); +		halbtc8723b1ant_limited_rx(btcoexist, NORMAL_EXEC, false, +					   bt_ctrl_agg_buf_size, agg_buf_size); +		halbtc8723b1ant_action_wifi_multiport(btcoexist); +		return; +	} + +	if (coex_sta->c2h_bt_inquiry_page) { +		halbtc8723b1ant_action_bt_inquiry(btcoexist); +		return; +	} else if (bt_hs_on) { +		halbtc8723b1ant_action_hs(btcoexist); +		return; +	} + +	if (BTC_SCAN_START == type) { +		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, +			  "[BTCoex], SCAN START notify\n"); +		if (!wifi_connected)	/* non-connected scan */ +			action_wifi_not_connected_scan(btcoexist); +		else	/* wifi is connected */ +			action_wifi_connected_scan(btcoexist); +	} else if (BTC_SCAN_FINISH == type) { +		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, +			  "[BTCoex], SCAN FINISH notify\n"); +		if (!wifi_connected)	/* non-connected scan */ +			action_wifi_not_connected(btcoexist); +		else +			halbtc8723b1ant_action_wifi_connected(btcoexist); +	} +} + +void ex_halbtc8723b1ant_connect_notify(struct btc_coexist *btcoexist, u8 type) +{ +	bool wifi_connected = false, bt_hs_on = false; +	u32 wifi_link_status = 0; +	u32 num_of_wifi_link = 0; +	bool bt_ctrl_agg_buf_size = false; +	u8 agg_buf_size = 5; + +	if (btcoexist->manual_control || btcoexist->stop_coex_dm || +	    btcoexist->bt_info.bt_disabled) +		return; + +	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_LINK_STATUS, +			   &wifi_link_status); +	num_of_wifi_link = wifi_link_status>>16; +	if (num_of_wifi_link >= 2) { +		halbtc8723b1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0); +		halbtc8723b1ant_limited_rx(btcoexist, NORMAL_EXEC, false, +					   bt_ctrl_agg_buf_size, agg_buf_size); +		halbtc8723b1ant_action_wifi_multiport(btcoexist); +		return; +	} + +	btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); +	if (coex_sta->c2h_bt_inquiry_page) { +		halbtc8723b1ant_action_bt_inquiry(btcoexist); +		return; +	} else if (bt_hs_on) { +		halbtc8723b1ant_action_hs(btcoexist); +		return; +	} + +	if (BTC_ASSOCIATE_START == type) { +		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, +			  "[BTCoex], CONNECT START notify\n"); +		action_wifi_not_connected_asso_auth(btcoexist); +	} else if (BTC_ASSOCIATE_FINISH == type) { +		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, +			  "[BTCoex], CONNECT FINISH notify\n"); + +		btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, +				   &wifi_connected); +		if (!wifi_connected) /* non-connected scan */ +			action_wifi_not_connected(btcoexist); +		else +			halbtc8723b1ant_action_wifi_connected(btcoexist); +	} +} + +void ex_halbtc8723b1ant_media_status_notify(struct btc_coexist *btcoexist, +					    u8 type) +{ +	u8 h2c_parameter[3] = {0}; +	u32 wifi_bw; +	u8 wificentralchnl; + +	if (btcoexist->manual_control || btcoexist->stop_coex_dm || +	    btcoexist->bt_info.bt_disabled) +		return; + +	if (BTC_MEDIA_CONNECT == type) +		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, +			  "[BTCoex], MEDIA connect notify\n"); +	else +		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, +			  "[BTCoex], MEDIA disconnect notify\n"); + +	/* only 2.4G we need to inform bt the chnl mask */ +	btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_CENTRAL_CHNL, +			   &wificentralchnl); + +	if ((BTC_MEDIA_CONNECT == type) && +	    (wificentralchnl <= 14)) { +		h2c_parameter[0] = 0x0; +		h2c_parameter[1] = wificentralchnl; +		btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); +		if (BTC_WIFI_BW_HT40 == wifi_bw) +			h2c_parameter[2] = 0x30; +		else +			h2c_parameter[2] = 0x20; +	} + +	coex_dm->wifi_chnl_info[0] = h2c_parameter[0]; +	coex_dm->wifi_chnl_info[1] = h2c_parameter[1]; +	coex_dm->wifi_chnl_info[2] = h2c_parameter[2]; + +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, +		  "[BTCoex], FW write 0x66 = 0x%x\n", +		  h2c_parameter[0] << 16 | h2c_parameter[1] << 8 | +		  h2c_parameter[2]); + +	btcoexist->btc_fill_h2c(btcoexist, 0x66, 3, h2c_parameter); +} + +void ex_halbtc8723b1ant_special_packet_notify(struct btc_coexist *btcoexist, +					      u8 type) +{ +	bool bt_hs_on = false; +	u32 wifi_link_status = 0; +	u32 num_of_wifi_link = 0; +	bool bt_ctrl_agg_buf_size = false; +	u8 agg_buf_size = 5; + +	if (btcoexist->manual_control || btcoexist->stop_coex_dm || +	    btcoexist->bt_info.bt_disabled) +		return; + +	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_LINK_STATUS, +			   &wifi_link_status); +	num_of_wifi_link = wifi_link_status >> 16; +	if (num_of_wifi_link >= 2) { +		halbtc8723b1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0); +		halbtc8723b1ant_limited_rx(btcoexist, NORMAL_EXEC, false, +					   bt_ctrl_agg_buf_size, agg_buf_size); +		halbtc8723b1ant_action_wifi_multiport(btcoexist); +		return; +	} + +	coex_sta->special_pkt_period_cnt = 0; + +	btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); +	if (coex_sta->c2h_bt_inquiry_page) { +		halbtc8723b1ant_action_bt_inquiry(btcoexist); +		return; +	} else if (bt_hs_on) { +		halbtc8723b1ant_action_hs(btcoexist); +		return; +	} + +	if (BTC_PACKET_DHCP == type || +	    BTC_PACKET_EAPOL == type) { +		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, +			  "[BTCoex], special Packet(%d) notify\n", type); +		action_wifi_connected_special_packet(btcoexist); +	} +} + +void ex_halbtc8723b1ant_bt_info_notify(struct btc_coexist *btcoexist, +				       u8 *tmp_buf, u8 length) +{ +	u8 bt_info = 0; +	u8 i, rsp_source = 0; +	bool wifi_connected = false; +	bool bt_busy = false; + +	coex_sta->c2h_bt_info_req_sent = false; + +	rsp_source = tmp_buf[0] & 0xf; +	if (rsp_source >= BT_INFO_SRC_8723B_1ANT_MAX) +		rsp_source = BT_INFO_SRC_8723B_1ANT_WIFI_FW; +	coex_sta->bt_info_c2h_cnt[rsp_source]++; + +	BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, +		  "[BTCoex], Bt info[%d], length =%d, hex data =[", +		  rsp_source, length); +	for (i = 0; i < length; i++) { +		coex_sta->bt_info_c2h[rsp_source][i] = tmp_buf[i]; +		if (i == 1) +			bt_info = tmp_buf[i]; +		if (i == length - 1) +			BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, +				  "0x%02x]\n", tmp_buf[i]); +		else +			BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, +				  "0x%02x, ", tmp_buf[i]); +	} + +	if (BT_INFO_SRC_8723B_1ANT_WIFI_FW != rsp_source) { +		coex_sta->bt_retry_cnt =	/* [3:0] */ +			coex_sta->bt_info_c2h[rsp_source][2] & 0xf; + +		coex_sta->bt_rssi = +			coex_sta->bt_info_c2h[rsp_source][3] * 2 + 10; + +		coex_sta->bt_info_ext = +			coex_sta->bt_info_c2h[rsp_source][4]; + +		/* Here we need to resend some wifi info to BT +		 * because bt is reset and loss of the info.*/ +		if (coex_sta->bt_info_ext & BIT(1)) { +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +				  "[BTCoex], BT ext info bit1 check, send wifi BW&Chnl to BT!!\n"); +			btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, +					   &wifi_connected); +			if (wifi_connected) +				ex_halbtc8723b1ant_media_status_notify(btcoexist, +							     BTC_MEDIA_CONNECT); +			else +				ex_halbtc8723b1ant_media_status_notify(btcoexist, +							  BTC_MEDIA_DISCONNECT); +		} + +		if (coex_sta->bt_info_ext & BIT(3)) { +			if (!btcoexist->manual_control && +			    !btcoexist->stop_coex_dm) { +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +					  "[BTCoex], BT ext info bit3 check, set BT NOT ignore Wlan active!!\n"); +				halbtc8723b1ant_ignore_wlan_act(btcoexist, +								FORCE_EXEC, +								false); +			} +		} else { +			/* BT already NOT ignore Wlan active, do nothing here.*/ +		} +#if (BT_AUTO_REPORT_ONLY_8723B_1ANT == 0) +		if (coex_sta->bt_info_ext & BIT(4)) { +			/* BT auto report already enabled, do nothing */ +		} else { +			halbtc8723b1ant_bt_auto_report(btcoexist, FORCE_EXEC, +						       true); +		} +#endif +	} + +	/* check BIT(2) first ==> check if bt is under inquiry or page scan */ +	if (bt_info & BT_INFO_8723B_1ANT_B_INQ_PAGE) +		coex_sta->c2h_bt_inquiry_page = true; +	else +		coex_sta->c2h_bt_inquiry_page = false; + +	/* set link exist status */ +	if (!(bt_info & BT_INFO_8723B_1ANT_B_CONNECTION)) { +		coex_sta->bt_link_exist = false; +		coex_sta->pan_exist = false; +		coex_sta->a2dp_exist = false; +		coex_sta->hid_exist = false; +		coex_sta->sco_exist = false; +	} else { /* connection exists */ +		coex_sta->bt_link_exist = true; +		if (bt_info & BT_INFO_8723B_1ANT_B_FTP) +			coex_sta->pan_exist = true; +		else +			coex_sta->pan_exist = false; +		if (bt_info & BT_INFO_8723B_1ANT_B_A2DP) +			coex_sta->a2dp_exist = true; +		else +			coex_sta->a2dp_exist = false; +		if (bt_info & BT_INFO_8723B_1ANT_B_HID) +			coex_sta->hid_exist = true; +		else +			coex_sta->hid_exist = false; +		if (bt_info & BT_INFO_8723B_1ANT_B_SCO_ESCO) +			coex_sta->sco_exist = true; +		else +			coex_sta->sco_exist = false; +	} + +	halbtc8723b1ant_update_bt_link_info(btcoexist); + +	if (!(bt_info&BT_INFO_8723B_1ANT_B_CONNECTION)) { +		coex_dm->bt_status = BT_8723B_1ANT_BT_STATUS_NON_CONNECTED_IDLE; +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +			  "[BTCoex], BtInfoNotify(), BT Non-Connected idle!\n"); +	/* connection exists but no busy */ +	} else if (bt_info == BT_INFO_8723B_1ANT_B_CONNECTION) { +		coex_dm->bt_status = BT_8723B_1ANT_BT_STATUS_CONNECTED_IDLE; +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +			  "[BTCoex], BtInfoNotify(), BT Connected-idle!!!\n"); +	} else if ((bt_info & BT_INFO_8723B_1ANT_B_SCO_ESCO) || +		(bt_info & BT_INFO_8723B_1ANT_B_SCO_BUSY)) { +		coex_dm->bt_status = BT_8723B_1ANT_BT_STATUS_SCO_BUSY; +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +			  "[BTCoex], BtInfoNotify(), BT SCO busy!!!\n"); +	} else if (bt_info & BT_INFO_8723B_1ANT_B_ACL_BUSY) { +		if (BT_8723B_1ANT_BT_STATUS_ACL_BUSY != coex_dm->bt_status) +			coex_dm->auto_tdma_adjust = false; + +		coex_dm->bt_status = BT_8723B_1ANT_BT_STATUS_ACL_BUSY; +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +			  "[BTCoex], BtInfoNotify(), BT ACL busy!!!\n"); +	} else { +		coex_dm->bt_status = +			BT_8723B_1ANT_BT_STATUS_MAX; +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +			  "[BTCoex], BtInfoNotify(), BT Non-Defined state!!\n"); +	} + +	if ((BT_8723B_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) || +	    (BT_8723B_1ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) || +	    (BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY == coex_dm->bt_status)) +		bt_busy = true; +	else +		bt_busy = false; +	btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_TRAFFIC_BUSY, &bt_busy); + +	halbtc8723b1ant_run_coexist_mechanism(btcoexist); +} + +void ex_halbtc8723b1ant_halt_notify(struct btc_coexist *btcoexist) +{ +	BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, "[BTCoex], Halt notify\n"); + +	btcoexist->stop_coex_dm = true; + +	halbtc8723b1ant_setantpath(btcoexist, BTC_ANT_PATH_BT, false, true); + +	halbtc8723b1ant_wifi_off_hw_cfg(btcoexist); +	halbtc8723b1ant_ignore_wlan_act(btcoexist, FORCE_EXEC, true); + +	halbtc8723b1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, +					 0x0, 0x0); +	halbtc8723b1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 0); + +	ex_halbtc8723b1ant_media_status_notify(btcoexist, BTC_MEDIA_DISCONNECT); +} + +void ex_halbtc8723b1ant_pnp_notify(struct btc_coexist *btcoexist, u8 pnp_state) +{ +	BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, "[BTCoex], Pnp notify\n"); + +	if (BTC_WIFI_PNP_SLEEP == pnp_state) { +		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, +			  "[BTCoex], Pnp notify to SLEEP\n"); +		btcoexist->stop_coex_dm = true; +		halbtc8723b1ant_setantpath(btcoexist, BTC_ANT_PATH_BT, false, +					   true); +		halbtc8723b1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, +						 0x0, 0x0); +		halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); +		coex_table_with_type(btcoexist, NORMAL_EXEC, 2); +		halbtc8723b1ant_wifi_off_hw_cfg(btcoexist); +	} else if (BTC_WIFI_PNP_WAKE_UP == pnp_state) { +		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, +			  "[BTCoex], Pnp notify to WAKE UP\n"); +		btcoexist->stop_coex_dm = false; +		init_hw_config(btcoexist, false); +		halbtc8723b1ant_init_coex_dm(btcoexist); +		halbtc8723b1ant_query_bt_info(btcoexist); +	} +} + +void ex_halbtc8723b1ant_coex_dm_reset(struct btc_coexist *btcoexist) +{ +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +		  "[BTCoex], *****************Coex DM Reset****************\n"); + +	init_hw_config(btcoexist, false); +	btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); +	btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x2, 0xfffff, 0x0); +	halbtc8723b1ant_init_coex_dm(btcoexist); +} + +void ex_halbtc8723b1ant_periodical(struct btc_coexist *btcoexist) +{ +	struct btc_board_info *brd_info = &btcoexist->board_info; +	struct btc_stack_info *stack_info = &btcoexist->stack_info; +	static u8 dis_ver_info_cnt; +	u32 fw_ver = 0, bt_patch_ver = 0; + +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +		  "[BTCoex], ========================== Periodical ===========================\n"); + +	if (dis_ver_info_cnt <= 5) { +		dis_ver_info_cnt += 1; +		BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, +			  "[BTCoex], ****************************************************************\n"); +		BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, +			  "[BTCoex], Ant PG Num/ Ant Mech/ Ant Pos = %d/ %d/ %d\n", +			  brd_info->pg_ant_num, brd_info->btdm_ant_num, +			  brd_info->btdm_ant_pos); +		BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, +			  "[BTCoex], BT stack/ hci ext ver = %s / %d\n", +			  ((stack_info->profile_notified) ? "Yes" : "No"), +			  stack_info->hci_version); +		btcoexist->btc_get(btcoexist, BTC_GET_U4_BT_PATCH_VER, +				   &bt_patch_ver); +		btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver); +		BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, +			  "[BTCoex], CoexVer/ FwVer/ PatchVer = %d_%x/ 0x%x/ 0x%x(%d)\n", +			  glcoex_ver_date_8723b_1ant, +			  glcoex_ver_8723b_1ant, fw_ver, +			  bt_patch_ver, bt_patch_ver); +		BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, +			  "[BTCoex], ****************************************************************\n"); +	} + +#if (BT_AUTO_REPORT_ONLY_8723B_1ANT == 0) +	halbtc8723b1ant_query_bt_info(btcoexist); +	halbtc8723b1ant_monitor_bt_ctr(btcoexist); +	halbtc8723b1ant_monitor_bt_enable_disable(btcoexist); +#else +	if (is_wifi_status_changed(btcoexist) || +	    coex_dm->auto_tdma_adjust) { +		halbtc8723b1ant_run_coexist_mechanism(btcoexist); +	} + +	coex_sta->special_pkt_period_cnt++; +#endif +} + diff --git a/drivers/staging/rtl8192ee/btcoexist/halbtc8723b1ant.h b/drivers/staging/rtl8192ee/btcoexist/halbtc8723b1ant.h new file mode 100644 index 00000000000..bded3738f24 --- /dev/null +++ b/drivers/staging/rtl8192ee/btcoexist/halbtc8723b1ant.h @@ -0,0 +1,160 @@ +/********************************************************************** + * The following is for 8723B 1ANT BT Co-exist definition + **********************************************************************/ +#define	BT_AUTO_REPORT_ONLY_8723B_1ANT			1 + +#define	BT_INFO_8723B_1ANT_B_FTP			BIT(7) +#define	BT_INFO_8723B_1ANT_B_A2DP			BIT(6) +#define	BT_INFO_8723B_1ANT_B_HID			BIT(5) +#define	BT_INFO_8723B_1ANT_B_SCO_BUSY			BIT(4) +#define	BT_INFO_8723B_1ANT_B_ACL_BUSY			BIT(3) +#define	BT_INFO_8723B_1ANT_B_INQ_PAGE			BIT(2) +#define	BT_INFO_8723B_1ANT_B_SCO_ESCO			BIT(1) +#define	BT_INFO_8723B_1ANT_B_CONNECTION			BIT(0) + +#define	BT_INFO_8723B_1ANT_A2DP_BASIC_RATE(_BT_INFO_EXT_)	\ +		(((_BT_INFO_EXT_&BIT(0))) ? true : false) + +#define	BTC_RSSI_COEX_THRESH_TOL_8723B_1ANT		2 + +enum BT_INFO_SRC_8723B_1ANT { +	BT_INFO_SRC_8723B_1ANT_WIFI_FW			= 0x0, +	BT_INFO_SRC_8723B_1ANT_BT_RSP			= 0x1, +	BT_INFO_SRC_8723B_1ANT_BT_ACTIVE_SEND		= 0x2, +	BT_INFO_SRC_8723B_1ANT_MAX +}; + +enum BT_8723B_1ANT_BT_STATUS { +	BT_8723B_1ANT_BT_STATUS_NON_CONNECTED_IDLE	= 0x0, +	BT_8723B_1ANT_BT_STATUS_CONNECTED_IDLE		= 0x1, +	BT_8723B_1ANT_BT_STATUS_INQ_PAGE		= 0x2, +	BT_8723B_1ANT_BT_STATUS_ACL_BUSY		= 0x3, +	BT_8723B_1ANT_BT_STATUS_SCO_BUSY		= 0x4, +	BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY		= 0x5, +	BT_8723B_1ANT_BT_STATUS_MAX +}; + +enum BT_8723B_1ANT_WIFI_STATUS { +	BT_8723B_1ANT_WIFI_STATUS_NON_CONNECTED_IDLE			= 0x0, +	BT_8723B_1ANT_WIFI_STATUS_NON_CONNECTED_ASSO_AUTH_SCAN		= 0x1, +	BT_8723B_1ANT_WIFI_STATUS_CONNECTED_SCAN			= 0x2, +	BT_8723B_1ANT_WIFI_STATUS_CONNECTED_SPECIAL_PKT			= 0x3, +	BT_8723B_1ANT_WIFI_STATUS_CONNECTED_IDLE			= 0x4, +	BT_8723B_1ANT_WIFI_STATUS_CONNECTED_BUSY			= 0x5, +	BT_8723B_1ANT_WIFI_STATUS_MAX +}; + +enum BT_8723B_1ANT_COEX_ALGO { +	BT_8723B_1ANT_COEX_ALGO_UNDEFINED		= 0x0, +	BT_8723B_1ANT_COEX_ALGO_SCO			= 0x1, +	BT_8723B_1ANT_COEX_ALGO_HID			= 0x2, +	BT_8723B_1ANT_COEX_ALGO_A2DP			= 0x3, +	BT_8723B_1ANT_COEX_ALGO_A2DP_PANHS		= 0x4, +	BT_8723B_1ANT_COEX_ALGO_PANEDR			= 0x5, +	BT_8723B_1ANT_COEX_ALGO_PANHS			= 0x6, +	BT_8723B_1ANT_COEX_ALGO_PANEDR_A2DP		= 0x7, +	BT_8723B_1ANT_COEX_ALGO_PANEDR_HID		= 0x8, +	BT_8723B_1ANT_COEX_ALGO_HID_A2DP_PANEDR		= 0x9, +	BT_8723B_1ANT_COEX_ALGO_HID_A2DP		= 0xa, +	BT_8723B_1ANT_COEX_ALGO_MAX			= 0xb, +}; + +struct coex_dm_8723b_1ant { +	/* fw mechanism */ +	bool cur_ignore_wlan_act; +	bool pre_ignore_wlan_act; +	u8 pre_ps_tdma; +	u8 cur_ps_tdma; +	u8 ps_tdma_para[5]; +	u8 ps_tdma_du_adj_type; +	bool auto_tdma_adjust; +	bool pre_ps_tdma_on; +	bool cur_ps_tdma_on; +	bool pre_bt_auto_report; +	bool cur_bt_auto_report; +	u8 pre_lps; +	u8 cur_lps; +	u8 pre_rpwm; +	u8 cur_rpwm; + +	/* sw mechanism */ +	bool pre_low_penalty_ra; +	bool cur_low_penalty_ra; +	u32 pre_val0x6c0; +	u32 cur_val0x6c0; +	u32 pre_val0x6c4; +	u32 cur_val0x6c4; +	u32 pre_val0x6c8; +	u32 cur_val0x6c8; +	u8 pre_val0x6cc; +	u8 cur_val0x6cc; +	bool limited_dig; + +	u32 backup_arfr_cnt1;	/* Auto Rate Fallback Retry cnt */ +	u32 backup_arfr_cnt2;	/* Auto Rate Fallback Retry cnt */ +	u16 backup_retry_limit; +	u8 backup_ampdu_max_time; + +	/* algorithm related */ +	u8 pre_algorithm; +	u8 cur_algorithm; +	u8 bt_status; +	u8 wifi_chnl_info[3]; + +	u32 prera_mask; +	u32 curra_mask; +	u8 pre_arfr_type; +	u8 cur_arfr_type; +	u8 pre_retry_limit_type; +	u8 cur_retry_limit_type; +	u8 pre_ampdu_time_type; +	u8 cur_ampdu_time_type; + +	u8 error_condition; +}; + +struct coex_sta_8723b_1ant { +	bool bt_link_exist; +	bool sco_exist; +	bool a2dp_exist; +	bool hid_exist; +	bool pan_exist; + +	bool under_lps; +	bool under_ips; +	u32 special_pkt_period_cnt; +	u32 high_priority_tx; +	u32 high_priority_rx; +	u32 low_priority_tx; +	u32 low_priority_rx; +	u8 bt_rssi; +	u8 pre_bt_rssi_state; +	u8 pre_wifi_rssi_state[4]; +	bool c2h_bt_info_req_sent; +	u8 bt_info_c2h[BT_INFO_SRC_8723B_1ANT_MAX][10]; +	u32 bt_info_c2h_cnt[BT_INFO_SRC_8723B_1ANT_MAX]; +	bool c2h_bt_inquiry_page; +	u8 bt_retry_cnt; +	u8 bt_info_ext; +}; + +/************************************************************************* + * The following is interface which will notify coex module. + *************************************************************************/ +void ex_halbtc8723b1ant_init_hwconfig(struct btc_coexist *btcoexist); +void ex_halbtc8723b1ant_init_coex_dm(struct btc_coexist *btcoexist); +void ex_halbtc8723b1ant_ips_notify(struct btc_coexist *btcoexist, u8 type); +void ex_halbtc8723b1ant_lps_notify(struct btc_coexist *btcoexist, u8 type); +void ex_halbtc8723b1ant_scan_notify(struct btc_coexist *btcoexist, u8 type); +void ex_halbtc8723b1ant_connect_notify(struct btc_coexist *btcoexist, u8 type); +void ex_halbtc8723b1ant_media_status_notify(struct btc_coexist *btcoexist, +					    u8 type); +void ex_halbtc8723b1ant_special_packet_notify(struct btc_coexist *btcoexist, +					      u8 type); +void ex_halbtc8723b1ant_bt_info_notify(struct btc_coexist *btcoexist, +				       u8 *tmpbuf, u8 length); +void ex_halbtc8723b1ant_halt_notify(struct btc_coexist *btcoexist); +void ex_halbtc8723b1ant_pnp_notify(struct btc_coexist *btcoexist, u8 state); +void ex_halbtc8723b1ant_coex_dm_reset(struct btc_coexist *btcoexist); +void ex_halbtc8723b1ant_periodical(struct btc_coexist *btcoexist); +void ex_halbtc8723b1ant_display_coex_info(struct btc_coexist *btcoexist); diff --git a/drivers/staging/rtl8192ee/btcoexist/halbtc8723b2ant.c b/drivers/staging/rtl8192ee/btcoexist/halbtc8723b2ant.c new file mode 100644 index 00000000000..836206357e6 --- /dev/null +++ b/drivers/staging/rtl8192ee/btcoexist/halbtc8723b2ant.c @@ -0,0 +1,3929 @@ +/*************************************************************** + * Description: + * + * This file is for RTL8723B Co-exist mechanism + * + * History + * 2012/11/15 Cosa first check in. + * + **************************************************************/ +/************************************************************** + * include files + **************************************************************/ +#include "halbt_precomp.h" +/************************************************************** + * Global variables, these are static variables + **************************************************************/ +static struct coex_dm_8723b_2ant glcoex_dm_8723b_2ant; +static struct coex_dm_8723b_2ant *coex_dm = &glcoex_dm_8723b_2ant; +static struct coex_sta_8723b_2ant glcoex_sta_8723b_2ant; +static struct coex_sta_8723b_2ant *coex_sta = &glcoex_sta_8723b_2ant; + +static const char *const glbt_info_src_8723b_2ant[] = { +	"BT Info[wifi fw]", +	"BT Info[bt rsp]", +	"BT Info[bt auto report]", +}; + +static u32 glcoex_ver_date_8723b_2ant = 20131113; +static u32 glcoex_ver_8723b_2ant = 0x3f; + +/************************************************************** + * local function proto type if needed + **************************************************************/ +/************************************************************** + * local function start with halbtc8723b2ant_ + **************************************************************/ +static u8 halbtc8723b2ant_bt_rssi_state(u8 level_num, u8 rssi_thresh, +					u8 rssi_thresh1) +{ +	s32 bt_rssi = 0; +	u8 bt_rssi_state = coex_sta->pre_bt_rssi_state; + +	bt_rssi = coex_sta->bt_rssi; + +	if (level_num == 2) { +		if ((coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_LOW) || +		    (coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_STAY_LOW)) { +			if (bt_rssi >= rssi_thresh + +				       BTC_RSSI_COEX_THRESH_TOL_8723B_2ANT) { +				bt_rssi_state = BTC_RSSI_STATE_HIGH; +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, +					  "[BTCoex], BT Rssi state switch to High\n"); +			} else { +				bt_rssi_state = BTC_RSSI_STATE_STAY_LOW; +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, +					  "[BTCoex], BT Rssi state stay at Low\n"); +			} +		} else { +			if (bt_rssi < rssi_thresh) { +				bt_rssi_state = BTC_RSSI_STATE_LOW; +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, +					  "[BTCoex], BT Rssi state switch to Low\n"); +			} else { +				bt_rssi_state = BTC_RSSI_STATE_STAY_HIGH; +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, +					  "[BTCoex], BT Rssi state stay at High\n"); +			} +		} +	} else if (level_num == 3) { +		if (rssi_thresh > rssi_thresh1) { +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, +				  "[BTCoex], BT Rssi thresh error!!\n"); +			return coex_sta->pre_bt_rssi_state; +		} + +		if ((coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_LOW) || +		    (coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_STAY_LOW)) { +			if (bt_rssi >= rssi_thresh + +				       BTC_RSSI_COEX_THRESH_TOL_8723B_2ANT) { +				bt_rssi_state = BTC_RSSI_STATE_MEDIUM; +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, +					  "[BTCoex], BT Rssi state switch to Medium\n"); +			} else { +				bt_rssi_state = BTC_RSSI_STATE_STAY_LOW; +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, +					  "[BTCoex], BT Rssi state stay at Low\n"); +			} +		} else if ((coex_sta->pre_bt_rssi_state == +						BTC_RSSI_STATE_MEDIUM) || +			   (coex_sta->pre_bt_rssi_state == +						BTC_RSSI_STATE_STAY_MEDIUM)) { +			if (bt_rssi >= rssi_thresh1 + +				       BTC_RSSI_COEX_THRESH_TOL_8723B_2ANT) { +				bt_rssi_state = BTC_RSSI_STATE_HIGH; +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, +					  "[BTCoex], BT Rssi state switch to High\n"); +			} else if (bt_rssi < rssi_thresh) { +				bt_rssi_state = BTC_RSSI_STATE_LOW; +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, +					  "[BTCoex], BT Rssi state switch to Low\n"); +			} else { +				bt_rssi_state = BTC_RSSI_STATE_STAY_MEDIUM; +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, +					  "[BTCoex], BT Rssi state stay at Medium\n"); +			} +		} else { +			if (bt_rssi < rssi_thresh1) { +				bt_rssi_state = BTC_RSSI_STATE_MEDIUM; +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, +					  "[BTCoex], BT Rssi state switch to Medium\n"); +			} else { +				bt_rssi_state = BTC_RSSI_STATE_STAY_HIGH; +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, +					  "[BTCoex], BT Rssi state stay at High\n"); +			} +		} +	} + +	coex_sta->pre_bt_rssi_state = bt_rssi_state; + +	return bt_rssi_state; +} + +static u8 halbtc8723b2ant_wifi_rssi_state(struct btc_coexist *btcoexist, +					  u8 index, u8 level_num, +					  u8 rssi_thresh, u8 rssi_thresh1) +{ +	s32 wifi_rssi = 0; +	u8 wifi_rssi_state = coex_sta->pre_wifi_rssi_state[index]; + +	btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifi_rssi); + +	if (level_num == 2) { +		if ((coex_sta->pre_wifi_rssi_state[index] == +						BTC_RSSI_STATE_LOW) || +		    (coex_sta->pre_wifi_rssi_state[index] == +						BTC_RSSI_STATE_STAY_LOW)) { +			if (wifi_rssi >= rssi_thresh + +					 BTC_RSSI_COEX_THRESH_TOL_8723B_2ANT) { +				wifi_rssi_state = BTC_RSSI_STATE_HIGH; +				BTC_PRINT(BTC_MSG_ALGORITHM, +					  ALGO_WIFI_RSSI_STATE, +					  "[BTCoex], wifi RSSI state switch to High\n"); +			} else { +				wifi_rssi_state = BTC_RSSI_STATE_STAY_LOW; +				BTC_PRINT(BTC_MSG_ALGORITHM, +					  ALGO_WIFI_RSSI_STATE, +					  "[BTCoex], wifi RSSI state stay at Low\n"); +			} +		} else { +			if (wifi_rssi < rssi_thresh) { +				wifi_rssi_state = BTC_RSSI_STATE_LOW; +				BTC_PRINT(BTC_MSG_ALGORITHM, +					  ALGO_WIFI_RSSI_STATE, +					  "[BTCoex], wifi RSSI state switch to Low\n"); +			} else { +				wifi_rssi_state = BTC_RSSI_STATE_STAY_HIGH; +				BTC_PRINT(BTC_MSG_ALGORITHM, +					  ALGO_WIFI_RSSI_STATE, +					  "[BTCoex], wifi RSSI state stay at High\n"); +			} +		} +	} else if (level_num == 3) { +		if (rssi_thresh > rssi_thresh1) { +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, +				  "[BTCoex], wifi RSSI thresh error!!\n"); +			return coex_sta->pre_wifi_rssi_state[index]; +		} + +		if ((coex_sta->pre_wifi_rssi_state[index] == +						BTC_RSSI_STATE_LOW) || +		    (coex_sta->pre_wifi_rssi_state[index] == +						BTC_RSSI_STATE_STAY_LOW)) { +			if (wifi_rssi >= rssi_thresh + +					BTC_RSSI_COEX_THRESH_TOL_8723B_2ANT) { +				wifi_rssi_state = BTC_RSSI_STATE_MEDIUM; +				BTC_PRINT(BTC_MSG_ALGORITHM, +					  ALGO_WIFI_RSSI_STATE, +					  "[BTCoex], wifi RSSI state switch to Medium\n"); +			} else { +				wifi_rssi_state = BTC_RSSI_STATE_STAY_LOW; +				BTC_PRINT(BTC_MSG_ALGORITHM, +					  ALGO_WIFI_RSSI_STATE, +					  "[BTCoex], wifi RSSI state stay at Low\n"); +			} +		} else if ((coex_sta->pre_wifi_rssi_state[index] == +						BTC_RSSI_STATE_MEDIUM) || +			   (coex_sta->pre_wifi_rssi_state[index] == +						BTC_RSSI_STATE_STAY_MEDIUM)) { +			if (wifi_rssi >= rssi_thresh1 + +					 BTC_RSSI_COEX_THRESH_TOL_8723B_2ANT) { +				wifi_rssi_state = BTC_RSSI_STATE_HIGH; +				BTC_PRINT(BTC_MSG_ALGORITHM, +					  ALGO_WIFI_RSSI_STATE, +					  "[BTCoex], wifi RSSI state switch to High\n"); +			} else if (wifi_rssi < rssi_thresh) { +				wifi_rssi_state = BTC_RSSI_STATE_LOW; +				BTC_PRINT(BTC_MSG_ALGORITHM, +					  ALGO_WIFI_RSSI_STATE, +					  "[BTCoex], wifi RSSI state switch to Low\n"); +			} else { +				wifi_rssi_state = BTC_RSSI_STATE_STAY_MEDIUM; +				BTC_PRINT(BTC_MSG_ALGORITHM, +					  ALGO_WIFI_RSSI_STATE, +					  "[BTCoex], wifi RSSI state stay at Medium\n"); +			} +		} else { +			if (wifi_rssi < rssi_thresh1) { +				wifi_rssi_state = BTC_RSSI_STATE_MEDIUM; +				BTC_PRINT(BTC_MSG_ALGORITHM, +					  ALGO_WIFI_RSSI_STATE, +					  "[BTCoex], wifi RSSI state switch to Medium\n"); +			} else { +				wifi_rssi_state = BTC_RSSI_STATE_STAY_HIGH; +				BTC_PRINT(BTC_MSG_ALGORITHM, +					  ALGO_WIFI_RSSI_STATE, +					  "[BTCoex], wifi RSSI state stay at High\n"); +			} +		} +	} + +	coex_sta->pre_wifi_rssi_state[index] = wifi_rssi_state; + +	return wifi_rssi_state; +} + +static void halbtc8723b2ant_monitor_bt_ctr(struct btc_coexist *btcoexist) +{ +	u32 reg_hp_txrx, reg_lp_txrx, u32tmp; +	u32 reg_hp_tx = 0, reg_hp_rx = 0; +	u32 reg_lp_tx = 0, reg_lp_rx = 0; + +	reg_hp_txrx = 0x770; +	reg_lp_txrx = 0x774; + +	u32tmp = btcoexist->btc_read_4byte(btcoexist, reg_hp_txrx); +	reg_hp_tx = u32tmp & MASKLWORD; +	reg_hp_rx = (u32tmp & MASKHWORD) >> 16; + +	u32tmp = btcoexist->btc_read_4byte(btcoexist, reg_lp_txrx); +	reg_lp_tx = u32tmp & MASKLWORD; +	reg_lp_rx = (u32tmp & MASKHWORD) >> 16; + +	coex_sta->high_priority_tx = reg_hp_tx; +	coex_sta->high_priority_rx = reg_hp_rx; +	coex_sta->low_priority_tx = reg_lp_tx; +	coex_sta->low_priority_rx = reg_lp_rx; + +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, +		  "[BTCoex], High Priority Tx/Rx(reg 0x%x) = 0x%x(%d)/0x%x(%d)\n", +		  reg_hp_txrx, reg_hp_tx, reg_hp_tx, reg_hp_rx, reg_hp_rx); +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, +		  "[BTCoex], Low Priority Tx/Rx(reg 0x%x) = 0x%x(%d)/0x%x(%d)\n", +		  reg_lp_txrx, reg_lp_tx, reg_lp_tx, reg_lp_rx, reg_lp_rx); + +	/* reset counter */ +	btcoexist->btc_write_1byte(btcoexist, 0x76e, 0xc); +} + +static void halbtc8723b2ant_query_bt_info(struct btc_coexist *btcoexist) +{ +	u8 h2c_parameter[1] = {0}; + +	coex_sta->c2h_bt_info_req_sent = true; + +	h2c_parameter[0] |= BIT(0);	/* trigger */ + +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, +		  "[BTCoex], Query Bt Info, FW write 0x61 = 0x%x\n", +		  h2c_parameter[0]); + +	btcoexist->btc_fill_h2c(btcoexist, 0x61, 1, h2c_parameter); +} + +static bool is_wifi_status_changed(struct btc_coexist *btcoexist) +{ +	static bool pre_wifi_busy; +	static bool pre_under_4way; +	static bool pre_bt_hs_on; +	bool wifi_busy = false, under_4way = false, bt_hs_on = false; +	bool wifi_connected = false; + +	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, +			   &wifi_connected); +	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); +	btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); +	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS, +			   &under_4way); + +	if (wifi_connected) { +		if (wifi_busy != pre_wifi_busy) { +			pre_wifi_busy = wifi_busy; +			return true; +		} + +		if (under_4way != pre_under_4way) { +			pre_under_4way = under_4way; +			return true; +		} + +		if (bt_hs_on != pre_bt_hs_on) { +			pre_bt_hs_on = bt_hs_on; +			return true; +		} +	} + +	return false; +} + +static void halbtc8723b2ant_update_bt_link_info(struct btc_coexist *btcoexist) +{ +	/*struct btc_stack_info *stack_info = &btcoexist->stack_info;*/ +	struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; +	bool bt_hs_on = false; + +#if (BT_AUTO_REPORT_ONLY_8723B_2ANT == 1) /* profile from bt patch */ +	btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + +	bt_link_info->bt_link_exist = coex_sta->bt_link_exist; +	bt_link_info->sco_exist = coex_sta->sco_exist; +	bt_link_info->a2dp_exist = coex_sta->a2dp_exist; +	bt_link_info->pan_exist = coex_sta->pan_exist; +	bt_link_info->hid_exist = coex_sta->hid_exist; + +	/* work around for HS mode. */ +	if (bt_hs_on) { +		bt_link_info->pan_exist = true; +		bt_link_info->bt_link_exist = true; +	} +#else	/* profile from bt stack */ +	bt_link_info->bt_link_exist = stack_info->bt_link_exist; +	bt_link_info->sco_exist = stack_info->sco_exist; +	bt_link_info->a2dp_exist = stack_info->a2dp_exist; +	bt_link_info->pan_exist = stack_info->pan_exist; +	bt_link_info->hid_exist = stack_info->hid_exist; + +	/*for win-8 stack HID report error*/ +	if (!stack_info->hid_exist) +		stack_info->hid_exist = coex_sta->hid_exist; +	/*sync  BTInfo with BT firmware and stack*/ +	/* when stack HID report error, here we use the info from bt fw.*/ +	if (!stack_info->bt_link_exist) +		stack_info->bt_link_exist = coex_sta->bt_link_exist; +#endif +	/* check if Sco only */ +	if (bt_link_info->sco_exist && !bt_link_info->a2dp_exist && +	    !bt_link_info->pan_exist && !bt_link_info->hid_exist) +		bt_link_info->sco_only = true; +	else +		bt_link_info->sco_only = false; + +	/* check if A2dp only */ +	if (!bt_link_info->sco_exist && bt_link_info->a2dp_exist && +	    !bt_link_info->pan_exist && !bt_link_info->hid_exist) +		bt_link_info->a2dp_only = true; +	else +		bt_link_info->a2dp_only = false; + +	/* check if Pan only */ +	if (!bt_link_info->sco_exist && !bt_link_info->a2dp_exist && +	    bt_link_info->pan_exist && !bt_link_info->hid_exist) +		bt_link_info->pan_only = true; +	else +		bt_link_info->pan_only = false; + +	/* check if Hid only */ +	if (!bt_link_info->sco_exist && !bt_link_info->a2dp_exist && +	    !bt_link_info->pan_exist && bt_link_info->hid_exist) +		bt_link_info->hid_only = true; +	else +		bt_link_info->hid_only = false; +} + +static u8 halbtc8723b2ant_action_algorithm(struct btc_coexist *btcoexist) +{ +	struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; +	bool bt_hs_on = false; +	u8 algorithm = BT_8723B_2ANT_COEX_ALGO_UNDEFINED; +	u8 num_of_diff_profile = 0; + +	btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + +	if (!bt_link_info->bt_link_exist) { +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +			  "[BTCoex], No BT link exists!!!\n"); +		return algorithm; +	} + +	if (bt_link_info->sco_exist) +		num_of_diff_profile++; +	if (bt_link_info->hid_exist) +		num_of_diff_profile++; +	if (bt_link_info->pan_exist) +		num_of_diff_profile++; +	if (bt_link_info->a2dp_exist) +		num_of_diff_profile++; + +	if (num_of_diff_profile == 1) { +		if (bt_link_info->sco_exist) { +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +				  "[BTCoex], SCO only\n"); +			algorithm = BT_8723B_2ANT_COEX_ALGO_SCO; +		} else { +			if (bt_link_info->hid_exist) { +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +					  "[BTCoex], HID only\n"); +				algorithm = BT_8723B_2ANT_COEX_ALGO_HID; +			} else if (bt_link_info->a2dp_exist) { +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +					  "[BTCoex], A2DP only\n"); +				algorithm = BT_8723B_2ANT_COEX_ALGO_A2DP; +			} else if (bt_link_info->pan_exist) { +				if (bt_hs_on) { +					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +						  "[BTCoex], PAN(HS) only\n"); +					algorithm = +						BT_8723B_2ANT_COEX_ALGO_PANHS; +				} else { +					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +						  "[BTCoex], PAN(EDR) only\n"); +					algorithm = +						BT_8723B_2ANT_COEX_ALGO_PANEDR; +				} +			} +		} +	} else if (num_of_diff_profile == 2) { +		if (bt_link_info->sco_exist) { +			if (bt_link_info->hid_exist) { +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +					  "[BTCoex], SCO + HID\n"); +				algorithm = BT_8723B_2ANT_COEX_ALGO_PANEDR_HID; +			} else if (bt_link_info->a2dp_exist) { +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +					  "[BTCoex], SCO + A2DP ==> SCO\n"); +				algorithm = BT_8723B_2ANT_COEX_ALGO_PANEDR_HID; +			} else if (bt_link_info->pan_exist) { +				if (bt_hs_on) { +					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +						  "[BTCoex], SCO + PAN(HS)\n"); +					algorithm = BT_8723B_2ANT_COEX_ALGO_SCO; +				} else { +					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +						  "[BTCoex], SCO + PAN(EDR)\n"); +					algorithm = +					    BT_8723B_2ANT_COEX_ALGO_PANEDR_HID; +				} +			} +		} else { +			if (bt_link_info->hid_exist && +			    bt_link_info->a2dp_exist) { +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +					  "[BTCoex], HID + A2DP\n"); +				algorithm = BT_8723B_2ANT_COEX_ALGO_HID_A2DP; +			} else if (bt_link_info->hid_exist && +				   bt_link_info->pan_exist) { +				if (bt_hs_on) { +					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +						  "[BTCoex], HID + PAN(HS)\n"); +					algorithm = BT_8723B_2ANT_COEX_ALGO_HID; +				} else { +					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +						  "[BTCoex], HID + PAN(EDR)\n"); +					algorithm = +					    BT_8723B_2ANT_COEX_ALGO_PANEDR_HID; +				} +			} else if (bt_link_info->pan_exist && +				   bt_link_info->a2dp_exist) { +				if (bt_hs_on) { +					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +						  "[BTCoex], A2DP + PAN(HS)\n"); +					algorithm = +					    BT_8723B_2ANT_COEX_ALGO_A2DP_PANHS; +				} else { +					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +						  "[BTCoex], A2DP + PAN(EDR)\n"); +					algorithm = +					    BT_8723B_2ANT_COEX_ALGO_PANEDR_A2DP; +				} +			} +		} +	} else if (num_of_diff_profile == 3) { +		if (bt_link_info->sco_exist) { +			if (bt_link_info->hid_exist && +			    bt_link_info->a2dp_exist) { +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +					  "[BTCoex], SCO + HID + A2DP ==> HID\n"); +				algorithm = BT_8723B_2ANT_COEX_ALGO_PANEDR_HID; +			} else if (bt_link_info->hid_exist && +				   bt_link_info->pan_exist) { +				if (bt_hs_on) { +					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +						  "[BTCoex], SCO + HID + PAN(HS)\n"); +					algorithm = +					    BT_8723B_2ANT_COEX_ALGO_PANEDR_HID; +				} else { +					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +						  "[BTCoex], SCO + HID + PAN(EDR)\n"); +					algorithm = +					    BT_8723B_2ANT_COEX_ALGO_PANEDR_HID; +				} +			} else if (bt_link_info->pan_exist && +				   bt_link_info->a2dp_exist) { +				if (bt_hs_on) { +					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +						  "[BTCoex], SCO + A2DP + PAN(HS)\n"); +					algorithm = +					    BT_8723B_2ANT_COEX_ALGO_PANEDR_HID; +				} else { +					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +						  "[BTCoex], SCO + A2DP + PAN(EDR) ==> HID\n"); +					algorithm = +					    BT_8723B_2ANT_COEX_ALGO_PANEDR_HID; +				} +			} +		} else { +			if (bt_link_info->hid_exist && +			    bt_link_info->pan_exist && +			    bt_link_info->a2dp_exist) { +				if (bt_hs_on) { +					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +						  "[BTCoex], HID + A2DP + PAN(HS)\n"); +					algorithm = +					    BT_8723B_2ANT_COEX_ALGO_HID_A2DP; +				} else { +					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +						  "[BTCoex], HID + A2DP + PAN(EDR)\n"); +					algorithm = +					BT_8723B_2ANT_COEX_ALGO_HID_A2DP_PANEDR; +				} +			} +		} +	} else if (num_of_diff_profile >= 3) { +		if (bt_link_info->sco_exist) { +			if (bt_link_info->hid_exist && +			    bt_link_info->pan_exist && +			    bt_link_info->a2dp_exist) { +				if (bt_hs_on) { +					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +						  "[BTCoex], Error!!! SCO + HID + A2DP + PAN(HS)\n"); +				} else { +					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +						  "[BTCoex], SCO + HID + A2DP + PAN(EDR) ==>PAN(EDR)+HID\n"); +					algorithm = +					    BT_8723B_2ANT_COEX_ALGO_PANEDR_HID; +				} +			} +		} +	} + +	return algorithm; +} + +static bool halbtc8723b2ant_need_to_dec_bt_pwr(struct btc_coexist *btcoexist) +{ +	bool ret = false; +	bool bt_hs_on = false, wifi_connected = false; +	s32 bt_hs_rssi = 0; +	u8 bt_rssi_state; + +	if (!btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, +				&bt_hs_on)) +		return false; +	if (!btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, +				&wifi_connected)) +		return false; +	if (!btcoexist->btc_get(btcoexist, BTC_GET_S4_HS_RSSI, +				&bt_hs_rssi)) +		return false; + +	bt_rssi_state = halbtc8723b2ant_bt_rssi_state(2, 29, 0); + +	if (wifi_connected) { +		if (bt_hs_on) { +			if (bt_hs_rssi > 37) { +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, +					  "[BTCoex], Need to decrease bt power for HS mode!!\n"); +				ret = true; +			} +		} else { +			if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || +			    (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, +					  "[BTCoex], Need to decrease bt power for Wifi is connected!!\n"); +				ret = true; +			} +		} +	} + +	return ret; +} + +static void set_fw_dac_swing_level(struct btc_coexist *btcoexist, +				   u8 dac_swing_lvl) +{ +	u8 h2c_parameter[1] = {0}; + +	/* There are several type of dacswing +	 * 0x18/ 0x10/ 0xc/ 0x8/ 0x4/ 0x6 */ +	h2c_parameter[0] = dac_swing_lvl; + +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, +		  "[BTCoex], Set Dac Swing Level = 0x%x\n", dac_swing_lvl); +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, +		  "[BTCoex], FW write 0x64 = 0x%x\n", h2c_parameter[0]); + +	btcoexist->btc_fill_h2c(btcoexist, 0x64, 1, h2c_parameter); +} + +static void halbtc8723b2ant_set_fw_dec_bt_pwr(struct btc_coexist *btcoexist, +					      bool dec_bt_pwr) +{ +	u8 h2c_parameter[1] = {0}; + +	h2c_parameter[0] = 0; + +	if (dec_bt_pwr) +		h2c_parameter[0] |= BIT(1); + +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, +		  "[BTCoex], decrease Bt Power : %s, FW write 0x62 = 0x%x\n", +		  (dec_bt_pwr ? "Yes!!" : "No!!"), h2c_parameter[0]); + +	btcoexist->btc_fill_h2c(btcoexist, 0x62, 1, h2c_parameter); +} + +static void halbtc8723b2ant_dec_bt_pwr(struct btc_coexist *btcoexist, +				       bool force_exec, bool dec_bt_pwr) +{ +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, +		  "[BTCoex], %s Dec BT power = %s\n", +		  (force_exec ? "force to" : ""), (dec_bt_pwr ? "ON" : "OFF")); +	coex_dm->cur_dec_bt_pwr = dec_bt_pwr; + +	if (!force_exec) { +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, +			  "[BTCoex], bPreDecBtPwr =%d, bCurDecBtPwr =%d\n", +			  coex_dm->pre_dec_bt_pwr, coex_dm->cur_dec_bt_pwr); + +		if (coex_dm->pre_dec_bt_pwr == coex_dm->cur_dec_bt_pwr) +			return; +	} +	halbtc8723b2ant_set_fw_dec_bt_pwr(btcoexist, coex_dm->cur_dec_bt_pwr); + +	coex_dm->pre_dec_bt_pwr = coex_dm->cur_dec_bt_pwr; +} + +static void halbtc8723b2ant_fw_dac_swing_lvl(struct btc_coexist *btcoexist, +					     bool force_exec, +					     u8 fw_dac_swing_lvl) +{ +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, +		  "[BTCoex], %s set FW Dac Swing level = %d\n", +		  (force_exec ? "force to" : ""), fw_dac_swing_lvl); +	coex_dm->cur_fw_dac_swing_lvl = fw_dac_swing_lvl; + +	if (!force_exec) { +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, +			  "[BTCoex], preFwDacSwingLvl =%d, curFwDacSwingLvl =%d\n", +			  coex_dm->pre_fw_dac_swing_lvl, +			  coex_dm->cur_fw_dac_swing_lvl); + +		if (coex_dm->pre_fw_dac_swing_lvl == +		   coex_dm->cur_fw_dac_swing_lvl) +			return; +	} + +	set_fw_dac_swing_level(btcoexist, coex_dm->cur_fw_dac_swing_lvl); +	coex_dm->pre_fw_dac_swing_lvl = coex_dm->cur_fw_dac_swing_lvl; +} + +static void set_sw_rf_rx_lpf_corner(struct btc_coexist *btcoexist, +				    bool rx_rf_shrink_on) +{ +	if (rx_rf_shrink_on) { +		/* Shrink RF Rx LPF corner */ +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, +			  "[BTCoex], Shrink RF Rx LPF corner!!\n"); +		btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1e, +					  0xfffff, 0xffffc); +	} else { +		/* Resume RF Rx LPF corner */ +		/* After initialized, we can use coex_dm->btRf0x1eBackup */ +		if (btcoexist->initilized) { +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, +				  "[BTCoex], Resume RF Rx LPF corner!!\n"); +			btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1e, +						  0xfffff, +						  coex_dm->bt_rf0x1e_backup); +		} +	} +} + +static void halbtc8723b2ant_rf_shrink(struct btc_coexist *btcoexist, +				      bool force_exec, bool rx_rf_shrink_on) +{ +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, +		  "[BTCoex], %s turn Rx RF Shrink = %s\n", +		  (force_exec ? "force to" : ""), +		  (rx_rf_shrink_on ? "ON" : "OFF")); +	coex_dm->cur_rf_rx_lpf_shrink = rx_rf_shrink_on; + +	if (!force_exec) { +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, +			  "[BTCoex], bPreRfRxLpfShrink =%d, bCurRfRxLpfShrink =%d\n", +			  coex_dm->pre_rf_rx_lpf_shrink, +			  coex_dm->cur_rf_rx_lpf_shrink); + +		if (coex_dm->pre_rf_rx_lpf_shrink == +		    coex_dm->cur_rf_rx_lpf_shrink) +			return; +	} +	set_sw_rf_rx_lpf_corner(btcoexist, coex_dm->cur_rf_rx_lpf_shrink); + +	coex_dm->pre_rf_rx_lpf_shrink = coex_dm->cur_rf_rx_lpf_shrink; +} + +static void set_sw_penalty_txrate_adaptive( +						struct btc_coexist *btcoexist, +						bool low_penalty_ra) +{ +	u8 h2c_parameter[6] = {0}; + +	h2c_parameter[0] = 0x6;	/* opCode, 0x6 = Retry_Penalty*/ + +	if (low_penalty_ra) { +		h2c_parameter[1] |= BIT(0); +		/*normal rate except MCS7/6/5, OFDM54/48/36*/ +		h2c_parameter[2] = 0x00; +		h2c_parameter[3] = 0xf7;  /*MCS7 or OFDM54*/ +		h2c_parameter[4] = 0xf8;  /*MCS6 or OFDM48*/ +		h2c_parameter[5] = 0xf9;  /*MCS5 or OFDM36*/ +	} + +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, +		  "[BTCoex], set WiFi Low-Penalty Retry: %s", +		  (low_penalty_ra ? "ON!!" : "OFF!!")); + +	btcoexist->btc_fill_h2c(btcoexist, 0x69, 6, h2c_parameter); +} + +static void halbtc8723b2ant_low_penalty_ra(struct btc_coexist *btcoexist, +					   bool force_exec, bool low_penalty_ra) +{ +	/*return; */ +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, +		  "[BTCoex], %s turn LowPenaltyRA = %s\n", +		  (force_exec ? "force to" : ""), +		  (low_penalty_ra ? "ON" : "OFF")); +	coex_dm->cur_low_penalty_ra = low_penalty_ra; + +	if (!force_exec) { +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, +			  "[BTCoex], bPreLowPenaltyRa =%d, bCurLowPenaltyRa =%d\n", +			  coex_dm->pre_low_penalty_ra, +			  coex_dm->cur_low_penalty_ra); + +		if (coex_dm->pre_low_penalty_ra == coex_dm->cur_low_penalty_ra) +			return; +	} +	set_sw_penalty_txrate_adaptive(btcoexist, coex_dm->cur_low_penalty_ra); + +	coex_dm->pre_low_penalty_ra = coex_dm->cur_low_penalty_ra; +} + +static void halbtc8723b2ant_set_dac_swing_reg(struct btc_coexist *btcoexist, +					      u32 level) +{ +	u8 val = (u8) level; +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, +		  "[BTCoex], Write SwDacSwing = 0x%x\n", level); +	btcoexist->btc_write_1byte_bitmask(btcoexist, 0x883, 0x3e, val); +} + +static void set_sw_fulltime_dac_swing(struct btc_coexist *btcoexist, +				      bool sw_dac_swing_on, +				      u32 sw_dac_swing_lvl) +{ +	if (sw_dac_swing_on) +		halbtc8723b2ant_set_dac_swing_reg(btcoexist, sw_dac_swing_lvl); +	else +		halbtc8723b2ant_set_dac_swing_reg(btcoexist, 0x18); +} + +static void halbtc8723b2ant_dac_swing(struct btc_coexist *btcoexist, +				      bool force_exec, bool dac_swing_on, +			       u32 dac_swing_lvl) +{ +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, +		  "[BTCoex], %s turn DacSwing =%s, dac_swing_lvl = 0x%x\n", +		  (force_exec ? "force to" : ""), +		  (dac_swing_on ? "ON" : "OFF"), dac_swing_lvl); +	coex_dm->cur_dac_swing_on = dac_swing_on; +	coex_dm->cur_dac_swing_lvl = dac_swing_lvl; + +	if (!force_exec) { +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, +			  "[BTCoex], bPreDacSwingOn =%d, preDacSwingLvl = 0x%x, bCurDacSwingOn =%d, curDacSwingLvl = 0x%x\n", +			  coex_dm->pre_dac_swing_on, coex_dm->pre_dac_swing_lvl, +			  coex_dm->cur_dac_swing_on, +			  coex_dm->cur_dac_swing_lvl); + +		if ((coex_dm->pre_dac_swing_on == coex_dm->cur_dac_swing_on) && +		    (coex_dm->pre_dac_swing_lvl == coex_dm->cur_dac_swing_lvl)) +			return; +	} +	mdelay(30); +	set_sw_fulltime_dac_swing(btcoexist, dac_swing_on, +				  dac_swing_lvl); + +	coex_dm->pre_dac_swing_on = coex_dm->cur_dac_swing_on; +	coex_dm->pre_dac_swing_lvl = coex_dm->cur_dac_swing_lvl; +} + +static void halbtc8723b2ant_set_agc_table(struct btc_coexist *btcoexist, +					  bool agc_table_en) +{ +	u8 rssi_adjust_val = 0; + +	/*  BB AGC Gain Table */ +	if (agc_table_en) { +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, +			  "[BTCoex], BB Agc Table On!\n"); +		btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x6e1A0001); +		btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x6d1B0001); +		btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x6c1C0001); +		btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x6b1D0001); +		btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x6a1E0001); +		btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x691F0001); +		btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x68200001); +	} else { +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, +			  "[BTCoex], BB Agc Table Off!\n"); +		btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xaa1A0001); +		btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xa91B0001); +		btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xa81C0001); +		btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xa71D0001); +		btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xa61E0001); +		btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xa51F0001); +		btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xa4200001); +	} + +	/* RF Gain */ +	btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0xef, 0xfffff, 0x02000); +	if (agc_table_en) { +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, +			  "[BTCoex], Agc Table On!\n"); +		btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x3b, +					  0xfffff, 0x38fff); +		btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x3b, +					  0xfffff, 0x38ffe); +	} else { +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, +			  "[BTCoex], Agc Table Off!\n"); +		btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x3b, +					  0xfffff, 0x380c3); +		btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x3b, +					  0xfffff, 0x28ce6); +	} +	btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0xef, 0xfffff, 0x0); + +	btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0xed, 0xfffff, 0x1); + +	if (agc_table_en) { +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, +			  "[BTCoex], Agc Table On!\n"); +		btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x40, +					  0xfffff, 0x38fff); +		btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x40, +					  0xfffff, 0x38ffe); +	} else { +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, +			  "[BTCoex], Agc Table Off!\n"); +		btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x40, +					  0xfffff, 0x380c3); +		btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x40, +					  0xfffff, 0x28ce6); +	} +	btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0xed, 0xfffff, 0x0); + +	/* set rssiAdjustVal for wifi module. */ +	if (agc_table_en) +		rssi_adjust_val = 8; +	btcoexist->btc_set(btcoexist, BTC_SET_U1_RSSI_ADJ_VAL_FOR_AGC_TABLE_ON, +			   &rssi_adjust_val); +} + +static void halbtc8723b2ant_agc_table(struct btc_coexist *btcoexist, +				      bool force_exec, bool agc_table_en) +{ +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, +		  "[BTCoex], %s %s Agc Table\n", +		  (force_exec ? "force to" : ""), +		  (agc_table_en ? "Enable" : "Disable")); +	coex_dm->cur_agc_table_en = agc_table_en; + +	if (!force_exec) { +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, +			  "[BTCoex], bPreAgcTableEn =%d, bCurAgcTableEn =%d\n", +			  coex_dm->pre_agc_table_en, coex_dm->cur_agc_table_en); + +		if (coex_dm->pre_agc_table_en == coex_dm->cur_agc_table_en) +			return; +	} +	halbtc8723b2ant_set_agc_table(btcoexist, agc_table_en); + +	coex_dm->pre_agc_table_en = coex_dm->cur_agc_table_en; +} + +static void halbtc8723b2ant_set_coex_table(struct btc_coexist *btcoexist, +					   u32 val0x6c0, u32 val0x6c4, +					   u32 val0x6c8, u8 val0x6cc) +{ +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, +		  "[BTCoex], set coex table, set 0x6c0 = 0x%x\n", val0x6c0); +	btcoexist->btc_write_4byte(btcoexist, 0x6c0, val0x6c0); + +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, +		  "[BTCoex], set coex table, set 0x6c4 = 0x%x\n", val0x6c4); +	btcoexist->btc_write_4byte(btcoexist, 0x6c4, val0x6c4); + +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, +		  "[BTCoex], set coex table, set 0x6c8 = 0x%x\n", val0x6c8); +	btcoexist->btc_write_4byte(btcoexist, 0x6c8, val0x6c8); + +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, +		  "[BTCoex], set coex table, set 0x6cc = 0x%x\n", val0x6cc); +	btcoexist->btc_write_1byte(btcoexist, 0x6cc, val0x6cc); +} + +static void halbtc8723b2ant_coex_table(struct btc_coexist *btcoexist, +				       bool force_exec, u32 val0x6c0, +				       u32 val0x6c4, u32 val0x6c8, +				       u8 val0x6cc) +{ +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, +		  "[BTCoex], %s write Coex Table 0x6c0 = 0x%x, 0x6c4 = 0x%x, 0x6c8 = 0x%x, 0x6cc = 0x%x\n", +		  (force_exec ? "force to" : ""), val0x6c0, +		  val0x6c4, val0x6c8, val0x6cc); +	coex_dm->cur_val0x6c0 = val0x6c0; +	coex_dm->cur_val0x6c4 = val0x6c4; +	coex_dm->cur_val0x6c8 = val0x6c8; +	coex_dm->cur_val0x6cc = val0x6cc; + +	if (!force_exec) { +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, +			  "[BTCoex], preVal0x6c0 = 0x%x, preVal0x6c4 = 0x%x, preVal0x6c8 = 0x%x, preVal0x6cc = 0x%x !!\n", +			  coex_dm->pre_val0x6c0, coex_dm->pre_val0x6c4, +			  coex_dm->pre_val0x6c8, coex_dm->pre_val0x6cc); +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, +			  "[BTCoex], curVal0x6c0 = 0x%x, curVal0x6c4 = 0x%x, curVal0x6c8 = 0x%x, curVal0x6cc = 0x%x !!\n", +			  coex_dm->cur_val0x6c0, coex_dm->cur_val0x6c4, +			  coex_dm->cur_val0x6c8, coex_dm->cur_val0x6cc); + +		if ((coex_dm->pre_val0x6c0 == coex_dm->cur_val0x6c0) && +		    (coex_dm->pre_val0x6c4 == coex_dm->cur_val0x6c4) && +		    (coex_dm->pre_val0x6c8 == coex_dm->cur_val0x6c8) && +		    (coex_dm->pre_val0x6cc == coex_dm->cur_val0x6cc)) +			return; +	} +	halbtc8723b2ant_set_coex_table(btcoexist, val0x6c0, val0x6c4, +				       val0x6c8, val0x6cc); + +	coex_dm->pre_val0x6c0 = coex_dm->cur_val0x6c0; +	coex_dm->pre_val0x6c4 = coex_dm->cur_val0x6c4; +	coex_dm->pre_val0x6c8 = coex_dm->cur_val0x6c8; +	coex_dm->pre_val0x6cc = coex_dm->cur_val0x6cc; +} + +static void coex_table_with_type(struct btc_coexist *btcoexist, +						 bool force_exec, u8 type) +{ +	switch (type) { +	case 0: +		halbtc8723b2ant_coex_table(btcoexist, force_exec, 0x55555555, +					   0x55555555, 0xffff, 0x3); +		break; +	case 1: +		halbtc8723b2ant_coex_table(btcoexist, force_exec, 0x55555555, +					   0x5afa5afa, 0xffff, 0x3); +		break; +	case 2: +		halbtc8723b2ant_coex_table(btcoexist, force_exec, 0x5a5a5a5a, +					   0x5a5a5a5a, 0xffff, 0x3); +		break; +	case 3: +		halbtc8723b2ant_coex_table(btcoexist, force_exec, 0xaaaaaaaa, +					   0xaaaaaaaa, 0xffff, 0x3); +		break; +	case 4: +		halbtc8723b2ant_coex_table(btcoexist, force_exec, 0xffffffff, +					   0xffffffff, 0xffff, 0x3); +		break; +	case 5: +		halbtc8723b2ant_coex_table(btcoexist, force_exec, 0x5fff5fff, +					   0x5fff5fff, 0xffff, 0x3); +		break; +	case 6: +		halbtc8723b2ant_coex_table(btcoexist, force_exec, 0x55ff55ff, +					   0x5a5a5a5a, 0xffff, 0x3); +		break; +	case 7: +		halbtc8723b2ant_coex_table(btcoexist, force_exec, 0x55ff55ff, +					   0x5afa5afa, 0xffff, 0x3); +		break; +	case 8: +		halbtc8723b2ant_coex_table(btcoexist, force_exec, 0x5aea5aea, +					   0x5aea5aea, 0xffff, 0x3); +		break; +	case 9: +		halbtc8723b2ant_coex_table(btcoexist, force_exec, 0x55ff55ff, +					   0x5aea5aea, 0xffff, 0x3); +		break; +	case 10: +		halbtc8723b2ant_coex_table(btcoexist, force_exec, 0x55ff55ff, +					   0x5aff5aff, 0xffff, 0x3); +		break; +	case 11: +		halbtc8723b2ant_coex_table(btcoexist, force_exec, 0x55ff55ff, +					   0x5a5f5a5f, 0xffff, 0x3); +		break; +	case 12: +		halbtc8723b2ant_coex_table(btcoexist, force_exec, 0x55ff55ff, +					   0x5f5f5f5f, 0xffff, 0x3); +		break; +	default: +		break; +	} +} + +static void set_fw_ignore_wlan_act(struct btc_coexist *btcoexist, +				   bool enable) +{ +	u8 h2c_parameter[1] = {0}; + +	if (enable) +		h2c_parameter[0] |= BIT(0);/* function enable*/ + +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, +		  "[BTCoex], set FW for BT Ignore Wlan_Act, FW write 0x63 = 0x%x\n", +		  h2c_parameter[0]); + +	btcoexist->btc_fill_h2c(btcoexist, 0x63, 1, h2c_parameter); +} + +static void halbtc8723b2ant_ignore_wlan_act(struct btc_coexist *btcoexist, +					    bool force_exec, bool enable) +{ +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, +		  "[BTCoex], %s turn Ignore WlanAct %s\n", +		  (force_exec ? "force to" : ""), (enable ? "ON" : "OFF")); +	coex_dm->cur_ignore_wlan_act = enable; + +	if (!force_exec) { +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, +			  "[BTCoex], bPreIgnoreWlanAct = %d, bCurIgnoreWlanAct = %d!!\n", +			  coex_dm->pre_ignore_wlan_act, +			  coex_dm->cur_ignore_wlan_act); + +		if (coex_dm->pre_ignore_wlan_act == +		    coex_dm->cur_ignore_wlan_act) +			return; +	} +	set_fw_ignore_wlan_act(btcoexist, enable); + +	coex_dm->pre_ignore_wlan_act = coex_dm->cur_ignore_wlan_act; +} + +static void set_fw_ps_tdma(struct btc_coexist *btcoexist, u8 byte1, +			   u8 byte2, u8 byte3, u8 byte4, u8 byte5) +{ +	u8 h2c_parameter[5] = {0}; + +	h2c_parameter[0] = byte1; +	h2c_parameter[1] = byte2; +	h2c_parameter[2] = byte3; +	h2c_parameter[3] = byte4; +	h2c_parameter[4] = byte5; + +	coex_dm->ps_tdma_para[0] = byte1; +	coex_dm->ps_tdma_para[1] = byte2; +	coex_dm->ps_tdma_para[2] = byte3; +	coex_dm->ps_tdma_para[3] = byte4; +	coex_dm->ps_tdma_para[4] = byte5; + +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, +		  "[BTCoex], FW write 0x60(5bytes) = 0x%x%08x\n", +		  h2c_parameter[0], +		  h2c_parameter[1] << 24 | h2c_parameter[2] << 16 | +		  h2c_parameter[3] << 8 | h2c_parameter[4]); + +	btcoexist->btc_fill_h2c(btcoexist, 0x60, 5, h2c_parameter); +} + +static void halbtc8723b2ant_sw_mechanism1(struct btc_coexist *btcoexist, +					  bool shrink_rx_lpf, +					  bool low_penalty_ra, +					  bool limited_dig, +					  bool bt_lna_constrain) +{ +	halbtc8723b2ant_rf_shrink(btcoexist, NORMAL_EXEC, shrink_rx_lpf); +	halbtc8723b2ant_low_penalty_ra(btcoexist, NORMAL_EXEC, low_penalty_ra); +} + +static void halbtc8723b2ant_sw_mechanism2(struct btc_coexist *btcoexist, +					  bool agc_table_shift, +					  bool adc_backoff, +					  bool sw_dac_swing, u32 dac_swing_lvl) +{ +	halbtc8723b2ant_agc_table(btcoexist, NORMAL_EXEC, agc_table_shift); +	halbtc8723b2ant_dac_swing(btcoexist, NORMAL_EXEC, sw_dac_swing, +				  dac_swing_lvl); +} + +static void halbtc8723b2ant_set_ant_path(struct btc_coexist *btcoexist, +					 u8 antpos_type, bool init_hwcfg, +					 bool wifi_off) +{ +	struct btc_board_info *board_info = &btcoexist->board_info; +	u32 fw_ver = 0, u32tmp = 0; +	bool pg_ext_switch = false; +	bool use_ext_switch = false; +	u8 h2c_parameter[2] = {0}; + +	btcoexist->btc_get(btcoexist, BTC_GET_BL_EXT_SWITCH, &pg_ext_switch); +	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver); + +	if ((fw_ver < 0xc0000) || pg_ext_switch) +		use_ext_switch = true; + +	if (init_hwcfg) { +		/* 0x4c[23] = 0, 0x4c[24] = 1  Antenna control by WL/BT */ +		u32tmp = btcoexist->btc_read_4byte(btcoexist, 0x4c); +		u32tmp &= ~BIT(23); +		u32tmp |= BIT(24); +		btcoexist->btc_write_4byte(btcoexist, 0x4c, u32tmp); + +		btcoexist->btc_write_1byte(btcoexist, 0x974, 0xff); +		btcoexist->btc_write_1byte_bitmask(btcoexist, 0x944, 0x3, 0x3); +		btcoexist->btc_write_1byte(btcoexist, 0x930, 0x77); +		btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, 0x20, 0x1); + +		/* Force GNT_BT to low */ +		btcoexist->btc_write_1byte_bitmask(btcoexist, 0x765, 0x18, 0x0); +		btcoexist->btc_write_2byte(btcoexist, 0x948, 0x0); + +		if (board_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT) { +			/* tell firmware "no antenna inverse" */ +			h2c_parameter[0] = 0; +			h2c_parameter[1] = 1;  /* ext switch type */ +			btcoexist->btc_fill_h2c(btcoexist, 0x65, 2, +						h2c_parameter); +		} else { +			/* tell firmware "antenna inverse" */ +			h2c_parameter[0] = 1; +			h2c_parameter[1] = 1;  /* ext switch type */ +			btcoexist->btc_fill_h2c(btcoexist, 0x65, 2, +						h2c_parameter); +		} +	} + +	/* ext switch setting */ +	if (use_ext_switch) { +		/* fixed internal switch S1->WiFi, S0->BT */ +		btcoexist->btc_write_2byte(btcoexist, 0x948, 0x0); +		switch (antpos_type) { +		case BTC_ANT_WIFI_AT_MAIN: +			/* ext switch main at wifi */ +			btcoexist->btc_write_1byte_bitmask(btcoexist, 0x92c, +							   0x3, 0x1); +			break; +		case BTC_ANT_WIFI_AT_AUX: +			/* ext switch aux at wifi */ +			btcoexist->btc_write_1byte_bitmask(btcoexist, +							   0x92c, 0x3, 0x2); +			break; +		} +	} else {	/* internal switch */ +		/* fixed ext switch */ +		btcoexist->btc_write_1byte_bitmask(btcoexist, 0x92c, 0x3, 0x1); +		switch (antpos_type) { +		case BTC_ANT_WIFI_AT_MAIN: +			/* fixed internal switch S1->WiFi, S0->BT */ +			btcoexist->btc_write_2byte(btcoexist, 0x948, 0x0); +			break; +		case BTC_ANT_WIFI_AT_AUX: +			/* fixed internal switch S0->WiFi, S1->BT */ +			btcoexist->btc_write_2byte(btcoexist, 0x948, 0x280); +			break; +		} +	} +} + +static void halbtc8723b2ant_ps_tdma(struct btc_coexist *btcoexist, +				    bool force_exec, bool turn_on, u8 type) +{ +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, +		  "[BTCoex], %s turn %s PS TDMA, type =%d\n", +		  (force_exec ? "force to" : ""), +		  (turn_on ? "ON" : "OFF"), type); +	coex_dm->cur_ps_tdma_on = turn_on; +	coex_dm->cur_ps_tdma = type; + +	if (!force_exec) { +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, +			  "[BTCoex], bPrePsTdmaOn = %d, bCurPsTdmaOn = %d!!\n", +			  coex_dm->pre_ps_tdma_on, coex_dm->cur_ps_tdma_on); +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, +			  "[BTCoex], prePsTdma = %d, curPsTdma = %d!!\n", +			  coex_dm->pre_ps_tdma, coex_dm->cur_ps_tdma); + +		if ((coex_dm->pre_ps_tdma_on == coex_dm->cur_ps_tdma_on) && +		    (coex_dm->pre_ps_tdma == coex_dm->cur_ps_tdma)) +			return; +	} +	if (turn_on) { +		switch (type) { +		case 1: +		default: +			set_fw_ps_tdma(btcoexist, 0xe3, 0x1a, 0x1a, 0xe1, 0x90); +			break; +		case 2: +			set_fw_ps_tdma(btcoexist, 0xe3, 0x12, 0x12, 0xe1, 0x90); +			break; +		case 3: +			set_fw_ps_tdma(btcoexist, 0xe3, 0x1c, 0x3, 0xf1, 0x90); +			break; +		case 4: +			set_fw_ps_tdma(btcoexist, 0xe3, 0x10, 0x03, 0xf1, 0x90); +			break; +		case 5: +			set_fw_ps_tdma(btcoexist, 0xe3, 0x1a, 0x1a, 0x60, 0x90); +			break; +		case 6: +			set_fw_ps_tdma(btcoexist, 0xe3, 0x12, 0x12, 0x60, 0x90); +			break; +		case 7: +			set_fw_ps_tdma(btcoexist, 0xe3, 0x1c, 0x3, 0x70, 0x90); +			break; +		case 8: +			set_fw_ps_tdma(btcoexist, 0xa3, 0x10, 0x3, 0x70, 0x90); +			break; +		case 9: +			set_fw_ps_tdma(btcoexist, 0xe3, 0x1a, 0x1a, 0xe1, 0x90); +			break; +		case 10: +			set_fw_ps_tdma(btcoexist, 0xe3, 0x12, 0x12, 0xe1, 0x90); +			break; +		case 11: +			set_fw_ps_tdma(btcoexist, 0xe3, 0xa, 0xa, 0xe1, 0x90); +			break; +		case 12: +			set_fw_ps_tdma(btcoexist, 0xe3, 0x5, 0x5, 0xe1, 0x90); +			break; +		case 13: +			set_fw_ps_tdma(btcoexist, 0xe3, 0x1a, 0x1a, 0x60, 0x90); +			break; +		case 14: +			set_fw_ps_tdma(btcoexist, 0xe3, 0x12, 0x12, 0x60, 0x90); +			break; +		case 15: +			set_fw_ps_tdma(btcoexist, 0xe3, 0xa, 0xa, 0x60, 0x90); +			break; +		case 16: +			set_fw_ps_tdma(btcoexist, 0xe3, 0x5, 0x5, 0x60, 0x90); +			break; +		case 17: +			set_fw_ps_tdma(btcoexist, 0xa3, 0x2f, 0x2f, 0x60, 0x90); +			break; +		case 18: +			set_fw_ps_tdma(btcoexist, 0xe3, 0x5, 0x5, 0xe1, 0x90); +			break; +		case 19: +			set_fw_ps_tdma(btcoexist, 0xe3, 0x25, 0x25, 0xe1, 0x90); +			break; +		case 20: +			set_fw_ps_tdma(btcoexist, 0xe3, 0x25, 0x25, 0x60, 0x90); +			break; +		case 21: +			set_fw_ps_tdma(btcoexist, 0xe3, 0x15, 0x03, 0x70, 0x90); +			break; +		case 71: +			set_fw_ps_tdma(btcoexist, 0xe3, 0x1a, 0x1a, 0xe1, 0x90); +			break; +		} +	} else { +		/* disable PS tdma */ +		switch (type) { +		case 0: +			set_fw_ps_tdma(btcoexist, 0x0, 0x0, 0x0, 0x40, 0x0); +			break; +		case 1: +			set_fw_ps_tdma(btcoexist, 0x0, 0x0, 0x0, 0x48, 0x0); +			break; +		default: +			set_fw_ps_tdma(btcoexist, 0x0, 0x0, 0x0, 0x40, 0x0); +			break; +		} +	} + +	/* update pre state */ +	coex_dm->pre_ps_tdma_on = coex_dm->cur_ps_tdma_on; +	coex_dm->pre_ps_tdma = coex_dm->cur_ps_tdma; +} + +static void halbtc8723b2ant_coex_alloff(struct btc_coexist *btcoexist) +{ +	/* fw all off */ +	halbtc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1); +	halbtc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); +	halbtc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + +	/* sw all off */ +	halbtc8723b2ant_sw_mechanism1(btcoexist, false, false, false, false); +	halbtc8723b2ant_sw_mechanism2(btcoexist, false, false, false, 0x18); + +	/* hw all off */ +	btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); +	coex_table_with_type(btcoexist, NORMAL_EXEC, 0); +} + +static void halbtc8723b2ant_init_coex_dm(struct btc_coexist *btcoexist) +{ +	/* force to reset coex mechanism*/ + +	halbtc8723b2ant_ps_tdma(btcoexist, FORCE_EXEC, false, 1); +	halbtc8723b2ant_fw_dac_swing_lvl(btcoexist, FORCE_EXEC, 6); +	halbtc8723b2ant_dec_bt_pwr(btcoexist, FORCE_EXEC, false); + +	halbtc8723b2ant_sw_mechanism1(btcoexist, false, false, false, false); +	halbtc8723b2ant_sw_mechanism2(btcoexist, false, false, false, 0x18); +} + +static void halbtc8723b2ant_action_bt_inquiry(struct btc_coexist *btcoexist) +{ +	bool wifi_connected = false; +	bool low_pwr_disable = true; + +	btcoexist->btc_set(btcoexist, BTC_SET_ACT_DISABLE_LOW_POWER, +			   &low_pwr_disable); +	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, +			   &wifi_connected); + +	if (wifi_connected) { +		coex_table_with_type(btcoexist, NORMAL_EXEC, 7); +		halbtc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 3); +	} else { +		coex_table_with_type(btcoexist, NORMAL_EXEC, 0); +		halbtc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1); +	} +	halbtc8723b2ant_fw_dac_swing_lvl(btcoexist, FORCE_EXEC, 6); +	halbtc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + +	halbtc8723b2ant_sw_mechanism1(btcoexist, false, false, false, false); +	halbtc8723b2ant_sw_mechanism2(btcoexist, false, false, false, 0x18); + +	coex_dm->need_recover_0x948 = true; +	coex_dm->backup_0x948 = btcoexist->btc_read_2byte(btcoexist, 0x948); + +	halbtc8723b2ant_set_ant_path(btcoexist, BTC_ANT_WIFI_AT_AUX, +				     false, false); +} + +static bool halbtc8723b2ant_is_common_action(struct btc_coexist *btcoexist) +{ +	bool common = false, wifi_connected = false; +	bool wifi_busy = false; +	bool bt_hs_on = false, low_pwr_disable = false; + +	btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); +	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, +			   &wifi_connected); +	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + +	if (!wifi_connected) { +		low_pwr_disable = false; +		btcoexist->btc_set(btcoexist, BTC_SET_ACT_DISABLE_LOW_POWER, +				   &low_pwr_disable); + +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +			  "[BTCoex], Wifi non-connected idle!!\n"); + +		btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, +					  0x0); +		coex_table_with_type(btcoexist, NORMAL_EXEC, 0); +		halbtc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1); +		halbtc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); +		halbtc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + +		halbtc8723b2ant_sw_mechanism1(btcoexist, false, false, false, +					      false); +		halbtc8723b2ant_sw_mechanism2(btcoexist, false, false, false, +					      0x18); + +		common = true; +	} else { +		if (BT_8723B_2ANT_BT_STATUS_NON_CONNECTED_IDLE == +		    coex_dm->bt_status) { +			low_pwr_disable = false; +			btcoexist->btc_set(btcoexist, +					   BTC_SET_ACT_DISABLE_LOW_POWER, +					   &low_pwr_disable); + +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +				  "[BTCoex], Wifi connected + BT non connected-idle!!\n"); + +			btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, +						  0xfffff, 0x0); +			coex_table_with_type(btcoexist, +							     NORMAL_EXEC, 0); +			halbtc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, +						1); +			halbtc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, +							 0xb); +			halbtc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, +						   false); + +			halbtc8723b2ant_sw_mechanism1(btcoexist, false, false, +						      false, false); +			halbtc8723b2ant_sw_mechanism2(btcoexist, false, false, +						      false, 0x18); + +			common = true; +		} else if (BT_8723B_2ANT_BT_STATUS_CONNECTED_IDLE == +			   coex_dm->bt_status) { +			low_pwr_disable = true; +			btcoexist->btc_set(btcoexist, +					   BTC_SET_ACT_DISABLE_LOW_POWER, +					   &low_pwr_disable); + +			if (bt_hs_on) +				return false; +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +				  "[BTCoex], Wifi connected + BT connected-idle!!\n"); + +			btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, +						  0xfffff, 0x0); +			coex_table_with_type(btcoexist, +							     NORMAL_EXEC, 0); +			halbtc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, +						1); +			halbtc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, +							 0xb); +			halbtc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, +						   false); + +			halbtc8723b2ant_sw_mechanism1(btcoexist, true, false, +						      false, false); +			halbtc8723b2ant_sw_mechanism2(btcoexist, false, false, +						      false, 0x18); + +			common = true; +		} else { +			low_pwr_disable = true; +			btcoexist->btc_set(btcoexist, +					   BTC_SET_ACT_DISABLE_LOW_POWER, +					   &low_pwr_disable); + +			if (wifi_busy) { +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +					  "[BTCoex], Wifi Connected-Busy + BT Busy!!\n"); +				common = false; +			} else { +				if (bt_hs_on) +					return false; + +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +					  "[BTCoex], Wifi Connected-Idle + BT Busy!!\n"); + +				btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, +							  0x1, 0xfffff, 0x0); +				coex_table_with_type(btcoexist, +					    NORMAL_EXEC, 7); +				halbtc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, +							true, 21); +				halbtc8723b2ant_fw_dac_swing_lvl(btcoexist, +								 NORMAL_EXEC, +								 0xb); +				if (halbtc8723b2ant_need_to_dec_bt_pwr(btcoexist)) +					halbtc8723b2ant_dec_bt_pwr(btcoexist, +								   NORMAL_EXEC, +								   true); +				else +					halbtc8723b2ant_dec_bt_pwr(btcoexist, +								   NORMAL_EXEC, +								   false); +				halbtc8723b2ant_sw_mechanism1(btcoexist, false, +							      false, false, +							      false); +				halbtc8723b2ant_sw_mechanism2(btcoexist, false, +							      false, false, +							      0x18); +				common = true; +			} +		} +	} + +	return common; +} +static void halbtc8723b2ant_tdma_duration_adjust(struct btc_coexist *btcoexist, +						 bool sco_hid, bool tx_pause, +						 u8 max_interval) +{ +	static s32 up, dn, m, n, wait_count; +	/*0: no change, +1: increase WiFi duration, -1: decrease WiFi duration*/ +	s32 result; +	u8 retrycount = 0; + +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, +		  "[BTCoex], TdmaDurationAdjust()\n"); + +	if (!coex_dm->auto_tdma_adjust) { +		coex_dm->auto_tdma_adjust = true; +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, +			  "[BTCoex], first run TdmaDurationAdjust()!!\n"); +		if (sco_hid) { +			if (tx_pause) { +				if (max_interval == 1) { +					halbtc8723b2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 13); +					coex_dm->ps_tdma_du_adj_type = 13; +				} else if (max_interval == 2) { +					halbtc8723b2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 14); +					coex_dm->ps_tdma_du_adj_type = 14; +				} else if (max_interval == 3) { +					halbtc8723b2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 15); +					coex_dm->ps_tdma_du_adj_type = 15; +				} else { +					halbtc8723b2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 15); +					coex_dm->ps_tdma_du_adj_type = 15; +				} +			} else { +				if (max_interval == 1) { +					halbtc8723b2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 9); +					coex_dm->ps_tdma_du_adj_type = 9; +				} else if (max_interval == 2) { +					halbtc8723b2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 10); +					coex_dm->ps_tdma_du_adj_type = 10; +				} else if (max_interval == 3) { +					halbtc8723b2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 11); +					coex_dm->ps_tdma_du_adj_type = 11; +				} else { +					halbtc8723b2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 11); +					coex_dm->ps_tdma_du_adj_type = 11; +				} +			} +		} else { +			if (tx_pause) { +				if (max_interval == 1) { +					halbtc8723b2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 5); +					coex_dm->ps_tdma_du_adj_type = 5; +				} else if (max_interval == 2) { +					halbtc8723b2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 6); +					coex_dm->ps_tdma_du_adj_type = 6; +				} else if (max_interval == 3) { +					halbtc8723b2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 7); +					coex_dm->ps_tdma_du_adj_type = 7; +				} else { +					halbtc8723b2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 7); +					coex_dm->ps_tdma_du_adj_type = 7; +				} +			} else { +				if (max_interval == 1) { +					halbtc8723b2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 1); +					coex_dm->ps_tdma_du_adj_type = 1; +				} else if (max_interval == 2) { +					halbtc8723b2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 2); +					coex_dm->ps_tdma_du_adj_type = 2; +				} else if (max_interval == 3) { +					halbtc8723b2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 3); +					coex_dm->ps_tdma_du_adj_type = 3; +				} else { +					halbtc8723b2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 3); +					coex_dm->ps_tdma_du_adj_type = 3; +				} +			} +		} + +		up = 0; +		dn = 0; +		m = 1; +		n = 3; +		result = 0; +		wait_count = 0; +	} else { +		/*accquire the BT TRx retry count from BT_Info byte2*/ +		retrycount = coex_sta->bt_retry_cnt; +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, +			  "[BTCoex], retrycount = %d\n", retrycount); +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, +			  "[BTCoex], up =%d, dn =%d, m =%d, n =%d, wait_count =%d\n", +			  up, dn, m, n, wait_count); +		result = 0; +		wait_count++; +		 /* no retry in the last 2-second duration*/ +		if (retrycount == 0) { +			up++; +			dn--; + +			if (dn <= 0) +				dn = 0; + +			if (up >= n) { +				wait_count = 0; +				n = 3; +				up = 0; +				dn = 0; +				result = 1; +				BTC_PRINT(BTC_MSG_ALGORITHM, +					  ALGO_TRACE_FW_DETAIL, +					  "[BTCoex], Increase wifi duration!!\n"); +			} /* <= 3 retry in the last 2-second duration*/ +		} else if (retrycount <= 3) { +			up--; +			dn++; + +			if (up <= 0) +				up = 0; + +			if (dn == 2) { +				if (wait_count <= 2) +					m++; +				else +					m = 1; + +				if (m >= 20) +					m = 20; + +				n = 3 * m; +				up = 0; +				dn = 0; +				wait_count = 0; +				result = -1; +				BTC_PRINT(BTC_MSG_ALGORITHM, +					  ALGO_TRACE_FW_DETAIL, +					  "[BTCoex], Decrease wifi duration for retrycounter<3!!\n"); +			} +		} else { +			if (wait_count == 1) +				m++; +			else +				m = 1; + +			if (m >= 20) +				m = 20; + +			n = 3 * m; +			up = 0; +			dn = 0; +			wait_count = 0; +			result = -1; +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, +				  "[BTCoex], Decrease wifi duration for retrycounter>3!!\n"); +		} + +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, +			  "[BTCoex], max Interval = %d\n", max_interval); +		if (max_interval == 1) { +			if (tx_pause) { +				BTC_PRINT(BTC_MSG_ALGORITHM, +					  ALGO_TRACE_FW_DETAIL, +					  "[BTCoex], TxPause = 1\n"); + +				if (coex_dm->cur_ps_tdma == 71) { +					halbtc8723b2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 5); +					coex_dm->ps_tdma_du_adj_type = 5; +				} else if (coex_dm->cur_ps_tdma == 1) { +					halbtc8723b2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 5); +					coex_dm->ps_tdma_du_adj_type = 5; +				} else if (coex_dm->cur_ps_tdma == 2) { +					halbtc8723b2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 6); +					coex_dm->ps_tdma_du_adj_type = 6; +				} else if (coex_dm->cur_ps_tdma == 3) { +					halbtc8723b2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 7); +					coex_dm->ps_tdma_du_adj_type = 7; +				} else if (coex_dm->cur_ps_tdma == 4) { +					halbtc8723b2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 8); +					coex_dm->ps_tdma_du_adj_type = 8; +				} + +				if (coex_dm->cur_ps_tdma == 9) { +					halbtc8723b2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 13); +					coex_dm->ps_tdma_du_adj_type = 13; +				} else if (coex_dm->cur_ps_tdma == 10) { +					halbtc8723b2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 14); +					coex_dm->ps_tdma_du_adj_type = 14; +				} else if (coex_dm->cur_ps_tdma == 11) { +					halbtc8723b2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 15); +					coex_dm->ps_tdma_du_adj_type = 15; +				} else if (coex_dm->cur_ps_tdma == 12) { +					halbtc8723b2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 16); +					coex_dm->ps_tdma_du_adj_type = 16; +				} + +				if (result == -1) { +					if (coex_dm->cur_ps_tdma == 5) { +						halbtc8723b2ant_ps_tdma( +								btcoexist, +								NORMAL_EXEC, +								true, 6); +						coex_dm->ps_tdma_du_adj_type = +									      6; +					} else if (coex_dm->cur_ps_tdma == 6) { +						halbtc8723b2ant_ps_tdma( +								btcoexist, +								NORMAL_EXEC, +								true, 7); +						coex_dm->ps_tdma_du_adj_type = +									      7; +					} else if (coex_dm->cur_ps_tdma == 7) { +						halbtc8723b2ant_ps_tdma( +								btcoexist, +								NORMAL_EXEC, +								true, 8); +						coex_dm->ps_tdma_du_adj_type = +									      8; +					} else if (coex_dm->cur_ps_tdma == 13) { +						halbtc8723b2ant_ps_tdma( +								btcoexist, +								NORMAL_EXEC, +								true, 14); +						coex_dm->ps_tdma_du_adj_type = +									     14; +					} else if (coex_dm->cur_ps_tdma == 14) { +						halbtc8723b2ant_ps_tdma( +								btcoexist, +								NORMAL_EXEC, +								true, 15); +						coex_dm->ps_tdma_du_adj_type = +									     15; +					} else if (coex_dm->cur_ps_tdma == 15) { +						halbtc8723b2ant_ps_tdma( +								btcoexist, +								NORMAL_EXEC, +								true, 16); +						coex_dm->ps_tdma_du_adj_type = +									     16; +					} +				}  else if (result == 1) { +					if (coex_dm->cur_ps_tdma == 8) { +						halbtc8723b2ant_ps_tdma( +								btcoexist, +								NORMAL_EXEC, +								true, 7); +						coex_dm->ps_tdma_du_adj_type = +									      7; +					} else if (coex_dm->cur_ps_tdma == 7) { +						halbtc8723b2ant_ps_tdma( +								btcoexist, +								NORMAL_EXEC, +								true, 6); +						coex_dm->ps_tdma_du_adj_type = +									      6; +					} else if (coex_dm->cur_ps_tdma == 6) { +						halbtc8723b2ant_ps_tdma( +								btcoexist, +								NORMAL_EXEC, +								true, 5); +						coex_dm->ps_tdma_du_adj_type = +									      5; +					} else if (coex_dm->cur_ps_tdma == 16) { +						halbtc8723b2ant_ps_tdma( +								btcoexist, +								NORMAL_EXEC, +								true, 15); +						coex_dm->ps_tdma_du_adj_type = +									     15; +					} else if (coex_dm->cur_ps_tdma == 15) { +						halbtc8723b2ant_ps_tdma( +								btcoexist, +								NORMAL_EXEC, +								true, 14); +						coex_dm->ps_tdma_du_adj_type = +									     14; +					} else if (coex_dm->cur_ps_tdma == 14) { +						halbtc8723b2ant_ps_tdma( +								btcoexist, +								NORMAL_EXEC, +								true, 13); +						coex_dm->ps_tdma_du_adj_type = +									     13; +					} +				} +			} else { +				BTC_PRINT(BTC_MSG_ALGORITHM, +					  ALGO_TRACE_FW_DETAIL, +					  "[BTCoex], TxPause = 0\n"); +				if (coex_dm->cur_ps_tdma == 5) { +					halbtc8723b2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 71); +					coex_dm->ps_tdma_du_adj_type = 71; +				} else if (coex_dm->cur_ps_tdma == 6) { +					halbtc8723b2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 2); +					coex_dm->ps_tdma_du_adj_type = 2; +				} else if (coex_dm->cur_ps_tdma == 7) { +					halbtc8723b2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 3); +					coex_dm->ps_tdma_du_adj_type = 3; +				} else if (coex_dm->cur_ps_tdma == 8) { +					halbtc8723b2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 4); +					coex_dm->ps_tdma_du_adj_type = 4; +				} + +				if (coex_dm->cur_ps_tdma == 13) { +					halbtc8723b2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 9); +					coex_dm->ps_tdma_du_adj_type = 9; +				} else if (coex_dm->cur_ps_tdma == 14) { +					halbtc8723b2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 10); +					coex_dm->ps_tdma_du_adj_type = 10; +				} else if (coex_dm->cur_ps_tdma == 15) { +					halbtc8723b2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 11); +					coex_dm->ps_tdma_du_adj_type = 11; +				} else if (coex_dm->cur_ps_tdma == 16) { +					halbtc8723b2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 12); +					coex_dm->ps_tdma_du_adj_type = 12; +				} + +				if (result == -1) { +					if (coex_dm->cur_ps_tdma == 71) { +						halbtc8723b2ant_ps_tdma( +								btcoexist, +								NORMAL_EXEC, +								true, 1); +						coex_dm->ps_tdma_du_adj_type = +									      1; +					} else if (coex_dm->cur_ps_tdma == 1) { +						halbtc8723b2ant_ps_tdma( +								btcoexist, +								NORMAL_EXEC, +								true, 2); +						coex_dm->ps_tdma_du_adj_type = +									      2; +					} else if (coex_dm->cur_ps_tdma == 2) { +						halbtc8723b2ant_ps_tdma( +								btcoexist, +								NORMAL_EXEC, +								true, 3); +						coex_dm->ps_tdma_du_adj_type = +									      3; +					} else if (coex_dm->cur_ps_tdma == 3) { +						halbtc8723b2ant_ps_tdma( +								btcoexist, +								NORMAL_EXEC, +								true, 4); +						coex_dm->ps_tdma_du_adj_type = +									      4; +					} else if (coex_dm->cur_ps_tdma == 9) { +						halbtc8723b2ant_ps_tdma( +								btcoexist, +								NORMAL_EXEC, +								true, 10); +						coex_dm->ps_tdma_du_adj_type = +									     10; +					} else if (coex_dm->cur_ps_tdma == 10) { +						halbtc8723b2ant_ps_tdma( +								btcoexist, +								NORMAL_EXEC, +								true, 11); +						coex_dm->ps_tdma_du_adj_type = +									     11; +					} else if (coex_dm->cur_ps_tdma == 11) { +						halbtc8723b2ant_ps_tdma( +								btcoexist, +								NORMAL_EXEC, +								true, 12); +						coex_dm->ps_tdma_du_adj_type = +									     12; +					} +				}  else if (result == 1) { +					if (coex_dm->cur_ps_tdma == 4) { +						halbtc8723b2ant_ps_tdma( +								btcoexist, +								NORMAL_EXEC, +								true, 3); +						coex_dm->ps_tdma_du_adj_type = +									      3; +					} else if (coex_dm->cur_ps_tdma == 3) { +						halbtc8723b2ant_ps_tdma( +								btcoexist, +								NORMAL_EXEC, +								true, 2); +						coex_dm->ps_tdma_du_adj_type = +									      2; +					} else if (coex_dm->cur_ps_tdma == 2) { +						halbtc8723b2ant_ps_tdma( +								btcoexist, +								NORMAL_EXEC, +								true, 1); +						coex_dm->ps_tdma_du_adj_type = +									      1; +					} else if (coex_dm->cur_ps_tdma == 1) { +						halbtc8723b2ant_ps_tdma( +								btcoexist, +								NORMAL_EXEC, +								true, 71); +						coex_dm->ps_tdma_du_adj_type = +									     71; +					} else if (coex_dm->cur_ps_tdma == 12) { +						halbtc8723b2ant_ps_tdma( +								btcoexist, +								NORMAL_EXEC, +								true, 11); +						coex_dm->ps_tdma_du_adj_type = +									     11; +					} else if (coex_dm->cur_ps_tdma == 11) { +						halbtc8723b2ant_ps_tdma( +								btcoexist, +								NORMAL_EXEC, +								true, 10); +						coex_dm->ps_tdma_du_adj_type = +									     10; +					} else if (coex_dm->cur_ps_tdma == 10) { +						halbtc8723b2ant_ps_tdma( +								btcoexist, +								NORMAL_EXEC, +								true, 9); +						coex_dm->ps_tdma_du_adj_type = +									      9; +					} +				} +			} +		} else if (max_interval == 2) { +			if (tx_pause) { +				BTC_PRINT(BTC_MSG_ALGORITHM, +					  ALGO_TRACE_FW_DETAIL, +					  "[BTCoex], TxPause = 1\n"); +				if (coex_dm->cur_ps_tdma == 1) { +					halbtc8723b2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 6); +					coex_dm->ps_tdma_du_adj_type = 6; +				} else if (coex_dm->cur_ps_tdma == 2) { +					halbtc8723b2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 6); +					coex_dm->ps_tdma_du_adj_type = 6; +				} else if (coex_dm->cur_ps_tdma == 3) { +					halbtc8723b2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 7); +					coex_dm->ps_tdma_du_adj_type = 7; +				} else if (coex_dm->cur_ps_tdma == 4) { +					halbtc8723b2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 8); +					coex_dm->ps_tdma_du_adj_type = 8; +				} +				if (coex_dm->cur_ps_tdma == 9) { +					halbtc8723b2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 14); +					coex_dm->ps_tdma_du_adj_type = 14; +				} else if (coex_dm->cur_ps_tdma == 10) { +					halbtc8723b2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 14); +					coex_dm->ps_tdma_du_adj_type = 14; +				} else if (coex_dm->cur_ps_tdma == 11) { +					halbtc8723b2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 15); +					coex_dm->ps_tdma_du_adj_type = 15; +				} else if (coex_dm->cur_ps_tdma == 12) { +					halbtc8723b2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 16); +					coex_dm->ps_tdma_du_adj_type = 16; +				} +				if (result == -1) { +					if (coex_dm->cur_ps_tdma == 5) { +						halbtc8723b2ant_ps_tdma( +								btcoexist, +								NORMAL_EXEC, +								true, 6); +						coex_dm->ps_tdma_du_adj_type = +									      6; +					} else if (coex_dm->cur_ps_tdma == 6) { +						halbtc8723b2ant_ps_tdma( +								btcoexist, +								NORMAL_EXEC, +								true, 7); +						coex_dm->ps_tdma_du_adj_type = +									      7; +					} else if (coex_dm->cur_ps_tdma == 7) { +						halbtc8723b2ant_ps_tdma( +								btcoexist, +								NORMAL_EXEC, +								true, 8); +						coex_dm->ps_tdma_du_adj_type = +									      8; +					} else if (coex_dm->cur_ps_tdma == 13) { +						halbtc8723b2ant_ps_tdma( +								btcoexist, +								NORMAL_EXEC, +								true, 14); +						coex_dm->ps_tdma_du_adj_type = +									     14; +					} else if (coex_dm->cur_ps_tdma == 14) { +						halbtc8723b2ant_ps_tdma( +								btcoexist, +								NORMAL_EXEC, +								true, 15); +						coex_dm->ps_tdma_du_adj_type = +									     15; +					} else if (coex_dm->cur_ps_tdma == 15) { +						halbtc8723b2ant_ps_tdma( +								btcoexist, +								NORMAL_EXEC, +								true, 16); +						coex_dm->ps_tdma_du_adj_type = +									     16; +					} +				}  else if (result == 1) { +					if (coex_dm->cur_ps_tdma == 8) { +						halbtc8723b2ant_ps_tdma( +								btcoexist, +								NORMAL_EXEC, +								true, 7); +						coex_dm->ps_tdma_du_adj_type = +									      7; +					} else if (coex_dm->cur_ps_tdma == 7) { +						halbtc8723b2ant_ps_tdma( +								btcoexist, +								NORMAL_EXEC, +								true, 6); +						coex_dm->ps_tdma_du_adj_type = +									      6; +					} else if (coex_dm->cur_ps_tdma == 6) { +						halbtc8723b2ant_ps_tdma( +								btcoexist, +								NORMAL_EXEC, +								true, 6); +						coex_dm->ps_tdma_du_adj_type = +									      6; +					} else if (coex_dm->cur_ps_tdma == 16) { +						halbtc8723b2ant_ps_tdma( +								btcoexist, +								NORMAL_EXEC, +								true, 15); +						coex_dm->ps_tdma_du_adj_type = +									     15; +					} else if (coex_dm->cur_ps_tdma == 15) { +						halbtc8723b2ant_ps_tdma( +								btcoexist, +								NORMAL_EXEC, +								true, 14); +						coex_dm->ps_tdma_du_adj_type = +									     14; +					} else if (coex_dm->cur_ps_tdma == 14) { +						halbtc8723b2ant_ps_tdma( +								btcoexist, +								NORMAL_EXEC, +								true, 14); +						coex_dm->ps_tdma_du_adj_type = +									     14; +					} +				} +			} else { +				BTC_PRINT(BTC_MSG_ALGORITHM, +					  ALGO_TRACE_FW_DETAIL, +					  "[BTCoex], TxPause = 0\n"); +				if (coex_dm->cur_ps_tdma == 5) { +					halbtc8723b2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 2); +					coex_dm->ps_tdma_du_adj_type = 2; +				} else if (coex_dm->cur_ps_tdma == 6) { +					halbtc8723b2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 2); +					coex_dm->ps_tdma_du_adj_type = 2; +				} else if (coex_dm->cur_ps_tdma == 7) { +					halbtc8723b2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 3); +					coex_dm->ps_tdma_du_adj_type = 3; +				} else if (coex_dm->cur_ps_tdma == 8) { +					halbtc8723b2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 4); +					coex_dm->ps_tdma_du_adj_type = 4; +				} +				if (coex_dm->cur_ps_tdma == 13) { +					halbtc8723b2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 10); +					coex_dm->ps_tdma_du_adj_type = 10; +				} else if (coex_dm->cur_ps_tdma == 14) { +					halbtc8723b2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 10); +					coex_dm->ps_tdma_du_adj_type = 10; +				} else if (coex_dm->cur_ps_tdma == 15) { +					halbtc8723b2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 11); +					coex_dm->ps_tdma_du_adj_type = 11; +				} else if (coex_dm->cur_ps_tdma == 16) { +					halbtc8723b2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 12); +					coex_dm->ps_tdma_du_adj_type = 12; +				} +				if (result == -1) { +					if (coex_dm->cur_ps_tdma == 1) { +						halbtc8723b2ant_ps_tdma( +								btcoexist, +								NORMAL_EXEC, +								true, 2); +						coex_dm->ps_tdma_du_adj_type = +									      2; +					} else if (coex_dm->cur_ps_tdma == 2) { +						halbtc8723b2ant_ps_tdma( +								btcoexist, +								NORMAL_EXEC, +								true, 3); +						coex_dm->ps_tdma_du_adj_type = +									      3; +					} else if (coex_dm->cur_ps_tdma == 3) { +						halbtc8723b2ant_ps_tdma( +								btcoexist, +								NORMAL_EXEC, +								true, 4); +						coex_dm->ps_tdma_du_adj_type = +									      4; +					} else if (coex_dm->cur_ps_tdma == 9) { +						halbtc8723b2ant_ps_tdma( +								btcoexist, +								NORMAL_EXEC, +								true, 10); +						coex_dm->ps_tdma_du_adj_type = +									     10; +					} else if (coex_dm->cur_ps_tdma == 10) { +						halbtc8723b2ant_ps_tdma( +								btcoexist, +								NORMAL_EXEC, +								true, 11); +						coex_dm->ps_tdma_du_adj_type = +									     11; +					} else if (coex_dm->cur_ps_tdma == 11) { +						halbtc8723b2ant_ps_tdma( +								btcoexist, +								NORMAL_EXEC, +								true, 12); +						coex_dm->ps_tdma_du_adj_type = +									     12; +					} +				} else if (result == 1) { +					if (coex_dm->cur_ps_tdma == 4) { +						halbtc8723b2ant_ps_tdma( +								btcoexist, +								NORMAL_EXEC, +								true, 3); +						coex_dm->ps_tdma_du_adj_type = +									      3; +					} else if (coex_dm->cur_ps_tdma == 3) { +						halbtc8723b2ant_ps_tdma( +								btcoexist, +								NORMAL_EXEC, +								true, 2); +						coex_dm->ps_tdma_du_adj_type = +									      2; +					} else if (coex_dm->cur_ps_tdma == 2) { +						halbtc8723b2ant_ps_tdma( +								btcoexist, +								NORMAL_EXEC, +								true, 2); +						coex_dm->ps_tdma_du_adj_type = +									      2; +					} else if (coex_dm->cur_ps_tdma == 12) { +						halbtc8723b2ant_ps_tdma( +								btcoexist, +								NORMAL_EXEC, +								true, 11); +						coex_dm->ps_tdma_du_adj_type = +									     11; +					} else if (coex_dm->cur_ps_tdma == 11) { +						halbtc8723b2ant_ps_tdma( +								btcoexist, +								NORMAL_EXEC, +								true, 10); +						coex_dm->ps_tdma_du_adj_type = +									     10; +					} else if (coex_dm->cur_ps_tdma == 10) { +						halbtc8723b2ant_ps_tdma( +								btcoexist, +								NORMAL_EXEC, +								true, 10); +						coex_dm->ps_tdma_du_adj_type = +									     10; +					} +				} +			} +		} else if (max_interval == 3) { +			if (tx_pause) { +				BTC_PRINT(BTC_MSG_ALGORITHM, +					  ALGO_TRACE_FW_DETAIL, +					  "[BTCoex], TxPause = 1\n"); +				if (coex_dm->cur_ps_tdma == 1) { +					halbtc8723b2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 7); +					coex_dm->ps_tdma_du_adj_type = 7; +				} else if (coex_dm->cur_ps_tdma == 2) { +					halbtc8723b2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 7); +					coex_dm->ps_tdma_du_adj_type = 7; +				} else if (coex_dm->cur_ps_tdma == 3) { +					halbtc8723b2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 7); +					coex_dm->ps_tdma_du_adj_type = 7; +				} else if (coex_dm->cur_ps_tdma == 4) { +					halbtc8723b2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 8); +					coex_dm->ps_tdma_du_adj_type = 8; +				} +				if (coex_dm->cur_ps_tdma == 9) { +					halbtc8723b2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 15); +					coex_dm->ps_tdma_du_adj_type = 15; +				} else if (coex_dm->cur_ps_tdma == 10) { +					halbtc8723b2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 15); +					coex_dm->ps_tdma_du_adj_type = 15; +				} else if (coex_dm->cur_ps_tdma == 11) { +					halbtc8723b2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 15); +					coex_dm->ps_tdma_du_adj_type = 15; +				} else if (coex_dm->cur_ps_tdma == 12) { +					halbtc8723b2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 16); +					coex_dm->ps_tdma_du_adj_type = 16; +				} +				if (result == -1) { +					if (coex_dm->cur_ps_tdma == 5) { +						halbtc8723b2ant_ps_tdma( +								btcoexist, +								NORMAL_EXEC, +								true, 7); +						coex_dm->ps_tdma_du_adj_type = +									      7; +					} else if (coex_dm->cur_ps_tdma == 6) { +						halbtc8723b2ant_ps_tdma( +								btcoexist, +								NORMAL_EXEC, +								true, 7); +						coex_dm->ps_tdma_du_adj_type = +									      7; +					} else if (coex_dm->cur_ps_tdma == 7) { +						halbtc8723b2ant_ps_tdma( +								btcoexist, +								NORMAL_EXEC, +								true, 8); +						coex_dm->ps_tdma_du_adj_type = +									      8; +					} else if (coex_dm->cur_ps_tdma == 13) { +						halbtc8723b2ant_ps_tdma( +								btcoexist, +								NORMAL_EXEC, +								true, 15); +						coex_dm->ps_tdma_du_adj_type = +									     15; +					} else if (coex_dm->cur_ps_tdma == 14) { +						halbtc8723b2ant_ps_tdma( +								btcoexist, +								NORMAL_EXEC, +								true, 15); +						coex_dm->ps_tdma_du_adj_type = +									     15; +					} else if (coex_dm->cur_ps_tdma == 15) { +						halbtc8723b2ant_ps_tdma( +								btcoexist, +								NORMAL_EXEC, +								true, 16); +						coex_dm->ps_tdma_du_adj_type = +									     16; +					} +				}  else if (result == 1) { +					if (coex_dm->cur_ps_tdma == 8) { +						halbtc8723b2ant_ps_tdma( +								btcoexist, +								NORMAL_EXEC, +								true, 7); +						coex_dm->ps_tdma_du_adj_type = +									      7; +					} else if (coex_dm->cur_ps_tdma == 7) { +						halbtc8723b2ant_ps_tdma( +								btcoexist, +								NORMAL_EXEC, +								true, 7); +						coex_dm->ps_tdma_du_adj_type = +									      7; +					} else if (coex_dm->cur_ps_tdma == 6) { +						halbtc8723b2ant_ps_tdma( +								btcoexist, +								NORMAL_EXEC, +								true, 7); +						coex_dm->ps_tdma_du_adj_type = +									      7; +					} else if (coex_dm->cur_ps_tdma == 16) { +						halbtc8723b2ant_ps_tdma( +								btcoexist, +								NORMAL_EXEC, +								true, 15); +						coex_dm->ps_tdma_du_adj_type = +									     15; +					} else if (coex_dm->cur_ps_tdma == 15) { +						halbtc8723b2ant_ps_tdma( +								btcoexist, +								NORMAL_EXEC, +								true, 15); +						coex_dm->ps_tdma_du_adj_type = +									     15; +					} else if (coex_dm->cur_ps_tdma == 14) { +						halbtc8723b2ant_ps_tdma( +								btcoexist, +								NORMAL_EXEC, +								true, 15); +						coex_dm->ps_tdma_du_adj_type = +									     15; +					} +				} +			} else { +				BTC_PRINT(BTC_MSG_ALGORITHM, +					  ALGO_TRACE_FW_DETAIL, +					  "[BTCoex], TxPause = 0\n"); +				if (coex_dm->cur_ps_tdma == 5) { +					halbtc8723b2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 3); +					coex_dm->ps_tdma_du_adj_type = 3; +				} else if (coex_dm->cur_ps_tdma == 6) { +					halbtc8723b2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 3); +					coex_dm->ps_tdma_du_adj_type = 3; +				} else if (coex_dm->cur_ps_tdma == 7) { +					halbtc8723b2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 3); +					coex_dm->ps_tdma_du_adj_type = 3; +				} else if (coex_dm->cur_ps_tdma == 8) { +					halbtc8723b2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 4); +					coex_dm->ps_tdma_du_adj_type = 4; +				} +				if (coex_dm->cur_ps_tdma == 13) { +					halbtc8723b2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 11); +					coex_dm->ps_tdma_du_adj_type = 11; +				} else if (coex_dm->cur_ps_tdma == 14) { +					halbtc8723b2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 11); +					coex_dm->ps_tdma_du_adj_type = 11; +				} else if (coex_dm->cur_ps_tdma == 15) { +					halbtc8723b2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 11); +					coex_dm->ps_tdma_du_adj_type = 11; +				} else if (coex_dm->cur_ps_tdma == 16) { +					halbtc8723b2ant_ps_tdma(btcoexist, +								NORMAL_EXEC, +								true, 12); +					coex_dm->ps_tdma_du_adj_type = 12; +				} +				if (result == -1) { +					if (coex_dm->cur_ps_tdma == 1) { +						halbtc8723b2ant_ps_tdma( +								btcoexist, +								NORMAL_EXEC, +								true, 3); +						coex_dm->ps_tdma_du_adj_type = +									      3; +					} else if (coex_dm->cur_ps_tdma == 2) { +						halbtc8723b2ant_ps_tdma( +								btcoexist, +								NORMAL_EXEC, +								true, 3); +						coex_dm->ps_tdma_du_adj_type = +									      3; +					} else if (coex_dm->cur_ps_tdma == 3) { +						halbtc8723b2ant_ps_tdma( +								btcoexist, +								NORMAL_EXEC, +								true, 4); +						coex_dm->ps_tdma_du_adj_type = +									      4; +					} else if (coex_dm->cur_ps_tdma == 9) { +						halbtc8723b2ant_ps_tdma( +								btcoexist, +								NORMAL_EXEC, +								true, 11); +						coex_dm->ps_tdma_du_adj_type = +									     11; +					} else if (coex_dm->cur_ps_tdma == 10) { +						halbtc8723b2ant_ps_tdma( +								btcoexist, +								NORMAL_EXEC, +								true, 11); +						coex_dm->ps_tdma_du_adj_type = +									     11; +					} else if (coex_dm->cur_ps_tdma == 11) { +						halbtc8723b2ant_ps_tdma( +								btcoexist, +								NORMAL_EXEC, +								true, 12); +						coex_dm->ps_tdma_du_adj_type = +									     12; +					} +				} else if (result == 1) { +					if (coex_dm->cur_ps_tdma == 4) { +						halbtc8723b2ant_ps_tdma( +								btcoexist, +								NORMAL_EXEC, +								true, 3); +						coex_dm->ps_tdma_du_adj_type = +									      3; +					} else if (coex_dm->cur_ps_tdma == 3) { +						halbtc8723b2ant_ps_tdma( +								btcoexist, +								NORMAL_EXEC, +								true, 3); +						coex_dm->ps_tdma_du_adj_type = +									      3; +					} else if (coex_dm->cur_ps_tdma == 2) { +						halbtc8723b2ant_ps_tdma( +								btcoexist, +								NORMAL_EXEC, +								true, 3); +						coex_dm->ps_tdma_du_adj_type = +									      3; +					} else if (coex_dm->cur_ps_tdma == 12) { +						halbtc8723b2ant_ps_tdma( +								btcoexist, +								NORMAL_EXEC, +								true, 11); +						coex_dm->ps_tdma_du_adj_type = +									     11; +					} else if (coex_dm->cur_ps_tdma == 11) { +						halbtc8723b2ant_ps_tdma( +								btcoexist, +								NORMAL_EXEC, +								true, 11); +						coex_dm->ps_tdma_du_adj_type = +									     11; +					} else if (coex_dm->cur_ps_tdma == 10) { +						halbtc8723b2ant_ps_tdma( +								btcoexist, +								NORMAL_EXEC, +								true, 11); +						coex_dm->ps_tdma_du_adj_type = +									     11; +					} +				} +			} +		} +	} + +	/*if current PsTdma not match with the recorded one (when scan, dhcp..), +	 *then we have to adjust it back to the previous record one.*/ +	if (coex_dm->cur_ps_tdma != coex_dm->ps_tdma_du_adj_type) { +		bool scan = false, link = false, roam = false; +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, +			  "[BTCoex], PsTdma type dismatch!!!, curPsTdma =%d, recordPsTdma =%d\n", +			  coex_dm->cur_ps_tdma, coex_dm->ps_tdma_du_adj_type); + +		btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan); +		btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link); +		btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam); + +		if (!scan && !link && !roam) +			halbtc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, +						coex_dm->ps_tdma_du_adj_type); +		else +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, +				  "[BTCoex], roaming/link/scan is under progress, will adjust next time!!!\n"); +	} +} + +/* SCO only or SCO+PAN(HS) */ +static void halbtc8723b2ant_action_sco(struct btc_coexist *btcoexist) +{ +	u8 wifi_rssi_state; +	u32 wifi_bw; + +	wifi_rssi_state = halbtc8723b2ant_wifi_rssi_state(btcoexist, +							  0, 2, 15, 0); + +	btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); + +	halbtc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 4); + +	if (halbtc8723b2ant_need_to_dec_bt_pwr(btcoexist)) +		halbtc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true); +	else +		halbtc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + +	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + +	/*for SCO quality at 11b/g mode*/ +	if (BTC_WIFI_BW_LEGACY == wifi_bw) +		coex_table_with_type(btcoexist, NORMAL_EXEC, 2); +	else  /*for SCO quality & wifi performance balance at 11n mode*/ +		coex_table_with_type(btcoexist, NORMAL_EXEC, 8); + +	/*for voice quality */ +	halbtc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + +	/* sw mechanism */ +	if (BTC_WIFI_BW_HT40 == wifi_bw) { +		if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || +		    (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +			halbtc8723b2ant_sw_mechanism1(btcoexist, true, true, +						      false, false); +			halbtc8723b2ant_sw_mechanism2(btcoexist, true, false, +						      true, 0x4); +		} else { +			halbtc8723b2ant_sw_mechanism1(btcoexist, true, true, +						      false, false); +			halbtc8723b2ant_sw_mechanism2(btcoexist, false, false, +						      true, 0x4); +		} +	} else { +		if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || +		    (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +			halbtc8723b2ant_sw_mechanism1(btcoexist, false, true, +						      false, false); +			halbtc8723b2ant_sw_mechanism2(btcoexist, true, false, +						      true, 0x4); +		} else { +			halbtc8723b2ant_sw_mechanism1(btcoexist, false, true, +						      false, false); +			halbtc8723b2ant_sw_mechanism2(btcoexist, false, false, +						      true, 0x4); +		} +	} +} + +static void halbtc8723b2ant_action_hid(struct btc_coexist *btcoexist) +{ +	u8 wifi_rssi_state, bt_rssi_state; +	u32 wifi_bw; + +	wifi_rssi_state = halbtc8723b2ant_wifi_rssi_state(btcoexist, +							  0, 2, 15, 0); +	bt_rssi_state = halbtc8723b2ant_bt_rssi_state(2, 29, 0); + +	btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); + +	halbtc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + +	if (halbtc8723b2ant_need_to_dec_bt_pwr(btcoexist)) +		halbtc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true); +	else +		halbtc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + +	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + +	if (BTC_WIFI_BW_LEGACY == wifi_bw) /*/for HID at 11b/g mode*/ +		coex_table_with_type(btcoexist, NORMAL_EXEC, 7); +	else  /*for HID quality & wifi performance balance at 11n mode*/ +		coex_table_with_type(btcoexist, NORMAL_EXEC, 9); + +	if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || +	    (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) +		halbtc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 9); +	else +		halbtc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 13); + +	/* sw mechanism */ +	if (BTC_WIFI_BW_HT40 == wifi_bw) { +		if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || +		    (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +			halbtc8723b2ant_sw_mechanism1(btcoexist, true, true, +						      false, false); +			halbtc8723b2ant_sw_mechanism2(btcoexist, true, false, +						      false, 0x18); +		} else { +			halbtc8723b2ant_sw_mechanism1(btcoexist, true, true, +						      false, false); +			halbtc8723b2ant_sw_mechanism2(btcoexist, false, false, +						      false, 0x18); +		} +	} else { +		if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || +		    (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +			halbtc8723b2ant_sw_mechanism1(btcoexist, false, true, +						      false, false); +			halbtc8723b2ant_sw_mechanism2(btcoexist, true, false, +						      false, 0x18); +		} else { +			halbtc8723b2ant_sw_mechanism1(btcoexist, false, true, +						      false, false); +			halbtc8723b2ant_sw_mechanism2(btcoexist, false, false, +						      false, 0x18); +		} +	} +} + +/*A2DP only / PAN(EDR) only/ A2DP+PAN(HS)*/ +static void halbtc8723b2ant_action_a2dp(struct btc_coexist *btcoexist) +{ +	u8 wifi_rssi_state, wifi_rssi_state1, bt_rssi_state; +	u32 wifi_bw; +	u8 ap_num = 0; + +	wifi_rssi_state = halbtc8723b2ant_wifi_rssi_state(btcoexist, +							  0, 2, 15, 0); +	wifi_rssi_state1 = halbtc8723b2ant_wifi_rssi_state(btcoexist, +							   1, 2, 40, 0); +	bt_rssi_state = halbtc8723b2ant_bt_rssi_state(2, 29, 0); + +	btcoexist->btc_get(btcoexist, BTC_GET_U1_AP_NUM, &ap_num); + +	/* define the office environment */ +	/* driver don't know AP num in Linux, so we will never enter this if */ +	if (ap_num >= 10 && BTC_RSSI_HIGH(wifi_rssi_state1)) { +		btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, +					  0x0); +		halbtc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); +		halbtc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); +		coex_table_with_type(btcoexist, NORMAL_EXEC, 0); +		halbtc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1); + +		/* sw mechanism */ +		btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); +		if (BTC_WIFI_BW_HT40 == wifi_bw) { +			halbtc8723b2ant_sw_mechanism1(btcoexist, true, false, +						      false, false); +			halbtc8723b2ant_sw_mechanism2(btcoexist, true, false, +						      true, 0x18); +		} else { +			halbtc8723b2ant_sw_mechanism1(btcoexist, false, false, +						      false, false); +			halbtc8723b2ant_sw_mechanism2(btcoexist, true, false, +						      true, 0x18); +		} +		return; +	} + +	btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); + +	halbtc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + +	if (halbtc8723b2ant_need_to_dec_bt_pwr(btcoexist)) +		halbtc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true); +	else +		halbtc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + +	coex_table_with_type(btcoexist, NORMAL_EXEC, 7); + +	if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || +	    (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) +		halbtc8723b2ant_tdma_duration_adjust(btcoexist, false, false, 1); +	else +		halbtc8723b2ant_tdma_duration_adjust(btcoexist, false, true, 1); + +	/* sw mechanism */ +	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); +	if (BTC_WIFI_BW_HT40 == wifi_bw) { +		if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || +		    (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +			halbtc8723b2ant_sw_mechanism1(btcoexist, true, false, +						      false, false); +			halbtc8723b2ant_sw_mechanism2(btcoexist, true, false, +						      false, 0x18); +		} else { +			halbtc8723b2ant_sw_mechanism1(btcoexist, true, false, +						      false, false); +			halbtc8723b2ant_sw_mechanism2(btcoexist, false, false, +						      false, 0x18); +		} +	} else { +		if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || +		    (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +			halbtc8723b2ant_sw_mechanism1(btcoexist, false, false, +						      false, false); +			halbtc8723b2ant_sw_mechanism2(btcoexist, true, false, +						      false, 0x18); +		} else { +			halbtc8723b2ant_sw_mechanism1(btcoexist, false, false, +						      false, false); +			halbtc8723b2ant_sw_mechanism2(btcoexist, false, false, +						      false, 0x18); +		} +	} +} + +static void halbtc8723b2ant_action_a2dp_pan_hs(struct btc_coexist *btcoexist) +{ +	u8 wifi_rssi_state; +	u32 wifi_bw; + +	wifi_rssi_state = halbtc8723b2ant_wifi_rssi_state(btcoexist, +							  0, 2, 15, 0); + +	btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); + +	halbtc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + +	if (halbtc8723b2ant_need_to_dec_bt_pwr(btcoexist)) +		halbtc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true); +	else +		halbtc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + +	coex_table_with_type(btcoexist, NORMAL_EXEC, 7); + +	halbtc8723b2ant_tdma_duration_adjust(btcoexist, false, true, 2); + +	/* sw mechanism */ +	btcoexist->btc_get(btcoexist, +		BTC_GET_U4_WIFI_BW, &wifi_bw); +	if (BTC_WIFI_BW_HT40 == wifi_bw) { +		if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || +		    (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +			halbtc8723b2ant_sw_mechanism1(btcoexist, true, false, +						      false, false); +			halbtc8723b2ant_sw_mechanism2(btcoexist, true, false, +						      false, 0x18); +		} else { +			halbtc8723b2ant_sw_mechanism1(btcoexist, true, false, +						      false, false); +			halbtc8723b2ant_sw_mechanism2(btcoexist, false, false, +						      false, 0x18); +		} +	} else { +		if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || +		    (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +			halbtc8723b2ant_sw_mechanism1(btcoexist, false, false, +						      false, false); +			halbtc8723b2ant_sw_mechanism2(btcoexist, true, false, +						      false, 0x18); +		} else { +			halbtc8723b2ant_sw_mechanism1(btcoexist, false, false, +						      false, false); +			halbtc8723b2ant_sw_mechanism2(btcoexist, false, false, +						      false, 0x18); +		} +	} +} + +static void halbtc8723b2ant_action_pan_edr(struct btc_coexist *btcoexist) +{ +	u8 wifi_rssi_state, bt_rssi_state; +	u32 wifi_bw; + +	wifi_rssi_state = halbtc8723b2ant_wifi_rssi_state(btcoexist, +							  0, 2, 15, 0); +	bt_rssi_state = halbtc8723b2ant_bt_rssi_state(2, 29, 0); + +	btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); + +	halbtc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + +	if (halbtc8723b2ant_need_to_dec_bt_pwr(btcoexist)) +		halbtc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true); +	else +		halbtc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + +	coex_table_with_type(btcoexist, NORMAL_EXEC, 10); + +	if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || +	    (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) +		halbtc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 1); +	else +		halbtc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 5); + +	/* sw mechanism */ +	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); +	if (BTC_WIFI_BW_HT40 == wifi_bw) { +		if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || +		    (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +			halbtc8723b2ant_sw_mechanism1(btcoexist, true, false, +						      false, false); +			halbtc8723b2ant_sw_mechanism2(btcoexist, true, false, +						      false, 0x18); +		} else { +			halbtc8723b2ant_sw_mechanism1(btcoexist, true, false, +						      false, false); +			halbtc8723b2ant_sw_mechanism2(btcoexist, false, false, +						      false, 0x18); +		} +	} else { +		if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || +		    (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +			halbtc8723b2ant_sw_mechanism1(btcoexist, false, false, +						      false, false); +			halbtc8723b2ant_sw_mechanism2(btcoexist, true, false, +						      false, 0x18); +		} else { +			halbtc8723b2ant_sw_mechanism1(btcoexist, false, false, +						      false, false); +			halbtc8723b2ant_sw_mechanism2(btcoexist, false, false, +						      false, 0x18); +		} +	} +} + +/*PAN(HS) only*/ +static void halbtc8723b2ant_action_pan_hs(struct btc_coexist *btcoexist) +{ +	u8 wifi_rssi_state; +	u32 wifi_bw; + +	wifi_rssi_state = halbtc8723b2ant_wifi_rssi_state(btcoexist, +							  0, 2, 15, 0); + +	btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); + +	halbtc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + +	if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || +	    (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) +		halbtc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true); +	else +		halbtc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + +	coex_table_with_type(btcoexist, NORMAL_EXEC, 7); + +	halbtc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1); + +	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); +	if (BTC_WIFI_BW_HT40 == wifi_bw) { +		if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || +		    (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +			halbtc8723b2ant_sw_mechanism1(btcoexist, true, false, +						      false, false); +			halbtc8723b2ant_sw_mechanism2(btcoexist, true, false, +						      false, 0x18); +		} else { +			halbtc8723b2ant_sw_mechanism1(btcoexist, true, false, +						      false, false); +			halbtc8723b2ant_sw_mechanism2(btcoexist, false, false, +						      false, 0x18); +		} +	} else { +		if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || +		    (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +			halbtc8723b2ant_sw_mechanism1(btcoexist, false, false, +						      false, false); +			halbtc8723b2ant_sw_mechanism2(btcoexist, true, false, +						      false, 0x18); +		} else { +			halbtc8723b2ant_sw_mechanism1(btcoexist, false, false, +						      false, false); +			halbtc8723b2ant_sw_mechanism2(btcoexist, false, false, +						      false, 0x18); +		} +	} +} + +/*PAN(EDR)+A2DP*/ +static void halbtc8723b2ant_action_pan_edr_a2dp(struct btc_coexist *btcoexist) +{ +	u8 wifi_rssi_state, bt_rssi_state; +	u32 wifi_bw; + +	wifi_rssi_state = halbtc8723b2ant_wifi_rssi_state(btcoexist, +							  0, 2, 15, 0); +	bt_rssi_state = halbtc8723b2ant_bt_rssi_state(2, 29, 0); + +	btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); + +	halbtc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + +	if (halbtc8723b2ant_need_to_dec_bt_pwr(btcoexist)) +		halbtc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true); +	else +		halbtc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + +	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + +	if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || +	    (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +		coex_table_with_type(btcoexist, NORMAL_EXEC, 12); +		if (BTC_WIFI_BW_HT40 == wifi_bw) +			halbtc8723b2ant_tdma_duration_adjust(btcoexist, false, +							     true, 3); +		else +			halbtc8723b2ant_tdma_duration_adjust(btcoexist, false, +							     false, 3); +	} else { +		coex_table_with_type(btcoexist, NORMAL_EXEC, 7); +		halbtc8723b2ant_tdma_duration_adjust(btcoexist, false, true, 3); +	} + +	/* sw mechanism	*/ +	if (BTC_WIFI_BW_HT40 == wifi_bw) { +		if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || +		    (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +			halbtc8723b2ant_sw_mechanism1(btcoexist, true, false, +						      false, false); +			halbtc8723b2ant_sw_mechanism2(btcoexist, true, false, +						      false, 0x18); +		} else { +			halbtc8723b2ant_sw_mechanism1(btcoexist, true, false, +						      false, false); +			halbtc8723b2ant_sw_mechanism2(btcoexist, false, false, +						      false, 0x18); +		} +	} else { +		if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || +		    (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +			halbtc8723b2ant_sw_mechanism1(btcoexist, false, false, +						      false, false); +			halbtc8723b2ant_sw_mechanism2(btcoexist, true, false, +						      false, 0x18); +		} else { +			halbtc8723b2ant_sw_mechanism1(btcoexist, false, false, +						      false, false); +			halbtc8723b2ant_sw_mechanism2(btcoexist, false, false, +						      false, 0x18); +		} +	} +} + +static void halbtc8723b2ant_action_pan_edr_hid(struct btc_coexist *btcoexist) +{ +	u8 wifi_rssi_state, bt_rssi_state; +	u32 wifi_bw; + +	wifi_rssi_state = halbtc8723b2ant_wifi_rssi_state(btcoexist, +							  0, 2, 15, 0); +	bt_rssi_state = halbtc8723b2ant_bt_rssi_state(2, 29, 0); +	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + +	if (halbtc8723b2ant_need_to_dec_bt_pwr(btcoexist)) +		halbtc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true); +	else +		halbtc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + +	if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || +	    (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +		if (BTC_WIFI_BW_HT40 == wifi_bw) { +			halbtc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, +							 3); +			coex_table_with_type(btcoexist, +							     NORMAL_EXEC, 11); +			btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, +						  0xfffff, 0x780); +		} else { +			halbtc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, +							 6); +			coex_table_with_type(btcoexist, +							     NORMAL_EXEC, 7); +			btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, +						  0xfffff, 0x0); +		} +		halbtc8723b2ant_tdma_duration_adjust(btcoexist, true, false, 2); +	} else { +		halbtc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); +		coex_table_with_type(btcoexist, NORMAL_EXEC, 11); +		btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, +					  0x0); +		halbtc8723b2ant_tdma_duration_adjust(btcoexist, true, true, 2); +	} + +	/* sw mechanism */ +	if (BTC_WIFI_BW_HT40 == wifi_bw) { +		if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || +		    (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +			halbtc8723b2ant_sw_mechanism1(btcoexist, true, true, +						      false, false); +			halbtc8723b2ant_sw_mechanism2(btcoexist, true, false, +						      false, 0x18); +		} else { +			halbtc8723b2ant_sw_mechanism1(btcoexist, true, true, +						      false, false); +			halbtc8723b2ant_sw_mechanism2(btcoexist, false, false, +						      false, 0x18); +		} +	} else { +		if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || +		    (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +			halbtc8723b2ant_sw_mechanism1(btcoexist, false, true, +						      false, false); +			halbtc8723b2ant_sw_mechanism2(btcoexist, true, false, +						      false, 0x18); +		} else { +			halbtc8723b2ant_sw_mechanism1(btcoexist, false, true, +						      false, false); +			halbtc8723b2ant_sw_mechanism2(btcoexist, false, false, +						      false, 0x18); +		} +	} +} + +/* HID+A2DP+PAN(EDR) */ +static void halbtc8723b2ant_action_hid_a2dp_pan_edr(struct btc_coexist *btcoexist) +{ +	u8 wifi_rssi_state, bt_rssi_state; +	u32 wifi_bw; + +	wifi_rssi_state = halbtc8723b2ant_wifi_rssi_state(btcoexist, +							  0, 2, 15, 0); +	bt_rssi_state = halbtc8723b2ant_bt_rssi_state(2, 29, 0); + +	btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); + +	halbtc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + +	if (halbtc8723b2ant_need_to_dec_bt_pwr(btcoexist)) +		halbtc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true); +	else +		halbtc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + +	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + +	coex_table_with_type(btcoexist, NORMAL_EXEC, 7); + +	if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || +	    (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +		if (BTC_WIFI_BW_HT40 == wifi_bw) +			halbtc8723b2ant_tdma_duration_adjust(btcoexist, true, +							     true, 2); +		else +			halbtc8723b2ant_tdma_duration_adjust(btcoexist, true, +							     false, 3); +	} else { +		halbtc8723b2ant_tdma_duration_adjust(btcoexist, true, true, 3); +	} + +	/* sw mechanism */ +	if (BTC_WIFI_BW_HT40 == wifi_bw) { +		if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || +		    (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +			halbtc8723b2ant_sw_mechanism1(btcoexist, true, true, +						      false, false); +			halbtc8723b2ant_sw_mechanism2(btcoexist, true, false, +						      false, 0x18); +		} else { +			halbtc8723b2ant_sw_mechanism1(btcoexist, true, true, +						      false, false); +			halbtc8723b2ant_sw_mechanism2(btcoexist, false, false, +						      false, 0x18); +		} +	} else { +		if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || +		    (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +			halbtc8723b2ant_sw_mechanism1(btcoexist, false, true, +						      false, false); +			halbtc8723b2ant_sw_mechanism2(btcoexist, true, false, +						      false, 0x18); +		} else { +			halbtc8723b2ant_sw_mechanism1(btcoexist, false, true, +						      false, false); +			halbtc8723b2ant_sw_mechanism2(btcoexist, false, false, +						      false, 0x18); +		} +	} +} + +static void halbtc8723b2ant_action_hid_a2dp(struct btc_coexist *btcoexist) +{ +	u8 wifi_rssi_state, bt_rssi_state; +	u32 wifi_bw; + +	wifi_rssi_state = halbtc8723b2ant_wifi_rssi_state(btcoexist, +							  0, 2, 15, 0); +	bt_rssi_state = halbtc8723b2ant_bt_rssi_state(2, 29, 0); + +	btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); + +	halbtc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + +	if (halbtc8723b2ant_need_to_dec_bt_pwr(btcoexist)) +		halbtc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true); +	else +		halbtc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + +	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + +	coex_table_with_type(btcoexist, NORMAL_EXEC, 7); + +	if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || +	    (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) +		halbtc8723b2ant_tdma_duration_adjust(btcoexist, true, false, 2); +	else +		halbtc8723b2ant_tdma_duration_adjust(btcoexist, true, true, 2); + +	/* sw mechanism */ +	if (BTC_WIFI_BW_HT40 == wifi_bw) { +		if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || +		    (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +			halbtc8723b2ant_sw_mechanism1(btcoexist, true, true, +						      false, false); +			halbtc8723b2ant_sw_mechanism2(btcoexist, true, false, +						      false, 0x18); +		} else { +			halbtc8723b2ant_sw_mechanism1(btcoexist, true, true, +						      false, false); +			halbtc8723b2ant_sw_mechanism2(btcoexist, false, false, +						      false, 0x18); +		} +	} else { +		if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || +		    (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +			halbtc8723b2ant_sw_mechanism1(btcoexist, false, true, +						      false, false); +			halbtc8723b2ant_sw_mechanism2(btcoexist, true, false, +						      false, 0x18); +		} else { +			halbtc8723b2ant_sw_mechanism1(btcoexist, false, true, +						      false, false); +			halbtc8723b2ant_sw_mechanism2(btcoexist, false, false, +						      false, 0x18); +		} +	} +} + +static void halbtc8723b2ant_run_coexist_mechanism(struct btc_coexist *btcoexist) +{ +	u8 algorithm = 0; + +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +		  "[BTCoex], RunCoexistMechanism() ===>\n"); + +	if (btcoexist->manual_control) { +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +			  "[BTCoex], RunCoexistMechanism(), return for Manual CTRL <===\n"); +		return; +	} + +	if (coex_sta->under_ips) { +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +			  "[BTCoex], wifi is under IPS !!!\n"); +		return; +	} + +	algorithm = halbtc8723b2ant_action_algorithm(btcoexist); +	if (coex_sta->c2h_bt_inquiry_page && +	    (BT_8723B_2ANT_COEX_ALGO_PANHS != algorithm)) { +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +			  "[BTCoex], BT is under inquiry/page scan !!\n"); +		halbtc8723b2ant_action_bt_inquiry(btcoexist); +		return; +	} else { +		if (coex_dm->need_recover_0x948) { +			coex_dm->need_recover_0x948 = false; +			btcoexist->btc_write_2byte(btcoexist, 0x948, +						   coex_dm->backup_0x948); +		} +	} + +	coex_dm->cur_algorithm = algorithm; +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, "[BTCoex], Algorithm = %d \n", +		  coex_dm->cur_algorithm); + +	if (halbtc8723b2ant_is_common_action(btcoexist)) { +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +			  "[BTCoex], Action 2-Ant common.\n"); +		coex_dm->auto_tdma_adjust = false; +	} else { +		if (coex_dm->cur_algorithm != coex_dm->pre_algorithm) { +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +				  "[BTCoex], preAlgorithm =%d, curAlgorithm =%d\n", coex_dm->pre_algorithm, +				  coex_dm->cur_algorithm); +			coex_dm->auto_tdma_adjust = false; +		} +		switch (coex_dm->cur_algorithm) { +		case BT_8723B_2ANT_COEX_ALGO_SCO: +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +				  "[BTCoex], Action 2-Ant, algorithm = SCO.\n"); +			halbtc8723b2ant_action_sco(btcoexist); +			break; +		case BT_8723B_2ANT_COEX_ALGO_HID: +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +				  "[BTCoex], Action 2-Ant, algorithm = HID.\n"); +			halbtc8723b2ant_action_hid(btcoexist); +			break; +		case BT_8723B_2ANT_COEX_ALGO_A2DP: +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +				  "[BTCoex], Action 2-Ant, algorithm = A2DP.\n"); +			halbtc8723b2ant_action_a2dp(btcoexist); +			break; +		case BT_8723B_2ANT_COEX_ALGO_A2DP_PANHS: +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +				  "[BTCoex], Action 2-Ant, algorithm = A2DP+PAN(HS).\n"); +			halbtc8723b2ant_action_a2dp_pan_hs(btcoexist); +			break; +		case BT_8723B_2ANT_COEX_ALGO_PANEDR: +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +				  "[BTCoex], Action 2-Ant, algorithm = PAN(EDR).\n"); +			halbtc8723b2ant_action_pan_edr(btcoexist); +			break; +		case BT_8723B_2ANT_COEX_ALGO_PANHS: +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +				  "[BTCoex], Action 2-Ant, algorithm = HS mode.\n"); +			halbtc8723b2ant_action_pan_hs(btcoexist); +				break; +		case BT_8723B_2ANT_COEX_ALGO_PANEDR_A2DP: +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +				  "[BTCoex], Action 2-Ant, algorithm = PAN+A2DP.\n"); +			halbtc8723b2ant_action_pan_edr_a2dp(btcoexist); +			break; +		case BT_8723B_2ANT_COEX_ALGO_PANEDR_HID: +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +				  "[BTCoex], Action 2-Ant, algorithm = PAN(EDR)+HID.\n"); +			halbtc8723b2ant_action_pan_edr_hid(btcoexist); +			break; +		case BT_8723B_2ANT_COEX_ALGO_HID_A2DP_PANEDR: +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +				  "[BTCoex], Action 2-Ant, algorithm = HID+A2DP+PAN.\n"); +			halbtc8723b2ant_action_hid_a2dp_pan_edr(btcoexist); +			break; +		case BT_8723B_2ANT_COEX_ALGO_HID_A2DP: +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +				  "[BTCoex], Action 2-Ant, algorithm = HID+A2DP.\n"); +			halbtc8723b2ant_action_hid_a2dp(btcoexist); +			break; +		default: +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +				  "[BTCoex], Action 2-Ant, algorithm = coexist All Off!!\n"); +			halbtc8723b2ant_coex_alloff(btcoexist); +			break; +		} +		coex_dm->pre_algorithm = coex_dm->cur_algorithm; +	} +} + +static void halbtc8723b2ant_wifioff_hwcfg(struct btc_coexist *btcoexist) +{ +	/* set wlan_act to low */ +	btcoexist->btc_write_1byte(btcoexist, 0x76e, 0x4); +	/* Force GNT_BT to High */ +	btcoexist->btc_write_1byte_bitmask(btcoexist, 0x765, 0x18, 0x3); +	/* BT select s0/s1 is controlled by BT */ +	btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, 0x20, 0x0); +} + +/********************************************************************* + *  work around function start with wa_halbtc8723b2ant_ + *********************************************************************/ +/********************************************************************* + *  extern function start with EXhalbtc8723b2ant_ + *********************************************************************/ +void ex92e_halbtc8723b2ant_init_hwconfig(struct btc_coexist *btcoexist) +{ +	u8 u8tmp = 0; + +	BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, +		  "[BTCoex], 2Ant Init HW Config!!\n"); +	coex_dm->bt_rf0x1e_backup = +		btcoexist->btc_get_rf_reg(btcoexist, BTC_RF_A, 0x1e, 0xfffff); + +	/* 0x790[5:0] = 0x5 */ +	u8tmp = btcoexist->btc_read_1byte(btcoexist, 0x790); +	u8tmp &= 0xc0; +	u8tmp |= 0x5; +	btcoexist->btc_write_1byte(btcoexist, 0x790, u8tmp); + +	/*Antenna config	*/ +	halbtc8723b2ant_set_ant_path(btcoexist, BTC_ANT_WIFI_AT_MAIN, +				     true, false); + + + +	/* PTA parameter */ +	coex_table_with_type(btcoexist, FORCE_EXEC, 0); + +	/* Enable counter statistics */ +	/*0x76e[3] = 1, WLAN_Act control by PTA*/ +	btcoexist->btc_write_1byte(btcoexist, 0x76e, 0xc); +	btcoexist->btc_write_1byte(btcoexist, 0x778, 0x3); +	btcoexist->btc_write_1byte_bitmask(btcoexist, 0x40, 0x20, 0x1); +} + +void ex92e_halbtc8723b2ant_init_coex_dm(struct btc_coexist *btcoexist) +{ +	BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, +		  "[BTCoex], Coex Mechanism Init!!\n"); +	halbtc8723b2ant_init_coex_dm(btcoexist); +} + +void ex_halbtc8723b2ant92e_display_coex_info(struct btc_coexist *btcoexist) +{ +	struct btc_board_info *board_info = &btcoexist->board_info; +	struct btc_stack_info *stack_info = &btcoexist->stack_info; +	struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; +	u8 *cli_buf = btcoexist->cli_buf; +	u8 u8tmp[4], i, bt_info_ext, ps_tdma_case = 0; +	u32 u32tmp[4]; +	bool roam = false, scan = false; +	bool link = false, wifi_under_5g = false; +	bool bt_hs_on = false, wifi_busy = false; +	s32 wifi_rssi = 0, bt_hs_rssi = 0; +	u32 wifi_bw, wifi_traffic_dir, fa_ofdm, fa_cck; +	u8 wifi_dot11_chnl, wifi_hs_chnl; +	u32 fw_ver = 0, bt_patch_ver = 0; +	u8 ap_num = 0; + +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, +		   "\r\n ============[BT Coexist info] ============"); +	CL_PRINTF(cli_buf); + +	if (btcoexist->manual_control) { +		CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, +			   "\r\n ==========[Under Manual Control] ============"); +		CL_PRINTF(cli_buf); +		CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, +			   "\r\n =========================================="); +		CL_PRINTF(cli_buf); +	} + +	if (!board_info->bt_exist) { +		CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n BT not exists !!!"); +		CL_PRINTF(cli_buf); +		return; +	} + +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d ", +		   "Ant PG number/ Ant mechanism: ", +		   board_info->pg_ant_num, board_info->btdm_ant_num); +	CL_PRINTF(cli_buf); + +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s / %d", +		   "BT stack/ hci ext ver", +		   ((stack_info->profile_notified) ? "Yes" : "No"), +		   stack_info->hci_version); +	CL_PRINTF(cli_buf); + +	btcoexist->btc_get(btcoexist, BTC_GET_U4_BT_PATCH_VER, &bt_patch_ver); +	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver); +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, +		   "\r\n %-35s = %d_%x/ 0x%x/ 0x%x(%d)", +		   "CoexVer/ fw_ver/ PatchVer", +		   glcoex_ver_date_8723b_2ant, glcoex_ver_8723b_2ant, +		   fw_ver, bt_patch_ver, bt_patch_ver); +	CL_PRINTF(cli_buf); + +	btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); +	btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_DOT11_CHNL, +			   &wifi_dot11_chnl); +	btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_HS_CHNL, &wifi_hs_chnl); + +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d / %d(%d)", +		   "Dot11 channel / HsChnl(HsMode)", +		   wifi_dot11_chnl, wifi_hs_chnl, bt_hs_on); +	CL_PRINTF(cli_buf); + +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x ", +		   "H2C Wifi inform bt chnl Info", coex_dm->wifi_chnl_info[0], +		   coex_dm->wifi_chnl_info[1], coex_dm->wifi_chnl_info[2]); +	CL_PRINTF(cli_buf); + +	btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifi_rssi); +	btcoexist->btc_get(btcoexist, BTC_GET_S4_HS_RSSI, &bt_hs_rssi); +	btcoexist->btc_get(btcoexist, BTC_GET_U1_AP_NUM, &ap_num); +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d", +		   "Wifi rssi/ HS rssi/ AP#", wifi_rssi, bt_hs_rssi, ap_num); +	CL_PRINTF(cli_buf); + +	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan); +	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link); +	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam); +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d ", +		   "Wifi link/ roam/ scan", link, roam, scan); +	CL_PRINTF(cli_buf); + +	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); +	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); +	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); +	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_TRAFFIC_DIRECTION, +			   &wifi_traffic_dir); +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s / %s/ %s ", +		   "Wifi status", (wifi_under_5g ? "5G" : "2.4G"), +		   ((BTC_WIFI_BW_LEGACY == wifi_bw) ? "Legacy" : +		   (((BTC_WIFI_BW_HT40 == wifi_bw) ? "HT40" : "HT20"))), +		   ((!wifi_busy) ? "idle" : +		   ((BTC_WIFI_TRAFFIC_TX == wifi_traffic_dir) ? +		   "uplink" : "downlink"))); +	CL_PRINTF(cli_buf); + +	CL_PRINTF(cli_buf); + +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d / %d / %d / %d", +		   "SCO/HID/PAN/A2DP", +		   bt_link_info->sco_exist, bt_link_info->hid_exist, +		   bt_link_info->pan_exist, bt_link_info->a2dp_exist); +	CL_PRINTF(cli_buf); +	btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_BT_LINK_INFO); + +	bt_info_ext = coex_sta->bt_info_ext; +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s", +		   "BT Info A2DP rate", +		   (bt_info_ext & BIT(0)) ? "Basic rate" : "EDR rate"); +	CL_PRINTF(cli_buf); + +	for (i = 0; i < BT_INFO_SRC_8723B_2ANT_MAX; i++) { +		if (coex_sta->bt_info_c2h_cnt[i]) { +			CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, +				   "\r\n %-35s = %02x %02x %02x %02x %02x %02x %02x(%d)", +				   glbt_info_src_8723b_2ant[i], +				   coex_sta->bt_info_c2h[i][0], +				   coex_sta->bt_info_c2h[i][1], +				   coex_sta->bt_info_c2h[i][2], +				   coex_sta->bt_info_c2h[i][3], +				   coex_sta->bt_info_c2h[i][4], +				   coex_sta->bt_info_c2h[i][5], +				   coex_sta->bt_info_c2h[i][6], +				   coex_sta->bt_info_c2h_cnt[i]); +			CL_PRINTF(cli_buf); +		} +	} + +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s/%s", +		   "PS state, IPS/LPS", +		   ((coex_sta->under_ips ? "IPS ON" : "IPS OFF")), +		   ((coex_sta->under_lps ? "LPS ON" : "LPS OFF"))); +	CL_PRINTF(cli_buf); +	btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_FW_PWR_MODE_CMD); + +	/* Sw mechanism	*/ +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, +		   "\r\n %-35s", "============[Sw mechanism] ============"); +	CL_PRINTF(cli_buf); +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d ", +		   "SM1[ShRf/ LpRA/ LimDig]", coex_dm->cur_rf_rx_lpf_shrink, +		   coex_dm->cur_low_penalty_ra, coex_dm->limited_dig); +	CL_PRINTF(cli_buf); +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d(0x%x) ", +		   "SM2[AgcT/ AdcB/ SwDacSwing(lvl)]", +		   coex_dm->cur_agc_table_en, coex_dm->cur_adc_back_off, +		   coex_dm->cur_dac_swing_on, coex_dm->cur_dac_swing_lvl); +	CL_PRINTF(cli_buf); + +	/* Fw mechanism	*/ +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", +		   "============[Fw mechanism] ============"); +	CL_PRINTF(cli_buf); + +	ps_tdma_case = coex_dm->cur_ps_tdma; +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, +		   "\r\n %-35s = %02x %02x %02x %02x %02x case-%d (auto:%d)", +		   "PS TDMA", coex_dm->ps_tdma_para[0], +		   coex_dm->ps_tdma_para[1], coex_dm->ps_tdma_para[2], +		   coex_dm->ps_tdma_para[3], coex_dm->ps_tdma_para[4], +		   ps_tdma_case, coex_dm->auto_tdma_adjust); +	CL_PRINTF(cli_buf); + +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d ", +		   "DecBtPwr/ IgnWlanAct", coex_dm->cur_dec_bt_pwr, +		   coex_dm->cur_ignore_wlan_act); +	CL_PRINTF(cli_buf); + +	/* Hw setting */ +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", +		   "============[Hw setting] ============"); +	CL_PRINTF(cli_buf); + +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", +		   "RF-A, 0x1e initVal", coex_dm->bt_rf0x1e_backup); +	CL_PRINTF(cli_buf); + +	u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x778); +	u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x880); +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", +		   "0x778/0x880[29:25]", u8tmp[0], +		   (u32tmp[0]&0x3e000000) >> 25); +	CL_PRINTF(cli_buf); + +	u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x948); +	u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x67); +	u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0x765); +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", +		   "0x948/ 0x67[5] / 0x765", +		   u32tmp[0], ((u8tmp[0]&0x20) >> 5), u8tmp[1]); +	CL_PRINTF(cli_buf); + +	u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x92c); +	u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x930); +	u32tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0x944); +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", +		   "0x92c[1:0]/ 0x930[7:0]/0x944[1:0]", +		   u32tmp[0]&0x3, u32tmp[1]&0xff, u32tmp[2]&0x3); +	CL_PRINTF(cli_buf); + +	u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x39); +	u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0x40); +	u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x4c); +	u8tmp[2] = btcoexist->btc_read_1byte(btcoexist, 0x64); +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", +		   "0x38[11]/0x40/0x4c[24:23]/0x64[0]", +		   ((u8tmp[0] & 0x8)>>3), u8tmp[1], +		   ((u32tmp[0]&0x01800000)>>23), u8tmp[2]&0x1); +	CL_PRINTF(cli_buf); + +	u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x550); +	u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x522); +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", +		   "0x550(bcn ctrl)/0x522", u32tmp[0], u8tmp[0]); +	CL_PRINTF(cli_buf); + +	u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xc50); +	u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x49c); +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", +		   "0xc50(dig)/0x49c(null-drop)", u32tmp[0]&0xff, u8tmp[0]); +	CL_PRINTF(cli_buf); + +	u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xda0); +	u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0xda4); +	u32tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0xda8); +	u32tmp[3] = btcoexist->btc_read_4byte(btcoexist, 0xcf0); + +	u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0xa5b); +	u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0xa5c); + +	fa_ofdm = ((u32tmp[0]&0xffff0000) >> 16) + +		  ((u32tmp[1]&0xffff0000) >> 16) + +		   (u32tmp[1] & 0xffff) + +		   (u32tmp[2] & 0xffff) + +		  ((u32tmp[3]&0xffff0000) >> 16) + +		   (u32tmp[3] & 0xffff); +	fa_cck = (u8tmp[0] << 8) + u8tmp[1]; + +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", +		   "OFDM-CCA/OFDM-FA/CCK-FA", +		   u32tmp[0]&0xffff, fa_ofdm, fa_cck); +	CL_PRINTF(cli_buf); + +	u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x6c0); +	u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x6c4); +	u32tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0x6c8); +	u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x6cc); +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, +		   "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", +		   "0x6c0/0x6c4/0x6c8/0x6cc(coexTable)", \ +		   u32tmp[0], u32tmp[1], u32tmp[2], u8tmp[0]); +	CL_PRINTF(cli_buf); + +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", +		   "0x770(high-pri rx/tx)", +		   coex_sta->high_priority_rx, coex_sta->high_priority_tx); +	CL_PRINTF(cli_buf); +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", +		   "0x774(low-pri rx/tx)", coex_sta->low_priority_rx, +		   coex_sta->low_priority_tx); +	CL_PRINTF(cli_buf); +#if (BT_AUTO_REPORT_ONLY_8723B_2ANT == 1) +	halbtc8723b2ant_monitor_bt_ctr(btcoexist); +#endif +	btcoexist->btc_disp_dbg_msg(btcoexist, +	BTC_DBG_DISP_COEX_STATISTICS); +} + +void ex92e_halbtc8723b2ant_ips_notify(struct btc_coexist *btcoexist, u8 type) +{ +	if (BTC_IPS_ENTER == type) { +		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, +			  "[BTCoex], IPS ENTER notify\n"); +		coex_sta->under_ips = true; +		halbtc8723b2ant_wifioff_hwcfg(btcoexist); +		halbtc8723b2ant_ignore_wlan_act(btcoexist, FORCE_EXEC, true); +		halbtc8723b2ant_coex_alloff(btcoexist); +	} else if (BTC_IPS_LEAVE == type) { +		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, +			  "[BTCoex], IPS LEAVE notify\n"); +		coex_sta->under_ips = false; +		ex92e_halbtc8723b2ant_init_hwconfig(btcoexist); +		halbtc8723b2ant_init_coex_dm(btcoexist); +		halbtc8723b2ant_query_bt_info(btcoexist); +	} +} + +void ex92e_halbtc8723b2ant_lps_notify(struct btc_coexist *btcoexist, u8 type) +{ +	if (BTC_LPS_ENABLE == type) { +		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, +			  "[BTCoex], LPS ENABLE notify\n"); +		coex_sta->under_lps = true; +	} else if (BTC_LPS_DISABLE == type) { +		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, +			  "[BTCoex], LPS DISABLE notify\n"); +		coex_sta->under_lps = false; +	} +} + +void ex92e_halbtc8723b2ant_scan_notify(struct btc_coexist *btcoexist, u8 type) +{ +	if (BTC_SCAN_START == type) +		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, +			  "[BTCoex], SCAN START notify\n"); +	else if (BTC_SCAN_FINISH == type) +		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, +			  "[BTCoex], SCAN FINISH notify\n"); +} + +void ex92e_halbtc8723b2ant_connect_notify(struct btc_coexist *btcoexist, u8 type) +{ +	if (BTC_ASSOCIATE_START == type) +		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, +			  "[BTCoex], CONNECT START notify\n"); +	else if (BTC_ASSOCIATE_FINISH == type) +		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, +			  "[BTCoex], CONNECT FINISH notify\n"); +} + +void ex92e_halbtc8723b2ant_media_status_notify(struct btc_coexist *btcoexist, +					    u8 type) +{ +	u8 h2c_parameter[3] = {0}; +	u32 wifi_bw; +	u8 wifi_central_chnl; + +	if (BTC_MEDIA_CONNECT == type) +		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, +			  "[BTCoex], MEDIA connect notify\n"); +	else +		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, +			  "[BTCoex], MEDIA disconnect notify\n"); + +	/* only 2.4G we need to inform bt the chnl mask */ +	btcoexist->btc_get(btcoexist, +		BTC_GET_U1_WIFI_CENTRAL_CHNL, &wifi_central_chnl); +	if ((BTC_MEDIA_CONNECT == type) && +	    (wifi_central_chnl <= 14)) { +		h2c_parameter[0] = 0x1; +		h2c_parameter[1] = wifi_central_chnl; +		btcoexist->btc_get(btcoexist, +			BTC_GET_U4_WIFI_BW, &wifi_bw); +		if (BTC_WIFI_BW_HT40 == wifi_bw) +			h2c_parameter[2] = 0x30; +		else +			h2c_parameter[2] = 0x20; +	} + +	coex_dm->wifi_chnl_info[0] = h2c_parameter[0]; +	coex_dm->wifi_chnl_info[1] = h2c_parameter[1]; +	coex_dm->wifi_chnl_info[2] = h2c_parameter[2]; + +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, +		  "[BTCoex], FW write 0x66 = 0x%x\n", +		  h2c_parameter[0] << 16 | h2c_parameter[1] << 8 | +		  h2c_parameter[2]); + +	btcoexist->btc_fill_h2c(btcoexist, 0x66, 3, h2c_parameter); +} + +void ex92e_halbtc8723b2ant_special_packet_notify(struct btc_coexist *btcoexist, +					      u8 type) +{ +	if (type == BTC_PACKET_DHCP) +		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, +			  "[BTCoex], DHCP Packet notify\n"); +} + +void ex92e_halbtc8723b2ant_bt_info_notify(struct btc_coexist *btcoexist, +				       u8 *tmpbuf, u8 length) +{ +	u8 btInfo = 0; +	u8 i, rsp_source = 0; +	bool bt_busy = false, limited_dig = false; +	bool wifi_connected = false; + +	coex_sta->c2h_bt_info_req_sent = false; + +	rsp_source = tmpbuf[0]&0xf; +	if (rsp_source >= BT_INFO_SRC_8723B_2ANT_MAX) +		rsp_source = BT_INFO_SRC_8723B_2ANT_WIFI_FW; +	coex_sta->bt_info_c2h_cnt[rsp_source]++; + +	BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, +		  "[BTCoex], Bt info[%d], length =%d, hex data =[", +		  rsp_source, length); +	for (i = 0; i < length; i++) { +		coex_sta->bt_info_c2h[rsp_source][i] = tmpbuf[i]; +		if (i == 1) +			btInfo = tmpbuf[i]; +		if (i == length-1) +			BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, +				  "0x%02x]\n", tmpbuf[i]); +		else +			BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, +				  "0x%02x, ", tmpbuf[i]); +	} + +	if (btcoexist->manual_control) { +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +			  "[BTCoex], BtInfoNotify(), return for Manual CTRL<===\n"); +		return; +	} + +	if (BT_INFO_SRC_8723B_2ANT_WIFI_FW != rsp_source) { +		coex_sta->bt_retry_cnt =	/* [3:0]*/ +			coex_sta->bt_info_c2h[rsp_source][2] & 0xf; + +		coex_sta->bt_rssi = +			coex_sta->bt_info_c2h[rsp_source][3] * 2 + 10; + +		coex_sta->bt_info_ext = +			coex_sta->bt_info_c2h[rsp_source][4]; + +		/* Here we need to resend some wifi info to BT +		     because bt is reset and loss of the info.*/ +		if ((coex_sta->bt_info_ext & BIT(1))) { +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +				  "[BTCoex], BT ext info bit1 check, send wifi BW&Chnl to BT!!\n"); +			btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, +					   &wifi_connected); +			if (wifi_connected) +				ex92e_halbtc8723b2ant_media_status_notify( +							btcoexist, +							BTC_MEDIA_CONNECT); +			else +				ex92e_halbtc8723b2ant_media_status_notify( +							btcoexist, +							BTC_MEDIA_DISCONNECT); +		} + +		if ((coex_sta->bt_info_ext & BIT(3))) { +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +				  "[BTCoex], BT ext info bit3 check, set BT NOT to ignore Wlan active!!\n"); +			halbtc8723b2ant_ignore_wlan_act(btcoexist, FORCE_EXEC, +							false); +		} else { +			/* BT already NOT ignore Wlan active, do nothing here.*/ +		} +#if (BT_AUTO_REPORT_ONLY_8723B_2ANT == 0) +		if ((coex_sta->bt_info_ext & BIT(4))) { +			/* BT auto report already enabled, do nothing*/ +		} else { +			halbtc8723b2ant_bt_auto_report(btcoexist, FORCE_EXEC, +						       true); +		} +#endif +	} + +	/* check BIT(2) first ==> check if bt is under inquiry or page scan*/ +	if (btInfo & BT_INFO_8723B_2ANT_B_INQ_PAGE) +		coex_sta->c2h_bt_inquiry_page = true; +	else +		coex_sta->c2h_bt_inquiry_page = false; + +	/* set link exist status*/ +	if (!(btInfo & BT_INFO_8723B_2ANT_B_CONNECTION)) { +		coex_sta->bt_link_exist = false; +		coex_sta->pan_exist = false; +		coex_sta->a2dp_exist = false; +		coex_sta->hid_exist = false; +		coex_sta->sco_exist = false; +	} else {/*  connection exists */ +		coex_sta->bt_link_exist = true; +		if (btInfo & BT_INFO_8723B_2ANT_B_FTP) +			coex_sta->pan_exist = true; +		else +			coex_sta->pan_exist = false; +		if (btInfo & BT_INFO_8723B_2ANT_B_A2DP) +			coex_sta->a2dp_exist = true; +		else +			coex_sta->a2dp_exist = false; +		if (btInfo & BT_INFO_8723B_2ANT_B_HID) +			coex_sta->hid_exist = true; +		else +			coex_sta->hid_exist = false; +		if (btInfo & BT_INFO_8723B_2ANT_B_SCO_ESCO) +			coex_sta->sco_exist = true; +		else +			coex_sta->sco_exist = false; +	} + +	halbtc8723b2ant_update_bt_link_info(btcoexist); + +	if (!(btInfo & BT_INFO_8723B_2ANT_B_CONNECTION)) { +		coex_dm->bt_status = BT_8723B_2ANT_BT_STATUS_NON_CONNECTED_IDLE; +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +			  "[BTCoex], BtInfoNotify(), BT Non-Connected idle!!!\n"); +	/* connection exists but no busy */ +	} else if (btInfo == BT_INFO_8723B_2ANT_B_CONNECTION) { +		coex_dm->bt_status = BT_8723B_2ANT_BT_STATUS_CONNECTED_IDLE; +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +			  "[BTCoex], BtInfoNotify(), BT Connected-idle!!!\n"); +	} else if ((btInfo & BT_INFO_8723B_2ANT_B_SCO_ESCO) || +		   (btInfo & BT_INFO_8723B_2ANT_B_SCO_BUSY)) { +		coex_dm->bt_status = +			BT_8723B_2ANT_BT_STATUS_SCO_BUSY; +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +			  "[BTCoex], BtInfoNotify(), BT SCO busy!!!\n"); +	} else if (btInfo&BT_INFO_8723B_2ANT_B_ACL_BUSY) { +		coex_dm->bt_status = +			BT_8723B_2ANT_BT_STATUS_ACL_BUSY; +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +			  "[BTCoex], BtInfoNotify(), BT ACL busy!!!\n"); +	} else { +		coex_dm->bt_status = BT_8723B_2ANT_BT_STATUS_MAX; +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +			  "[BTCoex], BtInfoNotify(), BT Non-Defined state!!!\n"); +	} + +	if ((BT_8723B_2ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) || +	    (BT_8723B_2ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) || +	    (BT_8723B_2ANT_BT_STATUS_ACL_SCO_BUSY == coex_dm->bt_status)) { +		bt_busy = true; +		limited_dig = true; +	} else { +		bt_busy = false; +		limited_dig = false; +	} + +	btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_TRAFFIC_BUSY, &bt_busy); + +	coex_dm->limited_dig = limited_dig; +	btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_LIMITED_DIG, &limited_dig); + +	halbtc8723b2ant_run_coexist_mechanism(btcoexist); +} + +void ex92e_halbtc8723b2ant_halt_notify(struct btc_coexist *btcoexist) +{ +	BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, "[BTCoex], Halt notify\n"); + +	halbtc8723b2ant_wifioff_hwcfg(btcoexist); +	halbtc8723b2ant_ignore_wlan_act(btcoexist, FORCE_EXEC, true); +	ex92e_halbtc8723b2ant_media_status_notify(btcoexist, BTC_MEDIA_DISCONNECT); +} + +void ex92e_halbtc8723b2ant_periodical(struct btc_coexist *btcoexist) +{ +	struct btc_board_info *board_info = &btcoexist->board_info; +	struct btc_stack_info *stack_info = &btcoexist->stack_info; +	static u8 dis_ver_info_cnt; +	u32 fw_ver = 0, bt_patch_ver = 0; + +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +		  "[BTCoex], ========================== Periodical ===========================\n"); + +	if (dis_ver_info_cnt <= 5) { +		dis_ver_info_cnt += 1; +		BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, +			  "[BTCoex], ****************************************************************\n"); +		BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, +			  "[BTCoex], Ant PG Num/ Ant Mech/ Ant Pos = %d/%d/%d\n", board_info->pg_ant_num, +			  board_info->btdm_ant_num, board_info->btdm_ant_pos); +		BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, +			  "[BTCoex], BT stack/hci ext ver = %s/%d\n", +			  ((stack_info->profile_notified) ? "Yes" : "No"), +			  stack_info->hci_version); +		btcoexist->btc_get(btcoexist, BTC_GET_U4_BT_PATCH_VER, +				   &bt_patch_ver); +		btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver); +		BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, +			  "[BTCoex], CoexVer/fw_ver/PatchVer = %d_%x/0x%x/0x%x(%d)\n", +			  glcoex_ver_date_8723b_2ant, glcoex_ver_8723b_2ant, +			  fw_ver, bt_patch_ver, bt_patch_ver); +		BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, +			  "[BTCoex], ****************************************************************\n"); +	} + +#if (BT_AUTO_REPORT_ONLY_8723B_2ANT == 0) +	halbtc8723b2ant_query_bt_info(btcoexist); +	halbtc8723b2ant_monitor_bt_ctr(btcoexist); +	halbtc8723b2ant_monitor_bt_enable_disable(btcoexist); +#else +	if (is_wifi_status_changed(btcoexist) || +	    coex_dm->auto_tdma_adjust) +		halbtc8723b2ant_run_coexist_mechanism(btcoexist); +#endif +} diff --git a/drivers/staging/rtl8192ee/btcoexist/halbtc8723b2ant.h b/drivers/staging/rtl8192ee/btcoexist/halbtc8723b2ant.h new file mode 100644 index 00000000000..8437e1c3ecd --- /dev/null +++ b/drivers/staging/rtl8192ee/btcoexist/halbtc8723b2ant.h @@ -0,0 +1,145 @@ +/************************************************************************ + * The following is for 8723B 2Ant BT Co-exist definition + ************************************************************************/ +#define	BT_AUTO_REPORT_ONLY_8723B_2ANT			1 + + +#define	BT_INFO_8723B_2ANT_B_FTP			BIT(7) +#define	BT_INFO_8723B_2ANT_B_A2DP			BIT(6) +#define	BT_INFO_8723B_2ANT_B_HID			BIT(5) +#define	BT_INFO_8723B_2ANT_B_SCO_BUSY			BIT(4) +#define	BT_INFO_8723B_2ANT_B_ACL_BUSY			BIT(3) +#define	BT_INFO_8723B_2ANT_B_INQ_PAGE			BIT(2) +#define	BT_INFO_8723B_2ANT_B_SCO_ESCO			BIT(1) +#define	BT_INFO_8723B_2ANT_B_CONNECTION			BIT(0) + +#define BTC_RSSI_COEX_THRESH_TOL_8723B_2ANT		2 + +enum BT_INFO_SRC_8723B_2ANT { +	BT_INFO_SRC_8723B_2ANT_WIFI_FW			= 0x0, +	BT_INFO_SRC_8723B_2ANT_BT_RSP			= 0x1, +	BT_INFO_SRC_8723B_2ANT_BT_ACTIVE_SEND		= 0x2, +	BT_INFO_SRC_8723B_2ANT_MAX +}; + +enum BT_8723B_2ANT_BT_STATUS { +	BT_8723B_2ANT_BT_STATUS_NON_CONNECTED_IDLE	= 0x0, +	BT_8723B_2ANT_BT_STATUS_CONNECTED_IDLE		= 0x1, +	BT_8723B_2ANT_BT_STATUS_INQ_PAGE		= 0x2, +	BT_8723B_2ANT_BT_STATUS_ACL_BUSY		= 0x3, +	BT_8723B_2ANT_BT_STATUS_SCO_BUSY		= 0x4, +	BT_8723B_2ANT_BT_STATUS_ACL_SCO_BUSY		= 0x5, +	BT_8723B_2ANT_BT_STATUS_MAX +}; + +enum BT_8723B_2ANT_COEX_ALGO { +	BT_8723B_2ANT_COEX_ALGO_UNDEFINED		= 0x0, +	BT_8723B_2ANT_COEX_ALGO_SCO			= 0x1, +	BT_8723B_2ANT_COEX_ALGO_HID			= 0x2, +	BT_8723B_2ANT_COEX_ALGO_A2DP			= 0x3, +	BT_8723B_2ANT_COEX_ALGO_A2DP_PANHS		= 0x4, +	BT_8723B_2ANT_COEX_ALGO_PANEDR			= 0x5, +	BT_8723B_2ANT_COEX_ALGO_PANHS			= 0x6, +	BT_8723B_2ANT_COEX_ALGO_PANEDR_A2DP		= 0x7, +	BT_8723B_2ANT_COEX_ALGO_PANEDR_HID		= 0x8, +	BT_8723B_2ANT_COEX_ALGO_HID_A2DP_PANEDR		= 0x9, +	BT_8723B_2ANT_COEX_ALGO_HID_A2DP		= 0xa, +	BT_8723B_2ANT_COEX_ALGO_MAX			= 0xb, +}; + +struct coex_dm_8723b_2ant { +	/* fw mechanism */ +	bool pre_dec_bt_pwr; +	bool cur_dec_bt_pwr; +	u8 pre_fw_dac_swing_lvl; +	u8 cur_fw_dac_swing_lvl; +	bool cur_ignore_wlan_act; +	bool pre_ignore_wlan_act; +	u8 pre_ps_tdma; +	u8 cur_ps_tdma; +	u8 ps_tdma_para[5]; +	u8 ps_tdma_du_adj_type; +	bool reset_tdma_adjust; +	bool auto_tdma_adjust; +	bool pre_ps_tdma_on; +	bool cur_ps_tdma_on; +	bool pre_bt_auto_report; +	bool cur_bt_auto_report; + +	/* sw mechanism */ +	bool pre_rf_rx_lpf_shrink; +	bool cur_rf_rx_lpf_shrink; +	u32 bt_rf0x1e_backup; +	bool pre_low_penalty_ra; +	bool cur_low_penalty_ra; +	bool pre_dac_swing_on; +	u32 pre_dac_swing_lvl; +	bool cur_dac_swing_on; +	u32 cur_dac_swing_lvl; +	bool pre_adc_back_off; +	bool cur_adc_back_off; +	bool pre_agc_table_en; +	bool cur_agc_table_en; +	u32 pre_val0x6c0; +	u32 cur_val0x6c0; +	u32 pre_val0x6c4; +	u32 cur_val0x6c4; +	u32 pre_val0x6c8; +	u32 cur_val0x6c8; +	u8 pre_val0x6cc; +	u8 cur_val0x6cc; +	bool limited_dig; + +	/* algorithm related */ +	u8 pre_algorithm; +	u8 cur_algorithm; +	u8 bt_status; +	u8 wifi_chnl_info[3]; + +	bool need_recover_0x948; +	u16 backup_0x948; +}; + +struct coex_sta_8723b_2ant { +	bool bt_link_exist; +	bool sco_exist; +	bool a2dp_exist; +	bool hid_exist; +	bool pan_exist; + +	bool under_lps; +	bool under_ips; +	u32 high_priority_tx; +	u32 high_priority_rx; +	u32 low_priority_tx; +	u32 low_priority_rx; +	u8 bt_rssi; +	u8 pre_bt_rssi_state; +	u8 pre_wifi_rssi_state[4]; +	bool c2h_bt_info_req_sent; +	u8 bt_info_c2h[BT_INFO_SRC_8723B_2ANT_MAX][10]; +	u32 bt_info_c2h_cnt[BT_INFO_SRC_8723B_2ANT_MAX]; +	bool c2h_bt_inquiry_page; +	u8 bt_retry_cnt; +	u8 bt_info_ext; +}; + +/********************************************************************* + * The following is interface which will notify coex module. + *********************************************************************/ +void ex92e_halbtc8723b2ant_init_hwconfig(struct btc_coexist *btcoexist); +void ex92e_halbtc8723b2ant_init_coex_dm(struct btc_coexist *btcoexist); +void ex92e_halbtc8723b2ant_ips_notify(struct btc_coexist *btcoexist, u8 type); +void ex92e_halbtc8723b2ant_lps_notify(struct btc_coexist *btcoexist, u8 type); +void ex92e_halbtc8723b2ant_scan_notify(struct btc_coexist *btcoexist, u8 type); +void ex92e_halbtc8723b2ant_connect_notify(struct btc_coexist *btcoexist, +					  u8 type); +void ex92e_halbtc8723b2ant_media_status_notify(struct btc_coexist *btcoexist, +					       u8 type); +void ex92e_halbtc8723b2ant_special_packet_notify(struct btc_coexist *btcoexist, +						 u8 type); +void ex92e_halbtc8723b2ant_bt_info_notify(struct btc_coexist *btcoexist, +					  u8 *tmpbuf, u8 length); +void ex92e_halbtc8723b2ant_halt_notify(struct btc_coexist *btcoexist); +void ex92e_halbtc8723b2ant_periodical(struct btc_coexist *btcoexist); +void ex_halbtc8723b2ant92e_display_coex_info(struct btc_coexist *btcoexist); diff --git a/drivers/staging/rtl8192ee/btcoexist/halbtc8821a1ant.c b/drivers/staging/rtl8192ee/btcoexist/halbtc8821a1ant.c new file mode 100644 index 00000000000..fb5286387d8 --- /dev/null +++ b/drivers/staging/rtl8192ee/btcoexist/halbtc8821a1ant.c @@ -0,0 +1,2780 @@ +/*  */ +/*  Description: */ +/*  */ +/*  This file is for RTL8821A Co-exist mechanism */ +/*  */ +/*  History */ +/*  2012/11/15 Cosa first check in. */ +/*  */ +/*  */ + +/*  */ +/*  include files */ +/*  */ +#include "halbt_precomp.h" +/*  */ +/*  Global variables, these are static variables */ +/*  */ +static struct coex_dm_8821a_1ant glcoex_dm_8821a_1ant; +static struct coex_dm_8821a_1ant *coex_dm = &glcoex_dm_8821a_1ant; +static struct coex_sta_8821a_1ant glcoex_sta_8821a_1ant; +static struct coex_sta_8821a_1ant *coex_sta = &glcoex_sta_8821a_1ant; + +static const char *const glbt_info_src_8821a_1ant[] = { +	"BT Info[wifi fw]", +	"BT Info[bt rsp]", +	"BT Info[bt auto report]", +}; + +static u32 glcoex_ver_date_8821a_1ant = 20130816; +static u32 glcoex_ver_8821a_1ant = 0x41; + +/*  local function proto type if needed */ +/*  local function start with halbtc8821a1ant_ */ +static u8 halbtc8821a1ant_bt_rssi_state(u8 level_num, u8 rssi_thresh, +					u8 rssi_thresh1) +{ +	long			bt_rssi = 0; +	u8 bt_rssi_state = coex_sta->pre_bt_rssi_state; + +	bt_rssi = coex_sta->bt_rssi; + +	if (level_num == 2) { +		if ((coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_LOW) || +		    (coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_STAY_LOW)) { +			if (bt_rssi >= (rssi_thresh+BTC_RSSI_COEX_THRESH_TOL_8821A_1ANT)) { +				bt_rssi_state = BTC_RSSI_STATE_HIGH; +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, +					  "[BTCoex], BT Rssi state switch to High\n"); +			} else { +				bt_rssi_state = BTC_RSSI_STATE_STAY_LOW; +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, +					  "[BTCoex], BT Rssi state stay at Low\n"); +			} +		} else { +			if (bt_rssi < rssi_thresh) { +				bt_rssi_state = BTC_RSSI_STATE_LOW; +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, +					  "[BTCoex], BT Rssi state switch to Low\n"); +			} else { +				bt_rssi_state = BTC_RSSI_STATE_STAY_HIGH; +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, +					  "[BTCoex], BT Rssi state stay at High\n"); +			} +		} +	} else if (level_num == 3) { +		if (rssi_thresh > rssi_thresh1) { +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, +				  "[BTCoex], BT Rssi thresh error!!\n"); +			return coex_sta->pre_bt_rssi_state; +		} + +		if ((coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_LOW) || +		    (coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_STAY_LOW)) { +			if (bt_rssi >= (rssi_thresh+BTC_RSSI_COEX_THRESH_TOL_8821A_1ANT)) { +				bt_rssi_state = BTC_RSSI_STATE_MEDIUM; +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, +					  "[BTCoex], BT Rssi state switch to Medium\n"); +			} else { +				bt_rssi_state = BTC_RSSI_STATE_STAY_LOW; +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, +					  "[BTCoex], BT Rssi state stay at Low\n"); +			} +		} else if ((coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_MEDIUM) || +			   (coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_STAY_MEDIUM)) { +			if (bt_rssi >= (rssi_thresh1+BTC_RSSI_COEX_THRESH_TOL_8821A_1ANT)) { +				bt_rssi_state = BTC_RSSI_STATE_HIGH; +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, +					  "[BTCoex], BT Rssi state switch to High\n"); +			} else if (bt_rssi < rssi_thresh) { +				bt_rssi_state = BTC_RSSI_STATE_LOW; +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, +					  "[BTCoex], BT Rssi state switch to Low\n"); +			} else { +				bt_rssi_state = BTC_RSSI_STATE_STAY_MEDIUM; +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, +					  "[BTCoex], BT Rssi state stay at Medium\n"); +			} +		} else { +			if (bt_rssi < rssi_thresh1) { +				bt_rssi_state = BTC_RSSI_STATE_MEDIUM; +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, +					  "[BTCoex], BT Rssi state switch to Medium\n"); +			} else { +				bt_rssi_state = BTC_RSSI_STATE_STAY_HIGH; +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, +					  "[BTCoex], BT Rssi state stay at High\n"); +			} +		} +	} + +	coex_sta->pre_bt_rssi_state = bt_rssi_state; + +	return bt_rssi_state; +} + +static u8 Wifi_rssi_state(struct btc_coexist *btcoexist, u8 index, +			  u8 level_num, u8 rssi_thresh, +			  u8 rssi_thresh1) +{ +	long	wifi_rssi = 0; +	u8 wifi_rssi_state = coex_sta->pre_wifi_rssi_state[index]; + +	btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifi_rssi); + +	if (level_num == 2) { +		if ((coex_sta->pre_wifi_rssi_state[index] == BTC_RSSI_STATE_LOW) || +		    (coex_sta->pre_wifi_rssi_state[index] == BTC_RSSI_STATE_STAY_LOW)) { +			if (wifi_rssi >= (rssi_thresh+BTC_RSSI_COEX_THRESH_TOL_8821A_1ANT)) { +				wifi_rssi_state = BTC_RSSI_STATE_HIGH; +				BTC_PRINT(BTC_MSG_ALGORITHM, +					  ALGO_WIFI_RSSI_STATE, +					  "[BTCoex], wifi RSSI state switch to High\n"); +			} else { +				wifi_rssi_state = BTC_RSSI_STATE_STAY_LOW; +				BTC_PRINT(BTC_MSG_ALGORITHM, +					  ALGO_WIFI_RSSI_STATE, +					  "[BTCoex], wifi RSSI state stay at Low\n"); +			} +		} else { +			if (wifi_rssi < rssi_thresh) { +				wifi_rssi_state = BTC_RSSI_STATE_LOW; +				BTC_PRINT(BTC_MSG_ALGORITHM, +					  ALGO_WIFI_RSSI_STATE, +					  "[BTCoex], wifi RSSI state switch to Low\n"); +			} else { +				wifi_rssi_state = BTC_RSSI_STATE_STAY_HIGH; +				BTC_PRINT(BTC_MSG_ALGORITHM, +					  ALGO_WIFI_RSSI_STATE, +					  "[BTCoex], wifi RSSI state stay at High\n"); +			} +		} +	} else if (level_num == 3) { +		if (rssi_thresh > rssi_thresh1) { +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, +				  "[BTCoex], wifi RSSI thresh error!!\n"); +			return coex_sta->pre_wifi_rssi_state[index]; +		} + +		if ((coex_sta->pre_wifi_rssi_state[index] == +		     BTC_RSSI_STATE_LOW) || +		    (coex_sta->pre_wifi_rssi_state[index] == +		     BTC_RSSI_STATE_STAY_LOW)) { +			if (wifi_rssi >= (rssi_thresh + +			    BTC_RSSI_COEX_THRESH_TOL_8821A_1ANT)) { +				wifi_rssi_state = BTC_RSSI_STATE_MEDIUM; +				BTC_PRINT(BTC_MSG_ALGORITHM, +					  ALGO_WIFI_RSSI_STATE, +					  "[BTCoex], wifi RSSI state switch to Medium\n"); +			} else { +				wifi_rssi_state = BTC_RSSI_STATE_STAY_LOW; +				BTC_PRINT(BTC_MSG_ALGORITHM, +					  ALGO_WIFI_RSSI_STATE, +					  "[BTCoex], wifi RSSI state stay at Low\n"); +			} +		} else if ((coex_sta->pre_wifi_rssi_state[index] == +			    BTC_RSSI_STATE_MEDIUM) || +			   (coex_sta->pre_wifi_rssi_state[index] == +			    BTC_RSSI_STATE_STAY_MEDIUM)) { +			if (wifi_rssi >= (rssi_thresh1 + +			    BTC_RSSI_COEX_THRESH_TOL_8821A_1ANT)) { +				wifi_rssi_state = BTC_RSSI_STATE_HIGH; +				BTC_PRINT(BTC_MSG_ALGORITHM, +					  ALGO_WIFI_RSSI_STATE, +					  "[BTCoex], wifi RSSI state switch to High\n"); +			} else if (wifi_rssi < rssi_thresh) { +				wifi_rssi_state = BTC_RSSI_STATE_LOW; +				BTC_PRINT(BTC_MSG_ALGORITHM, +					  ALGO_WIFI_RSSI_STATE, +					  "[BTCoex], wifi RSSI state switch to Low\n"); +			} else { +				wifi_rssi_state = BTC_RSSI_STATE_STAY_MEDIUM; +				BTC_PRINT(BTC_MSG_ALGORITHM, +					  ALGO_WIFI_RSSI_STATE, +					  "[BTCoex], wifi RSSI state stay at Medium\n"); +			} +		} else { +			if (wifi_rssi < rssi_thresh1) { +				wifi_rssi_state = BTC_RSSI_STATE_MEDIUM; +				BTC_PRINT(BTC_MSG_ALGORITHM, +					  ALGO_WIFI_RSSI_STATE, +					  "[BTCoex], wifi RSSI state switch to Medium\n"); +			} else { +				wifi_rssi_state = BTC_RSSI_STATE_STAY_HIGH; +				BTC_PRINT(BTC_MSG_ALGORITHM, +					  ALGO_WIFI_RSSI_STATE, +					  "[BTCoex], wifi RSSI state stay at High\n"); +			} +		} +	} + +	coex_sta->pre_wifi_rssi_state[index] = wifi_rssi_state; + +	return wifi_rssi_state; +} + +static void update_ra_mask(struct btc_coexist *btcoexist, +			   bool force_exec, u32 dis_rate_mask) +{ +	coex_dm->cur_ra_mask = dis_rate_mask; + +	if (force_exec || (coex_dm->pre_ra_mask != coex_dm->cur_ra_mask)) { +		btcoexist->btc_set(btcoexist, BTC_SET_ACT_UPDATE_ra_mask, +				   &coex_dm->cur_ra_mask); +	} +	coex_dm->pre_ra_mask = coex_dm->cur_ra_mask; +} + +static void auto_rate_fallback_retry(struct btc_coexist *btcoexist, +				     bool force_exec, u8 type) +{ +	bool wifi_under_b_mode = false; + +	coex_dm->cur_arfr_type = type; + +	if (force_exec || (coex_dm->pre_arfr_type != coex_dm->cur_arfr_type)) { +		switch (coex_dm->cur_arfr_type) { +		case 0:	/*  normal mode */ +			btcoexist->btc_write_4byte(btcoexist, 0x430, +						   coex_dm->backup_arfr_cnt1); +			btcoexist->btc_write_4byte(btcoexist, 0x434, +						   coex_dm->backup_arfr_cnt2); +			break; +		case 1: +			btcoexist->btc_get(btcoexist, +					   BTC_GET_BL_WIFI_UNDER_B_MODE, +					   &wifi_under_b_mode); +			if (wifi_under_b_mode) { +				btcoexist->btc_write_4byte(btcoexist, +							   0x430, 0x0); +				btcoexist->btc_write_4byte(btcoexist, +							   0x434, +							   0x01010101); +			} else { +				btcoexist->btc_write_4byte(btcoexist, +							   0x430, 0x0); +				btcoexist->btc_write_4byte(btcoexist, +							   0x434, +							   0x04030201); +			} +			break; +		default: +			break; +		} +	} + +	coex_dm->pre_arfr_type = coex_dm->cur_arfr_type; +} + +static void halbtc8821a1ant_retry_limit(struct btc_coexist *btcoexist, +					bool force_exec, u8 type) +{ +	coex_dm->cur_retry_limit_type = type; + +	if (force_exec || (coex_dm->pre_retry_limit_type != +	    coex_dm->cur_retry_limit_type)) { +		switch (coex_dm->cur_retry_limit_type) { +		case 0:	/*  normal mode */ +			btcoexist->btc_write_2byte(btcoexist, 0x42a, coex_dm->backup_retry_limit); +			break; +		case 1:	/*  retry limit = 8 */ +			btcoexist->btc_write_2byte(btcoexist, 0x42a, 0x0808); +			break; +		default: +			break; +		} +	} + +	coex_dm->pre_retry_limit_type = coex_dm->cur_retry_limit_type; +} + +static void halbtc8821a1ant_ampdu_max_time(struct btc_coexist *btcoexist, +					   bool force_exec, u8 type) +{ +	coex_dm->cur_ampdu_time_type = type; + +	if (force_exec || +	    (coex_dm->pre_ampdu_time_type != coex_dm->cur_ampdu_time_type)) { +		switch (coex_dm->cur_ampdu_time_type) { +		case 0:	/*  normal mode */ +			btcoexist->btc_write_1byte(btcoexist, 0x456, coex_dm->backup_ampdu_max_time); +			break; +		case 1:	/*  AMPDU timw = 0x38 * 32us */ +			btcoexist->btc_write_1byte(btcoexist, 0x456, 0x38); +			break; +		default: +			break; +		} +	} + +	coex_dm->pre_ampdu_time_type = coex_dm->cur_ampdu_time_type; +} + +static void halbtc8821a1ant_limited_tx(struct btc_coexist *btcoexist, +				       bool force_exec, u8 ra_mask_type, +				       u8 arfr_type, u8 retry_limit_type, +				       u8 ampdu_time_type) +{ +	switch (ra_mask_type) { +	case 0:	/*  normal mode */ +		update_ra_mask(btcoexist, force_exec, 0x0); +		break; +	case 1:	/*  disable cck 1/2 */ +		update_ra_mask(btcoexist, force_exec, 0x00000003); +		break; +	case 2:	/*  disable cck 1/2/5.5, ofdm 6/9/12/18/24, mcs 0/1/2/3/4 */ +		update_ra_mask(btcoexist, force_exec, 0x0001f1f7); +		break; +	default: +		break; +	} + +	auto_rate_fallback_retry(btcoexist, force_exec, arfr_type); +	halbtc8821a1ant_retry_limit(btcoexist, force_exec, retry_limit_type); +	halbtc8821a1ant_ampdu_max_time(btcoexist, force_exec, ampdu_time_type); +} + +static void halbtc8821a1ant_limited_rx(struct btc_coexist *btcoexist, +				       bool force_exec, bool rej_ap_agg_pkt, +				       bool bt_ctrl_agg_buf_size, +				       u8 agg_buf_size) +{ +	bool reject_rx_agg = rej_ap_agg_pkt; +	bool bt_ctrl_rx_agg_size = bt_ctrl_agg_buf_size; +	u8 rx_agg_size = agg_buf_size; + +	/*  */ +	/*	Rx Aggregation related setting */ +	/*  */ +	btcoexist->btc_set(btcoexist, BTC_SET_BL_TO_REJ_AP_AGG_PKT, &reject_rx_agg); +	/*  decide BT control aggregation buf size or not */ +	btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_CTRL_AGG_SIZE, &bt_ctrl_rx_agg_size); +	/*  aggregation buf size, only work when BT control Rx aggregation size. */ +	btcoexist->btc_set(btcoexist, BTC_SET_U1_AGG_BUF_SIZE, &rx_agg_size); +	/*  real update aggregation setting */ +	btcoexist->btc_set(btcoexist, BTC_SET_ACT_AGGREGATE_CTRL, NULL); + +} + +static void halbtc8821a1ant_monitor_bt_ctr(struct btc_coexist *btcoexist) +{ +	u32 reg_hp_tx_rx, reg_lp_tx_rx, u4_tmp; +	u32 reg_hp_tx = 0, reg_hp_rx = 0, reg_lp_tx = 0, reg_lp_rx = 0; + +	reg_hp_tx_rx = 0x770; +	reg_lp_tx_rx = 0x774; + +	u4_tmp = btcoexist->btc_read_4byte(btcoexist, reg_hp_tx_rx); +	reg_hp_tx = u4_tmp & MASKLWORD; +	reg_hp_rx = (u4_tmp & MASKHWORD)>>16; + +	u4_tmp = btcoexist->btc_read_4byte(btcoexist, reg_lp_tx_rx); +	reg_lp_tx = u4_tmp & MASKLWORD; +	reg_lp_rx = (u4_tmp & MASKHWORD)>>16; + +	coex_sta->high_priority_tx = reg_hp_tx; +	coex_sta->high_priority_rx = reg_hp_rx; +	coex_sta->low_priority_tx = reg_lp_tx; +	coex_sta->low_priority_rx = reg_lp_rx; + +	/*  reset counter */ +	btcoexist->btc_write_1byte(btcoexist, 0x76e, 0xc); +} + +static void halbtc8821a1ant_query_bt_info(struct btc_coexist *btcoexist) +{ +	u8 h2c_parameter[1] = {0}; + +	coex_sta->c2h_bt_info_req_sent = true; + +	h2c_parameter[0] |= BIT(0);	/*  trigger */ + +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, +		  "[BTCoex], Query Bt Info, FW write 0x61 = 0x%x\n", +		h2c_parameter[0]); + +	btcoexist->btc_fill_h2c(btcoexist, 0x61, 1, h2c_parameter); +} + +static void halbtc8821a1ant_update_bt_link_info(struct btc_coexist *btcoexist) +{ +	struct btc_bt_link_info	*bt_link_info = &btcoexist->bt_link_info; +	bool bt_hs_on = false; + +	btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + +	bt_link_info->bt_link_exist = coex_sta->bt_link_exist; +	bt_link_info->sco_exist = coex_sta->sco_exist; +	bt_link_info->a2dp_exist = coex_sta->a2dp_exist; +	bt_link_info->pan_exist = coex_sta->pan_exist; +	bt_link_info->hid_exist = coex_sta->hid_exist; + +	/*  work around for HS mode. */ +	if (bt_hs_on) { +		bt_link_info->pan_exist = true; +		bt_link_info->bt_link_exist = true; +	} + +	/*  check if Sco only */ +	if (bt_link_info->sco_exist && +		!bt_link_info->a2dp_exist && +		!bt_link_info->pan_exist && +		!bt_link_info->hid_exist) +		bt_link_info->sco_only = true; +	else +		bt_link_info->sco_only = false; + +	/*  check if A2dp only */ +	if (!bt_link_info->sco_exist && +		bt_link_info->a2dp_exist && +		!bt_link_info->pan_exist && +		!bt_link_info->hid_exist) +		bt_link_info->a2dp_only = true; +	else +		bt_link_info->a2dp_only = false; + +	/*  check if Pan only */ +	if (!bt_link_info->sco_exist && +		!bt_link_info->a2dp_exist && +		bt_link_info->pan_exist && +		!bt_link_info->hid_exist) +		bt_link_info->pan_only = true; +	else +		bt_link_info->pan_only = false; + +	/*  check if Hid only */ +	if (!bt_link_info->sco_exist && +		!bt_link_info->a2dp_exist && +		!bt_link_info->pan_exist && +		bt_link_info->hid_exist) +		bt_link_info->hid_only = true; +	else +		bt_link_info->hid_only = false; +} + +static u8 halbtc8821a1ant_action_algorithm(struct btc_coexist *btcoexist) +{ +	struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; +	bool bt_hs_on = false; +	u8 algorithm = BT_8821A_1ANT_COEX_ALGO_UNDEFINED; +	u8 num_of_diff_profile = 0; + +	btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + +	if (!bt_link_info->bt_link_exist) { +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, "[BTCoex], No BT link exists!!!\n"); +		return algorithm; +	} + +	if (bt_link_info->sco_exist) +		num_of_diff_profile++; +	if (bt_link_info->hid_exist) +		num_of_diff_profile++; +	if (bt_link_info->pan_exist) +		num_of_diff_profile++; +	if (bt_link_info->a2dp_exist) +		num_of_diff_profile++; + +	if (num_of_diff_profile == 1) { +		if (bt_link_info->sco_exist) { +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, "[BTCoex], BT Profile = SCO only\n"); +			algorithm = BT_8821A_1ANT_COEX_ALGO_SCO; +		} else { +			if (bt_link_info->hid_exist) { +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, "[BTCoex], BT Profile = HID only\n"); +				algorithm = BT_8821A_1ANT_COEX_ALGO_HID; +			} else if (bt_link_info->a2dp_exist) { +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, "[BTCoex], BT Profile = A2DP only\n"); +				algorithm = BT_8821A_1ANT_COEX_ALGO_A2DP; +			} else if (bt_link_info->pan_exist) { +				if (bt_hs_on) { +					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, "[BTCoex], BT Profile = PAN(HS) only\n"); +					algorithm = BT_8821A_1ANT_COEX_ALGO_PANHS; +				} else { +					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, "[BTCoex], BT Profile = PAN(EDR) only\n"); +					algorithm = BT_8821A_1ANT_COEX_ALGO_PANEDR; +				} +			} +		} +	} else if (num_of_diff_profile == 2) { +		if (bt_link_info->sco_exist) { +			if (bt_link_info->hid_exist) { +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, "[BTCoex], BT Profile = SCO + HID\n"); +				algorithm = BT_8821A_1ANT_COEX_ALGO_HID; +			} else if (bt_link_info->a2dp_exist) { +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, "[BTCoex], BT Profile = SCO + A2DP ==> SCO\n"); +				algorithm = BT_8821A_1ANT_COEX_ALGO_SCO; +			} else if (bt_link_info->pan_exist) { +				if (bt_hs_on) { +					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, "[BTCoex], BT Profile = SCO + PAN(HS)\n"); +					algorithm = BT_8821A_1ANT_COEX_ALGO_SCO; +				} else { +					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, "[BTCoex], BT Profile = SCO + PAN(EDR)\n"); +					algorithm = BT_8821A_1ANT_COEX_ALGO_PANEDR_HID; +				} +			} +		} else { +			if (bt_link_info->hid_exist && +				bt_link_info->a2dp_exist) { +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, "[BTCoex], BT Profile = HID + A2DP\n"); +				algorithm = BT_8821A_1ANT_COEX_ALGO_HID_A2DP; +			} else if (bt_link_info->hid_exist && +				bt_link_info->pan_exist) { +				if (bt_hs_on) { +					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, "[BTCoex], BT Profile = HID + PAN(HS)\n"); +					algorithm = BT_8821A_1ANT_COEX_ALGO_HID_A2DP; +				} else { +					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, "[BTCoex], BT Profile = HID + PAN(EDR)\n"); +					algorithm = BT_8821A_1ANT_COEX_ALGO_PANEDR_HID; +				} +			} else if (bt_link_info->pan_exist && +				bt_link_info->a2dp_exist) { +				if (bt_hs_on) { +					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, "[BTCoex], BT Profile = A2DP + PAN(HS)\n"); +					algorithm = BT_8821A_1ANT_COEX_ALGO_A2DP_PANHS; +				} else { +					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, "[BTCoex], BT Profile = A2DP + PAN(EDR)\n"); +					algorithm = BT_8821A_1ANT_COEX_ALGO_PANEDR_A2DP; +				} +			} +		} +	} else if (num_of_diff_profile == 3) { +		if (bt_link_info->sco_exist) { +			if (bt_link_info->hid_exist && +				bt_link_info->a2dp_exist) { +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, "[BTCoex], BT Profile = SCO + HID + A2DP ==> HID\n"); +				algorithm = BT_8821A_1ANT_COEX_ALGO_HID; +			} else if (bt_link_info->hid_exist && +				bt_link_info->pan_exist) { +				if (bt_hs_on) { +					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, "[BTCoex], BT Profile = SCO + HID + PAN(HS)\n"); +					algorithm = BT_8821A_1ANT_COEX_ALGO_HID_A2DP; +				} else { +					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, "[BTCoex], BT Profile = SCO + HID + PAN(EDR)\n"); +					algorithm = BT_8821A_1ANT_COEX_ALGO_PANEDR_HID; +				} +			} else if (bt_link_info->pan_exist && +				bt_link_info->a2dp_exist) { +				if (bt_hs_on) { +					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, "[BTCoex], BT Profile = SCO + A2DP + PAN(HS)\n"); +					algorithm = BT_8821A_1ANT_COEX_ALGO_SCO; +				} else { +					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, "[BTCoex], BT Profile = SCO + A2DP + PAN(EDR) ==> HID\n"); +					algorithm = BT_8821A_1ANT_COEX_ALGO_PANEDR_HID; +				} +			} +		} else { +			if (bt_link_info->hid_exist && +				bt_link_info->pan_exist && +				bt_link_info->a2dp_exist) { +				if (bt_hs_on) { +					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, "[BTCoex], BT Profile = HID + A2DP + PAN(HS)\n"); +					algorithm = BT_8821A_1ANT_COEX_ALGO_HID_A2DP; +				} else { +					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, "[BTCoex], BT Profile = HID + A2DP + PAN(EDR)\n"); +					algorithm = BT_8821A_1ANT_COEX_ALGO_HID_A2DP_PANEDR; +				} +			} +		} +	} else if (num_of_diff_profile >= 3) { +		if (bt_link_info->sco_exist) { +			if (bt_link_info->hid_exist && +				bt_link_info->pan_exist && +				bt_link_info->a2dp_exist) { +				if (bt_hs_on) { +					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, "[BTCoex], Error!!! BT Profile = SCO + HID + A2DP + PAN(HS)\n"); +				} else { +					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, "[BTCoex], BT Profile = SCO + HID + A2DP + PAN(EDR) ==>PAN(EDR)+HID\n"); +					algorithm = BT_8821A_1ANT_COEX_ALGO_PANEDR_HID; +				} +			} +		} +	} + +	return algorithm; +} + +static void halbtc8821a1ant_set_bt_auto_report(struct btc_coexist *btcoexist, +					       bool enable_auto_report) +{ +	u8 h2c_parameter[1] = {0}; + +	h2c_parameter[0] = 0; + +	if (enable_auto_report) +		h2c_parameter[0] |= BIT(0); + +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, +		  "[BTCoex], BT FW auto report : %s, FW write 0x68 = 0x%x\n", +		  (enable_auto_report ? "Enabled!!" : "Disabled!!"), +		  h2c_parameter[0]); + +	btcoexist->btc_fill_h2c(btcoexist, 0x68, 1, h2c_parameter); +} + +static void halbtc8821a1ant_bt_auto_report(struct btc_coexist *btcoexist, +					   bool force_exec, +					   bool enable_auto_report) +{ +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, "[BTCoex], %s BT Auto report = %s\n", +		(force_exec ? "force to" : ""), ((enable_auto_report) ? "Enabled" : "Disabled")); +	coex_dm->cur_bt_auto_report = enable_auto_report; + +	if (!force_exec) { +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, "[BTCoex], pre_bt_auto_report =%d, cur_bt_auto_report =%d\n", +			coex_dm->pre_bt_auto_report, coex_dm->cur_bt_auto_report); + +		if (coex_dm->pre_bt_auto_report == coex_dm->cur_bt_auto_report) +			return; +	} +	halbtc8821a1ant_set_bt_auto_report(btcoexist, coex_dm->cur_bt_auto_report); + +	coex_dm->pre_bt_auto_report = coex_dm->cur_bt_auto_report; +} + +static void set_sw_penalty_tx_rate_adaptive(struct btc_coexist *btcoexist, +					    bool low_penalty_ra) +{ +	u8 h2c_parameter[6] = {0}; + +	h2c_parameter[0] = 0x6;	/*  opCode, 0x6 = Retry_Penalty */ + +	if (low_penalty_ra) { +		h2c_parameter[1] |= BIT(0); +		h2c_parameter[2] = 0x00;  /* normal rate except MCS7/6/5, +					   * OFDM54/48/36 */ +		h2c_parameter[3] = 0xf7;  /* MCS7 or OFDM54 */ +		h2c_parameter[4] = 0xf8;  /* MCS6 or OFDM48 */ +		h2c_parameter[5] = 0xf9;  /* MCS5 or OFDM36  */ +	} + +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, +		  "[BTCoex], set WiFi Low-Penalty Retry: %s", +		  (low_penalty_ra ? "ON!!" : "OFF!!")); + +	btcoexist->btc_fill_h2c(btcoexist, 0x69, 6, h2c_parameter); +} + +static void halbtc8821a1ant_low_penalty_ra(struct btc_coexist *btcoexist, +					   bool force_exec, bool low_penalty_ra) +{ +	coex_dm->cur_low_penalty_ra = low_penalty_ra; + +	if (!force_exec) { +		if (coex_dm->pre_low_penalty_ra == coex_dm->cur_low_penalty_ra) +			return; +	} +	set_sw_penalty_tx_rate_adaptive(btcoexist, coex_dm->cur_low_penalty_ra); + +	coex_dm->pre_low_penalty_ra = coex_dm->cur_low_penalty_ra; +} + +static void halbtc8821a1ant_set_coex_table(struct btc_coexist *btcoexist, +					   u32 val0x6c0, u32 val0x6c4, +					   u32 val0x6c8, u8 val0x6cc) +{ +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, +		  "[BTCoex], set coex table, set 0x6c0 = 0x%x\n", val0x6c0); +	btcoexist->btc_write_4byte(btcoexist, 0x6c0, val0x6c0); + +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, +		  "[BTCoex], set coex table, set 0x6c4 = 0x%x\n", val0x6c4); +	btcoexist->btc_write_4byte(btcoexist, 0x6c4, val0x6c4); + +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, +		  "[BTCoex], set coex table, set 0x6c8 = 0x%x\n", val0x6c8); +	btcoexist->btc_write_4byte(btcoexist, 0x6c8, val0x6c8); + +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, +		  "[BTCoex], set coex table, set 0x6cc = 0x%x\n", val0x6cc); +	btcoexist->btc_write_1byte(btcoexist, 0x6cc, val0x6cc); +} + +static void halbtc8821a1ant_coex_table(struct btc_coexist *btcoexist, +				       bool force_exec, u32 val0x6c0, +				       u32 val0x6c4, u32 val0x6c8, u8 val0x6cc) +{ +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, +		  "[BTCoex], %s write Coex Table 0x6c0 = 0x%x, 0x6c4 = 0x%x, 0x6c8 = 0x%x, 0x6cc = 0x%x\n", +		  (force_exec ? "force to" : ""), val0x6c0, val0x6c4, +		  val0x6c8, val0x6cc); +	coex_dm->cur_val_0x6c0 = val0x6c0; +	coex_dm->cur_val_0x6c4 = val0x6c4; +	coex_dm->cur_val_0x6c8 = val0x6c8; +	coex_dm->cur_val_0x6cc = val0x6cc; + +	if (!force_exec) { +		if ((coex_dm->pre_val_0x6c0 == coex_dm->cur_val_0x6c0) && +		    (coex_dm->pre_val_0x6c4 == coex_dm->cur_val_0x6c4) && +		    (coex_dm->pre_val_0x6c8 == coex_dm->cur_val_0x6c8) && +		    (coex_dm->pre_val_0x6cc == coex_dm->cur_val_0x6cc)) +			return; +	} +	halbtc8821a1ant_set_coex_table(btcoexist, val0x6c0, val0x6c4, +				       val0x6c8, val0x6cc); + +	coex_dm->pre_val_0x6c0 = coex_dm->cur_val_0x6c0; +	coex_dm->pre_val_0x6c4 = coex_dm->cur_val_0x6c4; +	coex_dm->pre_val_0x6c8 = coex_dm->cur_val_0x6c8; +	coex_dm->pre_val_0x6cc = coex_dm->cur_val_0x6cc; +} + +static void halbtc8821a1ant_coex_table_with_type(struct btc_coexist *btcoexist, +						 bool force_exec, u8 type) +{ +	switch (type) { +	case 0: +		halbtc8821a1ant_coex_table(btcoexist, force_exec, +					   0x55555555, 0x55555555, +					   0xffffff, 0x3); +		break; +	case 1: +		halbtc8821a1ant_coex_table(btcoexist, force_exec, +					   0x55555555, 0x5a5a5a5a, +					   0xffffff, 0x3); +		break; +	case 2: +		halbtc8821a1ant_coex_table(btcoexist, force_exec, +					   0x5a5a5a5a, 0x5a5a5a5a, +					   0xffffff, 0x3); +		break; +	case 3: +		halbtc8821a1ant_coex_table(btcoexist, force_exec, +					   0x55555555, 0xaaaaaaaa, +					   0xffffff, 0x3); +		break; +	case 4: +		halbtc8821a1ant_coex_table(btcoexist, force_exec, +					   0xffffffff, 0xffffffff, +					   0xffffff, 0x3); +		break; +	case 5: +		halbtc8821a1ant_coex_table(btcoexist, force_exec, +					   0x5fff5fff, 0x5fff5fff, +					   0xffffff, 0x3); +		break; +	case 6: +		halbtc8821a1ant_coex_table(btcoexist, force_exec, +					   0x55ff55ff, 0x5a5a5a5a, +					   0xffffff, 0x3); +		break; +	case 7: +		halbtc8821a1ant_coex_table(btcoexist, force_exec, +					   0x5afa5afa, 0x5afa5afa, +					   0xffffff, 0x3); +		break; +	default: +		break; +	} +} + +static void halbtc8821a1ant_set_fw_ignore_wlan_act(struct btc_coexist *btcoexist, +						   bool enable) +{ +	u8 h2c_parameter[1] = {0}; + +	if (enable) +		h2c_parameter[0] |= BIT(0);	/*  function enable */ + +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, +		  "[BTCoex], set FW for BT Ignore Wlan_Act, FW write 0x63 = 0x%x\n", +		  h2c_parameter[0]); + +	btcoexist->btc_fill_h2c(btcoexist, 0x63, 1, h2c_parameter); +} + +static void halbtc8821a1ant_ignore_wlan_act(struct btc_coexist *btcoexist, +					    bool force_exec, bool enable) +{ +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, +		  "[BTCoex], %s turn Ignore WlanAct %s\n", +		  (force_exec ? "force to" : ""), (enable ? "ON" : "OFF")); +	coex_dm->cur_ignore_wlan_act = enable; + +	if (!force_exec) { +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, +			  "[BTCoex], pre_ignore_wlan_act = %d, cur_ignore_wlan_act = %d!!\n", +			  coex_dm->pre_ignore_wlan_act, +			  coex_dm->cur_ignore_wlan_act); + +		if (coex_dm->pre_ignore_wlan_act == +		    coex_dm->cur_ignore_wlan_act) +			return; +	} +	halbtc8821a1ant_set_fw_ignore_wlan_act(btcoexist, enable); + +	coex_dm->pre_ignore_wlan_act = coex_dm->cur_ignore_wlan_act; +} + +static void +halbtc8821a1ant_set_fw_pstdma( +	struct btc_coexist *btcoexist, +	u8 byte1, +	u8 byte2, +	u8 byte3, +	u8 byte4, +	u8 byte5 +	) +{ +	u8 h2c_parameter[5] = {0}; + +	h2c_parameter[0] = byte1; +	h2c_parameter[1] = byte2; +	h2c_parameter[2] = byte3; +	h2c_parameter[3] = byte4; +	h2c_parameter[4] = byte5; + +	coex_dm->ps_tdma_para[0] = byte1; +	coex_dm->ps_tdma_para[1] = byte2; +	coex_dm->ps_tdma_para[2] = byte3; +	coex_dm->ps_tdma_para[3] = byte4; +	coex_dm->ps_tdma_para[4] = byte5; + +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, "[BTCoex], PS-TDMA H2C cmd = 0x%x%08x\n", +		h2c_parameter[0], +		h2c_parameter[1]<<24|h2c_parameter[2]<<16|h2c_parameter[3]<<8|h2c_parameter[4]); + +	btcoexist->btc_fill_h2c(btcoexist, 0x60, 5, h2c_parameter); +} + +static void +halbtc8821a1ant_set_lps_rpwm( +	struct btc_coexist *btcoexist, +	u8 lps_val, +	u8 rpwm_val +	) +{ +	u8 lps = lps_val; +	u8 rpwm = rpwm_val; + +	btcoexist->btc_set(btcoexist, BTC_SET_U1_LPS_VAL, &lps); +	btcoexist->btc_set(btcoexist, BTC_SET_U1_RPWM_VAL, &rpwm); +} + +static void +halbtc8821a1ant_lps_rpwm( +	struct btc_coexist *btcoexist, +	bool force_exec, +	u8 lps_val, +	u8 rpwm_val +	) +{ +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, "[BTCoex], %s set lps/rpwm = 0x%x/0x%x\n", +		(force_exec ? "force to" : ""), lps_val, rpwm_val); +	coex_dm->cur_lps = lps_val; +	coex_dm->cur_rpwm = rpwm_val; + +	if (!force_exec) { +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, "[BTCoex], LPS-RxBeaconMode = 0x%x , LPS-RPWM = 0x%x!!\n", +			 coex_dm->cur_lps, coex_dm->cur_rpwm); + +		if ((coex_dm->pre_lps == coex_dm->cur_lps) && +			(coex_dm->pre_rpwm == coex_dm->cur_rpwm)) { +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, "[BTCoex], LPS-RPWM_Last = 0x%x , LPS-RPWM_Now = 0x%x!!\n", +				 coex_dm->pre_rpwm, coex_dm->cur_rpwm); + +			return; +		} +	} +	halbtc8821a1ant_set_lps_rpwm(btcoexist, lps_val, rpwm_val); + +	coex_dm->pre_lps = coex_dm->cur_lps; +	coex_dm->pre_rpwm = coex_dm->cur_rpwm; +} + +static void +halbtc8821a1ant_sw_mechanism( +	struct btc_coexist *btcoexist, +	bool low_penalty_ra +	) +{ +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, "[BTCoex], SM[LpRA] = %d\n", low_penalty_ra); + +	halbtc8821a1ant_low_penalty_ra(btcoexist, NORMAL_EXEC, low_penalty_ra); +} + +static void +halbtc8821a1ant_set_ant_path( +	struct btc_coexist *btcoexist, +	u8 ant_pos_type, +	bool init_hw_cfg, +	bool wifi_off +	) +{ +	struct btc_board_info *board_info = &btcoexist->board_info; +	u32 u4_tmp = 0; +	u8 h2c_parameter[2] = {0}; + +	if (init_hw_cfg) { +		/*  0x4c[23] = 0, 0x4c[24] = 1  Antenna control by WL/BT */ +		u4_tmp = btcoexist->btc_read_4byte(btcoexist, 0x4c); +		u4_tmp &= ~BIT(23); +		u4_tmp |= BIT(24); +		btcoexist->btc_write_4byte(btcoexist, 0x4c, u4_tmp); + +		btcoexist->btc_write_1byte_bitmask(btcoexist, 0x975, 0x3, 0x3); +		btcoexist->btc_write_1byte(btcoexist, 0xcb4, 0x77); + +		if (board_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT) { +			/* tell firmware "antenna inverse"  ==> WRONG firmware antenna control code.==>need fw to fix */ +			h2c_parameter[0] = 1; +			h2c_parameter[1] = 1; +			btcoexist->btc_fill_h2c(btcoexist, 0x65, 2, h2c_parameter); + +			btcoexist->btc_write_1byte_bitmask(btcoexist, 0x64, 0x1, 0x1); /* Main Ant to  BT for IPS case 0x4c[23] = 1 */ +		} else { +			/* tell firmware "no antenna inverse" ==> WRONG firmware antenna control code.==>need fw to fix */ +			h2c_parameter[0] = 0; +			h2c_parameter[1] = 1; +			btcoexist->btc_fill_h2c(btcoexist, 0x65, 2, h2c_parameter); + +			btcoexist->btc_write_1byte_bitmask(btcoexist, 0x64, 0x1, 0x0); /* Aux Ant to  BT for IPS case 0x4c[23] = 1 */ +		} +	} else if (wifi_off) { +		/*  0x4c[24:23] = 00, Set Antenna control by BT_RFE_CTRL	BT Vendor 0xac = 0xf002 */ +		u4_tmp = btcoexist->btc_read_4byte(btcoexist, 0x4c); +		u4_tmp &= ~BIT(23); +		u4_tmp &= ~BIT(24); +		btcoexist->btc_write_4byte(btcoexist, 0x4c, u4_tmp); +	} + +	/*  ext switch setting */ +	switch (ant_pos_type) { +	case BTC_ANT_PATH_WIFI: +		if (board_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT) +			btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcb7, 0x30, 0x1); +		else +			btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcb7, 0x30, 0x2); +		break; +	case BTC_ANT_PATH_BT: +		if (board_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT) +			btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcb7, 0x30, 0x2); +		else +			btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcb7, 0x30, 0x1); +		break; +	case BTC_ANT_PATH_PTA: +	default: +		if (board_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT) +			btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcb7, 0x30, 0x1); +		else +			btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcb7, 0x30, 0x2); +		break; +	} +} + +static void +halbtc8821a1ant_ps_tdma( +	struct btc_coexist *btcoexist, +	bool force_exec, +	bool turn_on, +	u8 type +	) +{ +	u8 rssi_adjust_val = 0; + +	coex_dm->cur_ps_tdma_on = turn_on; +	coex_dm->cur_ps_tdma = type; + +	if (!force_exec) { +		if (coex_dm->cur_ps_tdma_on) { +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, "[BTCoex], ********** TDMA(on, %d) **********\n", +				coex_dm->cur_ps_tdma); +		} else { +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, "[BTCoex], ********** TDMA(off, %d) **********\n", +				coex_dm->cur_ps_tdma); +		} + +		if ((coex_dm->pre_ps_tdma_on == coex_dm->cur_ps_tdma_on) && +			(coex_dm->pre_ps_tdma == coex_dm->cur_ps_tdma)) +			return; +	} +	if (turn_on) { +		switch (type) { +		default: +			halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x51, 0x1a, 0x1a, 0x0, 0x50); +			break; +		case 1: +			halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x51, 0x3a, 0x03, 0x10, 0x50); +			rssi_adjust_val = 11; +			break; +		case 2: +			halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x51, 0x2b, 0x03, 0x10, 0x50); +			rssi_adjust_val = 14; +			break; +		case 3: +			halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x51, 0x1d, 0x1d, 0x0, 0x10); +			break; +		case 4: +			halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x93, 0x15, 0x3, 0x14, 0x0); +			rssi_adjust_val = 17; +			break; +		case 5: +			halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x61, 0x15, 0x3, 0x11, 0x10); +			break; +		case 6: +			halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x13, 0xa, 0x3, 0x0, 0x0); +			break; +		case 7: +			halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x13, 0xc, 0x5, 0x0, 0x0); +			break; +		case 8: +			halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x93, 0x25, 0x3, 0x10, 0x0); +			break; +		case 9: +			halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x51, 0x21, 0x3, 0x10, 0x50); +			rssi_adjust_val = 18; +			break; +		case 10: +			halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x13, 0xa, 0xa, 0x0, 0x40); +			break; +		case 11: +			halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x51, 0x14, 0x03, 0x10, 0x10); +			rssi_adjust_val = 20; +			break; +		case 12: +			halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x51, 0x0a, 0x0a, 0x0, 0x50); +			break; +		case 13: +			halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x51, 0x18, 0x18, 0x0, 0x10); +			break; +		case 14: +			halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x51, 0x21, 0x3, 0x10, 0x10); +			break; +		case 15: +			halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x13, 0xa, 0x3, 0x8, 0x0); +			break; +		case 16: +			halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x93, 0x15, 0x3, 0x10, 0x0); +			rssi_adjust_val = 18; +			break; +		case 18: +			halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x93, 0x25, 0x3, 0x10, 0x0); +			rssi_adjust_val = 14; +			break; +		case 20: +			halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x61, 0x35, 0x03, 0x11, 0x10); +			break; +		case 21: +			halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x61, 0x15, 0x03, 0x11, 0x10); +			break; +		case 22: +			halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x61, 0x25, 0x03, 0x11, 0x10); +			break; +		case 23: +			halbtc8821a1ant_set_fw_pstdma(btcoexist, 0xe3, 0x25, 0x3, 0x31, 0x18); +			rssi_adjust_val = 22; +			break; +		case 24: +			halbtc8821a1ant_set_fw_pstdma(btcoexist, 0xe3, 0x15, 0x3, 0x31, 0x18); +			rssi_adjust_val = 22; +			break; +		case 25: +			halbtc8821a1ant_set_fw_pstdma(btcoexist, 0xe3, 0xa, 0x3, 0x31, 0x18); +			rssi_adjust_val = 22; +			break; +		case 26: +			halbtc8821a1ant_set_fw_pstdma(btcoexist, 0xe3, 0xa, 0x3, 0x31, 0x18); +			rssi_adjust_val = 22; +			break; +		case 27: +			halbtc8821a1ant_set_fw_pstdma(btcoexist, 0xe3, 0x25, 0x3, 0x31, 0x98); +			rssi_adjust_val = 22; +			break; +		case 28: +			halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x69, 0x25, 0x3, 0x31, 0x0); +			break; +		case 29: +			halbtc8821a1ant_set_fw_pstdma(btcoexist, 0xab, 0x1a, 0x1a, 0x1, 0x10); +			break; +		case 30: +			halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x51, 0x14, 0x3, 0x10, 0x50); +			break; +		case 31: +			halbtc8821a1ant_set_fw_pstdma(btcoexist, 0xd3, 0x1a, 0x1a, 0, 0x58); +			break; +		case 32: +			halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x61, 0xa, 0x3, 0x10, 0x0); +			break; +		case 33: +			halbtc8821a1ant_set_fw_pstdma(btcoexist, 0xa3, 0x25, 0x3, 0x30, 0x90); +			break; +		case 34: +			halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x53, 0x1a, 0x1a, 0x0, 0x10); +			break; +		case 35: +			halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x63, 0x1a, 0x1a, 0x0, 0x10); +			break; +		case 36: +			halbtc8821a1ant_set_fw_pstdma(btcoexist, 0xd3, 0x12, 0x3, 0x14, 0x50); +				break; +		} +	} else { +		/*  disable PS tdma */ +		switch (type) { +		case 8: /* PTA Control */ +			halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x8, 0x0, 0x0, 0x0, 0x0); +			halbtc8821a1ant_set_ant_path(btcoexist, BTC_ANT_PATH_PTA, false, false); +			break; +		case 0: +		default:  /* Software control, Antenna at BT side */ +			halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x0, 0x0, 0x0, 0x0, 0x0); +			halbtc8821a1ant_set_ant_path(btcoexist, BTC_ANT_PATH_BT, false, false); +			break; +		case 9:   /* Software control, Antenna at WiFi side */ +			halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x0, 0x0, 0x0, 0x0, 0x0); +			halbtc8821a1ant_set_ant_path(btcoexist, BTC_ANT_PATH_WIFI, false, false); +			break; +		case 10:	/*  under 5G */ +			halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x0, 0x0, 0x0, 0x8, 0x0); +			halbtc8821a1ant_set_ant_path(btcoexist, BTC_ANT_PATH_BT, false, false); +			break; +		} +	} +	rssi_adjust_val = 0; +	btcoexist->btc_set(btcoexist, BTC_SET_U1_RSSI_ADJ_VAL_FOR_1ANT_COEX_TYPE, &rssi_adjust_val); + +	/*  update pre state */ +	coex_dm->pre_ps_tdma_on = coex_dm->cur_ps_tdma_on; +	coex_dm->pre_ps_tdma = coex_dm->cur_ps_tdma; +} + +static bool +halbtc8821a1ant_is_common_action( +	struct btc_coexist *btcoexist +	) +{ +	bool bCommon = false, wifi_connected = false, wifi_busy = false; + +	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, &wifi_connected); +	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + +	if (!wifi_connected && +		BT_8821A_1ANT_BT_STATUS_NON_CONNECTED_IDLE == coex_dm->bt_status) { +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, "[BTCoex], Wifi non connected-idle + BT non connected-idle!!\n"); +		halbtc8821a1ant_sw_mechanism(btcoexist, false); + +		bCommon = true; +	} else if (wifi_connected && +			(BT_8821A_1ANT_BT_STATUS_NON_CONNECTED_IDLE == coex_dm->bt_status)) { +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, "[BTCoex], Wifi connected + BT non connected-idle!!\n"); +		halbtc8821a1ant_sw_mechanism(btcoexist, false); + +		bCommon = true; +	} else if (!wifi_connected && +		(BT_8821A_1ANT_BT_STATUS_CONNECTED_IDLE == coex_dm->bt_status)) { +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, "[BTCoex], Wifi non connected-idle + BT connected-idle!!\n"); +		halbtc8821a1ant_sw_mechanism(btcoexist, false); + +		bCommon = true; +	} else if (wifi_connected && +		(BT_8821A_1ANT_BT_STATUS_CONNECTED_IDLE == coex_dm->bt_status)) { +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, "[BTCoex], Wifi connected + BT connected-idle!!\n"); +		halbtc8821a1ant_sw_mechanism(btcoexist, false); + +		bCommon = true; +	} else if (!wifi_connected && +		(BT_8821A_1ANT_BT_STATUS_CONNECTED_IDLE != coex_dm->bt_status)) { +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, "[BTCoex], Wifi non connected-idle + BT Busy!!\n"); +		halbtc8821a1ant_sw_mechanism(btcoexist, false); + +		bCommon = true; +	} else { +		if (wifi_busy) { +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, "[BTCoex], Wifi Connected-Busy + BT Busy!!\n"); +		} else { +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, "[BTCoex], Wifi Connected-Idle + BT Busy!!\n"); +		} + +		bCommon = false; +	} + +	return bCommon; +} + +static void +halbtc8821a1ant_tdma_duration_adjust_for_acl( +	struct btc_coexist *btcoexist, +	u8 wifi_status +	) +{ +	static long		up, dn, m, n, wait_count; +	long			result;   /* 0: no change, +1: increase WiFi duration, -1: decrease WiFi duration */ +	u8 retry_count = 0, bt_info_ext; + +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, "[BTCoex], TdmaDurationAdjustForAcl()\n"); + +	if ((BT_8821A_1ANT_WIFI_STATUS_NON_CONNECTED_ASSO_AUTH_SCAN == wifi_status) || +		(BT_8821A_1ANT_WIFI_STATUS_CONNECTED_SCAN == wifi_status) || +		(BT_8821A_1ANT_WIFI_STATUS_CONNECTED_SPECIAL_PKT == wifi_status)) { +		if (coex_dm->cur_ps_tdma != 1 && +			coex_dm->cur_ps_tdma != 2 && +			coex_dm->cur_ps_tdma != 3 && +			coex_dm->cur_ps_tdma != 9) { +			halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 9); +			coex_dm->ps_tdma_du_adj_type = 9; + +			up = 0; +			dn = 0; +			m = 1; +			n = 3; +			result = 0; +			wait_count = 0; +		} +		return; +	} + +	if (!coex_dm->auto_tdma_adjust) { +		coex_dm->auto_tdma_adjust = true; +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, "[BTCoex], first run TdmaDurationAdjust()!!\n"); + +		halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 2); +		coex_dm->ps_tdma_du_adj_type = 2; +		/*  */ +		up = 0; +		dn = 0; +		m = 1; +		n = 3; +		result = 0; +		wait_count = 0; +	} else { +		/* accquire the BT TRx retry count from BT_Info byte2 */ +		retry_count = coex_sta->bt_retry_cnt; +		bt_info_ext = coex_sta->bt_info_ext; +		/* BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, "[BTCoex], retry_count = %d\n", retry_count)); */ +		/* BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, "[BTCoex], up =%d, dn =%d, m =%d, n =%d, wait_count =%d\n",  */ +		/*	up, dn, m, n, wait_count)); */ +		result = 0; +		wait_count++; + +		if (retry_count == 0) { +			/*  no retry in the last 2-second duration */ +			up++; +			dn--; + +			if (dn <= 0) +				dn = 0; + +			if (up >= n) { +				wait_count = 0; +				n = 3; +				up = 0; +				dn = 0; +				result = 1; +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, "[BTCoex], Increase wifi duration!!\n"); +			} +		} else if (retry_count <= 3) { +			up--; +			dn++; + +			if (up <= 0) +				up = 0; + +			if (dn == 2) { +				if (wait_count <= 2) +					m++; +				else +					m = 1; +				if (m >= 20) +					m = 20; + +				n = 3*m; +				up = 0; +				dn = 0; +				wait_count = 0; +				result = -1; +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, "[BTCoex], Decrease wifi duration for retryCounter<3!!\n"); +			} +		} else { +			if (wait_count == 1) +				m++; +			else +				m = 1; +			if (m >= 20) +				m = 20; + +			n = 3*m; +			up = 0; +			dn = 0; +			wait_count = 0; +			result = -1; +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, "[BTCoex], Decrease wifi duration for retryCounter>3!!\n"); +		} + +		if (result == -1) { +			if ((BT_INFO_8821A_1ANT_A2DP_BASIC_RATE(bt_info_ext)) && +				((coex_dm->cur_ps_tdma == 1) || (coex_dm->cur_ps_tdma == 2))) { +				halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 9); +				coex_dm->ps_tdma_du_adj_type = 9; +			} else if (coex_dm->cur_ps_tdma == 1) { +				halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 2); +				coex_dm->ps_tdma_du_adj_type = 2; +			} else if (coex_dm->cur_ps_tdma == 2) { +				halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 9); +				coex_dm->ps_tdma_du_adj_type = 9; +			} else if (coex_dm->cur_ps_tdma == 9) { +				halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 11); +				coex_dm->ps_tdma_du_adj_type = 11; +			} +		} else if (result == 1) { +			if ((BT_INFO_8821A_1ANT_A2DP_BASIC_RATE(bt_info_ext)) && +				((coex_dm->cur_ps_tdma == 1) || (coex_dm->cur_ps_tdma == 2))) { +				halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 9); +				coex_dm->ps_tdma_du_adj_type = 9; +			} else if (coex_dm->cur_ps_tdma == 11) { +				halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 9); +				coex_dm->ps_tdma_du_adj_type = 9; +			} else if (coex_dm->cur_ps_tdma == 9) { +				halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 2); +				coex_dm->ps_tdma_du_adj_type = 2; +			} else if (coex_dm->cur_ps_tdma == 2) { +				halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 1); +				coex_dm->ps_tdma_du_adj_type = 1; +			} +		} else { +			/* no change */ +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, "[BTCoex], ********** TDMA(on, %d) **********\n", +				coex_dm->cur_ps_tdma); +		} + +		if (coex_dm->cur_ps_tdma != 1 && +			coex_dm->cur_ps_tdma != 2 && +			coex_dm->cur_ps_tdma != 9 && +			coex_dm->cur_ps_tdma != 11) { +			/*  recover to previous adjust type */ +			halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, coex_dm->ps_tdma_du_adj_type); +		} +	} +} + +static void +halbtc8821a1ant_ps_tdma_check_for_power_save_state( +	struct btc_coexist *btcoexist, +	bool new_ps_state +	) +{ +	u8 lps_mode = 0x0; + +	btcoexist->btc_get(btcoexist, BTC_GET_U1_LPS_MODE, &lps_mode); + +	if (lps_mode) { +		/*  already under LPS state */ +		if (!new_ps_state) { +			/*  will leave LPS state, turn off psTdma first */ +			halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); +		} +	} else { +		/*  NO PS state */ +		if (new_ps_state) { +			/*  will enter LPS state, turn off psTdma first */ +			halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); +		} else { +			/*  keep state under NO PS state, do nothing. */ +		} +	} +} + +static void +halbtc8821a1ant_power_save_state( +	struct btc_coexist *btcoexist, +	u8 ps_type, +	u8 lps_val, +	u8 rpwm_val +	) +{ +	bool low_pwr_disable = false; + +	switch (ps_type) { +	case BTC_PS_WIFI_NATIVE: +		/*  recover to original 32k low power setting */ +		low_pwr_disable = false; +		btcoexist->btc_set(btcoexist, BTC_SET_ACT_DISABLE_LOW_POWER, &low_pwr_disable); +		btcoexist->btc_set(btcoexist, BTC_SET_ACT_NORMAL_LPS, NULL); +		break; +	case BTC_PS_LPS_ON: +		halbtc8821a1ant_ps_tdma_check_for_power_save_state(btcoexist, true); +		halbtc8821a1ant_lps_rpwm(btcoexist, NORMAL_EXEC, lps_val, rpwm_val); +		/*  when coex force to enter LPS, do not enter 32k low power. */ +		low_pwr_disable = true; +		btcoexist->btc_set(btcoexist, BTC_SET_ACT_DISABLE_LOW_POWER, &low_pwr_disable); +		/*  power save must executed before psTdma. */ +		btcoexist->btc_set(btcoexist, BTC_SET_ACT_ENTER_LPS, NULL); +		break; +	case BTC_PS_LPS_OFF: +		halbtc8821a1ant_ps_tdma_check_for_power_save_state(btcoexist, false); +		btcoexist->btc_set(btcoexist, BTC_SET_ACT_LEAVE_LPS, NULL); +		break; +	default: +		break; +	} +} + +static void +halbtc8821a1ant_coex_under_5g( +	struct btc_coexist *btcoexist +	) +{ +	halbtc8821a1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); + +	halbtc8821a1ant_ignore_wlan_act(btcoexist, NORMAL_EXEC, true); + +	halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 10); + +	halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + +	halbtc8821a1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0); + +	halbtc8821a1ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 5); +} + +static void +halbtc8821a1ant_action_wifi_only( +	struct btc_coexist *btcoexist +	) +{ +	halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); +	halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 9); +} + +static void +halbtc8821a1ant_monitor_bt_enable_disable( +	struct btc_coexist *btcoexist +	) +{ +	static bool pre_bt_disabled; +	static u32 bt_disable_cnt; +	bool bt_active = true, bt_disabled = false; + +	/*  This function check if bt is disabled */ + +	if (coex_sta->high_priority_tx == 0 && +		coex_sta->high_priority_rx == 0 && +		coex_sta->low_priority_tx == 0 && +		coex_sta->low_priority_rx == 0) { +		bt_active = false; +	} +	if (coex_sta->high_priority_tx == 0xffff && +	    coex_sta->high_priority_rx == 0xffff && +	    coex_sta->low_priority_tx == 0xffff && +	    coex_sta->low_priority_rx == 0xffff) { +		bt_active = false; +	} +	if (bt_active) { +		bt_disable_cnt = 0; +		bt_disabled = false; +		btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_DISABLE, +				   &bt_disabled); +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, +			  "[BTCoex], BT is enabled !!\n"); +	} else { +		bt_disable_cnt++; +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, +			  "[BTCoex], bt all counters = 0, %d times!!\n", +			  bt_disable_cnt); +		if (bt_disable_cnt >= 2) { +			bt_disabled = true; +			btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_DISABLE, +					   &bt_disabled); +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, +				  "[BTCoex], BT is disabled !!\n"); +			halbtc8821a1ant_action_wifi_only(btcoexist); +		} +	} +	if (pre_bt_disabled != bt_disabled) { +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, +			  "[BTCoex], BT is from %s to %s!!\n", +			  (pre_bt_disabled ? "disabled" : "enabled"), +			  (bt_disabled ? "disabled" : "enabled")); +		pre_bt_disabled = bt_disabled; +		if (bt_disabled) { +			btcoexist->btc_set(btcoexist, +					   BTC_SET_ACT_LEAVE_LPS, NULL); +			btcoexist->btc_set(btcoexist, +					   BTC_SET_ACT_NORMAL_LPS, NULL); +		} +	} +} + +/*	Software Coex Mechanism start */ +static void halbtc8821a1ant_action_sco(struct btc_coexist *btcoexist) +{ +	halbtc8821a1ant_sw_mechanism(btcoexist, true); +} + +static void halbtc8821a1ant_action_hid(struct btc_coexist *btcoexist) +{ +	halbtc8821a1ant_sw_mechanism(btcoexist, true); +} + +/* A2DP only / PAN(EDR) only/ A2DP+PAN(HS) */ +static void halbtc8821a1ant_action_a2dp(struct btc_coexist *btcoexist) +{ +	halbtc8821a1ant_sw_mechanism(btcoexist, false); +} + +static void halbtc8821a1ant_action_a2dp_pan_hs(struct btc_coexist *btcoexist) +{ +	halbtc8821a1ant_sw_mechanism(btcoexist, false); +} + +static void halbtc8821a1ant_action_pan_edr(struct btc_coexist *btcoexist) +{ +	halbtc8821a1ant_sw_mechanism(btcoexist, false); +} + +/* PAN(HS) only */ +static void halbtc8821a1ant_action_pan_hs(struct btc_coexist *btcoexist) +{ +	halbtc8821a1ant_sw_mechanism(btcoexist, false); +} + +/* PAN(EDR)+A2DP */ +static void halbtc8821a1ant_action_pan_edr_a2dp(struct btc_coexist *btcoexist) +{ +	halbtc8821a1ant_sw_mechanism(btcoexist, false); +} + +static void halbtc8821a1ant_action_pan_edr_hid(struct btc_coexist *btcoexist) +{ +	halbtc8821a1ant_sw_mechanism(btcoexist, true); +} + +/*  HID+A2DP+PAN(EDR) */ +static void halbtc8821a1ant_action_hid_a2dp_pan_edr(struct btc_coexist *btcoexist) +{ +	halbtc8821a1ant_sw_mechanism(btcoexist, true); +} + +static void halbtc8821a1ant_action_hid_a2dp(struct btc_coexist *btcoexist) +{ +	halbtc8821a1ant_sw_mechanism(btcoexist, true); +} + +/*	Non-Software Coex Mechanism start */ +static void halbtc8821a1ant_action_hs(struct btc_coexist *btcoexist) +{ +	halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 5); +	halbtc8821a1ant_coex_table_with_type(btcoexist, FORCE_EXEC, 2); +} + +static void halbtc8821a1ant_action_bt_inquiry(struct btc_coexist *btcoexist) +{ +	struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; +	bool wifi_connected = false; + +	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, &wifi_connected); + +	if (!wifi_connected) { +		halbtc8821a1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); +		halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 5); +		halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); +	} else if ((bt_link_info->sco_exist) || +			(bt_link_info->hid_only)) { +		/*  SCO/HID-only busy */ +		halbtc8821a1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); +		halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 32); +		halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); +	} else { +		halbtc8821a1ant_power_save_state(btcoexist, BTC_PS_LPS_ON, 0x50, 0x4); +		halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 30); +		halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); +	} +} + +static void +halbtc8821a1ant_action_bt_sco_hid_only_busy( +	struct btc_coexist *btcoexist, +	u8 wifi_status +	) +{ +	/*  tdma and coex table */ +	halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 5); + +	if (BT_8821A_1ANT_WIFI_STATUS_NON_CONNECTED_ASSO_AUTH_SCAN == wifi_status) +		halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); +	else +		halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); +} + +static void action_wifi_connected_bt_acl_busy(struct btc_coexist *btcoexist, u8 wifi_status) +{ +	u8 bt_rssi_state; + +	struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; +	bt_rssi_state = halbtc8821a1ant_bt_rssi_state(2, 28, 0); + +	if (bt_link_info->hid_only)  { +		/* HID */ +		halbtc8821a1ant_action_bt_sco_hid_only_busy(btcoexist, wifi_status); +		coex_dm->auto_tdma_adjust = false; +		return; +	} else if (bt_link_info->a2dp_only) { /* A2DP */ +		if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || +			(bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +			 halbtc8821a1ant_tdma_duration_adjust_for_acl(btcoexist, wifi_status); +		} else { /* for low BT RSSI */ +			halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 11); +			coex_dm->auto_tdma_adjust = false; +		} + +		halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); +	} else if (bt_link_info->hid_exist && bt_link_info->a2dp_exist) { +		/* HID+A2DP */ +		if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || +		    (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +			halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 14); +			coex_dm->auto_tdma_adjust = false; +		} else /* for low BT RSSI */ { +			halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 11); +			coex_dm->auto_tdma_adjust = false; +		} + +		halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); +	} else if ((bt_link_info->pan_only) || (bt_link_info->hid_exist && bt_link_info->pan_exist)) { +		/* PAN(OPP, FTP), HID+PAN(OPP, FTP) */ +		halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 3); +		halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); +		coex_dm->auto_tdma_adjust = false; +	} else if (((bt_link_info->a2dp_exist) && (bt_link_info->pan_exist)) || +		   (bt_link_info->hid_exist && bt_link_info->a2dp_exist && +		    bt_link_info->pan_exist)) { +		/* A2DP+PAN(OPP, FTP), HID+A2DP+PAN(OPP, FTP) */ +		halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 13); +		halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); +		coex_dm->auto_tdma_adjust = false; +	} else { +		halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 11); +		halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); +		coex_dm->auto_tdma_adjust = false; +	} +} + +static void +halbtc8821a1ant_action_wifi_not_connected( +	struct btc_coexist *btcoexist +	) +{ +	/*  power save state */ +	halbtc8821a1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); + +	/*  tdma and coex table	 */ +	halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); +	halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); +} + +static void wifi_not_connected_asso_auth_scan(struct btc_coexist *btcoexist) +{ +	halbtc8821a1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); + +	halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 22); +	halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); +} + +static void +halbtc8821a1ant_action_wifi_connected_scan( +	struct btc_coexist *btcoexist +	) +{ +	struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + +	/*  power save state */ +	halbtc8821a1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); + +	/*  tdma and coex table */ +	if (BT_8821A_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) { +		if (bt_link_info->a2dp_exist && bt_link_info->pan_exist) { +			halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 22); +			halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); +		} else { +		halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 20); +		halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); +	} +	} else if ((BT_8821A_1ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) || +			(BT_8821A_1ANT_BT_STATUS_ACL_SCO_BUSY == coex_dm->bt_status)) { +		halbtc8821a1ant_action_bt_sco_hid_only_busy(btcoexist, +			BT_8821A_1ANT_WIFI_STATUS_CONNECTED_SCAN); +	} else { +		halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 20); +		halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); +	} +} + +static void action_wifi_connected_special_packet(struct btc_coexist *btcoexist) +{ +	bool hs_connecting = false; +	struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + +	btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_CONNECTING, &hs_connecting); + +	halbtc8821a1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); + +	/*  tdma and coex table */ +	if (BT_8821A_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) { +		if (bt_link_info->a2dp_exist && bt_link_info->pan_exist) { +			halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 22); +			halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); +		} else { +			halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 20); +			halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); +		} +	} else { +		halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 20); +		halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); +	} +} + +static void halbtc8821a1ant_action_wifi_connected(struct btc_coexist *btcoexist) +{ +	bool wifi_busy = false; +	bool scan = false, link = false, roam = false; +	bool under_4way = false; + +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, "[BTCoex], CoexForWifiConnect() ===>\n"); + +	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS, &under_4way); +	if (under_4way) { +		action_wifi_connected_special_packet(btcoexist); +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, "[BTCoex], CoexForWifiConnect(), return for wifi is under 4way<===\n"); +		return; +	} + +	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan); +	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link); +	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam); +	if (scan || link || roam) { +		halbtc8821a1ant_action_wifi_connected_scan(btcoexist); +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, "[BTCoex], CoexForWifiConnect(), return for wifi is under scan<===\n"); +		return; +	} + +	/*  power save state */ +	if (BT_8821A_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status && !btcoexist->bt_link_info.hid_only) +		halbtc8821a1ant_power_save_state(btcoexist, BTC_PS_LPS_ON, 0x50, 0x4); +	else +		halbtc8821a1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); + +	/*  tdma and coex table */ +	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); +	if (!wifi_busy) { +		if (BT_8821A_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) { +			action_wifi_connected_bt_acl_busy(btcoexist, +				BT_8821A_1ANT_WIFI_STATUS_CONNECTED_IDLE); +		} else if ((BT_8821A_1ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) || +			(BT_8821A_1ANT_BT_STATUS_ACL_SCO_BUSY == coex_dm->bt_status)) { +			halbtc8821a1ant_action_bt_sco_hid_only_busy(btcoexist, +				BT_8821A_1ANT_WIFI_STATUS_CONNECTED_IDLE); +		} else { +			halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 5); +			halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); +		} +	} else { +		if (BT_8821A_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) { +			action_wifi_connected_bt_acl_busy(btcoexist, +				BT_8821A_1ANT_WIFI_STATUS_CONNECTED_BUSY); +		} else if ((BT_8821A_1ANT_BT_STATUS_SCO_BUSY == +			    coex_dm->bt_status) || +			   (BT_8821A_1ANT_BT_STATUS_ACL_SCO_BUSY == +			    coex_dm->bt_status)) { +			halbtc8821a1ant_action_bt_sco_hid_only_busy(btcoexist, +				BT_8821A_1ANT_WIFI_STATUS_CONNECTED_BUSY); +		} else { +			halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, +						true, 5); +			halbtc8821a1ant_coex_table_with_type(btcoexist, +							     NORMAL_EXEC, 2); +		} +	} +} + +static void run_sw_coexist_mechanism(struct btc_coexist *btcoexist) +{ +	u8 algorithm = 0; + +	algorithm = halbtc8821a1ant_action_algorithm(btcoexist); +	coex_dm->cur_algorithm = algorithm; + +	if (!halbtc8821a1ant_is_common_action(btcoexist)) { +		switch (coex_dm->cur_algorithm) { +		case BT_8821A_1ANT_COEX_ALGO_SCO: +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +				  "[BTCoex], Action algorithm = SCO.\n"); +			halbtc8821a1ant_action_sco(btcoexist); +			break; +		case BT_8821A_1ANT_COEX_ALGO_HID: +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +				  "[BTCoex], Action algorithm = HID.\n"); +			halbtc8821a1ant_action_hid(btcoexist); +			break; +		case BT_8821A_1ANT_COEX_ALGO_A2DP: +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +				  "[BTCoex], Action algorithm = A2DP.\n"); +			halbtc8821a1ant_action_a2dp(btcoexist); +			break; +		case BT_8821A_1ANT_COEX_ALGO_A2DP_PANHS: +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +				  "[BTCoex], Action algorithm = A2DP+PAN(HS).\n"); +			halbtc8821a1ant_action_a2dp_pan_hs(btcoexist); +			break; +		case BT_8821A_1ANT_COEX_ALGO_PANEDR: +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +				  "[BTCoex], Action algorithm = PAN(EDR).\n"); +			halbtc8821a1ant_action_pan_edr(btcoexist); +			break; +		case BT_8821A_1ANT_COEX_ALGO_PANHS: +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +				  "[BTCoex], Action algorithm = HS mode.\n"); +			halbtc8821a1ant_action_pan_hs(btcoexist); +			break; +		case BT_8821A_1ANT_COEX_ALGO_PANEDR_A2DP: +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +				  "[BTCoex], Action algorithm = PAN+A2DP.\n"); +			halbtc8821a1ant_action_pan_edr_a2dp(btcoexist); +			break; +		case BT_8821A_1ANT_COEX_ALGO_PANEDR_HID: +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +				  "[BTCoex], Action algorithm = PAN(EDR)+HID.\n"); +			halbtc8821a1ant_action_pan_edr_hid(btcoexist); +			break; +		case BT_8821A_1ANT_COEX_ALGO_HID_A2DP_PANEDR: +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +				  "[BTCoex], Action algorithm = HID+A2DP+PAN.\n"); +			halbtc8821a1ant_action_hid_a2dp_pan_edr(btcoexist); +			break; +		case BT_8821A_1ANT_COEX_ALGO_HID_A2DP: +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +				  "[BTCoex], Action algorithm = HID+A2DP.\n"); +			halbtc8821a1ant_action_hid_a2dp(btcoexist); +			break; +		default: +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +				  "[BTCoex], Action algorithm = coexist All Off!!\n"); +			break; +		} +		coex_dm->pre_algorithm = coex_dm->cur_algorithm; +	} +} + +static void halbtc8821a1ant_run_coexist_mechanism(struct btc_coexist *btcoexist) +{ +	struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; +	bool wifi_connected = false, bt_hs_on = false; +	bool increase_scan_dev_num = false; +	bool bt_ctrl_agg_buf_size = false; +	u8 agg_buf_size = 5; +	u8 wifi_rssi_state = BTC_RSSI_STATE_HIGH; +	bool wifi_under_5g = false; + +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +		  "[BTCoex], RunCoexistMechanism() ===>\n"); + +	if (btcoexist->manual_control) { +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +			  "[BTCoex], RunCoexistMechanism(), return for Manual CTRL <===\n"); +		return; +	} + +	if (btcoexist->stop_coex_dm) { +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +			  "[BTCoex], RunCoexistMechanism(), return for Stop Coex DM <===\n"); +		return; +	} + +	if (coex_sta->under_ips) { +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +			  "[BTCoex], wifi is under IPS !!!\n"); +		return; +	} + +	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, +			   &wifi_under_5g); +	if (wifi_under_5g) { +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +			  "[BTCoex], RunCoexistMechanism(), return for 5G <===\n"); +		halbtc8821a1ant_coex_under_5g(btcoexist); +		return; +	} + +	if ((BT_8821A_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) || +	    (BT_8821A_1ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) || +	    (BT_8821A_1ANT_BT_STATUS_ACL_SCO_BUSY == coex_dm->bt_status)) { +		increase_scan_dev_num = true; +	} + +	btcoexist->btc_set(btcoexist, BTC_SET_BL_INC_SCAN_DEV_NUM, +			   &increase_scan_dev_num); + +	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, +			   &wifi_connected); + +	if (!bt_link_info->sco_exist && !bt_link_info->hid_exist) { +		halbtc8821a1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0); +	} else { +		if (wifi_connected) { +			wifi_rssi_state = Wifi_rssi_state(btcoexist, 1, 2, +							  30, 0); +			if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || +			    (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) +				halbtc8821a1ant_limited_tx(btcoexist, +							   NORMAL_EXEC, 1, 1, +							   1, 1); +			else +				halbtc8821a1ant_limited_tx(btcoexist, +							   NORMAL_EXEC, 1, 1, +							   1, 1); +		} else { +			halbtc8821a1ant_limited_tx(btcoexist, NORMAL_EXEC, +						   0, 0, 0, 0); +		} +	} + +	if (bt_link_info->sco_exist) { +		bt_ctrl_agg_buf_size = true; +		agg_buf_size = 0x3; +	} else if (bt_link_info->hid_exist) { +		bt_ctrl_agg_buf_size = true; +		agg_buf_size = 0x5; +	} else if (bt_link_info->a2dp_exist || bt_link_info->pan_exist) { +		bt_ctrl_agg_buf_size = true; +		agg_buf_size = 0x8; +	} +	halbtc8821a1ant_limited_rx(btcoexist, NORMAL_EXEC, false, +				   bt_ctrl_agg_buf_size, agg_buf_size); + +	run_sw_coexist_mechanism(btcoexist); + +	btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); +	if (coex_sta->c2h_bt_inquiry_page) { +		halbtc8821a1ant_action_bt_inquiry(btcoexist); +		return; +	} else if (bt_hs_on) { +		halbtc8821a1ant_action_hs(btcoexist); +		return; +	} + +	if (!wifi_connected) { +		bool scan = false, link = false, roam = false; + +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, "[BTCoex], wifi is non connected-idle !!!\n"); + +		btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan); +		btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link); +		btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam); + +		if (scan || link || roam) +			wifi_not_connected_asso_auth_scan(btcoexist); +		else +			halbtc8821a1ant_action_wifi_not_connected(btcoexist); +	} else { +		/*  wifi LPS/Busy */ +		halbtc8821a1ant_action_wifi_connected(btcoexist); +	} +} + +static void halbtc8821a1ant_init_coex_dm(struct btc_coexist *btcoexist) +{ +	/*  force to reset coex mechanism */ +	/*  sw all off */ +	halbtc8821a1ant_sw_mechanism(btcoexist, false); + +	halbtc8821a1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 8); +	halbtc8821a1ant_coex_table_with_type(btcoexist, FORCE_EXEC, 0); +} + +static void halbtc8821a1ant_init_hw_config(struct btc_coexist *btcoexist, +					   bool back_up) +{ +	u8 u1_tmp = 0; +	bool wifi_under_5g = false; + +	BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, +		  "[BTCoex], 1Ant Init HW Config!!\n"); + +	if (back_up) { +		coex_dm->backup_arfr_cnt1 = +			btcoexist->btc_read_4byte(btcoexist, 0x430); +		coex_dm->backup_arfr_cnt2 = +			btcoexist->btc_read_4byte(btcoexist, 0x434); +		coex_dm->backup_retry_limit = +			btcoexist->btc_read_2byte(btcoexist, 0x42a); +		coex_dm->backup_ampdu_max_time = +			btcoexist->btc_read_1byte(btcoexist, 0x456); +	} + +	/*  0x790[5:0] = 0x5 */ +	u1_tmp = btcoexist->btc_read_1byte(btcoexist, 0x790); +	u1_tmp &= 0xc0; +	u1_tmp |= 0x5; +	btcoexist->btc_write_1byte(btcoexist, 0x790, u1_tmp); + +	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); + +	/* Antenna config */ +	if (wifi_under_5g) +		halbtc8821a1ant_set_ant_path(btcoexist, BTC_ANT_PATH_BT, +					     true, false); +	else +		halbtc8821a1ant_set_ant_path(btcoexist, BTC_ANT_PATH_PTA, +					     true, false); +	/*  PTA parameter */ +	halbtc8821a1ant_coex_table_with_type(btcoexist, FORCE_EXEC, 0); + +	/*  Enable counter statistics */ +	/* 0x76e[3] = 1, WLAN_Act control by PTA */ +	btcoexist->btc_write_1byte(btcoexist, 0x76e, 0xc); +	btcoexist->btc_write_1byte(btcoexist, 0x778, 0x3); +	btcoexist->btc_write_1byte_bitmask(btcoexist, 0x40, 0x20, 0x1); +} + +/*  */ +/*  work around function start with wa_halbtc8821a1ant_ */ +/*  */ +/*  */ +/*  extern function start with EXhalbtc8821a1ant_ */ +/*  */ +void +ex_halbtc8821a1ant_init_hwconfig( +	struct btc_coexist *btcoexist +	) +{ +	halbtc8821a1ant_init_hw_config(btcoexist, true); +} + +void +ex_halbtc8821a1ant_init_coex_dm( +	struct btc_coexist *btcoexist +	) +{ +	BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, "[BTCoex], Coex Mechanism Init!!\n"); + +	btcoexist->stop_coex_dm = false; + +	halbtc8821a1ant_init_coex_dm(btcoexist); + +	halbtc8821a1ant_query_bt_info(btcoexist); +} + +void ex_halbtc8821a1ant_display_coex_info(struct btc_coexist *btcoexist) +{ +	struct btc_board_info *board_info = &btcoexist->board_info; +	struct btc_stack_info *stack_info = &btcoexist->stack_info; +	struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; +	u8 *cli_buf = btcoexist->cli_buf; +	u8 u1_tmp[4], i, bt_info_ext, ps_tdma_case = 0; +	u16 u2_tmp[4]; +	u32 u4_tmp[4]; +	bool roam = false, scan = false, link = false, wifi_under_5g = false; +	bool bt_hs_on = false, wifi_busy = false; +	long wifi_rssi = 0, bt_hs_rssi = 0; +	u32 wifi_bw, wifi_traffic_dir; +	u8 wifi_dot11_chnl, wifi_hs_chnl; +	u32 fw_ver = 0, bt_patch_ver = 0; + +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, +		   "\n ============[BT Coexist info] ============"); +	CL_PRINTF(cli_buf); + +	if (btcoexist->manual_control) { +		CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, +			   "\n ============[Under Manual Control] ============"); +		CL_PRINTF(cli_buf); +		CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, +			   "\n =========================================="); +		CL_PRINTF(cli_buf); +	} +	if (btcoexist->stop_coex_dm) { +		CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, +			   "\n ============[Coex is STOPPED] ============"); +		CL_PRINTF(cli_buf); +		CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, +			   "\n =========================================="); +		CL_PRINTF(cli_buf); +	} + +	if (!board_info->bt_exist) { +		CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\n BT not exists !!!"); +		CL_PRINTF(cli_buf); +		return; +	} + +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\n %-35s = %d/ %d/ %d", +		   "Ant PG Num/ Ant Mech/ Ant Pos: ", +		   board_info->pg_ant_num, board_info->btdm_ant_num, +		   board_info->btdm_ant_pos); +	CL_PRINTF(cli_buf); + +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\n %-35s = %s / %d", +		   "BT stack/ hci ext ver", +		   ((stack_info->profile_notified) ? "Yes" : "No"), +		   stack_info->hci_version); +	CL_PRINTF(cli_buf); + +	btcoexist->btc_get(btcoexist, BTC_GET_U4_BT_PATCH_VER, &bt_patch_ver); +	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver); +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\n %-35s = %d_%x/ 0x%x/ 0x%x(%d)", +		   "CoexVer/ FwVer/ PatchVer", +		   glcoex_ver_date_8821a_1ant, glcoex_ver_8821a_1ant, fw_ver, +		   bt_patch_ver, bt_patch_ver); +	CL_PRINTF(cli_buf); + +	btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); +	btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_DOT11_CHNL, +			   &wifi_dot11_chnl); +	btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_HS_CHNL, &wifi_hs_chnl); +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\n %-35s = %d / %d(%d)", +		   "Dot11 channel / HsChnl(HsMode)", +		   wifi_dot11_chnl, wifi_hs_chnl, bt_hs_on); +	CL_PRINTF(cli_buf); + +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\n %-35s = %02x %02x %02x ", +		   "H2C Wifi inform bt chnl Info", +		   coex_dm->wifi_chnl_info[0], coex_dm->wifi_chnl_info[1], +		   coex_dm->wifi_chnl_info[2]); +	CL_PRINTF(cli_buf); + +	btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifi_rssi); +	btcoexist->btc_get(btcoexist, BTC_GET_S4_HS_RSSI, &bt_hs_rssi); +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\n %-35s = %d/ %d", +		   "Wifi rssi/ HS rssi", +		   (int)wifi_rssi, (int)bt_hs_rssi); +	CL_PRINTF(cli_buf); + +	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan); +	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link); +	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam); +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\n %-35s = %d/ %d/ %d ", +		   "Wifi link/ roam/ scan", +		   link, roam, scan); +	CL_PRINTF(cli_buf); + +	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); +	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); +	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); +	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_TRAFFIC_DIRECTION, +			   &wifi_traffic_dir); +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\n %-35s = %s / %s/ %s ", +		   "Wifi status", +		   (wifi_under_5g ? "5G" : "2.4G"), +		   ((BTC_WIFI_BW_LEGACY == wifi_bw) ? "Legacy" : +		    (((BTC_WIFI_BW_HT40 == wifi_bw) ? "HT40" : "HT20"))), +		   ((!wifi_busy) ? "idle" : +		    ((BTC_WIFI_TRAFFIC_TX == wifi_traffic_dir) ? +		     "uplink" : "downlink"))); +	CL_PRINTF(cli_buf); +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, +		   "\n %-35s = [%s/ %d/ %d] ", "BT [status/ rssi/ retryCnt]", +		   ((btcoexist->bt_info.bt_disabled) ? ("disabled") : +		    ((coex_sta->c2h_bt_inquiry_page) ? ("inquiry/page scan") : +		     ((BT_8821A_1ANT_BT_STATUS_NON_CONNECTED_IDLE == +		       coex_dm->bt_status) ? "non-connected idle" : +		      ((BT_8821A_1ANT_BT_STATUS_CONNECTED_IDLE == +		       coex_dm->bt_status) ? "connected-idle" : "busy")))), +		   coex_sta->bt_rssi, coex_sta->bt_retry_cnt); +	CL_PRINTF(cli_buf); + +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\n %-35s = %d / %d / %d / %d", +		   "SCO/HID/PAN/A2DP", +		   bt_link_info->sco_exist, bt_link_info->hid_exist, +		   bt_link_info->pan_exist, bt_link_info->a2dp_exist); +	CL_PRINTF(cli_buf); +	btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_BT_LINK_INFO); + +	bt_info_ext = coex_sta->bt_info_ext; +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\n %-35s = %s", +		   "BT Info A2DP rate", +		   (bt_info_ext & BIT(0)) ? "Basic rate" : "EDR rate"); +	CL_PRINTF(cli_buf); + +	for (i = 0; i < BT_INFO_SRC_8821A_1ANT_MAX; i++) { +		if (coex_sta->bt_info_c2h_cnt[i]) { +			CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, +				   "\n %-35s = %02x %02x %02x %02x %02x %02x %02x(%d)", +				   glbt_info_src_8821a_1ant[i], +				   coex_sta->bt_info_c2h[i][0], +				   coex_sta->bt_info_c2h[i][1], +				   coex_sta->bt_info_c2h[i][2], +				   coex_sta->bt_info_c2h[i][3], +				   coex_sta->bt_info_c2h[i][4], +				   coex_sta->bt_info_c2h[i][5], +				   coex_sta->bt_info_c2h[i][6], +				   coex_sta->bt_info_c2h_cnt[i]); +			CL_PRINTF(cli_buf); +		} +	} +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\n %-35s = %s/%s, (0x%x/0x%x)", +		   "PS state, IPS/LPS, (lps/rpwm)", +		   ((coex_sta->under_ips ? "IPS ON" : "IPS OFF")), +		   ((coex_sta->under_lps ? "LPS ON" : "LPS OFF")), +		   btcoexist->bt_info.lps_val, +		   btcoexist->bt_info.rpwm_val); +	CL_PRINTF(cli_buf); +	btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_FW_PWR_MODE_CMD); + +	if (!btcoexist->manual_control) { +		/*  Sw mechanism	 */ +		CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, +			   "\n %-35s", "============[Sw mechanism] ============"); +		CL_PRINTF(cli_buf); + +		CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, +			   "\n %-35s = %d", "SM[LowPenaltyRA]", +			   coex_dm->cur_low_penalty_ra); +		CL_PRINTF(cli_buf); + +		CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, +			   "\n %-35s = %s/ %s/ %d ", "DelBA/ BtCtrlAgg/ AggSize", +			   (btcoexist->bt_info.reject_agg_pkt ? "Yes" : "No"), +			   (btcoexist->bt_info.b_bt_ctrl_buf_size ? +			    "Yes" : "No"), +			   btcoexist->bt_info.agg_buf_size); +		CL_PRINTF(cli_buf); +		CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, +			   "\n %-35s = 0x%x ", "Rate Mask", +			   btcoexist->bt_info.ra_mask); +		CL_PRINTF(cli_buf); + +		/*  Fw mechanism */ +		CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\n %-35s", +			   "============[Fw mechanism] ============"); +		CL_PRINTF(cli_buf); + +		ps_tdma_case = coex_dm->cur_ps_tdma; +		CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, +			   "\n %-35s = %02x %02x %02x %02x %02x case-%d (auto:%d)", +			   "PS TDMA", +			   coex_dm->ps_tdma_para[0], coex_dm->ps_tdma_para[1], +			   coex_dm->ps_tdma_para[2], coex_dm->ps_tdma_para[3], +			   coex_dm->ps_tdma_para[4], ps_tdma_case, +			   coex_dm->auto_tdma_adjust); +		CL_PRINTF(cli_buf); + +		CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\n %-35s = 0x%x ", +			   "Latest error condition(should be 0)", +			   coex_dm->error_condition); +		CL_PRINTF(cli_buf); + +		CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\n %-35s = %d ", +			   "IgnWlanAct", +			   coex_dm->cur_ignore_wlan_act); +		CL_PRINTF(cli_buf); +	} + +	/*  Hw setting		 */ +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\n %-35s", +		   "============[Hw setting] ============"); +	CL_PRINTF(cli_buf); + +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\n %-35s = 0x%x/0x%x/0x%x/0x%x", +		   "backup ARFR1/ARFR2/RL/AMaxTime", +		   coex_dm->backup_arfr_cnt1, coex_dm->backup_arfr_cnt2, +		   coex_dm->backup_retry_limit, coex_dm->backup_ampdu_max_time); +	CL_PRINTF(cli_buf); + +	u4_tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x430); +	u4_tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x434); +	u2_tmp[0] = btcoexist->btc_read_2byte(btcoexist, 0x42a); +	u1_tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x456); +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\n %-35s = 0x%x/0x%x/0x%x/0x%x", +		   "0x430/0x434/0x42a/0x456", +		   u4_tmp[0], u4_tmp[1], u2_tmp[0], u1_tmp[0]); +	CL_PRINTF(cli_buf); + +	u1_tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x778); +	u4_tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xc58); +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, +		   "\n %-35s = 0x%x/ 0x%x", "0x778/ 0xc58[29:25]", +		   u1_tmp[0], (u4_tmp[0]&0x3e000000) >> 25); +	CL_PRINTF(cli_buf); + +	u1_tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x8db); +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\n %-35s = 0x%x", "0x8db[6:5]", +		   ((u1_tmp[0]&0x60)>>5)); +	CL_PRINTF(cli_buf); + +	u1_tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x975); +	u4_tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xcb4); +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\n %-35s = 0x%x/ 0x%x/ 0x%x", +		   "0xcb4[29:28]/0xcb4[7:0]/0x974[9:8]", +		   (u4_tmp[0]&0x30000000)>>28, u4_tmp[0]&0xff, u1_tmp[0] & 0x3); +	CL_PRINTF(cli_buf); + +	u1_tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x40); +	u4_tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x4c); +	u1_tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0x64); +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\n %-35s = 0x%x/ 0x%x/ 0x%x", +		   "0x40/0x4c[24:23]/0x64[0]", +		   u1_tmp[0], ((u4_tmp[0]&0x01800000)>>23), u1_tmp[1]&0x1); +	CL_PRINTF(cli_buf); + +	u4_tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x550); +	u1_tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x522); +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\n %-35s = 0x%x/ 0x%x", +		   "0x550(bcn ctrl)/0x522", +		   u4_tmp[0], u1_tmp[0]); +	CL_PRINTF(cli_buf); + +	u4_tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xc50); +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\n %-35s = 0x%x", "0xc50(dig)", +		   u4_tmp[0]&0xff); +	CL_PRINTF(cli_buf); + +	u4_tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xf48); +	u1_tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0xa5d); +	u1_tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0xa5c); +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\n %-35s = 0x%x/ 0x%x", +		   "OFDM-FA/ CCK-FA", +		   u4_tmp[0], (u1_tmp[0]<<8) + u1_tmp[1]); +	CL_PRINTF(cli_buf); + +	u4_tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x6c0); +	u4_tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x6c4); +	u4_tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0x6c8); +	u1_tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x6cc); +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, +		   "\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", +		   "0x6c0/0x6c4/0x6c8/0x6cc(coexTable)", +		   u4_tmp[0], u4_tmp[1], u4_tmp[2], u1_tmp[0]); +	CL_PRINTF(cli_buf); + +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\n %-35s = %d/ %d", +		   "0x770(high-pri rx/tx)", +		   coex_sta->high_priority_rx, coex_sta->high_priority_tx); +	CL_PRINTF(cli_buf); +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\n %-35s = %d/ %d", +		   "0x774(low-pri rx/tx)", +		   coex_sta->low_priority_rx, coex_sta->low_priority_tx); +	CL_PRINTF(cli_buf); +#if (BT_AUTO_REPORT_ONLY_8821A_1ANT == 1) +	halbtc8821a1ant_monitor_bt_ctr(btcoexist); +#endif +	btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_COEX_STATISTICS); +} + +void ex_halbtc8821a1ant_ips_notify(struct btc_coexist *btcoexist, u8 type) +{ +	if (btcoexist->manual_control || btcoexist->stop_coex_dm) +		return; + +	if (BTC_IPS_ENTER == type) { +		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, +			  "[BTCoex], IPS ENTER notify\n"); +		coex_sta->under_ips = true; +		halbtc8821a1ant_set_ant_path(btcoexist, BTC_ANT_PATH_BT, +					     false, true); +		/* set PTA control */ +		halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); +		halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); +	} else if (BTC_IPS_LEAVE == type) { +		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, +			  "[BTCoex], IPS LEAVE notify\n"); +		coex_sta->under_ips = false; + +		halbtc8821a1ant_run_coexist_mechanism(btcoexist); +	} +} + +void ex_halbtc8821a1ant_lps_notify(struct btc_coexist *btcoexist, u8 type) +{ +	if (btcoexist->manual_control || btcoexist->stop_coex_dm) +		return; + +	if (BTC_LPS_ENABLE == type) { +		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, +			  "[BTCoex], LPS ENABLE notify\n"); +		coex_sta->under_lps = true; +	} else if (BTC_LPS_DISABLE == type) { +		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, +			  "[BTCoex], LPS DISABLE notify\n"); +		coex_sta->under_lps = false; +	} +} + +void ex_halbtc8821a1ant_scan_notify(struct btc_coexist *btcoexist, u8 type) +{ +	bool wifi_connected = false, bt_hs_on = false; + +	if (btcoexist->manual_control || +	    btcoexist->stop_coex_dm || +	    btcoexist->bt_info.bt_disabled) +		return; + +	btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); +	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, +			   &wifi_connected); + +	halbtc8821a1ant_query_bt_info(btcoexist); + +	if (coex_sta->c2h_bt_inquiry_page) { +		halbtc8821a1ant_action_bt_inquiry(btcoexist); +		return; +	} else if (bt_hs_on) { +		halbtc8821a1ant_action_hs(btcoexist); +		return; +	} + +	if (BTC_SCAN_START == type) { +		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, +			  "[BTCoex], SCAN START notify\n"); +		if (!wifi_connected) { +			/*  non-connected scan */ +			wifi_not_connected_asso_auth_scan(btcoexist); +		} else { +			/*  wifi is connected */ +			halbtc8821a1ant_action_wifi_connected_scan(btcoexist); +		} +	} else if (BTC_SCAN_FINISH == type) { +		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, +			  "[BTCoex], SCAN FINISH notify\n"); +		if (!wifi_connected)	/*  non-connected scan */ +			halbtc8821a1ant_action_wifi_not_connected(btcoexist); +		else +			halbtc8821a1ant_action_wifi_connected(btcoexist); +	} +} + +void ex_halbtc8821a1ant_connect_notify(struct btc_coexist *btcoexist, u8 type) +{ +	bool wifi_connected = false, bt_hs_on = false; + +	if (btcoexist->manual_control || +	    btcoexist->stop_coex_dm || +	    btcoexist->bt_info.bt_disabled) +		return; + +	btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); +	if (coex_sta->c2h_bt_inquiry_page) { +		halbtc8821a1ant_action_bt_inquiry(btcoexist); +		return; +	} else if (bt_hs_on) { +		halbtc8821a1ant_action_hs(btcoexist); +		return; +	} + +	if (BTC_ASSOCIATE_START == type) { +		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, +			  "[BTCoex], CONNECT START notify\n"); +		wifi_not_connected_asso_auth_scan(btcoexist); +	} else if (BTC_ASSOCIATE_FINISH == type) { +		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, +			  "[BTCoex], CONNECT FINISH notify\n"); + +		btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, +				   &wifi_connected); +		if (!wifi_connected) /*  non-connected scan */ +			halbtc8821a1ant_action_wifi_not_connected(btcoexist); +		else +			halbtc8821a1ant_action_wifi_connected(btcoexist); +	} +} + +void ex_halbtc8821a1ant_media_status_notify(struct btc_coexist *btcoexist, +					    u8 type) +{ +	u8 h2c_parameter[3] = {0}; +	u32 wifi_bw; +	u8 wifi_central_chnl; + +	if (btcoexist->manual_control || +	    btcoexist->stop_coex_dm || +	    btcoexist->bt_info.bt_disabled) +		return; + +	if (BTC_MEDIA_CONNECT == type) +		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, +			  "[BTCoex], MEDIA connect notify\n"); +	else +		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, +			  "[BTCoex], MEDIA disconnect notify\n"); + +	/*  only 2.4G we need to inform bt the chnl mask */ +	btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_CENTRAL_CHNL, +			   &wifi_central_chnl); +	if ((BTC_MEDIA_CONNECT == type) && +	    (wifi_central_chnl <= 14)) { +		/* h2c_parameter[0] = 0x1; */ +		h2c_parameter[0] = 0x0; +		h2c_parameter[1] = wifi_central_chnl; +		btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); +		if (BTC_WIFI_BW_HT40 == wifi_bw) +			h2c_parameter[2] = 0x30; +		else +			h2c_parameter[2] = 0x20; +	} + +	coex_dm->wifi_chnl_info[0] = h2c_parameter[0]; +	coex_dm->wifi_chnl_info[1] = h2c_parameter[1]; +	coex_dm->wifi_chnl_info[2] = h2c_parameter[2]; + +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, +		  "[BTCoex], FW write 0x66 = 0x%x\n", +		  h2c_parameter[0]<<16|h2c_parameter[1]<<8|h2c_parameter[2]); + +	btcoexist->btc_fill_h2c(btcoexist, 0x66, 3, h2c_parameter); +} + +void ex_halbtc8821a1ant_special_packet_notify(struct btc_coexist *btcoexist, +					      u8 type) +{ +	bool bt_hs_on = false; + +	if (btcoexist->manual_control || +	    btcoexist->stop_coex_dm || +	    btcoexist->bt_info.bt_disabled) +		return; + +	coex_sta->special_pkt_period_cnt = 0; + +	btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); +	if (coex_sta->c2h_bt_inquiry_page) { +		halbtc8821a1ant_action_bt_inquiry(btcoexist); +		return; +	} else if (bt_hs_on) { +		halbtc8821a1ant_action_hs(btcoexist); +		return; +	} + +	if (BTC_PACKET_DHCP == type || +	    BTC_PACKET_EAPOL == type) { +		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, +			  "[BTCoex], special Packet(%d) notify\n", type); +		action_wifi_connected_special_packet(btcoexist); +	} +} + +void ex_halbtc8821a1ant_bt_info_notify(struct btc_coexist *btcoexist, +				       u8 *tmp_buf, u8 length) +{ +	u8 bt_info = 0; +	u8 i, rsp_source = 0; +	bool wifi_connected = false; +	bool bt_busy = false; +	bool wifi_under_5g = false; + +	coex_sta->c2h_bt_info_req_sent = false; + +	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); + +	rsp_source = tmp_buf[0]&0xf; +	if (rsp_source >= BT_INFO_SRC_8821A_1ANT_MAX) +		rsp_source = BT_INFO_SRC_8821A_1ANT_WIFI_FW; +	coex_sta->bt_info_c2h_cnt[rsp_source]++; + +	BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, +		  "[BTCoex], Bt info[%d], length =%d, hex data =[", +		  rsp_source, length); +	for (i = 0; i < length; i++) { +		coex_sta->bt_info_c2h[rsp_source][i] = tmp_buf[i]; +		if (i == 1) +			bt_info = tmp_buf[i]; +		if (i == length-1) +			BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, +				  "0x%02x]\n", tmp_buf[i]); +		else +			BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, +				  "0x%02x, ", tmp_buf[i]); +	} + +	if (BT_INFO_SRC_8821A_1ANT_WIFI_FW != rsp_source) { +		coex_sta->bt_retry_cnt =	/*  [3:0] */ +			coex_sta->bt_info_c2h[rsp_source][2]&0xf; + +		coex_sta->bt_rssi = +			coex_sta->bt_info_c2h[rsp_source][3]*2+10; + +		coex_sta->bt_info_ext = +			coex_sta->bt_info_c2h[rsp_source][4]; + +		/*  Here we need to resend some wifi info to BT */ +		/*  because bt is reset and loss of the info. */ +		if (coex_sta->bt_info_ext & BIT(1)) { +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +				  "[BTCoex], BT ext info bit1 check, send wifi BW&Chnl to BT!!\n"); +			btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, +					   &wifi_connected); +			if (wifi_connected) +				ex_halbtc8821a1ant_media_status_notify(btcoexist, +								       BTC_MEDIA_CONNECT); +			else +				ex_halbtc8821a1ant_media_status_notify(btcoexist, +								       BTC_MEDIA_DISCONNECT); +		} + +		if ((coex_sta->bt_info_ext & BIT(3)) && !wifi_under_5g) { +			if (!btcoexist->manual_control && +			    !btcoexist->stop_coex_dm) { +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +					  "[BTCoex], BT ext info bit3 check, set BT NOT to ignore Wlan active!!\n"); +				halbtc8821a1ant_ignore_wlan_act(btcoexist, +								FORCE_EXEC, false); +			} +		} else { +			/*  BT already NOT ignore Wlan active, do nothing here. */ +		} +#if (BT_AUTO_REPORT_ONLY_8821A_1ANT == 0) +		if ((coex_sta->bt_info_ext & BIT(4))) { +			/*  BT auto report already enabled, do nothing */ +		} else { +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +				  "[BTCoex], BT ext info bit4 check, set BT to enable Auto Report!!\n"); +			halbtc8821a1ant_bt_auto_report(btcoexist, +						       FORCE_EXEC, true); +		} +#endif +	} + +	/*  check BIT(2) first ==> check if bt is under inquiry or page scan */ +	if (bt_info & BT_INFO_8821A_1ANT_B_INQ_PAGE) +		coex_sta->c2h_bt_inquiry_page = true; +	else +		coex_sta->c2h_bt_inquiry_page = false; + +	/*  set link exist status */ +	if (!(bt_info&BT_INFO_8821A_1ANT_B_CONNECTION)) { +		coex_sta->bt_link_exist = false; +		coex_sta->pan_exist = false; +		coex_sta->a2dp_exist = false; +		coex_sta->hid_exist = false; +		coex_sta->sco_exist = false; +	} else { +		/*  connection exists */ +		coex_sta->bt_link_exist = true; +		if (bt_info & BT_INFO_8821A_1ANT_B_FTP) +			coex_sta->pan_exist = true; +		else +			coex_sta->pan_exist = false; +		if (bt_info & BT_INFO_8821A_1ANT_B_A2DP) +			coex_sta->a2dp_exist = true; +		else +			coex_sta->a2dp_exist = false; +		if (bt_info & BT_INFO_8821A_1ANT_B_HID) +			coex_sta->hid_exist = true; +		else +			coex_sta->hid_exist = false; +		if (bt_info & BT_INFO_8821A_1ANT_B_SCO_ESCO) +			coex_sta->sco_exist = true; +		else +			coex_sta->sco_exist = false; +	} + +	halbtc8821a1ant_update_bt_link_info(btcoexist); + +	if (!(bt_info&BT_INFO_8821A_1ANT_B_CONNECTION)) { +		coex_dm->bt_status = BT_8821A_1ANT_BT_STATUS_NON_CONNECTED_IDLE; +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +			  "[BTCoex], BtInfoNotify(), BT Non-Connected idle!!!\n"); +	} else if (bt_info == BT_INFO_8821A_1ANT_B_CONNECTION) { +		/*  connection exists but not busy */ +		coex_dm->bt_status = BT_8821A_1ANT_BT_STATUS_CONNECTED_IDLE; +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +			  "[BTCoex], BtInfoNotify(), BT Connected-idle!!!\n"); +	} else if ((bt_info&BT_INFO_8821A_1ANT_B_SCO_ESCO) || +		   (bt_info&BT_INFO_8821A_1ANT_B_SCO_BUSY)) { +		coex_dm->bt_status = BT_8821A_1ANT_BT_STATUS_SCO_BUSY; +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +			  "[BTCoex], BtInfoNotify(), BT SCO busy!!!\n"); +	} else if (bt_info&BT_INFO_8821A_1ANT_B_ACL_BUSY) { +		if (BT_8821A_1ANT_BT_STATUS_ACL_BUSY != coex_dm->bt_status) +			coex_dm->auto_tdma_adjust = false; +		coex_dm->bt_status = BT_8821A_1ANT_BT_STATUS_ACL_BUSY; +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +			  "[BTCoex], BtInfoNotify(), BT ACL busy!!!\n"); +	} else { +		coex_dm->bt_status = BT_8821A_1ANT_BT_STATUS_MAX; +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +			  "[BTCoex], BtInfoNotify(), BT Non-Defined state!!!\n"); +	} + +	if ((BT_8821A_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) || +	    (BT_8821A_1ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) || +	    (BT_8821A_1ANT_BT_STATUS_ACL_SCO_BUSY == coex_dm->bt_status)) +		bt_busy = true; +	else +		bt_busy = false; +	btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_TRAFFIC_BUSY, &bt_busy); + +	halbtc8821a1ant_run_coexist_mechanism(btcoexist); +} + +void ex_halbtc8821a1ant_halt_notify(struct btc_coexist *btcoexist) +{ +	BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, "[BTCoex], Halt notify\n"); + +	btcoexist->stop_coex_dm = true; + +	halbtc8821a1ant_set_ant_path(btcoexist, BTC_ANT_PATH_BT, false, true); +	halbtc8821a1ant_ignore_wlan_act(btcoexist, FORCE_EXEC, true); + +	halbtc8821a1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, +					 0x0, 0x0); +	halbtc8821a1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 0); + +	ex_halbtc8821a1ant_media_status_notify(btcoexist, BTC_MEDIA_DISCONNECT); +} + +void ex_halbtc8821a1ant_pnp_notify(struct btc_coexist *btcoexist, u8 pnp_state) +{ +	BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, "[BTCoex], Pnp notify\n"); + +	if (BTC_WIFI_PNP_SLEEP == pnp_state) { +		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, +			  "[BTCoex], Pnp notify to SLEEP\n"); +		btcoexist->stop_coex_dm = true; +		halbtc8821a1ant_ignore_wlan_act(btcoexist, FORCE_EXEC, true); +		halbtc8821a1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, +						 0x0, 0x0); +		halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 9); +	} else if (BTC_WIFI_PNP_WAKE_UP == pnp_state) { +		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, +			  "[BTCoex], Pnp notify to WAKE UP\n"); +		btcoexist->stop_coex_dm = false; +		halbtc8821a1ant_init_hw_config(btcoexist, false); +		halbtc8821a1ant_init_coex_dm(btcoexist); +		halbtc8821a1ant_query_bt_info(btcoexist); +	} +} + +void ex_halbtc8821a1ant_periodical(struct btc_coexist *btcoexist) +{ +	static u8 dis_ver_info_cnt; +	u32 fw_ver = 0, bt_patch_ver = 0; +	struct btc_board_info *board_info = &btcoexist->board_info; +	struct btc_stack_info *stack_info = &btcoexist->stack_info; + +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +		  "[BTCoex], ========================== Periodical ===========================\n"); + +	if (dis_ver_info_cnt <= 5) { +		dis_ver_info_cnt += 1; +		BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, +			  "[BTCoex], ****************************************************************\n"); +		BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, +			  "[BTCoex], Ant PG Num/ Ant Mech/ Ant Pos = %d/ %d/ %d\n", +			  board_info->pg_ant_num, board_info->btdm_ant_num, +			  board_info->btdm_ant_pos); +		BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, +			  "[BTCoex], BT stack/ hci ext ver = %s / %d\n", +			  ((stack_info->profile_notified) ? "Yes" : "No"), +			  stack_info->hci_version); +		btcoexist->btc_get(btcoexist, BTC_GET_U4_BT_PATCH_VER, +				   &bt_patch_ver); +		btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver); +		BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, +			  "[BTCoex], CoexVer/ FwVer/ PatchVer = %d_%x/ 0x%x/ 0x%x(%d)\n", +			  glcoex_ver_date_8821a_1ant, glcoex_ver_8821a_1ant, +			  fw_ver, bt_patch_ver, bt_patch_ver); +		BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, +			  "[BTCoex], ****************************************************************\n"); +	} + +#if (BT_AUTO_REPORT_ONLY_8821A_1ANT == 0) +	halbtc8821a1ant_query_bt_info(btcoexist); +	halbtc8821a1ant_monitor_bt_ctr(btcoexist); +	halbtc8821a1ant_monitor_bt_enable_disable(btcoexist); +#else +	if (halbtc8821a1ant_Is_wifi_status_changed(btcoexist) || +	    coex_dm->auto_tdma_adjust) { +		if (coex_sta->special_pkt_period_cnt > 2) +			halbtc8821a1ant_run_coexist_mechanism(btcoexist); +	} + +	coex_sta->special_pkt_period_cnt++; +#endif +} diff --git a/drivers/staging/rtl8192ee/btcoexist/halbtc8821a1ant.h b/drivers/staging/rtl8192ee/btcoexist/halbtc8821a1ant.h new file mode 100644 index 00000000000..9b991d021a8 --- /dev/null +++ b/drivers/staging/rtl8192ee/btcoexist/halbtc8821a1ant.h @@ -0,0 +1,158 @@ +/*  */ +/*  The following is for 8821A 1ANT BT Co-exist definition */ +/*  */ +#define	BT_AUTO_REPORT_ONLY_8821A_1ANT				0 + +#define	BT_INFO_8821A_1ANT_B_FTP				BIT(7) +#define	BT_INFO_8821A_1ANT_B_A2DP				BIT(6) +#define	BT_INFO_8821A_1ANT_B_HID				BIT(5) +#define	BT_INFO_8821A_1ANT_B_SCO_BUSY				BIT(4) +#define	BT_INFO_8821A_1ANT_B_ACL_BUSY				BIT(3) +#define	BT_INFO_8821A_1ANT_B_INQ_PAGE				BIT(2) +#define	BT_INFO_8821A_1ANT_B_SCO_ESCO				BIT(1) +#define	BT_INFO_8821A_1ANT_B_CONNECTION				BIT(0) + +#define	BT_INFO_8821A_1ANT_A2DP_BASIC_RATE(_BT_INFO_EXT_)	\ +		(((_BT_INFO_EXT_&BIT(0))) ? true : false) + +#define	BTC_RSSI_COEX_THRESH_TOL_8821A_1ANT		2 + +enum BT_INFO_SRC_8821A_1ANT { +	BT_INFO_SRC_8821A_1ANT_WIFI_FW			= 0x0, +	BT_INFO_SRC_8821A_1ANT_BT_RSP			= 0x1, +	BT_INFO_SRC_8821A_1ANT_BT_ACTIVE_SEND		= 0x2, +	BT_INFO_SRC_8821A_1ANT_MAX +}; + +enum BT_8821A_1ANT_BT_STATUS { +	BT_8821A_1ANT_BT_STATUS_NON_CONNECTED_IDLE	= 0x0, +	BT_8821A_1ANT_BT_STATUS_CONNECTED_IDLE		= 0x1, +	BT_8821A_1ANT_BT_STATUS_INQ_PAGE		= 0x2, +	BT_8821A_1ANT_BT_STATUS_ACL_BUSY		= 0x3, +	BT_8821A_1ANT_BT_STATUS_SCO_BUSY		= 0x4, +	BT_8821A_1ANT_BT_STATUS_ACL_SCO_BUSY		= 0x5, +	BT_8821A_1ANT_BT_STATUS_MAX +}; + +enum BT_8821A_1ANT_WIFI_STATUS { +	BT_8821A_1ANT_WIFI_STATUS_NON_CONNECTED_IDLE			= 0x0, +	BT_8821A_1ANT_WIFI_STATUS_NON_CONNECTED_ASSO_AUTH_SCAN		= 0x1, +	BT_8821A_1ANT_WIFI_STATUS_CONNECTED_SCAN			= 0x2, +	BT_8821A_1ANT_WIFI_STATUS_CONNECTED_SPECIAL_PKT			= 0x3, +	BT_8821A_1ANT_WIFI_STATUS_CONNECTED_IDLE			= 0x4, +	BT_8821A_1ANT_WIFI_STATUS_CONNECTED_BUSY			= 0x5, +	BT_8821A_1ANT_WIFI_STATUS_MAX +}; + +enum BT_8821A_1ANT_COEX_ALGO { +	BT_8821A_1ANT_COEX_ALGO_UNDEFINED		= 0x0, +	BT_8821A_1ANT_COEX_ALGO_SCO			= 0x1, +	BT_8821A_1ANT_COEX_ALGO_HID			= 0x2, +	BT_8821A_1ANT_COEX_ALGO_A2DP			= 0x3, +	BT_8821A_1ANT_COEX_ALGO_A2DP_PANHS		= 0x4, +	BT_8821A_1ANT_COEX_ALGO_PANEDR			= 0x5, +	BT_8821A_1ANT_COEX_ALGO_PANHS			= 0x6, +	BT_8821A_1ANT_COEX_ALGO_PANEDR_A2DP		= 0x7, +	BT_8821A_1ANT_COEX_ALGO_PANEDR_HID		= 0x8, +	BT_8821A_1ANT_COEX_ALGO_HID_A2DP_PANEDR		= 0x9, +	BT_8821A_1ANT_COEX_ALGO_HID_A2DP		= 0xa, +	BT_8821A_1ANT_COEX_ALGO_MAX			= 0xb, +}; + +struct coex_dm_8821a_1ant { +	/*  fw mechanism */ +	bool		cur_ignore_wlan_act; +	bool		pre_ignore_wlan_act; +	u8		pre_ps_tdma; +	u8		cur_ps_tdma; +	u8		ps_tdma_para[5]; +	u8		ps_tdma_du_adj_type; +	bool		auto_tdma_adjust; +	bool		pre_ps_tdma_on; +	bool		cur_ps_tdma_on; +	bool		pre_bt_auto_report; +	bool		cur_bt_auto_report; +	u8		pre_lps; +	u8		cur_lps; +	u8		pre_rpwm; +	u8		cur_rpwm; + +	/*  sw mechanism */ +	bool	pre_low_penalty_ra; +	bool		cur_low_penalty_ra; +	u32		pre_val_0x6c0; +	u32		cur_val_0x6c0; +	u32		pre_val_0x6c4; +	u32		cur_val_0x6c4; +	u32		pre_val_0x6c8; +	u32		cur_val_0x6c8; +	u8		pre_val_0x6cc; +	u8		cur_val_0x6cc; + +	u32		backup_arfr_cnt1; /*  Auto Rate Fallback Retry cnt */ +	u32		backup_arfr_cnt2; /*  Auto Rate Fallback Retry cnt */ +	u16		backup_retry_limit; +	u8		backup_ampdu_max_time; + +	/*  algorithm related */ +	u8		pre_algorithm; +	u8		cur_algorithm; +	u8		bt_status; +	u8		wifi_chnl_info[3]; + +	u32		pre_ra_mask; +	u32		cur_ra_mask; +	u8		pre_arfr_type; +	u8		cur_arfr_type; +	u8		pre_retry_limit_type; +	u8		cur_retry_limit_type; +	u8		pre_ampdu_time_type; +	u8		cur_ampdu_time_type; + +	u8		error_condition; +}; + +struct coex_sta_8821a_1ant { +	bool		bt_link_exist; +	bool		sco_exist; +	bool		a2dp_exist; +	bool		hid_exist; +	bool		pan_exist; + +	bool		under_lps; +	bool		under_ips; +	u32		special_pkt_period_cnt; +	u32		high_priority_tx; +	u32		high_priority_rx; +	u32		low_priority_tx; +	u32		low_priority_rx; +	u8		bt_rssi; +	u8		pre_bt_rssi_state; +	u8		pre_wifi_rssi_state[4]; +	bool		c2h_bt_info_req_sent; +	u8		bt_info_c2h[BT_INFO_SRC_8821A_1ANT_MAX][10]; +	u32		bt_info_c2h_cnt[BT_INFO_SRC_8821A_1ANT_MAX]; +	bool		c2h_bt_inquiry_page; +	u8		bt_retry_cnt; +	u8		bt_info_ext; +}; + +/*  The following is interface which will notify coex module. */ +void ex_halbtc8821a1ant_init_hwconfig(struct btc_coexist *btcoexist); +void ex_halbtc8821a1ant_init_coex_dm(struct btc_coexist *btcoexist); +void ex_halbtc8821a1ant_ips_notify(struct btc_coexist *btcoexist, u8 type); +void ex_halbtc8821a1ant_lps_notify(struct btc_coexist *btcoexist, u8 type); +void ex_halbtc8821a1ant_scan_notify(struct btc_coexist *btcoexist, u8 type); +void ex_halbtc8821a1ant_connect_notify(struct btc_coexist *btcoexist, u8 type); +void ex_halbtc8821a1ant_media_status_notify(struct btc_coexist *btcoexist, +					    u8 type); +void ex_halbtc8821a1ant_special_packet_notify(struct btc_coexist *btcoexist, +					      u8 type); +void ex_halbtc8821a1ant_bt_info_notify(struct btc_coexist *btcoexist, +				       u8 *tmpbuf, u8 length); +void ex_halbtc8821a1ant_halt_notify(struct btc_coexist *btcoexist); +void ex_halbtc8821a1ant_pnp_notify(struct btc_coexist *btcoexist, u8 pnpstate); +void ex_halbtc8821a1ant_periodical(struct btc_coexist *btcoexist); +void ex_halbtc8821a1ant_display_coex_info(struct btc_coexist *btcoexist); +void ex_halbtc8821a1ant_dbg_control(struct btc_coexist *btcoexist, u8 op_code, +				    u8 op_len, u8 *data); diff --git a/drivers/staging/rtl8192ee/btcoexist/halbtc8821a2ant.c b/drivers/staging/rtl8192ee/btcoexist/halbtc8821a2ant.c new file mode 100644 index 00000000000..7fb59073901 --- /dev/null +++ b/drivers/staging/rtl8192ee/btcoexist/halbtc8821a2ant.c @@ -0,0 +1,3438 @@ +/*  Description: */ +/*  This file is for RTL8821A Co-exist mechanism */ +/*  History */ +/*  2012/08/22 Cosa first check in. */ +/*  2012/11/14 Cosa Revise for 8821A 2Ant out sourcing. */ + +/*  include files */ +#include "halbt_precomp.h" +/*  Global variables, these are static variables */ +static struct coex_dm_8821a_2ant	glcoex_dm_8821a_2ant; +static struct coex_dm_8821a_2ant	*coex_dm = &glcoex_dm_8821a_2ant; +static struct coex_sta_8821a_2ant	glcoex_sta_8821a_2ant; +static struct coex_sta_8821a_2ant	*coex_sta = &glcoex_sta_8821a_2ant; + +static const char *const glbt_info_src_8821a_2ant[] = { +	"BT Info[wifi fw]", +	"BT Info[bt rsp]", +	"BT Info[bt auto report]", +}; + +static u32 glcoex_ver_date_8821a_2ant = 20130618; +static u32 glcoex_ver_8821a_2ant = 0x5050; + +/*  local function proto type if needed */ +/*  local function start with halbtc8821a2ant_ */ +static u8 halbtc8821a2ant_bt_rssi_state(u8 level_num, u8 rssi_thresh, +					u8 rssi_thresh1) +{ +	long bt_rssi = 0; +	u8 bt_rssi_state = coex_sta->pre_bt_rssi_state; + +	bt_rssi = coex_sta->bt_rssi; + +	if (level_num == 2) { +		if ((coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_LOW) || +		    (coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_STAY_LOW)) { +			if (bt_rssi >= (rssi_thresh + +			    BTC_RSSI_COEX_THRESH_TOL_8821A_2ANT)) { +				bt_rssi_state = BTC_RSSI_STATE_HIGH; +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, +					  "[BTCoex], BT Rssi state switch to High\n"); +			} else { +				bt_rssi_state = BTC_RSSI_STATE_STAY_LOW; +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, +					  "[BTCoex], BT Rssi state stay at Low\n"); +			} +		} else { +			if (bt_rssi < rssi_thresh) { +				bt_rssi_state = BTC_RSSI_STATE_LOW; +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, +					  "[BTCoex], BT Rssi state switch to Low\n"); +			} else { +				bt_rssi_state = BTC_RSSI_STATE_STAY_HIGH; +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, +					  "[BTCoex], BT Rssi state stay at High\n"); +			} +		} +	} else if (level_num == 3) { +		if (rssi_thresh > rssi_thresh1) { +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, +				  "[BTCoex], BT Rssi thresh error!!\n"); +			return coex_sta->pre_bt_rssi_state; +		} + +		if ((coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_LOW) || +		    (coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_STAY_LOW)) { +			if (bt_rssi >= (rssi_thresh + +			    BTC_RSSI_COEX_THRESH_TOL_8821A_2ANT)) { +				bt_rssi_state = BTC_RSSI_STATE_MEDIUM; +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, +					  "[BTCoex], BT Rssi state switch to Medium\n"); +			} else { +				bt_rssi_state = BTC_RSSI_STATE_STAY_LOW; +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, +					  "[BTCoex], BT Rssi state stay at Low\n"); +			} +		} else if ((coex_sta->pre_bt_rssi_state == +			    BTC_RSSI_STATE_MEDIUM) || +			   (coex_sta->pre_bt_rssi_state == +			    BTC_RSSI_STATE_STAY_MEDIUM)) { +			if (bt_rssi >= (rssi_thresh1 + +			    BTC_RSSI_COEX_THRESH_TOL_8821A_2ANT)) { +				bt_rssi_state = BTC_RSSI_STATE_HIGH; +				BTC_PRINT(BTC_MSG_ALGORITHM, +					  ALGO_BT_RSSI_STATE, +					  "[BTCoex], BT Rssi state switch to High\n"); +			} else if (bt_rssi < rssi_thresh) { +				bt_rssi_state = BTC_RSSI_STATE_LOW; +				BTC_PRINT(BTC_MSG_ALGORITHM, +					  ALGO_BT_RSSI_STATE, +					  "[BTCoex], BT Rssi state switch to Low\n"); +			} else { +				bt_rssi_state = BTC_RSSI_STATE_STAY_MEDIUM; +				BTC_PRINT(BTC_MSG_ALGORITHM, +					  ALGO_BT_RSSI_STATE, +					  "[BTCoex], BT Rssi state stay at Medium\n"); +			} +		} else { +			if (bt_rssi < rssi_thresh1) { +				bt_rssi_state = BTC_RSSI_STATE_MEDIUM; +				BTC_PRINT(BTC_MSG_ALGORITHM, +					  ALGO_BT_RSSI_STATE, +					  "[BTCoex], BT Rssi state switch to Medium\n"); +			} else { +				bt_rssi_state = BTC_RSSI_STATE_STAY_HIGH; +				BTC_PRINT(BTC_MSG_ALGORITHM, +					  ALGO_BT_RSSI_STATE, +					  "[BTCoex], BT Rssi state stay at High\n"); +			} +		} +	} + +	coex_sta->pre_bt_rssi_state = bt_rssi_state; + +	return bt_rssi_state; +} + +static u8 wifi21a_rssi_state(struct btc_coexist *btcoexist, +			     u8 index, u8 level_num, +			     u8 rssi_thresh, u8 rssi_thresh1) +{ +	long	wifi_rssi = 0; +	u8 wifi_rssi_state = coex_sta->pre_wifi_rssi_state[index]; + +	btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifi_rssi); + +	if (level_num == 2) { +		if ((coex_sta->pre_wifi_rssi_state[index] == +		     BTC_RSSI_STATE_LOW) || +		    (coex_sta->pre_wifi_rssi_state[index] == +		     BTC_RSSI_STATE_STAY_LOW)) { +			if (wifi_rssi >= (rssi_thresh + +			    BTC_RSSI_COEX_THRESH_TOL_8821A_2ANT)) { +				wifi_rssi_state = BTC_RSSI_STATE_HIGH; +				BTC_PRINT(BTC_MSG_ALGORITHM, +					  ALGO_WIFI_RSSI_STATE, +					  "[BTCoex], wifi RSSI state switch to High\n"); +			} else { +				wifi_rssi_state = BTC_RSSI_STATE_STAY_LOW; +				BTC_PRINT(BTC_MSG_ALGORITHM, +					  ALGO_WIFI_RSSI_STATE, +					  "[BTCoex], wifi RSSI state stay at Low\n"); +			} +		} else { +			if (wifi_rssi < rssi_thresh) { +				wifi_rssi_state = BTC_RSSI_STATE_LOW; +				BTC_PRINT(BTC_MSG_ALGORITHM, +					  ALGO_WIFI_RSSI_STATE, +					  "[BTCoex], wifi RSSI state switch to Low\n"); +			} else { +				wifi_rssi_state = BTC_RSSI_STATE_STAY_HIGH; +				BTC_PRINT(BTC_MSG_ALGORITHM, +					  ALGO_WIFI_RSSI_STATE, +					  "[BTCoex], wifi RSSI state stay at High\n"); +			} +		} +	} else if (level_num == 3) { +		if (rssi_thresh > rssi_thresh1) { +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, +				  "[BTCoex], wifi RSSI thresh error!!\n"); +			return coex_sta->pre_wifi_rssi_state[index]; +		} + +		if ((coex_sta->pre_wifi_rssi_state[index] == +		    BTC_RSSI_STATE_LOW) || +		    (coex_sta->pre_wifi_rssi_state[index] == +		     BTC_RSSI_STATE_STAY_LOW)) { +			if (wifi_rssi >= (rssi_thresh + +			    BTC_RSSI_COEX_THRESH_TOL_8821A_2ANT)) { +				wifi_rssi_state = BTC_RSSI_STATE_MEDIUM; +				BTC_PRINT(BTC_MSG_ALGORITHM, +					  ALGO_WIFI_RSSI_STATE, +					  "[BTCoex], wifi RSSI state switch to Medium\n"); +			} else { +				wifi_rssi_state = BTC_RSSI_STATE_STAY_LOW; +				BTC_PRINT(BTC_MSG_ALGORITHM, +					  ALGO_WIFI_RSSI_STATE, +					  "[BTCoex], wifi RSSI state stay at Low\n"); +			} +		} else if ((coex_sta->pre_wifi_rssi_state[index] == +			    BTC_RSSI_STATE_MEDIUM) || +			   (coex_sta->pre_wifi_rssi_state[index] == +			    BTC_RSSI_STATE_STAY_MEDIUM)) { +			if (wifi_rssi >= (rssi_thresh1+BTC_RSSI_COEX_THRESH_TOL_8821A_2ANT)) { +				wifi_rssi_state = BTC_RSSI_STATE_HIGH; +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, +					  "[BTCoex], wifi RSSI state switch to High\n"); +			} else if (wifi_rssi < rssi_thresh) { +				wifi_rssi_state = BTC_RSSI_STATE_LOW; +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, +					  "[BTCoex], wifi RSSI state switch to Low\n"); +			} else { +				wifi_rssi_state = BTC_RSSI_STATE_STAY_MEDIUM; +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, +					  "[BTCoex], wifi RSSI state stay at Medium\n"); +			} +		} else { +			if (wifi_rssi < rssi_thresh1) { +				wifi_rssi_state = BTC_RSSI_STATE_MEDIUM; +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, +					  "[BTCoex], wifi RSSI state switch to Medium\n"); +			} else { +				wifi_rssi_state = BTC_RSSI_STATE_STAY_HIGH; +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, +					  "[BTCoex], wifi RSSI state stay at High\n"); +			} +		} +	} + +	coex_sta->pre_wifi_rssi_state[index] = wifi_rssi_state; + +	return wifi_rssi_state; +} + +static void monitor_bt_enable_disable(struct btc_coexist *btcoexist) +{ +	static bool pre_bt_disabled; +	static u32 bt_disable_cnt; +	bool bt_active = true, bt_disabled = false; + +	/*  This function check if bt is disabled */ + +	if (coex_sta->high_priority_tx == 0 && +	    coex_sta->high_priority_rx == 0 && +	    coex_sta->low_priority_tx == 0 && +	    coex_sta->low_priority_rx == 0) +		bt_active = false; +	if (coex_sta->high_priority_tx == 0xffff && +	    coex_sta->high_priority_rx == 0xffff && +	    coex_sta->low_priority_tx == 0xffff && +	    coex_sta->low_priority_rx == 0xffff) +		bt_active = false; +	if (bt_active) { +		bt_disable_cnt = 0; +		bt_disabled = false; +		btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_DISABLE, +				   &bt_disabled); +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, +			  "[BTCoex], BT is enabled !!\n"); +	} else { +		bt_disable_cnt++; +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, +			  "[BTCoex], bt all counters = 0, %d times!!\n", +			  bt_disable_cnt); +		if (bt_disable_cnt >= 2) { +			bt_disabled = true; +			btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_DISABLE, +					   &bt_disabled); +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, +				  "[BTCoex], BT is disabled !!\n"); +		} +	} +	if (pre_bt_disabled != bt_disabled) { +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, +			  "[BTCoex], BT is from %s to %s!!\n", +			  (pre_bt_disabled ? "disabled" : "enabled"), +			  (bt_disabled ? "disabled" : "enabled")); +		pre_bt_disabled = bt_disabled; +	} +} + +static void halbtc8821a2ant_monitor_bt_ctr(struct btc_coexist *btcoexist) +{ +	u32 reg_hp_txrx, reg_lp_txrx, u4tmp; +	u32 reg_hp_tx = 0, reg_hp_rx = 0, reg_lp_tx = 0, reg_lp_rx = 0; + +	reg_hp_txrx = 0x770; +	reg_lp_txrx = 0x774; + +	u4tmp = btcoexist->btc_read_4byte(btcoexist, reg_hp_txrx); +	reg_hp_tx = u4tmp & MASKLWORD; +	reg_hp_rx = (u4tmp & MASKHWORD)>>16; + +	u4tmp = btcoexist->btc_read_4byte(btcoexist, reg_lp_txrx); +	reg_lp_tx = u4tmp & MASKLWORD; +	reg_lp_rx = (u4tmp & MASKHWORD)>>16; + +	coex_sta->high_priority_tx = reg_hp_tx; +	coex_sta->high_priority_rx = reg_hp_rx; +	coex_sta->low_priority_tx = reg_lp_tx; +	coex_sta->low_priority_rx = reg_lp_rx; + +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, +		  "[BTCoex], High Priority Tx/Rx (reg 0x%x) = 0x%x(%d)/0x%x(%d)\n", +		  reg_hp_txrx, reg_hp_tx, reg_hp_tx, reg_hp_rx, reg_hp_rx); +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, +		  "[BTCoex], Low Priority Tx/Rx (reg 0x%x) = 0x%x(%d)/0x%x(%d)\n", +		  reg_lp_txrx, reg_lp_tx, reg_lp_tx, reg_lp_rx, reg_lp_rx); + +	/*  reset counter */ +	btcoexist->btc_write_1byte(btcoexist, 0x76e, 0xc); +} + +static void halbtc8821a2ant_query_bt_info(struct btc_coexist *btcoexist) +{ +	u8 h2c_parameter[1] = {0}; + +	coex_sta->c2h_bt_info_req_sent = true; + +	h2c_parameter[0] |= BIT(0);	/*  trigger */ + +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, +		  "[BTCoex], Query Bt Info, FW write 0x61 = 0x%x\n", +		  h2c_parameter[0]); + +	btcoexist->btc_fill_h2c(btcoexist, 0x61, 1, h2c_parameter); +} + +static u8 halbtc8821a2ant_action_algorithm(struct btc_coexist *btcoexist) +{ +	struct btc_stack_info *stack_info = &btcoexist->stack_info; +	bool bt_hs_on = false; +	u8 algorithm = BT_8821A_2ANT_COEX_ALGO_UNDEFINED; +	u8 num_of_diff_profile = 0; + +	btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + +	/* for win-8 stack HID report error */ +	if (!stack_info->hid_exist) { +		/* sync  BTInfo with BT firmware and stack */ +		stack_info->hid_exist = coex_sta->hid_exist; +	} +	/*  when stack HID report error, here we use the info from bt fw. */ +	if (!stack_info->bt_link_exist) +		stack_info->bt_link_exist = coex_sta->bt_link_exist; + +	if (!coex_sta->bt_link_exist) { +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +			  "[BTCoex], No profile exists!!!\n"); +		return algorithm; +	} + +	if (coex_sta->sco_exist) +		num_of_diff_profile++; +	if (coex_sta->hid_exist) +		num_of_diff_profile++; +	if (coex_sta->pan_exist) +		num_of_diff_profile++; +	if (coex_sta->a2dp_exist) +		num_of_diff_profile++; + +	if (num_of_diff_profile == 1) { +		if (coex_sta->sco_exist) { +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +				  "[BTCoex], SCO only\n"); +			algorithm = BT_8821A_2ANT_COEX_ALGO_SCO; +		} else { +			if (coex_sta->hid_exist) { +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +					  "[BTCoex], HID only\n"); +				algorithm = BT_8821A_2ANT_COEX_ALGO_HID; +			} else if (coex_sta->a2dp_exist) { +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +					  "[BTCoex], A2DP only\n"); +				algorithm = BT_8821A_2ANT_COEX_ALGO_A2DP; +			} else if (coex_sta->pan_exist) { +				if (bt_hs_on) { +					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +						  "[BTCoex], PAN(HS) only\n"); +					algorithm = BT_8821A_2ANT_COEX_ALGO_PANHS; +				} else { +					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +						  "[BTCoex], PAN(EDR) only\n"); +					algorithm = BT_8821A_2ANT_COEX_ALGO_PANEDR; +				} +			} +		} +	} else if (num_of_diff_profile == 2) { +		if (coex_sta->sco_exist) { +			if (coex_sta->hid_exist) { +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, "[BTCoex], SCO + HID\n"); +				algorithm = BT_8821A_2ANT_COEX_ALGO_PANEDR_HID; +			} else if (coex_sta->a2dp_exist) { +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +					  "[BTCoex], SCO + A2DP ==> SCO\n"); +				algorithm = BT_8821A_2ANT_COEX_ALGO_PANEDR_HID; +			} else if (coex_sta->pan_exist) { +				if (bt_hs_on) { +					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +						  "[BTCoex], SCO + PAN(HS)\n"); +					algorithm = BT_8821A_2ANT_COEX_ALGO_SCO; +				} else { +					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +						  "[BTCoex], SCO + PAN(EDR)\n"); +					algorithm = BT_8821A_2ANT_COEX_ALGO_PANEDR_HID; +				} +			} +		} else { +			if (coex_sta->hid_exist && +			    coex_sta->a2dp_exist) { +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +					  "[BTCoex], HID + A2DP\n"); +				algorithm = BT_8821A_2ANT_COEX_ALGO_HID_A2DP; +			} else if (coex_sta->hid_exist && +				   coex_sta->pan_exist) { +				if (bt_hs_on) { +					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +						  "[BTCoex], HID + PAN(HS)\n"); +					algorithm =  BT_8821A_2ANT_COEX_ALGO_HID; +				} else { +					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +						  "[BTCoex], HID + PAN(EDR)\n"); +					algorithm = BT_8821A_2ANT_COEX_ALGO_PANEDR_HID; +				} +			} else if (coex_sta->pan_exist && +				   coex_sta->a2dp_exist) { +				if (bt_hs_on) { +					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +						  "[BTCoex], A2DP + PAN(HS)\n"); +					algorithm = BT_8821A_2ANT_COEX_ALGO_A2DP_PANHS; +				} else { +					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +						  "[BTCoex], A2DP + PAN(EDR)\n"); +					algorithm = BT_8821A_2ANT_COEX_ALGO_PANEDR_A2DP; +				} +			} +		} +	} else if (num_of_diff_profile == 3) { +		if (coex_sta->sco_exist) { +			if (coex_sta->hid_exist && +			    coex_sta->a2dp_exist) { +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +					  "[BTCoex], SCO + HID + A2DP ==> HID\n"); +				algorithm = BT_8821A_2ANT_COEX_ALGO_PANEDR_HID; +			} else if (coex_sta->hid_exist && +				   coex_sta->pan_exist) { +				if (bt_hs_on) { +					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +						  "[BTCoex], SCO + HID + PAN(HS)\n"); +					algorithm = BT_8821A_2ANT_COEX_ALGO_PANEDR_HID; +				} else { +					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +						  "[BTCoex], SCO + HID + PAN(EDR)\n"); +					algorithm = BT_8821A_2ANT_COEX_ALGO_PANEDR_HID; +				} +			} else if (coex_sta->pan_exist && +				   coex_sta->a2dp_exist) { +				if (bt_hs_on) { +					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +						  "[BTCoex], SCO + A2DP + PAN(HS)\n"); +					algorithm = BT_8821A_2ANT_COEX_ALGO_PANEDR_HID; +				} else { +					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +						  "[BTCoex], SCO + A2DP + PAN(EDR) ==> HID\n"); +					algorithm = BT_8821A_2ANT_COEX_ALGO_PANEDR_HID; +				} +			} +		} else { +			if (coex_sta->hid_exist && +			    coex_sta->pan_exist && +			    coex_sta->a2dp_exist) { +				if (bt_hs_on) { +					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +						  "[BTCoex], HID + A2DP + PAN(HS)\n"); +					algorithm = BT_8821A_2ANT_COEX_ALGO_HID_A2DP; +				} else { +					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +						  "[BTCoex], HID + A2DP + PAN(EDR)\n"); +					algorithm = BT_8821A_2ANT_COEX_ALGO_HID_A2DP_PANEDR; +				} +			} +		} +	} else if (num_of_diff_profile >= 3) { +		if (coex_sta->sco_exist) { +			if (coex_sta->hid_exist && +			    coex_sta->pan_exist && +			    coex_sta->a2dp_exist) { +				if (bt_hs_on) { +					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +						  "[BTCoex], Error!!! SCO + HID + A2DP + PAN(HS)\n"); + +				} else { +					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +						  "[BTCoex], SCO + HID + A2DP + PAN(EDR) ==>PAN(EDR)+HID\n"); +					algorithm = BT_8821A_2ANT_COEX_ALGO_PANEDR_HID; +				} +			} +		} +	} +	return algorithm; +} + +static bool halbtc8821a2ant_need_to_dec_bt_pwr(struct btc_coexist *btcoexist) +{ +	bool ret = false; +	bool bt_hs_on = false, wifi_connected = false; +	long bt_hs_rssi = 0; +	u8 bt_rssi_state; + +	if (!btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on)) +		return false; +	if (!btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, +				&wifi_connected)) +		return false; +	if (!btcoexist->btc_get(btcoexist, BTC_GET_S4_HS_RSSI, &bt_hs_rssi)) +		return false; + +	bt_rssi_state = halbtc8821a2ant_bt_rssi_state(2, 35, 0); + +	if (wifi_connected) { +		if (bt_hs_on) { +			if (bt_hs_rssi > 37) { +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, +					  "[BTCoex], Need to decrease bt power for HS mode!!\n"); +				ret = true; +			} +		} else { +			if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || +			    (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, +					  "[BTCoex], Need to decrease bt power for Wifi is connected!!\n"); +				ret = true; +			} +		} +	} +	return ret; +} + +static void set_fw_dac_swing_level(struct btc_coexist *btcoexist, +				   u8 dac_swing_lvl) +{ +	u8 h2c_parameter[1] = {0}; + +	/*  There are several type of dacswing */ +	/*  0x18/ 0x10/ 0xc/ 0x8/ 0x4/ 0x6 */ +	h2c_parameter[0] = dac_swing_lvl; + +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, +		  "[BTCoex], Set Dac Swing Level = 0x%x\n", dac_swing_lvl); +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, +		  "[BTCoex], FW write 0x64 = 0x%x\n", h2c_parameter[0]); + +	btcoexist->btc_fill_h2c(btcoexist, 0x64, 1, h2c_parameter); +} + +static void halbtc8821a2ant_set_fw_dec_bt_pwr(struct btc_coexist *btcoexist, +					      bool dec_bt_pwr) +{ +	u8 h2c_parameter[1] = {0}; + +	h2c_parameter[0] = 0; + +	if (dec_bt_pwr) +		h2c_parameter[0] |= BIT(1); + +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, +		  "[BTCoex], decrease Bt Power : %s, FW write 0x62 = 0x%x\n", +		  (dec_bt_pwr ? "Yes!!" : "No!!"), h2c_parameter[0]); + +	btcoexist->btc_fill_h2c(btcoexist, 0x62, 1, h2c_parameter); +} + +static void halbtc8821a2ant_dec_bt_pwr(struct btc_coexist *btcoexist, +				       bool force_exec, bool dec_bt_pwr) +{ +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, +		  "[BTCoex], %s Dec BT power = %s\n", +		  (force_exec ? "force to" : ""), +		  ((dec_bt_pwr) ? "ON" : "OFF")); +	coex_dm->cur_dec_bt_pwr = dec_bt_pwr; + +	if (!force_exec) { +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, +			  "[BTCoex], pre_dec_bt_pwr =%d, cur_dec_bt_pwr =%d\n", +			  coex_dm->pre_dec_bt_pwr, coex_dm->cur_dec_bt_pwr); + +		if (coex_dm->pre_dec_bt_pwr == coex_dm->cur_dec_bt_pwr) +			return; +	} +	halbtc8821a2ant_set_fw_dec_bt_pwr(btcoexist, coex_dm->cur_dec_bt_pwr); + +	coex_dm->pre_dec_bt_pwr = coex_dm->cur_dec_bt_pwr; +} + +static void set_fw_bt_lna_constrain(struct btc_coexist *btcoexist, +				    bool bt_lna_cons_on) +{ +	u8 h2c_parameter[2] = {0}; + +	h2c_parameter[0] = 0x3;	/*  opCode, 0x3 = BT_SET_LNA_CONSTRAIN */ + +	if (bt_lna_cons_on) +		h2c_parameter[1] |= BIT(0); + +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, +		  "[BTCoex], set BT LNA Constrain: %s, FW write 0x69 = 0x%x\n", +		  (bt_lna_cons_on ? "ON!!" : "OFF!!"), +		  h2c_parameter[0]<<8|h2c_parameter[1]); + +	btcoexist->btc_fill_h2c(btcoexist, 0x69, 2, h2c_parameter); +} + +static void set_bt_lna_constrain(struct btc_coexist *btcoexist, bool force_exec, +				 bool bt_lna_cons_on) +{ +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, +		  "[BTCoex], %s BT Constrain = %s\n", +		  (force_exec ? "force" : ""), +		  ((bt_lna_cons_on) ? "ON" : "OFF")); +	coex_dm->cur_bt_lna_constrain = bt_lna_cons_on; + +	if (!force_exec) { +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, +			  "[BTCoex], pre_bt_lna_constrain =%d, cur_bt_lna_constrain =%d\n", +			  coex_dm->pre_bt_lna_constrain, +			  coex_dm->cur_bt_lna_constrain); + +		if (coex_dm->pre_bt_lna_constrain == +		    coex_dm->cur_bt_lna_constrain) +			return; +	} +	set_fw_bt_lna_constrain(btcoexist, coex_dm->cur_bt_lna_constrain); + +	coex_dm->pre_bt_lna_constrain = coex_dm->cur_bt_lna_constrain; +} + +static void halbtc8821a2ant_set_fw_bt_psd_mode(struct btc_coexist *btcoexist, +					       u8 bt_psd_mode) +{ +	u8 h2c_parameter[2] = {0}; + +	h2c_parameter[0] = 0x2;	/*  opCode, 0x2 = BT_SET_PSD_MODE */ + +	h2c_parameter[1] = bt_psd_mode; + +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, +		  "[BTCoex], set BT PSD mode = 0x%x, FW write 0x69 = 0x%x\n", +		  h2c_parameter[1], +		  h2c_parameter[0] << 8 | h2c_parameter[1]); + +	btcoexist->btc_fill_h2c(btcoexist, 0x69, 2, h2c_parameter); +} + +static void halbtc8821a2ant_set_bt_psd_mode(struct btc_coexist *btcoexist, +					    bool force_exec, u8 bt_psd_mode) +{ +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, +		  "[BTCoex], %s BT PSD mode = 0x%x\n", +		  (force_exec ? "force" : ""), bt_psd_mode); +	coex_dm->cur_bt_psd_mode = bt_psd_mode; + +	if (!force_exec) { +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, +			  "[BTCoex], pre_bt_psd_mode = 0x%x, cur_bt_psd_mode = 0x%x\n", +			  coex_dm->pre_bt_psd_mode, coex_dm->cur_bt_psd_mode); + +		if (coex_dm->pre_bt_psd_mode == coex_dm->cur_bt_psd_mode) +			return; +	} +	halbtc8821a2ant_set_fw_bt_psd_mode(btcoexist, coex_dm->cur_bt_psd_mode); + +	coex_dm->pre_bt_psd_mode = coex_dm->cur_bt_psd_mode; +} + +static void halbtc8821a2ant_set_bt_auto_report(struct btc_coexist *btcoexist, +					       bool enable_auto_report) +{ +	u8 h2c_parameter[1] = {0}; + +	h2c_parameter[0] = 0; + +	if (enable_auto_report) +		h2c_parameter[0] |= BIT(0); + +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, +		  "[BTCoex], BT FW auto report : %s, FW write 0x68 = 0x%x\n", +		  (enable_auto_report ? "Enabled!!" : "Disabled!!"), +		  h2c_parameter[0]); + +	btcoexist->btc_fill_h2c(btcoexist, 0x68, 1, h2c_parameter); +} + +static void halbtc8821a2ant_bt_auto_report(struct btc_coexist *btcoexist, +					   bool force_exec, +					   bool enable_auto_report) +{ +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, +		  "[BTCoex], %s BT Auto report = %s\n", +		  (force_exec ? "force to" : ""), +		  ((enable_auto_report) ? "Enabled" : "Disabled")); +	coex_dm->cur_bt_auto_report = enable_auto_report; + +	if (!force_exec) { +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, +			  "[BTCoex], pre_bt_auto_report =%d, cur_bt_auto_report =%d\n", +			  coex_dm->pre_bt_auto_report, +			  coex_dm->cur_bt_auto_report); + +		if (coex_dm->pre_bt_auto_report == coex_dm->cur_bt_auto_report) +			return; +	} +	halbtc8821a2ant_set_bt_auto_report(btcoexist, +					   coex_dm->cur_bt_auto_report); + +	coex_dm->pre_bt_auto_report = coex_dm->cur_bt_auto_report; +} + +static void halbtc8821a2ant_fw_dac_swing_lvl(struct btc_coexist *btcoexist, +					     bool force_exec, +					     u8 fw_dac_swing_lvl) +{ +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, +		  "[BTCoex], %s set FW Dac Swing level = %d\n", +		  (force_exec ? "force to" : ""), fw_dac_swing_lvl); +	coex_dm->cur_fw_dac_swing_lvl = fw_dac_swing_lvl; + +	if (!force_exec) { +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, +			  "[BTCoex], pre_fw_dac_swing_lvl =%d, cur_fw_dac_swing_lvl =%d\n", +			  coex_dm->pre_fw_dac_swing_lvl, +			  coex_dm->cur_fw_dac_swing_lvl); + +		if (coex_dm->pre_fw_dac_swing_lvl == +		    coex_dm->cur_fw_dac_swing_lvl) +			return; +	} + +	set_fw_dac_swing_level(btcoexist, coex_dm->cur_fw_dac_swing_lvl); + +	coex_dm->pre_fw_dac_swing_lvl = coex_dm->cur_fw_dac_swing_lvl; +} + +static void set_sw_rf_rx_lpf_corner(struct btc_coexist *btcoexist, +				    bool rx_rf_shrink_on) +{ +	if (rx_rf_shrink_on) { +		/* Shrink RF Rx LPF corner */ +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, +			  "[BTCoex], Shrink RF Rx LPF corner!!\n"); +		btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1e, +					  0xfffff, 0xffffc); +	} else { +		/* Resume RF Rx LPF corner */ +		/*  After initialized, we can use coex_dm->bt_rf0x1e_backup */ +		if (btcoexist->initilized) { +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, +				  "[BTCoex], Resume RF Rx LPF corner!!\n"); +			btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1e, +						  0xfffff, +						  coex_dm->bt_rf0x1e_backup); +		} +	} +} + +static void halbtc8821a2ant_RfShrink(struct btc_coexist *btcoexist, +				     bool force_exec, bool rx_rf_shrink_on) +{ +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, +		  "[BTCoex], %s turn Rx RF Shrink = %s\n", +		  (force_exec ? "force to" : ""), +		  ((rx_rf_shrink_on) ? "ON" : "OFF")); +	coex_dm->cur_rf_rx_lpf_shrink = rx_rf_shrink_on; + +	if (!force_exec) { +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, +			  "[BTCoex], pre_rf_rx_lpf_shrink =%d, cur_rf_rx_lpf_shrink =%d\n", +			  coex_dm->pre_rf_rx_lpf_shrink, +			  coex_dm->cur_rf_rx_lpf_shrink); + +		if (coex_dm->pre_rf_rx_lpf_shrink == +		    coex_dm->cur_rf_rx_lpf_shrink) +			return; +	} +	set_sw_rf_rx_lpf_corner(btcoexist, coex_dm->cur_rf_rx_lpf_shrink); + +	coex_dm->pre_rf_rx_lpf_shrink = coex_dm->cur_rf_rx_lpf_shrink; +} + +static void set_sw_penalty_tx_rate_adap(struct btc_coexist *btcoexist, +					bool low_penalty_ra) +{ +	u8 h2c_parameter[6] = {0}; + +	h2c_parameter[0] = 0x6;	/*  opCode, 0x6 = Retry_Penalty */ + +	if (low_penalty_ra) { +		h2c_parameter[1] |= BIT(0); +		/* normal rate except MCS7/6/5, OFDM54/48/36 */ +		h2c_parameter[2] = 0x00; +		h2c_parameter[3] = 0xf7;  /* MCS7 or OFDM54 */ +		h2c_parameter[4] = 0xf8;  /* MCS6 or OFDM48 */ +		h2c_parameter[5] = 0xf9;  /* MCS5 or OFDM36  */ +	} + +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, +		  "[BTCoex], set WiFi Low-Penalty Retry: %s", +		  (low_penalty_ra ? "ON!!" : "OFF!!")); + +	btcoexist->btc_fill_h2c(btcoexist, 0x69, 6, h2c_parameter); +} + +static void halbtc8821a2ant_low_penalty_ra(struct btc_coexist *btcoexist, +					   bool force_exec, bool low_penalty_ra) +{ +	/* return; */ +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, +		  "[BTCoex], %s turn LowPenaltyRA = %s\n", +		  (force_exec ? "force to" : ""), +		  ((low_penalty_ra) ? "ON" : "OFF")); +	coex_dm->cur_low_penalty_ra = low_penalty_ra; + +	if (!force_exec) { +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, +			  "[BTCoex], pre_low_penalty_ra =%d, cur_low_penalty_ra =%d\n", +			  coex_dm->pre_low_penalty_ra, +			  coex_dm->cur_low_penalty_ra); + +		if (coex_dm->pre_low_penalty_ra == coex_dm->cur_low_penalty_ra) +			return; +	} +	set_sw_penalty_tx_rate_adap(btcoexist, coex_dm->cur_low_penalty_ra); + +	coex_dm->pre_low_penalty_ra = coex_dm->cur_low_penalty_ra; +} + +static void halbtc8821a2ant_set_dac_swing_reg(struct btc_coexist *btcoexist, +					      u32 level) +{ +	u8 val = (u8)level; + +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, +		  "[BTCoex], Write SwDacSwing = 0x%x\n", level); +	btcoexist->btc_write_1byte_bitmask(btcoexist, 0xc5b, 0x3e, val); +} + +static void set_sw_fulltime_dac_swing(struct btc_coexist *btcoexist, +				      bool sw_dac_swing_on, +				      u32 sw_dac_swing_lvl) +{ +	if (sw_dac_swing_on) +		halbtc8821a2ant_set_dac_swing_reg(btcoexist, sw_dac_swing_lvl); +	else +		halbtc8821a2ant_set_dac_swing_reg(btcoexist, 0x18); +} + +static void halbtc8821a2ant_dac_swing(struct btc_coexist *btcoexist, +				      bool force_exec, bool dac_swing_on, +				      u32 dac_swing_lvl) +{ +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, +		  "[BTCoex], %s turn DacSwing =%s, dac_swing_lvl = 0x%x\n", +		  (force_exec ? "force to" : ""), +		  ((dac_swing_on) ? "ON" : "OFF"), dac_swing_lvl); +	coex_dm->cur_dac_swing_on = dac_swing_on; +	coex_dm->cur_dac_swing_lvl = dac_swing_lvl; + +	if (!force_exec) { +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, +			  "[BTCoex], pre_dac_swing_on =%d, pre_dac_swing_lvl = 0x%x, cur_dac_swing_on =%d, cur_dac_swing_lvl = 0x%x\n", +			  coex_dm->pre_dac_swing_on, +			  coex_dm->pre_dac_swing_lvl, +			  coex_dm->cur_dac_swing_on, +			  coex_dm->cur_dac_swing_lvl); + +		if ((coex_dm->pre_dac_swing_on == coex_dm->cur_dac_swing_on) && +		    (coex_dm->pre_dac_swing_lvl == coex_dm->cur_dac_swing_lvl)) +			return; +	} +	mdelay(30); +	set_sw_fulltime_dac_swing(btcoexist, dac_swing_on, dac_swing_lvl); + +	coex_dm->pre_dac_swing_on = coex_dm->cur_dac_swing_on; +	coex_dm->pre_dac_swing_lvl = coex_dm->cur_dac_swing_lvl; +} + +static void halbtc8821a2ant_set_adc_back_off(struct btc_coexist *btcoexist, +					     bool adc_back_off) +{ +	if (adc_back_off) { +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, +			  "[BTCoex], BB BackOff Level On!\n"); +		btcoexist->btc_write_1byte_bitmask(btcoexist, 0x8db, 0x60, 0x3); +	} else { +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, +			  "[BTCoex], BB BackOff Level Off!\n"); +		btcoexist->btc_write_1byte_bitmask(btcoexist, 0x8db, 0x60, 0x1); +	} +} + +static void halbtc8821a2ant_adc_back_off(struct btc_coexist *btcoexist, +					 bool force_exec, bool adc_back_off) +{ +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, +		  "[BTCoex], %s turn AdcBackOff = %s\n", +		  (force_exec ? "force to" : ""), +		  ((adc_back_off) ? "ON" : "OFF")); +	coex_dm->cur_adc_back_off = adc_back_off; + +	if (!force_exec) { +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, +			  "[BTCoex], pre_adc_back_off =%d, cur_adc_back_off =%d\n", +			coex_dm->pre_adc_back_off, coex_dm->cur_adc_back_off); + +		if (coex_dm->pre_adc_back_off == coex_dm->cur_adc_back_off) +			return; +	} +	halbtc8821a2ant_set_adc_back_off(btcoexist, coex_dm->cur_adc_back_off); + +	coex_dm->pre_adc_back_off = coex_dm->cur_adc_back_off; +} + +static void halbtc8821a2ant_set_coex_table(struct btc_coexist *btcoexist, +					   u32 val0x6c0, u32 val0x6c4, +					   u32 val0x6c8, u8 val0x6cc) +{ +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, +		  "[BTCoex], set coex table, set 0x6c0 = 0x%x\n", val0x6c0); +	btcoexist->btc_write_4byte(btcoexist, 0x6c0, val0x6c0); + +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, +		  "[BTCoex], set coex table, set 0x6c4 = 0x%x\n", val0x6c4); +	btcoexist->btc_write_4byte(btcoexist, 0x6c4, val0x6c4); + +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, +		  "[BTCoex], set coex table, set 0x6c8 = 0x%x\n", val0x6c8); +	btcoexist->btc_write_4byte(btcoexist, 0x6c8, val0x6c8); + +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, +		  "[BTCoex], set coex table, set 0x6cc = 0x%x\n", val0x6cc); +	btcoexist->btc_write_1byte(btcoexist, 0x6cc, val0x6cc); +} + +static void halbtc8821a2ant_coex_table(struct btc_coexist *btcoexist, +				       bool force_exec, u32 val0x6c0, +				       u32 val0x6c4, u32 val0x6c8, u8 val0x6cc) +{ +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, +		  "[BTCoex], %s write Coex Table 0x6c0 = 0x%x, 0x6c4 = 0x%x, 0x6c8 = 0x%x, 0x6cc = 0x%x\n", +		  (force_exec ? "force to" : ""), +		  val0x6c0, val0x6c4, val0x6c8, val0x6cc); +	coex_dm->cur_val0x6c0 = val0x6c0; +	coex_dm->cur_val0x6c4 = val0x6c4; +	coex_dm->cur_val0x6c8 = val0x6c8; +	coex_dm->cur_val0x6cc = val0x6cc; + +	if (!force_exec) { +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, +			  "[BTCoex], pre_val0x6c0 = 0x%x, pre_val0x6c4 = 0x%x, pre_val0x6c8 = 0x%x, pre_val0x6cc = 0x%x !!\n", +			  coex_dm->pre_val0x6c0, coex_dm->pre_val0x6c4, +			  coex_dm->pre_val0x6c8, coex_dm->pre_val0x6cc); +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, +			  "[BTCoex], cur_val0x6c0 = 0x%x, cur_val0x6c4 = 0x%x, cur_val0x6c8 = 0x%x, cur_val0x6cc = 0x%x !!\n", +			  coex_dm->cur_val0x6c0, coex_dm->cur_val0x6c4, +			  coex_dm->cur_val0x6c8, coex_dm->cur_val0x6cc); + +		if ((coex_dm->pre_val0x6c0 == coex_dm->cur_val0x6c0) && +			(coex_dm->pre_val0x6c4 == coex_dm->cur_val0x6c4) && +			(coex_dm->pre_val0x6c8 == coex_dm->cur_val0x6c8) && +			(coex_dm->pre_val0x6cc == coex_dm->cur_val0x6cc)) +			return; +	} +	halbtc8821a2ant_set_coex_table(btcoexist, val0x6c0, val0x6c4, +				       val0x6c8, val0x6cc); + +	coex_dm->pre_val0x6c0 = coex_dm->cur_val0x6c0; +	coex_dm->pre_val0x6c4 = coex_dm->cur_val0x6c4; +	coex_dm->pre_val0x6c8 = coex_dm->cur_val0x6c8; +	coex_dm->pre_val0x6cc = coex_dm->cur_val0x6cc; +} + +static void set_fw_ignore_wlan_act(struct btc_coexist *btcoexist, bool enable) +{ +	u8 h2c_parameter[1] = {0}; + +	if (enable) +		h2c_parameter[0] |= BIT(0);		/*  function enable */ + +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, +		  "[BTCoex], set FW for BT Ignore Wlan_Act, FW write 0x63 = 0x%x\n", +		  h2c_parameter[0]); + +	btcoexist->btc_fill_h2c(btcoexist, 0x63, 1, h2c_parameter); +} + +static void halbtc8821a2ant_ignore_wlan_act(struct btc_coexist *btcoexist, +					    bool force_exec, bool enable) +{ +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, +		  "[BTCoex], %s turn Ignore WlanAct %s\n", +		  (force_exec ? "force to" : ""), (enable ? "ON" : "OFF")); +	coex_dm->cur_ignore_wlan_act = enable; + +	if (!force_exec) { +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, +			  "[BTCoex], pre_ignore_wlan_act = %d, cur_ignore_wlan_act = %d!!\n", +			  coex_dm->pre_ignore_wlan_act, +			  coex_dm->cur_ignore_wlan_act); +		if (coex_dm->pre_ignore_wlan_act == +		    coex_dm->cur_ignore_wlan_act) +			return; +	} +	set_fw_ignore_wlan_act(btcoexist, enable); + +	coex_dm->pre_ignore_wlan_act = coex_dm->cur_ignore_wlan_act; +} + +static void halbtc8821a2ant_set_fw_pstdma(struct btc_coexist *btcoexist, +					  u8 byte1, u8 byte2, u8 byte3, +					  u8 byte4, u8 byte5) +{ +	u8 h2c_parameter[5] = {0}; + +	h2c_parameter[0] = byte1; +	h2c_parameter[1] = byte2; +	h2c_parameter[2] = byte3; +	h2c_parameter[3] = byte4; +	h2c_parameter[4] = byte5; + +	coex_dm->ps_tdma_para[0] = byte1; +	coex_dm->ps_tdma_para[1] = byte2; +	coex_dm->ps_tdma_para[2] = byte3; +	coex_dm->ps_tdma_para[3] = byte4; +	coex_dm->ps_tdma_para[4] = byte5; + +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, +		  "[BTCoex], FW write 0x60(5bytes) = 0x%x%08x\n", +		  h2c_parameter[0], +		  h2c_parameter[1] << 24 | h2c_parameter[2] << 16 | +		  h2c_parameter[3]<<8|h2c_parameter[4]); + +	btcoexist->btc_fill_h2c(btcoexist, 0x60, 5, h2c_parameter); +} + +static void sw_mechanism1(struct btc_coexist *btcoexist, bool shrink_rx_lpf, +			  bool low_penalty_ra, bool limited_dig, +			  bool bt_lna_constrain) +{ +	u32 wifi_bw; + +	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + +	if (BTC_WIFI_BW_HT40 != wifi_bw) {  /* only shrink RF Rx LPF for HT40 */ +		if (shrink_rx_lpf) +			shrink_rx_lpf = false; +	} + +	 halbtc8821a2ant_RfShrink(btcoexist, NORMAL_EXEC, shrink_rx_lpf); +	halbtc8821a2ant_low_penalty_ra(btcoexist, NORMAL_EXEC, low_penalty_ra); + +	/* no limited DIG */ +	/* set_bt_lna_constrain(btcoexist, NORMAL_EXEC, bBTLNAConstrain); */ +} + +static void sw_mechanism2(struct btc_coexist *btcoexist, bool agc_table_shift, +			  bool adc_back_off, bool sw_dac_swing, +			  u32 dac_swing_lvl) +{ +	/* halbtc8821a2ant_AgcTable(btcoexist, NORMAL_EXEC, bAGCTableShift); */ +	halbtc8821a2ant_adc_back_off(btcoexist, NORMAL_EXEC, adc_back_off); +	halbtc8821a2ant_dac_swing(btcoexist, NORMAL_EXEC, sw_dac_swing, +				  sw_dac_swing); +} + +static void halbtc8821a2ant_set_ant_path(struct btc_coexist *btcoexist, +					 u8 ant_pos_type, bool init_hw_cfg, +					 bool wifi_off) +{ +	struct btc_board_info *board_info = &btcoexist->board_info; +	u32 u4tmp = 0; +	u8 h2c_parameter[2] = {0}; + +	if (init_hw_cfg) { +		/*  0x4c[23] = 0, 0x4c[24] = 1  Antenna control by WL/BT */ +		u4tmp = btcoexist->btc_read_4byte(btcoexist, 0x4c); +		u4tmp &= ~BIT(23); +		u4tmp |= BIT(24); +		btcoexist->btc_write_4byte(btcoexist, 0x4c, u4tmp); + +		btcoexist->btc_write_4byte(btcoexist, 0x974, 0x3ff); +		btcoexist->btc_write_1byte(btcoexist, 0xcb4, 0x77); + +		if (board_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT) { +			/* tell firmware "antenna inverse"  ==> WRONG firmware +			 * antenna control code.==>need fw to fix */ +			h2c_parameter[0] = 1; +			h2c_parameter[1] = 1; +			btcoexist->btc_fill_h2c(btcoexist, 0x65, 2, h2c_parameter); +		} else { +			/* tell firmware "no antenna inverse" ==> WRONG firmware +			 * antenna control code.==>need fw to fix */ +			h2c_parameter[0] = 0; +			h2c_parameter[1] = 1; +			btcoexist->btc_fill_h2c(btcoexist, 0x65, 2, +						h2c_parameter); +		} +	} + +	/*  ext switch setting */ +	switch (ant_pos_type) { +	case BTC_ANT_WIFI_AT_MAIN: +		btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcb7, 0x30, 0x1); +		break; +	case BTC_ANT_WIFI_AT_AUX: +		btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcb7, 0x30, 0x2); +		break; +	} +} + +static void ps21a_tdma(struct btc_coexist *btcoexist, bool force_exec, +		       bool turn_on, u8 type) +{ +	/* bool turn_on_by_cnt = false; */ +	/* u8 ps_tdma_type_by_cnt = 0; */ + +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, +		  "[BTCoex], %s turn %s PS TDMA, type =%d\n", +		  (force_exec ? "force to" : ""), +		  (turn_on ? "ON" : "OFF"), type); +	coex_dm->cur_ps_tdma_on = turn_on; +	coex_dm->cur_ps_tdma = type; + +	if (!force_exec) { +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, +			  "[BTCoex], pre_ps_tdma_on = %d, cur_ps_tdma_on = %d!!\n", +			  coex_dm->pre_ps_tdma_on, coex_dm->cur_ps_tdma_on); +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, +			  "[BTCoex], pre_ps_tdma = %d, cur_ps_tdma = %d!!\n", +			  coex_dm->pre_ps_tdma, coex_dm->cur_ps_tdma); + +		if ((coex_dm->pre_ps_tdma_on == coex_dm->cur_ps_tdma_on) && +		    (coex_dm->pre_ps_tdma == coex_dm->cur_ps_tdma)) +			return; +	} +	if (turn_on) { +		switch (type) { +		case 1: +		default: +			halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x1a, +						      0x1a, 0xe1, 0x90); +			break; +		case 2: +			halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x12, +						      0x12, 0xe1, 0x90); +			break; +		case 3: +			halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x1c, +						      0x3, 0xf1, 0x90); +			break; +		case 4: +			halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x10, +						      0x03, 0xf1, 0x90); +			break; +		case 5: +			halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x1a, +						      0x1a, 0x60, 0x90); +			break; +		case 6: +			halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x12, +						      0x12, 0x60, 0x90); +			break; +		case 7: +			halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x1c, +						      0x3, 0x70, 0x90); +			break; +		case 8: +			halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xa3, 0x10, +						      0x3, 0x70, 0x90); +			break; +		case 9: +			halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x1a, +						      0x1a, 0xe1, 0x90); +			break; +		case 10: +			halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x12, +						      0x12, 0xe1, 0x90); +			break; +		case 11: +			halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0xa, +						      0xa, 0xe1, 0x90); +			break; +		case 12: +			halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x5, +						      0x5, 0xe1, 0x90); +			break; +		case 13: +			halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x1a, +						      0x1a, 0x60, 0x90); +			break; +		case 14: +			halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x12, +						      0x12, 0x60, 0x90); +			break; +		case 15: +			halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0xa, +						      0xa, 0x60, 0x90); +			break; +		case 16: +			halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x5, +						      0x5, 0x60, 0x90); +			break; +		case 17: +			halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xa3, 0x2f, +						      0x2f, 0x60, 0x90); +			break; +		case 18: +			halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x5, +						      0x5, 0xe1, 0x90); +			break; +		case 19: +			halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x25, +						      0x25, 0xe1, 0x90); +			break; +		case 20: +			halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x25, +						      0x25, 0x60, 0x90); +			break; +		case 21: +			halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x15, +						      0x03, 0x70, 0x90); +			break; +		case 71: +			halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x1a, +						      0x1a, 0xe1, 0x90); +			break; +		} +	} else { +		/*  disable PS tdma */ +		switch (type) { +		case 0: +			halbtc8821a2ant_set_fw_pstdma(btcoexist, 0x0, 0x0, 0x0, +						      0x40, 0x0); +			break; +		case 1: +			halbtc8821a2ant_set_fw_pstdma(btcoexist, 0x0, 0x0, 0x0, +						      0x48, 0x0); +			break; +		default: +			halbtc8821a2ant_set_fw_pstdma(btcoexist, 0x0, 0x0, 0x0, +						      0x40, 0x0); +			break; +		} +	} + +	/*  update pre state */ +	coex_dm->pre_ps_tdma_on = coex_dm->cur_ps_tdma_on; +	coex_dm->pre_ps_tdma = coex_dm->cur_ps_tdma; +} + +static void halbtc8821a2ant_coex_all_off(struct btc_coexist *btcoexist) +{ +	/*  fw all off */ +	ps21a_tdma(btcoexist, NORMAL_EXEC, false, 1); +	halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); +	halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + +	/*  sw all off */ +	sw_mechanism1(btcoexist, false, false, false, false); +	sw_mechanism2(btcoexist, false, false, false, 0x18); + +	/*  hw all off */ +	halbtc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55555555, +				   0x55555555, 0xffff, 0x3); +} + +static void halbtc8821a2ant_coex_under_5g(struct btc_coexist *btcoexist) +{ +	halbtc8821a2ant_coex_all_off(btcoexist); +} + +static void halbtc8821a2ant_init_coex_dm(struct btc_coexist *btcoexist) +{ +	/*  force to reset coex mechanism */ +	halbtc8821a2ant_coex_table(btcoexist, FORCE_EXEC, 0x55555555, +				   0x55555555, 0xffff, 0x3); + +	ps21a_tdma(btcoexist, FORCE_EXEC, false, 1); +	halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, FORCE_EXEC, 6); +	halbtc8821a2ant_dec_bt_pwr(btcoexist, FORCE_EXEC, false); + +	sw_mechanism1(btcoexist, false, false, false, false); +	sw_mechanism2(btcoexist, false, false, false, 0x18); +} + +static void halbtc8821a2ant_bt_inquiry_page(struct btc_coexist *btcoexist) +{ +	bool low_pwr_disable = true; + +	btcoexist->btc_set(btcoexist, BTC_SET_ACT_DISABLE_LOW_POWER, +			   &low_pwr_disable); + +	halbtc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff, +				   0x5afa5afa, 0xffff, 0x3); +	ps21a_tdma(btcoexist, NORMAL_EXEC, true, 3); +} + +static bool halbtc8821a2ant_is_common_action(struct btc_coexist *btcoexist) +{ +	bool common = false, wifi_connected = false, wifi_busy = false; +	bool low_pwr_disable = false; + +	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, +			   &wifi_connected); +	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + +	halbtc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff, +				   0x5afa5afa, 0xffff, 0x3); + +	if (!wifi_connected && +	    BT_8821A_2ANT_BT_STATUS_IDLE == coex_dm->bt_status) { +		low_pwr_disable = false; +		btcoexist->btc_set(btcoexist, BTC_SET_ACT_DISABLE_LOW_POWER, +				   &low_pwr_disable); + +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +			  "[BTCoex], Wifi IPS + BT IPS!!\n"); + +		ps21a_tdma(btcoexist, NORMAL_EXEC, false, 1); +		halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); +		halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + +		sw_mechanism1(btcoexist, false, false, false, false); +		sw_mechanism2(btcoexist, false, false, false, 0x18); + +		common = true; +	} else if (wifi_connected && +		   (BT_8821A_2ANT_BT_STATUS_IDLE == coex_dm->bt_status)) { +		low_pwr_disable = false; +		btcoexist->btc_set(btcoexist, BTC_SET_ACT_DISABLE_LOW_POWER, +				   &low_pwr_disable); + +		if (wifi_busy) { +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +				  "[BTCoex], Wifi Busy + BT IPS!!\n"); +			ps21a_tdma(btcoexist, NORMAL_EXEC, false, 1); +		} else { +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +				  "[BTCoex], Wifi LPS + BT IPS!!\n"); +			ps21a_tdma(btcoexist, NORMAL_EXEC, false, 1); +		} + +		halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); +		halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + +		sw_mechanism1(btcoexist, false, false, false, false); +		sw_mechanism2(btcoexist, false, false, false, 0x18); + +		common = true; +	} else if (!wifi_connected && +		   (BT_8821A_2ANT_BT_STATUS_CONNECTED_IDLE == +		    coex_dm->bt_status)) { +		low_pwr_disable = true; +		btcoexist->btc_set(btcoexist, BTC_SET_ACT_DISABLE_LOW_POWER, +				   &low_pwr_disable); + +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +			  "[BTCoex], Wifi IPS + BT LPS!!\n"); + +		ps21a_tdma(btcoexist, NORMAL_EXEC, false, 1); +		halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); +		halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + +		sw_mechanism1(btcoexist, false, false, false, false); +		sw_mechanism2(btcoexist, false, false, false, 0x18); + +		common = true; +	} else if (wifi_connected && +		   (BT_8821A_2ANT_BT_STATUS_CONNECTED_IDLE == +		    coex_dm->bt_status)) { +		low_pwr_disable = true; +		btcoexist->btc_set(btcoexist, BTC_SET_ACT_DISABLE_LOW_POWER, +				   &low_pwr_disable); + +		if (wifi_busy) { +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +				  "[BTCoex], Wifi Busy + BT LPS!!\n"); +			ps21a_tdma(btcoexist, NORMAL_EXEC, false, 1); +		} else { +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +				  "[BTCoex], Wifi LPS + BT LPS!!\n"); +			ps21a_tdma(btcoexist, NORMAL_EXEC, false, 1); +		} + +		halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); +		halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + +		sw_mechanism1(btcoexist, true, true, true, true); +		sw_mechanism2(btcoexist, false, false, false, 0x18); + +		common = true; +	} else if (!wifi_connected && +		   (BT_8821A_2ANT_BT_STATUS_NON_IDLE == coex_dm->bt_status)) { +		low_pwr_disable = false; +		btcoexist->btc_set(btcoexist, BTC_SET_ACT_DISABLE_LOW_POWER, +				   &low_pwr_disable); + +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +			  "[BTCoex], Wifi IPS + BT Busy!!\n"); + +		ps21a_tdma(btcoexist, NORMAL_EXEC, false, 1); +		halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); +		halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + +		sw_mechanism1(btcoexist, false, false, false, false); +		sw_mechanism2(btcoexist, false, false, false, 0x18); + +		common = true; +	} else { +		low_pwr_disable = true; +		btcoexist->btc_set(btcoexist, BTC_SET_ACT_DISABLE_LOW_POWER, +				   &low_pwr_disable); + +		if (wifi_busy) { +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +				  "[BTCoex], Wifi Busy + BT Busy!!\n"); +			common = false; +		} else { +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +				  "[BTCoex], Wifi LPS + BT Busy!!\n"); +			ps21a_tdma(btcoexist, NORMAL_EXEC, true, 21); + +			if (halbtc8821a2ant_need_to_dec_bt_pwr(btcoexist)) +				halbtc8821a2ant_dec_bt_pwr(btcoexist, +							   NORMAL_EXEC, true); +			else +				halbtc8821a2ant_dec_bt_pwr(btcoexist, +							   NORMAL_EXEC, false); + +			common = true; +		} +		sw_mechanism1(btcoexist, true, true, true, true); +	} +	return common; +} + +static void tdma_duration_adjust(struct btc_coexist *btcoexist, +				 bool sco_hid, bool tx_pause, u8 max_interval) +{ +	static long up, dn, m, n, wait_count; +	long result; +	/* 0: no change, +1: incr WiFi duration, -1: decr WiFi duration */ +	u8 retry_count = 0; + +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, +		  "[BTCoex], TdmaDurationAdjust()\n"); + +	if (coex_dm->reset_tdma_adjust) { +		coex_dm->reset_tdma_adjust = false; +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, +			  "[BTCoex], first run TdmaDurationAdjust()!!\n"); +		if (sco_hid) { +			if (tx_pause) { +				if (max_interval == 1) { +					ps21a_tdma(btcoexist, NORMAL_EXEC, true, 13); +					coex_dm->ps_tdma_du_adj_type = 13; +				} else if (max_interval == 2) { +					ps21a_tdma(btcoexist, NORMAL_EXEC, true, 14); +					coex_dm->ps_tdma_du_adj_type = 14; +				} else if (max_interval == 3) { +					ps21a_tdma(btcoexist, NORMAL_EXEC, true, 15); +					coex_dm->ps_tdma_du_adj_type = 15; +				} else { +					ps21a_tdma(btcoexist, NORMAL_EXEC, true, 15); +					coex_dm->ps_tdma_du_adj_type = 15; +				} +			} else { +				if (max_interval == 1) { +					ps21a_tdma(btcoexist, NORMAL_EXEC, true, 9); +					coex_dm->ps_tdma_du_adj_type = 9; +				} else if (max_interval == 2) { +					ps21a_tdma(btcoexist, NORMAL_EXEC, true, 10); +					coex_dm->ps_tdma_du_adj_type = 10; +				} else if (max_interval == 3) { +					ps21a_tdma(btcoexist, NORMAL_EXEC, true, 11); +					coex_dm->ps_tdma_du_adj_type = 11; +				} else { +					ps21a_tdma(btcoexist, NORMAL_EXEC, true, 11); +					coex_dm->ps_tdma_du_adj_type = 11; +				} +			} +		} else { +			if (tx_pause) { +				if (max_interval == 1) { +					ps21a_tdma(btcoexist, NORMAL_EXEC, true, 5); +					coex_dm->ps_tdma_du_adj_type = 5; +				} else if (max_interval == 2) { +					ps21a_tdma(btcoexist, NORMAL_EXEC, true, 6); +					coex_dm->ps_tdma_du_adj_type = 6; +				} else if (max_interval == 3) { +					ps21a_tdma(btcoexist, NORMAL_EXEC, true, 7); +					coex_dm->ps_tdma_du_adj_type = 7; +				} else { +					ps21a_tdma(btcoexist, NORMAL_EXEC, true, 7); +					coex_dm->ps_tdma_du_adj_type = 7; +				} +			} else { +				if (max_interval == 1) { +					ps21a_tdma(btcoexist, NORMAL_EXEC, true, 1); +					coex_dm->ps_tdma_du_adj_type = 1; +				} else if (max_interval == 2) { +					ps21a_tdma(btcoexist, NORMAL_EXEC, true, 2); +					coex_dm->ps_tdma_du_adj_type = 2; +				} else if (max_interval == 3) { +					ps21a_tdma(btcoexist, NORMAL_EXEC, true, 3); +					coex_dm->ps_tdma_du_adj_type = 3; +				} else { +					ps21a_tdma(btcoexist, NORMAL_EXEC, true, 3); +					coex_dm->ps_tdma_du_adj_type = 3; +				} +			} +		} +		up = 0; +		dn = 0; +		m = 1; +		n = 3; +		result = 0; +		wait_count = 0; +	} else { +		/* accquire the BT TRx retry count from BT_Info byte2 */ +		retry_count = coex_sta->bt_retry_cnt; +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, +			  "[BTCoex], retry_count = %d\n", retry_count); +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, +			  "[BTCoex], up =%d, dn =%d, m =%d, n =%d, wait_count =%d\n", +			  (int)up, (int)dn, (int)m, (int)n, (int)wait_count); +		result = 0; +		wait_count++; + +		if (retry_count == 0) { +			/*  no retry in the last 2-second duration */ +			up++; +			dn--; + +			if (dn <= 0) +				dn = 0; + +			if (up >= n) { +				wait_count = 0; +				n = 3; +				up = 0; +				dn = 0; +				result = 1; +				BTC_PRINT(BTC_MSG_ALGORITHM, +					  ALGO_TRACE_FW_DETAIL, +					  "[BTCoex], Increase wifi duration!!\n"); +			} +		} else if (retry_count <= 3) { +			/*  <= 3 retry in the last 2-second duration */ +			up--; +			dn++; + +			if (up <= 0) +				up = 0; + +			if (dn == 2) { +				if (wait_count <= 2) +					m++; +				else +					m = 1; + +				if (m >= 20) +					m = 20; + +				n = 3*m; +				up = 0; +				dn = 0; +				wait_count = 0; +				result = -1; +				BTC_PRINT(BTC_MSG_ALGORITHM, +					  ALGO_TRACE_FW_DETAIL, +					  "[BTCoex], Decrease wifi duration for retryCounter<3!!\n"); +			} +		} else { +			if (wait_count == 1) +				m++; +			else +				m = 1; + +			if (m >= 20) +				m = 20; + +			n = 3*m; +			up = 0; +			dn = 0; +			wait_count = 0; +			result = -1; +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, +				  "[BTCoex], Decrease wifi duration for retryCounter>3!!\n"); +		} + +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, +			  "[BTCoex], max Interval = %d\n", max_interval); +		if (max_interval == 1) { +			if (tx_pause) { +				/* TODO: refactor here */ +				BTC_PRINT(BTC_MSG_ALGORITHM, +					  ALGO_TRACE_FW_DETAIL, +					  "[BTCoex], TxPause = 1\n"); +				if (coex_dm->cur_ps_tdma == 71) { +					ps21a_tdma(btcoexist, +								NORMAL_EXEC, +								true, 5); +					coex_dm->ps_tdma_du_adj_type = 5; +				} else if (coex_dm->cur_ps_tdma == 1) { +					ps21a_tdma(btcoexist, +								NORMAL_EXEC, +								true, 5); +					coex_dm->ps_tdma_du_adj_type = 5; +				} else if (coex_dm->cur_ps_tdma == 2) { +					ps21a_tdma(btcoexist, +								NORMAL_EXEC, +								true, 6); +					coex_dm->ps_tdma_du_adj_type = 6; +				} else if (coex_dm->cur_ps_tdma == 3) { +					ps21a_tdma(btcoexist, +								NORMAL_EXEC, +								true, 7); +					coex_dm->ps_tdma_du_adj_type = 7; +				} else if (coex_dm->cur_ps_tdma == 4) { +					ps21a_tdma(btcoexist, NORMAL_EXEC, true, 8); +					coex_dm->ps_tdma_du_adj_type = 8; +				} +				if (coex_dm->cur_ps_tdma == 9) { +					ps21a_tdma(btcoexist, NORMAL_EXEC, true, 13); +					coex_dm->ps_tdma_du_adj_type = 13; +				} else if (coex_dm->cur_ps_tdma == 10) { +					ps21a_tdma(btcoexist, NORMAL_EXEC, true, 14); +					coex_dm->ps_tdma_du_adj_type = 14; +				} else if (coex_dm->cur_ps_tdma == 11) { +					ps21a_tdma(btcoexist, NORMAL_EXEC, true, 15); +					coex_dm->ps_tdma_du_adj_type = 15; +				} else if (coex_dm->cur_ps_tdma == 12) { +					ps21a_tdma(btcoexist, NORMAL_EXEC, true, 16); +					coex_dm->ps_tdma_du_adj_type = 16; +				} + +				if (result == -1) { +					if (coex_dm->cur_ps_tdma == 5) { +						ps21a_tdma(btcoexist, NORMAL_EXEC, true, 6); +						coex_dm->ps_tdma_du_adj_type = 6; +					} else if (coex_dm->cur_ps_tdma == 6) { +						ps21a_tdma(btcoexist, NORMAL_EXEC, true, 7); +						coex_dm->ps_tdma_du_adj_type = 7; +					} else if (coex_dm->cur_ps_tdma == 7) { +						ps21a_tdma(btcoexist, NORMAL_EXEC, true, 8); +						coex_dm->ps_tdma_du_adj_type = 8; +					} else if (coex_dm->cur_ps_tdma == 13) { +						ps21a_tdma(btcoexist, NORMAL_EXEC, true, 14); +						coex_dm->ps_tdma_du_adj_type = 14; +					} else if (coex_dm->cur_ps_tdma == 14) { +						ps21a_tdma(btcoexist, NORMAL_EXEC, true, 15); +						coex_dm->ps_tdma_du_adj_type = 15; +					} else if (coex_dm->cur_ps_tdma == 15) { +						ps21a_tdma(btcoexist, NORMAL_EXEC, true, 16); +						coex_dm->ps_tdma_du_adj_type = 16; +					} +				} else if (result == 1) { +					if (coex_dm->cur_ps_tdma == 8) { +						ps21a_tdma(btcoexist, NORMAL_EXEC, true, 7); +						coex_dm->ps_tdma_du_adj_type = 7; +					} else if (coex_dm->cur_ps_tdma == 7) { +						ps21a_tdma(btcoexist, NORMAL_EXEC, true, 6); +						coex_dm->ps_tdma_du_adj_type = 6; +					} else if (coex_dm->cur_ps_tdma == 6) { +						ps21a_tdma(btcoexist, NORMAL_EXEC, true, 5); +						coex_dm->ps_tdma_du_adj_type = 5; +					} else if (coex_dm->cur_ps_tdma == 16) { +						ps21a_tdma(btcoexist, NORMAL_EXEC, true, 15); +						coex_dm->ps_tdma_du_adj_type = 15; +					} else if (coex_dm->cur_ps_tdma == 15) { +						ps21a_tdma(btcoexist, NORMAL_EXEC, true, 14); +						coex_dm->ps_tdma_du_adj_type = 14; +					} else if (coex_dm->cur_ps_tdma == 14) { +						ps21a_tdma(btcoexist, NORMAL_EXEC, true, 13); +						coex_dm->ps_tdma_du_adj_type = 13; +					} +				} +			} else { +				/* TODO: refactor here */ +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, "[BTCoex], TxPause = 0\n"); +				if (coex_dm->cur_ps_tdma == 5) { +					ps21a_tdma(btcoexist, NORMAL_EXEC, true, 71); +					coex_dm->ps_tdma_du_adj_type = 71; +				} else if (coex_dm->cur_ps_tdma == 6) { +					ps21a_tdma(btcoexist, NORMAL_EXEC, true, 2); +					coex_dm->ps_tdma_du_adj_type = 2; +				} else if (coex_dm->cur_ps_tdma == 7) { +					ps21a_tdma(btcoexist, NORMAL_EXEC, true, 3); +					coex_dm->ps_tdma_du_adj_type = 3; +				} else if (coex_dm->cur_ps_tdma == 8) { +					ps21a_tdma(btcoexist, NORMAL_EXEC, true, 4); +					coex_dm->ps_tdma_du_adj_type = 4; +				} +				if (coex_dm->cur_ps_tdma == 13) { +					ps21a_tdma(btcoexist, NORMAL_EXEC, true, 9); +					coex_dm->ps_tdma_du_adj_type = 9; +				} else if (coex_dm->cur_ps_tdma == 14) { +					ps21a_tdma(btcoexist, NORMAL_EXEC, true, 10); +					coex_dm->ps_tdma_du_adj_type = 10; +				} else if (coex_dm->cur_ps_tdma == 15) { +					ps21a_tdma(btcoexist, NORMAL_EXEC, true, 11); +					coex_dm->ps_tdma_du_adj_type = 11; +				} else if (coex_dm->cur_ps_tdma == 16) { +					ps21a_tdma(btcoexist, NORMAL_EXEC, true, 12); +					coex_dm->ps_tdma_du_adj_type = 12; +				} + +				if (result == -1) { +					if (coex_dm->cur_ps_tdma == 71) { +						ps21a_tdma(btcoexist, NORMAL_EXEC, true, 1); +						coex_dm->ps_tdma_du_adj_type = 1; +					} else if (coex_dm->cur_ps_tdma == 1) { +						ps21a_tdma(btcoexist, NORMAL_EXEC, true, 2); +						coex_dm->ps_tdma_du_adj_type = 2; +					} else if (coex_dm->cur_ps_tdma == 2) { +						ps21a_tdma(btcoexist, NORMAL_EXEC, true, 3); +						coex_dm->ps_tdma_du_adj_type = 3; +					} else if (coex_dm->cur_ps_tdma == 3) { +						ps21a_tdma(btcoexist, NORMAL_EXEC, true, 4); +						coex_dm->ps_tdma_du_adj_type = 4; +					} else if (coex_dm->cur_ps_tdma == 9) { +						ps21a_tdma(btcoexist, NORMAL_EXEC, true, 10); +						coex_dm->ps_tdma_du_adj_type = 10; +					} else if (coex_dm->cur_ps_tdma == 10) { +						ps21a_tdma(btcoexist, NORMAL_EXEC, true, 11); +						coex_dm->ps_tdma_du_adj_type = 11; +					} else if (coex_dm->cur_ps_tdma == 11) { +						ps21a_tdma(btcoexist, NORMAL_EXEC, true, 12); +						coex_dm->ps_tdma_du_adj_type = 12; +					} +				} else if (result == 1) { +					if (coex_dm->cur_ps_tdma == 4) { +						ps21a_tdma(btcoexist, NORMAL_EXEC, true, 3); +						coex_dm->ps_tdma_du_adj_type = 3; +					} else if (coex_dm->cur_ps_tdma == 3) { +						ps21a_tdma(btcoexist, NORMAL_EXEC, true, 2); +						coex_dm->ps_tdma_du_adj_type = 2; +					} else if (coex_dm->cur_ps_tdma == 2) { +						ps21a_tdma(btcoexist, NORMAL_EXEC, true, 1); +						coex_dm->ps_tdma_du_adj_type = 1; +					} else if (coex_dm->cur_ps_tdma == 1) { +						ps21a_tdma(btcoexist, NORMAL_EXEC, true, 71); +						coex_dm->ps_tdma_du_adj_type = 71; +					} else if (coex_dm->cur_ps_tdma == 12) { +						ps21a_tdma(btcoexist, NORMAL_EXEC, true, 11); +						coex_dm->ps_tdma_du_adj_type = 11; +					} else if (coex_dm->cur_ps_tdma == 11) { +						ps21a_tdma(btcoexist, NORMAL_EXEC, true, 10); +						coex_dm->ps_tdma_du_adj_type = 10; +					} else if (coex_dm->cur_ps_tdma == 10) { +						ps21a_tdma(btcoexist, NORMAL_EXEC, true, 9); +						coex_dm->ps_tdma_du_adj_type = 9; +					} +				} +			} +		} else if (max_interval == 2) { +			if (tx_pause) { +				/* TODO: refactor here */ +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, "[BTCoex], TxPause = 1\n"); +				if (coex_dm->cur_ps_tdma == 1) { +					ps21a_tdma(btcoexist, NORMAL_EXEC, true, 6); +					coex_dm->ps_tdma_du_adj_type = 6; +				} else if (coex_dm->cur_ps_tdma == 2) { +					ps21a_tdma(btcoexist, NORMAL_EXEC, true, 6); +					coex_dm->ps_tdma_du_adj_type = 6; +				} else if (coex_dm->cur_ps_tdma == 3) { +					ps21a_tdma(btcoexist, NORMAL_EXEC, true, 7); +					coex_dm->ps_tdma_du_adj_type = 7; +				} else if (coex_dm->cur_ps_tdma == 4) { +					ps21a_tdma(btcoexist, NORMAL_EXEC, true, 8); +					coex_dm->ps_tdma_du_adj_type = 8; +				} +				if (coex_dm->cur_ps_tdma == 9) { +					ps21a_tdma(btcoexist, NORMAL_EXEC, true, 14); +					coex_dm->ps_tdma_du_adj_type = 14; +				} else if (coex_dm->cur_ps_tdma == 10) { +					ps21a_tdma(btcoexist, NORMAL_EXEC, true, 14); +					coex_dm->ps_tdma_du_adj_type = 14; +				} else if (coex_dm->cur_ps_tdma == 11) { +					ps21a_tdma(btcoexist, NORMAL_EXEC, true, 15); +					coex_dm->ps_tdma_du_adj_type = 15; +				} else if (coex_dm->cur_ps_tdma == 12) { +					ps21a_tdma(btcoexist, NORMAL_EXEC, true, 16); +					coex_dm->ps_tdma_du_adj_type = 16; +				} +				if (result == -1) { +					if (coex_dm->cur_ps_tdma == 5) { +						ps21a_tdma(btcoexist, NORMAL_EXEC, true, 6); +						coex_dm->ps_tdma_du_adj_type = 6; +					} else if (coex_dm->cur_ps_tdma == 6) { +						ps21a_tdma(btcoexist, NORMAL_EXEC, true, 7); +						coex_dm->ps_tdma_du_adj_type = 7; +					} else if (coex_dm->cur_ps_tdma == 7) { +						ps21a_tdma(btcoexist, NORMAL_EXEC, true, 8); +						coex_dm->ps_tdma_du_adj_type = 8; +					} else if (coex_dm->cur_ps_tdma == 13) { +						ps21a_tdma(btcoexist, NORMAL_EXEC, true, 14); +						coex_dm->ps_tdma_du_adj_type = 14; +					} else if (coex_dm->cur_ps_tdma == 14) { +						ps21a_tdma(btcoexist, NORMAL_EXEC, true, 15); +						coex_dm->ps_tdma_du_adj_type = 15; +					} else if (coex_dm->cur_ps_tdma == 15) { +						ps21a_tdma(btcoexist, NORMAL_EXEC, true, 16); +						coex_dm->ps_tdma_du_adj_type = 16; +					} +				} else if (result == 1) { +					if (coex_dm->cur_ps_tdma == 8) { +						ps21a_tdma(btcoexist, NORMAL_EXEC, true, 7); +						coex_dm->ps_tdma_du_adj_type = 7; +					} else if (coex_dm->cur_ps_tdma == 7) { +						ps21a_tdma(btcoexist, NORMAL_EXEC, true, 6); +						coex_dm->ps_tdma_du_adj_type = 6; +					} else if (coex_dm->cur_ps_tdma == 6) { +						ps21a_tdma(btcoexist, NORMAL_EXEC, true, 6); +						coex_dm->ps_tdma_du_adj_type = 6; +					} else if (coex_dm->cur_ps_tdma == 16) { +						ps21a_tdma(btcoexist, NORMAL_EXEC, true, 15); +						coex_dm->ps_tdma_du_adj_type = 15; +					} else if (coex_dm->cur_ps_tdma == 15) { +						ps21a_tdma(btcoexist, NORMAL_EXEC, true, 14); +						coex_dm->ps_tdma_du_adj_type = 14; +					} else if (coex_dm->cur_ps_tdma == 14) { +						ps21a_tdma(btcoexist, NORMAL_EXEC, true, 14); +						coex_dm->ps_tdma_du_adj_type = 14; +					} +				} +			} else { +				/* TODO: refactor here */ +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, +					  "[BTCoex], TxPause = 0\n"); +				if (coex_dm->cur_ps_tdma == 5) { +					ps21a_tdma(btcoexist, NORMAL_EXEC, true, 2); +					coex_dm->ps_tdma_du_adj_type = 2; +				} else if (coex_dm->cur_ps_tdma == 6) { +					ps21a_tdma(btcoexist, NORMAL_EXEC, true, 2); +					coex_dm->ps_tdma_du_adj_type = 2; +				} else if (coex_dm->cur_ps_tdma == 7) { +					ps21a_tdma(btcoexist, NORMAL_EXEC, true, 3); +					coex_dm->ps_tdma_du_adj_type = 3; +				} else if (coex_dm->cur_ps_tdma == 8) { +					ps21a_tdma(btcoexist, NORMAL_EXEC, true, 4); +					coex_dm->ps_tdma_du_adj_type = 4; +				} +				if (coex_dm->cur_ps_tdma == 13) { +					ps21a_tdma(btcoexist, NORMAL_EXEC, true, 10); +					coex_dm->ps_tdma_du_adj_type = 10; +				} else if (coex_dm->cur_ps_tdma == 14) { +					ps21a_tdma(btcoexist, NORMAL_EXEC, true, 10); +					coex_dm->ps_tdma_du_adj_type = 10; +				} else if (coex_dm->cur_ps_tdma == 15) { +					ps21a_tdma(btcoexist, NORMAL_EXEC, true, 11); +					coex_dm->ps_tdma_du_adj_type = 11; +				} else if (coex_dm->cur_ps_tdma == 16) { +					ps21a_tdma(btcoexist, NORMAL_EXEC, true, 12); +					coex_dm->ps_tdma_du_adj_type = 12; +				} +				if (result == -1) { +					if (coex_dm->cur_ps_tdma == 1) { +						ps21a_tdma(btcoexist, NORMAL_EXEC, true, 2); +						coex_dm->ps_tdma_du_adj_type = 2; +					} else if (coex_dm->cur_ps_tdma == 2) { +						ps21a_tdma(btcoexist, NORMAL_EXEC, true, 3); +						coex_dm->ps_tdma_du_adj_type = 3; +					} else if (coex_dm->cur_ps_tdma == 3) { +						ps21a_tdma(btcoexist, NORMAL_EXEC, true, 4); +						coex_dm->ps_tdma_du_adj_type = 4; +					} else if (coex_dm->cur_ps_tdma == 9) { +						ps21a_tdma(btcoexist, NORMAL_EXEC, true, 10); +						coex_dm->ps_tdma_du_adj_type = 10; +					} else if (coex_dm->cur_ps_tdma == 10) { +						ps21a_tdma(btcoexist, NORMAL_EXEC, true, 11); +						coex_dm->ps_tdma_du_adj_type = 11; +					} else if (coex_dm->cur_ps_tdma == 11) { +						ps21a_tdma(btcoexist, NORMAL_EXEC, true, 12); +						coex_dm->ps_tdma_du_adj_type = 12; +					} +				} else if (result == 1) { +					if (coex_dm->cur_ps_tdma == 4) { +						ps21a_tdma(btcoexist, NORMAL_EXEC, true, 3); +						coex_dm->ps_tdma_du_adj_type = 3; +					} else if (coex_dm->cur_ps_tdma == 3) { +						ps21a_tdma(btcoexist, NORMAL_EXEC, true, 2); +						coex_dm->ps_tdma_du_adj_type = 2; +					} else if (coex_dm->cur_ps_tdma == 2) { +						ps21a_tdma(btcoexist, NORMAL_EXEC, true, 2); +						coex_dm->ps_tdma_du_adj_type = 2; +					} else if (coex_dm->cur_ps_tdma == 12) { +						ps21a_tdma(btcoexist, NORMAL_EXEC, true, 11); +						coex_dm->ps_tdma_du_adj_type = 11; +					} else if (coex_dm->cur_ps_tdma == 11) { +						ps21a_tdma(btcoexist, NORMAL_EXEC, true, 10); +						coex_dm->ps_tdma_du_adj_type = 10; +					} else if (coex_dm->cur_ps_tdma == 10) { +						ps21a_tdma(btcoexist, NORMAL_EXEC, true, 10); +						coex_dm->ps_tdma_du_adj_type = 10; +					} +				} +			} +		} else if (max_interval == 3) { +			if (tx_pause) { +				/* TODO: refactor here */ +				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, +					  "[BTCoex], TxPause = 1\n"); +				if (coex_dm->cur_ps_tdma == 1) { +					ps21a_tdma(btcoexist, NORMAL_EXEC, true, 7); +					coex_dm->ps_tdma_du_adj_type = 7; +				} else if (coex_dm->cur_ps_tdma == 2) { +					ps21a_tdma(btcoexist, NORMAL_EXEC, true, 7); +					coex_dm->ps_tdma_du_adj_type = 7; +				} else if (coex_dm->cur_ps_tdma == 3) { +					ps21a_tdma(btcoexist, NORMAL_EXEC, true, 7); +					coex_dm->ps_tdma_du_adj_type = 7; +				} else if (coex_dm->cur_ps_tdma == 4) { +					ps21a_tdma(btcoexist, NORMAL_EXEC, true, 8); +					coex_dm->ps_tdma_du_adj_type = 8; +				} +				if (coex_dm->cur_ps_tdma == 9) { +					ps21a_tdma(btcoexist, NORMAL_EXEC, true, 15); +					coex_dm->ps_tdma_du_adj_type = 15; +				} else if (coex_dm->cur_ps_tdma == 10) { +					ps21a_tdma(btcoexist, NORMAL_EXEC, true, 15); +					coex_dm->ps_tdma_du_adj_type = 15; +				} else if (coex_dm->cur_ps_tdma == 11) { +					ps21a_tdma(btcoexist, NORMAL_EXEC, true, 15); +					coex_dm->ps_tdma_du_adj_type = 15; +				} else if (coex_dm->cur_ps_tdma == 12) { +					ps21a_tdma(btcoexist, NORMAL_EXEC, true, 16); +					coex_dm->ps_tdma_du_adj_type = 16; +				} +				if (result == -1) { +					if (coex_dm->cur_ps_tdma == 5) { +						ps21a_tdma(btcoexist, NORMAL_EXEC, true, 7); +						coex_dm->ps_tdma_du_adj_type = 7; +					} else if (coex_dm->cur_ps_tdma == 6) { +						ps21a_tdma(btcoexist, NORMAL_EXEC, true, 7); +						coex_dm->ps_tdma_du_adj_type = 7; +					} else if (coex_dm->cur_ps_tdma == 7) { +						ps21a_tdma(btcoexist, NORMAL_EXEC, true, 8); +						coex_dm->ps_tdma_du_adj_type = 8; +					} else if (coex_dm->cur_ps_tdma == 13) { +						ps21a_tdma(btcoexist, NORMAL_EXEC, true, 15); +						coex_dm->ps_tdma_du_adj_type = 15; +					} else if (coex_dm->cur_ps_tdma == 14) { +						ps21a_tdma(btcoexist, NORMAL_EXEC, true, 15); +						coex_dm->ps_tdma_du_adj_type = 15; +					} else if (coex_dm->cur_ps_tdma == 15) { +						ps21a_tdma(btcoexist, NORMAL_EXEC, true, 16); +						coex_dm->ps_tdma_du_adj_type = 16; +					} +				} else if (result == 1) { +					if (coex_dm->cur_ps_tdma == 8) { +						ps21a_tdma(btcoexist, NORMAL_EXEC, true, 7); +						coex_dm->ps_tdma_du_adj_type = 7; +					} else if (coex_dm->cur_ps_tdma == 7) { +						ps21a_tdma(btcoexist, NORMAL_EXEC, true, 7); +						coex_dm->ps_tdma_du_adj_type = 7; +					} else if (coex_dm->cur_ps_tdma == 6) { +						ps21a_tdma(btcoexist, NORMAL_EXEC, true, 7); +						coex_dm->ps_tdma_du_adj_type = 7; +					} else if (coex_dm->cur_ps_tdma == 16) { +						ps21a_tdma(btcoexist, NORMAL_EXEC, true, 15); +						coex_dm->ps_tdma_du_adj_type = 15; +					} else if (coex_dm->cur_ps_tdma == 15) { +						ps21a_tdma(btcoexist, NORMAL_EXEC, true, 15); +						coex_dm->ps_tdma_du_adj_type = 15; +					} else if (coex_dm->cur_ps_tdma == 14) { +						ps21a_tdma(btcoexist, NORMAL_EXEC, true, 15); +						coex_dm->ps_tdma_du_adj_type = 15; +					} +				} +			} else { +				BTC_PRINT(BTC_MSG_ALGORITHM, +					  ALGO_TRACE_FW_DETAIL, +					  "[BTCoex], TxPause = 0\n"); +				if (coex_dm->cur_ps_tdma == 5) { +					ps21a_tdma(btcoexist, NORMAL_EXEC, +						   true, 3); +					coex_dm->ps_tdma_du_adj_type = 3; +				} else if (coex_dm->cur_ps_tdma == 6) { +					ps21a_tdma(btcoexist, NORMAL_EXEC, +						   true, 3); +					coex_dm->ps_tdma_du_adj_type = 3; +				} else if (coex_dm->cur_ps_tdma == 7) { +					ps21a_tdma(btcoexist, NORMAL_EXEC, +						   true, 3); +					coex_dm->ps_tdma_du_adj_type = 3; +				} else if (coex_dm->cur_ps_tdma == 8) { +					ps21a_tdma(btcoexist, NORMAL_EXEC, +						   true, 4); +					coex_dm->ps_tdma_du_adj_type = 4; +				} +				if (coex_dm->cur_ps_tdma == 13) { +					ps21a_tdma(btcoexist, NORMAL_EXEC, +						   true, 11); +					coex_dm->ps_tdma_du_adj_type = 11; +				} else if (coex_dm->cur_ps_tdma == 14) { +					ps21a_tdma(btcoexist, NORMAL_EXEC, +						   true, 11); +					coex_dm->ps_tdma_du_adj_type = 11; +				} else if (coex_dm->cur_ps_tdma == 15) { +					ps21a_tdma(btcoexist, NORMAL_EXEC, +						   true, 11); +					coex_dm->ps_tdma_du_adj_type = 11; +				} else if (coex_dm->cur_ps_tdma == 16) { +					ps21a_tdma(btcoexist, NORMAL_EXEC, +						   true, 12); +					coex_dm->ps_tdma_du_adj_type = 12; +				} +				if (result == -1) { +					if (coex_dm->cur_ps_tdma == 1) { +						ps21a_tdma(btcoexist, +							   NORMAL_EXEC, +							   true, 3); +						coex_dm->ps_tdma_du_adj_type = 3; +					} else if (coex_dm->cur_ps_tdma == 2) { +						ps21a_tdma(btcoexist, +							   NORMAL_EXEC, +							   true, 3); +						coex_dm->ps_tdma_du_adj_type = 3; +					} else if (coex_dm->cur_ps_tdma == 3) { +						ps21a_tdma(btcoexist, +							   NORMAL_EXEC, +							   true, 4); +						coex_dm->ps_tdma_du_adj_type = 4; +					} else if (coex_dm->cur_ps_tdma == 9) { +						ps21a_tdma(btcoexist, NORMAL_EXEC, true, 11); +						coex_dm->ps_tdma_du_adj_type = 11; +					} else if (coex_dm->cur_ps_tdma == 10) { +						ps21a_tdma(btcoexist, NORMAL_EXEC, true, 11); +						coex_dm->ps_tdma_du_adj_type = 11; +					} else if (coex_dm->cur_ps_tdma == 11) { +						ps21a_tdma(btcoexist, NORMAL_EXEC, true, 12); +						coex_dm->ps_tdma_du_adj_type = 12; +					} +				} else if (result == 1) { +					if (coex_dm->cur_ps_tdma == 4) { +						ps21a_tdma(btcoexist, NORMAL_EXEC, true, 3); +						coex_dm->ps_tdma_du_adj_type = 3; +					} else if (coex_dm->cur_ps_tdma == 3) { +						ps21a_tdma(btcoexist, NORMAL_EXEC, true, 3); +						coex_dm->ps_tdma_du_adj_type = 3; +					} else if (coex_dm->cur_ps_tdma == 2) { +						ps21a_tdma(btcoexist, +							   NORMAL_EXEC, true, 3); +						coex_dm->ps_tdma_du_adj_type = 3; +					} else if (coex_dm->cur_ps_tdma == 12) { +						ps21a_tdma(btcoexist, NORMAL_EXEC, +							   true, 11); +						coex_dm->ps_tdma_du_adj_type = 11; +					} else if (coex_dm->cur_ps_tdma == 11) { +						ps21a_tdma(btcoexist, +							   NORMAL_EXEC, true, 11); +						coex_dm->ps_tdma_du_adj_type = 11; +					} else if (coex_dm->cur_ps_tdma == 10) { +						ps21a_tdma(btcoexist, +							   NORMAL_EXEC, true, 11); +						coex_dm->ps_tdma_du_adj_type = 11; +					} +				} +			} +		} +	} + +	/*  if current PsTdma not match with the recorded one +	 * (when scan, dhcp...), +	 *  then we have to adjust it back to the previous record one. */ +	if (coex_dm->cur_ps_tdma != coex_dm->ps_tdma_du_adj_type) { +		bool scan = false, link = false, roam = false; +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, +			  "[BTCoex], PsTdma type dismatch!!!, cur_ps_tdma =%d, recordPsTdma =%d\n", +			  coex_dm->cur_ps_tdma, coex_dm->ps_tdma_du_adj_type); + +		btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan); +		btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link); +		btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam); + +		if (!scan && !link && !roam) +			ps21a_tdma(btcoexist, NORMAL_EXEC, true, +				   coex_dm->ps_tdma_du_adj_type); +		else +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, +				  "[BTCoex], roaming/link/scan is under progress, will adjust next time!!!\n"); +	} + +	/* when tdma_duration_adjust() is called, fw dac swing is +	 * included in the function. */ +	halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0x6); +} + +/*  SCO only or SCO+PAN(HS) */ +static void halbtc8821a2ant_action_sco(struct btc_coexist *btcoexist) +{ +	u8 wifi_rssi_state, bt_rssi_state; +	u32 wifi_bw; + +	wifi_rssi_state = wifi21a_rssi_state(btcoexist, 0, 2, 15, 0); +	bt_rssi_state = halbtc8821a2ant_bt_rssi_state(2, 35, 0); + +	halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 4); + +	if (halbtc8821a2ant_need_to_dec_bt_pwr(btcoexist)) +		halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true); +	else +		halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + +	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + +	if (BTC_WIFI_BW_LEGACY == wifi_bw) /* for SCO quality at 11b/g mode */ +		halbtc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x5a5a5a5a, +					   0x5a5a5a5a, 0xffff, 0x3); +	else  /* for SCO quality & wifi performance balance at 11n mode */ +		halbtc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x5aea5aea, +					   0x5aea5aea, 0xffff, 0x3); + +	if (BTC_WIFI_BW_HT40 == wifi_bw) { +		/*  fw mechanism */ +		/* ps21a_tdma(btcoexist, NORMAL_EXEC, true, 5); */ + +		if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || +		    (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) +			ps21a_tdma(btcoexist, NORMAL_EXEC, +				   false, 0); /* for voice qual */ +		else +			ps21a_tdma(btcoexist, NORMAL_EXEC, +				   false, 0); /* for voice qual */ + +		/*  sw mechanism */ +		if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || +		    (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +			sw_mechanism1(btcoexist, true, true, false, false); +			sw_mechanism2(btcoexist, true, false, false, 0x18); +		} else { +			sw_mechanism1(btcoexist, true, true, false, false); +			sw_mechanism2(btcoexist, false, false, false, 0x18); +		} +	} else { +		/*  fw mechanism */ + +		if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || +		    (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) +			ps21a_tdma(btcoexist, NORMAL_EXEC, +				   false, 0); /* for voice qual */ +		else +			ps21a_tdma(btcoexist, NORMAL_EXEC, +				   false, 0); /* for voice qual */ + +		/*  sw mechanism */ +		if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || +		    (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +			sw_mechanism1(btcoexist, false, true, false, false); +			sw_mechanism2(btcoexist, true, false, false, 0x18); +		} else { +			sw_mechanism1(btcoexist, false, true, false, false); +			sw_mechanism2(btcoexist, false, false, false, 0x18); +		} +	} +} + +static void halbtc8821a2ant_action_hid(struct btc_coexist *btcoexist) +{ +	u8 wifi_rssi_state, bt_rssi_state; +	u32 wifi_bw; + +	wifi_rssi_state = wifi21a_rssi_state(btcoexist, 0, 2, 15, 0); +	bt_rssi_state = halbtc8821a2ant_bt_rssi_state(2, 35, 0); + +	halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + +	if (halbtc8821a2ant_need_to_dec_bt_pwr(btcoexist)) +		halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true); +	else +		halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + +	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + +	if (BTC_WIFI_BW_LEGACY == wifi_bw) /* for HID at 11b/g mode */ +		halbtc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff, +					   0x5a5a5a5a, 0xffff, 0x3); +	else  /* for HID quality & wifi performance balance at 11n mode */ +		halbtc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff, +					   0x5aea5aea, 0xffff, 0x3); + +	if (BTC_WIFI_BW_HT40 == wifi_bw) { +		/*  fw mechanism */ +		if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || +		    (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) +			ps21a_tdma(btcoexist, NORMAL_EXEC, true, 9); +		else +			ps21a_tdma(btcoexist, NORMAL_EXEC, true, 13); +		/*  sw mechanism */ +		if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || +		    (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +			sw_mechanism1(btcoexist, true, true, false, false); +			sw_mechanism2(btcoexist, true, false, false, 0x18); +		} else { +			sw_mechanism1(btcoexist, true, true, false, false); +			sw_mechanism2(btcoexist, false, false, false, 0x18); +		} +	} else { +		/*  fw mechanism */ +		if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || +		    (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) +			ps21a_tdma(btcoexist, NORMAL_EXEC, true, 9); +		else +			ps21a_tdma(btcoexist, NORMAL_EXEC, true, 13); + +		/*  sw mechanism */ +		if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || +		    (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +			sw_mechanism1(btcoexist, false, true, false, false); +			sw_mechanism2(btcoexist, true, false, false, 0x18); +		} else { +			sw_mechanism1(btcoexist, false, true, false, false); +			sw_mechanism2(btcoexist, false, false, false, 0x18); +		} +	} +} + +/* A2DP only / PAN(EDR) only/ A2DP+PAN(HS) */ +static void halbtc8821a2ant_action_a2dp(struct btc_coexist *btcoexist) +{ +	u8 wifi_rssi_state, bt_rssi_state; +	u32 wifi_bw; + +	wifi_rssi_state = wifi21a_rssi_state(btcoexist, 0, 2, 15, 0); +	bt_rssi_state = halbtc8821a2ant_bt_rssi_state(2, 35, 0); + +	/* fw dac swing is called in tdma_duration_adjust() */ +	/* halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); */ + +	if (halbtc8821a2ant_need_to_dec_bt_pwr(btcoexist)) +		halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true); +	else +		halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + +	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + +	if (BTC_WIFI_BW_HT40 == wifi_bw) { +		/*  fw mechanism */ +		if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || +		    (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) +			tdma_duration_adjust(btcoexist, false, false, 1); +		else +			tdma_duration_adjust(btcoexist, false, true, 1); + +		/*  sw mechanism */ +		if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || +		    (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +			sw_mechanism1(btcoexist, true, false, false, false); +			sw_mechanism2(btcoexist, true, false, false, 0x18); +		} else { +			sw_mechanism1(btcoexist, true, false, false, false); +			sw_mechanism2(btcoexist, false, false, false, 0x18); +		} +	} else { +		/*  fw mechanism */ +		if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || +		    (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) +			tdma_duration_adjust(btcoexist, false, false, 1); +		else +			tdma_duration_adjust(btcoexist, false, true, 1); + +		/*  sw mechanism */ +		if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || +		    (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +			sw_mechanism1(btcoexist, false, false, false, false); +			sw_mechanism2(btcoexist, true, false, false, 0x18); +		} else { +			sw_mechanism1(btcoexist, false, false, false, false); +			sw_mechanism2(btcoexist, false, false, false, 0x18); +		} +	} +} + +static void halbtc8821a2ant_action_a2dp_pan_hs(struct btc_coexist *btcoexist) +{ +	u8 wifi_rssi_state, bt_rssi_state, bt_info_ext; +	u32 wifi_bw; + +	bt_info_ext = coex_sta->bt_info_ext; +	wifi_rssi_state = wifi21a_rssi_state(btcoexist, 0, 2, 15, 0); +	bt_rssi_state = halbtc8821a2ant_bt_rssi_state(2, 35, 0); + +	/* fw dac swing is called in tdma_duration_adjust() */ +	/* halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); */ + +	if (halbtc8821a2ant_need_to_dec_bt_pwr(btcoexist)) +		halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true); +	else +		halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + +	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + +	if (BTC_WIFI_BW_HT40 == wifi_bw) { +		/*  fw mechanism */ +		if (bt_info_ext & BIT(0))	/* a2dp basic rate */ +			tdma_duration_adjust(btcoexist, false, true, 2); +		else				/* a2dp edr rate */ +			tdma_duration_adjust(btcoexist, false, true, 1); + +		/*  sw mechanism */ +		if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || +		    (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +			sw_mechanism1(btcoexist, true, false, false, false); +			sw_mechanism2(btcoexist, true, false, false, 0x18); +		} else { +			sw_mechanism1(btcoexist, true, false, false, false); +			sw_mechanism2(btcoexist, false, false, false, 0x18); +		} +	} else { +		/*  fw mechanism */ +		if (bt_info_ext & BIT(0))	/* a2dp basic rate */ +			tdma_duration_adjust(btcoexist, false, true, 2); +		else				/* a2dp edr rate */ +			tdma_duration_adjust(btcoexist, false, true, 1); + +		/*  sw mechanism */ +		if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || +		    (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +			sw_mechanism1(btcoexist, false, false, false, false); +			sw_mechanism2(btcoexist, true, false, false, 0x18); +		} else { +			sw_mechanism1(btcoexist, false, false, false, false); +			sw_mechanism2(btcoexist, false, false, false, 0x18); +		} +	} +} + +static void halbtc8821a2ant_action_pan_edr(struct btc_coexist *btcoexist) +{ +	u8 wifi_rssi_state, bt_rssi_state; +	u32 wifi_bw; + +	wifi_rssi_state = wifi21a_rssi_state(btcoexist, 0, 2, 15, 0); +	bt_rssi_state = halbtc8821a2ant_bt_rssi_state(2, 35, 0); + +	halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + +	if (halbtc8821a2ant_need_to_dec_bt_pwr(btcoexist)) +		halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true); +	else +		halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + +	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + +	if (BTC_WIFI_BW_LEGACY == wifi_bw) /* for HID at 11b/g mode */ +		halbtc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff, +					   0x5aff5aff, 0xffff, 0x3); +	else  /* for HID quality & wifi performance balance at 11n mode */ +		halbtc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff, +					   0x5aff5aff, 0xffff, 0x3); + +		if (BTC_WIFI_BW_HT40 == wifi_bw) { +			/*  fw mechanism */ +		if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || +		    (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) +			ps21a_tdma(btcoexist, NORMAL_EXEC, true, 1); +		else +			ps21a_tdma(btcoexist, NORMAL_EXEC, true, 5); + +		/*  sw mechanism */ +		if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || +		    (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +			sw_mechanism1(btcoexist, true, false, false, false); +			sw_mechanism2(btcoexist, true, false, false, 0x18); +		} else { +			sw_mechanism1(btcoexist, true, false, false, false); +			sw_mechanism2(btcoexist, false, false, false, 0x18); +		} +	} else { +		/*  fw mechanism */ +		if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || +		    (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) +			ps21a_tdma(btcoexist, NORMAL_EXEC, true, 1); +		else +			ps21a_tdma(btcoexist, NORMAL_EXEC, true, 5); + +		/*  sw mechanism */ +		if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || +		    (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +			sw_mechanism1(btcoexist, false, false, false, false); +			sw_mechanism2(btcoexist, true, false, false, 0x18); +		} else { +			sw_mechanism1(btcoexist, false, false, false, false); +			sw_mechanism2(btcoexist, false, false, false, 0x18); +		} +	} +} + +/* PAN(HS) only */ +static void halbtc8821a2ant_action_pan_hs(struct btc_coexist *btcoexist) +{ +	u8 wifi_rssi_state, bt_rssi_state; +	u32 wifi_bw; + +	wifi_rssi_state = wifi21a_rssi_state(btcoexist, 0, 2, 15, 0); +	bt_rssi_state = halbtc8821a2ant_bt_rssi_state(2, 35, 0); + +	halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + +	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + +	if (BTC_WIFI_BW_HT40 == wifi_bw) { +		/*  fw mechanism */ +		if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || +		    (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) +			halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, +						   true); +		else +			halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, +						   false); +		ps21a_tdma(btcoexist, NORMAL_EXEC, false, 1); + +		/*  sw mechanism */ +		if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || +		    (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +			sw_mechanism1(btcoexist, true, false, false, false); +			sw_mechanism2(btcoexist, true, false, false, 0x18); +		} else { +			sw_mechanism1(btcoexist, true, false, false, false); +			sw_mechanism2(btcoexist, false, false, false, 0x18); +		} +	} else { +		/*  fw mechanism */ +		if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || +		    (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) +			halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, +						   true); +		else +			halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, +						   false); + +		if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || +		    (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) +			ps21a_tdma(btcoexist, NORMAL_EXEC, false, 1); +		else +			ps21a_tdma(btcoexist, NORMAL_EXEC, false, 1); + +		/*  sw mechanism */ +		if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || +		    (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +			sw_mechanism1(btcoexist, false, false, false, false); +			sw_mechanism2(btcoexist, true, false, false, 0x18); +		} else { +			sw_mechanism1(btcoexist, false, false, false, false); +			sw_mechanism2(btcoexist, false, false, false, 0x18); +		} +	} +} + +/* PAN(EDR)+A2DP */ +static void halbtc8821a2ant_action_pan_edr_a2dp(struct btc_coexist *btcoexist) +{ +	u8 wifi_rssi_state, bt_rssi_state, bt_info_ext; +	u32 wifi_bw; + +	bt_info_ext = coex_sta->bt_info_ext; +	wifi_rssi_state = wifi21a_rssi_state(btcoexist, 0, 2, 15, 0); +	bt_rssi_state = halbtc8821a2ant_bt_rssi_state(2, 35, 0); + +	halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + +	if (halbtc8821a2ant_need_to_dec_bt_pwr(btcoexist)) +		halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true); +	else +		halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + +	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + +	if (BTC_WIFI_BW_LEGACY == wifi_bw) /* for HID at 11b/g mode */ +		halbtc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff, +					   0x5afa5afa, 0xffff, 0x3); +	else  /* for HID quality & wifi performance balance at 11n mode */ +		halbtc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff, +					   0x5afa5afa, 0xffff, 0x3); + +	if (BTC_WIFI_BW_HT40 == wifi_bw) { +		/*  fw mechanism */ +		if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || +		    (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +			if (bt_info_ext & BIT(0))	/* a2dp basic rate */ +				tdma_duration_adjust(btcoexist, false, +						     false, 3); +			else				/* a2dp edr rate */ +				tdma_duration_adjust(btcoexist, false, +						     false, 3); +		} else { +			if (bt_info_ext & BIT(0))	/* a2dp basic rate */ +				tdma_duration_adjust(btcoexist, false, true, 3); +			else				/* a2dp edr rate */ +				tdma_duration_adjust(btcoexist, false, true, 3); +		} + +		/*  sw mechanism */ +		if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || +		    (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +			sw_mechanism1(btcoexist, true, false, false, false); +			sw_mechanism2(btcoexist, true, false, false, 0x18); +		} else { +			sw_mechanism1(btcoexist, true, false, false, false); +			sw_mechanism2(btcoexist, false, false, false, 0x18); +		}; +	} else { +		/*  fw mechanism */ +		if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || +		    (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +			if (bt_info_ext & BIT(0))	/* a2dp basic rate */ +				tdma_duration_adjust(btcoexist, false, +						     false, 3); +			else				/* a2dp edr rate */ +				tdma_duration_adjust(btcoexist, false, +						     false, 3); +		} else { +			if (bt_info_ext & BIT(0))	/* a2dp basic rate */ +				tdma_duration_adjust(btcoexist, false, true, 3); +			else				/* a2dp edr rate */ +				tdma_duration_adjust(btcoexist, false, true, 3); +		} + +		/*  sw mechanism */ +		if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || +		    (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +			sw_mechanism1(btcoexist, false, false, false, false); +			sw_mechanism2(btcoexist, true, false, false, 0x18); +		} else { +			sw_mechanism1(btcoexist, false, false, false, false); +			sw_mechanism2(btcoexist, false, false, false, 0x18); +		} +	} +} + +static void halbtc8821a2ant_action_pan_edr_hid(struct btc_coexist *btcoexist) +{ +	u8 wifi_rssi_state, bt_rssi_state; +	u32 wifi_bw; + +	wifi_rssi_state = wifi21a_rssi_state(btcoexist, 0, 2, 15, 0); +	bt_rssi_state = halbtc8821a2ant_bt_rssi_state(2, 35, 0); + +	halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + +	if (halbtc8821a2ant_need_to_dec_bt_pwr(btcoexist)) +		halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true); +	else +		halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + +	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + +	if (BTC_WIFI_BW_LEGACY == wifi_bw) /* for HID at 11b/g mode */ +		halbtc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff, +					   0x5a5f5a5f, 0xffff, 0x3); +	else  /* for HID quality & wifi performance balance at 11n mode */ +		halbtc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff, +					   0x5a5f5a5f, 0xffff, 0x3); + +	if (BTC_WIFI_BW_HT40 == wifi_bw) { +		halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 3); +		/*  fw mechanism */ +		if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || +		    (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) +			ps21a_tdma(btcoexist, NORMAL_EXEC, true, 10); +		else +			ps21a_tdma(btcoexist, NORMAL_EXEC, true, 14); + +		/*  sw mechanism */ +		if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || +		    (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +			sw_mechanism1(btcoexist, true, true, false, false); +			sw_mechanism2(btcoexist, true, false, false, 0x18); +		} else { +			sw_mechanism1(btcoexist, true, true, false, false); +			sw_mechanism2(btcoexist, false, false, false, 0x18); +		} +	} else { +		halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); +		/*  fw mechanism */ +		if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || +		    (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) +			ps21a_tdma(btcoexist, NORMAL_EXEC, true, 10); +		else +			ps21a_tdma(btcoexist, NORMAL_EXEC, true, 14); + +		/*  sw mechanism */ +		if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || +		    (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +			sw_mechanism1(btcoexist, false, true, false, false); +			sw_mechanism2(btcoexist, true, false, false, 0x18); +		} else { +			sw_mechanism1(btcoexist, false, true, false, false); +			sw_mechanism2(btcoexist, false, false, false, 0x18); +		} +	} +} + +/*  HID+A2DP+PAN(EDR) */ +static void action_hid_a2dp_pan_edr(struct btc_coexist *btcoexist) +{ +	u8 wifi_rssi_state, bt_rssi_state, bt_info_ext; +	u32 wifi_bw; + +	bt_info_ext = coex_sta->bt_info_ext; +	wifi_rssi_state = wifi21a_rssi_state(btcoexist, 0, 2, 15, 0); +	bt_rssi_state = halbtc8821a2ant_bt_rssi_state(2, 35, 0); + +	halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + +	if (halbtc8821a2ant_need_to_dec_bt_pwr(btcoexist)) +		halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true); +	else +		halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + +	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + +	if (BTC_WIFI_BW_LEGACY == wifi_bw) /* for HID at 11b/g mode */ +		halbtc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff, +					   0x5a5a5a5a, 0xffff, 0x3); +	else  /* for HID quality & wifi performance balance at 11n mode */ +		halbtc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff, +					   0x5a5a5a5a, 0xffff, 0x3); + +	if (BTC_WIFI_BW_HT40 == wifi_bw) { +		/*  fw mechanism */ +		if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || +		    (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +			if (bt_info_ext & BIT(0)) {	/* a2dp basic rate */ +				tdma_duration_adjust(btcoexist, true, true, 3); +			} else { +				/* a2dp edr rate */ +				tdma_duration_adjust(btcoexist, true, true, 3); +			} +		} else { +			if (bt_info_ext & BIT(0))	/* a2dp basic rate */ +				tdma_duration_adjust(btcoexist, true, true, 3); +			else				/* a2dp edr rate */ +				tdma_duration_adjust(btcoexist, true, true, 3); +		} + +		/*  sw mechanism */ +		if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || +		    (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +			sw_mechanism1(btcoexist, true, true, false, false); +			sw_mechanism2(btcoexist, true, false, false, 0x18); +		} else { +			sw_mechanism1(btcoexist, true, true, false, false); +			sw_mechanism2(btcoexist, false, false, false, 0x18); +		} +	} else { +		/*  fw mechanism */ +		if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || +		    (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +			if (bt_info_ext & BIT(0))	/* a2dp basic rate */ +				tdma_duration_adjust(btcoexist, true, false, 3); +			else				/* a2dp edr rate */ +				tdma_duration_adjust(btcoexist, true, false, 3); +		} else { +			if (bt_info_ext & BIT(0)) { +				/* a2dp basic rate */ +				tdma_duration_adjust(btcoexist, true, true, 3); +			} else				/* a2dp edr rate */ { +				tdma_duration_adjust(btcoexist, true, true, 3); +			} +		} + +		/*  sw mechanism */ +		if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || +		    (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +			sw_mechanism1(btcoexist, false, true, false, false); +			sw_mechanism2(btcoexist, true, false, false, 0x18); +		} else { +			sw_mechanism1(btcoexist, false, true, false, false); +			sw_mechanism2(btcoexist, false, false, false, 0x18); +		} +	} +} + +static void halbtc8821a2ant_action_hid_a2dp(struct btc_coexist *btcoexist) +{ +	u8 wifi_rssi_state, bt_rssi_state, bt_info_ext; +	u32 wifi_bw; + +	bt_info_ext = coex_sta->bt_info_ext; +	wifi_rssi_state = wifi21a_rssi_state(btcoexist, 0, 2, 15, 0); +	bt_rssi_state = halbtc8821a2ant_bt_rssi_state(2, 35, 0); + +	if (halbtc8821a2ant_need_to_dec_bt_pwr(btcoexist)) +		halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true); +	else +		halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + +	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + +	if (BTC_WIFI_BW_LEGACY == wifi_bw) /* for HID at 11b/g mode */ +		halbtc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff, +					   0x5f5b5f5b, 0xffffff, 0x3); +	else  /* for HID quality & wifi performance balance at 11n mode */ +		halbtc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff, +					   0x5f5b5f5b, 0xffffff, 0x3); + +	if (BTC_WIFI_BW_HT40 == wifi_bw) { +		/*  fw mechanism */ +		if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || +		    (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +			if (bt_info_ext & BIT(0))	/* a2dp basic rate */ +				tdma_duration_adjust(btcoexist, true, true, 2); +			else				/* a2dp edr rate */ +				tdma_duration_adjust(btcoexist, true, true, 2); +		} else { +			if (bt_info_ext & BIT(0))	/* a2dp basic rate */ +				tdma_duration_adjust(btcoexist, true, true, 2); +			else				/* a2dp edr rate */ +				tdma_duration_adjust(btcoexist, true, true, 2); +		} + +		/*  sw mechanism */ +		if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || +		    (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +			sw_mechanism1(btcoexist, true, true, false, false); +			sw_mechanism2(btcoexist, true, false, false, 0x18); +		} else { +			sw_mechanism1(btcoexist, true, true, false, false); +			sw_mechanism2(btcoexist, false, false, false, 0x18); +		} +	} else { +		/*  fw mechanism */ +		if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || +		    (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +			if (bt_info_ext & BIT(0))	/* a2dp basic rate */ +				tdma_duration_adjust(btcoexist, true, true, 2); +			else				/* a2dp edr rate */ +				tdma_duration_adjust(btcoexist, true, true, 2); +		} else { +			if (bt_info_ext & BIT(0))	/* a2dp basic rate */ +				tdma_duration_adjust(btcoexist, true, true, 2); +			else				/* a2dp edr rate */ +				tdma_duration_adjust(btcoexist, true, true, 2); +		} + +		/*  sw mechanism */ +		if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || +		    (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { +			sw_mechanism1(btcoexist, false, true, false, false); +			sw_mechanism2(btcoexist, true, false, false, 0x18); +		} else { +			sw_mechanism1(btcoexist, false, true, false, false); +			sw_mechanism2(btcoexist, false, false, false, 0x18); +		} +	} +} + +static void halbtc8821a2ant_run_coexist_mechanism(struct btc_coexist *btcoexist) +{ +	bool wifi_under_5g = false; +	u8 algorithm = 0; + +	if (btcoexist->manual_control) { +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +			  "[BTCoex], Manual control!!!\n"); +		return; +	} + +	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); + +	if (wifi_under_5g) { +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +			  "[BTCoex], RunCoexistMechanism(), run 5G coex setting!!<===\n"); +		halbtc8821a2ant_coex_under_5g(btcoexist); +		return; +	} + +	algorithm = halbtc8821a2ant_action_algorithm(btcoexist); +	if (coex_sta->c2h_bt_inquiry_page && +	    (BT_8821A_2ANT_COEX_ALGO_PANHS != algorithm)) { +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +			  "[BTCoex], BT is under inquiry/page scan !!\n"); +		halbtc8821a2ant_bt_inquiry_page(btcoexist); +		return; +	} + +	coex_dm->cur_algorithm = algorithm; +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +		  "[BTCoex], Algorithm = %d\n", coex_dm->cur_algorithm); + +	if (halbtc8821a2ant_is_common_action(btcoexist)) { +		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +			  "[BTCoex], Action 2-Ant common.\n"); +		coex_dm->reset_tdma_adjust = true; +	} else { +		if (coex_dm->cur_algorithm != coex_dm->pre_algorithm) { +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +				  "[BTCoex], pre_algorithm =%d, cur_algorithm =%d\n", +				  coex_dm->pre_algorithm, +				  coex_dm->cur_algorithm); +			coex_dm->reset_tdma_adjust = true; +		} +		switch (coex_dm->cur_algorithm) { +		case BT_8821A_2ANT_COEX_ALGO_SCO: +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +				  "[BTCoex], Action 2-Ant, algorithm = SCO.\n"); +			halbtc8821a2ant_action_sco(btcoexist); +			break; +		case BT_8821A_2ANT_COEX_ALGO_HID: +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +				  "[BTCoex], Action 2-Ant, algorithm = HID.\n"); +			halbtc8821a2ant_action_hid(btcoexist); +			break; +		case BT_8821A_2ANT_COEX_ALGO_A2DP: +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +				  "[BTCoex], Action 2-Ant, algorithm = A2DP.\n"); +			halbtc8821a2ant_action_a2dp(btcoexist); +			break; +		case BT_8821A_2ANT_COEX_ALGO_A2DP_PANHS: +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +				  "[BTCoex], Action 2-Ant, algorithm = A2DP+PAN(HS).\n"); +			halbtc8821a2ant_action_a2dp_pan_hs(btcoexist); +			break; +		case BT_8821A_2ANT_COEX_ALGO_PANEDR: +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +				  "[BTCoex], Action 2-Ant, algorithm = PAN(EDR).\n"); +			halbtc8821a2ant_action_pan_edr(btcoexist); +			break; +		case BT_8821A_2ANT_COEX_ALGO_PANHS: +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +				  "[BTCoex], Action 2-Ant, algorithm = HS mode.\n"); +			halbtc8821a2ant_action_pan_hs(btcoexist); +			break; +		case BT_8821A_2ANT_COEX_ALGO_PANEDR_A2DP: +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +				  "[BTCoex], Action 2-Ant, algorithm = PAN+A2DP.\n"); +			halbtc8821a2ant_action_pan_edr_a2dp(btcoexist); +			break; +		case BT_8821A_2ANT_COEX_ALGO_PANEDR_HID: +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +				  "[BTCoex], Action 2-Ant, algorithm = PAN(EDR)+HID.\n"); +			halbtc8821a2ant_action_pan_edr_hid(btcoexist); +			break; +		case BT_8821A_2ANT_COEX_ALGO_HID_A2DP_PANEDR: +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +				  "[BTCoex], Action 2-Ant, algorithm = HID+A2DP+PAN.\n"); +			action_hid_a2dp_pan_edr(btcoexist); +			break; +		case BT_8821A_2ANT_COEX_ALGO_HID_A2DP: +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +				  "[BTCoex], Action 2-Ant, algorithm = HID+A2DP.\n"); +			halbtc8821a2ant_action_hid_a2dp(btcoexist); +			break; +		default: +			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +				  "[BTCoex], Action 2-Ant, algorithm = coexist All Off!!\n"); +			halbtc8821a2ant_coex_all_off(btcoexist); +			break; +		} +		coex_dm->pre_algorithm = coex_dm->cur_algorithm; +	} +} + +/*  work around function start with wa_halbtc8821a2ant_ */ +/*  extern function start with EXhalbtc8821a2ant_ */ +void ex_halbtc8821a2ant_init_hwconfig(struct btc_coexist *btcoexist) +{ +	u8 u1tmp = 0; + +	BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, +		  "[BTCoex], 2Ant Init HW Config!!\n"); + +	/*  backup rf 0x1e value */ +	coex_dm->bt_rf0x1e_backup = +		btcoexist->btc_get_rf_reg(btcoexist, BTC_RF_A, 0x1e, 0xfffff); + +	/*  0x790[5:0] = 0x5 */ +	u1tmp = btcoexist->btc_read_1byte(btcoexist, 0x790); +	u1tmp &= 0xc0; +	u1tmp |= 0x5; +	btcoexist->btc_write_1byte(btcoexist, 0x790, u1tmp); + +	/* Antenna config */ +	halbtc8821a2ant_set_ant_path(btcoexist, BTC_ANT_WIFI_AT_MAIN, +				     true, false); + +	/*  PTA parameter */ +	halbtc8821a2ant_coex_table(btcoexist, FORCE_EXEC, +				   0x55555555, 0x55555555, +				   0xffff, 0x3); + +	/*  Enable counter statistics */ +	/* 0x76e[3] = 1, WLAN_Act control by PTA */ +	btcoexist->btc_write_1byte(btcoexist, 0x76e, 0xc); +	btcoexist->btc_write_1byte(btcoexist, 0x778, 0x3); +	btcoexist->btc_write_1byte_bitmask(btcoexist, 0x40, 0x20, 0x1); +} + +void ex_halbtc8821a2ant_init_coex_dm(struct btc_coexist *btcoexist) +{ +	BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, +		  "[BTCoex], Coex Mechanism Init!!\n"); + +	halbtc8821a2ant_init_coex_dm(btcoexist); +} + +void ex_halbtc8821a2ant_display_coex_info(struct btc_coexist *btcoexist) +{ +	struct btc_board_info *board_info = &btcoexist->board_info; +	struct btc_stack_info *stack_info = &btcoexist->stack_info; +	u8 *cli_buf = btcoexist->cli_buf; +	u8 u1tmp[4], i, bt_info_ext, ps_tdma_case = 0; +	u32 u4tmp[4]; +	bool roam = false, scan = false, link = false, wifi_under_5g = false; +	bool bt_hs_on = false, wifi_busy = false; +	long wifi_rssi = 0, bt_hs_rssi = 0; +	u32 wifi_bw, wifi_traffic_dir; +	u8 wifi_dot_11_chnl, wifi_hs_chnl; +	u32 fw_ver = 0, bt_patch_ver = 0; + +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, +		   "\n ============[BT Coexist info] ============"); +	CL_PRINTF(cli_buf); + +	if (!board_info->bt_exist) { +		CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\n BT not exists !!!"); +		CL_PRINTF(cli_buf); +		return; +	} + +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\n %-35s = %d/ %d ", +		   "Ant PG number/ Ant mechanism: ", +		   board_info->pg_ant_num, board_info->btdm_ant_num); +	CL_PRINTF(cli_buf); + +	if (btcoexist->manual_control) { +		CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\n %-35s", +			   "[Action Manual control]!!"); +		CL_PRINTF(cli_buf); +	} + +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\n %-35s = %s / %d", +		   "BT stack/ hci ext ver", +		   ((stack_info->profile_notified) ? "Yes" : "No"), +		   stack_info->hci_version); +	CL_PRINTF(cli_buf); + +	btcoexist->btc_get(btcoexist, BTC_GET_U4_BT_PATCH_VER, &bt_patch_ver); +	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver); +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\n %-35s = %d_%d/ 0x%x/ 0x%x(%d)", +		   "CoexVer/ FwVer/ PatchVer", +		   glcoex_ver_date_8821a_2ant, glcoex_ver_8821a_2ant, +		   fw_ver, bt_patch_ver, bt_patch_ver); +	CL_PRINTF(cli_buf); + +	btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); +	btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_DOT11_CHNL, +			   &wifi_dot_11_chnl); +	btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_HS_CHNL, &wifi_hs_chnl); +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\n %-35s = %d / %d(%d)", +		   "Dot11 channel / HsMode(HsChnl)", +		   wifi_dot_11_chnl, bt_hs_on, wifi_hs_chnl); +	CL_PRINTF(cli_buf); + +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, +		   "\n %-35s = %02x %02x %02x ", "H2C Wifi inform bt chnl Info", +		   coex_dm->wifi_chnl_info[0], coex_dm->wifi_chnl_info[1], +		   coex_dm->wifi_chnl_info[2]); +	CL_PRINTF(cli_buf); + +	btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifi_rssi); +	btcoexist->btc_get(btcoexist, BTC_GET_S4_HS_RSSI, &bt_hs_rssi); +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, +		   "\n %-35s = %ld/ %ld", "Wifi rssi/ HS rssi", +		   wifi_rssi, bt_hs_rssi); +	CL_PRINTF(cli_buf); + +	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan); +	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link); +	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam); +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\n %-35s = %d/ %d/ %d ", +		   "Wifi link/ roam/ scan", +		   link, roam, scan); +	CL_PRINTF(cli_buf); + +	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); +	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); +	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); +	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_TRAFFIC_DIRECTION, +			   &wifi_traffic_dir); +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\n %-35s = %s / %s/ %s ", +		   "Wifi status", +		   (wifi_under_5g ? "5G" : "2.4G"), +		   ((BTC_WIFI_BW_LEGACY == wifi_bw) ? "Legacy" : +		    (((BTC_WIFI_BW_HT40 == wifi_bw) ? "HT40" : "HT20"))), +		   ((!wifi_busy) ? "idle" : +		    ((BTC_WIFI_TRAFFIC_TX == wifi_traffic_dir) ? "uplink" : +		    "downlink"))); +	CL_PRINTF(cli_buf); + +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\n %-35s = [%s/ %d/ %d] ", +		   "BT [status/ rssi/ retryCnt]", +		   ((coex_sta->c2h_bt_inquiry_page) ? ("inquiry/page scan") : +		   ((BT_8821A_2ANT_BT_STATUS_IDLE == coex_dm->bt_status) ? +		    "idle" : ((BT_8821A_2ANT_BT_STATUS_CONNECTED_IDLE == +		    coex_dm->bt_status) ? "connected-idle" : "busy"))), +		coex_sta->bt_rssi, coex_sta->bt_retry_cnt); +	CL_PRINTF(cli_buf); + +	if (stack_info->profile_notified) { +		CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, +			   "\n %-35s = %d / %d / %d / %d", "SCO/HID/PAN/A2DP", +			   stack_info->sco_exist, stack_info->hid_exist, +			   stack_info->pan_exist, stack_info->a2dp_exist); +		CL_PRINTF(cli_buf); + +		btcoexist->btc_disp_dbg_msg(btcoexist, +					    BTC_DBG_DISP_BT_LINK_INFO); +	} + +	bt_info_ext = coex_sta->bt_info_ext; +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\n %-35s = %s", +		   "BT Info A2DP rate", +		   (bt_info_ext & BIT(0)) ? "Basic rate" : "EDR rate"); +	CL_PRINTF(cli_buf); + +	for (i = 0; i < BT_INFO_SRC_8821A_2ANT_MAX; i++) { +		if (coex_sta->bt_info_c2h_cnt[i]) { +			CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, +				   "\n %-35s = %02x %02x %02x %02x %02x %02x %02x(%d)", +				   glbt_info_src_8821a_2ant[i], +				   coex_sta->bt_info_c2h[i][0], +				   coex_sta->bt_info_c2h[i][1], +				   coex_sta->bt_info_c2h[i][2], +				   coex_sta->bt_info_c2h[i][3], +				   coex_sta->bt_info_c2h[i][4], +				   coex_sta->bt_info_c2h[i][5], +				   coex_sta->bt_info_c2h[i][6], +				   coex_sta->bt_info_c2h_cnt[i]); +			CL_PRINTF(cli_buf); +		} +	} + +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\n %-35s = %s/%s", +		   "PS state, IPS/LPS", +		   ((coex_sta->under_ips ? "IPS ON" : "IPS OFF")), +		   ((coex_sta->under_lps ? "LPS ON" : "LPS OFF"))); +	CL_PRINTF(cli_buf); +	btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_FW_PWR_MODE_CMD); + +	/*  Sw mechanism	 */ +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\n %-35s", +		   "============[Sw mechanism] ============"); +	CL_PRINTF(cli_buf); +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\n %-35s = %d/ %d/ %d/ %d ", +		   "SM1[ShRf/ LpRA/ LimDig/ btLna]", +		   coex_dm->cur_rf_rx_lpf_shrink, coex_dm->cur_low_penalty_ra, +		   coex_dm->limited_dig, coex_dm->cur_bt_lna_constrain); +	CL_PRINTF(cli_buf); +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\n %-35s = %d/ %d/ %d(0x%x) ", +		   "SM2[AgcT/ AdcB/ SwDacSwing(lvl)]", +		   coex_dm->cur_agc_table_en, coex_dm->cur_adc_back_off, +		   coex_dm->cur_dac_swing_on, coex_dm->cur_dac_swing_lvl); +	CL_PRINTF(cli_buf); + +	/*  Fw mechanism		 */ +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\n %-35s", +		   "============[Fw mechanism] ============"); +	CL_PRINTF(cli_buf); + +	if (!btcoexist->manual_control) { +		ps_tdma_case = coex_dm->cur_ps_tdma; +		CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, +			   "\n %-35s = %02x %02x %02x %02x %02x case-%d", +			   "PS TDMA", +			   coex_dm->ps_tdma_para[0], coex_dm->ps_tdma_para[1], +			   coex_dm->ps_tdma_para[2], coex_dm->ps_tdma_para[3], +			   coex_dm->ps_tdma_para[4], ps_tdma_case); +		CL_PRINTF(cli_buf); + +		CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\n %-35s = %d/ %d ", +			   "DecBtPwr/ IgnWlanAct", +			   coex_dm->cur_dec_bt_pwr, +			   coex_dm->cur_ignore_wlan_act); +		CL_PRINTF(cli_buf); +	} + +	/*  Hw setting		 */ +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, +		   "\n %-35s", "============[Hw setting] ============"); +	CL_PRINTF(cli_buf); + +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\n %-35s = 0x%x", +		   "RF-A, 0x1e initVal", +		   coex_dm->bt_rf0x1e_backup); +	CL_PRINTF(cli_buf); + +	u1tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x778); +	u1tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0x6cc); +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\n %-35s = 0x%x/ 0x%x ", +		   "0x778 (W_Act)/ 0x6cc (CoTab Sel)", +		   u1tmp[0], u1tmp[1]); +	CL_PRINTF(cli_buf); + +	u1tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x8db); +	u1tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0xc5b); +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\n %-35s = 0x%x/ 0x%x", +		   "0x8db(ADC)/0xc5b[29:25](DAC)", +		   ((u1tmp[0]&0x60)>>5), ((u1tmp[1]&0x3e)>>1)); +	CL_PRINTF(cli_buf); + +	u4tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xcb4); +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\n %-35s = 0x%x/ 0x%x", +		   "0xcb4[7:0](ctrl)/ 0xcb4[29:28](val)", +		   u4tmp[0]&0xff, ((u4tmp[0]&0x30000000)>>28)); +	CL_PRINTF(cli_buf); + +	u1tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x40); +	u4tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x4c); +	u4tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x974); +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\n %-35s = 0x%x/ 0x%x/ 0x%x", +		   "0x40/ 0x4c[24:23]/ 0x974", +		   u1tmp[0], ((u4tmp[0]&0x01800000)>>23), u4tmp[1]); +	CL_PRINTF(cli_buf); + +	u4tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x550); +	u1tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x522); +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\n %-35s = 0x%x/ 0x%x", +		   "0x550(bcn ctrl)/0x522", +		   u4tmp[0], u1tmp[0]); +	CL_PRINTF(cli_buf); + +	u4tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xc50); +	u1tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0xa0a); +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\n %-35s = 0x%x/ 0x%x", +		   "0xc50(DIG)/0xa0a(CCK-TH)", +		   u4tmp[0], u1tmp[0]); +	CL_PRINTF(cli_buf); + +	u4tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xf48); +	u1tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0xa5b); +	u1tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0xa5c); +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, +		   "\n %-35s = 0x%x/ 0x%x", "OFDM-FA/ CCK-FA", +		   u4tmp[0], (u1tmp[0]<<8) + u1tmp[1]); +	CL_PRINTF(cli_buf); + +	u4tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x6c0); +	u4tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x6c4); +	u4tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0x6c8); +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\n %-35s = 0x%x/ 0x%x/ 0x%x", +		   "0x6c0/0x6c4/0x6c8", +		   u4tmp[0], u4tmp[1], u4tmp[2]); +	CL_PRINTF(cli_buf); + +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\n %-35s = %d/ %d", +		   "0x770 (hi-pri Rx/Tx)", +		   coex_sta->high_priority_rx, coex_sta->high_priority_tx); +	CL_PRINTF(cli_buf); +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\n %-35s = %d/ %d", +		   "0x774(low-pri Rx/Tx)", +		   coex_sta->low_priority_rx, coex_sta->low_priority_tx); +	CL_PRINTF(cli_buf); + +	/*  Tx mgnt queue hang or not, 0x41b should = 0xf, ex: 0xd ==>hang */ +	u1tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x41b); +	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\n %-35s = 0x%x", +		   "0x41b (mgntQ hang chk == 0xf)", +		   u1tmp[0]); +	CL_PRINTF(cli_buf); + +	btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_COEX_STATISTICS); +} + +void ex_halbtc8821a2ant_ips_notify(struct btc_coexist *btcoexist, u8 type) +{ +	if (BTC_IPS_ENTER == type) { +		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, +			  "[BTCoex], IPS ENTER notify\n"); +		coex_sta->under_ips = true; +		halbtc8821a2ant_coex_all_off(btcoexist); +	} else if (BTC_IPS_LEAVE == type) { +		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, +			  "[BTCoex], IPS LEAVE notify\n"); +		coex_sta->under_ips = false; +	} +} + +void ex_halbtc8821a2ant_lps_notify(struct btc_coexist *btcoexist, u8 type) +{ +	if (BTC_LPS_ENABLE == type) { +		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, +			  "[BTCoex], LPS ENABLE notify\n"); +		coex_sta->under_lps = true; +	} else if (BTC_LPS_DISABLE == type) { +		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, +			  "[BTCoex], LPS DISABLE notify\n"); +		coex_sta->under_lps = false; +	} +} + +void ex_halbtc8821a2ant_scan_notify(struct btc_coexist *btcoexist, u8 type) +{ +	if (BTC_SCAN_START == type) +		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, +			  "[BTCoex], SCAN START notify\n"); +	else if (BTC_SCAN_FINISH == type) +		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, +			  "[BTCoex], SCAN FINISH notify\n"); +} + +void ex_halbtc8821a2ant_connect_notify(struct btc_coexist *btcoexist, u8 type) +{ +	if (BTC_ASSOCIATE_START == type) +		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, +			  "[BTCoex], CONNECT START notify\n"); +	else if (BTC_ASSOCIATE_FINISH == type) +		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, +			  "[BTCoex], CONNECT FINISH notify\n"); +} + +void ex_halbtc8821a2ant_media_status_notify(struct btc_coexist *btcoexist, +					    u8 type) +{ +	u8 h2c_parameter[3] = {0}; +	u32 wifi_bw; +	u8 wifi_central_chnl; + +	if (BTC_MEDIA_CONNECT == type) +		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, +			  "[BTCoex], MEDIA connect notify\n"); +	else +		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, +			  "[BTCoex], MEDIA disconnect notify\n"); + +	/*  only 2.4G we need to inform bt the chnl mask */ +	btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_CENTRAL_CHNL, +			   &wifi_central_chnl); +	if ((BTC_MEDIA_CONNECT == type) && +	    (wifi_central_chnl <= 14)) { +		h2c_parameter[0] = 0x1; +		h2c_parameter[1] = wifi_central_chnl; +		btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); +		if (BTC_WIFI_BW_HT40 == wifi_bw) +			h2c_parameter[2] = 0x30; +		else +			h2c_parameter[2] = 0x20; +	} + +	coex_dm->wifi_chnl_info[0] = h2c_parameter[0]; +	coex_dm->wifi_chnl_info[1] = h2c_parameter[1]; +	coex_dm->wifi_chnl_info[2] = h2c_parameter[2]; + +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, +		  "[BTCoex], FW write 0x66 = 0x%x\n", +		  h2c_parameter[0] << 16 | +		  h2c_parameter[1] << 8 | h2c_parameter[2]); + +	btcoexist->btc_fill_h2c(btcoexist, 0x66, 3, h2c_parameter); +} + +void ex_halbtc8821a2ant_special_packet_notify(struct btc_coexist *btcoexist, +					      u8 type) +{ +	if (type == BTC_PACKET_DHCP) +		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, +			  "[BTCoex], DHCP Packet notify\n"); +} + +void ex_halbtc8821a2ant_bt_info_notify(struct btc_coexist *btcoexist, +				       u8 *tmp_buf, u8 length) +{ +	u8 bt_info = 0; +	u8 i, rsp_source = 0; +	static u32 set_bt_lna_cnt, set_bt_psd_mode; +	bool bt_busy = false, limited_dig = false; +	bool wifi_connected = false, bt_hs_on = false; + +	coex_sta->c2h_bt_info_req_sent = false; +	rsp_source = tmp_buf[0]&0xf; +	if (rsp_source >= BT_INFO_SRC_8821A_2ANT_MAX) +		rsp_source = BT_INFO_SRC_8821A_2ANT_WIFI_FW; +	coex_sta->bt_info_c2h_cnt[rsp_source]++; + +	BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, +		  "[BTCoex], Bt info[%d], length =%d, hex data =[", +		  rsp_source, length); +	for (i = 0; i < length; i++) { +		coex_sta->bt_info_c2h[rsp_source][i] = tmp_buf[i]; +		if (i == 1) +			bt_info = tmp_buf[i]; +		if (i == length-1) +			BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, "0x%02x]\n", +				  tmp_buf[i]); +		else +			BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, "0x%02x, ", +				  tmp_buf[i]); +	} + +	if (BT_INFO_SRC_8821A_2ANT_WIFI_FW != rsp_source) { +		coex_sta->bt_retry_cnt =	/*  [3:0] */ +			coex_sta->bt_info_c2h[rsp_source][2]&0xf; +		coex_sta->bt_rssi = +			coex_sta->bt_info_c2h[rsp_source][3]*2+10; +		coex_sta->bt_info_ext = +			coex_sta->bt_info_c2h[rsp_source][4]; + +		/*  Here we need to resend some wifi info to BT */ +		/*  because bt is reset and loss of the info. */ +		if ((coex_sta->bt_info_ext & BIT(1))) { +			btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, +					   &wifi_connected); +			if (wifi_connected) +				ex_halbtc8821a2ant_media_status_notify(btcoexist, +								       BTC_MEDIA_CONNECT); +			else +				ex_halbtc8821a2ant_media_status_notify(btcoexist, +								       BTC_MEDIA_DISCONNECT); + +			set_bt_psd_mode = 0; +		} +		if (set_bt_psd_mode <= 3) { +			/* fix CH-BW mode  */ +			halbtc8821a2ant_set_bt_psd_mode(btcoexist, +							FORCE_EXEC, 0x0); +			set_bt_psd_mode++; +		} + +		if (coex_dm->cur_bt_lna_constrain) { +			if (!(coex_sta->bt_info_ext & BIT(2))) { +				if (set_bt_lna_cnt <= 3) { +					set_bt_lna_constrain(btcoexist, +							     FORCE_EXEC, true); +					set_bt_lna_cnt++; +				} +			} +		} else { +			set_bt_lna_cnt = 0; +		} + +		if ((coex_sta->bt_info_ext & BIT(3))) +			halbtc8821a2ant_ignore_wlan_act(btcoexist, +							FORCE_EXEC, false); +		else +			/* BT already NOT ignore Wlan active, do nothing here */ + +		if (!(coex_sta->bt_info_ext & BIT(4))) +			halbtc8821a2ant_bt_auto_report(btcoexist, +						       FORCE_EXEC, true); +	} + +	btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); +	/*  check BIT(2) first ==> check if bt is under inquiry or page scan */ +	if (bt_info & BT_INFO_8821A_2ANT_B_INQ_PAGE) { +		coex_sta->c2h_bt_inquiry_page = true; +		coex_dm->bt_status = BT_8821A_2ANT_BT_STATUS_NON_IDLE; +	} else { +		coex_sta->c2h_bt_inquiry_page = false; +		if (bt_info == 0x1) {	/*  connection exists but not busy */ +			coex_sta->bt_link_exist = true; +			coex_dm->bt_status = +				BT_8821A_2ANT_BT_STATUS_CONNECTED_IDLE; +		} else if (bt_info & BT_INFO_8821A_2ANT_B_CONNECTION) { +			/*  connection exists and some link is busy */ +			coex_sta->bt_link_exist = true; +			if (bt_info & BT_INFO_8821A_2ANT_B_FTP) +				coex_sta->pan_exist = true; +			else +				coex_sta->pan_exist = false; +			if (bt_info & BT_INFO_8821A_2ANT_B_A2DP) +				coex_sta->a2dp_exist = true; +			else +				coex_sta->a2dp_exist = false; +			if (bt_info & BT_INFO_8821A_2ANT_B_HID) +				coex_sta->hid_exist = true; +			else +				coex_sta->hid_exist = false; +			if (bt_info & BT_INFO_8821A_2ANT_B_SCO_ESCO) +				coex_sta->sco_exist = true; +			else +				coex_sta->sco_exist = false; +			coex_dm->bt_status = BT_8821A_2ANT_BT_STATUS_NON_IDLE; +		} else { +			coex_sta->bt_link_exist = false; +			coex_sta->pan_exist = false; +			coex_sta->a2dp_exist = false; +			coex_sta->hid_exist = false; +			coex_sta->sco_exist = false; +			coex_dm->bt_status = BT_8821A_2ANT_BT_STATUS_IDLE; +		} + +		if (bt_hs_on) +			coex_dm->bt_status = BT_8821A_2ANT_BT_STATUS_NON_IDLE; +	} + +	if (BT_8821A_2ANT_BT_STATUS_NON_IDLE == coex_dm->bt_status) +		bt_busy = true; +	else +		bt_busy = false; +	btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_TRAFFIC_BUSY, &bt_busy); + +	if (BT_8821A_2ANT_BT_STATUS_IDLE != coex_dm->bt_status) +		limited_dig = true; +	else +		limited_dig = false; +	coex_dm->limited_dig = limited_dig; +	btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_LIMITED_DIG, &limited_dig); + +	halbtc8821a2ant_run_coexist_mechanism(btcoexist); +} + +void ex_halbtc8821a2ant_halt_notify(struct btc_coexist *btcoexist) +{ +	BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, "[BTCoex], Halt notify\n"); + +	halbtc8821a2ant_ignore_wlan_act(btcoexist, FORCE_EXEC, true); +	ex_halbtc8821a2ant_media_status_notify(btcoexist, BTC_MEDIA_DISCONNECT); +} + +void ex_halbtc8821a2ant_periodical(struct btc_coexist *btcoexist) +{ +	static u8 dis_ver_info_cnt; +	u32 fw_ver = 0, bt_patch_ver = 0; +	struct btc_board_info *board_info = &btcoexist->board_info; +	struct btc_stack_info *stack_info = &btcoexist->stack_info; + +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +		  "[BTCoex], ========================== Periodical ===========================\n"); + +	if (dis_ver_info_cnt <= 5) { +		dis_ver_info_cnt += 1; +		BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, +			  "[BTCoex], ****************************************************************\n"); +		BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, +			  "[BTCoex], Ant PG Num/ Ant Mech/ Ant Pos = %d/ %d/ %d\n", +			  board_info->pg_ant_num, board_info->btdm_ant_num, +			  board_info->btdm_ant_pos); +		BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, +			  "[BTCoex], BT stack/ hci ext ver = %s / %d\n", +			  ((stack_info->profile_notified) ? "Yes" : "No"), +			  stack_info->hci_version); +		btcoexist->btc_get(btcoexist, BTC_GET_U4_BT_PATCH_VER, +				   &bt_patch_ver); +		btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver); +		BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, +			  "[BTCoex], CoexVer/ FwVer/ PatchVer = %d_%x/ 0x%x/ 0x%x(%d)\n", +			  glcoex_ver_date_8821a_2ant, +			  glcoex_ver_8821a_2ant, +			  fw_ver, bt_patch_ver, bt_patch_ver); +		BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, +			  "[BTCoex], ****************************************************************\n"); +	} + +	halbtc8821a2ant_query_bt_info(btcoexist); +	halbtc8821a2ant_monitor_bt_ctr(btcoexist); +	monitor_bt_enable_disable(btcoexist); +} diff --git a/drivers/staging/rtl8192ee/btcoexist/halbtc8821a2ant.h b/drivers/staging/rtl8192ee/btcoexist/halbtc8821a2ant.h new file mode 100644 index 00000000000..745506b48d6 --- /dev/null +++ b/drivers/staging/rtl8192ee/btcoexist/halbtc8821a2ant.h @@ -0,0 +1,179 @@ +/*  */ +/*  The following is for 8821A 2Ant BT Co-exist definition */ +/*  */ +#define	BT_INFO_8821A_2ANT_B_FTP				BIT(7) +#define	BT_INFO_8821A_2ANT_B_A2DP				BIT(6) +#define	BT_INFO_8821A_2ANT_B_HID				BIT(5) +#define	BT_INFO_8821A_2ANT_B_SCO_BUSY				BIT(4) +#define	BT_INFO_8821A_2ANT_B_ACL_BUSY				BIT(3) +#define	BT_INFO_8821A_2ANT_B_INQ_PAGE				BIT(2) +#define	BT_INFO_8821A_2ANT_B_SCO_ESCO				BIT(1) +#define	BT_INFO_8821A_2ANT_B_CONNECTION				BIT(0) + +#define		BTC_RSSI_COEX_THRESH_TOL_8821A_2ANT		2 + +enum BT_INFO_SRC_8821A_2ANT { +	BT_INFO_SRC_8821A_2ANT_WIFI_FW			= 0x0, +	BT_INFO_SRC_8821A_2ANT_BT_RSP			= 0x1, +	BT_INFO_SRC_8821A_2ANT_BT_ACTIVE_SEND		= 0x2, +	BT_INFO_SRC_8821A_2ANT_MAX +}; + +enum BT_8821A_2ANT_BT_STATUS { +	BT_8821A_2ANT_BT_STATUS_IDLE				= 0x0, +	BT_8821A_2ANT_BT_STATUS_CONNECTED_IDLE	= 0x1, +	BT_8821A_2ANT_BT_STATUS_NON_IDLE			= 0x2, +	BT_8821A_2ANT_BT_STATUS_MAX +}; + +enum BT_8821A_2ANT_COEX_ALGO { +	BT_8821A_2ANT_COEX_ALGO_UNDEFINED			= 0x0, +	BT_8821A_2ANT_COEX_ALGO_SCO				= 0x1, +	BT_8821A_2ANT_COEX_ALGO_HID				= 0x2, +	BT_8821A_2ANT_COEX_ALGO_A2DP				= 0x3, +	BT_8821A_2ANT_COEX_ALGO_A2DP_PANHS		= 0x4, +	BT_8821A_2ANT_COEX_ALGO_PANEDR			= 0x5, +	BT_8821A_2ANT_COEX_ALGO_PANHS			= 0x6, +	BT_8821A_2ANT_COEX_ALGO_PANEDR_A2DP		= 0x7, +	BT_8821A_2ANT_COEX_ALGO_PANEDR_HID		= 0x8, +	BT_8821A_2ANT_COEX_ALGO_HID_A2DP_PANEDR	= 0x9, +	BT_8821A_2ANT_COEX_ALGO_HID_A2DP			= 0xa, +	BT_8821A_2ANT_COEX_ALGO_MAX				= 0xb, +}; + +struct coex_dm_8821a_2ant { +	/*  fw mechanism */ +	bool		pre_dec_bt_pwr; +	bool		cur_dec_bt_pwr; +	bool		pre_bt_lna_constrain; +	bool		cur_bt_lna_constrain; +	u8		pre_bt_psd_mode; +	u8		cur_bt_psd_mode; +	u8		pre_fw_dac_swing_lvl; +	u8		cur_fw_dac_swing_lvl; +	bool		cur_ignore_wlan_act; +	bool		pre_ignore_wlan_act; +	u8		pre_ps_tdma; +	u8		cur_ps_tdma; +	u8		ps_tdma_para[5]; +	u8		ps_tdma_du_adj_type; +	bool		reset_tdma_adjust; +	bool		pre_ps_tdma_on; +	bool		cur_ps_tdma_on; +	bool		pre_bt_auto_report; +	bool		cur_bt_auto_report; + +	/*  sw mechanism */ +	bool		pre_rf_rx_lpf_shrink; +	bool		cur_rf_rx_lpf_shrink; +	u32		bt_rf0x1e_backup; +	bool	pre_low_penalty_ra; +	bool		cur_low_penalty_ra; +	bool		pre_dac_swing_on; +	u32		pre_dac_swing_lvl; +	bool		cur_dac_swing_on; +	u32		cur_dac_swing_lvl; +	bool		pre_adc_back_off; +	bool		cur_adc_back_off; +	bool	pre_agc_table_en; +	bool		cur_agc_table_en; +	u32		pre_val0x6c0; +	u32		cur_val0x6c0; +	u32		pre_val0x6c4; +	u32		cur_val0x6c4; +	u32		pre_val0x6c8; +	u32		cur_val0x6c8; +	u8		pre_val0x6cc; +	u8		cur_val0x6cc; +	bool		limited_dig; + +	/*  algorithm related */ +	u8		pre_algorithm; +	u8		cur_algorithm; +	u8		bt_status; +	u8		wifi_chnl_info[3]; +}; + +struct coex_sta_8821a_2ant { +	bool		bt_link_exist; +	bool		sco_exist; +	bool		a2dp_exist; +	bool		hid_exist; +	bool		pan_exist; + +	bool		under_lps; +	bool		under_ips; +	u32		high_priority_tx; +	u32		high_priority_rx; +	u32		low_priority_tx; +	u32		low_priority_rx; +	u8		bt_rssi; +	u8		pre_bt_rssi_state; +	u8		pre_wifi_rssi_state[4]; +	bool		c2h_bt_info_req_sent; +	u8		bt_info_c2h[BT_INFO_SRC_8821A_2ANT_MAX][10]; +	u32		bt_info_c2h_cnt[BT_INFO_SRC_8821A_2ANT_MAX]; +	bool		c2h_bt_inquiry_page; +	u8		bt_retry_cnt; +	u8		bt_info_ext; +}; + +/*  */ +/*  The following is interface which will notify coex module. */ +/*  */ +void +ex_halbtc8821a2ant_init_hwconfig( +	struct btc_coexist *btcoexist +	); +void +ex_halbtc8821a2ant_init_coex_dm( +	struct btc_coexist *btcoexist +	); +void +ex_halbtc8821a2ant_ips_notify( +	struct btc_coexist *btcoexist, +	u8 type +	); +void +ex_halbtc8821a2ant_lps_notify( +	struct btc_coexist *btcoexist, +	u8 type +	); +void +ex_halbtc8821a2ant_scan_notify( +	struct btc_coexist *btcoexist, +	u8 type +	); +void +ex_halbtc8821a2ant_connect_notify( +	struct btc_coexist *btcoexist, +	u8 type +	); +void +ex_halbtc8821a2ant_media_status_notify( +	struct btc_coexist *btcoexist, +	u8 type +	); +void +ex_halbtc8821a2ant_special_packet_notify( +	struct btc_coexist *btcoexist, +	u8 type +	); +void +ex_halbtc8821a2ant_bt_info_notify( +	struct btc_coexist *btcoexist, +	u8 *tmp_buf, +	u8 length +	); +void +ex_halbtc8821a2ant_halt_notify( +	struct btc_coexist *btcoexist +	); +void +ex_halbtc8821a2ant_periodical( +	struct btc_coexist *btcoexist +	); +void +ex_halbtc8821a2ant_display_coex_info( +	struct btc_coexist *btcoexist +	); diff --git a/drivers/staging/rtl8192ee/btcoexist/halbtcoutsrc.c b/drivers/staging/rtl8192ee/btcoexist/halbtcoutsrc.c new file mode 100644 index 00000000000..2d9fc24b1e2 --- /dev/null +++ b/drivers/staging/rtl8192ee/btcoexist/halbtcoutsrc.c @@ -0,0 +1,1297 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2013 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * + ******************************************************************************/ + +#include "halbt_precomp.h" + +/*********************************************** + *		Global variables + ***********************************************/ +static const char *const bt_profile_string[] = { +	"NONE", +	"A2DP", +	"PAN", +	"HID", +	"SCO", +}; + +static const char *const bt_spec_string[] = { +	"1.0b", +	"1.1", +	"1.2", +	"2.0+EDR", +	"2.1+EDR", +	"3.0+HS", +	"4.0", +}; + +static const char *const bt_link_role_string[] = { +	"Master", +	"Slave", +}; + +static const char *const h2c_state_string[] = { +	"successful", +	"h2c busy", +	"rf off", +	"fw not read", +}; + +static const char *const io_state_string[] = { +	"IO_STATUS_SUCCESS", +	"IO_STATUS_FAIL_CANNOT_IO", +	"IO_STATUS_FAIL_RF_OFF", +	"IO_STATUS_FAIL_FW_READ_CLEAR_TIMEOUT", +	"IO_STATUS_FAIL_WAIT_IO_EVENT_TIMEOUT", +	"IO_STATUS_INVALID_LEN", +	"IO_STATUS_IO_IDLE_QUEUE_EMPTY", +	"IO_STATUS_IO_INSERT_WAIT_QUEUE_FAIL", +	"IO_STATUS_UNKNOWN_FAIL", +	"IO_STATUS_WRONG_LEVEL", +	"IO_STATUS_H2C_STOPPED", +}; + +struct btc_coexist gl92e_bt_coexist; + +u32 btc_92edbg_type[BTC_MSG_MAX]; +static u8 btc_dbg_buf[100]; + +/*************************************************** + *		Debug related function + ***************************************************/ +static bool is_any_client_connect_to_ap(struct btc_coexist *btcoexist) +{ +	struct rtl_priv *rtlpriv = btcoexist->adapter; +	struct rtl_mac *mac = rtl_mac(rtlpriv); +	struct rtl_sta_info *drv_priv; +	u8 cnt = 0; + +	if (mac->opmode == NL80211_IFTYPE_ADHOC || +	    mac->opmode == NL80211_IFTYPE_MESH_POINT || +	    mac->opmode == NL80211_IFTYPE_AP) { +		spin_lock_bh(&rtlpriv->locks.entry_list_lock); +		list_for_each_entry(drv_priv, &rtlpriv->entry_list, list) { +			cnt++; +		} +		spin_unlock_bh(&rtlpriv->locks.entry_list_lock); +	} +	if (cnt > 0) +		return true; +	else +		return false; +} + +static bool halbtc_is_bt_coexist_available(struct btc_coexist *btcoexist) +{ +	if (!btcoexist->binded || NULL == btcoexist->adapter) +		return false; + +	return true; +} + +static bool halbtc_is_wifi_busy(struct rtl_priv *rtlpriv) +{ +	if (rtlpriv->link_info.b_busytraffic) +		return true; +	else +		return false; +} + + +static void halbtc_dbg_init(void) +{ +	u8 i; + +	for (i = 0; i < BTC_MSG_MAX; i++) +		btc_92edbg_type[i] = 0; + +	btc_92edbg_type[BTC_MSG_INTERFACE] = 0; + +	btc_92edbg_type[BTC_MSG_ALGORITHM] = 0; +} + +static bool halbtc_is_bt40(struct rtl_priv *adapter) +{ +	struct rtl_priv *rtlpriv = adapter; +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	bool is_ht40 = true; +	enum ht_channel_width bw = rtlphy->current_chan_bw; + + +	if (bw == HT_CHANNEL_WIDTH_20) +		is_ht40 = false; +	else if (bw == HT_CHANNEL_WIDTH_20_40) +		is_ht40 = true; + +	return is_ht40; +} + +static bool halbtc_legacy(struct rtl_priv *adapter) +{ +	struct rtl_priv *rtlpriv = adapter; +	struct rtl_mac *mac = rtl_mac(rtlpriv); + +	bool is_legacy = false; + +	if ((mac->mode == WIRELESS_MODE_B) || (mac->mode == WIRELESS_MODE_G)) +		is_legacy = true; + +	return is_legacy; +} + +bool halbtc92e_is_wifi_uplink(struct rtl_priv *adapter) +{ +	struct rtl_priv *rtlpriv = adapter; + +	if (rtlpriv->link_info.b_tx_busy_traffic) +		return true; +	else +		return false; +} + +static u32 halbtc_get_wifi_bw(struct btc_coexist *btcoexist) +{ +	struct rtl_priv *rtlpriv = +		(struct rtl_priv *)btcoexist->adapter; +	u32 wifi_bw = BTC_WIFI_BW_HT20; + +	if (halbtc_is_bt40(rtlpriv)) { +		wifi_bw = BTC_WIFI_BW_HT40; +	} else { +		if (halbtc_legacy(rtlpriv)) +			wifi_bw = BTC_WIFI_BW_LEGACY; +		else +			wifi_bw = BTC_WIFI_BW_HT20; +	} +	return wifi_bw; +} + +static u8 halbtc_get_wifi_central_chnl(struct btc_coexist *btcoexist) +{ +	struct rtl_priv *rtlpriv = btcoexist->adapter; +	struct rtl_phy	*rtlphy = &(rtlpriv->phy); +	u8 chnl = 1; + + +	if (rtlphy->current_channel != 0) +		chnl = rtlphy->current_channel; +	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, +		  "halbtc_get_wifi_central_chnl:%d\n", chnl); +	return chnl; +} + +static void halbtc_leave_lps(struct btc_coexist *btcoexist) +{ +	struct rtl_priv *rtlpriv; +	struct rtl_ps_ctl *ppsc; +	bool ap_enable = false; + +	rtlpriv = btcoexist->adapter; +	ppsc = rtl_psc(rtlpriv); + +	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_AP_MODE_ENABLE, +			   &ap_enable); + +	if (ap_enable) { +		pr_debug("halbtc_leave_lps()<--dont leave lps under AP mode\n"); +		return; +	} + +	btcoexist->bt_info.bt_ctrl_lps = true; +	btcoexist->bt_info.bt_lps_on = false; +	rtl92e_lps_leave(rtlpriv->mac80211.hw); +} + +static void halbtc_enter_lps(struct btc_coexist *btcoexist) +{ +	struct rtl_priv *rtlpriv; +	struct rtl_ps_ctl *ppsc; +	bool ap_enable = false; + +	rtlpriv = btcoexist->adapter; +	ppsc = rtl_psc(rtlpriv); + +	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_AP_MODE_ENABLE, +			   &ap_enable); + +	if (ap_enable) { +		pr_debug("halbtc_enter_lps()<--dont enter lps under AP mode\n"); +		return; +	} + +	btcoexist->bt_info.bt_ctrl_lps = true; +	btcoexist->bt_info.bt_lps_on = false; +	rtl92e_lps_enter(rtlpriv->mac80211.hw); +} + +static void halbtc_normal_lps(struct btc_coexist *btcoexist) +{ +	if (btcoexist->bt_info.bt_ctrl_lps) { +		btcoexist->bt_info.bt_lps_on = false; +		btcoexist->bt_info.bt_ctrl_lps = false; +	} +} + +static void halbtc_aggregation_check(struct btc_coexist *btcoexist) +{ +} + +static u32 halbtcoutsrc_get_wifi_link_status(struct btc_coexist *btcoexist) +{ +	/*------------------------------------ +	 * return value: +	 * [31:16] => connected port number +	 * [15:0] => port connected bit define +	 *------------------------------------ +	 */ + +	struct rtl_priv *rtlpriv = btcoexist->adapter; +	struct rtl_mac *mac = rtl_mac(rtlpriv); +	u32 ret_val = 0; +	u32 port_connected_status = 0, num_of_connected_port = 0; + +	if (mac->opmode == NL80211_IFTYPE_STATION && +	    mac->link_state >= MAC80211_LINKED) { +		port_connected_status |= WIFI_STA_CONNECTED; +		num_of_connected_port++; +	} +	/* AP & ADHOC & MESH */ +	if (is_any_client_connect_to_ap(btcoexist)) { +		port_connected_status |= WIFI_AP_CONNECTED; +		num_of_connected_port++; +	} +	/*if (BT_HsConnectionEstablished(Adapter)) +	{ +		port_connected_status |= WIFI_HS_CONNECTED; +		num_of_connected_port++; +	}*/ +	/* TODO: +	 * P2P Connected Status	*/ + +	ret_val = (num_of_connected_port << 16) | port_connected_status; + +	return ret_val; +} + + +static u32 halbtc_get_bt_patch_version(struct btc_coexist *btcoexist) +{ +	return 0; +} + +static s32 halbtc_get_wifi_rssi(struct rtl_priv *adapter) +{ +	struct rtl_priv *rtlpriv = adapter; +	s32	undecorated_smoothed_pwdb = 0; + +	if (rtlpriv->mac80211.link_state >= MAC80211_LINKED) +		undecorated_smoothed_pwdb = +			rtlpriv->dm.undecorated_smoothed_pwdb; +	else /* associated entry pwdb */ +		undecorated_smoothed_pwdb = +			rtlpriv->dm.undecorated_smoothed_pwdb; +	return undecorated_smoothed_pwdb; +} + +static bool halbtc_get(void *void_btcoexist, u8 get_type, void *out_buf) +{ +	struct btc_coexist *btcoexist = (struct btc_coexist *)void_btcoexist; +	struct rtl_priv *rtlpriv = btcoexist->adapter; +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	struct rtl_mac *mac = rtl_mac(rtlpriv); +	struct rtl_hal *rtlhal = rtl_hal(rtlpriv); +	bool *bool_tmp = (bool *)out_buf; +	int *s32_tmp = (int *)out_buf; +	u32 *u32_tmp = (u32 *)out_buf; +	u8 *u8_tmp = (u8 *)out_buf; +	bool tmp = false; + + +	if (!halbtc_is_bt_coexist_available(btcoexist)) +		return false; + + +	switch (get_type) { +	case BTC_GET_BL_HS_OPERATION: +		*bool_tmp = false; +		break; +	case BTC_GET_BL_HS_CONNECTING: +		*bool_tmp = false; +		break; +	case BTC_GET_BL_WIFI_CONNECTED: +		if (rtlpriv->mac80211.opmode == NL80211_IFTYPE_STATION && +		    rtlpriv->mac80211.link_state >= MAC80211_LINKED) +			tmp = true; +		if (is_any_client_connect_to_ap(btcoexist)) +			tmp = true; +		*bool_tmp = tmp; +		break; +	case BTC_GET_BL_WIFI_BUSY: +		if (halbtc_is_wifi_busy(rtlpriv)) +			*bool_tmp = true; +		else +			*bool_tmp = false; +		break; +	case BTC_GET_BL_WIFI_SCAN: +		if (mac->act_scanning) +			*bool_tmp = true; +		else +			*bool_tmp = false; +		break; +	case BTC_GET_BL_WIFI_LINK: +		if (mac->link_state == MAC80211_LINKING) +			*bool_tmp = true; +		else +			*bool_tmp = false; +		break; +	case BTC_GET_BL_WIFI_ROAM:	/*TODO*/ +		*bool_tmp = false; +		break; +	case BTC_GET_BL_WIFI_4_WAY_PROGRESS:	/*TODO*/ +		*bool_tmp = false; +		break; +	case BTC_GET_BL_WIFI_UNDER_5G: +		*bool_tmp = false; /*TODO*/ + +	case BTC_GET_BL_WIFI_DHCP:	/*TODO*/ +		break; +	case BTC_GET_BL_WIFI_SOFTAP_IDLE: +		*bool_tmp = true; +		break; +	case BTC_GET_BL_WIFI_SOFTAP_LINKING: +		*bool_tmp = false; +		break; +	case BTC_GET_BL_WIFI_IN_EARLY_SUSPEND: +		*bool_tmp = false; +		break; +	case BTC_GET_BL_WIFI_AP_MODE_ENABLE: +		*bool_tmp = false; +		break; +	case BTC_GET_BL_WIFI_ENABLE_ENCRYPTION: +		if (NO_ENCRYPTION == rtlpriv->sec.pairwise_enc_algorithm) +			*bool_tmp = false; +		else +			*bool_tmp = true; +		break; +	case BTC_GET_BL_WIFI_UNDER_B_MODE: +		if (WIRELESS_MODE_B == rtlpriv->mac80211.mode) +			*bool_tmp = true; +		else +			*bool_tmp = false; +		break; +	case BTC_GET_BL_EXT_SWITCH: +		*bool_tmp = false; +		break; +	case BTC_GET_S4_WIFI_RSSI: +		*s32_tmp = halbtc_get_wifi_rssi(rtlpriv); +		break; +	case BTC_GET_S4_HS_RSSI:	/*TODO*/ +		*s32_tmp = halbtc_get_wifi_rssi(rtlpriv); +		break; +	case BTC_GET_U4_WIFI_BW: +		*u32_tmp = halbtc_get_wifi_bw(btcoexist); +		break; +	case BTC_GET_U4_WIFI_TRAFFIC_DIRECTION: +		if (halbtc92e_is_wifi_uplink(rtlpriv)) +			*u32_tmp = BTC_WIFI_TRAFFIC_TX; +		else +			*u32_tmp = BTC_WIFI_TRAFFIC_RX; +		break; +	case BTC_GET_U4_WIFI_FW_VER: +		*u32_tmp = (rtlhal->fw_version << 16) | rtlhal->fw_subversion; +		break; +	case BTC_GET_U4_WIFI_LINK_STATUS: +		*u32_tmp = halbtcoutsrc_get_wifi_link_status(btcoexist); +		break; +	case BTC_GET_U4_BT_PATCH_VER: +		*u32_tmp = halbtc_get_bt_patch_version(btcoexist); +		break; +	case BTC_GET_U1_WIFI_DOT11_CHNL: +		*u8_tmp = rtlphy->current_channel; +		break; +	case BTC_GET_U1_WIFI_CENTRAL_CHNL: +		*u8_tmp = halbtc_get_wifi_central_chnl(btcoexist); +		break; +	case BTC_GET_U1_WIFI_HS_CHNL: +		*u8_tmp = 1;/* BT_OperateChnl(rtlpriv); */ +		break; +	case BTC_GET_U1_MAC_PHY_MODE: +		*u8_tmp = BTC_MP_UNKNOWN; +		break; +	case BTC_GET_U1_AP_NUM: +		/* driver don't know AP num in Linux, +		 * So, the return value here is not right */ +		*u8_tmp = 1;/* pDefMgntInfo->NumBssDesc4Query; */ +		break; + +	/************* 1Ant **************/ +	case BTC_GET_U1_LPS_MODE: +		*u8_tmp = btcoexist->pwr_mode_val[0]; +		break; + +	default: +		break; +	} + +	return true; +} + +static bool halbtc_set(void *void_btcoexist, u8 set_type, void *in_buf) +{ +	struct btc_coexist *btcoexist = (struct btc_coexist *)void_btcoexist; +	bool *bool_tmp = (bool *)in_buf; +	u8 *u8_tmp = (u8 *)in_buf; +	u32 *u32_tmp = (u32 *)in_buf; + + +	if (!halbtc_is_bt_coexist_available(btcoexist)) +		return false; + +	switch (set_type) { +	/* set some bool type variables. */ +	case BTC_SET_BL_BT_DISABLE: +		btcoexist->bt_info.bt_disabled = *bool_tmp; +		break; +	case BTC_SET_BL_BT_TRAFFIC_BUSY: +		btcoexist->bt_info.bt_busy = *bool_tmp; +		break; +	case BTC_SET_BL_BT_LIMITED_DIG: +		btcoexist->bt_info.limited_dig = *bool_tmp; +		break; +	case BTC_SET_BL_FORCE_TO_ROAM: +		btcoexist->bt_info.force_to_roam = *bool_tmp; +		break; +	case BTC_SET_BL_TO_REJ_AP_AGG_PKT: +		btcoexist->bt_info.reject_agg_pkt = *bool_tmp; +		break; +	case BTC_SET_BL_BT_CTRL_AGG_SIZE: +		btcoexist->bt_info.b_bt_ctrl_buf_size = *bool_tmp; +		break; +	case BTC_SET_BL_INC_SCAN_DEV_NUM: +		btcoexist->bt_info.increase_scan_dev_num = *bool_tmp; +		break; +		/* set some u1Byte type variables. */ +	case BTC_SET_U1_RSSI_ADJ_VAL_FOR_AGC_TABLE_ON: +		btcoexist->bt_info.rssi_adjust_for_agc_table_on = *u8_tmp; +		break; +	case BTC_SET_U1_AGG_BUF_SIZE: +		btcoexist->bt_info.agg_buf_size = *u8_tmp; +		break; +		/* the following are some action which will be triggered */ +	case BTC_SET_ACT_GET_BT_RSSI: +		/*BTHCI_SendGetBtRssiEvent(rtlpriv);*/ +		break; +	case BTC_SET_ACT_AGGREGATE_CTRL: +		halbtc_aggregation_check(btcoexist); +		break; + +		/* 1Ant */ +	case BTC_SET_U1_RSSI_ADJ_VAL_FOR_1ANT_COEX_TYPE: +		btcoexist->bt_info.rssi_adjust_for_1ant_coex_type = *u8_tmp; +		break; +	case BTC_SET_U1_LPS_VAL: +		btcoexist->bt_info.lps_val = *u8_tmp; +		break; +	case BTC_SET_U1_RPWM_VAL: +		btcoexist->bt_info.rpwm_val = *u8_tmp; +		break; +	/* the following are some action which will be triggered  */ +	case BTC_SET_ACT_LEAVE_LPS: +		halbtc_leave_lps(btcoexist); +		break; +	case BTC_SET_ACT_ENTER_LPS: +		halbtc_enter_lps(btcoexist); +		break; +	case BTC_SET_ACT_NORMAL_LPS: +		halbtc_normal_lps(btcoexist); +		break; +	case BTC_SET_ACT_DISABLE_LOW_POWER: +		break; +	case BTC_SET_ACT_UPDATE_ra_mask: +		btcoexist->bt_info.ra_mask = *u32_tmp; +		break; +	case BTC_SET_ACT_SEND_MIMO_PS: +		break; +	case BTC_SET_ACT_INC_FORCE_EXEC_PWR_CMD_CNT: +		btcoexist->bt_info.force_exec_pwr_cmd_cnt++; +		break; +	case BTC_SET_ACT_CTRL_BT_INFO: /*wait for 8812/8821*/ +		break; +	case BTC_SET_ACT_CTRL_BT_COEX: +		break; +	default: +		break; +	} + +	return true; +} + +static void halbtc_display_coex_statistics(struct btc_coexist *btcoexist) +{ +} + +static void halbtc_display_bt_link_info(struct btc_coexist *btcoexist) +{ +} + +static void halbtc_display_bt_fw_info(struct btc_coexist *btcoexist) +{ +} + +static void halbtc_display_fw_pwr_mode_cmd(struct btc_coexist *btcoexist) +{ +} + +/************************************************************ + *		IO related function + ************************************************************/ +static u8 halbtc_read_1byte(void *bt_context, u32 reg_addr) +{ +	struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context; +	struct rtl_priv *rtlpriv = btcoexist->adapter; + +	return	rtl_read_byte(rtlpriv, reg_addr); +} + + +static u16 halbtc_read_2byte(void *bt_context, u32 reg_addr) +{ +	struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context; +	struct rtl_priv *rtlpriv = btcoexist->adapter; + +	return	rtl_read_word(rtlpriv, reg_addr); +} + + +static u32 halbtc_read_4byte(void *bt_context, u32 reg_addr) +{ +	struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context; +	struct rtl_priv *rtlpriv = btcoexist->adapter; + +	return	rtl_read_dword(rtlpriv, reg_addr); +} + + +static void halbtc_write_1byte(void *bt_context, u32 reg_addr, u8 data) +{ +	struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context; +	struct rtl_priv *rtlpriv = btcoexist->adapter; + +	rtl_write_byte(rtlpriv, reg_addr, data); +} + +static void halbtc_bitmask_write_1byte(void *bt_context, u32 reg_addr, +				       u8 bit_mask, u8 data) +{ +	struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context; +	struct rtl_priv *rtlpriv = btcoexist->adapter; +	u8 original_value, bit_shift = 0; +	u8 i; + +	if (bit_mask != MASKBYTE0) {/*if not "byte" write*/ +		original_value = rtl_read_byte(rtlpriv, reg_addr); +		for (i = 0; i <= 7; i++) { +			if ((bit_mask>>i)&0x1) +				break; +		} +		bit_shift = i; +		data = (original_value & (~bit_mask)) | +			((data << bit_shift) & bit_mask); +	} +	rtl_write_byte(rtlpriv, reg_addr, data); +} + + +static void halbtc_write_2byte(void *bt_context, u32 reg_addr, u16 data) +{ +	struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context; +	struct rtl_priv *rtlpriv = btcoexist->adapter; + +	rtl_write_word(rtlpriv, reg_addr, data); +} + + +static void halbtc_write_4byte(void *bt_context, u32 reg_addr, u32 data) +{ +	struct btc_coexist *btcoexist = +		(struct btc_coexist *)bt_context; +	struct rtl_priv *rtlpriv = btcoexist->adapter; + +	rtl_write_dword(rtlpriv, reg_addr, data); +} + + +static void halbtc_set_bbreg(void *bt_context, u32 reg_addr, +			     u32 bit_mask, u32 data) +{ +	struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context; +	struct rtl_priv *rtlpriv = btcoexist->adapter; + +	rtl_set_bbreg(rtlpriv->mac80211.hw, reg_addr, bit_mask, data); +} + + +static u32 halbtc_get_bbreg(void *bt_context, u32 reg_addr, u32 bit_mask) +{ +	struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context; +	struct rtl_priv *rtlpriv = btcoexist->adapter; + +	return rtl_get_bbreg(rtlpriv->mac80211.hw, reg_addr, bit_mask); +} + + +static void halbtc_set_rfreg(void *bt_context, u8 rf_path, u32 reg_addr, +			     u32 bit_mask, u32 data) +{ +	struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context; +	struct rtl_priv *rtlpriv = btcoexist->adapter; + +	rtl_set_rfreg(rtlpriv->mac80211.hw, rf_path, reg_addr, bit_mask, data); +} + + +static u32 halbtc_get_rfreg(void *bt_context, u8 rf_path, u32 reg_addr, +			    u32 bit_mask) +{ +	struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context; +	struct rtl_priv *rtlpriv = btcoexist->adapter; + +	return rtl_get_rfreg(rtlpriv->mac80211.hw, rf_path, reg_addr, bit_mask); +} + + +static void halbtc_fill_h2c_cmd(void *bt_context, u8 element_id, +				u32 cmd_len, u8 *cmd_buf) +{ +	struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context; +	struct rtl_priv *rtlpriv = btcoexist->adapter; + +	rtlpriv->cfg->ops->fill_h2c_cmd(rtlpriv->mac80211.hw, element_id, +					cmd_len, cmd_buf); +} + +static void halbtc_display_dbg_msg(void *bt_context, u8 disp_type) +{ +	struct btc_coexist *btcoexist =	(struct btc_coexist *)bt_context; +	switch (disp_type) { +	case BTC_DBG_DISP_COEX_STATISTICS: +		halbtc_display_coex_statistics(btcoexist); +		break; +	case BTC_DBG_DISP_BT_LINK_INFO: +		halbtc_display_bt_link_info(btcoexist); +		break; +	case BTC_DBG_DISP_BT_FW_VER: +		halbtc_display_bt_fw_info(btcoexist); +		break; +	case BTC_DBG_DISP_FW_PWR_MODE_CMD: +		halbtc_display_fw_pwr_mode_cmd(btcoexist); +		break; +	default: +		break; +	} +} + +static bool halbtc_under_ips(struct btc_coexist *btcoexist) +{ +	struct rtl_priv *rtlpriv = btcoexist->adapter; +	struct rtl_ps_ctl *ppsc = rtl_psc(rtlpriv); +	enum rf_pwrstate rtstate; + +	if (ppsc->b_inactiveps) { +		rtstate = ppsc->rfpwr_state; + +		if (rtstate != ERFON && +		    ppsc->rfoff_reason == RF_CHANGE_BY_IPS) +			return true; +	} + +	return false; +} + +/***************************************************************** + *         Extern functions called by other module + *****************************************************************/ +bool exhalbtc92e_initlize_variables(struct rtl_priv *adapter) +{ +	struct btc_coexist *btcoexist = &gl92e_bt_coexist; + +	btcoexist->statistics.cnt_bind++; + +	halbtc_dbg_init(); + +	if (btcoexist->binded) +		return false; +	else +		btcoexist->binded = true; + +	btcoexist->chip_interface = BTC_INTF_UNKNOWN; + +	if (NULL == btcoexist->adapter) +		btcoexist->adapter = adapter; + +	btcoexist->stack_info.profile_notified = false; + +	btcoexist->btc_read_1byte = halbtc_read_1byte; +	btcoexist->btc_write_1byte = halbtc_write_1byte; +	btcoexist->btc_write_1byte_bitmask = halbtc_bitmask_write_1byte; +	btcoexist->btc_read_2byte = halbtc_read_2byte; +	btcoexist->btc_write_2byte = halbtc_write_2byte; +	btcoexist->btc_read_4byte = halbtc_read_4byte; +	btcoexist->btc_write_4byte = halbtc_write_4byte; + +	btcoexist->btc_set_bb_reg = halbtc_set_bbreg; +	btcoexist->btc_get_bb_reg = halbtc_get_bbreg; + +	btcoexist->btc_set_rf_reg = halbtc_set_rfreg; +	btcoexist->btc_get_rf_reg = halbtc_get_rfreg; + +	btcoexist->btc_fill_h2c = halbtc_fill_h2c_cmd; +	btcoexist->btc_disp_dbg_msg = halbtc_display_dbg_msg; + +	btcoexist->btc_get = halbtc_get; +	btcoexist->btc_set = halbtc_set; + +	btcoexist->cli_buf = &btc_dbg_buf[0]; + +	btcoexist->bt_info.b_bt_ctrl_buf_size = false; +	btcoexist->bt_info.agg_buf_size = 5; + +	btcoexist->bt_info.increase_scan_dev_num = false; +	return true; +} + +void exhalbtc92e_init_hw_config(struct btc_coexist *btcoexist) +{ +	struct rtl_priv *rtlpriv = btcoexist->adapter; +	struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + +	if (!halbtc_is_bt_coexist_available(btcoexist)) +		return; + +	btcoexist->statistics.cnt_init_hw_config++; + +	if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE) { +		if (btcoexist->board_info.btdm_ant_num == 2) +			ex92e_halbtc8723b2ant_init_hwconfig(btcoexist); +		else if (btcoexist->board_info.btdm_ant_num == 1) +			ex_halbtc8723b1ant_init_hwconfig(btcoexist); +	} else if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192EE) { +		ex_halbtc8192e2ant_init_hwconfig(btcoexist); +	} else if (rtlhal->hw_type == HARDWARE_TYPE_RTL8821AE) { +		if (btcoexist->board_info.btdm_ant_num == 2) +			ex_halbtc8821a2ant_init_hwconfig(btcoexist); +		else if (btcoexist->board_info.btdm_ant_num == 1) +			ex_halbtc8821a1ant_init_hwconfig(btcoexist); +	} +} + +void exhalbtc92e_init_coex_dm(struct btc_coexist *btcoexist) +{ +	struct rtl_priv *rtlpriv = btcoexist->adapter; +	struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + +	if (!halbtc_is_bt_coexist_available(btcoexist)) +		return; + +	btcoexist->statistics.cnt_init_coex_dm++; + +	if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE) { +		if (btcoexist->board_info.btdm_ant_num == 2) +			ex92e_halbtc8723b2ant_init_coex_dm(btcoexist); +		else if (btcoexist->board_info.btdm_ant_num == 1) +			ex_halbtc8723b1ant_init_coex_dm(btcoexist); +	} else if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192EE) { +		ex_halbtc8192e2ant_init_coex_dm(btcoexist); +	} else if (rtlhal->hw_type == HARDWARE_TYPE_RTL8821AE) { +		if (btcoexist->board_info.btdm_ant_num == 2) +			ex_halbtc8821a2ant_init_coex_dm(btcoexist); +		else if (btcoexist->board_info.btdm_ant_num == 1) +			ex_halbtc8821a1ant_init_coex_dm(btcoexist); +	} + +	btcoexist->initilized = true; +} + +void exhalbtc92e_ips_notify(struct btc_coexist *btcoexist, u8 type) +{ +	struct rtl_priv *rtlpriv = btcoexist->adapter; +	struct rtl_hal *rtlhal = rtl_hal(rtlpriv); +	u8 ips_type; + +	if (!halbtc_is_bt_coexist_available(btcoexist)) +		return; +	btcoexist->statistics.cnt_ips_notify++; +	if (btcoexist->manual_control) +		return; + +	if (ERFOFF == type) +		ips_type = BTC_IPS_ENTER; +	else +		ips_type = BTC_IPS_LEAVE; + +	if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE) { +		if (btcoexist->board_info.btdm_ant_num == 2) +			ex92e_halbtc8723b2ant_ips_notify(btcoexist, ips_type); +		else if (btcoexist->board_info.btdm_ant_num == 1) +			ex_halbtc8723b1ant_ips_notify(btcoexist, ips_type); +	} else if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192EE) { +		ex_halbtc8192e2ant_ips_notify(btcoexist, ips_type); +	} else if (rtlhal->hw_type == HARDWARE_TYPE_RTL8821AE) { +		if (btcoexist->board_info.btdm_ant_num == 2) +			ex_halbtc8821a2ant_ips_notify(btcoexist, ips_type); +		else if (btcoexist->board_info.btdm_ant_num == 1) +			ex_halbtc8821a1ant_ips_notify(btcoexist, ips_type); +	} +} + +void exhalbtc92e_lps_notify(struct btc_coexist *btcoexist, u8 type) +{ +	struct rtl_priv *rtlpriv = btcoexist->adapter; +	struct rtl_hal *rtlhal = rtl_hal(rtlpriv); +	u8 lps_type; + +	if (!halbtc_is_bt_coexist_available(btcoexist)) +		return; +	btcoexist->statistics.cnt_lps_notify++; +	if (btcoexist->manual_control) +		return; + +	if (EACTIVE == type) +		lps_type = BTC_LPS_DISABLE; +	else +		lps_type = BTC_LPS_ENABLE; + +	if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE) { +		if (btcoexist->board_info.btdm_ant_num == 2) +			ex92e_halbtc8723b2ant_lps_notify(btcoexist, lps_type); +		else if (btcoexist->board_info.btdm_ant_num == 1) +			ex_halbtc8723b1ant_lps_notify(btcoexist, lps_type); +	} else if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192EE) { +		ex_halbtc8192e2ant_lps_notify(btcoexist, lps_type); +	} else if (rtlhal->hw_type == HARDWARE_TYPE_RTL8821AE) { +		if (btcoexist->board_info.btdm_ant_num == 2) +			ex_halbtc8821a2ant_lps_notify(btcoexist, lps_type); +		else if (btcoexist->board_info.btdm_ant_num == 1) +			ex_halbtc8821a1ant_lps_notify(btcoexist, lps_type); +	} +} + +void exhalbtc92e_scan_notify(struct btc_coexist *btcoexist, u8 type) +{ +	struct rtl_priv *rtlpriv = btcoexist->adapter; +	struct rtl_hal *rtlhal = rtl_hal(rtlpriv); +	u8 scan_type; + +	if (!halbtc_is_bt_coexist_available(btcoexist)) +		return; +	btcoexist->statistics.cnt_scan_notify++; +	if (btcoexist->manual_control) +		return; + +	if (type) +		scan_type = BTC_SCAN_START; +	else +		scan_type = BTC_SCAN_FINISH; + +	if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE) { +		if (btcoexist->board_info.btdm_ant_num == 2) +			ex92e_halbtc8723b2ant_scan_notify(btcoexist, scan_type); +		else if (btcoexist->board_info.btdm_ant_num == 1) +			ex_halbtc8723b1ant_scan_notify(btcoexist, scan_type); +	} else if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192EE) { +		ex_halbtc8192e2ant_scan_notify(btcoexist, scan_type); +	} else if (rtlhal->hw_type == HARDWARE_TYPE_RTL8821AE) { +		if (btcoexist->board_info.btdm_ant_num == 2) +			ex_halbtc8821a2ant_scan_notify(btcoexist, scan_type); +		else if (btcoexist->board_info.btdm_ant_num == 1) +			ex_halbtc8821a1ant_scan_notify(btcoexist, scan_type); +	} +} + +void exhalbtc92e_connect_notify(struct btc_coexist *btcoexist, u8 action) +{ +	struct rtl_priv *rtlpriv = btcoexist->adapter; +	struct rtl_hal *rtlhal = rtl_hal(rtlpriv); +	u8 asso_type; + +	if (!halbtc_is_bt_coexist_available(btcoexist)) +		return; +	btcoexist->statistics.cnt_connect_notify++; +	if (btcoexist->manual_control) +		return; + +	if (action) +		asso_type = BTC_ASSOCIATE_START; +	else +		asso_type = BTC_ASSOCIATE_FINISH; + +	if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE) { +		if (btcoexist->board_info.btdm_ant_num == 2) +			ex92e_halbtc8723b2ant_connect_notify(btcoexist, +							     asso_type); +		else if (btcoexist->board_info.btdm_ant_num == 1) +			ex_halbtc8723b1ant_connect_notify(btcoexist, asso_type); +	} else if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192EE) { +		ex_halbtc8192e2ant_connect_notify(btcoexist, asso_type); +	} else if (rtlhal->hw_type == HARDWARE_TYPE_RTL8821AE) { +		if (btcoexist->board_info.btdm_ant_num == 2) +			ex_halbtc8821a2ant_connect_notify(btcoexist, +							  asso_type); +		else if (btcoexist->board_info.btdm_ant_num == 1) +			ex_halbtc8821a1ant_connect_notify(btcoexist, +							  asso_type); +	} +} + +void exhalbtc92e_mediastatus_notify(struct btc_coexist *btcoexist, +				    enum rt_media_status media_status) +{ +	struct rtl_priv *rtlpriv = btcoexist->adapter; +	struct rtl_hal *rtlhal = rtl_hal(rtlpriv); +	u8 status; + +	if (!halbtc_is_bt_coexist_available(btcoexist)) +		return; +	btcoexist->statistics.cnt_media_status_notify++; +	if (btcoexist->manual_control) +		return; + +	if (RT_MEDIA_CONNECT == media_status) +		status = BTC_MEDIA_CONNECT; +	else +		status = BTC_MEDIA_DISCONNECT; + +	if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE) { +		if (btcoexist->board_info.btdm_ant_num == 2) +			ex92e_halbtc8723b2ant_media_status_notify(btcoexist, +								  status); +		else if (btcoexist->board_info.btdm_ant_num == 1) +			ex_halbtc8723b1ant_media_status_notify(btcoexist, +							       status); +	} else if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192EE) { +		ex_halbtc8192e2ant_media_status_notify(btcoexist, status); +	} else if (rtlhal->hw_type == HARDWARE_TYPE_RTL8821AE) { +		if (btcoexist->board_info.btdm_ant_num == 2) +			ex_halbtc8821a2ant_media_status_notify(btcoexist, +							       status); +		else if (btcoexist->board_info.btdm_ant_num == 1) +			ex_halbtc8821a1ant_media_status_notify(btcoexist, +							       status); +	} +} + +void exhalbtc92e_special_packet_notify(struct btc_coexist *btcoexist, +				       u8 pkt_type) +{ +	struct rtl_priv *rtlpriv = btcoexist->adapter; +	struct rtl_hal *rtlhal = rtl_hal(rtlpriv); +	u8 packet_type; + +	if (!halbtc_is_bt_coexist_available(btcoexist)) +		return; +	btcoexist->statistics.cnt_special_packet_notify++; +	if (btcoexist->manual_control) +		return; + +	if (PACKET_DHCP == pkt_type) { +		packet_type = BTC_PACKET_DHCP; +	} else if (PACKET_EAPOL == pkt_type) { +		packet_type = BTC_PACKET_EAPOL; +	} else if (PACKET_ARP == pkt_type) { +		packet_type = BTC_PACKET_ARP; +	} else { +		packet_type = BTC_PACKET_UNKNOWN; +		return; +	} + +	if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE) { +		if (btcoexist->board_info.btdm_ant_num == 2) +			ex92e_halbtc8723b2ant_special_packet_notify(btcoexist, +								    packet_type); +		else if (btcoexist->board_info.btdm_ant_num == 1) +			ex_halbtc8723b1ant_special_packet_notify(btcoexist, +								 packet_type); +	} else if (rtlhal->hw_type == HARDWARE_TYPE_RTL8821AE) { +		if (btcoexist->board_info.btdm_ant_num == 2) +			ex_halbtc8821a2ant_special_packet_notify(btcoexist, +								 packet_type); +		else if (btcoexist->board_info.btdm_ant_num == 1) +			ex_halbtc8821a1ant_special_packet_notify(btcoexist, +								 packet_type); +	} +} + +void exhalbtc92e_bt_info_notify(struct btc_coexist *btcoexist, +				u8 *tmp_buf, u8 length) +{ +	struct rtl_priv *rtlpriv = btcoexist->adapter; +	struct rtl_hal *rtlhal = rtl_hal(rtlpriv); +	if (!halbtc_is_bt_coexist_available(btcoexist)) +		return; +	btcoexist->statistics.cnt_bt_info_notify++; + +	if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE) { +		if (btcoexist->board_info.btdm_ant_num == 2) +			ex92e_halbtc8723b2ant_bt_info_notify(btcoexist, +							     tmp_buf, length); +		else if (btcoexist->board_info.btdm_ant_num == 1) +			ex_halbtc8723b1ant_bt_info_notify(btcoexist, tmp_buf, +							  length); +	} else if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192EE) { +		/* ex_halbtc8192e2ant_bt_info_notify(btcoexist, +						     tmp_buf, length); */ +	} else if (rtlhal->hw_type == HARDWARE_TYPE_RTL8821AE) { +		if (btcoexist->board_info.btdm_ant_num == 2) +			ex_halbtc8821a2ant_bt_info_notify(btcoexist, +							  tmp_buf, length); +		else if (btcoexist->board_info.btdm_ant_num == 1) +			ex_halbtc8821a1ant_bt_info_notify(btcoexist, +							  tmp_buf, length); +	} +} + +void exhalbtc92e_stack_operation_notify(struct btc_coexist *btcoexist, u8 type) +{ +	u8 stack_op_type; + +	if (!halbtc_is_bt_coexist_available(btcoexist)) +		return; +	btcoexist->statistics.cnt_stack_operation_notify++; +	if (btcoexist->manual_control) +		return; + +	if ((HCI_BT_OP_INQUIRY_START == type) || +	    (HCI_BT_OP_PAGING_START == type) || +	    (HCI_BT_OP_PAIRING_START == type)) +		stack_op_type = BTC_STACK_OP_INQ_PAGE_PAIR_START; +	else if ((HCI_BT_OP_INQUIRY_FINISH == type) || +		 (HCI_BT_OP_PAGING_SUCCESS == type) || +		 (HCI_BT_OP_PAGING_UNSUCCESS == type) || +		 (HCI_BT_OP_PAIRING_FINISH == type)) +		stack_op_type = BTC_STACK_OP_INQ_PAGE_PAIR_FINISH; +	else +		stack_op_type = BTC_STACK_OP_NONE; +} + +void exhalbtc92e_halt_notify(struct btc_coexist *btcoexist) +{ +	struct rtl_priv *rtlpriv = btcoexist->adapter; +	struct rtl_hal *rtlhal = rtl_hal(rtlpriv); +	if (!halbtc_is_bt_coexist_available(btcoexist)) +		return; + +	btcoexist->binded = false; + +	if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE) { +		if (btcoexist->board_info.btdm_ant_num == 2) +			ex92e_halbtc8723b2ant_halt_notify(btcoexist); +		else if (btcoexist->board_info.btdm_ant_num == 1) +			ex_halbtc8723b1ant_halt_notify(btcoexist); +	} else if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192EE) { +		ex_halbtc8192e2ant_halt_notify(btcoexist); +	} else if (rtlhal->hw_type == HARDWARE_TYPE_RTL8821AE) { +		if (btcoexist->board_info.btdm_ant_num == 2) +			ex_halbtc8821a2ant_halt_notify(btcoexist); +		else if (btcoexist->board_info.btdm_ant_num == 1) +			ex_halbtc8821a1ant_halt_notify(btcoexist); +	} +} + +void exhalbtc92e_pnp_notify(struct btc_coexist *btcoexist, u8 pnp_state) +{ +	struct rtl_priv *rtlpriv = btcoexist->adapter; +	struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + +	if (!halbtc_is_bt_coexist_available(btcoexist)) +		return; + +	if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE) { +		if (btcoexist->board_info.btdm_ant_num == 1) +			ex_halbtc8723b1ant_pnp_notify(btcoexist, pnp_state); +	} +} + +void exhalbtc_coex_dm_switch(struct btc_coexist *btcoexist) +{ +	struct rtl_priv *rtlpriv = btcoexist->adapter; +	struct rtl_hal *rtlhal = rtl_hal(rtlpriv); +	if (!halbtc_is_bt_coexist_available(btcoexist)) +		return; +	btcoexist->statistics.cnt_coex_dm_switch++; + +	if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE) { +		if (btcoexist->board_info.btdm_ant_num == 1) { +			btcoexist->stop_coex_dm = true; +			ex_halbtc8723b1ant_coex_dm_reset(btcoexist); +			exhalbtc92e_set_ant_num(BT_COEX_ANT_TYPE_DETECTED, 2); +			ex92e_halbtc8723b2ant_init_hwconfig(btcoexist); +			ex92e_halbtc8723b2ant_init_coex_dm(btcoexist); +			btcoexist->stop_coex_dm = false; +		} +	} +} + +void exhalbtc92e_periodical(struct btc_coexist *btcoexist) +{ +	struct rtl_priv *rtlpriv = btcoexist->adapter; +	struct rtl_hal *rtlhal = rtl_hal(rtlpriv); +	if (!halbtc_is_bt_coexist_available(btcoexist)) +		return; +	btcoexist->statistics.cnt_periodical++; + +	if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE) { +		if (btcoexist->board_info.btdm_ant_num == 2) +			ex92e_halbtc8723b2ant_periodical(btcoexist); +		else if (btcoexist->board_info.btdm_ant_num == 1) +			ex_halbtc8723b1ant_periodical(btcoexist); +	} else if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192EE) { +		ex_halbtc8192e2ant_periodical(btcoexist); +	} else if (rtlhal->hw_type == HARDWARE_TYPE_RTL8821AE) { +		if (btcoexist->board_info.btdm_ant_num == 2) +			ex_halbtc8821a2ant_periodical(btcoexist); +		else if (btcoexist->board_info.btdm_ant_num == 1) +			if (!halbtc_under_ips(btcoexist)) +				ex_halbtc8821a1ant_periodical(btcoexist); +	} +} + +void exhalbtc92e_dbg_control(struct btc_coexist *btcoexist, +			     u8 code, u8 len, u8 *data) +{ +	if (!halbtc_is_bt_coexist_available(btcoexist)) +		return; +	btcoexist->statistics.cnt_dbg_ctrl++; +} + +void exhalbtc92e_stack_update_profile_info(void) +{ +} + +void exhalbtc92e_update_min_bt_rssi(char bt_rssi) +{ +	struct btc_coexist *btcoexist = &gl92e_bt_coexist; + +	if (!halbtc_is_bt_coexist_available(btcoexist)) +		return; + +	btcoexist->stack_info.min_bt_rssi = bt_rssi; +} + + +void exhalbtc92e_set_hci_version(u16 hci_version) +{ +	struct btc_coexist *btcoexist = &gl92e_bt_coexist; + +	if (!halbtc_is_bt_coexist_available(btcoexist)) +		return; + +	btcoexist->stack_info.hci_version = hci_version; +} + +void exhalbtc92e_set_bt_patch_version(u16 bt_hci_version, u16 bt_patch_version) +{ +	struct btc_coexist *btcoexist = &gl92e_bt_coexist; + +	if (!halbtc_is_bt_coexist_available(btcoexist)) +		return; + +	btcoexist->bt_info.bt_real_fw_ver = bt_patch_version; +	btcoexist->bt_info.bt_hci_ver = bt_hci_version; +} + +void exhalbtc92e_set_bt_exist(bool bt_exist) +{ +	gl92e_bt_coexist.board_info.bt_exist = bt_exist; +} + +void exhalbtc92e_set_chip_type(u8 chip_type) +{ +	switch (chip_type) { +	default: +	case BT_2WIRE: +	case BT_ISSC_3WIRE: +	case BT_ACCEL: +	case BT_RTL8756: +		gl92e_bt_coexist.board_info.bt_chip_type = BTC_CHIP_UNDEF; +		break; +	case BT_CSR_BC4: +		gl92e_bt_coexist.board_info.bt_chip_type = BTC_CHIP_CSR_BC4; +		break; +	case BT_CSR_BC8: +		gl92e_bt_coexist.board_info.bt_chip_type = BTC_CHIP_CSR_BC8; +		break; +	case BT_RTL8723A: +		gl92e_bt_coexist.board_info.bt_chip_type = BTC_CHIP_RTL8723A; +		break; +	case BT_RTL8821A: +		gl92e_bt_coexist.board_info.bt_chip_type = BTC_CHIP_RTL8821; +		break; +	case BT_RTL8723B: +		gl92e_bt_coexist.board_info.bt_chip_type = BTC_CHIP_RTL8723B; +		break; +	} +} + +void exhalbtc92e_set_ant_num(u8 type, u8 ant_num) +{ +	if (BT_COEX_ANT_TYPE_PG == type) { +		gl92e_bt_coexist.board_info.pg_ant_num = ant_num; +		gl92e_bt_coexist.board_info.btdm_ant_num = ant_num; +		/* The antenna position: +		 * Main (default) or Aux for pgAntNum = 2 && btdmAntNum = 1. +		 * The antenna position should be determined by +		 * auto-detect mechanism. +		 * The following is assumed to main, +		 * and those must be modified +		 * if y auto-detect mechanism is ready +		 */ +		if ((gl92e_bt_coexist.board_info.pg_ant_num == 2) && +		    (gl92e_bt_coexist.board_info.btdm_ant_num == 1)) +			gl92e_bt_coexist.board_info.btdm_ant_pos = +						       BTC_ANTENNA_AT_MAIN_PORT; +		else +			gl92e_bt_coexist.board_info.btdm_ant_pos = +						       BTC_ANTENNA_AT_MAIN_PORT; +	} else if (BT_COEX_ANT_TYPE_ANTDIV == type) { +		gl92e_bt_coexist.board_info.btdm_ant_num = ant_num; +		gl92e_bt_coexist.board_info.btdm_ant_pos = +						       BTC_ANTENNA_AT_MAIN_PORT; +	} else if (BT_COEX_ANT_TYPE_DETECTED == type) { +		gl92e_bt_coexist.board_info.btdm_ant_num = ant_num; +		gl92e_bt_coexist.board_info.btdm_ant_pos = +						       BTC_ANTENNA_AT_MAIN_PORT; +	} +} + +void exhalbtc92e_display_bt_coex_info(struct btc_coexist *btcoexist) +{ +	struct rtl_priv *rtlpriv = btcoexist->adapter; +	struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + +	if (!halbtc_is_bt_coexist_available(btcoexist)) +		return; + +	if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE) { +		if (btcoexist->board_info.btdm_ant_num == 2) +			ex_halbtc8723b2ant92e_display_coex_info(btcoexist); +		else if (btcoexist->board_info.btdm_ant_num == 1) +			ex_halbtc8723b1ant_display_coex_info(btcoexist); +	} else if (rtlhal->hw_type == HARDWARE_TYPE_RTL8821AE) { +		if (btcoexist->board_info.btdm_ant_num == 2) +			ex_halbtc8821a2ant_display_coex_info(btcoexist); +		else if (btcoexist->board_info.btdm_ant_num == 1) +			ex_halbtc8821a1ant_display_coex_info(btcoexist); +	} +} diff --git a/drivers/staging/rtl8192ee/btcoexist/halbtcoutsrc.h b/drivers/staging/rtl8192ee/btcoexist/halbtcoutsrc.h new file mode 100644 index 00000000000..c0a4286430a --- /dev/null +++ b/drivers/staging/rtl8192ee/btcoexist/halbtcoutsrc.h @@ -0,0 +1,537 @@ +#ifndef	__HALBTC_OUT_SRC_H__ +#define __HALBTC_OUT_SRC_H__ + +#include	"../wifi.h" + +#define		NORMAL_EXEC				false +#define		FORCE_EXEC				true + +#define		BTC_RF_A				RF90_PATH_A +#define		BTC_RF_B				RF90_PATH_B +#define		BTC_RF_C				RF90_PATH_C +#define		BTC_RF_D				RF90_PATH_D + +#define		BTC_SMSP				SINGLEMAC_SINGLEPHY +#define		BTC_DMDP				DUALMAC_DUALPHY +#define		BTC_DMSP				DUALMAC_SINGLEPHY +#define		BTC_MP_UNKNOWN				0xff + +#define		IN +#define		OUT + +#define		BT_TMP_BUF_SIZE				100 + +#define		BT_COEX_ANT_TYPE_PG			0 +#define		BT_COEX_ANT_TYPE_ANTDIV			1 +#define		BT_COEX_ANT_TYPE_DETECTED		2 + +#define		BTC_MIMO_PS_STATIC			0 +#define		BTC_MIMO_PS_DYNAMIC			1 + +#define		BTC_RATE_DISABLE			0 +#define		BTC_RATE_ENABLE				1 + +/* single Antenna definition */ +#define		BTC_ANT_PATH_WIFI			0 +#define		BTC_ANT_PATH_BT				1 +#define		BTC_ANT_PATH_PTA			2 +/* dual Antenna definition */ +#define		BTC_ANT_WIFI_AT_MAIN			0 +#define		BTC_ANT_WIFI_AT_AUX			1 +/* coupler Antenna definition */ +#define		BTC_ANT_WIFI_AT_CPL_MAIN		0 +#define		BTC_ANT_WIFI_AT_CPL_AUX			1 + +enum btc_chip_interface { +	BTC_INTF_UNKNOWN	= 0, +	BTC_INTF_PCI		= 1, +	BTC_INTF_USB		= 2, +	BTC_INTF_SDIO		= 3, +	BTC_INTF_GSPI		= 4, +	BTC_INTF_MAX +}; + +enum btc_chip_type { +	BTC_CHIP_UNDEF		= 0, +	BTC_CHIP_CSR_BC4	= 1, +	BTC_CHIP_CSR_BC8	= 2, +	BTC_CHIP_RTL8723A	= 3, +	BTC_CHIP_RTL8821	= 4, +	BTC_CHIP_RTL8723B	= 5, +	BTC_CHIP_MAX +}; + +enum btc_msg_type { +	BTC_MSG_INTERFACE	= 0x0, +	BTC_MSG_ALGORITHM	= 0x1, +	BTC_MSG_MAX +}; + +extern u32 btc_92edbg_type[]; + +/* following is for BTC_MSG_INTERFACE */ +#define		INTF_INIT				BIT(0) +#define		INTF_NOTIFY				BIT(2) + +/* following is for BTC_ALGORITHM */ +#define		ALGO_BT_RSSI_STATE			BIT(0) +#define		ALGO_WIFI_RSSI_STATE			BIT(1) +#define		ALGO_BT_MONITOR				BIT(2) +#define		ALGO_TRACE				BIT(3) +#define		ALGO_TRACE_FW				BIT(4) +#define		ALGO_TRACE_FW_DETAIL			BIT(5) +#define		ALGO_TRACE_FW_EXEC			BIT(6) +#define		ALGO_TRACE_SW				BIT(7) +#define		ALGO_TRACE_SW_DETAIL			BIT(8) +#define		ALGO_TRACE_SW_EXEC			BIT(9) + +/* following is for wifi link status */ +#define		WIFI_STA_CONNECTED			BIT(0) +#define		WIFI_AP_CONNECTED			BIT(1) +#define		WIFI_HS_CONNECTED			BIT(2) +#define		WIFI_P2P_GO_CONNECTED			BIT(3) +#define		WIFI_P2P_GC_CONNECTED			BIT(4) + + +#define	CL_SPRINTF	snprintf +#define	CL_PRINTF	printk + +#define	BTC_PRINT(dbgtype, dbgflag, printstr, ...)		\ +	do {							\ +		if (unlikely(btc_92edbg_type[dbgtype] & dbgflag)) {\ +			pr_debug(printstr, ##__VA_ARGS__);	\ +		}						\ +	} while (0) + +#define	BTC_PRINT_F(dbgtype, dbgflag, printstr, ...)		\ +	do {							\ +		if (unlikely(btc_92edbg_type[dbgtype] & dbgflag)) {\ +			pr_debug("%s: ", __func__);	\ +			pr_cont(printstr, ##__VA_ARGS__);	\ +		}						\ +	} while (0) + +#define	BTC_PRINT_ADDR(dbgtype, dbgflag, printstr, _ptr)	\ +	do {							\ +		if (unlikely(btc_92edbg_type[dbgtype] & dbgflag)) {	\ +			int __i;				\ +			u8 *__ptr = (u8 *)_ptr;			\ +			pr_debug printstr;			\ +			for (__i = 0; __i < 6; __i++)		\ +				pr_cont("%02X%s", __ptr[__i],	\ +					(__i == 5) ? "" : "-");	\ +			pr_debug("\n");				\ +		}						\ +	} while (0) + +#define BTC_PRINT_DATA(dbgtype, dbgflag, _titlestring, _hexdata, _hexdatalen) \ +	do {								\ +		if (unlikely(btc_92edbg_type[dbgtype] & dbgflag)) {	\ +			int __i;					\ +			u8 *__ptr = (u8 *)_hexdata;			\ +			pr_debug(_titlestring);				\ +			for (__i = 0; __i < (int)_hexdatalen; __i++) {	\ +				pr_cont("%02X%s", __ptr[__i], (((__i + 1) % 4) \ +							== 0) ? "  " : " ");\ +				if (((__i + 1) % 16) == 0)		\ +					pr_cont("\n");			\ +			}						\ +			pr_debug("\n");			\ +		}							\ +	} while (0) + + +#define	BTC_RSSI_HIGH(_rssi_)	\ +	((_rssi_ == BTC_RSSI_STATE_HIGH ||	\ +	  _rssi_ == BTC_RSSI_STATE_STAY_HIGH) ? true : false) +#define	BTC_RSSI_MEDIUM(_rssi_)	\ +	((_rssi_ == BTC_RSSI_STATE_MEDIUM ||	\ +	  _rssi_ == BTC_RSSI_STATE_STAY_MEDIUM) ? true : false) +#define	BTC_RSSI_LOW(_rssi_)	\ +	((_rssi_ == BTC_RSSI_STATE_LOW ||	\ +	  _rssi_ == BTC_RSSI_STATE_STAY_LOW) ? true : false) + + +enum btc_power_save_type { +	BTC_PS_WIFI_NATIVE = 0, +	BTC_PS_LPS_ON = 1, +	BTC_PS_LPS_OFF = 2, +	BTC_PS_LPS_MAX +}; + +struct btc_board_info { +	/* The following is some board information */ +	u8 bt_chip_type; +	u8 pg_ant_num;	/* pg ant number */ +	u8 btdm_ant_num;	/* ant number for btdm */ +	u8 btdm_ant_pos; +	bool bt_exist; +}; + +enum btc_dbg_opcode { +	BTC_DBG_SET_COEX_NORMAL = 0x0, +	BTC_DBG_SET_COEX_WIFI_ONLY = 0x1, +	BTC_DBG_SET_COEX_BT_ONLY = 0x2, +	BTC_DBG_MAX +}; + +enum btc_rssi_state { +	BTC_RSSI_STATE_HIGH = 0x0, +	BTC_RSSI_STATE_MEDIUM = 0x1, +	BTC_RSSI_STATE_LOW = 0x2, +	BTC_RSSI_STATE_STAY_HIGH = 0x3, +	BTC_RSSI_STATE_STAY_MEDIUM = 0x4, +	BTC_RSSI_STATE_STAY_LOW = 0x5, +	BTC_RSSI_MAX +}; + +enum btc_wifi_role { +	BTC_ROLE_STATION = 0x0, +	BTC_ROLE_AP = 0x1, +	BTC_ROLE_IBSS = 0x2, +	BTC_ROLE_HS_MODE = 0x3, +	BTC_ROLE_MAX +}; + +enum btc_wifi_bw_mode { +	BTC_WIFI_BW_LEGACY = 0x0, +	BTC_WIFI_BW_HT20 = 0x1, +	BTC_WIFI_BW_HT40 = 0x2, +	BTC_WIFI_BW_MAX +}; + +enum btc_wifi_traffic_dir { +	BTC_WIFI_TRAFFIC_TX = 0x0, +	BTC_WIFI_TRAFFIC_RX = 0x1, +	BTC_WIFI_TRAFFIC_MAX +}; + +enum btc_wifi_pnp { +	BTC_WIFI_PNP_WAKE_UP = 0x0, +	BTC_WIFI_PNP_SLEEP = 0x1, +	BTC_WIFI_PNP_MAX +}; + + +enum btc_get_type { +	/* type bool */ +	BTC_GET_BL_HS_OPERATION, +	BTC_GET_BL_HS_CONNECTING, +	BTC_GET_BL_WIFI_CONNECTED, +	BTC_GET_BL_WIFI_BUSY, +	BTC_GET_BL_WIFI_SCAN, +	BTC_GET_BL_WIFI_LINK, +	BTC_GET_BL_WIFI_DHCP, +	BTC_GET_BL_WIFI_SOFTAP_IDLE, +	BTC_GET_BL_WIFI_SOFTAP_LINKING, +	BTC_GET_BL_WIFI_IN_EARLY_SUSPEND, +	BTC_GET_BL_WIFI_ROAM, +	BTC_GET_BL_WIFI_4_WAY_PROGRESS, +	BTC_GET_BL_WIFI_UNDER_5G, +	BTC_GET_BL_WIFI_AP_MODE_ENABLE, +	BTC_GET_BL_WIFI_ENABLE_ENCRYPTION, +	BTC_GET_BL_WIFI_UNDER_B_MODE, +	BTC_GET_BL_EXT_SWITCH, + +	/* type s4Byte */ +	BTC_GET_S4_WIFI_RSSI, +	BTC_GET_S4_HS_RSSI, + +	/* type u32 */ +	BTC_GET_U4_WIFI_BW, +	BTC_GET_U4_WIFI_TRAFFIC_DIRECTION, +	BTC_GET_U4_WIFI_FW_VER, +	BTC_GET_U4_WIFI_LINK_STATUS, +	BTC_GET_U4_BT_PATCH_VER, + +	/* type u1Byte */ +	BTC_GET_U1_WIFI_DOT11_CHNL, +	BTC_GET_U1_WIFI_CENTRAL_CHNL, +	BTC_GET_U1_WIFI_HS_CHNL, +	BTC_GET_U1_MAC_PHY_MODE, +	BTC_GET_U1_AP_NUM, + +	/* for 1Ant */ +	BTC_GET_U1_LPS_MODE, +	BTC_GET_BL_BT_SCO_BUSY, + +	/* for test mode */ +	BTC_GET_DRIVER_TEST_CFG, +	BTC_GET_MAX +}; + + +enum btc_set_type { +	/* type bool */ +	BTC_SET_BL_BT_DISABLE, +	BTC_SET_BL_BT_TRAFFIC_BUSY, +	BTC_SET_BL_BT_LIMITED_DIG, +	BTC_SET_BL_FORCE_TO_ROAM, +	BTC_SET_BL_TO_REJ_AP_AGG_PKT, +	BTC_SET_BL_BT_CTRL_AGG_SIZE, +	BTC_SET_BL_INC_SCAN_DEV_NUM, + +	/* type u1Byte */ +	BTC_SET_U1_RSSI_ADJ_VAL_FOR_AGC_TABLE_ON, +	BTC_SET_U1_AGG_BUF_SIZE, + +	/* type trigger some action */ +	BTC_SET_ACT_GET_BT_RSSI, +	BTC_SET_ACT_AGGREGATE_CTRL, + +	/********* for 1Ant **********/ +	/* type bool */ +	BTC_SET_BL_BT_SCO_BUSY, +	/* type u1Byte */ +	BTC_SET_U1_RSSI_ADJ_VAL_FOR_1ANT_COEX_TYPE, +	BTC_SET_U1_LPS_VAL, +	BTC_SET_U1_RPWM_VAL, +	BTC_SET_U1_1ANT_LPS, +	BTC_SET_U1_1ANT_RPWM, +	/* type trigger some action */ +	BTC_SET_ACT_LEAVE_LPS, +	BTC_SET_ACT_ENTER_LPS, +	BTC_SET_ACT_NORMAL_LPS, +	BTC_SET_ACT_INC_FORCE_EXEC_PWR_CMD_CNT, +	BTC_SET_ACT_DISABLE_LOW_POWER, +	BTC_SET_ACT_UPDATE_ra_mask, +	BTC_SET_ACT_SEND_MIMO_PS, +	/* BT Coex related */ +	BTC_SET_ACT_CTRL_BT_INFO, +	BTC_SET_ACT_CTRL_BT_COEX, +	/***************************/ +	BTC_SET_MAX +}; + +enum btc_dbg_disp_type { +	BTC_DBG_DISP_COEX_STATISTICS = 0x0, +	BTC_DBG_DISP_BT_LINK_INFO = 0x1, +	BTC_DBG_DISP_BT_FW_VER = 0x2, +	BTC_DBG_DISP_FW_PWR_MODE_CMD = 0x3, +	BTC_DBG_DISP_MAX +}; + +enum btc_notify_type_ips { +	BTC_IPS_LEAVE = 0x0, +	BTC_IPS_ENTER = 0x1, +	BTC_IPS_MAX +}; + +enum btc_notify_type_lps { +	BTC_LPS_DISABLE = 0x0, +	BTC_LPS_ENABLE = 0x1, +	BTC_LPS_MAX +}; + +enum btc_notify_type_scan { +	BTC_SCAN_FINISH = 0x0, +	BTC_SCAN_START = 0x1, +	BTC_SCAN_MAX +}; + +enum btc_notify_type_associate { +	BTC_ASSOCIATE_FINISH = 0x0, +	BTC_ASSOCIATE_START = 0x1, +	BTC_ASSOCIATE_MAX +}; + +enum btc_notify_type_media_status { +	BTC_MEDIA_DISCONNECT = 0x0, +	BTC_MEDIA_CONNECT = 0x1, +	BTC_MEDIA_MAX +}; + +enum btc_notify_type_special_packet { +	BTC_PACKET_UNKNOWN = 0x0, +	BTC_PACKET_DHCP = 0x1, +	BTC_PACKET_ARP = 0x2, +	BTC_PACKET_EAPOL = 0x3, +	BTC_PACKET_MAX +}; + +enum hci_ext_bt_operation { +	HCI_BT_OP_NONE = 0x0, +	HCI_BT_OP_INQUIRY_START = 0x1, +	HCI_BT_OP_INQUIRY_FINISH = 0x2, +	HCI_BT_OP_PAGING_START = 0x3, +	HCI_BT_OP_PAGING_SUCCESS = 0x4, +	HCI_BT_OP_PAGING_UNSUCCESS = 0x5, +	HCI_BT_OP_PAIRING_START = 0x6, +	HCI_BT_OP_PAIRING_FINISH = 0x7, +	HCI_BT_OP_BT_DEV_ENABLE = 0x8, +	HCI_BT_OP_BT_DEV_DISABLE = 0x9, +	HCI_BT_OP_MAX +}; + +enum btc_notify_type_stack_operation { +	BTC_STACK_OP_NONE = 0x0, +	BTC_STACK_OP_INQ_PAGE_PAIR_START = 0x1, +	BTC_STACK_OP_INQ_PAGE_PAIR_FINISH = 0x2, +	BTC_STACK_OP_MAX +}; + + +struct btc_bt_info { +	bool bt_disabled; +	u8 rssi_adjust_for_agc_table_on; +	u8 rssi_adjust_for_1ant_coex_type; +	bool bt_busy; +	u8 agg_buf_size; +	bool limited_dig; +	bool reject_agg_pkt; +	bool b_bt_ctrl_buf_size; +	bool increase_scan_dev_num; +	u16 bt_hci_ver; +	u16 bt_real_fw_ver; +	u8 bt_fw_ver; + +	bool bt_disable_low_pwr; + +	/* the following is for 1Ant solution */ +	bool bt_ctrl_lps; +	bool bt_pwr_save_mode; +	bool bt_lps_on; +	bool force_to_roam; +	u8 force_exec_pwr_cmd_cnt; +	u8 lps_val; +	u8 rpwm_val; +	u32 ra_mask; +}; + +struct btc_stack_info { +	bool profile_notified; +	u16 hci_version;	/* stack hci version */ +	u8 num_of_link; +	bool bt_link_exist; +	bool sco_exist; +	bool acl_exist; +	bool a2dp_exist; +	bool hid_exist; +	u8 num_of_hid; +	bool pan_exist; +	bool unknown_acl_exist; +	char min_bt_rssi; +}; + +struct btc_statistics { +	u32 cnt_bind; +	u32 cnt_init_hw_config; +	u32 cnt_init_coex_dm; +	u32 cnt_ips_notify; +	u32 cnt_lps_notify; +	u32 cnt_scan_notify; +	u32 cnt_connect_notify; +	u32 cnt_media_status_notify; +	u32 cnt_special_packet_notify; +	u32 cnt_bt_info_notify; +	u32 cnt_periodical; +	u32 cnt_coex_dm_switch; +	u32 cnt_stack_operation_notify; +	u32 cnt_dbg_ctrl; +}; + +struct btc_bt_link_info { +	bool bt_link_exist; +	bool sco_exist; +	bool sco_only; +	bool a2dp_exist; +	bool a2dp_only; +	bool hid_exist; +	bool hid_only; +	bool pan_exist; +	bool pan_only; +}; + +enum btc_antenna_pos { +	BTC_ANTENNA_AT_MAIN_PORT = 0x1, +	BTC_ANTENNA_AT_AUX_PORT = 0x2, +}; + +struct btc_coexist { +	/* make sure only one adapter can bind the data context  */ +	bool binded; +	/* default adapter */ +	void *adapter; +	struct btc_board_info board_info; +	/* some bt info referenced by non-bt module */ +	struct btc_bt_info bt_info; +	struct btc_stack_info stack_info; +	enum btc_chip_interface	chip_interface; +	struct btc_bt_link_info bt_link_info; + +	bool initilized; +	bool stop_coex_dm; +	bool manual_control; +	u8 *cli_buf; +	struct btc_statistics statistics; +	u8 pwr_mode_val[10]; + +	/* function pointers io related */ +	u8 (*btc_read_1byte)(void *btc_context, u32 reg_addr); +	void (*btc_write_1byte)(void *btc_context, u32 reg_addr, u8 data); +	void (*btc_write_1byte_bitmask)(void *btc_context, u32 reg_addr, +					u8 bit_mask, u8 data1b); +	u16 (*btc_read_2byte)(void *btc_context, u32 reg_addr); +	void (*btc_write_2byte)(void *btc_context, u32 reg_addr, u16 data); +	u32 (*btc_read_4byte)(void *btc_context, u32 reg_addr); +	void (*btc_write_4byte)(void *btc_context, u32 reg_addr, u32 data); + +	void (*btc_set_bb_reg)(void *btc_context, u32 reg_addr, +			       u32 bit_mask, u32 data); +	u32 (*btc_get_bb_reg)(void *btc_context, u32 reg_addr, +			      u32 bit_mask); + +	void (*btc_set_rf_reg)(void *btc_context, u8 rf_path, u32 reg_addr, +			       u32 bit_mask, u32 data); +	u32 (*btc_get_rf_reg)(void *btc_context, u8 rf_path, +			      u32 reg_addr, u32 bit_mask); + + +	void (*btc_fill_h2c)(void *btc_context, u8 element_id, +			     u32 cmd_len, u8 *cmd_buffer); + +	void (*btc_disp_dbg_msg)(void *btcoexist, u8 disp_type); + +	bool (*btc_get)(void *btcoexist, u8 get_type, void *out_buf); +	bool (*btc_set)(void *btcoexist, u8 set_type, void *in_buf); +}; + + +bool halbtc92e_is_wifi_uplink(struct rtl_priv *adapter); + + +extern struct btc_coexist gl92e_bt_coexist; + +bool exhalbtc92e_initlize_variables(struct rtl_priv *adapter); +void exhalbtc92e_init_hw_config(struct btc_coexist *btcoexist); +void exhalbtc92e_init_coex_dm(struct btc_coexist *btcoexist); +void exhalbtc92e_ips_notify(struct btc_coexist *btcoexist, u8 type); +void exhalbtc92e_lps_notify(struct btc_coexist *btcoexist, u8 type); +void exhalbtc92e_scan_notify(struct btc_coexist *btcoexist, u8 type); +void exhalbtc92e_connect_notify(struct btc_coexist *btcoexist, u8 action); +void exhalbtc92e_mediastatus_notify(struct btc_coexist *btcoexist, +				    enum rt_media_status media_status); +void exhalbtc92e_special_packet_notify(struct btc_coexist *btcoexist, +				       u8 pkt_type); +void exhalbtc92e_bt_info_notify(struct btc_coexist *btcoexist, u8 *tmp_buf, +				u8 length); +void exhalbtc92e_stack_operation_notify(struct btc_coexist *btcoexist, u8 type); +void exhalbtc92e_halt_notify(struct btc_coexist *btcoexist); +void exhalbtc92e_pnp_notify(struct btc_coexist *btcoexist, u8 pnp_state); +void exhalbtc_coex_dm_switch(struct btc_coexist *btcoexist); +void exhalbtc92e_periodical(struct btc_coexist *btcoexist); +void exhalbtc92e_dbg_control(struct btc_coexist *btcoexist, u8 code, u8 len, +			     u8 *data); +void exhalbtc92e_stack_update_profile_info(void); +void exhalbtc92e_set_hci_version(u16 hci_version); +void exhalbtc92e_set_bt_patch_version(u16 bt_hci_version, u16 bt_patch_version); +void exhalbtc92e_update_min_bt_rssi(char bt_rssi); +void exhalbtc92e_set_bt_exist(bool bt_exist); +void exhalbtc92e_set_chip_type(u8 chip_type); +void exhalbtc92e_set_ant_num(u8 type, u8 ant_num); +void exhalbtc92e_display_bt_coex_info(struct btc_coexist *btcoexist); +void exhalbtc_signal_compensation(struct btc_coexist *btcoexist, +				  u8 *rssi_wifi, u8 *rssi_bt); +void exhalbtc_lps_leave(struct btc_coexist *btcoexist); +void exhalbtc_low_wifi_traffic_notify(struct btc_coexist *btcoexist); +#endif diff --git a/drivers/staging/rtl8192ee/btcoexist/rtl_btc.c b/drivers/staging/rtl8192ee/btcoexist/rtl_btc.c new file mode 100644 index 00000000000..50c012a4c17 --- /dev/null +++ b/drivers/staging/rtl8192ee/btcoexist/rtl_btc.c @@ -0,0 +1,194 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010  Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +#include <linux/vmalloc.h> +#include <linux/module.h> + +#include "rtl_btc.h" +#include "halbt_precomp.h" + +static struct rtl_btc_ops rtl_btc_operation = { +	.btc_init_variables = rtl92e_btc_init_variables, +	.btc_init_hal_vars = rtl92e_btc_init_hal_vars, +	.btc_init_hw_config = rtl92e_btc_init_hw_config, +	.btc_ips_notify = rtl92e_btc_ips_notify, +	.btc_lps_notify = rtl_btc_lps_notify, +	.btc_scan_notify = rtl92e_btc_scan_notify, +	.btc_connect_notify = rtl92e_btc_connect_notify, +	.btc_mediastatus_notify = rtl92e_btc_mediastatus_notify, +	.btc_periodical = rtl92e_btc_periodical, +	.btc_halt_notify = rtl92e_btc_halt_notify, +	.btc_btinfo_notify = rtl92e_btc_btinfo_notify, +	.btc_is_limited_dig = rtl92e_btc_is_limited_dig, +	.btc_is_disable_edca_turbo = rtl92e_btc_is_disable_edca_turbo, +	.btc_is_bt_disabled = rtl92e_btc_is_bt_disabled, +	.btc_special_packet_notify = rtl_btc_special_packet_notify, +}; + +void rtl92e_btc_init_variables(struct rtl_priv *rtlpriv) +{ +	exhalbtc92e_initlize_variables(rtlpriv); +} + +void rtl92e_btc_init_hal_vars(struct rtl_priv *rtlpriv) +{ +	u8 ant_num; +	u8 bt_exist; +	u8 bt_type; +	ant_num = rtl92e_get_hwpg_ant_num(rtlpriv); +	RT_TRACE(COMP_INIT, DBG_DMESG, +		 ("%s, antNum is %d\n", __func__, ant_num)); + +	bt_exist = rtl92e_get_hwpg_bt_exist(rtlpriv); +	RT_TRACE(COMP_INIT, DBG_DMESG, +		 ("%s, bt_exist is %d\n", __func__, bt_exist)); +	exhalbtc92e_set_bt_exist(bt_exist); + +	bt_type = rtl92e_get_hwpg_bt_type(rtlpriv); +	RT_TRACE(COMP_INIT, DBG_DMESG, +		 ("%s, bt_type is %d\n", __func__, bt_type)); +	exhalbtc92e_set_chip_type(bt_type); + +	exhalbtc92e_set_ant_num(BT_COEX_ANT_TYPE_PG, ant_num); +} + +void rtl92e_btc_init_hw_config(struct rtl_priv *rtlpriv) +{ +	exhalbtc92e_init_hw_config(&gl92e_bt_coexist); +	exhalbtc92e_init_coex_dm(&gl92e_bt_coexist); +} + +void rtl92e_btc_ips_notify(struct rtl_priv *rtlpriv, u8 type) +{ +	exhalbtc92e_ips_notify(&gl92e_bt_coexist, type); +} + +void rtl_btc_lps_notify(struct rtl_priv *rtlpriv, u8 type) +{ +	exhalbtc92e_lps_notify(&gl92e_bt_coexist, type); +} + +void rtl92e_btc_scan_notify(struct rtl_priv *rtlpriv, u8 scantype) +{ +	exhalbtc92e_scan_notify(&gl92e_bt_coexist, scantype); +} + +void rtl92e_btc_connect_notify(struct rtl_priv *rtlpriv, u8 action) +{ +	exhalbtc92e_connect_notify(&gl92e_bt_coexist, action); +} + +void rtl92e_btc_mediastatus_notify(struct rtl_priv *rtlpriv, +				   enum rt_media_status mstatus) +{ +	exhalbtc92e_mediastatus_notify(&gl92e_bt_coexist, mstatus); +} + +void rtl92e_btc_periodical(struct rtl_priv *rtlpriv) +{ +	exhalbtc92e_periodical(&gl92e_bt_coexist); +} + +void rtl92e_btc_halt_notify(void) +{ +	exhalbtc92e_halt_notify(&gl92e_bt_coexist); +} + +void rtl92e_btc_btinfo_notify(struct rtl_priv *rtlpriv, u8 *tmp_buf, u8 length) +{ +	exhalbtc92e_bt_info_notify(&gl92e_bt_coexist, tmp_buf, length); +} + +bool rtl92e_btc_is_limited_dig(struct rtl_priv *rtlpriv) +{ +	return gl92e_bt_coexist.bt_info.limited_dig; +} + +bool rtl92e_btc_is_disable_edca_turbo(struct rtl_priv *rtlpriv) +{ +	bool bt_change_edca = false; +	u32 cur_edca_val; +	u32 edca_bt_hs_uplink = 0x5ea42b, edca_bt_hs_downlink = 0x5ea42b; +	u32 edca_hs; +	u32 edca_addr = 0x504; + +	cur_edca_val = rtl_read_dword(rtlpriv, edca_addr); +	if (halbtc92e_is_wifi_uplink(rtlpriv)) { +		if (cur_edca_val != edca_bt_hs_uplink) { +			edca_hs = edca_bt_hs_uplink; +			bt_change_edca = true; +		} +	} else { +		if (cur_edca_val != edca_bt_hs_downlink) { +			edca_hs = edca_bt_hs_downlink; +			bt_change_edca = true; +		} +	} + +	if (bt_change_edca) +		rtl_write_dword(rtlpriv, edca_addr, edca_hs); + +	return true; +} + +bool rtl92e_btc_is_bt_disabled(struct rtl_priv *rtlpriv) +{ +	/* It seems 'bt_disabled' is never be initialized or set. */ +	if (gl92e_bt_coexist.bt_info.bt_disabled) +		return true; +	else +		return false; +} + +void rtl_btc_special_packet_notify(struct rtl_priv *rtlpriv, u8 pkt_type) +{ +	return exhalbtc92e_special_packet_notify(&gl92e_bt_coexist, pkt_type); +} + +struct rtl_btc_ops *stg_rtl_btc_get_ops_pointer(void) +{ +	return &rtl_btc_operation; +} +EXPORT_SYMBOL(stg_rtl_btc_get_ops_pointer); + +u8 rtl92e_get_hwpg_ant_num(struct rtl_priv *rtlpriv) +{ +	u8 num; + +	if (rtlpriv->btcoexist.btc_info.ant_num == ANT_X2) +		num = 2; +	else +		num = 1; + +	return num; +} +u8 rtl92e_get_hwpg_bt_exist(struct rtl_priv *rtlpriv) +{ +	return rtlpriv->btcoexist.btc_info.btcoexist; +} + +u8 rtl92e_get_hwpg_bt_type(struct rtl_priv *rtlpriv) +{ +	return rtlpriv->btcoexist.btc_info.bt_type; +} diff --git a/drivers/staging/rtl8192ee/btcoexist/rtl_btc.h b/drivers/staging/rtl8192ee/btcoexist/rtl_btc.h new file mode 100644 index 00000000000..9530eb1a664 --- /dev/null +++ b/drivers/staging/rtl8192ee/btcoexist/rtl_btc.h @@ -0,0 +1,62 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010  Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __RTL_BTC_H__ +#define __RTL_BTC_H__ + +#include "halbt_precomp.h" + +void rtl92e_btc_init_variables(struct rtl_priv *rtlpriv); +void rtl92e_btc_init_hal_vars(struct rtl_priv *rtlpriv); +void rtl92e_btc_init_hw_config(struct rtl_priv *rtlpriv); +void rtl92e_btc_ips_notify(struct rtl_priv *rtlpriv, u8 type); +void rtl_btc_lps_notify(struct rtl_priv *rtlpriv, u8 type); +void rtl92e_btc_scan_notify(struct rtl_priv *rtlpriv, u8 scantype); +void rtl92e_btc_connect_notify(struct rtl_priv *rtlpriv, u8 action); +void rtl92e_btc_mediastatus_notify(struct rtl_priv *rtlpriv, +				   enum rt_media_status mstatus); +void rtl92e_btc_periodical(struct rtl_priv *rtlpriv); +void rtl92e_btc_halt_notify(void); +void rtl92e_btc_btinfo_notify(struct rtl_priv *rtlpriv, u8 *tmpbuf, u8 length); +bool rtl92e_btc_is_limited_dig(struct rtl_priv *rtlpriv); +bool rtl92e_btc_is_disable_edca_turbo(struct rtl_priv *rtlpriv); +bool rtl92e_btc_is_bt_disabled(struct rtl_priv *rtlpriv); +void rtl_btc_special_packet_notify(struct rtl_priv *rtlpriv, u8 pkt_type); + + +struct rtl_btc_ops *stg_rtl_btc_get_ops_pointer(void); + +u8 rtl92e_get_hwpg_ant_num(struct rtl_priv *rtlpriv); +u8 rtl92e_get_hwpg_bt_exist(struct rtl_priv *rtlpriv); +u8 rtl92e_get_hwpg_bt_type(struct rtl_priv *rtlpriv); +enum rt_media_status mgnt_link_status_query(struct ieee80211_hw *hw); + + + + + + + + +#endif diff --git a/drivers/staging/rtl8192ee/cam.c b/drivers/staging/rtl8192ee/cam.c new file mode 100644 index 00000000000..e32c329da87 --- /dev/null +++ b/drivers/staging/rtl8192ee/cam.c @@ -0,0 +1,337 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010  Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +#include "wifi.h" +#include "cam.h" + +void rtl92e_cam_reset_sec_info(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); + +	rtlpriv->sec.use_defaultkey = false; +	rtlpriv->sec.pairwise_enc_algorithm = NO_ENCRYPTION; +	rtlpriv->sec.group_enc_algorithm = NO_ENCRYPTION; +	memset(rtlpriv->sec.key_buf, 0, KEY_BUF_SIZE * MAX_KEY_LEN); +	memset(rtlpriv->sec.key_len, 0, KEY_BUF_SIZE); +	rtlpriv->sec.pairwise_key = NULL; +} + +static void rtl_cam_program_entry(struct ieee80211_hw *hw, u32 entry_no, +				  u8 *mac_addr, u8 *key_cont_128, u16 us_config) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); + +	u32 target_command; +	u32 target_content = 0; +	u8 entry_i; + +	RT_PRINT_DATA(rtlpriv, COMP_SEC, DBG_DMESG, "Key content:", +		      key_cont_128, 16); + +	for (entry_i = 0; entry_i < CAM_CONTENT_COUNT; entry_i++) { +		target_command = entry_i + CAM_CONTENT_COUNT * entry_no; +		target_command = target_command | BIT(31) | BIT(16); + +		if (entry_i == 0) { +			target_content = (u32) (*(mac_addr + 0)) << 16 | +			    (u32) (*(mac_addr + 1)) << 24 | (u32) us_config; + +			rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[WCAMI], +					target_content); +			rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM], +					target_command); + +			RT_TRACE(COMP_SEC, DBG_LOUD, +				 ("WRITE %x: %x\n", +				  rtlpriv->cfg->maps[WCAMI], target_content)); +			RT_TRACE(COMP_SEC, DBG_LOUD, +				 ("The Key ID is %d\n", entry_no)); +			RT_TRACE(COMP_SEC, DBG_LOUD, +				 ("WRITE %x: %x\n", +				  rtlpriv->cfg->maps[RWCAM], target_command)); +		} else if (entry_i == 1) { +			target_content = (u32) (*(mac_addr + 5)) << 24 | +			    (u32) (*(mac_addr + 4)) << 16 | +			    (u32) (*(mac_addr + 3)) << 8 | +			    (u32) (*(mac_addr + 2)); + +			rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[WCAMI], +					target_content); +			rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM], +					target_command); + +			RT_TRACE(COMP_SEC, DBG_LOUD, +				 ("WRITE A4: %x\n", target_content)); +			RT_TRACE(COMP_SEC, DBG_LOUD, +				 ("WRITE A0: %x\n", target_command)); +		} else { +			target_content = +			    (u32) (*(key_cont_128 + (entry_i * 4 - 8) + 3)) << +			    24 | (u32) (*(key_cont_128 + (entry_i * 4 - 8) + 2)) +			    << 16 | +			    (u32) (*(key_cont_128 + (entry_i * 4 - 8) + 1)) << 8 +			    | (u32) (*(key_cont_128 + (entry_i * 4 - 8) + 0)); + +			rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[WCAMI], +					target_content); +			rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM], +					target_command); +			udelay(100); + +			RT_TRACE(COMP_SEC, DBG_LOUD, +				 ("WRITE A4: %x\n", target_content)); +			RT_TRACE(COMP_SEC, DBG_LOUD, +				 ("WRITE A0: %x\n", target_command)); +		} +	} + +	RT_TRACE(COMP_SEC, DBG_LOUD, +		 ("after set key, usconfig:%x\n", us_config)); +} + +u8 stg_rtl_cam_add_one_entry(struct ieee80211_hw *hw, u8 *mac_addr, +			     u32 ul_key_id, u32 ul_entry_idx, u32 ul_enc_alg, +			     u32 ul_default_key, u8 *key_content) +{ +	u32 us_config; +	struct rtl_priv *rtlpriv = rtl_priv(hw); + +	RT_TRACE(COMP_SEC, DBG_DMESG, +		 ("EntryNo:%x, ulKeyId=%x, ulEncAlg=%x, ulUseDK=%x MacAddr %pM\n", +		  ul_entry_idx, ul_key_id, ul_enc_alg, +		  ul_default_key, mac_addr)); + +	if (ul_key_id == TOTAL_CAM_ENTRY) { +		RT_TRACE(COMP_ERR, DBG_WARNING, +			 ("ulKeyId exceed!\n")); +		return 0; +	} + +	if (ul_default_key == 1) +		us_config = CFG_VALID | ((u16) (ul_enc_alg) << 2); +	else +		us_config = CFG_VALID | ((ul_enc_alg) << 2) | ul_key_id; + +	rtl_cam_program_entry(hw, ul_entry_idx, mac_addr, +			      (u8 *)key_content, us_config); + +	RT_TRACE(COMP_SEC, DBG_DMESG, ("end\n")); + +	return 1; +} +EXPORT_SYMBOL(stg_rtl_cam_add_one_entry); + +int stg_rtl_cam_delete_one_entry(struct ieee80211_hw *hw, +				 u8 *mac_addr, u32 ul_key_id) +{ +	u32 ul_command; +	struct rtl_priv *rtlpriv = rtl_priv(hw); + +	RT_TRACE(COMP_SEC, DBG_DMESG, ("key_idx:%d\n", ul_key_id)); + +	ul_command = ul_key_id * CAM_CONTENT_COUNT; +	ul_command = ul_command | BIT(31) | BIT(16); + +	rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[WCAMI], 0); +	rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM], ul_command); + +	RT_TRACE(COMP_SEC, DBG_DMESG, +		 ("stg_rtl_cam_delete_one_entry(): WRITE A4: %x\n", 0)); +	RT_TRACE(COMP_SEC, DBG_DMESG, +		 ("stg_rtl_cam_delete_one_entry(): WRITE A0: %x\n", +		  ul_command)); +	return 0; +} +EXPORT_SYMBOL(stg_rtl_cam_delete_one_entry); + +void stg_rtl_cam_reset_all_entry(struct ieee80211_hw *hw) +{ +	u32 ul_command; +	struct rtl_priv *rtlpriv = rtl_priv(hw); + +	ul_command = BIT(31) | BIT(30); +	rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM], ul_command); +} +EXPORT_SYMBOL(stg_rtl_cam_reset_all_entry); + +void stg_rtl_cam_mark_invalid(struct ieee80211_hw *hw, u8 uc_index) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); + +	u32 ul_command; +	u32 ul_content; +	u32 ul_enc_algo = rtlpriv->cfg->maps[SEC_CAM_AES]; + +	switch (rtlpriv->sec.pairwise_enc_algorithm) { +	case WEP40_ENCRYPTION: +		ul_enc_algo = rtlpriv->cfg->maps[SEC_CAM_WEP40]; +		break; +	case WEP104_ENCRYPTION: +		ul_enc_algo = rtlpriv->cfg->maps[SEC_CAM_WEP104]; +		break; +	case TKIP_ENCRYPTION: +		ul_enc_algo = rtlpriv->cfg->maps[SEC_CAM_TKIP]; +		break; +	case AESCCMP_ENCRYPTION: +		ul_enc_algo = rtlpriv->cfg->maps[SEC_CAM_AES]; +		break; +	default: +		ul_enc_algo = rtlpriv->cfg->maps[SEC_CAM_AES]; +	} + +	ul_content = (uc_index & 3) | ((u16) (ul_enc_algo) << 2); + +	ul_content |= BIT(15); +	ul_command = CAM_CONTENT_COUNT * uc_index; +	ul_command = ul_command | BIT(31) | BIT(16); + +	rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[WCAMI], ul_content); +	rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM], ul_command); + +	RT_TRACE(COMP_SEC, DBG_DMESG, +		 ("stg_rtl_cam_mark_invalid(): WRITE A4: %x\n", ul_content)); +	RT_TRACE(COMP_SEC, DBG_DMESG, +		 ("stg_rtl_cam_mark_invalid(): WRITE A0: %x\n", ul_command)); +} +EXPORT_SYMBOL(stg_rtl_cam_mark_invalid); + +void stg_rtl_cam_empty_entry(struct ieee80211_hw *hw, u8 uc_index) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); + +	u32 ul_command; +	u32 ul_content; +	u32 ul_encalgo = rtlpriv->cfg->maps[SEC_CAM_AES]; +	u8 entry_i; + +	switch (rtlpriv->sec.pairwise_enc_algorithm) { +	case WEP40_ENCRYPTION: +		ul_encalgo = rtlpriv->cfg->maps[SEC_CAM_WEP40]; +		break; +	case WEP104_ENCRYPTION: +		ul_encalgo = rtlpriv->cfg->maps[SEC_CAM_WEP104]; +		break; +	case TKIP_ENCRYPTION: +		ul_encalgo = rtlpriv->cfg->maps[SEC_CAM_TKIP]; +		break; +	case AESCCMP_ENCRYPTION: +		ul_encalgo = rtlpriv->cfg->maps[SEC_CAM_AES]; +		break; +	default: +		ul_encalgo = rtlpriv->cfg->maps[SEC_CAM_AES]; +	} + +	for (entry_i = 0; entry_i < CAM_CONTENT_COUNT; entry_i++) { +		if (entry_i == 0) { +			ul_content = +			    (uc_index & 0x03) | ((u16) (ul_encalgo) << 2); +			ul_content |= BIT(15); + +		} else { +			ul_content = 0; +		} + +		ul_command = CAM_CONTENT_COUNT * uc_index + entry_i; +		ul_command = ul_command | BIT(31) | BIT(16); + +		rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[WCAMI], ul_content); +		rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM], ul_command); + +		RT_TRACE(COMP_SEC, DBG_LOUD, +			 ("stg_rtl_cam_empty_entry(): WRITE A4: %x\n", +			  ul_content)); +		RT_TRACE(COMP_SEC, DBG_LOUD, +			 ("stg_rtl_cam_empty_entry(): WRITE A0: %x\n", +			  ul_command)); +	} +} +EXPORT_SYMBOL(stg_rtl_cam_empty_entry); + +u8 stg_rtl_cam_get_free_entry(struct ieee80211_hw *hw, u8 *sta_addr) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u32 bitmap = (rtlpriv->sec.hwsec_cam_bitmap) >> 4; +	u8 entry_idx = 0; +	u8 i, *addr; + +	if (!sta_addr) { +		RT_TRACE(COMP_SEC, DBG_EMERG, +			 ("sta_addr is NULL\n")); +		return TOTAL_CAM_ENTRY; +	} +	/* Does STA already exist? */ +	for (i = 4; i < TOTAL_CAM_ENTRY; i++) { +		addr = rtlpriv->sec.hwsec_cam_sta_addr[i]; +		if (memcmp(addr, sta_addr, ETH_ALEN) == 0) +			return i; +	} +	/* Get a free CAM entry. */ +	for (entry_idx = 4; entry_idx < TOTAL_CAM_ENTRY; entry_idx++) { +		if ((bitmap & BIT(0)) == 0) { +			RT_TRACE(COMP_SEC, DBG_EMERG, +				 ("-----hwsec_cam_bitmap: 0x%x entry_idx=%d\n", +					  rtlpriv->sec.hwsec_cam_bitmap, entry_idx)); +			rtlpriv->sec.hwsec_cam_bitmap |= BIT(0) << entry_idx; +			memcpy(rtlpriv->sec.hwsec_cam_sta_addr[entry_idx], +			       sta_addr, ETH_ALEN); +			return entry_idx; +		} +		bitmap = bitmap >> 1; +	} +	return TOTAL_CAM_ENTRY; +} +EXPORT_SYMBOL(stg_rtl_cam_get_free_entry); + +void stg_rtl_cam_del_entry(struct ieee80211_hw *hw, u8 *sta_addr) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u32 bitmap; +	u8 i, *addr; + +	if (NULL == sta_addr) { +		RT_TRACE(COMP_SEC, DBG_EMERG, +			 ("sta_addr is NULL.\n")); +		return; +	} + +	if (is_zero_ether_addr(sta_addr)) { +		RT_TRACE(COMP_SEC, DBG_EMERG, +			 ("sta_addr is 00:00:00:00:00:00.\n")); +		return; +	} +	/* Does STA already exist? */ +	for (i = 4; i < TOTAL_CAM_ENTRY; i++) { +		addr = rtlpriv->sec.hwsec_cam_sta_addr[i]; +		bitmap = (rtlpriv->sec.hwsec_cam_bitmap) >> i; +		if (((bitmap & BIT(0)) == BIT(0)) && +		    (memcmp(addr, sta_addr, ETH_ALEN) == 0)) { +			/* Remove from HW Security CAM */ +			memset(rtlpriv->sec.hwsec_cam_sta_addr[i], 0, ETH_ALEN); +			rtlpriv->sec.hwsec_cam_bitmap &= ~(BIT(0) << i); +			pr_info("&&&&&&&&&del entry %d\n", i); +		} +	} +	return; +} +EXPORT_SYMBOL(stg_rtl_cam_del_entry); diff --git a/drivers/staging/rtl8192ee/cam.h b/drivers/staging/rtl8192ee/cam.h new file mode 100644 index 00000000000..b3a9464e7ed --- /dev/null +++ b/drivers/staging/rtl8192ee/cam.h @@ -0,0 +1,52 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010  Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __RTL_CAM_H_ +#define __RTL_CAM_H_ + +#define CAM_CONTENT_COUNT				8 + +#define CFG_DEFAULT_KEY					BIT(5) +#define CFG_VALID					BIT(15) + +#define PAIRWISE_KEYIDX					0 +#define CAM_PAIRWISE_KEY_POSITION			4 + +#define	CAM_CONFIG_USEDK				1 +#define	CAM_CONFIG_NO_USEDK				0 + +void stg_rtl_cam_reset_all_entry(struct ieee80211_hw *hw); +u8 stg_rtl_cam_add_one_entry(struct ieee80211_hw *hw, u8 *mac_addr, +			     u32 ul_key_id, u32 ul_entry_idx, u32 ul_enc_alg, +			     u32 ul_default_key, u8 *key_content); +int stg_rtl_cam_delete_one_entry(struct ieee80211_hw *hw, u8 *mac_addr, +				 u32 ul_key_id); +void stg_rtl_cam_mark_invalid(struct ieee80211_hw *hw, u8 uc_index); +void stg_rtl_cam_empty_entry(struct ieee80211_hw *hw, u8 uc_index); +void rtl92e_cam_reset_sec_info(struct ieee80211_hw *hw); +u8 stg_rtl_cam_get_free_entry(struct ieee80211_hw *hw, u8 *sta_addr); +void stg_rtl_cam_del_entry(struct ieee80211_hw *hw, u8 *sta_addr); + +#endif diff --git a/drivers/staging/rtl8192ee/compat.h b/drivers/staging/rtl8192ee/compat.h new file mode 100644 index 00000000000..72a3c13afed --- /dev/null +++ b/drivers/staging/rtl8192ee/compat.h @@ -0,0 +1,70 @@ +#ifndef __RTL_COMPAT_H__ +#define __RTL_COMPAT_H__ + + +#define RX_FLAG_MACTIME_MPDU RX_FLAG_MACTIME_START + +#define IEEE80211_KEY_FLAG_SW_MGMT IEEE80211_KEY_FLAG_SW_MGMT_TX + +struct ieee80211_mgmt_compat { +	__le16 frame_control; +	__le16 duration; +	u8 da[6]; +	u8 sa[6]; +	u8 bssid[6]; +	__le16 seq_ctrl; +	union { +		struct { +			u8 category; +			union { +				struct { +					u8 action_code; +					u8 dialog_token; +					u8 status_code; +					u8 variable[0]; +				} __packed wme_action; +				struct { +					u8 action_code; +					u8 dialog_token; +					__le16 capab; +					__le16 timeout; +					__le16 start_seq_num; +				} __packed addba_req; +				struct{ +					u8 action_code; +					u8 dialog_token; +					__le16 status; +					__le16 capab; +					__le16 timeout; +				} __packed addba_resp; +				struct { +					u8 action_code; +					__le16 params; +					__le16 reason_code; +				} __packed delba; +				struct { +					u8 action_code; +					/* capab_info for open and confirm, +					 * reason for close +					 */ +					__le16 aux; +					/* Followed in plink_confirm by status +					 * code, AID and supported rates, +					 * and directly by supported rates in +					 * plink_open and plink_close +					 */ +					u8 variable[0]; +				} __packed plink_action; +				struct { +					u8 action_code; +					u8 variable[0]; +				} __packed mesh_action; +				struct { +					u8 action; +					u8 smps_control; +				} __packed ht_smps; +			} u; +		} __packed action; +	} u; +} __packed; +#endif diff --git a/drivers/staging/rtl8192ee/core.c b/drivers/staging/rtl8192ee/core.c new file mode 100644 index 00000000000..7f6accd5998 --- /dev/null +++ b/drivers/staging/rtl8192ee/core.c @@ -0,0 +1,1600 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010  Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#include "wifi.h" +#include "core.h" +#include "cam.h" +#include "base.h" +#include "ps.h" + +#include "btcoexist/rtl_btc.h" + +/*mutex for start & stop is must here. */ +static int rtl_op_start(struct ieee80211_hw *hw) +{ +	int err = 0; +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + +	if (!is_hal_stop(rtlhal)) +		return 0; +	if (!test_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status)) +		return 0; +	mutex_lock(&rtlpriv->locks.conf_mutex); +	err = rtlpriv->intf_ops->adapter_start(hw); +	if (err) +		goto out; +	rtl92e_watch_dog_timer_callback((unsigned long)hw); + +out: +	mutex_unlock(&rtlpriv->locks.conf_mutex); +	return err; +} + +static void rtl_op_stop(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); +	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); +	bool b_support_remote_wakeup = false; + +	if (is_hal_stop(rtlhal)) +		return; + +	rtlpriv->cfg->ops->get_hw_reg(hw, HAL_DEF_WOWLAN, +				      (u8 *)(&b_support_remote_wakeup)); +	/* here is must, because adhoc do stop and start, +	 * but stop with RFOFF may cause something wrong, +	 * like adhoc TP */ +	if (unlikely(ppsc->rfpwr_state == ERFOFF)) +		rtl92e_ips_nic_on(hw); + +	mutex_lock(&rtlpriv->locks.conf_mutex); +	/* if wowlan supported, DON'T clear connected info */ +	if (!(b_support_remote_wakeup && +	      rtlhal->b_enter_pnp_sleep)) { +		mac->link_state = MAC80211_NOLINK; +		memset(mac->bssid, 0, 6); +		mac->vendor = PEER_UNKNOWN; + +		/* reset sec info */ +		rtl92e_cam_reset_sec_info(hw); + +		rtl92e_deinit_deferred_work(hw); +	} +	rtlpriv->intf_ops->adapter_stop(hw); + +	mutex_unlock(&rtlpriv->locks.conf_mutex); +} + +static void rtl_op_tx(struct ieee80211_hw *hw, +		      struct ieee80211_tx_control *control, +		      struct sk_buff *skb) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); +	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); +	struct rtl_tcb_desc tcb_desc; +	memset(&tcb_desc, 0, sizeof(struct rtl_tcb_desc)); + +	if (unlikely(is_hal_stop(rtlhal) || ppsc->rfpwr_state != ERFON)) +		goto err_free; + +	if (!test_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status)) +		goto err_free; + +	if (!rtlpriv->intf_ops->waitq_insert(hw, control->sta, skb)) +		rtlpriv->intf_ops->adapter_tx(hw, control->sta, skb, &tcb_desc); +	return; + +err_free: +	dev_kfree_skb_any(skb); +	return; +} + +static int rtl_op_add_interface(struct ieee80211_hw *hw, +				struct ieee80211_vif *vif) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +	int err = 0; + +	if (mac->vif) { +		RT_TRACE(COMP_ERR, DBG_WARNING, +			 ("vif has been set!! mac->vif = 0x%p\n", mac->vif)); +		return -EOPNOTSUPP; +	} + +	vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER; + +	rtl92e_ips_nic_on(hw); + +	mutex_lock(&rtlpriv->locks.conf_mutex); +	switch (ieee80211_vif_type_p2p(vif)) { +	case NL80211_IFTYPE_P2P_CLIENT: +		mac->p2p = P2P_ROLE_CLIENT; +		/*fall through*/ +	case NL80211_IFTYPE_STATION: +		if (mac->beacon_enabled == 1) { +			RT_TRACE(COMP_MAC80211, DBG_LOUD, +				 ("NL80211_IFTYPE_STATION\n")); +			mac->beacon_enabled = 0; +			rtlpriv->cfg->ops->update_interrupt_mask(hw, 0, +					rtlpriv->cfg->maps[RTL_IBSS_INT_MASKS]); +		} +		break; +	case NL80211_IFTYPE_ADHOC: +		RT_TRACE(COMP_MAC80211, DBG_LOUD, +			 ("NL80211_IFTYPE_ADHOC\n")); +		mac->link_state = MAC80211_LINKED; +		rtlpriv->cfg->ops->set_bcn_reg(hw); +		if (rtlpriv->rtlhal.current_bandtype == BAND_ON_2_4G) +			mac->basic_rates = 0xfff; +		else +			mac->basic_rates = 0xff0; +		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_BASIC_RATE, +				(u8 *)(&mac->basic_rates)); +		break; +	case NL80211_IFTYPE_P2P_GO: +		mac->p2p = P2P_ROLE_GO; +		/*fall through*/ +	case NL80211_IFTYPE_AP: +		RT_TRACE(COMP_MAC80211, DBG_LOUD, +			 ("NL80211_IFTYPE_AP\n")); + +		mac->link_state = MAC80211_LINKED; +		rtlpriv->cfg->ops->set_bcn_reg(hw); +		if (rtlpriv->rtlhal.current_bandtype == BAND_ON_2_4G) +			mac->basic_rates = 0xfff; +		else +			mac->basic_rates = 0xff0; +		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_BASIC_RATE, +					      (u8 *)(&mac->basic_rates)); +		break; +	case NL80211_IFTYPE_MESH_POINT: +		RT_TRACE(COMP_MAC80211, DBG_LOUD, +			 ("NL80211_IFTYPE_MESH_POINT\n")); + +		mac->link_state = MAC80211_LINKED; +		rtlpriv->cfg->ops->set_bcn_reg(hw); +		if (rtlpriv->rtlhal.current_bandtype == BAND_ON_2_4G) +			mac->basic_rates = 0xfff; +		else +			mac->basic_rates = 0xff0; +		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_BASIC_RATE, +				(u8 *)(&mac->basic_rates)); +		break; +	default: +		RT_TRACE(COMP_ERR, DBG_EMERG, +			 ("operation mode %d is not support!\n", vif->type)); +		err = -EOPNOTSUPP; +		goto out; +	} + +#ifdef VIF_TODO +	if (!rtl_set_vif_info(hw, vif)) +		goto out; +#endif + +	if (mac->p2p) { +		RT_TRACE(COMP_MAC80211, DBG_LOUD, +			 ("p2p role %x\n", vif->type)); +		mac->basic_rates = 0xff0;/*disable cck rate for p2p*/ +		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_BASIC_RATE, +				(u8 *)(&mac->basic_rates)); +	} +	mac->vif = vif; +	mac->opmode = vif->type; +	rtlpriv->cfg->ops->set_network_type(hw, vif->type); +	ether_addr_copy(mac->mac_addr, vif->addr); +	rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_ETHER_ADDR, mac->mac_addr); + +out: +	mutex_unlock(&rtlpriv->locks.conf_mutex); +	return err; +} + +static void rtl_op_remove_interface(struct ieee80211_hw *hw, +				    struct ieee80211_vif *vif) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + +	mutex_lock(&rtlpriv->locks.conf_mutex); + +	/* Free beacon resources */ +	if ((vif->type == NL80211_IFTYPE_AP) || +	    (vif->type == NL80211_IFTYPE_ADHOC) || +	    (vif->type == NL80211_IFTYPE_MESH_POINT)) { +		if (mac->beacon_enabled == 1) { +			mac->beacon_enabled = 0; +			rtlpriv->cfg->ops->update_interrupt_mask(hw, 0, +					rtlpriv->cfg->maps[RTL_IBSS_INT_MASKS]); +		} +	} + +	/* +	 *Note: We assume NL80211_IFTYPE_UNSPECIFIED as +	 *NO LINK for our hardware. +	 */ +	mac->p2p = 0; +	mac->vif = NULL; +	mac->link_state = MAC80211_NOLINK; +	memset(mac->bssid, 0, 6); +	mac->vendor = PEER_UNKNOWN; +	mac->opmode = NL80211_IFTYPE_UNSPECIFIED; +	rtlpriv->cfg->ops->set_network_type(hw, mac->opmode); + +	mutex_unlock(&rtlpriv->locks.conf_mutex); +} +/*<delete in kernel start>*/ +static int rtl_op_change_interface(struct ieee80211_hw *hw, +				   struct ieee80211_vif *vif, +				   enum nl80211_iftype new_type, bool p2p) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	int ret; +	rtl_op_remove_interface(hw, vif); + +	vif->type = new_type; +	vif->p2p = p2p; +	ret = rtl_op_add_interface(hw, vif); +	RT_TRACE(COMP_MAC80211, DBG_LOUD, +		 (" p2p  %x\n", p2p)); +	return ret; +} + +#ifdef CONFIG_PM +static u16 crc16_ccitt(u8 data, u16 crc) +{ +	u8 shift_in, data_bit, crc_bit11, crc_bit4, crc_bit15; +	u8 i; +	u16 result; + +	for (i = 0; i < 8; i++) { +		crc_bit15 = ((crc & BIT(15)) ? 1 : 0); +		data_bit  = (data & (BIT(0) << i) ? 1 : 0); +		shift_in = crc_bit15 ^ data_bit; + +		result = crc << 1; +		if (shift_in == 0) +			result &= (~BIT(0)); +		else +			result |= BIT(0); + +		crc_bit11 = ((crc & BIT(11)) ? 1 : 0) ^ shift_in; +		if (crc_bit11 == 0) +			result &= (~BIT(12)); +		else +			result |= BIT(12); + +		crc_bit4 = ((crc & BIT(4)) ? 1 : 0) ^ shift_in; +		if (crc_bit4 == 0) +			result &= (~BIT(5)); +		else +			result |= BIT(5); + +		crc = result; +	} + +	return crc; +} + +static u16 _calculate_wol_pattern_crc(u8 *pattern, u16 len) +{ +	u16 crc = 0xffff; +	u32 i; + +	for (i = 0; i < len; i++) +		crc = crc16_ccitt(pattern[i], crc); +	crc = ~crc; + +	return crc; +} + +static void _rtl_add_wowlan_patterns(struct ieee80211_hw *hw, +				     struct cfg80211_wowlan *wow) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_mac *mac = &(rtlpriv->mac80211); +	struct cfg80211_pkt_pattern *patterns = wow->patterns; +	struct rtl_wow_pattern rtl_pattern; +	const u8 *pattern_os, *mask_os; +	u8 mask[MAX_WOL_BIT_MASK_SIZE] = {0}; +	u8 content[MAX_WOL_PATTERN_SIZE] = {0}; +	u8 broadcast_addr[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +	u8 multicast_addr1[2] = {0x33, 0x33}; +	u8 multicast_addr2[3] = {0x01, 0x00, 0x5e}; +	u8 i, mask_len; +	u16 j, len; + +	for (i = 0; i < wow->n_patterns; i++) { +		memset(&rtl_pattern, 0, sizeof(struct rtl_wow_pattern)); +		memset(mask, 0, MAX_WOL_BIT_MASK_SIZE); +		if (patterns[i].pattern_len > MAX_WOL_PATTERN_SIZE) { +			RT_TRACE(COMP_POWER, DBG_WARNING, +				 ("Pattern[%d] is too long\n", i)); +			continue; +		} +		pattern_os = patterns[i].pattern; +		mask_len = DIV_ROUND_UP(patterns[i].pattern_len, 8); +		mask_os = patterns[i].mask; +		RT_PRINT_DATA(rtlpriv, COMP_POWER, DBG_TRACE, +			      "pattern content\n", pattern_os, +			      patterns[i].pattern_len); +		RT_PRINT_DATA(rtlpriv, COMP_POWER, DBG_TRACE, +			      "mask content\n", mask_os, mask_len); +		/* 1. unicast? multicast? or broadcast? */ +		if (memcmp(pattern_os, broadcast_addr, 6) == 0) +			rtl_pattern.type = BROADCAST_PATTERN; +		else if (memcmp(pattern_os, multicast_addr1, 2) == 0 || +			 memcmp(pattern_os, multicast_addr2, 3) == 0) +			rtl_pattern.type = MULTICAST_PATTERN; +		else if  (memcmp(pattern_os, mac->mac_addr, 6) == 0) +			rtl_pattern.type = UNICAST_PATTERN; +		else +			rtl_pattern.type = UNKNOWN_TYPE; + +		/* 2. translate mask_from_os to mask_for_hw */ + +/****************************************************************************** + * pattern from OS uses 'ethenet frame', like this: + +		   |    6   |    6   |   2  |     20    |  Variable  |	4  | +		   |--------+--------+------+-----------+------------+-----| +		   |    802.3 Mac Header    | IP Header | TCP Packet | FCS | +		   |   DA   |   SA   | Type | + + * BUT, packet catched by our HW is in '802.11 frame', begin from LLC, + +	|     24 or 30      |    6   |   2  |     20    |  Variable  |  4  | +	|-------------------+--------+------+-----------+------------+-----| +	| 802.11 MAC Header |       LLC     | IP Header | TCP Packet | FCS | +			    | Others | Tpye | + + * Therefore, we need translate mask_from_OS to mask_to_hw. + * We should left-shift mask by 6 bits, then set the new bit[0~5] = 0, + * because new mask[0~5] means 'SA', but our HW packet begins from LLC, + * bit[0~5] corresponds to first 6 Bytes in LLC, they just don't match. + ******************************************************************************/ + +		/* Shift 6 bits */ +		for (j = 0; j < mask_len - 1; j++) { +			mask[j] = mask_os[j] >> 6; +			mask[j] |= (mask_os[j + 1] & 0x3F) << 2; +		} +		mask[j] = (mask_os[j] >> 6) & 0x3F; +		/* Set bit 0-5 to zero */ +		mask[0] &= 0xC0; + +		RT_PRINT_DATA(rtlpriv, COMP_POWER, DBG_TRACE, +			      "mask to hw\n", mask, mask_len); +		for (j = 0; j < (MAX_WOL_BIT_MASK_SIZE + 1) / 4; j++) { +			rtl_pattern.mask[j] = mask[j * 4]; +			rtl_pattern.mask[j] |= (mask[j * 4 + 1] << 8); +			rtl_pattern.mask[j] |= (mask[j * 4 + 2] << 16); +			rtl_pattern.mask[j] |= (mask[j * 4 + 3] << 24); +		} + +		/* To get the wake up pattern from the mask. +		 * We do not count first 12 bits which means +		 * DA[6] and SA[6] in the pattern to match HW design. */ +		len = 0; +		for (j = 12; j < patterns[i].pattern_len; j++) { +			if ((mask_os[j / 8] >> (j % 8)) & 0x01) { +				content[len] = pattern_os[j]; +				len++; +			} +		} + +		RT_PRINT_DATA(rtlpriv, COMP_POWER, DBG_TRACE, +			      "pattern to hw\n", content, len); +		/* 3. calculate crc */ +		rtl_pattern.crc = _calculate_wol_pattern_crc(content, len); +		RT_TRACE(COMP_POWER, DBG_TRACE, +			 ("CRC_Remainder = 0x%x", rtl_pattern.crc)); + +		/* 4. write crc & mask_for_hw to hw */ +		rtlpriv->cfg->ops->add_wowlan_pattern(hw, &rtl_pattern, i); +	} +	rtl_write_byte(rtlpriv, 0x698, wow->n_patterns); +} + +static int rtl_op_suspend(struct ieee80211_hw *hw, +			  struct cfg80211_wowlan *wow) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_hal *rtlhal = rtl_hal(rtlpriv); +	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); +	struct timeval ts; + +	RT_TRACE(COMP_POWER, DBG_DMESG, ("\n")); +	if (WARN_ON(!wow)) +		return -EINVAL; + +	/* to resolve s4 can not wake up*/ +	do_gettimeofday(&ts); +	rtlhal->last_suspend_sec = ts.tv_sec; + +	if ((ppsc->wo_wlan_mode & WAKE_ON_PATTERN_MATCH) && wow->n_patterns) +		_rtl_add_wowlan_patterns(hw, wow); + +	rtlhal->driver_is_goingto_unload = true; +	rtlhal->b_enter_pnp_sleep = true; + +	rtl92e_lps_leave(hw); +	rtl_op_stop(hw); +	device_set_wakeup_enable(wiphy_dev(hw->wiphy), true); +	return 0; +} + +static int rtl_op_resume(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_hal *rtlhal = rtl_hal(rtlpriv); +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +	struct timeval ts; + +	RT_TRACE(COMP_POWER, DBG_DMESG, ("\n")); +	rtlhal->driver_is_goingto_unload = false; +	rtlhal->b_enter_pnp_sleep = false; +	rtlhal->b_wake_from_pnp_sleep = true; + +	/* to resovle s4 can not wake up*/ +	do_gettimeofday(&ts); +	if (ts.tv_sec - rtlhal->last_suspend_sec < 5) +		return -1; + +	rtl_op_start(hw); +	device_set_wakeup_enable(wiphy_dev(hw->wiphy), false); +	ieee80211_resume_disconnect(mac->vif); +	rtlhal->b_wake_from_pnp_sleep = false; +	return 0; +} +#endif + +static int rtl_op_config(struct ieee80211_hw *hw, u32 changed) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); +	struct ieee80211_conf *conf = &hw->conf; + +	if (mac->skip_scan) +		return 1; + + +	mutex_lock(&rtlpriv->locks.conf_mutex); +	if (changed & IEEE80211_CONF_CHANGE_LISTEN_INTERVAL) {	/* BIT(2) */ +		RT_TRACE(COMP_MAC80211, DBG_LOUD, +			 ("IEEE80211_CONF_CHANGE_LISTEN_INTERVAL\n")); +	} + +	/*For IPS */ +	if (changed & IEEE80211_CONF_CHANGE_IDLE) { +		if (hw->conf.flags & IEEE80211_CONF_IDLE) +			rtl92e_ips_nic_off(hw); +		else +			rtl92e_ips_nic_on(hw); +	} else { +		/* +		 *although rfoff may not cause by ips, but we will +		 *check the reason in set_rf_power_state function +		 */ +		if (unlikely(ppsc->rfpwr_state == ERFOFF)) +			rtl92e_ips_nic_on(hw); +	} + +	/*For LPS */ +	if (changed & IEEE80211_CONF_CHANGE_PS) { +		cancel_delayed_work(&rtlpriv->works.ps_work); +		cancel_delayed_work(&rtlpriv->works.ps_rfon_wq); +		if (conf->flags & IEEE80211_CONF_PS) { +			rtlpriv->psc.sw_ps_enabled = true; +			/* sleep here is must, or we may recv the beacon and +			 * cause mac80211 into wrong ps state, this will cause +			 * power save nullfunc send fail, and further cause +			 * pkt loss, So sleep must quickly but not immediatly +			 * because that will cause nullfunc send by mac80211 +			 * fail, and cause pkt loss, we have tested that 5mA +			 * is worked very well */ +			if (!rtlpriv->psc.multi_buffered) +				queue_delayed_work(rtlpriv->works.rtl_wq, +						   &rtlpriv->works.ps_work, +						   MSECS(5)); +		} else { +			rtl92e_swlps_rf_awake(hw); +			rtlpriv->psc.sw_ps_enabled = false; +		} +	} + +	if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS) { +		RT_TRACE(COMP_MAC80211, DBG_LOUD, +			 ("IEEE80211_CONF_CHANGE_RETRY_LIMITS %x\n", +			  hw->conf.long_frame_max_tx_count)); +		mac->retry_long = hw->conf.long_frame_max_tx_count; +		mac->retry_short = hw->conf.long_frame_max_tx_count; +		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RETRY_LIMIT, +				(u8 *)(&hw->conf.long_frame_max_tx_count)); +	} +	if (changed & IEEE80211_CONF_CHANGE_CHANNEL && +	    !rtlpriv->proximity.proxim_on) { +		struct ieee80211_channel *channel = hw->conf.chandef.chan; +		enum nl80211_chan_width width = hw->conf.chandef.width; +		u8 wide_chan = (u8) channel->hw_value; +		enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; + +		/* channel_type is for 20&40M */ +		if (width < NL80211_CHAN_WIDTH_80) +			channel_type = cfg80211_get_chandef_type(&(hw->conf.chandef)); +		if (mac->act_scanning) +			mac->n_channels++; + +		if (rtlpriv->dm.supp_phymode_switch && +		    mac->link_state < MAC80211_LINKED && +		    !mac->act_scanning) { +			if (rtlpriv->cfg->ops->check_switch_to_dmdp) +				rtlpriv->cfg->ops->check_switch_to_dmdp(hw); +		} + +		/* +		 *because we should back channel to +		 *current_network.chan in in scanning, +		 *So if set_chan == current_network.chan +		 *we should set it. +		 *because mac80211 tell us wrong bw40 +		 *info for cisco1253 bw20, so we modify +		 *it here based on UPPER & LOWER +		 */ + +		if (width >= NL80211_CHAN_WIDTH_80) { +			if (width == NL80211_CHAN_WIDTH_80) { +				u32 center_freq = hw->conf.chandef.center_freq1; +				u32 primary_freq = +				(u32)hw->conf.chandef.chan->center_freq; + +				rtlphy->current_chan_bw = +					HT_CHANNEL_WIDTH_80; +				mac->bw_80 = true; +				mac->bw_40 = true; +				if (center_freq > primary_freq) { +					mac->cur_80_prime_sc = +					PRIME_CHNL_OFFSET_LOWER; +					if (center_freq - primary_freq == 10) { +						mac->cur_40_prime_sc = +						PRIME_CHNL_OFFSET_UPPER; + +						wide_chan += 2; +					} else if (center_freq - primary_freq == 30) { +						mac->cur_40_prime_sc = +						PRIME_CHNL_OFFSET_LOWER; + +						wide_chan += 6; +					} +				} else { +					mac->cur_80_prime_sc = +					PRIME_CHNL_OFFSET_UPPER; +					if (primary_freq - center_freq == 10) { +						mac->cur_40_prime_sc = +						PRIME_CHNL_OFFSET_LOWER; + +						wide_chan -= 2; +					} else if (primary_freq - center_freq == 30) { +						mac->cur_40_prime_sc = +						PRIME_CHNL_OFFSET_UPPER; + +						wide_chan -= 6; +					} +				} +			} +		} else { +			switch (channel_type) { +			case NL80211_CHAN_HT20: +			case NL80211_CHAN_NO_HT: +				/* SC */ +				mac->cur_40_prime_sc = +					PRIME_CHNL_OFFSET_DONT_CARE; +				rtlphy->current_chan_bw = +					HT_CHANNEL_WIDTH_20; +				mac->bw_40 = false; +				mac->bw_80 = false; +				break; +			case NL80211_CHAN_HT40MINUS: +				/* SC */ +				mac->cur_40_prime_sc = +					PRIME_CHNL_OFFSET_UPPER; +				rtlphy->current_chan_bw = +					HT_CHANNEL_WIDTH_20_40; +				mac->bw_40 = true; +				mac->bw_80 = false; + +				/*wide channel */ +				wide_chan -= 2; +				break; +			case NL80211_CHAN_HT40PLUS: +				/* SC */ +				mac->cur_40_prime_sc = +					PRIME_CHNL_OFFSET_LOWER; +				rtlphy->current_chan_bw = +					HT_CHANNEL_WIDTH_20_40; +				mac->bw_40 = true; +				mac->bw_80 = false; +				/*wide channel */ +				wide_chan += 2; +				break; +			default: +				mac->bw_40 = false; +				mac->bw_80 = false; +				RT_TRACE(COMP_ERR, DBG_EMERG, +					 ("switch case not processed\n")); +				break; +			} +		} + +		if (wide_chan <= 0) +			wide_chan = 1; + +		/* in scanning, when before we offchannel we may send a ps=1 +		 * null to AP, and then we may send a ps = 0 null to AP quickly, +		 * but first null have cause AP's put lots of packet to hw tx +		 * buffer, these packet must be tx before off channel so we must +		 * delay more time to let AP flush these packets before +		 * offchannel, or dis-association or delete BA will happen by AP +		 */ +		if (rtlpriv->mac80211.offchan_deley) { +			rtlpriv->mac80211.offchan_deley = false; +			mdelay(50); +		} + +		rtlphy->current_channel = wide_chan; + +		rtlpriv->cfg->ops->switch_channel(hw); +		rtlpriv->cfg->ops->set_channel_access(hw); +		rtlpriv->cfg->ops->set_bw_mode(hw, +			channel_type); +	} + +	mutex_unlock(&rtlpriv->locks.conf_mutex); + +	return 0; +} + +static void rtl_op_configure_filter(struct ieee80211_hw *hw, +				    unsigned int changed_flags, +				    unsigned int *new_flags, u64 multicast) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + +	*new_flags &= RTL_SUPPORTED_FILTERS; +	if (0 == changed_flags) +		return; + +	/*TODO: we disable broadcase now, so enable here */ +	if (changed_flags & FIF_ALLMULTI) { +		if (*new_flags & FIF_ALLMULTI) { +			mac->rx_conf |= rtlpriv->cfg->maps[MAC_RCR_AM] | +			    rtlpriv->cfg->maps[MAC_RCR_AB]; +			RT_TRACE(COMP_MAC80211, DBG_LOUD, +				 ("Enable receive multicast frame.\n")); +		} else { +			mac->rx_conf &= ~(rtlpriv->cfg->maps[MAC_RCR_AM] | +					  rtlpriv->cfg->maps[MAC_RCR_AB]); +			RT_TRACE(COMP_MAC80211, DBG_LOUD, +				 ("Disable receive multicast frame.\n")); +		} +	} + +	if (changed_flags & FIF_FCSFAIL) { +		if (*new_flags & FIF_FCSFAIL) { +			mac->rx_conf |= rtlpriv->cfg->maps[MAC_RCR_ACRC32]; +			RT_TRACE(COMP_MAC80211, DBG_LOUD, +				 ("Enable receive FCS error frame.\n")); +		} else { +			mac->rx_conf &= ~rtlpriv->cfg->maps[MAC_RCR_ACRC32]; +			RT_TRACE(COMP_MAC80211, DBG_LOUD, +				 ("Disable receive FCS error frame.\n")); +		} +	} + +	/* if ssid not set to hw don't check bssid +	 * here just used for linked scanning, & linked +	 * and nolink check bssid is set in set network_type */ +	if ((changed_flags & FIF_BCN_PRBRESP_PROMISC) && +	    (mac->link_state >= MAC80211_LINKED)) { +		if (mac->opmode != NL80211_IFTYPE_AP && +		    mac->opmode != NL80211_IFTYPE_MESH_POINT) { +			if (*new_flags & FIF_BCN_PRBRESP_PROMISC) +				rtlpriv->cfg->ops->set_chk_bssid(hw, false); +			else +				rtlpriv->cfg->ops->set_chk_bssid(hw, true); +		} +	} + +	if (changed_flags & FIF_CONTROL) { +		if (*new_flags & FIF_CONTROL) { +			mac->rx_conf |= rtlpriv->cfg->maps[MAC_RCR_ACF]; + +			RT_TRACE(COMP_MAC80211, DBG_LOUD, +				 ("Enable receive control frame.\n")); +		} else { +			mac->rx_conf &= ~rtlpriv->cfg->maps[MAC_RCR_ACF]; +			RT_TRACE(COMP_MAC80211, DBG_LOUD, +				 ("Disable receive control frame.\n")); +		} +	} + +	if (changed_flags & FIF_OTHER_BSS) { +		if (*new_flags & FIF_OTHER_BSS) { +			mac->rx_conf |= rtlpriv->cfg->maps[MAC_RCR_AAP]; +			RT_TRACE(COMP_MAC80211, DBG_LOUD, +				 ("Enable receive other BSS's frame.\n")); +		} else { +			mac->rx_conf &= ~rtlpriv->cfg->maps[MAC_RCR_AAP]; +			RT_TRACE(COMP_MAC80211, DBG_LOUD, +				 ("Disable receive other BSS's frame.\n")); +		} +	} +} +static int rtl_op_sta_add(struct ieee80211_hw *hw, +			  struct ieee80211_vif *vif, +			  struct ieee80211_sta *sta) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +	struct rtl_sta_info *sta_entry; + +	if (sta) { +		sta_entry = (struct rtl_sta_info *)sta->drv_priv; +		spin_lock_bh(&rtlpriv->locks.entry_list_lock); +		list_add_tail(&sta_entry->list, &rtlpriv->entry_list); +		spin_unlock_bh(&rtlpriv->locks.entry_list_lock); +		if (rtlhal->current_bandtype == BAND_ON_2_4G) { +			sta_entry->wireless_mode = WIRELESS_MODE_G; +			if (sta->supp_rates[0] <= 0xf) +				sta_entry->wireless_mode = WIRELESS_MODE_B; +			if (sta->ht_cap.ht_supported) +				sta_entry->wireless_mode = WIRELESS_MODE_N_24G; + +			if (vif->type == NL80211_IFTYPE_ADHOC) +				sta_entry->wireless_mode = WIRELESS_MODE_G; +		} else if (rtlhal->current_bandtype == BAND_ON_5G) { +			sta_entry->wireless_mode = WIRELESS_MODE_A; +			if (sta->ht_cap.ht_supported) +				sta_entry->wireless_mode = WIRELESS_MODE_N_5G; +			if (sta->vht_cap.vht_supported) +				sta_entry->wireless_mode = WIRELESS_MODE_AC_5G; + +			if (vif->type == NL80211_IFTYPE_ADHOC) +				sta_entry->wireless_mode = WIRELESS_MODE_A; +		} +		/*disable cck rate for p2p*/ +		if (mac->p2p) +			sta->supp_rates[0] &= 0xfffffff0; + +		ether_addr_copy(sta_entry->mac_addr, sta->addr); +		RT_TRACE(COMP_MAC80211, DBG_DMESG, +			 ("Add sta addr is %pM\n", sta->addr)); +		rtlpriv->cfg->ops->update_rate_tbl(hw, sta, 0); +	} + +	return 0; +} + +static int rtl_op_sta_remove(struct ieee80211_hw *hw, +			     struct ieee80211_vif *vif, +			     struct ieee80211_sta *sta) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_sta_info *sta_entry; +	if (sta) { +		RT_TRACE(COMP_MAC80211, DBG_DMESG, +			 ("Remove sta addr is %pM\n", sta->addr)); +		sta_entry = (struct rtl_sta_info *)sta->drv_priv; +		sta_entry->wireless_mode = 0; +		sta_entry->ratr_index = 0; +		spin_lock_bh(&rtlpriv->locks.entry_list_lock); +		list_del(&sta_entry->list); +		spin_unlock_bh(&rtlpriv->locks.entry_list_lock); +	} +	return 0; +} +static int _rtl_get_hal_qnum(u16 queue) +{ +	int qnum; + +	switch (queue) { +	case 0: +		qnum = AC3_VO; +		break; +	case 1: +		qnum = AC2_VI; +		break; +	case 2: +		qnum = AC0_BE; +		break; +	case 3: +		qnum = AC1_BK; +		break; +	default: +		qnum = AC0_BE; +		break; +	} +	return qnum; +} + +/* + *for mac80211 VO=0, VI=1, BE=2, BK=3 + *for rtl819x  BE=0, BK=1, VI=2, VO=3 + */ +static int rtl_op_conf_tx(struct ieee80211_hw *hw, +			  struct ieee80211_vif *vif, u16 queue, +			  const struct ieee80211_tx_queue_params *param) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +	int aci; + +	if (queue >= AC_MAX) { +		RT_TRACE(COMP_ERR, DBG_WARNING, +			 ("queue number %d is incorrect!\n", queue)); +		return -EINVAL; +	} + +	aci = _rtl_get_hal_qnum(queue); +	mac->ac[aci].aifs = param->aifs; +	mac->ac[aci].cw_min = cpu_to_le16(param->cw_min); +	mac->ac[aci].cw_max = cpu_to_le16(param->cw_max); +	mac->ac[aci].tx_op = cpu_to_le16(param->txop); +	memcpy(&mac->edca_param[aci], param, sizeof(*param)); +	rtlpriv->cfg->ops->set_qos(hw, aci); +	return 0; +} + +static void rtl_op_bss_info_changed(struct ieee80211_hw *hw, +				    struct ieee80211_vif *vif, +				    struct ieee80211_bss_conf *bss_conf, +				    u32 changed) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_hal *rtlhal = rtl_hal(rtlpriv); +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + +	mutex_lock(&rtlpriv->locks.conf_mutex); +	if ((vif->type == NL80211_IFTYPE_ADHOC) || +	    (vif->type == NL80211_IFTYPE_AP) || +	    (vif->type == NL80211_IFTYPE_MESH_POINT)) { +		if ((changed & BSS_CHANGED_BEACON) || +		    (changed & BSS_CHANGED_BEACON_ENABLED && +		     bss_conf->enable_beacon)) { +			if (mac->beacon_enabled == 0) { +				RT_TRACE(COMP_MAC80211, DBG_DMESG, +					 ("BSS_CHANGED_BEACON_ENABLED\n")); + +				/*start hw beacon interrupt. */ +				/*rtlpriv->cfg->ops->set_bcn_reg(hw); */ +				mac->beacon_enabled = 1; +				rtlpriv->cfg->ops->update_interrupt_mask(hw, +						rtlpriv->cfg->maps +						[RTL_IBSS_INT_MASKS], 0); + +				if (rtlpriv->cfg->ops->linked_set_reg) +					rtlpriv->cfg->ops->linked_set_reg(hw); +			} +		} +		if ((changed & BSS_CHANGED_BEACON_ENABLED) && +		    !bss_conf->enable_beacon) { +			if (mac->beacon_enabled == 1) { +				RT_TRACE(COMP_MAC80211, DBG_DMESG, +					 ("ADHOC DISABLE BEACON\n")); + +				mac->beacon_enabled = 0; +				rtlpriv->cfg->ops->update_interrupt_mask(hw, 0, +						rtlpriv->cfg->maps +						[RTL_IBSS_INT_MASKS]); +			} +		} +		if (changed & BSS_CHANGED_BEACON_INT) { +			RT_TRACE(COMP_BEACON, DBG_TRACE, +				 ("BSS_CHANGED_BEACON_INT\n")); +			mac->beacon_interval = bss_conf->beacon_int; +			rtlpriv->cfg->ops->set_bcn_intv(hw); +		} +	} + +	/*TODO: reference to enum ieee80211_bss_change */ +	if (changed & BSS_CHANGED_ASSOC) { +		u8 mstatus; +		if (bss_conf->assoc) { +			struct ieee80211_sta *sta = NULL; +			u8 keep_alive = 10; + +			mstatus = RT_MEDIA_CONNECT; +			/* we should reset all sec info & cam +			 * before set cam after linked, we should not +			 * reset in disassoc, that will cause tkip->wep +			 * fail because some flag will be wrong */ +			/* reset sec info */ +			rtl92e_cam_reset_sec_info(hw); +			/* reset cam to fix wep fail issue +			 * when change from wpa to wep */ +			stg_rtl_cam_reset_all_entry(hw); + +			mac->link_state = MAC80211_LINKED; +			mac->cnt_after_linked = 0; +			mac->assoc_id = bss_conf->aid; +			memcpy(mac->bssid, bss_conf->bssid, 6); + +			if (rtlpriv->cfg->ops->linked_set_reg) +				rtlpriv->cfg->ops->linked_set_reg(hw); + +			rcu_read_lock(); +			sta = ieee80211_find_sta(vif, (u8 *)bss_conf->bssid); +			if (!sta) { +				pr_err("ieee80211_find_sta returned NULL\n"); +				rcu_read_unlock(); +				goto out; +			} + +			if (vif->type == NL80211_IFTYPE_STATION && sta) +				rtlpriv->cfg->ops->update_rate_tbl(hw, sta, 0); +			RT_TRACE(COMP_EASY_CONCURRENT, DBG_LOUD, +				 ("send PS STATIC frame\n")); +			if (rtlpriv->dm.supp_phymode_switch) { +				if (sta->ht_cap.ht_supported) +					stg_rtl_send_smps_action(hw, sta, +							IEEE80211_SMPS_STATIC); +			} + +			if (rtlhal->current_bandtype == BAND_ON_5G) { +				mac->mode = WIRELESS_MODE_A; +			} else { +				if (sta->supp_rates[0] <= 0xf) +					mac->mode = WIRELESS_MODE_B; +				else +					mac->mode = WIRELESS_MODE_G; +			} + +			if (sta->ht_cap.ht_supported) { +				if (rtlhal->current_bandtype == BAND_ON_2_4G) +					mac->mode = WIRELESS_MODE_N_24G; +				else +					mac->mode = WIRELESS_MODE_N_5G; +			} + +			if (sta->vht_cap.vht_supported) { +				if (rtlhal->current_bandtype == BAND_ON_5G) +					mac->mode = WIRELESS_MODE_AC_5G; +				else +					mac->mode = WIRELESS_MODE_AC_24G; +			} + +			rcu_read_unlock(); + +			/* to avoid AP Disassociation caused by inactivity */ +			rtlpriv->cfg->ops->set_hw_reg(hw, +						      HW_VAR_KEEP_ALIVE, +						      (u8 *)(&keep_alive)); + +			RT_TRACE(COMP_MAC80211, DBG_DMESG, +				 ("BSS_CHANGED_ASSOC\n")); +		} else { +			mstatus = RT_MEDIA_DISCONNECT; + +			if (mac->link_state == MAC80211_LINKED) +				rtl92e_lps_leave(hw); +			if (ppsc->p2p_ps_info.p2p_ps_mode > P2P_PS_NONE) +				rtl92e_p2p_ps_cmd(hw, P2P_PS_DISABLE); +			mac->link_state = MAC80211_NOLINK; +			memset(mac->bssid, 0, 6); +			mac->vendor = PEER_UNKNOWN; +			mac->mode = 0; + +			if (rtlpriv->dm.supp_phymode_switch) { +				if (rtlpriv->cfg->ops->check_switch_to_dmdp) +					rtlpriv->cfg->ops->check_switch_to_dmdp(hw); +			} +			RT_TRACE(COMP_MAC80211, DBG_DMESG, +				 ("BSS_CHANGED_UN_ASSOC\n")); +		} +		rtlpriv->cfg->ops->set_network_type(hw, vif->type); +		/* For FW LPS: +		 * To tell firmware we have connected or disconnected*/ +		rtlpriv->cfg->ops->set_hw_reg(hw, +					      HW_VAR_H2C_FW_JOINBSSRPT, +					      (u8 *)(&mstatus)); +		ppsc->report_linked = (mstatus == RT_MEDIA_CONNECT) ? +				      true : false; + +		if (rtlpriv->cfg->ops->get_btc_status()) +			rtlpriv->btcoexist.btc_ops->btc_mediastatus_notify( +							rtlpriv, mstatus); +	} + +	if (changed & BSS_CHANGED_ERP_CTS_PROT) { +		RT_TRACE(COMP_MAC80211, DBG_TRACE, +			 ("BSS_CHANGED_ERP_CTS_PROT\n")); +		mac->use_cts_protect = bss_conf->use_cts_prot; +	} + +	if (changed & BSS_CHANGED_ERP_PREAMBLE) { +		RT_TRACE(COMP_MAC80211, DBG_LOUD, +			 ("BSS_CHANGED_ERP_PREAMBLE use short preamble:%x\n", +			  bss_conf->use_short_preamble)); + +		mac->short_preamble = bss_conf->use_short_preamble; +		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_ACK_PREAMBLE, +					      (u8 *)(&mac->short_preamble)); +	} + +	if (changed & BSS_CHANGED_ERP_SLOT) { +		RT_TRACE(COMP_MAC80211, DBG_TRACE, +			 ("BSS_CHANGED_ERP_SLOT\n")); + +		if (bss_conf->use_short_slot) +			mac->slot_time = RTL_SLOT_TIME_9; +		else +			mac->slot_time = RTL_SLOT_TIME_20; + +		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SLOT_TIME, +					      (u8 *)(&mac->slot_time)); +	} + +	if (changed & BSS_CHANGED_HT) { +		struct ieee80211_sta *sta = NULL; + +		RT_TRACE(COMP_MAC80211, DBG_TRACE, +			 ("BSS_CHANGED_HT\n")); + +		rcu_read_lock(); +		sta = ieee80211_find_sta(vif, (u8 *)bss_conf->bssid); +		if (sta) { +			if (sta->ht_cap.ampdu_density > +			    mac->current_ampdu_density) +				mac->current_ampdu_density = +				    sta->ht_cap.ampdu_density; +			if (sta->ht_cap.ampdu_factor < +			    mac->current_ampdu_factor) +				mac->current_ampdu_factor = +				    sta->ht_cap.ampdu_factor; +		} +		rcu_read_unlock(); + +		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SHORTGI_DENSITY, +					      (u8 *)(&mac->max_mss_density)); +		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_AMPDU_FACTOR, +					      &mac->current_ampdu_factor); +		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_AMPDU_MIN_SPACE, +					      &mac->current_ampdu_density); +	} + +	if (changed & BSS_CHANGED_BSSID) { +		u32 basic_rates; +		struct ieee80211_sta *sta = NULL; + +		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_BSSID, +					      (u8 *)bss_conf->bssid); + +		RT_TRACE(COMP_MAC80211, DBG_DMESG, +			 ("bssid: %pM\n", bss_conf->bssid)); + +		mac->vendor = PEER_UNKNOWN; +		memcpy(mac->bssid, bss_conf->bssid, 6); + +		rcu_read_lock(); +		sta = ieee80211_find_sta(vif, (u8 *)bss_conf->bssid); +		if (!sta) { +			rcu_read_unlock(); +			goto out; +		} + +		if (rtlhal->current_bandtype == BAND_ON_5G) { +			mac->mode = WIRELESS_MODE_A; +		} else { +			if (sta->supp_rates[0] <= 0xf) +				mac->mode = WIRELESS_MODE_B; +			else +				mac->mode = WIRELESS_MODE_G; +		} + +		if (sta->ht_cap.ht_supported) { +			if (rtlhal->current_bandtype == BAND_ON_2_4G) +				mac->mode = WIRELESS_MODE_N_24G; +			else +				mac->mode = WIRELESS_MODE_N_5G; +		} + +		if (sta->vht_cap.vht_supported) { +			if (rtlhal->current_bandtype == BAND_ON_5G) +				mac->mode = WIRELESS_MODE_AC_5G; +			else +				mac->mode = WIRELESS_MODE_AC_24G; +		} + +		/* just station need it, because ibss & ap mode will +		 * set in sta_add, and will be NULL here */ +		if (vif->type == NL80211_IFTYPE_STATION) { +			struct rtl_sta_info *sta_entry; +			sta_entry = (struct rtl_sta_info *)sta->drv_priv; +			sta_entry->wireless_mode = mac->mode; +		} + +		if (sta->ht_cap.ht_supported) { +			mac->ht_enable = true; + +			/* +			 * for cisco 1252 bw20 it's wrong +			 * if (ht_cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) { +			 *	mac->bw_40 = true; +			 * } +			 * */ +		} + +		if (sta->vht_cap.vht_supported) +			mac->vht_enable = true; + +		if (changed & BSS_CHANGED_BASIC_RATES) { +			/* for 5G must << RATE_6M_INDEX=4, +			 * because 5G have no cck rate*/ +			if (rtlhal->current_bandtype == BAND_ON_5G) +				basic_rates = sta->supp_rates[1] << 4; +			else +				basic_rates = sta->supp_rates[0]; + +			mac->basic_rates = basic_rates; +			rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_BASIC_RATE, +					(u8 *)(&basic_rates)); +		} +		rcu_read_unlock(); +	} +out: +	mutex_unlock(&rtlpriv->locks.conf_mutex); +} + +static u64 rtl_op_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u64 tsf; + +	rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_CORRECT_TSF, (u8 *)(&tsf)); +	return tsf; +} + +static void rtl_op_set_tsf(struct ieee80211_hw *hw, +			   struct ieee80211_vif *vif, u64 tsf) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +	u8 bibss = (mac->opmode == NL80211_IFTYPE_ADHOC) ? 1 : 0; + +	mac->tsf = tsf; +	rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_CORRECT_TSF, (u8 *)(&bibss)); +} + +static void rtl_op_reset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u8 tmp = 0; + +	rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_DUAL_TSF_RST, (u8 *)(&tmp)); +} + +static void rtl_op_sta_notify(struct ieee80211_hw *hw, +			      struct ieee80211_vif *vif, +			      enum sta_notify_cmd cmd, +			      struct ieee80211_sta *sta) +{ +	switch (cmd) { +	case STA_NOTIFY_SLEEP: +		break; +	case STA_NOTIFY_AWAKE: +		break; +	default: +		break; +	} +} + +static int rtl_op_ampdu_action(struct ieee80211_hw *hw, +			       struct ieee80211_vif *vif, +			       enum ieee80211_ampdu_mlme_action action, +			       struct ieee80211_sta *sta, u16 tid, u16 *ssn, +			       u8 buf_size) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); + +	switch (action) { +	case IEEE80211_AMPDU_TX_START: +		RT_TRACE(COMP_MAC80211, DBG_TRACE, +			 ("IEEE80211_AMPDU_TX_START: TID:%d\n", tid)); +		return rtl92e_tx_agg_start(hw, vif, sta, tid, ssn); +		break; +	case IEEE80211_AMPDU_TX_STOP_CONT: +	case IEEE80211_AMPDU_TX_STOP_FLUSH: +	case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: +		RT_TRACE(COMP_MAC80211, DBG_TRACE, +			 ("IEEE80211_AMPDU_TX_STOP: TID:%d\n", tid)); +		return rtl92e_tx_agg_stop(hw, vif, sta, tid); +		break; +	case IEEE80211_AMPDU_TX_OPERATIONAL: +		RT_TRACE(COMP_MAC80211, DBG_TRACE, +			 ("IEEE80211_AMPDU_TX_OPERATIONAL:TID:%d\n", tid)); +		rtl92e_tx_agg_oper(hw, sta, tid); +		break; +	case IEEE80211_AMPDU_RX_START: +		RT_TRACE(COMP_MAC80211, DBG_TRACE, +			 ("IEEE80211_AMPDU_RX_START:TID:%d\n", tid)); +		return rtl92e_rx_agg_start(hw, sta, tid); +		break; +	case IEEE80211_AMPDU_RX_STOP: +		RT_TRACE(COMP_MAC80211, DBG_TRACE, +			 ("IEEE80211_AMPDU_RX_STOP:TID:%d\n", tid)); +		return rtl92e_rx_agg_stop(hw, sta, tid); +		break; +	default: +		RT_TRACE(COMP_ERR, DBG_EMERG, +			 ("IEEE80211_AMPDU_ERR!!!!:\n")); +		return -EOPNOTSUPP; +	} +	return 0; +} + +static void rtl_op_sw_scan_start(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + +	RT_TRACE(COMP_MAC80211, DBG_LOUD, ("\n")); +	mac->act_scanning = true; +	if (rtlpriv->link_info.b_higher_busytraffic) { +		mac->skip_scan = true; +		return; +	} + +	if (rtlpriv->cfg->ops->get_btc_status()) +		rtlpriv->btcoexist.btc_ops->btc_scan_notify(rtlpriv, 1); + +	if (rtlpriv->dm.supp_phymode_switch) { +		if (rtlpriv->cfg->ops->check_switch_to_dmdp) +			rtlpriv->cfg->ops->check_switch_to_dmdp(hw); +	} + +	if (mac->link_state == MAC80211_LINKED) { +		rtl92e_lps_leave(hw); +		mac->link_state = MAC80211_LINKED_SCANNING; +	} else { +		rtl92e_ips_nic_on(hw); +	} + +	/* Dul mac */ +	rtlpriv->rtlhal.b_load_imrandiqk_setting_for2g = false; + +	rtlpriv->cfg->ops->led_control(hw, LED_CTL_SITE_SURVEY); +	rtlpriv->cfg->ops->scan_operation_backup(hw, SCAN_OPT_BACKUP_BAND0); +} + +static void rtl_op_sw_scan_complete(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + +	RT_TRACE(COMP_MAC80211, DBG_LOUD, ("\n")); +	mac->act_scanning = false; +	mac->skip_scan = false; +	if (rtlpriv->link_info.b_higher_busytraffic) +		return; + +	/* p2p will use 1/6/11 to scan */ +	if (mac->n_channels == 3) +		mac->p2p_in_use = true; +	else +		mac->p2p_in_use = false; +	mac->n_channels = 0; +	/* Dul mac */ +	rtlpriv->rtlhal.b_load_imrandiqk_setting_for2g = false; + +	if (mac->link_state == MAC80211_LINKED_SCANNING) { +		mac->link_state = MAC80211_LINKED; +		if (mac->opmode == NL80211_IFTYPE_STATION) { +			/* fix fwlps issue */ +			rtlpriv->cfg->ops->set_network_type(hw, mac->opmode); +		} +	} + +	rtlpriv->cfg->ops->scan_operation_backup(hw, SCAN_OPT_RESTORE); +	if (rtlpriv->cfg->ops->get_btc_status()) +		rtlpriv->btcoexist.btc_ops->btc_scan_notify(rtlpriv, 0); +} + +static int rtl_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, +			  struct ieee80211_vif *vif, struct ieee80211_sta *sta, +			  struct ieee80211_key_conf *key) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u8 key_type = NO_ENCRYPTION; +	u8 key_idx; +	bool group_key = false; +	bool wep_only = false; +	int err = 0; +	u8 mac_addr[ETH_ALEN]; +	u8 bcast_addr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + +	if (rtlpriv->cfg->mod_params->sw_crypto || rtlpriv->sec.use_sw_sec) { +		RT_TRACE(COMP_ERR, DBG_WARNING, +			 ("not open hw encryption\n")); +		return -ENOSPC;	/*User disabled HW-crypto */ +	} +	/* To support IBSS, use sw-crypto for GTK */ +	if (((vif->type == NL80211_IFTYPE_ADHOC) || +	     (vif->type == NL80211_IFTYPE_MESH_POINT)) && +	     !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) +		return -ENOSPC; +	RT_TRACE(COMP_SEC, DBG_DMESG, +		 ("%s hardware based encryption for keyidx: %d, mac: %pM\n", +		  cmd == SET_KEY ? "Using" : "Disabling", key->keyidx, +		  sta ? sta->addr : bcast_addr)); +	rtlpriv->sec.being_setkey = true; +	rtl92e_ips_nic_on(hw); +	mutex_lock(&rtlpriv->locks.conf_mutex); +	/* <1> get encryption alg */ + +	switch (key->cipher) { +	case WLAN_CIPHER_SUITE_WEP40: +		key_type = WEP40_ENCRYPTION; +		RT_TRACE(COMP_SEC, DBG_DMESG, ("alg:WEP40\n")); +		break; +	case WLAN_CIPHER_SUITE_WEP104: +		RT_TRACE(COMP_SEC, DBG_DMESG, ("alg:WEP104\n")); +		key_type = WEP104_ENCRYPTION; +		break; +	case WLAN_CIPHER_SUITE_TKIP: +		key_type = TKIP_ENCRYPTION; +		RT_TRACE(COMP_SEC, DBG_DMESG, ("alg:TKIP\n")); +		break; +	case WLAN_CIPHER_SUITE_CCMP: +		key_type = AESCCMP_ENCRYPTION; +		RT_TRACE(COMP_SEC, DBG_DMESG, ("alg:CCMP\n")); +		break; +	case WLAN_CIPHER_SUITE_AES_CMAC: +		/* HW don't support CMAC encryption, +		 * use software CMAC encryption */ +		key_type = AESCMAC_ENCRYPTION; +		RT_TRACE(COMP_SEC, DBG_DMESG, ("alg:CMAC\n")); +		RT_TRACE(COMP_SEC, DBG_DMESG, +			 ("HW don't support CMAC encrypiton, use software CMAC encryption\n")); +		err = -EOPNOTSUPP; +		goto out_unlock; +	default: +		RT_TRACE(COMP_ERR, DBG_EMERG, +			 ("alg_err:%x!!!!:\n", key->cipher)); +		goto out_unlock; +	} +	if (key_type == WEP40_ENCRYPTION || +	    key_type == WEP104_ENCRYPTION || +	    vif->type == NL80211_IFTYPE_ADHOC) +		rtlpriv->sec.use_defaultkey = true; + +	/* <2> get key_idx */ +	key_idx = (u8) (key->keyidx); +	if (key_idx > 3) +		goto out_unlock; +	/* <3> if pairwise key enable_hw_sec */ +	group_key = !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE); + +	/* wep always be group key, but there are two conditions: +	 * 1) wep only: is just for wep enc, in this condition +	 * rtlpriv->sec.pairwise_enc_algorithm == NO_ENCRYPTION +	 * will be true & enable_hw_sec will be set when wep +	 * ke setting. +	 * 2) wep(group) + AES(pairwise): some AP like cisco +	 * may use it, in this condition enable_hw_sec will not +	 * be set when wep key setting */ +	/* we must reset sec_info after lingked before set key, +	 * or some flag will be wrong*/ +	if (vif->type == NL80211_IFTYPE_AP || +	    vif->type == NL80211_IFTYPE_MESH_POINT) { +		if (!group_key || key_type == WEP40_ENCRYPTION || +		    key_type == WEP104_ENCRYPTION) { +			if (group_key) +				wep_only = true; +			rtlpriv->cfg->ops->enable_hw_sec(hw); +		} +	} else { +		if ((!group_key) || (vif->type == NL80211_IFTYPE_ADHOC) || +		    rtlpriv->sec.pairwise_enc_algorithm == NO_ENCRYPTION) { +			if (rtlpriv->sec.pairwise_enc_algorithm == +			    NO_ENCRYPTION && +			   (key_type == WEP40_ENCRYPTION || +			    key_type == WEP104_ENCRYPTION)) +				wep_only = true; +			rtlpriv->sec.pairwise_enc_algorithm = key_type; +			RT_TRACE(COMP_SEC, DBG_DMESG, +				 ("set enable_hw_sec, key_type:%x(OPEN:0 WEP40:1 TKIP:2 AES:4 WEP104:5)\n", +				  key_type)); +			rtlpriv->cfg->ops->enable_hw_sec(hw); +		} +	} +	/* <4> set key based on cmd */ +	switch (cmd) { +	case SET_KEY: +		if (wep_only) { +			RT_TRACE(COMP_SEC, DBG_DMESG, +				 ("set WEP(group/pairwise) key\n")); +			/* Pairwise key with an assigned MAC address. */ +			rtlpriv->sec.pairwise_enc_algorithm = key_type; +			rtlpriv->sec.group_enc_algorithm = key_type; +			/*set local buf about wep key. */ +			memcpy(rtlpriv->sec.key_buf[key_idx], +			       key->key, key->keylen); +			rtlpriv->sec.key_len[key_idx] = key->keylen; +			eth_zero_addr(mac_addr); +		} else if (group_key) {	/* group key */ +			RT_TRACE(COMP_SEC, DBG_DMESG, +				 ("set group key\n")); +			/* group key */ +			rtlpriv->sec.group_enc_algorithm = key_type; +			/*set local buf about group key. */ +			memcpy(rtlpriv->sec.key_buf[key_idx], +			       key->key, key->keylen); +			rtlpriv->sec.key_len[key_idx] = key->keylen; +			ether_addr_copy(mac_addr, bcast_addr); +		} else {	/* pairwise key */ +			RT_TRACE(COMP_SEC, DBG_DMESG, +				 ("set pairwise key\n")); +			if (!sta) { +				RT_ASSERT(false, +					  ("pairwise key without mac_addr\n")); + +				err = -EOPNOTSUPP; +				goto out_unlock; +			} +			/* Pairwise key with an assigned MAC address. */ +			rtlpriv->sec.pairwise_enc_algorithm = key_type; +			/*set local buf about pairwise key. */ +			memcpy(rtlpriv->sec.key_buf[PAIRWISE_KEYIDX], +			       key->key, key->keylen); +			rtlpriv->sec.key_len[PAIRWISE_KEYIDX] = key->keylen; +			rtlpriv->sec.pairwise_key = +			    rtlpriv->sec.key_buf[PAIRWISE_KEYIDX]; +			ether_addr_copy(mac_addr, sta->addr); +		} +		rtlpriv->cfg->ops->set_key(hw, key_idx, mac_addr, +					   group_key, key_type, wep_only, +					   false); +		/* <5> tell mac80211 do something: */ +		/*must use sw generate IV, or can not work !!!!. */ +		key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; +		key->hw_key_idx = key_idx; +		if (key_type == TKIP_ENCRYPTION) +			key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; +		/*use software CCMP encryption for management frames (MFP) */ +		if (key_type == AESCCMP_ENCRYPTION) +			key->flags |= IEEE80211_KEY_FLAG_SW_MGMT; +		break; +	case DISABLE_KEY: +		RT_TRACE(COMP_SEC, DBG_DMESG, +			 ("disable key delete one entry\n")); +		/*set local buf about wep key. */ +		if (vif->type == NL80211_IFTYPE_AP || +		    vif->type == NL80211_IFTYPE_MESH_POINT) { +			if (sta) +				stg_rtl_cam_del_entry(hw, sta->addr); +		} +		memset(rtlpriv->sec.key_buf[key_idx], 0, key->keylen); +		rtlpriv->sec.key_len[key_idx] = 0; +		eth_zero_addr(mac_addr); +		/* +		 *mac80211 will delete entrys one by one, +		 *so don't use stg_rtl_cam_reset_all_entry +		 *or clear all entry here. +		 */ +		stg_rtl_cam_delete_one_entry(hw, mac_addr, key_idx); +		break; +	default: +		RT_TRACE(COMP_ERR, DBG_EMERG, +			 ("cmd_err:%x!!!!:\n", cmd)); +	} +out_unlock: +	mutex_unlock(&rtlpriv->locks.conf_mutex); +	rtlpriv->sec.being_setkey = false; +	return err; +} + +static void rtl_op_rfkill_poll(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); + +	bool radio_state; +	bool blocked; +	u8 valid = 0; + +	if (!test_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status)) +		return; + +	mutex_lock(&rtlpriv->locks.conf_mutex); + +	/*if Radio On return true here */ +	radio_state = rtlpriv->cfg->ops->radio_onoff_checking(hw, &valid); + +	if (valid) { +		if (unlikely(radio_state != rtlpriv->rfkill.rfkill_state)) { +			rtlpriv->rfkill.rfkill_state = radio_state; + +			RT_TRACE(COMP_RF, DBG_DMESG, +				 (KERN_INFO "wireless radio switch turned %s\n", +				  radio_state ? "on" : "off")); + +			blocked = (rtlpriv->rfkill.rfkill_state == 1) ? 0 : 1; +			wiphy_rfkill_set_hw_state(hw->wiphy, blocked); +		} +	} + +	mutex_unlock(&rtlpriv->locks.conf_mutex); +} + +/* this function is called by mac80211 to flush tx buffer + * before switch channle or power save, or tx buffer packet + * maybe send after offchannel or rf sleep, this may cause + * dis-association by AP */ +static void rtl_op_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, +			 u32 queues, bool drop) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); + +	if (rtlpriv->intf_ops->flush) +		rtlpriv->intf_ops->flush(hw, queues, drop); +} + +const struct ieee80211_ops rtl92e_ops = { +	.start = rtl_op_start, +	.stop = rtl_op_stop, +	.tx = rtl_op_tx, +	.add_interface = rtl_op_add_interface, +	.remove_interface = rtl_op_remove_interface, +	.change_interface = rtl_op_change_interface, +#ifdef CONFIG_PM +	.suspend = rtl_op_suspend, +	.resume = rtl_op_resume, +#endif +	.config = rtl_op_config, +	.configure_filter = rtl_op_configure_filter, +	.set_key = rtl_op_set_key, +	.conf_tx = rtl_op_conf_tx, +	.bss_info_changed = rtl_op_bss_info_changed, +	.get_tsf = rtl_op_get_tsf, +	.set_tsf = rtl_op_set_tsf, +	.reset_tsf = rtl_op_reset_tsf, +	.sta_notify = rtl_op_sta_notify, +	.ampdu_action = rtl_op_ampdu_action, +	.sw_scan_start = rtl_op_sw_scan_start, +	.sw_scan_complete = rtl_op_sw_scan_complete, +	.rfkill_poll = rtl_op_rfkill_poll, +	.sta_add = rtl_op_sta_add, +	.sta_remove = rtl_op_sta_remove, +	.flush = rtl_op_flush, +}; diff --git a/drivers/staging/rtl8192ee/core.h b/drivers/staging/rtl8192ee/core.h new file mode 100644 index 00000000000..ef75ad5f029 --- /dev/null +++ b/drivers/staging/rtl8192ee/core.h @@ -0,0 +1,39 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010  Realtek Corporation. + * + * Tmis program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * Tme full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __RTL_CORE_H__ +#define __RTL_CORE_H__ + +#define RTL_SUPPORTED_FILTERS		\ +	(FIF_PROMISC_IN_BSS | \ +	FIF_ALLMULTI | FIF_CONTROL | \ +	FIF_OTHER_BSS | \ +	FIF_FCSFAIL | \ +	FIF_BCN_PRBRESP_PROMISC) + +#define RTL_SUPPORTED_CTRL_FILTER	0xFF + +extern const struct ieee80211_ops rtl92e_ops; +#endif diff --git a/drivers/staging/rtl8192ee/debug.c b/drivers/staging/rtl8192ee/debug.c new file mode 100644 index 00000000000..feec3948585 --- /dev/null +++ b/drivers/staging/rtl8192ee/debug.c @@ -0,0 +1,978 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010  Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * Tmis program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#include "wifi.h" +#include "cam.h" + +#define GET_INODE_DATA(__node)		PDE_DATA(__node) + + +void rtl92e_dbgp_flag_init(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u8 i; + +	rtlpriv->dbg.global_debuglevel = DBG_DMESG; + +	rtlpriv->dbg.global_debugcomponents = +		COMP_ERR | +		COMP_FW | +		COMP_INIT | +		COMP_RECV | +		COMP_SEND | +		COMP_MLME | +		COMP_SCAN | +		COMP_INTR | +		COMP_LED | +		COMP_SEC | +		COMP_BEACON | +		COMP_RATE | +		COMP_RXDESC | +		COMP_DIG | +		COMP_TXAGC | +		COMP_POWER | +		COMP_POWER_TRACKING | +		COMP_BB_POWERSAVING | +		COMP_SWAS | +		COMP_RF | +		COMP_TURBO | +		COMP_RATR | +		COMP_CMD | +		COMP_EASY_CONCURRENT | +		COMP_EFUSE | +		COMP_QOS | COMP_MAC80211 | COMP_REGD | +		COMP_CHAN | +		COMP_BT_COEXIST | +		COMP_IQK | +		0; + +	for (i = 0; i < DBGP_TYPE_MAX; i++) +		rtlpriv->dbg.dbgp_type[i] = 0; + +	/*Init Debug flag enable condition */ +} + +static struct proc_dir_entry *proc_topdir; + +static int rtl_proc_get_mac_0(struct seq_file *m, void *v) +{ +	struct ieee80211_hw *hw = m->private; +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	int i, n, page; +	int max = 0xff; +	page = 0x000; + +	for (n = 0; n <= max; ) { +		seq_printf(m, "\n%8.8x  ", n + page); +		for (i = 0; i < 4 && n <= max; i++, n += 4) +			seq_printf(m, "%8.8x    ", +				   rtl_read_dword(rtlpriv, (page | n))); +	} +	seq_puts(m, "\n"); +	return 0; +} + +static int dl_proc_open_mac_0(struct inode *inode, struct file *file) +{ +	return single_open(file, rtl_proc_get_mac_0, GET_INODE_DATA(inode)); +} + +static const struct file_operations file_ops_mac_0 = { +	.open = dl_proc_open_mac_0, +	.read = seq_read, +	.llseek = seq_lseek, +	.release = seq_release, +}; + +static int rtl_proc_get_mac_1(struct seq_file *m, void *v) +{ +	struct ieee80211_hw *hw = m->private; +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	int i, n, page; +	int max = 0xff; +	page = 0x100; + +	for (n = 0; n <= max; ) { +		seq_printf(m, "\n%8.8x  ", n + page); +		for (i = 0; i < 4 && n <= max; i++, n += 4) +			seq_printf(m, "%8.8x    ", +				   rtl_read_dword(rtlpriv, (page | n))); +	} +	seq_puts(m, "\n"); +	return 0; +} + +static int dl_proc_open_mac_1(struct inode *inode, struct file *file) +{ +	return single_open(file, rtl_proc_get_mac_1, GET_INODE_DATA(inode)); +} + +static const struct file_operations file_ops_mac_1 = { +	.open = dl_proc_open_mac_1, +	.read = seq_read, +	.llseek = seq_lseek, +	.release = seq_release, +}; + +static int rtl_proc_get_mac_2(struct seq_file *m, void *v) +{ +	struct ieee80211_hw *hw = m->private; +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	int i, n, page; +	int max = 0xff; +	page = 0x200; + +	for (n = 0; n <= max; ) { +		seq_printf(m, "\n%8.8x  ", n + page); +		for (i = 0; i < 4 && n <= max; i++, n += 4) +			seq_printf(m, "%8.8x    ", +				   rtl_read_dword(rtlpriv, (page | n))); +	} +	seq_puts(m, "\n"); +	return 0; +} + +static int dl_proc_open_mac_2(struct inode *inode, struct file *file) +{ +	return single_open(file, rtl_proc_get_mac_2, GET_INODE_DATA(inode)); +} + +static const struct file_operations file_ops_mac_2 = { +	.open = dl_proc_open_mac_2, +	.read = seq_read, +	.llseek = seq_lseek, +	.release = seq_release, +}; + +static int rtl_proc_get_mac_3(struct seq_file *m, void *v) +{ +	struct ieee80211_hw *hw = m->private; +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	int i, n, page; +	int max = 0xff; +	page = 0x300; + +	for (n = 0; n <= max; ) { +		seq_printf(m, "\n%8.8x  ", n + page); +		for (i = 0; i < 4 && n <= max; i++, n += 4) +			seq_printf(m, "%8.8x    ", +				   rtl_read_dword(rtlpriv, (page | n))); +	} +	seq_puts(m, "\n"); +	return 0; +} + +static int dl_proc_open_mac_3(struct inode *inode, struct file *file) +{ +	return single_open(file, rtl_proc_get_mac_3, GET_INODE_DATA(inode)); +} + +static const struct file_operations file_ops_mac_3 = { +	.open = dl_proc_open_mac_3, +	.read = seq_read, +	.llseek = seq_lseek, +	.release = seq_release, +}; + +static int rtl_proc_get_mac_4(struct seq_file *m, void *v) +{ +	struct ieee80211_hw *hw = m->private; +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	int i, n, page; +	int max = 0xff; +	page = 0x400; + +	for (n = 0; n <= max; ) { +		seq_printf(m, "\n%8.8x  ", n + page); +		for (i = 0; i < 4 && n <= max; i++, n += 4) +			seq_printf(m, "%8.8x    ", +				   rtl_read_dword(rtlpriv, (page | n))); +	} +	seq_puts(m, "\n"); +	return 0; +} + +static int dl_proc_open_mac_4(struct inode *inode, struct file *file) +{ +	return single_open(file, rtl_proc_get_mac_4, GET_INODE_DATA(inode)); +} + +static const struct file_operations file_ops_mac_4 = { +	.open = dl_proc_open_mac_4, +	.read = seq_read, +	.llseek = seq_lseek, +	.release = seq_release, +}; + +static int rtl_proc_get_mac_5(struct seq_file *m, void *v) +{ +	struct ieee80211_hw *hw = m->private; +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	int i, n, page; +	int max = 0xff; +	page = 0x500; + +	for (n = 0; n <= max; ) { +		seq_printf(m, "\n%8.8x  ", n + page); +		for (i = 0; i < 4 && n <= max; i++, n += 4) +			seq_printf(m, "%8.8x    ", +				   rtl_read_dword(rtlpriv, (page | n))); +	} +	seq_puts(m, "\n"); +	return 0; +} + +static int dl_proc_open_mac_5(struct inode *inode, struct file *file) +{ +	return single_open(file, rtl_proc_get_mac_5, GET_INODE_DATA(inode)); +} + +static const struct file_operations file_ops_mac_5 = { +	.open = dl_proc_open_mac_5, +	.read = seq_read, +	.llseek = seq_lseek, +	.release = seq_release, +}; + +static int rtl_proc_get_mac_6(struct seq_file *m, void *v) +{ +	struct ieee80211_hw *hw = m->private; +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	int i, n, page; +	int max = 0xff; +	page = 0x600; + +	for (n = 0; n <= max; ) { +		seq_printf(m, "\n%8.8x  ", n + page); +		for (i = 0; i < 4 && n <= max; i++, n += 4) +			seq_printf(m, "%8.8x    ", +				   rtl_read_dword(rtlpriv, (page | n))); +	} +	seq_puts(m, "\n"); +	return 0; +} + +static int dl_proc_open_mac_6(struct inode *inode, struct file *file) +{ +	return single_open(file, rtl_proc_get_mac_6, GET_INODE_DATA(inode)); +} + +static const struct file_operations file_ops_mac_6 = { +	.open = dl_proc_open_mac_6, +	.read = seq_read, +	.llseek = seq_lseek, +	.release = seq_release, +}; + +static int rtl_proc_get_mac_7(struct seq_file *m, void *v) +{ +	struct ieee80211_hw *hw = m->private; +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	int i, n, page; +	int max = 0xff; +	page = 0x700; + +	for (n = 0; n <= max; ) { +		seq_printf(m, "\n%8.8x  ", n + page); +		for (i = 0; i < 4 && n <= max; i++, n += 4) +			seq_printf(m, "%8.8x    ", +				   rtl_read_dword(rtlpriv, (page | n))); +	} +	seq_puts(m, "\n"); +	return 0; +} + +static int dl_proc_open_mac_7(struct inode *inode, struct file *file) +{ +	return single_open(file, rtl_proc_get_mac_7, GET_INODE_DATA(inode)); +} + +static const struct file_operations file_ops_mac_7 = { +	.open = dl_proc_open_mac_7, +	.read = seq_read, +	.llseek = seq_lseek, +	.release = seq_release, +}; + +static int rtl_proc_get_bb_8(struct seq_file *m, void *v) +{ +	struct ieee80211_hw *hw = m->private; +	int i, n, page; +	int max = 0xff; +	page = 0x800; + +	for (n = 0; n <= max; ) { +		seq_printf(m, "\n%8.8x  ", n + page); +		for (i = 0; i < 4 && n <= max; i++, n += 4) +			seq_printf(m, "%8.8x    ", +				   rtl_get_bbreg(hw, (page | n), 0xffffffff)); +	} +	seq_puts(m, "\n"); +	return 0; +} + +static int dl_proc_open_bb_8(struct inode *inode, struct file *file) +{ +	return single_open(file, rtl_proc_get_bb_8, GET_INODE_DATA(inode)); +} + +static const struct file_operations file_ops_bb_8 = { +	.open = dl_proc_open_bb_8, +	.read = seq_read, +	.llseek = seq_lseek, +	.release = seq_release, +}; + +static int rtl_proc_get_bb_9(struct seq_file *m, void *v) +{ +	struct ieee80211_hw *hw = m->private; +	int i, n, page; +	int max = 0xff; +	page = 0x900; + +	for (n = 0; n <= max; ) { +		seq_printf(m, "\n%8.8x  ", n + page); +		for (i = 0; i < 4 && n <= max; i++, n += 4) +			seq_printf(m, "%8.8x    ", +				   rtl_get_bbreg(hw, (page | n), 0xffffffff)); +	} +	seq_puts(m, "\n"); +	return 0; +} + +static int dl_proc_open_bb_9(struct inode *inode, struct file *file) +{ +	return single_open(file, rtl_proc_get_bb_9, GET_INODE_DATA(inode)); +} + +static const struct file_operations file_ops_bb_9 = { +	.open = dl_proc_open_bb_9, +	.read = seq_read, +	.llseek = seq_lseek, +	.release = seq_release, +}; + +static int rtl_proc_get_bb_a(struct seq_file *m, void *v) +{ +	struct ieee80211_hw *hw = m->private; +	int i, n, page; +	int max = 0xff; +	page = 0xa00; + +	for (n = 0; n <= max; ) { +		seq_printf(m, "\n%8.8x  ", n + page); +		for (i = 0; i < 4 && n <= max; i++, n += 4) +			seq_printf(m, "%8.8x    ", +				   rtl_get_bbreg(hw, (page | n), 0xffffffff)); +	} +	seq_puts(m, "\n"); +	return 0; +} + +static int dl_proc_open_bb_a(struct inode *inode, struct file *file) +{ +	return single_open(file, rtl_proc_get_bb_a, GET_INODE_DATA(inode)); +} + +static const struct file_operations file_ops_bb_a = { +	.open = dl_proc_open_bb_a, +	.read = seq_read, +	.llseek = seq_lseek, +	.release = seq_release, +}; + +static int rtl_proc_get_bb_b(struct seq_file *m, void *v) +{ +	struct ieee80211_hw *hw = m->private; +	int i, n, page; +	int max = 0xff; +	page = 0xb00; + +	for (n = 0; n <= max; ) { +		seq_printf(m, "\n%8.8x  ", n + page); +		for (i = 0; i < 4 && n <= max; i++, n += 4) +			seq_printf(m, "%8.8x    ", +				   rtl_get_bbreg(hw, (page | n), 0xffffffff)); +	} +	seq_puts(m, "\n"); +	return 0; +} + +static int dl_proc_open_bb_b(struct inode *inode, struct file *file) +{ +	return single_open(file, rtl_proc_get_bb_b, GET_INODE_DATA(inode)); +} + +static const struct file_operations file_ops_bb_b = { +	.open = dl_proc_open_bb_b, +	.read = seq_read, +	.llseek = seq_lseek, +	.release = seq_release, +}; + +static int rtl_proc_get_bb_c(struct seq_file *m, void *v) +{ +	struct ieee80211_hw *hw = m->private; +	int i, n, page; +	int max = 0xff; +	page = 0xc00; + +	for (n = 0; n <= max; ) { +		seq_printf(m, "\n%8.8x  ", n + page); +		for (i = 0; i < 4 && n <= max; i++, n += 4) +			seq_printf(m, "%8.8x    ", +				   rtl_get_bbreg(hw, (page | n), 0xffffffff)); +	} +	seq_puts(m, "\n"); +	return 0; +} + +static int dl_proc_open_bb_c(struct inode *inode, struct file *file) +{ +	return single_open(file, rtl_proc_get_bb_c, GET_INODE_DATA(inode)); +} + +static const struct file_operations file_ops_bb_c = { +	.open = dl_proc_open_bb_c, +	.read = seq_read, +	.llseek = seq_lseek, +	.release = seq_release, +}; + +static int rtl_proc_get_bb_d(struct seq_file *m, void *v) +{ +	struct ieee80211_hw *hw = m->private; +	int i, n, page; +	int max = 0xff; +	page = 0xd00; + +	for (n = 0; n <= max; ) { +		seq_printf(m, "\n%8.8x  ", n + page); +		for (i = 0; i < 4 && n <= max; i++, n += 4) +			seq_printf(m, "%8.8x    ", +				   rtl_get_bbreg(hw, (page | n), 0xffffffff)); +	} +	seq_puts(m, "\n"); +	return 0; +} + +static int dl_proc_open_bb_d(struct inode *inode, struct file *file) +{ +	return single_open(file, rtl_proc_get_bb_d, GET_INODE_DATA(inode)); +} + +static const struct file_operations file_ops_bb_d = { +	.open = dl_proc_open_bb_d, +	.read = seq_read, +	.llseek = seq_lseek, +	.release = seq_release, +}; + +static int rtl_proc_get_bb_e(struct seq_file *m, void *v) +{ +	struct ieee80211_hw *hw = m->private; +	int i, n, page; +	int max = 0xff; +	page = 0xe00; + +	for (n = 0; n <= max; ) { +		seq_printf(m, "\n%8.8x  ", n + page); +		for (i = 0; i < 4 && n <= max; i++, n += 4) +			seq_printf(m, "%8.8x    ", +				   rtl_get_bbreg(hw, (page | n), 0xffffffff)); +	} +	seq_puts(m, "\n"); +	return 0; +} + +static int dl_proc_open_bb_e(struct inode *inode, struct file *file) +{ +	return single_open(file, rtl_proc_get_bb_e, GET_INODE_DATA(inode)); +} + +static const struct file_operations file_ops_bb_e = { +	.open = dl_proc_open_bb_e, +	.read = seq_read, +	.llseek = seq_lseek, +	.release = seq_release, +}; + +static int rtl_proc_get_bb_f(struct seq_file *m, void *v) +{ +	struct ieee80211_hw *hw = m->private; +	int i, n, page; +	int max = 0xff; +	page = 0xf00; + +	for (n = 0; n <= max; ) { +		seq_printf(m, "\n%8.8x  ", n + page); +		for (i = 0; i < 4 && n <= max; i++, n += 4) +			seq_printf(m, "%8.8x    ", +				   rtl_get_bbreg(hw, (page | n), 0xffffffff)); +	} +	seq_puts(m, "\n"); +	return 0; +} + +static int dl_proc_open_bb_f(struct inode *inode, struct file *file) +{ +	return single_open(file, rtl_proc_get_bb_f, GET_INODE_DATA(inode)); +} + +static const struct file_operations file_ops_bb_f = { +	.open = dl_proc_open_bb_f, +	.read = seq_read, +	.llseek = seq_lseek, +	.release = seq_release, +}; + +static int rtl_proc_get_reg_rf_a(struct seq_file *m, void *v) +{ +	struct ieee80211_hw *hw = m->private; +	int i, n; +	int max = 0x40; + +	for (n = 0; n <= max; ) { +		seq_printf(m, "\n%8.8x  ", n); +		for (i = 0; i < 4 && n <= max; n += 1, i++) +			seq_printf(m, "%8.8x    ", +				   rtl_get_rfreg(hw, RF90_PATH_A, n, 0xffffffff)); +	} +	seq_puts(m, "\n"); +	return 0; +} + +static int dl_proc_open_rf_a(struct inode *inode, struct file *file) +{ +	return single_open(file, rtl_proc_get_reg_rf_a, GET_INODE_DATA(inode)); +} + +static const struct file_operations file_ops_rf_a = { +	.open = dl_proc_open_rf_a, +	.read = seq_read, +	.llseek = seq_lseek, +	.release = seq_release, +}; + +static int rtl_proc_get_reg_rf_b(struct seq_file *m, void *v) +{ +	struct ieee80211_hw *hw = m->private; +	int i, n; +	int max = 0x40; + +	for (n = 0; n <= max; ) { +		seq_printf(m, "\n%8.8x  ", n); +		for (i = 0; i < 4 && n <= max; n += 1, i++) +			seq_printf(m, "%8.8x    ", +				   rtl_get_rfreg(hw, RF90_PATH_B, n, +						 0xffffffff)); +	} +	seq_puts(m, "\n"); +	return 0; +} + +static int dl_proc_open_rf_b(struct inode *inode, struct file *file) +{ +	return single_open(file, rtl_proc_get_reg_rf_b, GET_INODE_DATA(inode)); +} + +static const struct file_operations file_ops_rf_b = { +	.open = dl_proc_open_rf_b, +	.read = seq_read, +	.llseek = seq_lseek, +	.release = seq_release, +}; + +static int rtl_proc_get_cam_register_1(struct seq_file *m, void *v) +{ +	struct ieee80211_hw *hw = m->private; +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u32 target_cmd = 0; +	u32 target_val = 0; +	u8 entry_i = 0; +	u32 ulstatus; +	int i = 100, j = 0; + +	/* This dump the current register page */ +	seq_puts(m, +	    "\n#################### SECURITY CAM (0-10) ##################\n "); + +	for (j = 0; j < 11; j++) { +		seq_printf(m, "\nD:  %2x > ", j); +		for (entry_i = 0; entry_i < CAM_CONTENT_COUNT; entry_i++) { +			/* polling bit, and No Write enable, and address  */ +			target_cmd = entry_i + CAM_CONTENT_COUNT * j; +			target_cmd = target_cmd | BIT(31); + +			/* Check polling bit is clear */ +			while ((i--) >= 0) { +				ulstatus = rtl_read_dword(rtlpriv, +						rtlpriv->cfg->maps[RWCAM]); +				if (ulstatus & BIT(31)) +					continue; +				else +					break; +			} + +			rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM], +					target_cmd); +			target_val = rtl_read_dword(rtlpriv, +						    rtlpriv->cfg->maps[RCAMO]); +			seq_printf(m, "%8.8x ", target_val); +		} +	} +	seq_puts(m, "\n"); +	return 0; +} + +static int dl_proc_open_cam_1(struct inode *inode, struct file *file) +{ +	return single_open(file, rtl_proc_get_cam_register_1, +			   GET_INODE_DATA(inode)); +} + +static const struct file_operations file_ops_cam_1 = { +	.open = dl_proc_open_cam_1, +	.read = seq_read, +	.llseek = seq_lseek, +	.release = seq_release, +}; + +static int rtl_proc_get_cam_register_2(struct seq_file *m, void *v) +{ +	struct ieee80211_hw *hw = m->private; +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u32 target_cmd = 0; +	u32 target_val = 0; +	u8 entry_i = 0; +	u32 ulstatus; +	int i = 100, j = 0; + +	/* This dump the current register page */ +	seq_puts(m, +	    "\n################### SECURITY CAM (11-21) ##################\n "); + +	for (j = 11; j < 22; j++) { +		seq_printf(m, "\nD:  %2x > ", j); +		for (entry_i = 0; entry_i < CAM_CONTENT_COUNT; entry_i++) { +			target_cmd = entry_i + CAM_CONTENT_COUNT * j; +			target_cmd = target_cmd | BIT(31); + +			while ((i--) >= 0) { +				ulstatus = rtl_read_dword(rtlpriv, +						rtlpriv->cfg->maps[RWCAM]); +				if (ulstatus & BIT(31)) +					continue; +				else +					break; +			} + +			rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM], +					target_cmd); +			target_val = rtl_read_dword(rtlpriv, +						    rtlpriv->cfg->maps[RCAMO]); +			seq_printf(m, "%8.8x ", target_val); +		} +	} +	seq_puts(m, "\n"); +	return 0; +} + +static int dl_proc_open_cam_2(struct inode *inode, struct file *file) +{ +	return single_open(file, rtl_proc_get_cam_register_2, +			   GET_INODE_DATA(inode)); +} + +static const struct file_operations file_ops_cam_2 = { +	.open = dl_proc_open_cam_2, +	.read = seq_read, +	.llseek = seq_lseek, +	.release = seq_release, +}; + +static int rtl_proc_get_cam_register_3(struct seq_file *m, void *v) +{ +	struct ieee80211_hw *hw = m->private; +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u32 target_cmd = 0; +	u32 target_val = 0; +	u8 entry_i = 0; +	u32 ulstatus; +	int i = 100, j = 0; + +	/* This dump the current register page */ +	seq_puts(m, +	    "\n################### SECURITY CAM (22-31) ##################\n "); + +	for (j = 22; j < TOTAL_CAM_ENTRY; j++) { +		seq_printf(m, "\nD:  %2x > ", j); +		for (entry_i = 0; entry_i < CAM_CONTENT_COUNT; entry_i++) { +			target_cmd = entry_i+CAM_CONTENT_COUNT*j; +			target_cmd = target_cmd | BIT(31); + +			while ((i--) >= 0) { +				ulstatus = rtl_read_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM]); +				if (ulstatus & BIT(31)) +					continue; +				else +					break; +			} + +			rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM], +					target_cmd); +			target_val = rtl_read_dword(rtlpriv, +						    rtlpriv->cfg->maps[RCAMO]); +			seq_printf(m, "%8.8x ", target_val); +		} +	} +	seq_puts(m, "\n"); +	return 0; +} + +static int dl_proc_open_cam_3(struct inode *inode, struct file *file) +{ +	return single_open(file, rtl_proc_get_cam_register_3, +			   GET_INODE_DATA(inode)); +} + +static const struct file_operations file_ops_cam_3 = { +	.open = dl_proc_open_cam_3, +	.read = seq_read, +	.llseek = seq_lseek, +	.release = seq_release, +}; + +void rtl_proc_add_one(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); +	struct proc_dir_entry *entry; + +	snprintf(rtlpriv->dbg.proc_name, 18, "%x-%x-%x-%x-%x-%x", +		 rtlefuse->dev_addr[0], rtlefuse->dev_addr[1], +		 rtlefuse->dev_addr[2], rtlefuse->dev_addr[3], +		 rtlefuse->dev_addr[4], rtlefuse->dev_addr[5]); + +	rtlpriv->dbg.proc_dir = proc_mkdir(rtlpriv->dbg.proc_name, proc_topdir); +	if (!rtlpriv->dbg.proc_dir) { +		RT_TRACE(COMP_INIT, DBG_EMERG, +			 ("Unable to init /proc/net/%s/%s\n", +			  rtlpriv->cfg->name, +			  rtlpriv->dbg.proc_name)); +		return; +	} + +	entry = proc_create_data("mac-0", S_IFREG | S_IRUGO, +				 rtlpriv->dbg.proc_dir, &file_ops_mac_0, hw); +	if (!entry) +		RT_TRACE(COMP_INIT, DBG_EMERG, +			 ("Unable to initialize /proc/net/%s/%s/mac-0\n", +			  rtlpriv->cfg->name, rtlpriv->dbg.proc_name)); + +	entry = proc_create_data("mac-1", S_IFREG | S_IRUGO, +				 rtlpriv->dbg.proc_dir, &file_ops_mac_1, hw); +	if (!entry) +		RT_TRACE(COMP_INIT, COMP_ERR, +			 ("Unable to initialize /proc/net/%s/%s/mac-1\n", +			  rtlpriv->cfg->name, rtlpriv->dbg.proc_name)); + +	entry = proc_create_data("mac-2", S_IFREG | S_IRUGO, +				 rtlpriv->dbg.proc_dir, &file_ops_mac_2, hw); +	if (!entry) +		RT_TRACE(COMP_INIT, COMP_ERR, +			 ("Unable to initialize /proc/net/%s/%s/mac-2\n", +			  rtlpriv->cfg->name, rtlpriv->dbg.proc_name)); + +	entry = proc_create_data("mac-3", S_IFREG | S_IRUGO, +				 rtlpriv->dbg.proc_dir, &file_ops_mac_3, hw); +	if (!entry) +		RT_TRACE(COMP_INIT, COMP_ERR, +			 ("Unable to initialize /proc/net/%s/%s/mac-3\n", +			  rtlpriv->cfg->name, rtlpriv->dbg.proc_name)); + +	entry = proc_create_data("mac-4", S_IFREG | S_IRUGO, +				 rtlpriv->dbg.proc_dir, &file_ops_mac_4, hw); +	if (!entry) +		RT_TRACE(COMP_INIT, COMP_ERR, +			 ("Unable to initialize /proc/net/%s/%s/mac-4\n", +			  rtlpriv->cfg->name, rtlpriv->dbg.proc_name)); + +	entry = proc_create_data("mac-5", S_IFREG | S_IRUGO, +				 rtlpriv->dbg.proc_dir, &file_ops_mac_5, hw); +	if (!entry) +		RT_TRACE(COMP_INIT, COMP_ERR, +			 ("Unable to initialize /proc/net/%s/%s/mac-5\n", +			  rtlpriv->cfg->name, rtlpriv->dbg.proc_name)); + +	entry = proc_create_data("mac-6", S_IFREG | S_IRUGO, +				 rtlpriv->dbg.proc_dir, &file_ops_mac_6, hw); +	if (!entry) +		RT_TRACE(COMP_INIT, COMP_ERR, +			 ("Unable to initialize /proc/net/%s/%s/mac-6\n", +			  rtlpriv->cfg->name, rtlpriv->dbg.proc_name)); + +	entry = proc_create_data("mac-7", S_IFREG | S_IRUGO, +				 rtlpriv->dbg.proc_dir, &file_ops_mac_7, hw); +	if (!entry) +		RT_TRACE(COMP_INIT, COMP_ERR, +			 ("Unable to initialize /proc/net/%s/%s/mac-7\n", +			  rtlpriv->cfg->name, rtlpriv->dbg.proc_name)); + +	entry = proc_create_data("bb-8", S_IFREG | S_IRUGO, +				 rtlpriv->dbg.proc_dir, &file_ops_bb_8, hw); +	if (!entry) +		RT_TRACE(COMP_INIT, COMP_ERR, +			 ("Unable to initialize /proc/net/%s/%s/bb-8\n", +			  rtlpriv->cfg->name, rtlpriv->dbg.proc_name)); + +	entry = proc_create_data("bb-9", S_IFREG | S_IRUGO, +				 rtlpriv->dbg.proc_dir, &file_ops_bb_9, hw); +	if (!entry) +		RT_TRACE(COMP_INIT, COMP_ERR, +			 ("Unable to initialize /proc/net/%s/%s/bb-9\n", +			  rtlpriv->cfg->name, rtlpriv->dbg.proc_name)); + +	entry = proc_create_data("bb-a", S_IFREG | S_IRUGO, +				 rtlpriv->dbg.proc_dir, &file_ops_bb_a, hw); +	if (!entry) +		RT_TRACE(COMP_INIT, COMP_ERR, +			 ("Unable to initialize /proc/net/%s/%s/bb-a\n", +			  rtlpriv->cfg->name, rtlpriv->dbg.proc_name)); + +	entry = proc_create_data("bb-b", S_IFREG | S_IRUGO, +				 rtlpriv->dbg.proc_dir, &file_ops_bb_b, hw); +	if (!entry) +		RT_TRACE(COMP_INIT, COMP_ERR, +			 ("Unable to initialize /proc/net/%s/%s/bb-b\n", +		      rtlpriv->cfg->name, rtlpriv->dbg.proc_name)); + +	entry = proc_create_data("bb-c", S_IFREG | S_IRUGO, +				 rtlpriv->dbg.proc_dir, &file_ops_bb_c, hw); +	if (!entry) +		RT_TRACE(COMP_INIT, COMP_ERR, +			 ("Unable to initialize /proc/net/%s/%s/bb-c\n", +			  rtlpriv->cfg->name, rtlpriv->dbg.proc_name)); + +	entry = proc_create_data("bb-d", S_IFREG | S_IRUGO, +				 rtlpriv->dbg.proc_dir, &file_ops_bb_d, hw); +	if (!entry) +		RT_TRACE(COMP_INIT, COMP_ERR, +			 ("Unable to initialize /proc/net/%s/%s/bb-d\n", +			  rtlpriv->cfg->name, rtlpriv->dbg.proc_name)); + +	entry = proc_create_data("bb-e", S_IFREG | S_IRUGO, +				 rtlpriv->dbg.proc_dir, &file_ops_bb_e, hw); +	if (!entry) +		RT_TRACE(COMP_INIT, COMP_ERR, +			 ("Unable to initialize /proc/net/%s/%s/bb-e\n", +			  rtlpriv->cfg->name, rtlpriv->dbg.proc_name)); + +	entry = proc_create_data("bb-f", S_IFREG | S_IRUGO, +				 rtlpriv->dbg.proc_dir, &file_ops_bb_f, hw); +	if (!entry) +		RT_TRACE(COMP_INIT, COMP_ERR, +			 ("Unable to initialize /proc/net/%s/%s/bb-f\n", +			  rtlpriv->cfg->name, rtlpriv->dbg.proc_name)); + +	entry = proc_create_data("rf-a", S_IFREG | S_IRUGO, +				 rtlpriv->dbg.proc_dir, &file_ops_rf_a, hw); +	if (!entry) +		RT_TRACE(COMP_INIT, COMP_ERR, +			 ("Unable to initialize /proc/net/%s/%s/rf-a\n", +			  rtlpriv->cfg->name, rtlpriv->dbg.proc_name)); + +	entry = proc_create_data("rf-b", S_IFREG | S_IRUGO, +				 rtlpriv->dbg.proc_dir, &file_ops_rf_b, hw); +	if (!entry) +		RT_TRACE(COMP_INIT, COMP_ERR, +			 ("Unable to initialize /proc/net/%s/%s/rf-b\n", +			  rtlpriv->cfg->name, rtlpriv->dbg.proc_name)); + +	entry = proc_create_data("cam-1", S_IFREG | S_IRUGO, +				 rtlpriv->dbg.proc_dir, &file_ops_cam_1, hw); +	if (!entry) +		RT_TRACE(COMP_INIT, COMP_ERR, +			 ("Unable to initialize /proc/net/%s/%s/cam-1\n", +			  rtlpriv->cfg->name, rtlpriv->dbg.proc_name)); + +	entry = proc_create_data("cam-2", S_IFREG | S_IRUGO, +				 rtlpriv->dbg.proc_dir, &file_ops_cam_2, hw); +	if (!entry) +		RT_TRACE(COMP_INIT, COMP_ERR, +			 ("Unable to initialize /proc/net/%s/%s/cam-2\n", +			  rtlpriv->cfg->name, rtlpriv->dbg.proc_name)); + +	entry = proc_create_data("cam-3", S_IFREG | S_IRUGO, +				 rtlpriv->dbg.proc_dir, &file_ops_cam_3, hw); +	if (!entry) +		RT_TRACE(COMP_INIT, COMP_ERR, +			 ("Unable to initialize /proc/net/%s/%s/cam-3\n", +			  rtlpriv->cfg->name, rtlpriv->dbg.proc_name)); +} + +void rtl_proc_remove_one(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); + +	if (rtlpriv->dbg.proc_dir) { +		remove_proc_entry("mac-0", rtlpriv->dbg.proc_dir); +		remove_proc_entry("mac-1", rtlpriv->dbg.proc_dir); +		remove_proc_entry("mac-2", rtlpriv->dbg.proc_dir); +		remove_proc_entry("mac-3", rtlpriv->dbg.proc_dir); +		remove_proc_entry("mac-4", rtlpriv->dbg.proc_dir); +		remove_proc_entry("mac-5", rtlpriv->dbg.proc_dir); +		remove_proc_entry("mac-6", rtlpriv->dbg.proc_dir); +		remove_proc_entry("mac-7", rtlpriv->dbg.proc_dir); +		remove_proc_entry("bb-8", rtlpriv->dbg.proc_dir); +		remove_proc_entry("bb-9", rtlpriv->dbg.proc_dir); +		remove_proc_entry("bb-a", rtlpriv->dbg.proc_dir); +		remove_proc_entry("bb-b", rtlpriv->dbg.proc_dir); +		remove_proc_entry("bb-c", rtlpriv->dbg.proc_dir); +		remove_proc_entry("bb-d", rtlpriv->dbg.proc_dir); +		remove_proc_entry("bb-e", rtlpriv->dbg.proc_dir); +		remove_proc_entry("bb-f", rtlpriv->dbg.proc_dir); +		remove_proc_entry("rf-a", rtlpriv->dbg.proc_dir); +		remove_proc_entry("rf-b", rtlpriv->dbg.proc_dir); +		remove_proc_entry("cam-1", rtlpriv->dbg.proc_dir); +		remove_proc_entry("cam-2", rtlpriv->dbg.proc_dir); +		remove_proc_entry("cam-3", rtlpriv->dbg.proc_dir); + +		remove_proc_entry(rtlpriv->dbg.proc_name, proc_topdir); + +		rtlpriv->dbg.proc_dir = NULL; +	} +} + +void rtl_proc_add_topdir(void) +{ +	proc_topdir = proc_mkdir("rtlwifi", init_net.proc_net); +} + +void rtl_proc_remove_topdir(void) +{ +	if (proc_topdir) +		remove_proc_entry("rtlwifi", init_net.proc_net); +} diff --git a/drivers/staging/rtl8192ee/debug.h b/drivers/staging/rtl8192ee/debug.h new file mode 100644 index 00000000000..093128d1f36 --- /dev/null +++ b/drivers/staging/rtl8192ee/debug.h @@ -0,0 +1,221 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010  Realtek Corporation. + * + * Tmis program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * Tmis program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * Tme full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __RTL_DEBUG_H__ +#define __RTL_DEBUG_H__ + +/*-------------------------------------------------------------- +			Debug level +--------------------------------------------------------------*/ +/* + *Fatal bug. + *For example, Tx/Rx/IO locked up, + *memory access violation, + *resource allocation failed, + *unexpected HW behavior, HW BUG + *and so on. + */ +#define DBG_EMERG			1 + +/* + *Abnormal, rare, or unexpeted cases. + *For example, Packet/IO Ctl canceled, + *device suprisely unremoved and so on. + */ +#define	DBG_WARNING			2 + +/* + *Normal case driver developer should + *open, we can see link status like + *assoc/AddBA/DHCP/adapter start and + *so on basic and useful infromations. + */ +#define DBG_DMESG			3 + +/* + *Normal case with useful information + *about current SW or HW state. + *For example, Tx/Rx descriptor to fill, + *Tx/Rx descriptor completed status, + *SW protocol state change, dynamic + *mechanism state change and so on. + */ +#define DBG_LOUD			4 + +/* + *Normal case with detail execution + *flow or information. + */ +#define	DBG_TRACE			5 + +/*-------------------------------------------------------------- +		Define the rt_trace components +--------------------------------------------------------------*/ +#define COMP_ERR			BIT(0) +#define COMP_FW				BIT(1) +#define COMP_INIT			BIT(2)	/*For init/deinit */ +#define COMP_RECV			BIT(3)	/*For Rx. */ +#define COMP_SEND			BIT(4)	/*For Tx. */ +#define COMP_MLME			BIT(5)	/*For MLME. */ +#define COMP_SCAN			BIT(6)	/*For Scan. */ +#define COMP_INTR			BIT(7)	/*For interrupt Related. */ +#define COMP_LED			BIT(8)	/*For LED. */ +#define COMP_SEC			BIT(9)	/*For sec. */ +#define COMP_BEACON			BIT(10)	/*For beacon. */ +#define COMP_RATE			BIT(11)	/*For rate. */ +#define COMP_RXDESC			BIT(12)	/*For rx desc. */ +#define COMP_DIG			BIT(13)	/*For DIG */ +#define COMP_TXAGC			BIT(14)	/*For Tx power */ +#define COMP_HIPWR			BIT(15)	/*For High Power Mechanism */ +#define COMP_POWER			BIT(16)	/*For lps/ips/aspm. */ +#define COMP_POWER_TRACKING		BIT(17)	/*For TX POWER TRACKING */ +#define COMP_BB_POWERSAVING		BIT(18) +#define COMP_SWAS			BIT(19)	/*For SW Antenna Switch */ +#define COMP_RF				BIT(20)	/*For RF. */ +#define COMP_TURBO			BIT(21)	/*For EDCA TURBO. */ +#define COMP_RATR			BIT(22) +#define COMP_CMD			BIT(23) +#define COMP_EFUSE			BIT(24) +#define COMP_QOS			BIT(25) +#define COMP_MAC80211			BIT(26) +#define COMP_REGD			BIT(27) +#define COMP_CHAN			BIT(28) +#define COMP_EASY_CONCURRENT		BIT(29) +#define COMP_BT_COEXIST			BIT(30) +#define COMP_IQK			BIT(31) + +/*-------------------------------------------------------------- +		Define the rt_print components +--------------------------------------------------------------*/ +/* Define EEPROM and EFUSE  check module bit*/ +#define EEPROM_W			BIT(0) +#define EFUSE_PG			BIT(1) +#define EFUSE_READ_ALL			BIT(2) + +/* Define init check for module bit*/ +#define	INIT_EEPROM			BIT(0) +#define	INIT_TxPower			BIT(1) +#define	INIT_IQK			BIT(2) +#define	INIT_RF				BIT(3) + +/* Define PHY-BB/RF/MAC check module bit */ +#define	PHY_BBR				BIT(0) +#define	PHY_BBW				BIT(1) +#define	PHY_RFR				BIT(2) +#define	PHY_RFW				BIT(3) +#define	PHY_MACR			BIT(4) +#define	PHY_MACW			BIT(5) +#define	PHY_ALLR			BIT(6) +#define	PHY_ALLW			BIT(7) +#define	PHY_TXPWR			BIT(8) +#define	PHY_PWRDIFF			BIT(9) + +/* Define Dynamic Mechanism check module bit --> FDM */ +#define WA_IOT				BIT(0) +#define DM_PWDB				BIT(1) +#define DM_MONITOR			BIT(2) +#define DM_DIG				BIT(3) +#define DM_EDCA_TURBO			BIT(4) + +enum dbgp_flag_e { +	FQOS = 0, +	FTX = 1, +	FRX = 2, +	FSEC = 3, +	FMGNT = 4, +	FMLME = 5, +	FRESOURCE = 6, +	FBEACON = 7, +	FISR = 8, +	FPHY = 9, +	FMP = 10, +	FEEPROM = 11, +	FPWR = 12, +	FDM = 13, +	FDBGCtrl = 14, +	FC2H = 15, +	FBT = 16, +	FINIT = 17, +	FIOCTL = 18, +	DBGP_TYPE_MAX +}; + +#define RT_ASSERT(_exp , fmt)				\ +	do { \ +		if (!(_exp))	{			\ +			pr_debug("%s:%s(): ", KBUILD_MODNAME, \ +			__func__);	\ +			pr_cont fmt;			\ +		} \ +	} while (0) + +#define RT_TRACE(comp, level, fmt)\ +	do { \ +		if (unlikely(((comp) & rtlpriv->dbg.global_debugcomponents) && \ +			((level) <= rtlpriv->dbg.global_debuglevel))) {\ +			pr_debug("%s-%d:%s():<%lx> ", \ +			KBUILD_MODNAME, \ +			rtlpriv->rtlhal.interfaceindex, __func__, \ +			in_interrupt());	\ +			pr_cont fmt;			\ +		} \ +	} while (0) + +#define RTPRINT(rtlpriv, dbgtype, dbgflag, fmt, ...)			\ +do {									\ +	if (unlikely(rtlpriv->dbg.dbgp_type[dbgtype] & dbgflag)) {	\ +		pr_debug(KBUILD_MODNAME ": " fmt,		\ +		       ##__VA_ARGS__);					\ +	}								\ +} while (0) + +#define RT_PRINT_DATA(rtlpriv, _comp, _level, _titlestring, _hexdata, \ +		_hexdatalen) \ +	do {\ +		if (unlikely(((_comp) & rtlpriv->dbg.global_debugcomponents) &&\ +			(_level <= rtlpriv->dbg.global_debuglevel)))	{ \ +			int __i;					\ +			u8 *ptr = (u8 *)_hexdata;			\ +			pr_debug("%s: ", KBUILD_MODNAME);	\ +			pr_cont("In process \"%s\" (pid %i):", \ +					current->comm,	\ +					current->pid); \ +			pr_cont(_titlestring);		\ +			for (__i = 0; __i < (int)_hexdatalen; __i++) {	\ +				pr_cont("%02X%s", ptr[__i], (((__i + 1) % 4) \ +							== 0) ? "  " : " ");\ +				if (((__i + 1) % 16) == 0)	\ +					pr_cont("\n");	\ +			}				\ +			pr_cont("\n");			\ +		} \ +	} while (0) + +void rtl92e_dbgp_flag_init(struct ieee80211_hw *hw); +void rtl_proc_add_one(struct ieee80211_hw *hw); +void rtl_proc_remove_one(struct ieee80211_hw *hw); +void rtl_proc_add_topdir(void); +void rtl_proc_remove_topdir(void); +#endif diff --git a/drivers/staging/rtl8192ee/efuse.c b/drivers/staging/rtl8192ee/efuse.c new file mode 100644 index 00000000000..3fae1836983 --- /dev/null +++ b/drivers/staging/rtl8192ee/efuse.c @@ -0,0 +1,1233 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010  Realtek Corporation. + * + * Tmis program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +#include "wifi.h" +#include "efuse.h" + +static const u8 MAX_PGPKT_SIZE = 9; +static const u8 PGPKT_DATA_SIZE = 8; +static const int EFUSE_MAX_SIZE = 512; + +static const struct efuse_map RTL8712_SDIO_EFUSE_TABLE[] = { +	{0, 0, 0, 2}, +	{0, 1, 0, 2}, +	{0, 2, 0, 2}, +	{1, 0, 0, 1}, +	{1, 0, 1, 1}, +	{1, 1, 0, 1}, +	{1, 1, 1, 3}, +	{1, 3, 0, 17}, +	{3, 3, 1, 48}, +	{10, 0, 0, 6}, +	{10, 3, 0, 1}, +	{10, 3, 1, 1}, +	{11, 0, 0, 28} +}; + +static void efuse92e_shadow_read_1byte(struct ieee80211_hw *hw, u16 offset, +				       u8 *value); +static void efuse92e_shadow_read_2byte(struct ieee80211_hw *hw, u16 offset, +				       u16 *value); +static void efuse92e_shadow_read_4byte(struct ieee80211_hw *hw, u16 offset, +				       u32 *value); +static void efuse92e_shadow_write_1byte(struct ieee80211_hw *hw, u16 offset, +					u8 value); +static void efuse92e_shadow_write_2byte(struct ieee80211_hw *hw, u16 offset, +					u16 value); +static void efuse92e_shadow_write_4byte(struct ieee80211_hw *hw, u16 offset, +					u32 value); +static int efuse_one_byte_write(struct ieee80211_hw *hw, u16 addr, +				u8 data); +static void efuse_read_all_map(struct ieee80211_hw *hw, u8 *efuse); +static int efuse_pg_packet_read(struct ieee80211_hw *hw, u8 offset, +				u8 *data); +static int efuse_pg_packet_write(struct ieee80211_hw *hw, u8 offset, +				 u8 word_en, u8 *data); +static void efuse_word_enable_data_read(u8 word_en, u8 *sourdata, +					u8 *targetdata); +static u8 efuse_word_enable_data_write(struct ieee80211_hw *hw, +				       u16 efuse_addr, u8 word_en, u8 *data); +static void efuse_power_switch(struct ieee80211_hw *hw, u8 bwrite, +			       u8 pwrstate); +static u16 efuse_get_current_size(struct ieee80211_hw *hw); +static u8 efuse_calculate_word_cnts(u8 word_en); + +void efuse92e_initialize(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u8 bytetemp; +	u8 temp; + +	bytetemp = rtl_read_byte(rtlpriv, rtlpriv->cfg->maps[SYS_FUNC_EN] + 1); +	temp = bytetemp | 0x20; +	rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[SYS_FUNC_EN] + 1, temp); + +	bytetemp = rtl_read_byte(rtlpriv, rtlpriv->cfg->maps[SYS_ISO_CTRL] + 1); +	temp = bytetemp & 0xFE; +	rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[SYS_ISO_CTRL] + 1, temp); + +	bytetemp = rtl_read_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_TEST] + 3); +	temp = bytetemp | 0x80; +	rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_TEST] + 3, temp); + +	rtl_write_byte(rtlpriv, 0x2F8, 0x3); + +	rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 3, 0x72); +} + +u8 stg_efuse_read_1byte(struct ieee80211_hw *hw, u16 address) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u8 data; +	u8 bytetemp; +	u8 temp; +	u32 k = 0; +	const u32 efuse_real_content_len = +		rtlpriv->cfg->maps[EFUSE_REAL_CONTENT_SIZE]; + +	if (address < efuse_real_content_len) { +		temp = address & 0xFF; +		rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 1, +			       temp); +		bytetemp = rtl_read_byte(rtlpriv, +					 rtlpriv->cfg->maps[EFUSE_CTRL] + 2); +		temp = ((address >> 8) & 0x03) | (bytetemp & 0xFC); +		rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 2, +			       temp); + +		bytetemp = rtl_read_byte(rtlpriv, +					 rtlpriv->cfg->maps[EFUSE_CTRL] + 3); +		temp = bytetemp & 0x7F; +		rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 3, +			       temp); + +		bytetemp = rtl_read_byte(rtlpriv, +					 rtlpriv->cfg->maps[EFUSE_CTRL] + 3); +		while (!(bytetemp & 0x80)) { +			bytetemp = rtl_read_byte(rtlpriv, +						 rtlpriv->cfg-> +						 maps[EFUSE_CTRL] + 3); +			k++; +			if (k == 1000) { +				k = 0; +				break; +			} +		} +		data = rtl_read_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL]); +		return data; +	} else { +		return 0xFF; +	} +} +EXPORT_SYMBOL(stg_efuse_read_1byte); + +void efuse92e_write_1byte(struct ieee80211_hw *hw, u16 address, u8 value) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u8 bytetemp; +	u8 temp; +	u32 k = 0; +	const u32 efuse_real_content_len = +		rtlpriv->cfg->maps[EFUSE_REAL_CONTENT_SIZE]; + +	RT_TRACE(COMP_EFUSE, DBG_LOUD, +		 ("Addr=%x Data =%x\n", address, value)); + +	if (address < efuse_real_content_len) { +		rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL], value); + +		temp = address & 0xFF; +		rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 1, +			       temp); +		bytetemp = rtl_read_byte(rtlpriv, +					 rtlpriv->cfg->maps[EFUSE_CTRL] + 2); + +		temp = ((address >> 8) & 0x03) | (bytetemp & 0xFC); +		rtl_write_byte(rtlpriv, +			       rtlpriv->cfg->maps[EFUSE_CTRL] + 2, temp); + +		bytetemp = rtl_read_byte(rtlpriv, +					 rtlpriv->cfg->maps[EFUSE_CTRL] + 3); +		temp = bytetemp | 0x80; +		rtl_write_byte(rtlpriv, +			       rtlpriv->cfg->maps[EFUSE_CTRL] + 3, temp); + +		bytetemp = rtl_read_byte(rtlpriv, +					 rtlpriv->cfg->maps[EFUSE_CTRL] + 3); + +		while (bytetemp & 0x80) { +			bytetemp = rtl_read_byte(rtlpriv, +						 rtlpriv->cfg-> +						 maps[EFUSE_CTRL] + 3); +			k++; +			if (k == 100) { +				k = 0; +				break; +			} +		} +	} +} + +void read92e_efuse_byte(struct ieee80211_hw *hw, u16 _offset, u8 *pbuf) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u32 value32; +	u8 readbyte; +	u16 retry; + +	rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 1, +		       (_offset & 0xff)); +	readbyte = rtl_read_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 2); +	rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 2, +		       ((_offset >> 8) & 0x03) | (readbyte & 0xfc)); + +	readbyte = rtl_read_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 3); +	rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 3, +		       (readbyte & 0x7f)); + +	retry = 0; +	value32 = rtl_read_dword(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL]); +	while (!(((value32 >> 24) & 0xff) & 0x80) && (retry < 10000)) { +		value32 = rtl_read_dword(rtlpriv, +					 rtlpriv->cfg->maps[EFUSE_CTRL]); +		retry++; +	} + +	udelay(50); +	value32 = rtl_read_dword(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL]); + +	*pbuf = (u8) (value32 & 0xff); +} + +void read92e_efuse(struct ieee80211_hw *hw, u16 _offset, u16 _size_byte, +		   u8 *pbuf) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); +	u8 *efuse_tbl; +	u8 rtemp8[1]; +	u16 efuse_addr = 0; +	u8 offset, wren; +	u8 u1temp = 0; +	u16 i; +	u16 j; +	const u16 efuse_max_section = +		rtlpriv->cfg->maps[EFUSE_MAX_SECTION_MAP]; +	const u32 efuse_real_content_len = +		rtlpriv->cfg->maps[EFUSE_REAL_CONTENT_SIZE]; +	u16 **efuse_word; +	u16 efuse_utilized = 0; +	u8 efuse_usage; + +	if ((_offset + _size_byte) > rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE]) { +		RT_TRACE(COMP_EFUSE, DBG_LOUD, +			 ("read92e_efuse(): Invalid offset(%#x) with read bytes(%#x)!!\n", +			 _offset, _size_byte)); +		return; +	} + +	/* allocate memory for efuse_tbl and efuse_word */ +	efuse_tbl = kmalloc(rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE] * +			    sizeof(u8), GFP_ATOMIC); +	if (!efuse_tbl) +		return; +	efuse_word = kzalloc(EFUSE_MAX_WORD_UNIT * sizeof(u16 *), GFP_ATOMIC); +	if (!efuse_word) +		goto out; +	for (i = 0; i < EFUSE_MAX_WORD_UNIT; i++) { +		efuse_word[i] = kmalloc(efuse_max_section * sizeof(u16), +					GFP_ATOMIC); +		if (!efuse_word[i]) +			goto done; +	} + +	for (i = 0; i < efuse_max_section; i++) +		for (j = 0; j < EFUSE_MAX_WORD_UNIT; j++) +			efuse_word[j][j] = 0xFFFF; + +	read92e_efuse_byte(hw, efuse_addr, rtemp8); +	if (*rtemp8 != 0xFF) { +		efuse_utilized++; +		RTPRINT(rtlpriv, FEEPROM, EFUSE_READ_ALL, +			"Addr=%d\n", efuse_addr); +		efuse_addr++; +	} + +	while ((*rtemp8 != 0xFF) && (efuse_addr < efuse_real_content_len)) { +		/*  Check PG header for section num.  */ +		if ((*rtemp8 & 0x1F) == 0x0F) {/* extended header */ +			u1temp = ((*rtemp8 & 0xE0) >> 5); +			read92e_efuse_byte(hw, efuse_addr, rtemp8); + +			if ((*rtemp8 & 0x0F) == 0x0F) { +				efuse_addr++; +				read92e_efuse_byte(hw, efuse_addr, rtemp8); + +				if (*rtemp8 != 0xFF && +				    (efuse_addr < efuse_real_content_len)) { +					efuse_addr++; +				} +				continue; +			} else { +				offset = ((*rtemp8 & 0xF0) >> 1) | u1temp; +				wren = (*rtemp8 & 0x0F); +				efuse_addr++; +			} +		} else { +			offset = ((*rtemp8 >> 4) & 0x0f); +			wren = (*rtemp8 & 0x0f); +		} + +		if (offset < efuse_max_section) { +			RTPRINT(rtlpriv, FEEPROM, EFUSE_READ_ALL, +				"offset-%d Worden=%x\n", offset, wren); + +			for (i = 0; i < EFUSE_MAX_WORD_UNIT; i++) { +				if (!(wren & 0x01)) { +					RTPRINT(rtlpriv, FEEPROM, +						EFUSE_READ_ALL, "Addr=%d\n", +						efuse_addr); + +					read92e_efuse_byte(hw, efuse_addr, +							   rtemp8); +					efuse_addr++; +					efuse_utilized++; +					efuse_word[i][offset] = (*rtemp8 & +								 0xff); + +					if (efuse_addr >= +					    efuse_real_content_len) +						break; + +					RTPRINT(rtlpriv, FEEPROM, +						EFUSE_READ_ALL, "Addr=%d\n", +						efuse_addr); + +					read92e_efuse_byte(hw, efuse_addr, +							   rtemp8); +					efuse_addr++; +					efuse_utilized++; +					efuse_word[i][offset] |= +					    (((u16) *rtemp8 << 8) & 0xff00); + +					if (efuse_addr >= +					    efuse_real_content_len) +						break; +				} + +				wren >>= 1; +			} +		} + +		RTPRINT(rtlpriv, FEEPROM, EFUSE_READ_ALL, +			"Addr=%d\n", efuse_addr); +		read92e_efuse_byte(hw, efuse_addr, rtemp8); +		if (*rtemp8 != 0xFF && (efuse_addr < efuse_real_content_len)) { +			efuse_utilized++; +			efuse_addr++; +		} +	} + +	for (i = 0; i < efuse_max_section; i++) { +		for (j = 0; j < EFUSE_MAX_WORD_UNIT; j++) { +			efuse_tbl[(i * 8) + (j * 2)] = +			    (efuse_word[j][i] & 0xff); +			efuse_tbl[(i * 8) + ((j * 2) + 1)] = +			    ((efuse_word[j][i] >> 8) & 0xff); +		} +	} + +	for (i = 0; i < _size_byte; i++) +		pbuf[i] = efuse_tbl[_offset + i]; + +	rtlefuse->efuse_usedbytes = efuse_utilized; +	efuse_usage = (u8) ((efuse_utilized * 100) / efuse_real_content_len); +	rtlefuse->efuse_usedpercentage = efuse_usage; +	rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_EFUSE_BYTES, +				      (u8 *)&efuse_utilized); +	rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_EFUSE_USAGE, +				      (u8 *)&efuse_usage); +done: +	for (i = 0; i < EFUSE_MAX_WORD_UNIT; i++) +		kfree(efuse_word[i]); +	kfree(efuse_word); +out: +	kfree(efuse_tbl); +} + +bool efuse92e_shadow_update_chk(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); +	u8 section_idx, i, Base; +	u16 words_need = 0, hdr_num = 0, totalbytes, efuse_used; +	bool bwordchanged, bresult = true; + +	for (section_idx = 0; section_idx < 16; section_idx++) { +		Base = section_idx * 8; +		bwordchanged = false; + +		for (i = 0; i < 8; i = i + 2) { +			if ((rtlefuse->efuse_map[EFUSE_INIT_MAP][Base + i] != +			     rtlefuse->efuse_map[EFUSE_MODIFY_MAP][Base + i]) || +			    (rtlefuse->efuse_map[EFUSE_INIT_MAP][Base + i + 1] != +			     rtlefuse->efuse_map[EFUSE_MODIFY_MAP][Base + i + +								   1])) { +				words_need++; +				bwordchanged = true; +			} +		} + +		if (bwordchanged) +			hdr_num++; +	} + +	totalbytes = hdr_num + words_need * 2; +	efuse_used = rtlefuse->efuse_usedbytes; + +	if ((totalbytes + efuse_used) >= +	    (EFUSE_MAX_SIZE - rtlpriv->cfg->maps[EFUSE_OOB_PROTECT_BYTES_LEN])) +		bresult = false; + +	RT_TRACE(COMP_EFUSE, DBG_LOUD, +		 ("efuse92e_shadow_update_chk(): totalbytes(%#x), hdr_num(%#x), words_need(%#x), efuse_used(%d)\n", +		  totalbytes, hdr_num, words_need, efuse_used)); + +	return bresult; +} + +void efuse92e_shadow_read(struct ieee80211_hw *hw, u8 type, +		       u16 offset, u32 *value) +{ +	if (type == 1) +		efuse92e_shadow_read_1byte(hw, offset, (u8 *)value); +	else if (type == 2) +		efuse92e_shadow_read_2byte(hw, offset, (u16 *)value); +	else if (type == 4) +		efuse92e_shadow_read_4byte(hw, offset, (u32 *)value); +} +EXPORT_SYMBOL(efuse92e_shadow_read); + +void efuse92e_shadow_write(struct ieee80211_hw *hw, u8 type, u16 offset, +			   u32 value) +{ +	if (type == 1) +		efuse92e_shadow_write_1byte(hw, offset, (u8)value); +	else if (type == 2) +		efuse92e_shadow_write_2byte(hw, offset, (u16)value); +	else if (type == 4) +		efuse92e_shadow_write_4byte(hw, offset, (u32)value); +} + +bool efuse92e_shadow_update(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); +	u16 i, offset, base; +	u8 word_en = 0x0F; +	u8 first_pg = false; + +	RT_TRACE(COMP_EFUSE, DBG_LOUD, ("\n")); + +	if (!efuse92e_shadow_update_chk(hw)) { +		efuse_read_all_map(hw, &rtlefuse->efuse_map[EFUSE_INIT_MAP][0]); +		memcpy(&rtlefuse->efuse_map[EFUSE_MODIFY_MAP][0], +		       &rtlefuse->efuse_map[EFUSE_INIT_MAP][0], +		       rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE]); + +		RT_TRACE(COMP_EFUSE, DBG_LOUD, +			 ("efuse out of capacity!!\n")); +		return false; +	} +	efuse_power_switch(hw, true, true); + +	for (offset = 0; offset < 16; offset++) { +		word_en = 0x0F; +		base = offset * 8; + +		for (i = 0; i < 8; i++) { +			if (first_pg) { +				word_en &= ~(BIT(i / 2)); + +				rtlefuse->efuse_map[EFUSE_INIT_MAP][base + i] = +				    rtlefuse->efuse_map[EFUSE_MODIFY_MAP][base + i]; +			} else { +				if (rtlefuse->efuse_map[EFUSE_INIT_MAP][base + i] != +				    rtlefuse->efuse_map[EFUSE_MODIFY_MAP][base + i]) { +					word_en &= ~(BIT(i / 2)); + +					rtlefuse->efuse_map[EFUSE_INIT_MAP][base + i] = +					    rtlefuse->efuse_map[EFUSE_MODIFY_MAP][base + i]; +				} +			} +		} + +		if (word_en != 0x0F) { +			u8 tmpdata[8]; +			memcpy(tmpdata, +			       (&rtlefuse->efuse_map[EFUSE_MODIFY_MAP][base]), +			       8); +			RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_LOUD, +				      "U-efuse\n", tmpdata, 8); + +			if (!efuse_pg_packet_write(hw, (u8) offset, word_en, +						   tmpdata)) { +				RT_TRACE(COMP_ERR, DBG_WARNING, +					 ("PG section(%#x) fail!!\n", offset)); +				break; +			} +		} +	} + +	efuse_power_switch(hw, true, false); +	efuse_read_all_map(hw, &rtlefuse->efuse_map[EFUSE_INIT_MAP][0]); + +	memcpy(&rtlefuse->efuse_map[EFUSE_MODIFY_MAP][0], +	       &rtlefuse->efuse_map[EFUSE_INIT_MAP][0], +	       rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE]); + +	RT_TRACE(COMP_EFUSE, DBG_LOUD, ("\n")); +	return true; +} + +void stg_rtl_efuse92e_shadow_map_update(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + +	if (rtlefuse->autoload_failflag) { +		memset(&rtlefuse->efuse_map[EFUSE_INIT_MAP][0], +		       0xFF, rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE]); +	} else { +		efuse_read_all_map(hw, &rtlefuse->efuse_map[EFUSE_INIT_MAP][0]); +	} + +	memcpy(&rtlefuse->efuse_map[EFUSE_MODIFY_MAP][0], +	       &rtlefuse->efuse_map[EFUSE_INIT_MAP][0], +	       rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE]); +} +EXPORT_SYMBOL(stg_rtl_efuse92e_shadow_map_update); + +void efuse92e_force_write_vendor_Id(struct ieee80211_hw *hw) +{ +	u8 tmpdata[8] = { 0xFF, 0xFF, 0xEC, 0x10, 0xFF, 0xFF, 0xFF, 0xFF }; + +	efuse_power_switch(hw, true, true); +	efuse_pg_packet_write(hw, 1, 0xD, tmpdata); +	efuse_power_switch(hw, true, false); +} + +void efuse92e_re_pg_section(struct ieee80211_hw *hw, u8 section_idx) +{ +} + +static void efuse92e_shadow_read_1byte(struct ieee80211_hw *hw, +				       u16 offset, u8 *value) +{ +	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); +	*value = rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset]; +} + +static void efuse92e_shadow_read_2byte(struct ieee80211_hw *hw, +				       u16 offset, u16 *value) +{ +	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + +	*value = rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset]; +	*value |= rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset + 1] << 8; +} + +static void efuse92e_shadow_read_4byte(struct ieee80211_hw *hw, +				       u16 offset, u32 *value) +{ +	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + +	*value = rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset]; +	*value |= rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset + 1] << 8; +	*value |= rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset + 2] << 16; +	*value |= rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset + 3] << 24; +} + +static void efuse92e_shadow_write_1byte(struct ieee80211_hw *hw, +					u16 offset, u8 value) +{ +	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + +	rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset] = value; +} + +static void efuse92e_shadow_write_2byte(struct ieee80211_hw *hw, +					u16 offset, u16 value) +{ +	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + +	rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset] = value & 0x00FF; +	rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset + 1] = value >> 8; +} + +static void efuse92e_shadow_write_4byte(struct ieee80211_hw *hw, +					u16 offset, u32 value) +{ +	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + +	rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset] = +	    (u8) (value & 0x000000FF); +	rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset + 1] = +	    (u8) ((value >> 8) & 0x0000FF); +	rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset + 2] = +	    (u8) ((value >> 16) & 0x00FF); +	rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset + 3] = +	    (u8) ((value >> 24) & 0xFF); +} + +int stg_efuse_one_byte_read(struct ieee80211_hw *hw, u16 addr, u8 *data) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u8 tmpidx = 0; +	int bresult; + +	rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 1, +		       (u8) (addr & 0xff)); +	rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 2, +		       ((u8) ((addr >> 8) & 0x03)) | +		       (rtl_read_byte(rtlpriv, +				      rtlpriv->cfg->maps[EFUSE_CTRL] + 2) & +			0xFC)); + +	rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 3, 0x72); + +	while (!(0x80 & rtl_read_byte(rtlpriv, +				      rtlpriv->cfg->maps[EFUSE_CTRL] + 3)) && +	       (tmpidx < 100)) { +		tmpidx++; +	} + +	if (tmpidx < 100) { +		*data = rtl_read_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL]); +		bresult = true; +	} else { +		*data = 0xff; +		bresult = false; +	} +	return bresult; +} +EXPORT_SYMBOL(stg_efuse_one_byte_read); + +static int efuse_one_byte_write(struct ieee80211_hw *hw, u16 addr, u8 data) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u8 tmpidx = 0; +	bool bresult; + +	RT_TRACE(COMP_EFUSE, DBG_LOUD, +		 ("Addr = %x Data=%x\n", addr, data)); + +	rtl_write_byte(rtlpriv, +		       rtlpriv->cfg->maps[EFUSE_CTRL] + 1, (u8) (addr & 0xff)); +	rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 2, +		       (rtl_read_byte(rtlpriv, +			 rtlpriv->cfg->maps[EFUSE_CTRL] + +			 2) & 0xFC) | (u8) ((addr >> 8) & 0x03)); + +	rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL], data); +	rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 3, 0xF2); + +	while ((0x80 & rtl_read_byte(rtlpriv, +				     rtlpriv->cfg->maps[EFUSE_CTRL] + 3)) && +	       (tmpidx < 100)) { +		tmpidx++; +	} + +	if (tmpidx < 100) +		bresult = true; +	else +		bresult = false; + +	return bresult; +} + +static void efuse_read_all_map(struct ieee80211_hw *hw, u8 *efuse) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	efuse_power_switch(hw, false, true); +	read92e_efuse(hw, 0, rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE], efuse); +	efuse_power_switch(hw, false, false); +} + +static void efuse_read_data_case1(struct ieee80211_hw *hw, u16 *efuse_addr, +				u8 efuse_data, u8 offset, u8 *tmpdata, +				u8 *readstate) +{ +	bool bdataempty = true; +	u8 hoffset; +	u8 tmpidx; +	u8 hworden; +	u8 word_cnts; + +	hoffset = (efuse_data >> 4) & 0x0F; +	hworden = efuse_data & 0x0F; +	word_cnts = efuse_calculate_word_cnts(hworden); + +	if (hoffset == offset) { +		for (tmpidx = 0; tmpidx < word_cnts * 2; tmpidx++) { +			if (stg_efuse_one_byte_read(hw, *efuse_addr + 1 + tmpidx, +						    &efuse_data)) { +				tmpdata[tmpidx] = efuse_data; +				if (efuse_data != 0xff) +					bdataempty = false; +			} +		} + +		if (!bdataempty) { +			*readstate = PG_STATE_DATA; +		} else { +			*efuse_addr = *efuse_addr + (word_cnts * 2) + 1; +			*readstate = PG_STATE_HEADER; +		} + +	} else { +		*efuse_addr = *efuse_addr + (word_cnts * 2) + 1; +		*readstate = PG_STATE_HEADER; +	} +} + +static int efuse_pg_packet_read(struct ieee80211_hw *hw, u8 offset, u8 *data) +{ +	u8 readstate = PG_STATE_HEADER; + +	bool bcontinual = true; + +	u8 efuse_data, word_cnts = 0; +	u16 efuse_addr = 0; +	u8 hworden = 0; +	u8 tmpdata[8]; + +	if (data == NULL) +		return false; +	if (offset > 15) +		return false; + +	memset(data, 0xff, PGPKT_DATA_SIZE * sizeof(u8)); +	memset(tmpdata, 0xff, PGPKT_DATA_SIZE * sizeof(u8)); + +	while (bcontinual && (efuse_addr < EFUSE_MAX_SIZE)) { +		if (readstate & PG_STATE_HEADER) { +			if (stg_efuse_one_byte_read(hw, efuse_addr, &efuse_data) && +			    (efuse_data != 0xFF)) +				efuse_read_data_case1(hw, &efuse_addr, +						      efuse_data, offset, +						      tmpdata, &readstate); +			else +				bcontinual = false; +		} else if (readstate & PG_STATE_DATA) { +			efuse_word_enable_data_read(hworden, tmpdata, data); +			efuse_addr = efuse_addr + (word_cnts * 2) + 1; +			readstate = PG_STATE_HEADER; +		} +	} + +	if ((data[0] == 0xff) && (data[1] == 0xff) && +	    (data[2] == 0xff) && (data[3] == 0xff) && +	    (data[4] == 0xff) && (data[5] == 0xff) && +	    (data[6] == 0xff) && (data[7] == 0xff)) +		return false; +	else +		return true; +} + +static void efuse_write_data_case1(struct ieee80211_hw *hw, u16 *efuse_addr, +				   u8 efuse_data, u8 offset, +				   int *bcontinual, u8 *write_state, +				   struct pgpkt_struct *target_pkt, +				   int *repeat_times, int *bresult, u8 word_en) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct pgpkt_struct tmp_pkt; +	int bdataempty = true; +	u8 originaldata[8 * sizeof(u8)]; +	u8 badworden = 0x0F; +	u8 match_word_en, tmp_word_en; +	u8 tmpindex; +	u8 tmp_header = efuse_data; +	u8 tmp_word_cnts; + +	tmp_pkt.offset = (tmp_header >> 4) & 0x0F; +	tmp_pkt.word_en = tmp_header & 0x0F; +	tmp_word_cnts = efuse_calculate_word_cnts(tmp_pkt.word_en); + +	if (tmp_pkt.offset != target_pkt->offset) { +		*efuse_addr = *efuse_addr + (tmp_word_cnts * 2) + 1; +		*write_state = PG_STATE_HEADER; +	} else { +		for (tmpindex = 0; tmpindex < (tmp_word_cnts * 2); tmpindex++) { +			if (stg_efuse_one_byte_read(hw, +						(*efuse_addr + 1 + tmpindex), +						&efuse_data) && +			    (efuse_data != 0xFF)) +				bdataempty = false; +		} + +		if (!bdataempty) { +			*efuse_addr = *efuse_addr + (tmp_word_cnts * 2) + 1; +			*write_state = PG_STATE_HEADER; +		} else { +			match_word_en = 0x0F; +			if (!((target_pkt->word_en & BIT(0)) | +			    (tmp_pkt.word_en & BIT(0)))) +				match_word_en &= (~BIT(0)); + +			if (!((target_pkt->word_en & BIT(1)) | +			    (tmp_pkt.word_en & BIT(1)))) +				match_word_en &= (~BIT(1)); + +			if (!((target_pkt->word_en & BIT(2)) | +			    (tmp_pkt.word_en & BIT(2)))) +				match_word_en &= (~BIT(2)); + +			if (!((target_pkt->word_en & BIT(3)) | +			    (tmp_pkt.word_en & BIT(3)))) +				match_word_en &= (~BIT(3)); + +			if ((match_word_en & 0x0F) != 0x0F) { +				badworden = efuse_word_enable_data_write(hw, +							*efuse_addr + 1, +							tmp_pkt.word_en, +							target_pkt->data); + +				if (0x0F != (badworden & 0x0F))	{ +					u8 reorg_offset = offset; +					u8 reorg_worden = badworden; +					efuse_pg_packet_write(hw, reorg_offset, +							      reorg_worden, +							      originaldata); +				} + +				tmp_word_en = 0x0F; +				if ((target_pkt->word_en & BIT(0)) ^ +				    (match_word_en & BIT(0))) +					tmp_word_en &= (~BIT(0)); + +				if ((target_pkt->word_en & BIT(1)) ^ +				    (match_word_en & BIT(1))) +					tmp_word_en &= (~BIT(1)); + +				if ((target_pkt->word_en & BIT(2)) ^ +				    (match_word_en & BIT(2))) +					tmp_word_en &= (~BIT(2)); + +				if ((target_pkt->word_en & BIT(3)) ^ +				    (match_word_en & BIT(3))) +					tmp_word_en &= (~BIT(3)); + +				if ((tmp_word_en & 0x0F) != 0x0F) { +					*efuse_addr = efuse_get_current_size(hw); +					target_pkt->offset = offset; +					target_pkt->word_en = tmp_word_en; +				} else { +					*bcontinual = false; +				} +				*write_state = PG_STATE_HEADER; +				*repeat_times += 1; +				if (*repeat_times > EFUSE_REPEAT_THRESHOLD_) { +					*bcontinual = false; +					*bresult = false; +				} +			} else { +				*efuse_addr += (2 * tmp_word_cnts) + 1; +				target_pkt->offset = offset; +				target_pkt->word_en = word_en; +				*write_state = PG_STATE_HEADER; +			} +		} +	} +	RTPRINT(rtlpriv, FEEPROM, EFUSE_PG, "efuse PG_STATE_HEADER-1\n"); +} + +static void efuse_write_data_case2(struct ieee80211_hw *hw, u16 *efuse_addr, +				   int *bcontinual, u8 *write_state, +				   struct pgpkt_struct target_pkt, +				   int *repeat_times, int *bresult) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct pgpkt_struct tmp_pkt; +	u8 pg_header; +	u8 tmp_header; +	u8 originaldata[8 * sizeof(u8)]; +	u8 tmp_word_cnts; +	u8 badworden = 0x0F; + +	pg_header = ((target_pkt.offset << 4) & 0xf0) | target_pkt.word_en; +	efuse_one_byte_write(hw, *efuse_addr, pg_header); +	stg_efuse_one_byte_read(hw, *efuse_addr, &tmp_header); + +	if (tmp_header == pg_header) { +		*write_state = PG_STATE_DATA; +	} else if (tmp_header == 0xFF) { +		*write_state = PG_STATE_HEADER; +		*repeat_times += 1; +		if (*repeat_times > EFUSE_REPEAT_THRESHOLD_) { +			*bcontinual = false; +			*bresult = false; +		} +	} else { +		tmp_pkt.offset = (tmp_header >> 4) & 0x0F; +		tmp_pkt.word_en = tmp_header & 0x0F; + +		tmp_word_cnts = efuse_calculate_word_cnts(tmp_pkt.word_en); + +		memset(originaldata, 0xff,  8 * sizeof(u8)); + +		if (efuse_pg_packet_read(hw, tmp_pkt.offset, originaldata)) { +			badworden = efuse_word_enable_data_write(hw, +								 *efuse_addr + 1, +								 tmp_pkt.word_en, +								 originaldata); + +			if (0x0F != (badworden & 0x0F)) { +				u8 reorg_offset = tmp_pkt.offset; +				u8 reorg_worden = badworden; +				efuse_pg_packet_write(hw, reorg_offset, +						      reorg_worden, +						      originaldata); +				*efuse_addr = efuse_get_current_size(hw); +			} else { +				*efuse_addr = *efuse_addr + +					      (tmp_word_cnts * 2) + 1; +			} +		} else { +			*efuse_addr = *efuse_addr + (tmp_word_cnts * 2) + 1; +		} + +		*write_state = PG_STATE_HEADER; +		*repeat_times += 1; +		if (*repeat_times > EFUSE_REPEAT_THRESHOLD_) { +			*bcontinual = false; +			*bresult = false; +		} + +		RTPRINT(rtlpriv, FEEPROM, EFUSE_PG, +			"efuse PG_STATE_HEADER-2\n"); +	} +} + +static int efuse_pg_packet_write(struct ieee80211_hw *hw, +				 u8 offset, u8 word_en, u8 *data) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct pgpkt_struct target_pkt; +	u8 write_state = PG_STATE_HEADER; +	int bcontinual = true, bdataempty = true, bresult = true; +	u16 efuse_addr = 0; +	u8 efuse_data; +	u8 target_word_cnts = 0; +	u8 badworden = 0x0F; +	static int repeat_times; + +	if (efuse_get_current_size(hw) >= (EFUSE_MAX_SIZE - +		rtlpriv->cfg->maps[EFUSE_OOB_PROTECT_BYTES_LEN])) { +		RTPRINT(rtlpriv, FEEPROM, EFUSE_PG, +			"efuse_pg_packet_write error\n"); +		return false; +	} + +	target_pkt.offset = offset; +	target_pkt.word_en = word_en; + +	memset(target_pkt.data, 0xFF,  8 * sizeof(u8)); + +	efuse_word_enable_data_read(word_en, data, target_pkt.data); +	target_word_cnts = efuse_calculate_word_cnts(target_pkt.word_en); + +	RTPRINT(rtlpriv, FEEPROM, EFUSE_PG, "efuse Power ON\n"); + +	while (bcontinual && (efuse_addr < (EFUSE_MAX_SIZE - +	       rtlpriv->cfg->maps[EFUSE_OOB_PROTECT_BYTES_LEN]))) { +		if (write_state == PG_STATE_HEADER) { +			bdataempty = true; +			badworden = 0x0F; +			RTPRINT(rtlpriv, FEEPROM, EFUSE_PG, +				"efuse PG_STATE_HEADER\n"); + +			if (stg_efuse_one_byte_read(hw, efuse_addr, &efuse_data) && +			    (efuse_data != 0xFF)) +				efuse_write_data_case1(hw, &efuse_addr, +						       efuse_data, offset, +						       &bcontinual, +						       &write_state, +						       &target_pkt, +						       &repeat_times, &bresult, +						       word_en); +			else +				efuse_write_data_case2(hw, &efuse_addr, +						       &bcontinual, +						       &write_state, +						       target_pkt, +						       &repeat_times, +						       &bresult); + +		} else if (write_state == PG_STATE_DATA) { +			RTPRINT(rtlpriv, FEEPROM, EFUSE_PG, +				"efuse PG_STATE_DATA\n"); +			badworden = 0x0f; +			badworden = +			    efuse_word_enable_data_write(hw, efuse_addr + 1, +							 target_pkt.word_en, +							 target_pkt.data); + +			if ((badworden & 0x0F) == 0x0F) { +				bcontinual = false; +			} else { +				efuse_addr = +				    efuse_addr + (2 * target_word_cnts) + 1; + +				target_pkt.offset = offset; +				target_pkt.word_en = badworden; +				target_word_cnts = +				    efuse_calculate_word_cnts(target_pkt. +							      word_en); +				write_state = PG_STATE_HEADER; +				repeat_times++; +				if (repeat_times > EFUSE_REPEAT_THRESHOLD_) { +					bcontinual = false; +					bresult = false; +				} +				RTPRINT(rtlpriv, FEEPROM, EFUSE_PG, +					"efuse PG_STATE_HEADER-3\n"); +			} +		} +	} + +	if (efuse_addr >= (EFUSE_MAX_SIZE - +		rtlpriv->cfg->maps[EFUSE_OOB_PROTECT_BYTES_LEN])) { +		RT_TRACE(COMP_EFUSE, DBG_LOUD, +			 ("efuse_addr(%#x) Out of size!!\n", efuse_addr)); +	} + +	return true; +} + +static void efuse_word_enable_data_read(u8 word_en, u8 *sourdata, +					u8 *targetdata) +{ +	if (!(word_en & BIT(0))) { +		targetdata[0] = sourdata[0]; +		targetdata[1] = sourdata[1]; +	} + +	if (!(word_en & BIT(1))) { +		targetdata[2] = sourdata[2]; +		targetdata[3] = sourdata[3]; +	} + +	if (!(word_en & BIT(2))) { +		targetdata[4] = sourdata[4]; +		targetdata[5] = sourdata[5]; +	} + +	if (!(word_en & BIT(3))) { +		targetdata[6] = sourdata[6]; +		targetdata[7] = sourdata[7]; +	} +} + +static u8 efuse_word_enable_data_write(struct ieee80211_hw *hw, +				       u16 efuse_addr, u8 word_en, u8 *data) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u16 tmpaddr; +	u16 start_addr = efuse_addr; +	u8 badworden = 0x0F; +	u8 tmpdata[8]; + +	memset(tmpdata, 0xff, PGPKT_DATA_SIZE); +	RT_TRACE(COMP_EFUSE, DBG_LOUD, +		 ("word_en = %x efuse_addr=%x\n", word_en, efuse_addr)); + +	if (!(word_en & BIT(0))) { +		tmpaddr = start_addr; +		efuse_one_byte_write(hw, start_addr++, data[0]); +		efuse_one_byte_write(hw, start_addr++, data[1]); + +		stg_efuse_one_byte_read(hw, tmpaddr, &tmpdata[0]); +		stg_efuse_one_byte_read(hw, tmpaddr + 1, &tmpdata[1]); +		if ((data[0] != tmpdata[0]) || (data[1] != tmpdata[1])) +			badworden &= (~BIT(0)); +	} + +	if (!(word_en & BIT(1))) { +		tmpaddr = start_addr; +		efuse_one_byte_write(hw, start_addr++, data[2]); +		efuse_one_byte_write(hw, start_addr++, data[3]); + +		stg_efuse_one_byte_read(hw, tmpaddr, &tmpdata[2]); +		stg_efuse_one_byte_read(hw, tmpaddr + 1, &tmpdata[3]); +		if ((data[2] != tmpdata[2]) || (data[3] != tmpdata[3])) +			badworden &= (~BIT(1)); +	} + +	if (!(word_en & BIT(2))) { +		tmpaddr = start_addr; +		efuse_one_byte_write(hw, start_addr++, data[4]); +		efuse_one_byte_write(hw, start_addr++, data[5]); + +		stg_efuse_one_byte_read(hw, tmpaddr, &tmpdata[4]); +		stg_efuse_one_byte_read(hw, tmpaddr + 1, &tmpdata[5]); +		if ((data[4] != tmpdata[4]) || (data[5] != tmpdata[5])) +			badworden &= (~BIT(2)); +	} + +	if (!(word_en & BIT(3))) { +		tmpaddr = start_addr; +		efuse_one_byte_write(hw, start_addr++, data[6]); +		efuse_one_byte_write(hw, start_addr++, data[7]); + +		stg_efuse_one_byte_read(hw, tmpaddr, &tmpdata[6]); +		stg_efuse_one_byte_read(hw, tmpaddr + 1, &tmpdata[7]); +		if ((data[6] != tmpdata[6]) || (data[7] != tmpdata[7])) +			badworden &= (~BIT(3)); +	} + +	return badworden; +} + +static void efuse_power_switch(struct ieee80211_hw *hw, u8 bwrite, u8 pwrstate) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); +	u8 tempval; +	u16 tmpv16; + +	if (pwrstate && (rtlhal->hw_type != HARDWARE_TYPE_RTL8192SE)) { +		if (rtlhal->hw_type != HARDWARE_TYPE_RTL8192CE && +		    rtlhal->hw_type != HARDWARE_TYPE_RTL8192DE) { +			rtl_write_byte(rtlpriv, +				       rtlpriv->cfg->maps[EFUSE_ACCESS], 0x69); +		} else { +			tmpv16 = rtl_read_word(rtlpriv, +					       rtlpriv->cfg->maps[SYS_ISO_CTRL]); +			if (!(tmpv16 & rtlpriv->cfg->maps[EFUSE_PWC_EV12V])) { +				tmpv16 |= rtlpriv->cfg->maps[EFUSE_PWC_EV12V]; +				rtl_write_word(rtlpriv, +					       rtlpriv->cfg->maps[SYS_ISO_CTRL], +					       tmpv16); +			} +		} +		tmpv16 = rtl_read_word(rtlpriv, +				       rtlpriv->cfg->maps[SYS_FUNC_EN]); +		if (!(tmpv16 & rtlpriv->cfg->maps[EFUSE_FEN_ELDR])) { +			tmpv16 |= rtlpriv->cfg->maps[EFUSE_FEN_ELDR]; +			rtl_write_word(rtlpriv, +				       rtlpriv->cfg->maps[SYS_FUNC_EN], tmpv16); +		} + +		tmpv16 = rtl_read_word(rtlpriv, rtlpriv->cfg->maps[SYS_CLK]); +		if ((!(tmpv16 & rtlpriv->cfg->maps[EFUSE_LOADER_CLK_EN])) || +		    (!(tmpv16 & rtlpriv->cfg->maps[EFUSE_ANA8M]))) { +			tmpv16 |= (rtlpriv->cfg->maps[EFUSE_LOADER_CLK_EN] | +				   rtlpriv->cfg->maps[EFUSE_ANA8M]); +			rtl_write_word(rtlpriv, +				       rtlpriv->cfg->maps[SYS_CLK], tmpv16); +		} +	} + +	if (pwrstate) { +		if (bwrite) { +			tempval = rtl_read_byte(rtlpriv, +						rtlpriv->cfg->maps[EFUSE_TEST] + +						3); + +			if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) { +				tempval &= ~(BIT(3) | BIT(4) | BIT(5) | BIT(6)); +				tempval |= (VOLTAGE_V25 << 3); +			} else if (rtlhal->hw_type != HARDWARE_TYPE_RTL8192SE) { +				tempval &= 0x0F; +				tempval |= (VOLTAGE_V25 << 4); +			} + +			rtl_write_byte(rtlpriv, +				       rtlpriv->cfg->maps[EFUSE_TEST] + 3, +				       (tempval | 0x80)); +		} + +		if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192SE) { +			rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CLK], +				       0x03); +		} +	} else { +		if (rtlhal->hw_type != HARDWARE_TYPE_RTL8192CE && +		    rtlhal->hw_type != HARDWARE_TYPE_RTL8192DE) +			rtl_write_byte(rtlpriv, +				       rtlpriv->cfg->maps[EFUSE_ACCESS], 0); +		if (bwrite) { +			tempval = rtl_read_byte(rtlpriv, +						rtlpriv->cfg->maps[EFUSE_TEST] + +						3); +			rtl_write_byte(rtlpriv, +				       rtlpriv->cfg->maps[EFUSE_TEST] + 3, +				       (tempval & 0x7F)); +		} + +		if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192SE) { +			rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CLK], +				       0x02); +		} +	} +} + +static u16 efuse_get_current_size(struct ieee80211_hw *hw) +{ +	int bcontinual = true; +	u16 efuse_addr = 0; +	u8 hoffset, hworden; +	u8 efuse_data, word_cnts; + +	while (bcontinual && +	       stg_efuse_one_byte_read(hw, efuse_addr, &efuse_data) && +	       (efuse_addr < EFUSE_MAX_SIZE)) { +		if (efuse_data != 0xFF) { +			hoffset = (efuse_data >> 4) & 0x0F; +			hworden = efuse_data & 0x0F; +			word_cnts = efuse_calculate_word_cnts(hworden); +			efuse_addr = efuse_addr + (word_cnts * 2) + 1; +		} else { +			bcontinual = false; +		} +	} + +	return efuse_addr; +} + +static u8 efuse_calculate_word_cnts(u8 word_en) +{ +	u8 word_cnts = 0; +	if (!(word_en & BIT(0))) +		word_cnts++; +	if (!(word_en & BIT(1))) +		word_cnts++; +	if (!(word_en & BIT(2))) +		word_cnts++; +	if (!(word_en & BIT(3))) +		word_cnts++; +	return word_cnts; +} diff --git a/drivers/staging/rtl8192ee/efuse.h b/drivers/staging/rtl8192ee/efuse.h new file mode 100644 index 00000000000..cc3e1116b3e --- /dev/null +++ b/drivers/staging/rtl8192ee/efuse.h @@ -0,0 +1,127 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010  Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __RTL_EFUSE_H_ +#define __RTL_EFUSE_H_ + +#define EFUSE_IC_ID_OFFSET		506 + +/* +#define EFUSE_REAL_CONTENT_LEN	512 +#define EFUSE_MAP_LEN			128 +#define EFUSE_MAX_SECTION		16 +#define EFUSE_MAX_WORD_UNIT		4 +#define EFUSE_IC_ID_OFFSET		506 +*/ + +#define EFUSE_MAX_WORD_UNIT		4 + +#define EFUSE_INIT_MAP			0 +#define EFUSE_MODIFY_MAP		1 + +#define PG_STATE_HEADER			0x01 +#define PG_STATE_WORD_0			0x02 +#define PG_STATE_WORD_1			0x04 +#define PG_STATE_WORD_2			0x08 +#define PG_STATE_WORD_3			0x10 +#define PG_STATE_DATA			0x20 + +#define PG_SWBYTE_H			0x01 +#define PG_SWBYTE_L			0x02 + +#define _POWERON_DELAY_ +#define _PRE_EXECUTE_READ_CMD_ + +#define EFUSE_REPEAT_THRESHOLD_		3 +#define EFUSE_ERROE_HANDLE		1 + +struct efuse_map { +	u8 offset; +	u8 word_start; +	u8 byte_start; +	u8 byte_cnts; +}; + +struct pgpkt_struct { +	u8 offset; +	u8 word_en; +	u8 data[8]; +}; + +enum efuse_data_item { +	EFUSE_CHIP_ID = 0, +	EFUSE_LDO_SETTING, +	EFUSE_CLK_SETTING, +	EFUSE_SDIO_SETTING, +	EFUSE_CCCR, +	EFUSE_SDIO_MODE, +	EFUSE_OCR, +	EFUSE_F0CIS, +	EFUSE_F1CIS, +	EFUSE_MAC_ADDR, +	EFUSE_EEPROM_VER, +	EFUSE_CHAN_PLAN, +	EFUSE_TXPW_TAB +}; + +enum { +	VOLTAGE_V25 = 0x03, +	LDOE25_SHIFT = 28, +}; + +struct efuse_priv { +	u8 id[2]; +	u8 ldo_setting[2]; +	u8 clk_setting[2]; +	u8 cccr; +	u8 sdio_mode; +	u8 ocr[3]; +	u8 cis0[17]; +	u8 cis1[48]; +	u8 mac_addr[6]; +	u8 eeprom_verno; +	u8 channel_plan; +	u8 tx_power_b[14]; +	u8 tx_power_g[14]; +}; + +void read92e_efuse_byte(struct ieee80211_hw *hw, u16 _offset, u8 *pbuf); +void efuse92e_initialize(struct ieee80211_hw *hw); +u8 stg_efuse_read_1byte(struct ieee80211_hw *hw, u16 address); +int stg_efuse_one_byte_read(struct ieee80211_hw *hw, u16 addr, u8 *data); +void efuse92e_write_1byte(struct ieee80211_hw *hw, u16 address, u8 value); +void read92e_efuse(struct ieee80211_hw *hw, u16 _offset, +		   u16 _size_byte, u8 *pbuf); +void efuse92e_shadow_read(struct ieee80211_hw *hw, u8 type, +		          u16 offset, u32 *value); +void efuse92e_shadow_write(struct ieee80211_hw *hw, u8 type, +			   u16 offset, u32 value); +bool efuse92e_shadow_update(struct ieee80211_hw *hw); +bool efuse92e_shadow_update_chk(struct ieee80211_hw *hw); +void stg_rtl_efuse92e_shadow_map_update(struct ieee80211_hw *hw); +void efuse92e_force_write_vendor_Id(struct ieee80211_hw *hw); +void efuse92e_re_pg_section(struct ieee80211_hw *hw, u8 section_idx); + +#endif diff --git a/drivers/staging/rtl8192ee/pci.c b/drivers/staging/rtl8192ee/pci.c new file mode 100644 index 00000000000..3fe9b7ba01d --- /dev/null +++ b/drivers/staging/rtl8192ee/pci.c @@ -0,0 +1,2397 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010  Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#include "core.h" +#include "wifi.h" +#include "pci.h" +#include "base.h" +#include "ps.h" +#include "efuse.h" + +static const u16 pcibridge_vendors[PCI_BRIDGE_VENDOR_MAX] = { +	INTEL_VENDOR_ID, +	ATI_VENDOR_ID, +	AMD_VENDOR_ID, +	SIS_VENDOR_ID +}; + +static const u8 ac_to_hwq[] = { +	VO_QUEUE, +	VI_QUEUE, +	BE_QUEUE, +	BK_QUEUE +}; + +static u8 _rtl_mac_to_hwqueue(struct ieee80211_hw *hw, +			      struct sk_buff *skb) +{ +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); +	__le16 fc = rtl_get_fc(skb); +	u8 queue_index = skb_get_queue_mapping(skb); + +	if (unlikely(ieee80211_is_beacon(fc))) +		return BEACON_QUEUE; +	if (ieee80211_is_mgmt(fc) || ieee80211_is_ctl(fc)) +		return MGNT_QUEUE; +	if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192SE) +		if (ieee80211_is_nullfunc(fc)) +			return HIGH_QUEUE; + +	return ac_to_hwq[queue_index]; +} + +/* Update PCI dependent default settings*/ +static void _rtl_pci_update_default_setting(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); +	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); +	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); +	u8 pcibridge_vendor = pcipriv->ndis_adapter.pcibridge_vendor; +	u8 init_aspm; + +	ppsc->reg_rfps_level = 0; +	ppsc->b_support_aspm = 0; + +	/*Update PCI ASPM setting */ +	ppsc->const_amdpci_aspm = rtlpci->const_amdpci_aspm; +	switch (rtlpci->const_pci_aspm) { +	case 0: +		/*No ASPM */ +		break; + +	case 1: +		/*ASPM dynamically enabled/disable. */ +		ppsc->reg_rfps_level |= RT_RF_LPS_LEVEL_ASPM; +		break; + +	case 2: +		/*ASPM with Clock Req dynamically enabled/disable. */ +		ppsc->reg_rfps_level |= (RT_RF_LPS_LEVEL_ASPM | +					 RT_RF_OFF_LEVL_CLK_REQ); +		break; + +	case 3: +		/* +		 * Always enable ASPM and Clock Req +		 * from initialization to halt. +		 * */ +		ppsc->reg_rfps_level &= ~(RT_RF_LPS_LEVEL_ASPM); +		ppsc->reg_rfps_level |= (RT_RF_PS_LEVEL_ALWAYS_ASPM | +					 RT_RF_OFF_LEVL_CLK_REQ); +		break; + +	case 4: +		/* +		 * Always enable ASPM without Clock Req +		 * from initialization to halt. +		 * */ +		ppsc->reg_rfps_level &= ~(RT_RF_LPS_LEVEL_ASPM | +					  RT_RF_OFF_LEVL_CLK_REQ); +		ppsc->reg_rfps_level |= RT_RF_PS_LEVEL_ALWAYS_ASPM; +		break; +	} + +	ppsc->reg_rfps_level |= RT_RF_OFF_LEVL_HALT_NIC; + +	/*Update Radio OFF setting */ +	switch (rtlpci->const_hwsw_rfoff_d3) { +	case 1: +		if (ppsc->reg_rfps_level & RT_RF_LPS_LEVEL_ASPM) +			ppsc->reg_rfps_level |= RT_RF_OFF_LEVL_ASPM; +		break; + +	case 2: +		if (ppsc->reg_rfps_level & RT_RF_LPS_LEVEL_ASPM) +			ppsc->reg_rfps_level |= RT_RF_OFF_LEVL_ASPM; +		ppsc->reg_rfps_level |= RT_RF_OFF_LEVL_HALT_NIC; +		break; + +	case 3: +		ppsc->reg_rfps_level |= RT_RF_OFF_LEVL_PCI_D3; +		break; +	} + +	/*Set HW definition to determine if it supports ASPM. */ +	switch (rtlpci->const_support_pciaspm) { +	case 0:{ +			/*Not support ASPM. */ +			bool b_support_aspm = false; +			ppsc->b_support_aspm = b_support_aspm; +			break; +		} +	case 1:{ +			/*Support ASPM. */ +			bool b_support_aspm = true; +			bool b_support_backdoor = true; +			ppsc->b_support_aspm = b_support_aspm; + +			/*if (priv->oem_id == RT_CID_TOSHIBA && +			   !priv->ndis_adapter.amd_l1_patch) +			   b_support_backdoor = false; */ + +			ppsc->b_support_backdoor = b_support_backdoor; + +			break; +		} +	case 2: +		/*ASPM value set by chipset. */ +		if (pcibridge_vendor == PCI_BRIDGE_VENDOR_INTEL) { +			bool b_support_aspm = true; +			ppsc->b_support_aspm = b_support_aspm; +		} +		break; +	default: +		RT_TRACE(COMP_ERR, DBG_EMERG, +			 ("switch case not process\n")); +		break; +	} + +	/* toshiba aspm issue, toshiba will set aspm selfly +	 * so we should not set aspm in driver */ +	pci_read_config_byte(rtlpci->pdev, 0x80, &init_aspm); +	if (rtlpriv->rtlhal.hw_type == HARDWARE_TYPE_RTL8192SE && +	    init_aspm == 0x43) +		ppsc->b_support_aspm = false; +} + +static bool _rtl_pci_platform_switch_device_pci_aspm(struct ieee80211_hw *hw, +						     u8 value) +{ +	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); +	bool bresult = false; + +	if (rtlhal->hw_type != HARDWARE_TYPE_RTL8192SE) +		value |= 0x40; + +	pci_write_config_byte(rtlpci->pdev, 0x80, value); + +	return bresult; +} + +/*When we set 0x01 to enable clk request. Set 0x0 to disable clk req.*/ +static bool _rtl_pci_switch_clk_req(struct ieee80211_hw *hw, u8 value) +{ +	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); +	bool bresult = false; + +	pci_write_config_byte(rtlpci->pdev, 0x81, value); +	bresult = true; + +	if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192SE) +		udelay(100); + +	return bresult; +} + +/*Disable RTL8192SE ASPM & Disable Pci Bridge ASPM*/ +static void rtl_pci_disable_aspm(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); +	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); +	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); +	u8 pcibridge_vendor = pcipriv->ndis_adapter.pcibridge_vendor; +	u32 pcicfg_addrport = pcipriv->ndis_adapter.pcicfg_addrport; +	u8 num4bytes = pcipriv->ndis_adapter.num4bytes; +	/*Retrieve original configuration settings. */ +	u8 linkctrl_reg = pcipriv->ndis_adapter.linkctrl_reg; +	u16 pcibridge_linkctrlreg = pcipriv->ndis_adapter. +				pcibridge_linkctrlreg; +	u16 aspmlevel = 0; + +	if (!ppsc->b_support_aspm) +		return; + +	if (pcibridge_vendor == PCI_BRIDGE_VENDOR_UNKNOWN) { +		RT_TRACE(COMP_POWER, DBG_TRACE, +			 ("PCI(Bridge) UNKNOWN.\n")); + +		return; +	} + +	if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_CLK_REQ) { +		RT_CLEAR_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_CLK_REQ); +		_rtl_pci_switch_clk_req(hw, 0x0); +	} + +	if (1) { +		/*for promising device will in L0 state after an I/O. */ +		u8 tmp_u1b; +		pci_read_config_byte(rtlpci->pdev, 0x80, &tmp_u1b); +	} + +	/*Set corresponding value. */ +	aspmlevel |= BIT(0) | BIT(1); +	linkctrl_reg &= ~aspmlevel; +	pcibridge_linkctrlreg &= ~(BIT(0) | BIT(1)); + +	_rtl_pci_platform_switch_device_pci_aspm(hw, linkctrl_reg); +	udelay(50); + +	/*4 Disable Pci Bridge ASPM */ +	rtl_pci_raw_write_port_ulong(PCI_CONF_ADDRESS, +				     pcicfg_addrport + (num4bytes << 2)); +	rtl_pci_raw_write_port_uchar(PCI_CONF_DATA, pcibridge_linkctrlreg); + +	udelay(50); +} + +/* + *Enable RTL8192SE ASPM & Enable Pci Bridge ASPM for + *power saving We should follow the sequence to enable + *RTL8192SE first then enable Pci Bridge ASPM + *or the system will show bluescreen. + */ +static void rtl_pci_enable_aspm(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); +	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); +	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); +	u8 pcibridge_vendor = pcipriv->ndis_adapter.pcibridge_vendor; +	u32 pcicfg_addrport = pcipriv->ndis_adapter.pcicfg_addrport; +	u8 num4bytes = pcipriv->ndis_adapter.num4bytes; +	u16 aspmlevel; +	u8 u_pcibridge_aspmsetting; +	u8 u_device_aspmsetting; + +	if (!ppsc->b_support_aspm) +		return; + +	if (pcibridge_vendor == PCI_BRIDGE_VENDOR_UNKNOWN) { +		RT_TRACE(COMP_POWER, DBG_TRACE, +			 ("PCI(Bridge) UNKNOWN.\n")); +		return; +	} + +	/*4 Enable Pci Bridge ASPM */ +	rtl_pci_raw_write_port_ulong(PCI_CONF_ADDRESS, +				     pcicfg_addrport + (num4bytes << 2)); + +	u_pcibridge_aspmsetting = +	    pcipriv->ndis_adapter.pcibridge_linkctrlreg | +	    rtlpci->const_hostpci_aspm_setting; + +	if (pcibridge_vendor == PCI_BRIDGE_VENDOR_INTEL) +		u_pcibridge_aspmsetting &= ~BIT(0); + +	rtl_pci_raw_write_port_uchar(PCI_CONF_DATA, u_pcibridge_aspmsetting); + +	RT_TRACE(COMP_INIT, DBG_LOUD, +		 ("PlatformEnableASPM(): Write reg[%x] = %x\n", +		  (pcipriv->ndis_adapter.pcibridge_pciehdr_offset + 0x10), +		  u_pcibridge_aspmsetting)); + +	udelay(50); + +	/*Get ASPM level (with/without Clock Req) */ +	aspmlevel = rtlpci->const_devicepci_aspm_setting; +	u_device_aspmsetting = pcipriv->ndis_adapter.linkctrl_reg; + +	/*_rtl_pci_platform_switch_device_pci_aspm(dev,*/ +	/*(priv->ndis_adapter.linkctrl_reg | ASPMLevel)); */ + +	u_device_aspmsetting |= aspmlevel; + +	_rtl_pci_platform_switch_device_pci_aspm(hw, u_device_aspmsetting); + +	if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_CLK_REQ) { +		_rtl_pci_switch_clk_req(hw, (ppsc->reg_rfps_level & +					     RT_RF_OFF_LEVL_CLK_REQ) ? 1 : 0); +		RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_CLK_REQ); +	} +	udelay(100); +} + +static bool rtl_pci_get_amd_l1_patch(struct ieee80211_hw *hw) +{ +	struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); +	u32 pcicfg_addrport = pcipriv->ndis_adapter.pcicfg_addrport; + +	bool status = false; +	u8 offset_e0; +	unsigned offset_e4; + +	rtl_pci_raw_write_port_ulong(PCI_CONF_ADDRESS, pcicfg_addrport + 0xE0); +	rtl_pci_raw_write_port_uchar(PCI_CONF_DATA, 0xA0); + +	rtl_pci_raw_write_port_ulong(PCI_CONF_ADDRESS, pcicfg_addrport + 0xE0); +	rtl_pci_raw_read_port_uchar(PCI_CONF_DATA, &offset_e0); + +	if (offset_e0 == 0xA0) { +		rtl_pci_raw_write_port_ulong(PCI_CONF_ADDRESS, +					     pcicfg_addrport + 0xE4); +		rtl_pci_raw_read_port_ulong(PCI_CONF_DATA, &offset_e4); +		if (offset_e4 & BIT(23)) +			status = true; +	} + +	return status; +} + +static bool rtl_pci_check_buddy_priv(struct ieee80211_hw *hw, +				     struct rtl_priv **buddy_priv) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); +	bool find_buddy_priv = false; +	struct rtl_priv *tpriv = NULL; +	struct rtl_pci_priv *tpcipriv = NULL; + +	if (!list_empty(&rtlpriv->glb_var->glb_priv_list)) { +		list_for_each_entry(tpriv, &rtlpriv->glb_var->glb_priv_list, +				    list) { +			if (tpriv == NULL) +				break; + +			tpcipriv = (struct rtl_pci_priv *)tpriv->priv; +			RT_TRACE(COMP_INIT, DBG_LOUD, +				 ("pcipriv->ndis_adapter.funcnumber %x\n", +				  pcipriv->ndis_adapter.funcnumber)); +			RT_TRACE(COMP_INIT, DBG_LOUD, +				 ("tpcipriv->ndis_adapter.funcnumber %x\n", +				  tpcipriv->ndis_adapter.funcnumber)); + +			if ((pcipriv->ndis_adapter.busnumber == +			     tpcipriv->ndis_adapter.busnumber) && +			    (pcipriv->ndis_adapter.devnumber == +			     tpcipriv->ndis_adapter.devnumber) && +			    (pcipriv->ndis_adapter.funcnumber != +			     tpcipriv->ndis_adapter.funcnumber)) { +				find_buddy_priv = true; +				break; +			} +		} +	} + +	RT_TRACE(COMP_INIT, DBG_LOUD, +		 ("find_buddy_priv %d\n", find_buddy_priv)); + +	if (find_buddy_priv) +		*buddy_priv = tpriv; + +	return find_buddy_priv; +} + +static void rtl_pci_get_linkcontrol_field(struct ieee80211_hw *hw) +{ +	struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); +	u8 capabilityoffset = pcipriv->ndis_adapter.pcibridge_pciehdr_offset; +	u32 pcicfg_addrport = pcipriv->ndis_adapter.pcicfg_addrport; +	u8 linkctrl_reg; +	u8 num4bbytes; + +	num4bbytes = (capabilityoffset + 0x10) / 4; + +	/*Read  Link Control Register */ +	rtl_pci_raw_write_port_ulong(PCI_CONF_ADDRESS, +				     pcicfg_addrport + (num4bbytes << 2)); +	rtl_pci_raw_read_port_uchar(PCI_CONF_DATA, &linkctrl_reg); + +	pcipriv->ndis_adapter.pcibridge_linkctrlreg = linkctrl_reg; +} + +static void rtl_pci_parse_configuration(struct pci_dev *pdev, +					struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); + +	u8 tmp; +	int pos; +	u8 linkctrl_reg; + +	/*Link Control Register */ +	pos = pci_find_capability(pdev, PCI_CAP_ID_EXP); +	pci_read_config_byte(pdev, pos + PCI_EXP_LNKCTL, &linkctrl_reg); +	pcipriv->ndis_adapter.linkctrl_reg = linkctrl_reg; + +	RT_TRACE(COMP_INIT, DBG_TRACE, +		 ("Link Control Register =%x\n", +		  pcipriv->ndis_adapter.linkctrl_reg)); + +	pci_read_config_byte(pdev, 0x98, &tmp); +	tmp |= BIT(4); +	pci_write_config_byte(pdev, 0x98, tmp); + +	tmp = 0x17; +	pci_write_config_byte(pdev, 0x70f, tmp); +} + +static void rtl_pci_init_aspm(struct ieee80211_hw *hw) +{ +	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + +	_rtl_pci_update_default_setting(hw); + +	if (ppsc->reg_rfps_level & RT_RF_PS_LEVEL_ALWAYS_ASPM) { +		/*Always enable ASPM & Clock Req. */ +		rtl_pci_enable_aspm(hw); +		RT_SET_PS_LEVEL(ppsc, RT_RF_PS_LEVEL_ALWAYS_ASPM); +	} +} + +static void _rtl_pci_io_handler_init(struct device *dev, +				     struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); + +	rtlpriv->io.dev = dev; + +	rtlpriv->io.write8_async = pci_write8_async; +	rtlpriv->io.write16_async = pci_write16_async; +	rtlpriv->io.write32_async = pci_write32_async; + +	rtlpriv->io.read8_sync = pci_read8_sync; +	rtlpriv->io.read16_sync = pci_read16_sync; +	rtlpriv->io.read32_sync = pci_read32_sync; +} + +static bool _rtl_pci_update_earlymode_info(struct ieee80211_hw *hw, +					   struct sk_buff *skb, +					   struct rtl_tcb_desc *tcb_desc, +					   u8 tid) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); +	struct sk_buff *next_skb; +	u8 additionlen = FCS_LEN; + +	/* here open is 4, wep/tkip is 8, aes is 12*/ +	if (info->control.hw_key) +		additionlen += info->control.hw_key->icv_len; + +	/* The most skb num is 6 */ +	tcb_desc->empkt_num = 0; +	spin_lock_bh(&rtlpriv->locks.waitq_lock); +	skb_queue_walk(&rtlpriv->mac80211.skb_waitq[tid], next_skb) { +		struct ieee80211_tx_info *next_info; + +		next_info = IEEE80211_SKB_CB(next_skb); +		if (next_info->flags & IEEE80211_TX_CTL_AMPDU) { +			tcb_desc->empkt_len[tcb_desc->empkt_num] = +				next_skb->len + additionlen; +			tcb_desc->empkt_num++; +		} else { +			break; +		} + +		if (skb_queue_is_last(&rtlpriv->mac80211.skb_waitq[tid], +				      next_skb)) +			break; + +		if (tcb_desc->empkt_num >= rtlhal->max_earlymode_num) +			break; +	} +	spin_unlock_bh(&rtlpriv->locks.waitq_lock); +	return true; +} + +/* just for early mode now */ +static void _rtl_pci_tx_chk_waitq(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); +	struct sk_buff *skb = NULL; +	struct ieee80211_tx_info *info = NULL; +	int tid; /* should be int */ + +	if (!rtlpriv->rtlhal.b_earlymode_enable) +		return; +	if (rtlpriv->dm.supp_phymode_switch && +	    (rtlpriv->easy_concurrent_ctl.bswitch_in_process || +	    (rtlpriv->buddy_priv && +	     rtlpriv->buddy_priv->easy_concurrent_ctl.bswitch_in_process))) +		return; +	/* we juse use em for BE/BK/VI/VO */ +	for (tid = 7; tid >= 0; tid--) { +		u8 hw_queue = ac_to_hwq[rtl92e_tid_to_ac(hw, tid)]; +		struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[hw_queue]; +		while (!mac->act_scanning && +		       rtlpriv->psc.rfpwr_state == ERFON) { +			struct rtl_tcb_desc tcb_desc; +			memset(&tcb_desc, 0, sizeof(struct rtl_tcb_desc)); + +			spin_lock_bh(&rtlpriv->locks.waitq_lock); +			if (!skb_queue_empty(&mac->skb_waitq[tid]) && +			    (ring->entries - skb_queue_len(&ring->queue) > +			     rtlhal->max_earlymode_num)) { +				skb = skb_dequeue(&mac->skb_waitq[tid]); +			} else { +				spin_unlock_bh(&rtlpriv->locks.waitq_lock); +				break; +			} +			spin_unlock_bh(&rtlpriv->locks.waitq_lock); + +			/* Some macaddr can't do early mode. like +			 * multicast/broadcast/no_qos data */ +			info = IEEE80211_SKB_CB(skb); +			if (info->flags & IEEE80211_TX_CTL_AMPDU) +				_rtl_pci_update_earlymode_info(hw, skb, +							       &tcb_desc, tid); + +			rtlpriv->intf_ops->adapter_tx(hw, NULL, skb, &tcb_desc); +		} +	} +} + +static void _rtl_pci_tx_isr(struct ieee80211_hw *hw, int prio) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); +	struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[prio]; + +	while (skb_queue_len(&ring->queue)) { +		struct sk_buff *skb; +		struct ieee80211_tx_info *info; +		__le16 fc; +		u8 tid; +		u8 *entry; + + +		if (rtlpriv->use_new_trx_flow) +			entry = (u8 *)(&ring->buffer_desc[ring->idx]); +		else +			entry = (u8 *)(&ring->desc[ring->idx]); + +		if (rtlpriv->cfg->ops->is_tx_desc_closed && +		    !rtlpriv->cfg->ops->is_tx_desc_closed(hw, prio, ring->idx)) +			return; + +		ring->idx = (ring->idx + 1) % ring->entries; + +		skb = __skb_dequeue(&ring->queue); + +		pci_unmap_single(rtlpci->pdev, +				 rtlpriv->cfg->ops-> +					     get_desc((u8 *)entry, true, +						      HW_DESC_TXBUFF_ADDR), +				 skb->len, PCI_DMA_TODEVICE); + +		/* remove early mode header */ +		if (rtlpriv->rtlhal.b_earlymode_enable) +			skb_pull(skb, EM_HDR_LEN); + +		RT_TRACE((COMP_INTR | COMP_SEND), DBG_TRACE, +			 ("new ring->idx:%d, free: skb_queue_len:%d, free: seq:%d\n", +			  ring->idx, +			  skb_queue_len(&ring->queue), +			  *(u16 *)(skb->data + 22))); + +		if (prio == TXCMD_QUEUE) { +			dev_kfree_skb(skb); +			goto tx_status_ok; +		} + +		/* for sw LPS, just after NULL skb send out, we can +		 * sure AP knows that we are sleeping, our we should not let +		 * rf to sleep +		 */ +		fc = rtl_get_fc(skb); +		if (ieee80211_is_nullfunc(fc)) { +			if (ieee80211_has_pm(fc)) { +				rtlpriv->mac80211.offchan_deley = true; +				rtlpriv->psc.state_inap = 1; +			} else { +				rtlpriv->psc.state_inap = 0; +			} +		} +		if (ieee80211_is_action(fc)) { +			struct ieee80211_mgmt_compat *action_frame = +				(struct ieee80211_mgmt_compat *)skb->data; +			if (action_frame->u.action.u.ht_smps.action == +				WLAN_HT_ACTION_SMPS) { +				dev_kfree_skb(skb); +				goto tx_status_ok; +			} +		} + +		/* update tid tx pkt num */ +		tid = rtl_get_tid(skb); +		if (tid <= 7) +			rtlpriv->link_info.tidtx_inperiod[tid]++; + +		info = IEEE80211_SKB_CB(skb); +		ieee80211_tx_info_clear_status(info); + +		info->flags |= IEEE80211_TX_STAT_ACK; +		/*info->status.rates[0].count = 1; */ + +		ieee80211_tx_status_irqsafe(hw, skb); + +		if ((ring->entries - skb_queue_len(&ring->queue)) == 2) { +			RT_TRACE(COMP_ERR, DBG_LOUD, +				 ("more desc left, wake skb_queue@%d,ring->idx = %d, skb_queue_len = 0x%d\n", +					 prio, ring->idx, +					 skb_queue_len(&ring->queue))); + +			ieee80211_wake_queue(hw, skb_get_queue_mapping +					     (skb)); +		} +tx_status_ok: +		skb = NULL; +	} + +	if (((rtlpriv->link_info.num_rx_inperiod + +		rtlpriv->link_info.num_tx_inperiod) > 8) || +		(rtlpriv->link_info.num_rx_inperiod > 2)) { +		rtl92e_lps_leave(hw); +	} +} + +static int _rtl_pci_init_one_rxdesc(struct ieee80211_hw *hw, +				    u8 *entry, int rxring_idx, int desc_idx) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); +	struct sk_buff *skb; +	u32 bufferaddress; +	u8 tmp_one = 1; + +	skb = dev_alloc_skb(rtlpci->rxbuffersize); +	if (!skb) +		return 0; +	rtlpci->rx_ring[rxring_idx].rx_buf[desc_idx] = skb; + +	/* just set skb->cb to mapping addr +	 * for pci_unmap_single use +	 */ +	*((dma_addr_t *)skb->cb) = pci_map_single(rtlpci->pdev, +				skb_tail_pointer(skb), rtlpci->rxbuffersize, +				PCI_DMA_FROMDEVICE); +	bufferaddress = *((dma_addr_t *)skb->cb); +	if (pci_dma_mapping_error(rtlpci->pdev, bufferaddress)) +		return 0; +	if (rtlpriv->use_new_trx_flow) { +		rtlpriv->cfg->ops->set_desc(hw, (u8 *)entry, false, +					    HW_DESC_RX_PREPARE, +					    (u8 *)&bufferaddress); +	} else { +		rtlpriv->cfg->ops->set_desc(hw, (u8 *)entry, false, +					    HW_DESC_RXBUFF_ADDR, +					    (u8 *)&bufferaddress); +		rtlpriv->cfg->ops->set_desc(hw, (u8 *)entry, false, +					    HW_DESC_RXPKT_LEN, +					    (u8 *)&rtlpci->rxbuffersize); +		rtlpriv->cfg->ops->set_desc(hw, (u8 *)entry, false, +					    HW_DESC_RXOWN, +					    (u8 *)&tmp_one); +	} +	return 1; +} + +/* inorder to receive 8K AMSDU we have set skb to + * 9100bytes in init rx ring, but if this packet is + * not a AMSDU, this so big packet will be sent to + * TCP/IP directly, this cause big packet ping fail + * like: "ping -s 65507", so here we will realloc skb + * based on the true size of packet, I think mac80211 + * do it will be better, but now mac80211 haven't */ + +/* but some platform will fail when alloc skb sometimes. + * in this condition, we will send the old skb to + * mac80211 directly, this will not cause any other + * issues, but only be losted by TCP/IP */ +static void _rtl_pci_rx_to_mac80211(struct ieee80211_hw *hw, +				    struct sk_buff *skb, +				    struct ieee80211_rx_status rx_status) +{ +	if (unlikely(!rtl92e_action_proc(hw, skb, false))) { +		dev_kfree_skb_any(skb); +	} else { +		struct sk_buff *uskb = NULL; +		u8 *pdata; + +		uskb = dev_alloc_skb(skb->len + 128); +		if (likely(uskb)) { +			memcpy(IEEE80211_SKB_RXCB(uskb), &rx_status, +			       sizeof(rx_status)); +			pdata = (u8 *)skb_put(uskb, skb->len); +			memcpy(pdata, skb->data, skb->len); +			dev_kfree_skb_any(skb); + +			ieee80211_rx_irqsafe(hw, uskb); +		} else { +			ieee80211_rx_irqsafe(hw, skb); +		} +	} +} + +/*hsisr interrupt handler*/ +static void _rtl_pci_hs_interrupt(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + +	rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[MAC_HSISR], +		       rtl_read_byte(rtlpriv, rtlpriv->cfg->maps[MAC_HSISR]) | +		       rtlpci->sys_irq_mask); +} + +static void _rtl_receive_one(struct ieee80211_hw *hw, struct sk_buff *skb, +			     struct ieee80211_rx_status rx_status) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct ieee80211_hdr *hdr = rtl_get_hdr(skb); +	__le16 fc = rtl_get_fc(skb); +	bool unicast = false; + +	memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status)); + +	if (is_broadcast_ether_addr(hdr->addr1)) { +		;/*TODO*/ +	} else if (is_multicast_ether_addr(hdr->addr1)) { +		;/*TODO*/ +	} else { +		unicast = true; +		rtlpriv->stats.rxbytesunicast += skb->len; +	} + +	rtl92e_is_special_data(hw, skb, false); +	if (ieee80211_is_data(fc)) { +		rtlpriv->cfg->ops->led_control(hw, LED_CTL_RX); + +		if (unicast) +			rtlpriv->link_info.num_rx_inperiod++; +	} + +	/* static bcn for roaming */ +	rtl92e_beacon_statistic(hw, skb); +	rtl92e_p2p_info(hw, (void *)skb->data, skb->len); + +	/* for sw lps */ +	rtl92e_swlps_beacon(hw, (void *)skb->data, skb->len); +	rtl92e_recognize_peer(hw, (void *)skb->data, skb->len); +	if ((rtlpriv->mac80211.opmode == NL80211_IFTYPE_AP) && +	    (rtlpriv->rtlhal.current_bandtype == BAND_ON_2_4G) && +	    (ieee80211_is_beacon(fc) || +	     ieee80211_is_probe_resp(fc))) +		dev_kfree_skb_any(skb); +	else +		_rtl_pci_rx_to_mac80211(hw, skb, rx_status); +} + +static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); +	struct ieee80211_rx_status rx_status = { 0 }; +	int rxring_idx = RTL_PCI_RX_MPDU_QUEUE; +	unsigned int count = rtlpci->rxringcount; +	u8 hw_queue = 0; +	unsigned int rx_remained_cnt; +	u8 own; +	u8 tmp_one; +	static int err_count; +	struct rtl_stats stats = { +		.signal = 0, +		.rate = 0, +	}; + +	/*RX NORMAL PKT */ +	while (count--) { +		struct ieee80211_hdr *hdr; +		__le16 fc; +		u16 len; +		/*rx buffer descriptor */ +		struct rtl_rx_buffer_desc *buffer_desc = NULL; +		/*if use new trx flow, it means wifi info */ +		struct rtl_rx_desc *pdesc = NULL; +		/*rx pkt */ +		struct sk_buff *skb = rtlpci->rx_ring[rxring_idx].rx_buf[ +					rtlpci->rx_ring[rxring_idx].idx]; + +		if (rtlpriv->use_new_trx_flow) { +			rx_remained_cnt = +				rtlpriv->cfg->ops->rx_desc_buff_remained_cnt(hw, +								      hw_queue); +			if (rx_remained_cnt < 1) +				return; + +		} else {	/* rx descriptor */ +			pdesc = &rtlpci->rx_ring[rxring_idx].desc[ +				rtlpci->rx_ring[rxring_idx].idx]; + +			own = (u8) rtlpriv->cfg->ops->get_desc((u8 *)pdesc, +							       false, +							       HW_DESC_OWN); +			if (own) /* wait data to be filled by hardware */ +				return; +		} + +		/* If we get here, the data is filled already +		 * Attention !!! +		 * We can NOT access 'skb' before 'pci_unmap_single' +		 */ +		pci_unmap_single(rtlpci->pdev, *((dma_addr_t *)skb->cb), +				 rtlpci->rxbuffersize, PCI_DMA_FROMDEVICE); + +		if (rtlpriv->use_new_trx_flow) { +			buffer_desc = &rtlpci->rx_ring[rxring_idx].buffer_desc[ +				rtlpci->rx_ring[rxring_idx].idx]; +			/*means rx wifi info*/ +			pdesc = (struct rtl_rx_desc *)skb->data; +		} +		memset(&rx_status , 0 , sizeof(rx_status)); +		rtlpriv->cfg->ops->query_rx_desc(hw, &stats, +						 &rx_status, (u8 *)pdesc, skb); + +		if (rtlpriv->use_new_trx_flow) +			rtlpriv->cfg->ops->rx_check_dma_ok(hw, +							   (u8 *)buffer_desc, +							   hw_queue); +		len = rtlpriv->cfg->ops->get_desc((u8 *)pdesc, false, +						  HW_DESC_RXPKT_LEN); + +		if (skb->end - skb->tail > len) { +			skb_put(skb, len); +			if (rtlpriv->use_new_trx_flow) +				skb_reserve(skb, stats.rx_drvinfo_size + +						 stats.rx_bufshift + 24); +			else +				skb_reserve(skb, stats.rx_drvinfo_size + +						 stats.rx_bufshift); + +		} else { +			if (err_count++ < 10) { +				pr_info("skb->end (%d) - skb->tail (%d) > len (%d)\n", +					skb->end, skb->tail, len); +				RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_EMERG, +					      "RX desc\n", +					      (u8 *)pdesc, 32); +			} +			break; +		} + +		/* handle command packet here */ +		if (rtlpriv->cfg->ops->rx_command_packet(hw, stats, skb)) { +				dev_kfree_skb_any(skb); +				goto end; +		} + +		/* NOTICE This can not be use for mac80211, +		 *this is done in mac80211 code, +		 *if you done here sec DHCP will fail +		 *skb_trim(skb, skb->len - 4); +		 */ + +		hdr = rtl_get_hdr(skb); +		fc = rtl_get_fc(skb); + +		if (!stats.b_crc && !stats.b_hwerror) +			_rtl_receive_one(hw, skb, rx_status); +		else +			dev_kfree_skb_any(skb); +		if (rtlpriv->use_new_trx_flow) { +			rtlpci->rx_ring[hw_queue].next_rx_rp += 1; +			rtlpci->rx_ring[hw_queue].next_rx_rp %= +							RTL_PCI_MAX_RX_COUNT; + + +			rx_remained_cnt--; +			rtl_write_word(rtlpriv, 0x3B4, +				       rtlpci->rx_ring[hw_queue].next_rx_rp); +		} +		if (((rtlpriv->link_info.num_rx_inperiod + +		      rtlpriv->link_info.num_tx_inperiod) > 8) || +		    (rtlpriv->link_info.num_rx_inperiod > 2)) { +			rtl92e_lps_leave(hw); +		} +end: +		if (rtlpriv->use_new_trx_flow) { +			_rtl_pci_init_one_rxdesc(hw, (u8 *)buffer_desc, +						 rxring_idx, +					       rtlpci->rx_ring[rxring_idx].idx); +		} else { +			_rtl_pci_init_one_rxdesc(hw, (u8 *)pdesc, rxring_idx, +						 rtlpci->rx_ring[rxring_idx].idx); + +			if (rtlpci->rx_ring[rxring_idx].idx == +			    rtlpci->rxringcount - 1) +				rtlpriv->cfg->ops->set_desc(hw, (u8 *)pdesc, +							    false, +							    HW_DESC_RXERO, +							    (u8 *)&tmp_one); +		} +		rtlpci->rx_ring[rxring_idx].idx = +				(rtlpci->rx_ring[rxring_idx].idx + 1) % +				rtlpci->rxringcount; +	} +} + +static irqreturn_t _rtl_pci_interrupt(int irq, void *dev_id) +{ +	struct ieee80211_hw *hw = dev_id; +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); +	unsigned long flags; +	u32 inta = 0; +	u32 intb = 0; + +	if (rtlpci->irq_enabled == 0) +		return IRQ_HANDLED; + +	spin_lock_irqsave(&rtlpriv->locks.irq_th_lock , flags); +	rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[MAC_HIMR], 0x0); +	rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[MAC_HIMRE], 0x0); + +	/*read ISR: 4/8bytes */ +	rtlpriv->cfg->ops->interrupt_recognized(hw, &inta, &intb); + +	/*Shared IRQ or HW disappared */ +	if (!inta || inta == 0xffff) +		goto done; +	/*<1> beacon related */ +	if (inta & rtlpriv->cfg->maps[RTL_IMR_TBDOK]) +		RT_TRACE(COMP_INTR, DBG_TRACE, ("beacon ok interrupt!\n")); + +	if (unlikely(inta & rtlpriv->cfg->maps[RTL_IMR_TBDER])) +		RT_TRACE(COMP_INTR, DBG_TRACE, ("beacon err interrupt!\n")); + +	if (inta & rtlpriv->cfg->maps[RTL_IMR_BDOK]) +		RT_TRACE(COMP_INTR, DBG_TRACE, ("beacon interrupt!\n")); + +	if (inta & rtlpriv->cfg->maps[RTL_IMR_BcnInt]) { +		RT_TRACE(COMP_INTR, DBG_TRACE, +			 ("prepare beacon for interrupt!\n")); +		tasklet_schedule(&rtlpriv->works.irq_prepare_bcn_tasklet); +	} + +	/*<2> tx related */ +	if (unlikely(intb & rtlpriv->cfg->maps[RTL_IMR_TXFOVW])) +		RT_TRACE(COMP_ERR, DBG_TRACE, ("IMR_TXFOVW!\n")); + +	if (inta & rtlpriv->cfg->maps[RTL_IMR_MGNTDOK]) { +		RT_TRACE(COMP_INTR, DBG_TRACE, ("Manage ok interrupt!\n")); +		_rtl_pci_tx_isr(hw, MGNT_QUEUE); +	} + +	if (inta & rtlpriv->cfg->maps[RTL_IMR_HIGHDOK]) { +		RT_TRACE(COMP_INTR, DBG_TRACE, ("HIGH_QUEUE ok interrupt!\n")); +		_rtl_pci_tx_isr(hw, HIGH_QUEUE); +	} + +	if (inta & rtlpriv->cfg->maps[RTL_IMR_BKDOK]) { +		rtlpriv->link_info.num_tx_inperiod++; + +		RT_TRACE(COMP_INTR, DBG_TRACE, ("BK Tx OK interrupt!\n")); +		_rtl_pci_tx_isr(hw, BK_QUEUE); +	} + +	if (inta & rtlpriv->cfg->maps[RTL_IMR_BEDOK]) { +		rtlpriv->link_info.num_tx_inperiod++; + +		RT_TRACE(COMP_INTR, DBG_TRACE, ("BE TX OK interrupt!\n")); +		_rtl_pci_tx_isr(hw, BE_QUEUE); +	} + +	if (inta & rtlpriv->cfg->maps[RTL_IMR_VIDOK]) { +		rtlpriv->link_info.num_tx_inperiod++; + +		RT_TRACE(COMP_INTR, DBG_TRACE, ("VI TX OK interrupt!\n")); +		_rtl_pci_tx_isr(hw, VI_QUEUE); +	} + +	if (inta & rtlpriv->cfg->maps[RTL_IMR_VODOK]) { +		rtlpriv->link_info.num_tx_inperiod++; + +		RT_TRACE(COMP_INTR, DBG_TRACE, ("Vo TX OK interrupt!\n")); +		_rtl_pci_tx_isr(hw, VO_QUEUE); +	} + +	if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192SE) { +		if (inta & rtlpriv->cfg->maps[RTL_IMR_COMDOK]) { +			rtlpriv->link_info.num_tx_inperiod++; + +			RT_TRACE(COMP_INTR, DBG_TRACE, +				 ("CMD TX OK interrupt!\n")); +			_rtl_pci_tx_isr(hw, TXCMD_QUEUE); +		} +	} + +	/*<3> rx related */ +	if (inta & rtlpriv->cfg->maps[RTL_IMR_ROK]) { +		RT_TRACE(COMP_INTR, DBG_TRACE, ("Rx ok interrupt!\n")); +		_rtl_pci_rx_interrupt(hw); +	} + +	if (unlikely(inta & rtlpriv->cfg->maps[RTL_IMR_RDU])) { +		RT_TRACE(COMP_ERR, DBG_WARNING, +			 ("rx descriptor unavailable!\n")); +		_rtl_pci_rx_interrupt(hw); +	} + +	if (unlikely(intb & rtlpriv->cfg->maps[RTL_IMR_RXFOVW])) { +		RT_TRACE(COMP_ERR, DBG_WARNING, ("rx overflow !\n")); +		_rtl_pci_rx_interrupt(hw); +	} + +	/*<4> fw related*/ +	if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723AE) { +		if (inta & rtlpriv->cfg->maps[RTL_IMR_C2HCMD]) { +			RT_TRACE(COMP_INTR, DBG_TRACE, +				 ("firmware interrupt!\n")); +			queue_delayed_work(rtlpriv->works.rtl_wq, +					   &rtlpriv->works.fwevt_wq, 0); +		} +	} + +	/*<5> hsisr related*/ +	/* Only 8188EE & 8723BE Supported. +	 * If Other ICs Come in, System will corrupt, +	 * because maps[RTL_IMR_HSISR_IND] & maps[MAC_HSISR] +	 * are not initialized*/ +	if (rtlhal->hw_type == HARDWARE_TYPE_RTL8188EE || +	    rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE) { +		if (unlikely(inta & rtlpriv->cfg->maps[RTL_IMR_HSISR_IND])) { +			RT_TRACE(COMP_INTR, DBG_TRACE, +				 ("hsisr interrupt!\n")); +			_rtl_pci_hs_interrupt(hw); +		} +	} + + +	if (rtlpriv->rtlhal.b_earlymode_enable) +		tasklet_schedule(&rtlpriv->works.irq_tasklet); + +done: +	rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[MAC_HIMR], +			rtlpci->irq_mask[0]); +	rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[MAC_HIMRE], +			rtlpci->irq_mask[1]); +	spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags); +	return IRQ_HANDLED; +} + +static void _rtl_pci_irq_tasklet(struct ieee80211_hw *hw) +{ +	_rtl_pci_tx_chk_waitq(hw); +} + +static void _rtl_pci_prepare_bcn_tasklet(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +	struct rtl8192_tx_ring *ring = NULL; +	struct ieee80211_hdr *hdr = NULL; +	struct ieee80211_tx_info *info = NULL; +	struct sk_buff *pskb = NULL; +	struct rtl_tx_desc *pdesc = NULL; +	struct rtl_tcb_desc tcb_desc; +	/*This is for new trx flow*/ +	struct rtl_tx_buffer_desc *pbuffer_desc = NULL; +	u8 temp_one = 1; + +	memset(&tcb_desc, 0, sizeof(struct rtl_tcb_desc)); +	ring = &rtlpci->tx_ring[BEACON_QUEUE]; +	pskb = __skb_dequeue(&ring->queue); +	if (pskb) +		kfree_skb(pskb); + +	/*NB: the beacon data buffer must be 32-bit aligned. */ +	pskb = ieee80211_beacon_get(hw, mac->vif); +	if (pskb == NULL) +		return; +	hdr = rtl_get_hdr(pskb); +	info = IEEE80211_SKB_CB(pskb); +	pdesc = &ring->desc[0]; +	if (rtlpriv->use_new_trx_flow) +		pbuffer_desc = &ring->buffer_desc[0]; + +	rtlpriv->cfg->ops->fill_tx_desc(hw, hdr, (u8 *)pdesc, +					(u8 *)pbuffer_desc, info, NULL, pskb, +					BEACON_QUEUE, &tcb_desc); + +	__skb_queue_tail(&ring->queue, pskb); + +	rtlpriv->cfg->ops->set_desc(hw, (u8 *)pdesc, true, HW_DESC_OWN, +				    (u8 *)&temp_one); + +	return; +} + +static void _rtl_pci_init_trx_var(struct ieee80211_hw *hw) +{ +	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_hal *rtlhal = rtl_hal(rtlpriv); +	u8 i; +	u16 desc_num; + +	if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192EE) +		desc_num = TX_DESC_NUM_92E; +	else +		desc_num = RT_TXDESC_NUM; + +	for (i = 0; i < RTL_PCI_MAX_TX_QUEUE_COUNT; i++) +		rtlpci->txringcount[i] = desc_num; +	/* +	 *we just alloc 2 desc for beacon queue, +	 *because we just need first desc in hw beacon. +	 */ +	rtlpci->txringcount[BEACON_QUEUE] = 2; + +	/* +	 *BE queue need more descriptor for performance +	 *consideration or, No more tx desc will happen, +	 *and may cause mac80211 mem leakage. +	 */ +	if (!rtl_priv(hw)->use_new_trx_flow) +		rtlpci->txringcount[BE_QUEUE] = RT_TXDESC_NUM_BE_QUEUE; + +	rtlpci->rxbuffersize = 9100;	/*2048/1024; */ +	rtlpci->rxringcount = RTL_PCI_MAX_RX_COUNT;	/*64; */ +} + +static void _rtl_pci_init_struct(struct ieee80211_hw *hw, +				 struct pci_dev *pdev) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + +	rtlpriv->rtlhal.up_first_time = true; +	rtlpriv->rtlhal.being_init_adapter = false; + +	rtlhal->hw = hw; +	rtlpci->pdev = pdev; + +	/*Tx/Rx related var */ +	_rtl_pci_init_trx_var(hw); + +	/*IBSS*/ mac->beacon_interval = 100; + +	/*AMPDU*/ +	mac->min_space_cfg = 0; +	mac->max_mss_density = 0; +	/*set sane AMPDU defaults */ +	mac->current_ampdu_density = 7; +	mac->current_ampdu_factor = 3; + +	/*QOS*/ +	rtlpci->acm_method = eAcmWay2_SW; + +	/*task */ +	tasklet_init(&rtlpriv->works.irq_tasklet, +		     (void (*)(unsigned long))_rtl_pci_irq_tasklet, +		     (unsigned long)hw); +	tasklet_init(&rtlpriv->works.irq_prepare_bcn_tasklet, +		     (void (*)(unsigned long))_rtl_pci_prepare_bcn_tasklet, +		     (unsigned long)hw); +} + +static int _rtl_pci_init_tx_ring(struct ieee80211_hw *hw, +				 unsigned int prio, unsigned int entries) +{ +	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_tx_buffer_desc *buffer_desc; +	struct rtl_tx_desc *desc; +	dma_addr_t buffer_desc_dma, desc_dma; +	u32 nextdescaddress; +	int i; + +	/* alloc tx buffer desc for new trx flow*/ +	if (rtlpriv->use_new_trx_flow) { +		buffer_desc = pci_alloc_consistent(rtlpci->pdev, +					sizeof(*buffer_desc) * entries, +					&buffer_desc_dma); + +		if (!buffer_desc || (unsigned long)buffer_desc & 0xFF) { +			RT_TRACE(COMP_ERR, DBG_EMERG, +				 ("Cannot allocate TX ring (prio = %d)\n", +				 prio)); +			return -ENOMEM; +		} + +		memset(buffer_desc, 0, sizeof(*buffer_desc) * entries); +		rtlpci->tx_ring[prio].buffer_desc = buffer_desc; +		rtlpci->tx_ring[prio].buffer_desc_dma = buffer_desc_dma; + +		rtlpci->tx_ring[prio].cur_tx_rp = 0; +		rtlpci->tx_ring[prio].cur_tx_wp = 0; +		rtlpci->tx_ring[prio].avl_desc = entries; +	} + +	/* alloc dma for this ring */ +	desc = pci_alloc_consistent(rtlpci->pdev, +				    sizeof(*desc) * entries, &desc_dma); + +	if (!desc || (unsigned long)desc & 0xFF) { +		RT_TRACE(COMP_ERR, DBG_EMERG, +			 ("Cannot allocate TX ring (prio = %d)\n", prio)); +		return -ENOMEM; +	} + +	memset(desc, 0, sizeof(*desc) * entries); +	rtlpci->tx_ring[prio].desc = desc; +	rtlpci->tx_ring[prio].dma = desc_dma; + +	rtlpci->tx_ring[prio].idx = 0; +	rtlpci->tx_ring[prio].entries = entries; +	skb_queue_head_init(&rtlpci->tx_ring[prio].queue); +	RT_TRACE(COMP_INIT, DBG_LOUD, +		 ("queue:%d, ring_addr:%p\n", prio, desc)); + +	/* init every desc in this ring */ +	if (!rtlpriv->use_new_trx_flow) { +		for (i = 0; i < entries; i++) { +			nextdescaddress = (u32) desc_dma + +						      ((i +	1) % entries) * +						      sizeof(*desc); + +			rtlpriv->cfg->ops->set_desc(hw, (u8 *)&(desc[i]), +						    true, +						    HW_DESC_TX_NEXTDESC_ADDR, +						    (u8 *)&nextdescaddress); +		} +	} +	return 0; +} + +static int _rtl_pci_init_rx_ring(struct ieee80211_hw *hw, int rxring_idx) +{ +	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	int i; + +	if (rtlpriv->use_new_trx_flow) { +		struct rtl_rx_buffer_desc *entry = NULL; +		/* alloc dma for this ring */ +		rtlpci->rx_ring[rxring_idx].buffer_desc = +		    pci_alloc_consistent(rtlpci->pdev, +					 sizeof(*rtlpci->rx_ring[rxring_idx]. +						buffer_desc) * +						rtlpci->rxringcount, +					 &rtlpci->rx_ring[rxring_idx].dma); +		if (!rtlpci->rx_ring[rxring_idx].buffer_desc || +		    (unsigned long)rtlpci->rx_ring[rxring_idx].buffer_desc & 0xFF) { +			RT_TRACE(COMP_ERR, DBG_EMERG, +				 ("Cannot allocate RX ring\n")); +			return -ENOMEM; +		} + +		memset(rtlpci->rx_ring[rxring_idx].buffer_desc, 0, +		       sizeof(*rtlpci->rx_ring[rxring_idx].buffer_desc) * +		       rtlpci->rxringcount); + +		/* init every desc in this ring */ +		rtlpci->rx_ring[rxring_idx].idx = 0; + +		for (i = 0; i < rtlpci->rxringcount; i++) { +			entry = &rtlpci->rx_ring[rxring_idx].buffer_desc[i]; +			if (!_rtl_pci_init_one_rxdesc(hw, (u8 *)entry, +						      rxring_idx, i)) +				return -ENOMEM; +		} +	} else { +		struct rtl_rx_desc *entry = NULL; +		u8 tmp_one = 1; +		/* alloc dma for this ring */ +		rtlpci->rx_ring[rxring_idx].desc = +		    pci_alloc_consistent(rtlpci->pdev, +					 sizeof(*rtlpci->rx_ring[rxring_idx]. +					desc) * rtlpci->rxringcount, +					 &rtlpci->rx_ring[rxring_idx].dma); +		if (!rtlpci->rx_ring[rxring_idx].desc || +		    (unsigned long)rtlpci->rx_ring[rxring_idx].desc & 0xFF) { +			RT_TRACE(COMP_ERR, DBG_EMERG, +				 ("Cannot allocate RX ring\n")); +			return -ENOMEM; +		} +		memset(rtlpci->rx_ring[rxring_idx].desc, 0, +		       sizeof(*rtlpci->rx_ring[rxring_idx].desc) * +		       rtlpci->rxringcount); + +		/* init every desc in this ring */ +		rtlpci->rx_ring[rxring_idx].idx = 0; +		for (i = 0; i < rtlpci->rxringcount; i++) { +			entry = &rtlpci->rx_ring[rxring_idx].desc[i]; +			if (!_rtl_pci_init_one_rxdesc(hw, (u8 *)entry, +						      rxring_idx, i)) +				return -ENOMEM; +		} +		rtlpriv->cfg->ops->set_desc(hw, (u8 *)entry, false, +					    HW_DESC_RXERO, (u8 *) &tmp_one); +	} +	return 0; +} + +static void _rtl_pci_free_tx_ring(struct ieee80211_hw *hw, +				  unsigned int prio) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); +	struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[prio]; + +	/* free every desc in this ring */ +	while (skb_queue_len(&ring->queue)) { +		struct sk_buff *skb = __skb_dequeue(&ring->queue); +		u8 *entry; + +		if (rtlpriv->use_new_trx_flow) +			entry = (u8 *)(&ring->buffer_desc[ring->idx]); +		else +			entry = (u8 *)(&ring->desc[ring->idx]); + +		pci_unmap_single(rtlpci->pdev, +				 rtlpriv->cfg->ops->get_desc((u8 *)entry, true, +				 HW_DESC_TXBUFF_ADDR), +				 skb->len, PCI_DMA_TODEVICE); +		kfree_skb(skb); +		ring->idx = (ring->idx + 1) % ring->entries; +	} + +	/* free dma of this ring */ +	pci_free_consistent(rtlpci->pdev, +			    sizeof(*ring->desc) * ring->entries, +			    ring->desc, ring->dma); +	ring->desc = NULL; +	if (rtlpriv->use_new_trx_flow) { +		pci_free_consistent(rtlpci->pdev, +				    sizeof(*ring->buffer_desc) * ring->entries, +				    ring->buffer_desc, ring->buffer_desc_dma); +		ring->buffer_desc = NULL; +	} +} + +static void _rtl_pci_free_rx_ring(struct ieee80211_hw *hw, int rxring_idx) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); +	int i; + +	/* free every desc in this ring */ +	for (i = 0; i < rtlpci->rxringcount; i++) { +		struct sk_buff *skb = rtlpci->rx_ring[rxring_idx].rx_buf[i]; + +		if (!skb) +			continue; + +		pci_unmap_single(rtlpci->pdev, *((dma_addr_t *)skb->cb), +				 rtlpci->rxbuffersize, PCI_DMA_FROMDEVICE); +		kfree_skb(skb); +	} + +	/* free dma of this ring */ +	if (rtlpriv->use_new_trx_flow) { +		pci_free_consistent(rtlpci->pdev, +				    sizeof(*rtlpci->rx_ring[rxring_idx]. +				    buffer_desc) * rtlpci->rxringcount, +				    rtlpci->rx_ring[rxring_idx].buffer_desc, +				    rtlpci->rx_ring[rxring_idx].dma); +		rtlpci->rx_ring[rxring_idx].buffer_desc = NULL; +	} else { +		pci_free_consistent(rtlpci->pdev, +				    sizeof(*rtlpci->rx_ring[rxring_idx].desc) * +				    rtlpci->rxringcount, +				    rtlpci->rx_ring[rxring_idx].desc, +				    rtlpci->rx_ring[rxring_idx].dma); +		rtlpci->rx_ring[rxring_idx].desc = NULL; +	} +} + +static int _rtl_pci_init_trx_ring(struct ieee80211_hw *hw) +{ +	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); +	int ret; +	int i, rxring_idx; + +	/* rxring_idx 0:RX_MPDU_QUEUE +	 * rxring_idx 1:RX_CMD_QUEUE */ +	for (rxring_idx = 0; rxring_idx < RTL_PCI_MAX_RX_QUEUE; rxring_idx++) { +		ret = _rtl_pci_init_rx_ring(hw, rxring_idx); +		if (ret) +			return ret; +	} + +	for (i = 0; i < RTL_PCI_MAX_TX_QUEUE_COUNT; i++) { +		ret = _rtl_pci_init_tx_ring(hw, i, +					    rtlpci->txringcount[i]); +		if (ret) +			goto err_free_rings; +	} + +	return 0; + +err_free_rings: +	for (rxring_idx = 0; rxring_idx < RTL_PCI_MAX_RX_QUEUE; rxring_idx++) +		_rtl_pci_free_rx_ring(hw, rxring_idx); + +	for (i = 0; i < RTL_PCI_MAX_TX_QUEUE_COUNT; i++) +		if (rtlpci->tx_ring[i].desc || +		    rtlpci->tx_ring[i].buffer_desc) +			_rtl_pci_free_tx_ring(hw, i); + +	return 1; +} + +static int _rtl_pci_deinit_trx_ring(struct ieee80211_hw *hw) +{ +	u32 i, rxring_idx; + +	/*free rx rings */ +	for (rxring_idx = 0; rxring_idx < RTL_PCI_MAX_RX_QUEUE; rxring_idx++) +		_rtl_pci_free_rx_ring(hw, rxring_idx); + +	/*free tx rings */ +	for (i = 0; i < RTL_PCI_MAX_TX_QUEUE_COUNT; i++) +		_rtl_pci_free_tx_ring(hw, i); + +	return 0; +} + +int rtl92e_pci_reset_trx_ring(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); +	int i, rxring_idx; +	unsigned long flags; +	u8 tmp_one = 1; +	/* rxring_idx 0:RX_MPDU_QUEUE */ +	/* rxring_idx 1:RX_CMD_QUEUE */ +	for (rxring_idx = 0; rxring_idx < RTL_PCI_MAX_RX_QUEUE; rxring_idx++) { +		/* force the rx_ring[RX_MPDU_QUEUE] +		 * RX_CMD_QUEUE].idx to the first one +		 * If using the new trx flow, do nothing +		 */ +		if (!rtlpriv->use_new_trx_flow && +		    rtlpci->rx_ring[rxring_idx].desc) { +			struct rtl_rx_desc *entry = NULL; + +			for (i = 0; i < rtlpci->rxringcount; i++) { +				entry = &rtlpci->rx_ring[rxring_idx].desc[i]; +				rtlpriv->cfg->ops->set_desc(hw, (u8 *)entry, +							    false, +							    HW_DESC_RXOWN, +							    &tmp_one); +			} +		} +		rtlpci->rx_ring[rxring_idx].idx = 0; +	} + +	/* after reset, release previous pending packet, +	 * and force the  tx idx to the first one +	 */ +	spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags); +	for (i = 0; i < RTL_PCI_MAX_TX_QUEUE_COUNT; i++) { +		if (rtlpci->tx_ring[i].desc || +		    rtlpci->tx_ring[i].buffer_desc) { +			struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[i]; + +			while (skb_queue_len(&ring->queue)) { +				struct sk_buff *skb = +					__skb_dequeue(&ring->queue); +				u8 *entry; + +				if (rtlpriv->use_new_trx_flow) +					entry = (u8 *)(&ring->buffer_desc +								[ring->idx]); +				else +					entry = (u8 *)(&ring->desc[ring->idx]); + +				pci_unmap_single(rtlpci->pdev, +						 rtlpriv->cfg->ops->get_desc( +						 (u8 *)entry, true, +						 HW_DESC_TXBUFF_ADDR), +					skb->len, PCI_DMA_TODEVICE); +				kfree_skb(skb); +				ring->idx = (ring->idx + 1) % ring->entries; +			} +			ring->idx = 0; +		} +	} + +	spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags); + +	return 0; +} + +static bool rtl_pci_tx_chk_waitq_insert(struct ieee80211_hw *hw, +					struct ieee80211_sta *sta, +					struct sk_buff *skb) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_sta_info *sta_entry = NULL; +	u8 tid = rtl_get_tid(skb); +	__le16 fc = rtl_get_fc(skb); + +	if (!sta) +		return false; +	sta_entry = (struct rtl_sta_info *)sta->drv_priv; + +	if (!rtlpriv->rtlhal.b_earlymode_enable) +		return false; +	if (ieee80211_is_nullfunc(fc)) +		return false; +	if (ieee80211_is_qos_nullfunc(fc)) +		return false; +	if (ieee80211_is_pspoll(fc)) +		return false; + +	if (sta_entry->tids[tid].agg.agg_state != RTL_AGG_OPERATIONAL) +		return false; +	if (_rtl_mac_to_hwqueue(hw, skb) > VO_QUEUE) +		return false; +	if (tid > 7) +		return false; +	/* maybe every tid should be checked */ +	if (!rtlpriv->link_info.higher_busytxtraffic[tid]) +		return false; + +	spin_lock_bh(&rtlpriv->locks.waitq_lock); +	skb_queue_tail(&rtlpriv->mac80211.skb_waitq[tid], skb); +	spin_unlock_bh(&rtlpriv->locks.waitq_lock); + +	return true; +} + +static int rtl_pci_tx(struct ieee80211_hw *hw, +		      struct ieee80211_sta *sta, +		      struct sk_buff *skb, +		      struct rtl_tcb_desc *ptcb_desc) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_sta_info *sta_entry = NULL; +	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); +	struct rtl8192_tx_ring *ring; +	struct rtl_tx_desc *pdesc; +	struct rtl_tx_buffer_desc *ptx_bd_desc = NULL; +	u16 idx; +	u8 own; +	u8 temp_one = 1; +	u8 hw_queue = _rtl_mac_to_hwqueue(hw, skb); +	unsigned long flags; +	struct ieee80211_hdr *hdr = rtl_get_hdr(skb); +	__le16 fc = rtl_get_fc(skb); +	u8 *pda_addr = hdr->addr1; +	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); +	/*ssn */ +	u8 tid = 0; +	u16 seq_number = 0; + +	if (ieee80211_is_mgmt(fc)) +		rtl92e_tx_mgmt_proc(hw, skb); + +	if (rtlpriv->psc.sw_ps_enabled) { +		if (ieee80211_is_data(fc) && !ieee80211_is_nullfunc(fc) && +		    !ieee80211_has_pm(fc)) +			hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM); +	} + +	rtl92e_action_proc(hw, skb, true); + +	if (is_multicast_ether_addr(pda_addr)) +		rtlpriv->stats.txbytesmulticast += skb->len; +	else if (is_broadcast_ether_addr(pda_addr)) +		rtlpriv->stats.txbytesbroadcast += skb->len; +	else +		rtlpriv->stats.txbytesunicast += skb->len; + +	spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags); +	ring = &rtlpci->tx_ring[hw_queue]; +	if (hw_queue != BEACON_QUEUE) { +		if (rtlpriv->use_new_trx_flow) +			idx = ring->cur_tx_wp; +		else +			idx = (ring->idx + skb_queue_len(&ring->queue)) % +			      ring->entries; +	} else { +		idx = 0; +	} + +	pdesc = &ring->desc[idx]; + +	if (rtlpriv->use_new_trx_flow) { +		ptx_bd_desc = &ring->buffer_desc[idx]; +	} else { +		own = (u8) rtlpriv->cfg->ops->get_desc((u8 *)pdesc, +				true, HW_DESC_OWN); + +		if ((own == 1) && (hw_queue != BEACON_QUEUE)) { +			RT_TRACE(COMP_ERR, DBG_WARNING, +				 ("No more TX desc@%d, ring->idx = %d, idx = %d, skb_queue_len = 0x%d\n", +				  hw_queue, ring->idx, idx, +				  skb_queue_len(&ring->queue))); + +			spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, +					       flags); +			return skb->len; +		} +	} + +	if (ieee80211_is_data_qos(fc)) { +		tid = rtl_get_tid(skb); +		if (sta) { +			sta_entry = (struct rtl_sta_info *)sta->drv_priv; +			seq_number = (le16_to_cpu(hdr->seq_ctrl) & +				      IEEE80211_SCTL_SEQ) >> 4; +			seq_number += 1; + +			if (!ieee80211_has_morefrags(hdr->frame_control)) +				sta_entry->tids[tid].seq_number = seq_number; +		} +	} + +	if (ieee80211_is_data(fc)) +		rtlpriv->cfg->ops->led_control(hw, LED_CTL_TX); + +	rtlpriv->cfg->ops->fill_tx_desc(hw, hdr, (u8 *)pdesc, +					(u8 *)ptx_bd_desc, info, sta, skb, +					hw_queue, ptcb_desc); + +	__skb_queue_tail(&ring->queue, skb); +	if (rtlpriv->use_new_trx_flow) { +		rtlpriv->cfg->ops->set_desc(hw, (u8 *)pdesc, true, +					    HW_DESC_OWN, (u8 *)&hw_queue); +	} else { +		rtlpriv->cfg->ops->set_desc(hw, (u8 *)pdesc, true, +					    HW_DESC_OWN, (u8 *)&temp_one); +	} + +	if ((ring->entries - skb_queue_len(&ring->queue)) < 2 && +	    hw_queue != BEACON_QUEUE) { +		RT_TRACE(COMP_ERR, DBG_LOUD, +			 ("less desc left, stop skb_queue@%d, ring->idx = %d, idx = %d, skb_queue_len = 0x%d\n", +			  hw_queue, ring->idx, idx, +			  skb_queue_len(&ring->queue))); + +		ieee80211_stop_queue(hw, skb_get_queue_mapping(skb)); +	} + +	spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags); + +	if (rtlpriv->cfg->ops->tx_polling) +		rtlpriv->cfg->ops->tx_polling(hw, hw_queue); + +	return 0; +} +static void rtl_pci_flush(struct ieee80211_hw *hw, u32 queues, bool drop) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); +	u16 i = 0; +	int queue_id; +	struct rtl8192_tx_ring *ring; + +	if (mac->skip_scan) +		return; + +	for (queue_id = RTL_PCI_MAX_TX_QUEUE_COUNT - 1; queue_id >= 0;) { +		u32 queue_len; +		if (((queues >> queue_id) & 0x1) == 0) { +			queue_id--; +			continue; +		} +		ring = &pcipriv->dev.tx_ring[queue_id]; +		queue_len = skb_queue_len(&ring->queue); +		if (queue_len == 0 || queue_id == BEACON_QUEUE || +		    queue_id == TXCMD_QUEUE) { +			queue_id--; +			continue; +		} else { +			msleep(5); +			i++; +		} + +		/* we just wait 1s for all queues */ +		if (rtlpriv->psc.rfpwr_state == ERFOFF || +		    is_hal_stop(rtlhal) || i >= 200) +			return; +	} +} + +static void rtl_pci_deinit(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + +	_rtl_pci_deinit_trx_ring(hw); + +	synchronize_irq(rtlpci->pdev->irq); +	tasklet_kill(&rtlpriv->works.irq_tasklet); + +	flush_workqueue(rtlpriv->works.rtl_wq); +	destroy_workqueue(rtlpriv->works.rtl_wq); +} + +static int rtl_pci_init(struct ieee80211_hw *hw, struct pci_dev *pdev) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	int err; + +	_rtl_pci_init_struct(hw, pdev); + +	err = _rtl_pci_init_trx_ring(hw); +	if (err) { +		RT_TRACE(COMP_ERR, DBG_EMERG, +			 ("tx ring initialization failed")); +		return err; +	} + +	return 1; +} + +static int rtl_pci_start(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); +	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); +	int err = 0; + +	RT_TRACE(COMP_INIT, DBG_DMESG, (" rtl_pci_start\n")); +	rtl92e_pci_reset_trx_ring(hw); + +	rtlpriv->rtlhal.driver_is_goingto_unload = false; +	if (rtlpriv->cfg->ops->get_btc_status()) { +		rtlpriv->btcoexist.btc_ops->btc_init_variables(rtlpriv); +		rtlpriv->btcoexist.btc_ops->btc_init_hal_vars(rtlpriv); +	} + +	err = rtlpriv->cfg->ops->hw_init(hw); +	if (err) { +		RT_TRACE(COMP_INIT, DBG_DMESG, +			 ("Failed to config hardware err %x!\n" , err)); +		return err; +	} + +	rtlpriv->cfg->ops->enable_interrupt(hw); +	RT_TRACE(COMP_INIT, DBG_LOUD, ("enable_interrupt OK\n")); + +	rtl92e_init_rx_config(hw); + +	/*should after adapter start and interrupt enable. */ +	set_hal_start(rtlhal); + +	RT_CLEAR_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC); + +	rtlpriv->rtlhal.up_first_time = false; + +	RT_TRACE(COMP_INIT, DBG_DMESG, ("rtl_pci_start OK\n")); +	return 0; +} + +static void rtl_pci_stop(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); +	u8 RFInProgressTimeOut = 0; + +	if (rtlpriv->cfg->ops->get_btc_status()) +		rtlpriv->btcoexist.btc_ops->btc_halt_notify(); + +	/* +	 *should before disable interrrupt&adapter +	 *and will do it immediately. +	 */ +	set_hal_stop(rtlhal); + +	rtlpriv->cfg->ops->disable_interrupt(hw); + +	spin_lock(&rtlpriv->locks.rf_ps_lock); +	while (ppsc->rfchange_inprogress) { +		spin_unlock(&rtlpriv->locks.rf_ps_lock); +		if (RFInProgressTimeOut > 100) { +			spin_lock(&rtlpriv->locks.rf_ps_lock); +			break; +		} +		mdelay(1); +		RFInProgressTimeOut++; +		spin_lock(&rtlpriv->locks.rf_ps_lock); +	} +	ppsc->rfchange_inprogress = true; +	spin_unlock(&rtlpriv->locks.rf_ps_lock); + +	rtlpriv->rtlhal.driver_is_goingto_unload = true; +	rtlpriv->cfg->ops->hw_disable(hw); +	rtlpriv->cfg->ops->led_control(hw, LED_CTL_POWER_OFF); + +	spin_lock(&rtlpriv->locks.rf_ps_lock); +	ppsc->rfchange_inprogress = false; +	spin_unlock(&rtlpriv->locks.rf_ps_lock); + +	rtl_pci_enable_aspm(hw); +} + +static bool _rtl_pci_find_adapter(struct pci_dev *pdev, +				  struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); +	struct pci_dev *bridge_pdev = pdev->bus->self; +	u16 venderid; +	u16 deviceid; +	u8 revisionid; +	u16 irqline; +	u8 tmp; + +	venderid = pdev->vendor; +	deviceid = pdev->device; +	pci_read_config_byte(pdev, 0x8, &revisionid); +	pci_read_config_word(pdev, 0x3C, &irqline); + +	if (deviceid == RTL_PCI_8192_DID || +	    deviceid == RTL_PCI_0044_DID || +	    deviceid == RTL_PCI_0047_DID || +	    deviceid == RTL_PCI_8192SE_DID || +	    deviceid == RTL_PCI_8174_DID || +	    deviceid == RTL_PCI_8173_DID || +	    deviceid == RTL_PCI_8172_DID || +	    deviceid == RTL_PCI_8171_DID) { +		switch (revisionid) { +		case RTL_PCI_REVISION_ID_8192PCIE: +			RT_TRACE(COMP_INIT, DBG_DMESG, +				 ("8192E is found but not supported now-vid/did=%x/%x\n", +				  venderid, deviceid)); +			rtlhal->hw_type = HARDWARE_TYPE_RTL8192E; +			return false; +			break; +		case RTL_PCI_REVISION_ID_8192SE: +			RT_TRACE(COMP_INIT, DBG_DMESG, +				 ("8192SE is found - vid/did=%x/%x\n", +				  venderid, deviceid)); +			rtlhal->hw_type = HARDWARE_TYPE_RTL8192SE; +			break; +		default: +			RT_TRACE(COMP_ERR, DBG_WARNING, +				 ("Err: Unknown device - vid/did=%x/%x\n", +				  venderid, deviceid)); +			rtlhal->hw_type = HARDWARE_TYPE_RTL8192SE; +			break; +		} +	} else if (deviceid == RTL_PCI_8723AE_DID) { +		rtlhal->hw_type = HARDWARE_TYPE_RTL8723AE; +		RT_TRACE(COMP_INIT, DBG_DMESG, +			 ("8723AE PCI-E is found - vid/did=%x/%x\n", +			  venderid, deviceid)); +	} else if (deviceid == RTL_PCI_8192CET_DID || +		   deviceid == RTL_PCI_8192CE_DID || +		   deviceid == RTL_PCI_8191CE_DID || +		   deviceid == RTL_PCI_8188CE_DID) { +		rtlhal->hw_type = HARDWARE_TYPE_RTL8192CE; +		RT_TRACE(COMP_INIT, DBG_DMESG, +			 ("8192C PCI-E is found - vid/did=%x/%x\n", +			  venderid, deviceid)); +	} else if (deviceid == RTL_PCI_8192DE_DID || +		   deviceid == RTL_PCI_8192DE_DID2) { +		rtlhal->hw_type = HARDWARE_TYPE_RTL8192DE; +		RT_TRACE(COMP_INIT, DBG_DMESG, +			 ("8192D PCI-E is found - vid/did=%x/%x\n", +			  venderid, deviceid)); +	} else if (deviceid == RTL_PCI_8188EE_DID) { +			rtlhal->hw_type = HARDWARE_TYPE_RTL8188EE; +			RT_TRACE(COMP_INIT , DBG_LOUD, +				 ("Find adapter, Hardware type is 8188EE\n")); +	} else if (deviceid == RTL_PCI_8723BE_DID) { +			rtlhal->hw_type = HARDWARE_TYPE_RTL8723BE; +			RT_TRACE(COMP_INIT , DBG_LOUD, +				 ("Find adapter, Hardware type is 8723BE\n")); +	} else if (deviceid == RTL_PCI_8192EE_DID) { +			rtlhal->hw_type = HARDWARE_TYPE_RTL8192EE; +			RT_TRACE(COMP_INIT , DBG_LOUD, +				 ("Find adapter, Hardware type is 8192EE\n")); +	} else if (deviceid == RTL_PCI_8821AE_DID) { +			rtlhal->hw_type = HARDWARE_TYPE_RTL8821AE; +			RT_TRACE(COMP_INIT , DBG_LOUD, +				 ("Find adapter, Hardware type is 8821AE\n")); +	} else if (deviceid == RTL_PCI_8812AE_DID) { +			rtlhal->hw_type = HARDWARE_TYPE_RTL8812AE; +			RT_TRACE(COMP_INIT , DBG_LOUD, +				 ("Find adapter, Hardware type is 8812AE\n")); +	} else { +		RT_TRACE(COMP_ERR, DBG_WARNING, +			 ("Err: Unknown device - vid/did=%x/%x\n", +			  venderid, deviceid)); + +		rtlhal->hw_type = RTL_DEFAULT_HARDWARE_TYPE; +	} + +	if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192DE) { +		if (revisionid == 0 || revisionid == 1) { +			if (revisionid == 0) { +				RT_TRACE(COMP_INIT, DBG_LOUD, +					 ("Find 92DE MAC0.\n")); +				rtlhal->interfaceindex = 0; +			} else if (revisionid == 1) { +				RT_TRACE(COMP_INIT, DBG_LOUD, +					 ("Find 92DE MAC1.\n")); +				rtlhal->interfaceindex = 1; +			} +		} else { +			RT_TRACE(COMP_INIT, DBG_LOUD, +				 ("Unknown device - VendorID/DeviceID=%x/%x, Revision=%x\n", +				  venderid, deviceid, revisionid)); +			rtlhal->interfaceindex = 0; +		} +	} + +	/* 92ee use new trx flow */ +	if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192EE) +		rtlpriv->use_new_trx_flow = true; +	else +		rtlpriv->use_new_trx_flow = false; + +	/*find bus info */ +	pcipriv->ndis_adapter.busnumber = pdev->bus->number; +	pcipriv->ndis_adapter.devnumber = PCI_SLOT(pdev->devfn); +	pcipriv->ndis_adapter.funcnumber = PCI_FUNC(pdev->devfn); + +	/*find bridge info */ +	pcipriv->ndis_adapter.pcibridge_vendor = PCI_BRIDGE_VENDOR_UNKNOWN; +	/* some ARM have no bridge_pdev and will crash here +	 * so we should check if bridge_pdev is NULL */ +	if (bridge_pdev) { +		pcipriv->ndis_adapter.pcibridge_vendorid = bridge_pdev->vendor; +		for (tmp = 0; tmp < PCI_BRIDGE_VENDOR_MAX; tmp++) { +			if (bridge_pdev->vendor == pcibridge_vendors[tmp]) { +				pcipriv->ndis_adapter.pcibridge_vendor = tmp; +				RT_TRACE(COMP_INIT, DBG_DMESG, +					 ("Pci Bridge Vendor is found index: %d\n", +					  tmp)); +				break; +			} +		} +	} + +	if (pcipriv->ndis_adapter.pcibridge_vendor != +	    PCI_BRIDGE_VENDOR_UNKNOWN) { +		pcipriv->ndis_adapter.pcibridge_busnum = +		    bridge_pdev->bus->number; +		pcipriv->ndis_adapter.pcibridge_devnum = +		    PCI_SLOT(bridge_pdev->devfn); +		pcipriv->ndis_adapter.pcibridge_funcnum = +		    PCI_FUNC(bridge_pdev->devfn); +		pcipriv->ndis_adapter.pcicfg_addrport = +		    (pcipriv->ndis_adapter.pcibridge_busnum << 16) | +		    (pcipriv->ndis_adapter.pcibridge_devnum << 11) | +		    (pcipriv->ndis_adapter.pcibridge_funcnum << 8) | (1 << 31); +		pcipriv->ndis_adapter.pcibridge_pciehdr_offset = +		    pci_pcie_cap(bridge_pdev); +		pcipriv->ndis_adapter.num4bytes = +		    (pcipriv->ndis_adapter.pcibridge_pciehdr_offset + 0x10) / 4; + +		rtl_pci_get_linkcontrol_field(hw); + +		if (pcipriv->ndis_adapter.pcibridge_vendor == +		    PCI_BRIDGE_VENDOR_AMD) { +			pcipriv->ndis_adapter.amd_l1_patch = +			    rtl_pci_get_amd_l1_patch(hw); +		} +	} + +	RT_TRACE(COMP_INIT, DBG_DMESG, +		 ("pcidev busnumber:devnumber:funcnumber:vendor:link_ctl %d:%d:%d:%x:%x\n", +		  pcipriv->ndis_adapter.busnumber, +		  pcipriv->ndis_adapter.devnumber, +		  pcipriv->ndis_adapter.funcnumber, +		  pdev->vendor, pcipriv->ndis_adapter.linkctrl_reg)); + +	RT_TRACE(COMP_INIT, DBG_DMESG, +		 ("pci_bridge busnumber:devnumber:funcnumber:vendor:pcie_cap:link_ctl_reg:amd %d:%d:%d:%x:%x:%x:%x\n", +		  pcipriv->ndis_adapter.pcibridge_busnum, +		  pcipriv->ndis_adapter.pcibridge_devnum, +		  pcipriv->ndis_adapter.pcibridge_funcnum, +		  pcibridge_vendors[pcipriv->ndis_adapter.pcibridge_vendor], +		  pcipriv->ndis_adapter.pcibridge_pciehdr_offset, +		  pcipriv->ndis_adapter.pcibridge_linkctrlreg, +		  pcipriv->ndis_adapter.amd_l1_patch)); + +	rtl_pci_parse_configuration(pdev, hw); +	list_add_tail(&rtlpriv->list, &rtlpriv->glb_var->glb_priv_list); +	return true; +} + +static int rtl_pci_intr_mode_msi(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); +	struct rtl_pci *rtlpci = rtl_pcidev(pcipriv); +	int ret; +	ret = pci_enable_msi(rtlpci->pdev); +	if (ret < 0) +		return ret; + +	ret = request_irq(rtlpci->pdev->irq, &_rtl_pci_interrupt, +			  IRQF_SHARED, KBUILD_MODNAME, hw); +	if (ret < 0) { +		pci_disable_msi(rtlpci->pdev); +		return ret; +	} + +	rtlpci->using_msi = true; + +	RT_TRACE(COMP_INIT|COMP_INTR, DBG_DMESG, ("MSI Interrupt Mode!\n")); +	return 0; +} + +static int rtl_pci_intr_mode_legacy(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); +	struct rtl_pci *rtlpci = rtl_pcidev(pcipriv); +	int ret; + +	ret = request_irq(rtlpci->pdev->irq, &_rtl_pci_interrupt, +			  IRQF_SHARED, KBUILD_MODNAME, hw); +	if (ret < 0) +		return ret; + +	rtlpci->using_msi = false; +	RT_TRACE(COMP_INIT|COMP_INTR, DBG_DMESG, +		 ("Pin-based Interrupt Mode!\n")); +	return 0; +} + +static int rtl_pci_intr_mode_decide(struct ieee80211_hw *hw) +{ +	struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); +	struct rtl_pci *rtlpci = rtl_pcidev(pcipriv); +	int ret; +	if (rtlpci->msi_support) { +		ret = rtl_pci_intr_mode_msi(hw); +		if (ret < 0) +			ret = rtl_pci_intr_mode_legacy(hw); +	} else { +		ret = rtl_pci_intr_mode_legacy(hw); +	} +	return ret; +} + +/* this is used for other modules get + * hw pointer in rtl_pci_get_hw_pointer */ +static struct ieee80211_hw *hw_export; + +int stg_rtl_pci_probe(struct pci_dev *pdev, +		      const struct pci_device_id *id) +{ +	struct ieee80211_hw *hw = NULL; +	struct rtl_priv *rtlpriv = NULL; +	struct rtl_pci_priv *pcipriv = NULL; +	struct rtl_pci *rtlpci; +	unsigned long pmem_start, pmem_len, pmem_flags; +	int err; + +	err = pci_enable_device(pdev); +	if (err) { +		RT_ASSERT(false, +			  ("%s : Cannot enable new PCI device\n", +			   pci_name(pdev))); +		return err; +	} + +	if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) { +		if (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) { +			RT_ASSERT(false, +				  ("Unable to obtain 32bit DMA for consistent allocations\n")); +			pci_disable_device(pdev); +			return -ENOMEM; +		} +	} + +	pci_set_master(pdev); + +	hw = ieee80211_alloc_hw(sizeof(struct rtl_pci_priv) + +				sizeof(struct rtl_priv), &rtl92e_ops); +	if (!hw) { +		RT_ASSERT(false, +			  ("%s : ieee80211 alloc failed\n", pci_name(pdev))); +		err = -ENOMEM; +		goto fail1; +	} +	hw_export = hw; + +	SET_IEEE80211_DEV(hw, &pdev->dev); +	pci_set_drvdata(pdev, hw); + +	rtlpriv = hw->priv; +	pcipriv = (void *)rtlpriv->priv; +	pcipriv->dev.pdev = pdev; + +	/* init cfg & intf_ops */ +	rtlpriv->rtlhal.interface = INTF_PCI; +	rtlpriv->cfg = (struct rtl_hal_cfg *)(id->driver_data); +	rtlpriv->intf_ops = &rtl92e_pci_ops; +	rtlpriv->glb_var = &global_var; + +	/* +	 *init dbgp flags before all +	 *other functions, because we will +	 *use it in other funtions like +	 *RT_TRACE/RT_PRINT/RTL_PRINT_DATA +	 *you can not use these macro +	 *before this +	 */ +	rtl92e_dbgp_flag_init(hw); + +	/* MEM map */ +	err = pci_request_regions(pdev, KBUILD_MODNAME); +	if (err) { +		RT_ASSERT(false, ("Can't obtain PCI resources\n")); +		return err; +	} + +	pmem_start = pci_resource_start(pdev, rtlpriv->cfg->bar_id); +	pmem_len = pci_resource_len(pdev, rtlpriv->cfg->bar_id); +	pmem_flags = pci_resource_flags(pdev, rtlpriv->cfg->bar_id); + +	/*shared mem start */ +	rtlpriv->io.pci_mem_start = +			(unsigned long)pci_iomap(pdev, +			rtlpriv->cfg->bar_id, pmem_len); +	if (rtlpriv->io.pci_mem_start == 0) { +		RT_ASSERT(false, ("Can't map PCI mem\n")); +		goto fail2; +	} + +	RT_TRACE(COMP_INIT, DBG_DMESG, +		 ("mem mapped space: start: 0x%08lx len:%08lx flags:%08lx, after map:0x%08lx\n", +		  pmem_start, pmem_len, pmem_flags, +		  rtlpriv->io.pci_mem_start)); + +	/* Disable Clk Request */ +	pci_write_config_byte(pdev, 0x81, 0); +	/* leave D3 mode */ +	pci_write_config_byte(pdev, 0x44, 0); +	pci_write_config_byte(pdev, 0x04, 0x06); +	pci_write_config_byte(pdev, 0x04, 0x07); + +	/* The next statement is needed when built as single module */ +	rtl_core_module_init(); + +	/* find adapter */ +	/* if chip not support, will return false */ +	if (!_rtl_pci_find_adapter(pdev, hw)) +		goto fail3; + +	/* Init IO handler */ +	_rtl_pci_io_handler_init(&pdev->dev, hw); + +	/*like read eeprom and so on */ +	rtlpriv->cfg->ops->read_eeprom_info(hw); + +	if (rtlpriv->cfg->ops->init_sw_vars(hw)) { +		RT_TRACE(COMP_ERR, DBG_EMERG, ("Can't init_sw_vars.\n")); +		goto fail3; +	} + +	rtlpriv->cfg->ops->init_sw_leds(hw); + +	/*aspm */ +	rtl_pci_init_aspm(hw); + +	/* Init mac80211 sw */ +	err = rtl92e_init_core(hw); +	if (err) { +		RT_TRACE(COMP_ERR, DBG_EMERG, +			 ("Can't allocate sw for mac80211.\n")); +		goto fail3; +	} + +	/* Init PCI sw */ +	err = !rtl_pci_init(hw, pdev); +	if (err) { +		RT_TRACE(COMP_ERR, DBG_EMERG, ("Failed to init PCI.\n")); +		goto fail3; +	} + +	err = ieee80211_register_hw(hw); +	if (err) { +		RT_TRACE(COMP_ERR, DBG_EMERG, +			 ("Can't register mac80211 hw.\n")); +		goto fail3; +	} else { +		rtlpriv->mac80211.mac80211_registered = 1; +	} +	/* the wiphy must have been registed to +	 * cfg80211 prior to regulatory_hint */ +	if (regulatory_hint(hw->wiphy, rtlpriv->regd.alpha2)) +		RT_TRACE(COMP_ERR, DBG_WARNING, ("regulatory_hint fail\n")); + +	/* add for prov */ +	rtl_proc_add_one(hw); + +	/*init rfkill */ +	rtl92e_init_rfkill(hw); + +	rtlpci = rtl_pcidev(pcipriv); +	err = rtl_pci_intr_mode_decide(hw); +	if (err) { +		RT_TRACE(COMP_INIT, DBG_DMESG, +			 ("%s: failed to register IRQ handler\n", +			  wiphy_name(hw->wiphy))); +		goto fail3; +	} else { +		rtlpci->irq_alloc = 1; +	} + +	set_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status); +	return 0; + +fail3: +	pci_set_drvdata(pdev, NULL); +	rtl92e_deinit_core(hw); +	ieee80211_free_hw(hw); + +	if (rtlpriv->io.pci_mem_start != 0) +		pci_iounmap(pdev, (void __iomem *)rtlpriv->io.pci_mem_start); + +fail2: +	pci_release_regions(pdev); + +fail1: + +	pci_disable_device(pdev); + +	return -ENODEV; +} +EXPORT_SYMBOL(stg_rtl_pci_probe); + +struct ieee80211_hw *rtl_pci_get_hw_pointer(void) +{ +	return hw_export; +} +EXPORT_SYMBOL(rtl_pci_get_hw_pointer); + +void stg_rtl_pci_disconnect(struct pci_dev *pdev) +{ +	struct ieee80211_hw *hw = pci_get_drvdata(pdev); +	struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_pci *rtlpci = rtl_pcidev(pcipriv); +	struct rtl_mac *rtlmac = rtl_mac(rtlpriv); + +	clear_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status); + +	/* add for prov */ +	rtl_proc_remove_one(hw); + +	/*ieee80211_unregister_hw will call ops_stop */ +	if (rtlmac->mac80211_registered == 1) { +		ieee80211_unregister_hw(hw); +		rtlmac->mac80211_registered = 0; +	} else { +		rtl92e_deinit_deferred_work(hw); +		rtlpriv->intf_ops->adapter_stop(hw); +	} + +	/*deinit rfkill */ +	rtl92e_deinit_rfkill(hw); + +	rtl_pci_deinit(hw); +	rtl92e_deinit_core(hw); +	rtlpriv->cfg->ops->deinit_sw_vars(hw); + +	if (rtlpci->irq_alloc) { +		synchronize_irq(rtlpci->pdev->irq); +		free_irq(rtlpci->pdev->irq, hw); +		rtlpci->irq_alloc = 0; +	} + +	if (rtlpci->using_msi) +		pci_disable_msi(rtlpci->pdev); + +	list_del(&rtlpriv->list); +	if (rtlpriv->io.pci_mem_start != 0) { +		pci_iounmap(pdev, (void __iomem *)rtlpriv->io.pci_mem_start); +		pci_release_regions(pdev); +	} + +	pci_disable_device(pdev); + +	rtl_pci_disable_aspm(hw); + +	pci_set_drvdata(pdev, NULL); + +	ieee80211_free_hw(hw); +} +EXPORT_SYMBOL(stg_rtl_pci_disconnect); + +/*************************************** +kernel pci power state define: +PCI_D0         ((pci_power_t __force) 0) +PCI_D1         ((pci_power_t __force) 1) +PCI_D2         ((pci_power_t __force) 2) +PCI_D3hot      ((pci_power_t __force) 3) +PCI_D3cold     ((pci_power_t __force) 4) +PCI_UNKNOWN    ((pci_power_t __force) 5) + +This function is called when system +goes into suspend state mac80211 will +call rtl_mac_stop() from the mac80211 +suspend function first, So there is +no need to call hw_disable here. +****************************************/ +int stg_rtl_pci_suspend(struct device *dev) +{ +	struct pci_dev *pdev = to_pci_dev(dev); +	struct ieee80211_hw *hw = pci_get_drvdata(pdev); +	struct rtl_priv *rtlpriv = rtl_priv(hw); + +	rtlpriv->cfg->ops->hw_suspend(hw); +	rtl92e_deinit_rfkill(hw); + +	return 0; +} +EXPORT_SYMBOL(stg_rtl_pci_suspend); + +int stg_rtl_pci_resume(struct device *dev) +{ +	struct pci_dev *pdev = to_pci_dev(dev); +	struct ieee80211_hw *hw = pci_get_drvdata(pdev); +	struct rtl_priv *rtlpriv = rtl_priv(hw); + +	rtlpriv->cfg->ops->hw_resume(hw); +	rtl92e_init_rfkill(hw); + +	return 0; +} +EXPORT_SYMBOL(stg_rtl_pci_resume); + +struct rtl_intf_ops rtl92e_pci_ops = { +	.read92e_efuse_byte = read92e_efuse_byte, +	.adapter_start = rtl_pci_start, +	.adapter_stop = rtl_pci_stop, +	.check_buddy_priv = rtl_pci_check_buddy_priv, +	.adapter_tx = rtl_pci_tx, +	.flush = rtl_pci_flush, +	.reset_trx_ring = rtl92e_pci_reset_trx_ring, +	.waitq_insert = rtl_pci_tx_chk_waitq_insert, + +	.disable_aspm = rtl_pci_disable_aspm, +	.enable_aspm = rtl_pci_enable_aspm, +}; diff --git a/drivers/staging/rtl8192ee/pci.h b/drivers/staging/rtl8192ee/pci.h new file mode 100644 index 00000000000..62c23a7f450 --- /dev/null +++ b/drivers/staging/rtl8192ee/pci.h @@ -0,0 +1,342 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010  Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __RTL_PCI_H__ +#define __RTL_PCI_H__ + +#include <linux/pci.h> +/* +1: MSDU packet queue, +2: Rx Command Queue +*/ +#define RTL_PCI_RX_MPDU_QUEUE			0 +#define RTL_PCI_RX_CMD_QUEUE			1 +#define RTL_PCI_MAX_RX_QUEUE			2 + +#define RTL_PCI_MAX_RX_COUNT			512/*64*/ +#define RTL_PCI_MAX_TX_QUEUE_COUNT		9 + +#define RT_TXDESC_NUM				128 +#define TX_DESC_NUM_92E				512 +#define RT_TXDESC_NUM_BE_QUEUE			256 + +#define BK_QUEUE				0 +#define BE_QUEUE				1 +#define VI_QUEUE				2 +#define VO_QUEUE				3 +#define BEACON_QUEUE				4 +#define TXCMD_QUEUE				5 +#define MGNT_QUEUE				6 +#define HIGH_QUEUE				7 +#define HCCA_QUEUE				8 + +#define RTL_PCI_DEVICE(vend, dev, cfg)  \ +	.vendor = (vend), \ +	.device = (dev), \ +	.subvendor = PCI_ANY_ID, \ +	.subdevice = PCI_ANY_ID,\ +	.driver_data = (kernel_ulong_t)&(cfg) + +#define INTEL_VENDOR_ID				0x8086 +#define SIS_VENDOR_ID				0x1039 +#define ATI_VENDOR_ID				0x1002 +#define ATI_DEVICE_ID				0x7914 +#define AMD_VENDOR_ID				0x1022 + +#define PCI_MAX_BRIDGE_NUMBER			255 +#define PCI_MAX_DEVICES				32 +#define PCI_MAX_FUNCTION			8 + +#define PCI_CONF_ADDRESS	0x0CF8	/*PCI Configuration Space Address */ +#define PCI_CONF_DATA		0x0CFC	/*PCI Configuration Space Data */ + +#define PCI_CLASS_BRIDGE_DEV		0x06 +#define PCI_SUBCLASS_BR_PCI_TO_PCI	0x04 +#define PCI_CAPABILITY_ID_PCI_EXPRESS	0x10 +#define PCI_CAP_ID_EXP			0x10 + +#define U1DONTCARE			0xFF +#define U2DONTCARE			0xFFFF +#define U4DONTCARE			0xFFFFFFFF + +#define RTL_PCI_8192_DID	0x8192	/*8192 PCI-E */ +#define RTL_PCI_8192SE_DID	0x8192	/*8192 SE */ +#define RTL_PCI_8174_DID	0x8174	/*8192 SE */ +#define RTL_PCI_8173_DID	0x8173	/*8191 SE Crab */ +#define RTL_PCI_8172_DID	0x8172	/*8191 SE RE */ +#define RTL_PCI_8171_DID	0x8171	/*8191 SE Unicron */ +#define RTL_PCI_0045_DID	0x0045	/*8190 PCI for Ceraga */ +#define RTL_PCI_0046_DID	0x0046	/*8190 Cardbus for Ceraga */ +#define RTL_PCI_0044_DID	0x0044	/*8192e PCIE for Ceraga */ +#define RTL_PCI_0047_DID	0x0047	/*8192e Express Card for Ceraga */ +#define RTL_PCI_700F_DID	0x700F +#define RTL_PCI_701F_DID	0x701F +#define RTL_PCI_DLINK_DID	0x3304 +#define RTL_PCI_8723AE_DID	0x8723	/*8723e */ +#define RTL_PCI_8192CET_DID	0x8191	/*8192ce */ +#define RTL_PCI_8192CE_DID	0x8178	/*8192ce */ +#define RTL_PCI_8191CE_DID	0x8177	/*8192ce */ +#define RTL_PCI_8188CE_DID	0x8176	/*8192ce */ +#define RTL_PCI_8192CU_DID	0x8191	/*8192ce */ +#define RTL_PCI_8192DE_DID	0x8193	/*8192de */ +#define RTL_PCI_8192DE_DID2	0x002B	/*92DE*/ +#define RTL_PCI_8188EE_DID	0x8179  /*8188ee*/ +#define RTL_PCI_8723BE_DID	0xB723  /*8723be*/ +#define RTL_PCI_8192EE_DID	0x818B	/*8192ee*/ +#define RTL_PCI_8821AE_DID	0x8821	/*8821ae*/ +#define RTL_PCI_8812AE_DID	0x8812	/*8812ae*/ + +/*8192 support 16 pages of IO registers*/ +#define RTL_MEM_MAPPED_IO_RANGE_8190PCI		0x1000 +#define RTL_MEM_MAPPED_IO_RANGE_8192PCIE	0x4000 +#define RTL_MEM_MAPPED_IO_RANGE_8192SE		0x4000 +#define RTL_MEM_MAPPED_IO_RANGE_8192CE		0x4000 +#define RTL_MEM_MAPPED_IO_RANGE_8192DE		0x4000 + +#define RTL_PCI_REVISION_ID_8190PCI		0x00 +#define RTL_PCI_REVISION_ID_8192PCIE		0x01 +#define RTL_PCI_REVISION_ID_8192SE		0x10 +#define RTL_PCI_REVISION_ID_8192CE		0x1 +#define RTL_PCI_REVISION_ID_8192DE		0x0 + +#define RTL_DEFAULT_HARDWARE_TYPE	HARDWARE_TYPE_RTL8192CE + +enum pci_bridge_vendor { +	PCI_BRIDGE_VENDOR_INTEL = 0x0,	/*0b'0000,0001 */ +	PCI_BRIDGE_VENDOR_ATI,		/*0b'0000,0010*/ +	PCI_BRIDGE_VENDOR_AMD,		/*0b'0000,0100*/ +	PCI_BRIDGE_VENDOR_SIS,		/*0b'0000,1000*/ +	PCI_BRIDGE_VENDOR_UNKNOWN,	/*0b'0100,0000*/ +	PCI_BRIDGE_VENDOR_MAX, +}; + +struct rtl_pci_capabilities_header { +	u8 capability_id; +	u8 next; +}; + +/* In new TRX flow, Buffer_desc is new concept +  * But TX wifi info == TX descriptor in old flow +  * RX wifi info == RX descriptor in old flow */ +struct rtl_tx_buffer_desc { +#if (RTL8192EE_SEG_NUM == 2) +	u32 dword[2*(DMA_IS_64BIT + 1)*8]; /*seg = 8*/ +#elif (RTL8192EE_SEG_NUM == 1) +	u32 dword[2*(DMA_IS_64BIT + 1)*4]; /*seg = 4*/ +#elif (RTL8192EE_SEG_NUM == 0) +	u32 dword[2*(DMA_IS_64BIT + 1)*2]; /*seg = 2*/ +#endif +} __packed; + +struct rtl_tx_desc {/*old: tx desc new: tx wifi info*/ +	u32 dword[16]; +} __packed; + +struct rtl_rx_buffer_desc { /*rx buffer desc*/ +	u32 dword[2]; +} __packed; + +struct rtl_rx_desc { /*old: rx desc new: rx wifi info*/ +	u32 dword[8]; +} __packed; + +struct rtl_tx_cmd_desc { +	u32 dword[16]; +} __packed; + +struct rtl8192_tx_ring { +	struct rtl_tx_desc *desc; /*tx desc / tx wifi info*/ +	dma_addr_t dma; /*tx desc dma memory / tx wifi info dma memory*/ +	unsigned int idx; +	unsigned int entries; +	struct sk_buff_head queue; +	/*add for new trx flow*/ +	struct rtl_tx_buffer_desc *buffer_desc; /*tx buffer descriptor*/ +	dma_addr_t buffer_desc_dma; /*tx bufferd desc dma memory*/ +	u16 avl_desc; /* available_desc_to_write */ +	u16 cur_tx_wp; /* current_tx_write_point */ +	u16 cur_tx_rp; /* current_tx_read_point */ +}; + +struct rtl8192_rx_ring { +	struct rtl_rx_desc *desc;/*for old trx flow, not uesd in new trx*/ +	/*dma matches either 'desc' or 'buffer_desc'*/ +	dma_addr_t dma; +	unsigned int idx; +	struct sk_buff *rx_buf[RTL_PCI_MAX_RX_COUNT]; +	/*add for new trx flow*/ +	struct rtl_rx_buffer_desc *buffer_desc; /*rx buffer descriptor*/ +	u16 next_rx_rp; /* next_rx_read_point */ +}; + +struct rtl_pci { +	struct pci_dev *pdev; +	bool irq_enabled; + +	/*Tx */ +	struct rtl8192_tx_ring tx_ring[RTL_PCI_MAX_TX_QUEUE_COUNT]; +	int txringcount[RTL_PCI_MAX_TX_QUEUE_COUNT]; +	u32 transmit_config; + +	/*Rx */ +	struct rtl8192_rx_ring rx_ring[RTL_PCI_MAX_RX_QUEUE]; +	int rxringcount; +	u16 rxbuffersize; +	u32 receive_config; + +	/*irq */ +	u8 irq_alloc; +	u32 irq_mask[2]; +	u32 sys_irq_mask; + +	/*Bcn control register setting */ +	u32 reg_bcn_ctrl_val; + +	 /*ASPM*/ u8 const_pci_aspm; +	u8 const_amdpci_aspm; +	u8 const_hwsw_rfoff_d3; +	u8 const_support_pciaspm; +	/*pci-e bridge */ +	u8 const_hostpci_aspm_setting; +	/*pci-e device */ +	u8 const_devicepci_aspm_setting; +	/*If it supports ASPM, Offset[560h] = 0x40, +	   otherwise Offset[560h] = 0x00. */ +	bool b_support_aspm; +	bool b_support_backdoor; + +	/*QOS & EDCA */ +	enum acm_method acm_method; + +	u16 shortretry_limit; +	u16 longretry_limit; + +	/* MSI support */ +	bool msi_support; +	bool using_msi; +}; + +struct mp_adapter { +	u8 linkctrl_reg; + +	u8 busnumber; +	u8 devnumber; +	u8 funcnumber; + +	u8 pcibridge_busnum; +	u8 pcibridge_devnum; +	u8 pcibridge_funcnum; + +	u8 pcibridge_vendor; +	u16 pcibridge_vendorid; +	u16 pcibridge_deviceid; + +	u32 pcicfg_addrport; +	u8 num4bytes; + +	u8 pcibridge_pciehdr_offset; +	u8 pcibridge_linkctrlreg; + +	bool amd_l1_patch; +}; + +struct rtl_pci_priv { +	struct rtl_pci dev; +	struct mp_adapter ndis_adapter; +	struct rtl_led_ctl ledctl; +	struct bt_coexist_info btcoexist; +}; + +#define rtl_pcipriv(hw)		(((struct rtl_pci_priv *)(rtl_priv(hw))->priv)) +#define rtl_pcidev(pcipriv)	(&((pcipriv)->dev)) + +int rtl92e_pci_reset_trx_ring(struct ieee80211_hw *hw); + +extern struct rtl_intf_ops rtl92e_pci_ops; + +int stg_rtl_pci_probe(struct pci_dev *pdev, +		      const struct pci_device_id *id); +void stg_rtl_pci_disconnect(struct pci_dev *pdev); +int stg_rtl_pci_suspend(struct device *dev); +int stg_rtl_pci_resume(struct device *dev); + +static inline u8 pci_read8_sync(struct rtl_priv *rtlpriv, u32 addr) +{ +	return 0xff & readb((u8 __iomem *)rtlpriv->io.pci_mem_start + addr); +} + +static inline u16 pci_read16_sync(struct rtl_priv *rtlpriv, u32 addr) +{ +	return readw((u8 __iomem *)rtlpriv->io.pci_mem_start + addr); +} + +static inline u32 pci_read32_sync(struct rtl_priv *rtlpriv, u32 addr) +{ +	return readl((u8 __iomem *)rtlpriv->io.pci_mem_start + addr); +} + +static inline void pci_write8_async(struct rtl_priv *rtlpriv, u32 addr, u8 val) +{ +	writeb(val, (u8 __iomem *)rtlpriv->io.pci_mem_start + addr); +} + +static inline void pci_write16_async(struct rtl_priv *rtlpriv, +				     u32 addr, u16 val) +{ +	writew(val, (u8 __iomem *)rtlpriv->io.pci_mem_start + addr); +} + +static inline void pci_write32_async(struct rtl_priv *rtlpriv, +				     u32 addr, u32 val) +{ +	writel(val, (u8 __iomem *)rtlpriv->io.pci_mem_start + addr); +} + +static inline void rtl_pci_raw_write_port_ulong(u32 port, u32 val) +{ +	outl(val, port); +} + +static inline void rtl_pci_raw_write_port_uchar(u32 port, u8 val) +{ +	outb(val, port); +} + +static inline void rtl_pci_raw_read_port_uchar(u32 port, u8 *pval) +{ +	*pval = inb(port); +} + +static inline void rtl_pci_raw_read_port_ushort(u32 port, u16 *pval) +{ +	*pval = inw(port); +} + +static inline void rtl_pci_raw_read_port_ulong(u32 port, u32 *pval) +{ +	*pval = inl(port); +} + +#endif diff --git a/drivers/staging/rtl8192ee/ps.c b/drivers/staging/rtl8192ee/ps.c new file mode 100644 index 00000000000..90c3fc2e62b --- /dev/null +++ b/drivers/staging/rtl8192ee/ps.c @@ -0,0 +1,983 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010  Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#include "wifi.h" +#include "base.h" +#include "ps.h" +#include "btcoexist/rtl_btc.h" + +bool stg_rtl_ps_enable_nic(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); +	bool init_status = true; + +	/*<1> reset trx ring */ +	if (rtlhal->interface == INTF_PCI) +		rtlpriv->intf_ops->reset_trx_ring(hw); + +	if (is_hal_stop(rtlhal)) +		RT_TRACE(COMP_ERR, DBG_WARNING, ("Driver is already down!\n")); + +	/*<2> Enable Adapter */ +	rtlpriv->cfg->ops->hw_init(hw); +	RT_CLEAR_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC); +	/*init_status = false; */ + +	/*<3> Enable Interrupt */ +	rtlpriv->cfg->ops->enable_interrupt(hw); + +	/*<enable timer> */ +	rtl92e_watch_dog_timer_callback((unsigned long)hw); + +	return init_status; +} +EXPORT_SYMBOL(stg_rtl_ps_enable_nic); + +bool stg_rtl_ps_disable_nic(struct ieee80211_hw *hw) +{ +	bool status = true; +	struct rtl_priv *rtlpriv = rtl_priv(hw); + +	/*<1> Stop all timer */ +	rtl92e_deinit_deferred_work(hw); + +	/*<2> Disable Interrupt */ +	rtlpriv->cfg->ops->disable_interrupt(hw); + +	/*<3> Disable Adapter */ +	rtlpriv->cfg->ops->hw_disable(hw); + +	return status; +} +EXPORT_SYMBOL(stg_rtl_ps_disable_nic); + +bool stg_rtl_ps_set_rf_state(struct ieee80211_hw *hw, +			     enum rf_pwrstate state_toset, +			     u32 changesource, bool protect_or_not) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); +	enum rf_pwrstate rtstate; +	bool b_actionallowed = false; +	u16 rfwait_cnt = 0; + +	/*protect_or_not = true; */ + +	if (protect_or_not) +		goto no_protect; + +	/* +	 *Only one thread can change +	 *the RF state at one time, and others +	 *should wait to be executed. +	 */ +	while (true) { +		spin_lock(&rtlpriv->locks.rf_ps_lock); +		if (ppsc->rfchange_inprogress) { +			spin_unlock(&rtlpriv->locks.rf_ps_lock); + +			RT_TRACE(COMP_ERR, DBG_WARNING, +				 ("RF Change in progress! Wait to set..state_toset(%d)\n", +				  state_toset)); + +			/* Set RF after the previous action is done.  */ +			while (ppsc->rfchange_inprogress) { +				rfwait_cnt++; +				mdelay(1); +				/* +				 *Wait too long, return false to avoid +				 *to be stuck here. +				 */ +				if (rfwait_cnt > 100) +					return false; +			} +		} else { +			ppsc->rfchange_inprogress = true; +			spin_unlock(&rtlpriv->locks.rf_ps_lock); +			break; +		} +	} + +no_protect: +	rtstate = ppsc->rfpwr_state; + +	switch (state_toset) { +	case ERFON: +		ppsc->rfoff_reason &= (~changesource); + +		if ((changesource == RF_CHANGE_BY_HW) && +		    (ppsc->b_hwradiooff)) { +			ppsc->b_hwradiooff = false; +		} +		if (!ppsc->rfoff_reason) { +			ppsc->rfoff_reason = 0; +			b_actionallowed = true; +		} +		break; +	case ERFOFF: +		if ((changesource == RF_CHANGE_BY_HW) && +		    (!ppsc->b_hwradiooff)) { +			ppsc->b_hwradiooff = true; +		} +		ppsc->rfoff_reason |= changesource; +		b_actionallowed = true; +		break; +	case ERFSLEEP: +		ppsc->rfoff_reason |= changesource; +		b_actionallowed = true; +		break; +	default: +		RT_TRACE(COMP_ERR, DBG_EMERG, ("switch case not process\n")); +		break; +	} + +	if (b_actionallowed) +		rtlpriv->cfg->ops->set_rf_power_state(hw, state_toset); + +	if (!protect_or_not) { +		spin_lock(&rtlpriv->locks.rf_ps_lock); +		ppsc->rfchange_inprogress = false; +		spin_unlock(&rtlpriv->locks.rf_ps_lock); +	} + +	return b_actionallowed; +} +EXPORT_SYMBOL(stg_rtl_ps_set_rf_state); + +static void _rtl_ps_inactive_ps(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); +	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + +	ppsc->b_swrf_processing = true; + +	if (ppsc->inactive_pwrstate == ERFON && rtlhal->interface == INTF_PCI) { +		if ((ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM) && +		    RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM) && +		    rtlhal->interface == INTF_PCI) { +			rtlpriv->intf_ops->disable_aspm(hw); +			RT_CLEAR_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM); +		} +	} + +	stg_rtl_ps_set_rf_state(hw, ppsc->inactive_pwrstate, +				RF_CHANGE_BY_IPS, false); + +	if (ppsc->inactive_pwrstate == ERFOFF && +	    rtlhal->interface == INTF_PCI) { +		if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM && +		    !RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM)) { +			rtlpriv->intf_ops->enable_aspm(hw); +			RT_SET_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM); +		} +	} + +	ppsc->b_swrf_processing = false; +} + +void rtl92e_ips_nic_off_wq_callback(void *data) +{ +	struct rtl_works *rtlworks = +	    container_of_dwork_rtl(data, struct rtl_works, ips_nic_off_wq); +	struct ieee80211_hw *hw = rtlworks->hw; +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); +	enum rf_pwrstate rtstate; + +	if (mac->opmode != NL80211_IFTYPE_STATION) { +		RT_TRACE(COMP_ERR, DBG_WARNING, ("not station return\n")); +		return; +	} + +	if (mac->p2p_in_use) +		return; + +	if (mac->link_state > MAC80211_NOLINK) +		return; + +	if (is_hal_stop(rtlhal)) +		return; + +	if (rtlpriv->sec.being_setkey) +		return; + +	if (rtlpriv->cfg->ops->bt_turn_off_bt_coexist_before_enter_lps) +		rtlpriv->cfg->ops->bt_turn_off_bt_coexist_before_enter_lps(hw); + +	if (ppsc->b_inactiveps) { +		rtstate = ppsc->rfpwr_state; + +		/* +		 *Do not enter IPS in the following conditions: +		 *(1) RF is already OFF or Sleep +		 *(2) b_swrf_processing (indicates the IPS is still under going) +		 *(3) Connectted (only disconnected can trigger IPS) +		 *(4) IBSS (send Beacon) +		 *(5) AP mode (send Beacon) +		 *(6) monitor mode (rcv packet) +		 */ + +		if (rtstate == ERFON && +		    !ppsc->b_swrf_processing && +		    (mac->link_state == MAC80211_NOLINK) && +		    !mac->act_scanning) { +			RT_TRACE(COMP_RF, DBG_LOUD, +				 ("IPSEnter(): Turn off RF.\n")); + +			ppsc->inactive_pwrstate = ERFOFF; +			ppsc->b_in_powersavemode = true; + +			/* call before RF off */ +			if (rtlpriv->cfg->ops->get_btc_status()) +				rtlpriv->btcoexist.btc_ops->btc_ips_notify(rtlpriv, +									ppsc->inactive_pwrstate); + +			/*rtl92e_pci_reset_trx_ring(hw); */ +			_rtl_ps_inactive_ps(hw); +		} +	} +} + +void rtl92e_ips_nic_off(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); + +	/* +	 *because when link with ap, mac80211 will ask us +	 *to disable nic quickly after scan before linking, +	 *this will cause link failed, so we delay 100ms here +	 */ +	queue_delayed_work(rtlpriv->works.rtl_wq, +			   &rtlpriv->works.ips_nic_off_wq, MSECS(100)); +} + +/* NOTICE: any opmode should exc nic_on, or disable without + * nic_on may something wrong, like adhoc TP*/ +void rtl92e_ips_nic_on(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); +	enum rf_pwrstate rtstate; + +	cancel_delayed_work(&rtlpriv->works.ips_nic_off_wq); + +	spin_lock(&rtlpriv->locks.ips_lock); +	if (ppsc->b_inactiveps) { +		rtstate = ppsc->rfpwr_state; + +		if (rtstate != ERFON && +		    !ppsc->b_swrf_processing && +		    ppsc->rfoff_reason <= RF_CHANGE_BY_IPS) { +			ppsc->inactive_pwrstate = ERFON; +			ppsc->b_in_powersavemode = false; +			_rtl_ps_inactive_ps(hw); +			/* call after RF on */ +			if (rtlpriv->cfg->ops->get_btc_status()) +				rtlpriv->btcoexist.btc_ops->btc_ips_notify(rtlpriv, +									ppsc->inactive_pwrstate); +		} +	} +	spin_unlock(&rtlpriv->locks.ips_lock); +} + +/*for FW LPS*/ + +/* + *Determine if we can set Fw into PS mode + *in current condition.Return true if it + *can enter PS mode. + */ +static bool rtl_get_fwlps_doze(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); +	u32 ps_timediff; + +	ps_timediff = jiffies_to_msecs(jiffies - +				       ppsc->last_delaylps_stamp_jiffies); + +	if (ps_timediff < 2000) { +		RT_TRACE(COMP_POWER, DBG_LOUD, +			 ("Delay enter Fw LPS for DHCP, ARP, or EAPOL exchanging state\n")); +		return false; +	} + +	if (mac->link_state != MAC80211_LINKED) +		return false; + +	if (mac->opmode == NL80211_IFTYPE_ADHOC) +		return false; + +	return true; +} + +/* Change current and default preamble mode.*/ +void rtl_lps_set_psmode(struct ieee80211_hw *hw, u8 rt_psmode) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); +	bool enter_fwlps; + +	if (mac->opmode == NL80211_IFTYPE_ADHOC) +		return; + +	if (mac->link_state != MAC80211_LINKED) +		return; + +	if (ppsc->dot11_psmode == rt_psmode) +		return; + +	/* Update power save mode configured. */ +	ppsc->dot11_psmode = rt_psmode; + +	/* +	 *<FW control LPS> +	 *1. Enter PS mode +	 *   Set RPWM to Fw to turn RF off and send H2C fw_pwrmode +	 *   cmd to set Fw into PS mode. +	 *2. Leave PS mode +	 *   Send H2C fw_pwrmode cmd to Fw to set Fw into Active +	 *   mode and set RPWM to turn RF on. +	 */ + +	if ((ppsc->b_fwctrl_lps) && ppsc->report_linked) { +		if (ppsc->dot11_psmode == EACTIVE) { +			RT_TRACE(COMP_RF, DBG_DMESG, +				 ("FW LPS leave ps_mode:%x\n", +				  FW_PS_ACTIVE_MODE)); +			enter_fwlps = false; +			ppsc->pwr_mode = FW_PS_ACTIVE_MODE; +			ppsc->smart_ps = 0; +			rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_FW_LPS_ACTION, +						      (u8 *)(&enter_fwlps)); +			if (ppsc->p2p_ps_info.opp_ps) +				rtl92e_p2p_ps_cmd(hw , P2P_PS_ENABLE); + +			if (rtlpriv->cfg->ops->get_btc_status()) +				rtlpriv->btcoexist.btc_ops->btc_lps_notify(rtlpriv, rt_psmode); +		} else { +			if (rtl_get_fwlps_doze(hw)) { +				RT_TRACE(COMP_RF, DBG_DMESG, +					 ("FW LPS enter ps_mode:%x\n", +					 ppsc->fwctrl_psmode)); +				if (rtlpriv->cfg->ops->get_btc_status()) +					rtlpriv->btcoexist.btc_ops->btc_lps_notify(rtlpriv, rt_psmode); +				enter_fwlps = true; +				ppsc->pwr_mode = ppsc->fwctrl_psmode; +				ppsc->smart_ps = 2; +				rtlpriv->cfg->ops->set_hw_reg(hw, +							HW_VAR_FW_LPS_ACTION, +							(u8 *)(&enter_fwlps)); + +			} else { +				/* Reset the power save related parameters. */ +				ppsc->dot11_psmode = EACTIVE; +			} +		} +	} +} + +/*Enter the leisure power save mode.*/ +void rtl92e_lps_enter(struct ieee80211_hw *hw) +{ +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	unsigned long flag; + +	if (!ppsc->b_fwctrl_lps) +		return; + +	if (rtlpriv->sec.being_setkey) +		return; + +	if (rtlpriv->link_info.b_busytraffic) +		return; + +	/*sleep after linked 10s, to let DHCP and 4-way handshake ok enough!! */ +	if (mac->cnt_after_linked < 5) +		return; + +	if (mac->opmode == NL80211_IFTYPE_ADHOC) +		return; + +	if (mac->link_state != MAC80211_LINKED) +		return; + +	spin_lock_irqsave(&rtlpriv->locks.lps_lock, flag); + +	/* Idle for a while if we connect to AP a while ago. */ +	if (mac->cnt_after_linked >= 2) { +		if (ppsc->dot11_psmode == EACTIVE) { +			RT_TRACE(COMP_POWER, DBG_LOUD, +				 ("Enter 802.11 power save mode...\n")); + +			rtl_lps_set_psmode(hw, EAUTOPS); +		} +	} + +	spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag); +} +EXPORT_SYMBOL(rtl92e_lps_enter); + +/*Leave the leisure power save mode.*/ +void rtl92e_lps_leave(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); +	unsigned long flag; + +	spin_lock_irqsave(&rtlpriv->locks.lps_lock, flag); + +	if (ppsc->b_fwctrl_lps) { +		if (ppsc->dot11_psmode != EACTIVE) { +			if (ppsc->reg_rfps_level & RT_RF_LPS_LEVEL_ASPM && +			    RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM) && +			    rtlhal->interface == INTF_PCI) { +				rtlpriv->intf_ops->disable_aspm(hw); +				RT_CLEAR_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM); +			} + +			RT_TRACE(COMP_POWER, DBG_LOUD, +				 ("Busy Traffic,Leave 802.11 power save..\n")); + +			rtl_lps_set_psmode(hw, EACTIVE); +		} +	} +	spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag); +} +EXPORT_SYMBOL(rtl92e_lps_leave); + +/* For sw LPS*/ +void rtl92e_swlps_beacon(struct ieee80211_hw *hw, void *data, unsigned int len) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +	struct ieee80211_hdr *hdr = (void *)data; +	struct ieee80211_tim_ie *tim_ie; +	u8 *tim; +	u8 tim_len; +	bool u_buffed; +	bool m_buffed; + +	if (mac->opmode != NL80211_IFTYPE_STATION) +		return; + +	if (!rtlpriv->psc.b_swctrl_lps) +		return; + +	if (rtlpriv->mac80211.link_state != MAC80211_LINKED) +		return; + +	if (!rtlpriv->psc.sw_ps_enabled) +		return; + +	if (rtlpriv->psc.b_fwctrl_lps) +		return; + +	if (likely(!(hw->conf.flags & IEEE80211_CONF_PS))) +		return; + +	/* check if this really is a beacon */ +	if (!ieee80211_is_beacon(hdr->frame_control)) +		return; + +	/* min. beacon length + FCS_LEN */ +	if (len <= 40 + FCS_LEN) +		return; + +	/* and only beacons from the associated BSSID, please */ +	if (!ether_addr_equal(hdr->addr3, rtlpriv->mac80211.bssid)) +		return; + +	rtlpriv->psc.last_beacon = jiffies; + +	tim = rtl92e_find_ie(data, len - FCS_LEN, WLAN_EID_TIM); +	if (!tim) +		return; + +	if (tim[1] < sizeof(*tim_ie)) +		return; + +	tim_len = tim[1]; +	tim_ie = (struct ieee80211_tim_ie *)&tim[2]; + +	if (!WARN_ON_ONCE(!hw->conf.ps_dtim_period)) +		rtlpriv->psc.dtim_counter = tim_ie->dtim_count; + +	/* Check whenever the PHY can be turned off again. */ + +	/* 1. What about buffered unicast traffic for our AID? */ +	u_buffed = ieee80211_check_tim(tim_ie, tim_len, +				       rtlpriv->mac80211.assoc_id); + +	/* 2. Maybe the AP wants to send multicast/broadcast data? */ +	m_buffed = tim_ie->bitmap_ctrl & 0x01; +	rtlpriv->psc.multi_buffered = m_buffed; + +	/* unicast will process by mac80211 through +	 * set ~IEEE80211_CONF_PS, So we just check +	 * multicast frames here */ +	if (!m_buffed) {/*&&) { !rtlpriv->psc.tx_doing) { */ +		/* back to low-power land. and delay is +		 * prevent null power save frame tx fail */ +		queue_delayed_work(rtlpriv->works.rtl_wq, +				   &rtlpriv->works.ps_work, MSECS(5)); +	} else { +		RT_TRACE(COMP_POWER, DBG_DMESG, +			 ("u_bufferd: %x, m_buffered: %x\n", +			  u_buffed, m_buffed)); +	} +} + +void rtl92e_swlps_rf_awake(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +	unsigned long flag; + +	if (!rtlpriv->psc.b_swctrl_lps) +		return; +	if (mac->link_state != MAC80211_LINKED) +		return; + +	if (ppsc->reg_rfps_level & RT_RF_LPS_LEVEL_ASPM && +	    RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM)) { +		rtlpriv->intf_ops->disable_aspm(hw); +		RT_CLEAR_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM); +	} + +	spin_lock_irqsave(&rtlpriv->locks.lps_lock, flag); +	stg_rtl_ps_set_rf_state(hw, ERFON, RF_CHANGE_BY_PS, false); +	spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag); +} + +void rtl92e_swlps_rfon_wq_callback(void *data) +{ +	struct rtl_works *rtlworks = +	    container_of_dwork_rtl(data, struct rtl_works, ps_rfon_wq); +	struct ieee80211_hw *hw = rtlworks->hw; + +	rtl92e_swlps_rf_awake(hw); +} + +void rtl92e_swlps_rf_sleep(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); +	unsigned long flag; +	u8 sleep_intv; + +	if (!rtlpriv->psc.sw_ps_enabled) +		return; + +	if ((rtlpriv->sec.being_setkey) || +	    (mac->opmode == NL80211_IFTYPE_ADHOC)) +		return; + +	/*sleep after linked 10s, to let DHCP and 4-way handshake ok enough!! */ +	if ((mac->link_state != MAC80211_LINKED) || (mac->cnt_after_linked < 5)) +		return; + +	if (rtlpriv->link_info.b_busytraffic) +		return; + +	spin_lock(&rtlpriv->locks.rf_ps_lock); +	if (rtlpriv->psc.rfchange_inprogress) { +		spin_unlock(&rtlpriv->locks.rf_ps_lock); +		return; +	} +	spin_unlock(&rtlpriv->locks.rf_ps_lock); + +	spin_lock_irqsave(&rtlpriv->locks.lps_lock, flag); +	stg_rtl_ps_set_rf_state(hw, ERFSLEEP, RF_CHANGE_BY_PS , false); +	spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag); + +	if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM && +	    !RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM)) { +		rtlpriv->intf_ops->enable_aspm(hw); +		RT_SET_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM); +	} + +	/* here is power save alg, when this beacon is DTIM +	 * we will set sleep time to dtim_period * n; +	 * when this beacon is not DTIM, we will set sleep +	 * time to sleep_intv = rtlpriv->psc.dtim_counter or +	 * MAX_SW_LPS_SLEEP_INTV(default set to 5) */ + +	if (rtlpriv->psc.dtim_counter == 0) { +		if (hw->conf.ps_dtim_period == 1) +			sleep_intv = hw->conf.ps_dtim_period * 2; +		else +			sleep_intv = hw->conf.ps_dtim_period; +	} else { +		sleep_intv = rtlpriv->psc.dtim_counter; +	} + +	if (sleep_intv > MAX_SW_LPS_SLEEP_INTV) +		sleep_intv = MAX_SW_LPS_SLEEP_INTV; + +	/* this print should always be dtim_conter = 0 & +	 * sleep  = dtim_period, that meaons, we should +	 * awake before every dtim */ +	RT_TRACE(COMP_POWER, DBG_DMESG, +		 ("dtim_counter:%x will sleep :%d beacon_intv\n", +		  rtlpriv->psc.dtim_counter, sleep_intv)); + +	/* we tested that 40ms is enough for sw & hw sw delay */ +	queue_delayed_work(rtlpriv->works.rtl_wq, &rtlpriv->works.ps_rfon_wq, +			   MSECS(sleep_intv*mac->vif->bss_conf.beacon_int-40)); +} + + +void rtl92e_swlps_wq_callback(void *data) +{ +	struct rtl_works *rtlworks = +		container_of_dwork_rtl(data, struct rtl_works, ps_work); +	struct ieee80211_hw *hw = rtlworks->hw; +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	bool ps = false; + +	ps = (hw->conf.flags & IEEE80211_CONF_PS); + +	/* we can sleep after ps null send ok */ +	if (rtlpriv->psc.state_inap) { +		rtl92e_swlps_rf_sleep(hw); + +		if (rtlpriv->psc.state && !ps) { +			rtlpriv->psc.sleep_ms = +				jiffies_to_msecs(jiffies - +						 rtlpriv->psc.last_action); +		} + +		if (ps) +			rtlpriv->psc.last_slept = jiffies; + +		rtlpriv->psc.last_action = jiffies; +		rtlpriv->psc.state = ps; +	} +} + +static void rtl_p2p_noa_ie(struct ieee80211_hw *hw, void *data, +			   unsigned int len) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct ieee80211_mgmt *mgmt = (void *)data; +	struct rtl_p2p_ps_info *p2pinfo = &(rtlpriv->psc.p2p_ps_info); +	u8 *pos, *end, *ie; +	u16 noa_len; +	static u8 p2p_oui_ie_type[4] = {0x50, 0x6f, 0x9a, 0x09}; +	u8 noa_num, index , i, noa_index = 0; +	bool find_p2p_ie = false , find_p2p_ps_ie = false; +	pos = (u8 *)mgmt->u.beacon.variable; +	end = data + len; +	ie = NULL; + +	while (pos + 1 < end) { +		if (pos + 2 + pos[1] > end) +			return; + +		if (pos[0] == 221 && pos[1] > 4) { +			if (memcmp(&pos[2], p2p_oui_ie_type, 4) == 0) { +				ie = pos + 2+4; +				break; +			} +		} +		pos += 2 + pos[1]; +	} + +	if (ie == NULL) +		return; +	find_p2p_ie = true; +	/*to find noa ie*/ +	while (ie + 1 < end) { +		noa_len = READEF2BYTE((__le16 *)&ie[1]); +		if (ie + 3 + ie[1] > end) +			return; + +		if (ie[0] == 12) { +			find_p2p_ps_ie = true; +			if ((noa_len - 2) % 13 != 0) { +				RT_TRACE(COMP_INIT, DBG_LOUD, +					 ("P2P notice of absence: invalid length%d\n", +					 noa_len)); +				return; +			} else { +				noa_num = (noa_len - 2) / 13; +			} +			noa_index = ie[3]; +			if (rtlpriv->psc.p2p_ps_info.p2p_ps_mode == +			    P2P_PS_NONE || noa_index != p2pinfo->noa_index) { +				RT_TRACE(COMP_FW, DBG_LOUD, +					 ("update NOA ie.\n")); +				p2pinfo->noa_index = noa_index; +				p2pinfo->opp_ps = (ie[4] >> 7); +				p2pinfo->ctwindow = ie[4] & 0x7F; +				p2pinfo->noa_num = noa_num; +				index = 5; +				for (i = 0; i < noa_num; i++) { +					p2pinfo->noa_count_type[i] = +							READEF1BYTE(ie+index); +					index += 1; +					p2pinfo->noa_duration[i] = +						 READEF4BYTE((__le32 *)ie+index); +					index += 4; +					p2pinfo->noa_interval[i] = +						 READEF4BYTE((__le32 *)ie+index); +					index += 4; +					p2pinfo->noa_start_time[i] = +						 READEF4BYTE((__le32 *)ie+index); +					index += 4; +				} + +				if (p2pinfo->opp_ps == 1) { +					p2pinfo->p2p_ps_mode = P2P_PS_CTWINDOW; +					/* Driver should wait LPS +					 * entering CTWindow*/ +					if (rtlpriv->psc.b_fw_current_inpsmode) { +						rtl92e_p2p_ps_cmd(hw, +							       P2P_PS_ENABLE); +					} +				} else if (p2pinfo->noa_num > 0) { +					p2pinfo->p2p_ps_mode = P2P_PS_NOA; +					rtl92e_p2p_ps_cmd(hw, P2P_PS_ENABLE); +				} else if (p2pinfo->p2p_ps_mode > P2P_PS_NONE) { +					rtl92e_p2p_ps_cmd(hw, P2P_PS_DISABLE); +				} +			} + +		break; +		} +		ie += 3 + noa_len; +	} + +	if (find_p2p_ie) { +		if ((p2pinfo->p2p_ps_mode > P2P_PS_NONE) && +		    (!find_p2p_ps_ie)) +			rtl92e_p2p_ps_cmd(hw, P2P_PS_DISABLE); +	} +} + +static void rtl_p2p_action_ie(struct ieee80211_hw *hw, void *data, +			      unsigned int len) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct ieee80211_mgmt *mgmt = (void *)data; +	struct rtl_p2p_ps_info *p2pinfo = &(rtlpriv->psc.p2p_ps_info); +	bool find_p2p_ie = false, find_p2p_ps_ie = false; +	u8 noa_num, index, i, noa_index = 0; +	u8 *pos, *end, *ie; +	u16 noa_len; +	static u8 p2p_oui_ie_type[4] = {0x50, 0x6f, 0x9a, 0x09}; + +	pos = (u8 *)&mgmt->u.action.category; +	end = data + len; +	ie = NULL; + +	if (pos[0] == 0x7f) { +		if (memcmp(&pos[1], p2p_oui_ie_type, 4) == 0) +			ie = pos + 3+4; +	} + +	if (ie == NULL) +		return; +	find_p2p_ie = true; + +	RT_TRACE(COMP_FW, DBG_LOUD, ("action frame find P2P IE.\n")); +	/*to find noa ie*/ +	while (ie + 1 < end) { +		noa_len = READEF2BYTE((__le16 *)&ie[1]); +		if (ie + 3 + ie[1] > end) +			return; + +		if (ie[0] == 12) { +			RT_TRACE(COMP_FW, DBG_LOUD, ("find NOA IE\n")); +			RT_PRINT_DATA(rtlpriv, COMP_FW, DBG_LOUD, "noa ie ", +				      ie, noa_len); +			find_p2p_ps_ie = true; +			if ((noa_len - 2) % 13 != 0) { +				RT_TRACE(COMP_FW, DBG_LOUD, +					 ("P2P notice of absence: invalid length%d\n", +					 noa_len)); +				return; +			} else { +				noa_num = (noa_len - 2) / 13; +			} +			noa_index = ie[3]; +			if (rtlpriv->psc.p2p_ps_info.p2p_ps_mode == +			    P2P_PS_NONE || +			    noa_index != p2pinfo->noa_index) { +				p2pinfo->noa_index = noa_index; +				p2pinfo->opp_ps = (ie[4] >> 7); +				p2pinfo->ctwindow = ie[4] & 0x7F; +				p2pinfo->noa_num = noa_num; +				index = 5; +				for (i = 0; i < noa_num; i++) { +					p2pinfo->noa_count_type[i] = +							READEF1BYTE(ie+index); +					index += 1; +					p2pinfo->noa_duration[i] = +						 READEF4BYTE((__le32 *)ie+index); +					index += 4; +					p2pinfo->noa_interval[i] = +						 READEF4BYTE((__le32 *)ie+index); +					index += 4; +					p2pinfo->noa_start_time[i] = +						 READEF4BYTE((__le32 *)ie+index); +					index += 4; +				} + +				if (p2pinfo->opp_ps == 1) { +					p2pinfo->p2p_ps_mode = P2P_PS_CTWINDOW; +					/* Driver should wait LPS +					 * entering CTWindow */ +					if (rtlpriv->psc.b_fw_current_inpsmode) { +						rtl92e_p2p_ps_cmd(hw, +							       P2P_PS_ENABLE); +					} +				} else if (p2pinfo->noa_num > 0) { +					p2pinfo->p2p_ps_mode = P2P_PS_NOA; +					rtl92e_p2p_ps_cmd(hw, P2P_PS_ENABLE); +				} else if (p2pinfo->p2p_ps_mode > P2P_PS_NONE) { +					rtl92e_p2p_ps_cmd(hw, P2P_PS_DISABLE); +				} +			} + +		break; +		} +		ie += 3 + noa_len; +	} +} + +void rtl92e_p2p_ps_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_ps_ctl *rtlps = rtl_psc(rtl_priv(hw)); +	struct rtl_p2p_ps_info  *p2pinfo = &(rtlpriv->psc.p2p_ps_info); + +	RT_TRACE(COMP_FW, DBG_LOUD, ("p2p state %x\n", p2p_ps_state)); +	switch (p2p_ps_state) { +	case P2P_PS_DISABLE: +		p2pinfo->p2p_ps_state = p2p_ps_state; +		rtlpriv->cfg->ops->set_hw_reg(hw, +					   HW_VAR_H2C_FW_P2P_PS_OFFLOAD, +					   (u8 *)(&p2p_ps_state)); + +		p2pinfo->noa_index = 0; +		p2pinfo->ctwindow = 0; +		p2pinfo->opp_ps = 0; +		p2pinfo->noa_num = 0; +		p2pinfo->p2p_ps_mode = P2P_PS_NONE; +		if (rtlps->b_fw_current_inpsmode) { +			if (rtlps->smart_ps == 0) { +				rtlps->smart_ps = 2; +				rtlpriv->cfg->ops->set_hw_reg(hw, +					    HW_VAR_H2C_FW_PWRMODE, +					    (u8 *)(&rtlps->pwr_mode)); +			} +		} +		break; +	case P2P_PS_ENABLE: +		if (p2pinfo->p2p_ps_mode > P2P_PS_NONE) { +			p2pinfo->p2p_ps_state = p2p_ps_state; + +			if (p2pinfo->ctwindow > 0) { +				if (rtlps->smart_ps != 0) { +					rtlps->smart_ps = 0; +					rtlpriv->cfg->ops->set_hw_reg( +					    hw, HW_VAR_H2C_FW_PWRMODE, +					    (u8 *)(&rtlps->pwr_mode)); +				} +			} +			rtlpriv->cfg->ops->set_hw_reg(hw, +						HW_VAR_H2C_FW_P2P_PS_OFFLOAD, +						(u8 *)(&p2p_ps_state)); +			} +			break; +	case P2P_PS_SCAN: +	case P2P_PS_SCAN_DONE: +	case P2P_PS_ALLSTASLEEP: +		if (p2pinfo->p2p_ps_mode > P2P_PS_NONE) { +			p2pinfo->p2p_ps_state = p2p_ps_state; +			rtlpriv->cfg->ops->set_hw_reg(hw, +						HW_VAR_H2C_FW_P2P_PS_OFFLOAD, +						(u8 *)(&p2p_ps_state)); +		} +		break; +	default: +		break; +	} +	RT_TRACE(COMP_FW, DBG_LOUD, (" ctwindow %x oppps %x\n", +				     p2pinfo->ctwindow , p2pinfo->opp_ps)); +	RT_TRACE(COMP_FW, DBG_LOUD, +		 ("count %x duration %x index %x interval %x start time %x noa num %x\n", +		 p2pinfo->noa_count_type[0], +		 p2pinfo->noa_duration[0], +		 p2pinfo->noa_index, +		 p2pinfo->noa_interval[0], +		 p2pinfo->noa_start_time[0], +		 p2pinfo->noa_num)); +	RT_TRACE(COMP_FW, DBG_LOUD, ("end\n")); +} + +void rtl92e_p2p_info(struct ieee80211_hw *hw, void *data, unsigned int len) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +	struct ieee80211_hdr *hdr = (void *)data; + +	if (!mac->p2p) +		return; +	if (mac->link_state != MAC80211_LINKED) +		return; +	/* min. beacon length + FCS_LEN */ +	if (len <= 40 + FCS_LEN) +		return; + +	/* and only beacons from the associated BSSID, please */ +	if (!ether_addr_equal(hdr->addr3, rtlpriv->mac80211.bssid)) +		return; + +	/* check if this really is a beacon */ +	if (!(ieee80211_is_beacon(hdr->frame_control) || +	      ieee80211_is_probe_resp(hdr->frame_control) || +	      ieee80211_is_action(hdr->frame_control))) +		return; + +	if (ieee80211_is_action(hdr->frame_control)) +		rtl_p2p_action_ie(hw , data , len - FCS_LEN); +	else +		rtl_p2p_noa_ie(hw , data , len - FCS_LEN); +} diff --git a/drivers/staging/rtl8192ee/ps.h b/drivers/staging/rtl8192ee/ps.h new file mode 100644 index 00000000000..1533661a2f4 --- /dev/null +++ b/drivers/staging/rtl8192ee/ps.h @@ -0,0 +1,52 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010  Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __REALTEK_RTL_PCI_PS_H__ +#define __REALTEK_RTL_PCI_PS_H__ + +#define MAX_SW_LPS_SLEEP_INTV	5 + +bool stg_rtl_ps_set_rf_state(struct ieee80211_hw *hw, +			     enum rf_pwrstate state_toset, u32 changesource, +			     bool protect_or_not); +bool stg_rtl_ps_enable_nic(struct ieee80211_hw *hw); +bool stg_rtl_ps_disable_nic(struct ieee80211_hw *hw); +void rtl92e_ips_nic_off(struct ieee80211_hw *hw); +void rtl92e_ips_nic_on(struct ieee80211_hw *hw); +void rtl92e_ips_nic_off_wq_callback(void *data); +void rtl92e_lps_enter(struct ieee80211_hw *hw); +void rtl92e_lps_leave(struct ieee80211_hw *hw); + +void rtl_lps_set_psmode(struct ieee80211_hw *hw, u8 rt_psmode); + +void rtl92e_swlps_beacon(struct ieee80211_hw *hw, void *data, unsigned int len); +void rtl92e_swlps_wq_callback(void *data); +void rtl92e_swlps_rfon_wq_callback(void *data); +void rtl92e_swlps_rf_awake(struct ieee80211_hw *hw); +void rtl92e_swlps_rf_sleep(struct ieee80211_hw *hw); +void rtl92e_p2p_ps_cmd(struct ieee80211_hw *hw , u8 p2p_ps_state); +void rtl92e_p2p_info(struct ieee80211_hw *hw, void *data, unsigned int len); + +#endif diff --git a/drivers/staging/rtl8192ee/rc.c b/drivers/staging/rtl8192ee/rc.c new file mode 100644 index 00000000000..c4c34ddcf8c --- /dev/null +++ b/drivers/staging/rtl8192ee/rc.c @@ -0,0 +1,288 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010  Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#include "wifi.h" +#include "base.h" +#include "rc.h" + +/* + *Finds the highest rate index we can use + *if skb is special data like DHCP/EAPOL, we set should + *it to lowest rate CCK_1M, otherwise we set rate to + *highest rate based on wireless mode used for iwconfig + *show Tx rate. + */ +static u8 _rtl_rc_get_highest_rix(struct rtl_priv *rtlpriv, +				  struct ieee80211_sta *sta, +				  struct sk_buff *skb, bool not_data) +{ +	struct rtl_hal *rtlhal = rtl_hal(rtlpriv); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	struct rtl_sta_info *sta_entry = NULL; +	u8 wireless_mode = 0; + +	/* +	 *this rate is no use for true rate, firmware +	 *will control rate at all it just used for +	 *1.show in iwconfig in B/G mode +	 *2.in stg_rtl_get_tcb_desc when we check rate is +	 *      1M we will not use FW rate but user rate. +	 */ + +	if (sta) { +		sta_entry = (struct rtl_sta_info *)sta->drv_priv; +		wireless_mode = sta_entry->wireless_mode; +	} + +	if (rtl92e_is_special_data(rtlpriv->mac80211.hw, skb, true) || +	    not_data) { +		return 0; +	} else { +		if (rtlhal->current_bandtype == BAND_ON_2_4G) { +			if (wireless_mode == WIRELESS_MODE_B) { +				return B_MODE_MAX_RIX; +			} else if (wireless_mode == WIRELESS_MODE_G) { +				return G_MODE_MAX_RIX; +			} else if (wireless_mode == WIRELESS_MODE_N_24G) { +				if (get_rf_type(rtlphy) != RF_2T2R) +					return N_MODE_MCS7_RIX; +				else +					return N_MODE_MCS15_RIX; +			} else if (wireless_mode == WIRELESS_MODE_AC_24G) { +				return AC_MODE_MCS9_RIX; +			} else { +				return 0; +			} +		} else { +			if (wireless_mode == WIRELESS_MODE_A) { +				return A_MODE_MAX_RIX; +			} else if (wireless_mode == WIRELESS_MODE_N_5G) { +				if (get_rf_type(rtlphy) != RF_2T2R) +					return N_MODE_MCS7_RIX; +				else +					return N_MODE_MCS15_RIX; +			} else if (wireless_mode == WIRELESS_MODE_AC_5G) { +				return AC_MODE_MCS9_RIX; +			} else { +				return 0; +			} +		} +	} +} + +static void _rtl_rc_rate_set_series(struct rtl_priv *rtlpriv, +				    struct ieee80211_sta *sta, +				    struct ieee80211_tx_rate *rate, +				    struct ieee80211_tx_rate_control *txrc, +				    u8 tries, char rix, int rtsctsenable, +				    bool not_data) +{ +	struct rtl_mac *mac = rtl_mac(rtlpriv); +	u8 sgi_20 = 0, sgi_40 = 0, sgi_80 = 0; + +	if (sta) { +		sgi_20 = sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20; +		sgi_40 = sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40; +		sgi_80 = sta->vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_80; +	} +	rate->count = tries; +	rate->idx = rix >= 0x00 ? rix : 0x00; + +	if (!not_data) { +		if (txrc->short_preamble) +			rate->flags |= IEEE80211_TX_RC_USE_SHORT_PREAMBLE; +		if (mac->opmode == NL80211_IFTYPE_AP || +		    mac->opmode == NL80211_IFTYPE_ADHOC) { +			if (sta && (sta->ht_cap.cap & +				    IEEE80211_HT_CAP_SUP_WIDTH_20_40)) +				rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; +			if (sta && (sta->vht_cap.vht_supported)) +				rate->flags |= IEEE80211_TX_RC_80_MHZ_WIDTH; +		} else { +			if (mac->bw_40) +				rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; +			if (mac->bw_80) +				rate->flags |= IEEE80211_TX_RC_80_MHZ_WIDTH; +		} + +		if (sgi_20 || sgi_40 || sgi_80) +			rate->flags |= IEEE80211_TX_RC_SHORT_GI; +		if (sta && sta->ht_cap.ht_supported) +			rate->flags |= IEEE80211_TX_RC_MCS; +		if (sta && sta->vht_cap.vht_supported) +			rate->flags |= IEEE80211_TX_RC_VHT_MCS; +	} +} + +static void rtl_get_rate(void *ppriv, struct ieee80211_sta *sta, +			 void *priv_sta, +			 struct ieee80211_tx_rate_control *txrc) +{ +	struct rtl_priv *rtlpriv = ppriv; +	struct sk_buff *skb = txrc->skb; +	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); +	struct ieee80211_tx_rate *rates = tx_info->control.rates; +	__le16 fc = rtl_get_fc(skb); +	u8 try_per_rate, i, rix; +	bool not_data = !ieee80211_is_data(fc); + +	if (rate_control_send_low(sta, priv_sta, txrc)) +		return; + +	rix = _rtl_rc_get_highest_rix(rtlpriv, sta, skb, not_data); +	try_per_rate = 1; +	_rtl_rc_rate_set_series(rtlpriv, sta, &rates[0], txrc, +				try_per_rate, rix, 1, not_data); + +	if (!not_data) { +		for (i = 1; i < 4; i++) +			_rtl_rc_rate_set_series(rtlpriv, sta, &rates[i], +						txrc, i, (rix - i), 1, +						not_data); +	} +} + +static bool _rtl_tx_aggr_check(struct rtl_priv *rtlpriv, +			       struct rtl_sta_info *sta_entry, u16 tid) +{ +	struct rtl_mac *mac = rtl_mac(rtlpriv); + +	if (mac->act_scanning) +		return false; + +	if (mac->opmode == NL80211_IFTYPE_STATION && +	    mac->cnt_after_linked < 3) +		return false; + +	if (sta_entry->tids[tid].agg.agg_state == RTL_AGG_STOP) +		return true; + +	return false; +} + +/*mac80211 Rate Control callbacks*/ +static void rtl_tx_status(void *ppriv, +			  struct ieee80211_supported_band *sband, +			  struct ieee80211_sta *sta, void *priv_sta, +			  struct sk_buff *skb) +{ +	struct rtl_priv *rtlpriv = ppriv; +	struct rtl_mac *mac = rtl_mac(rtlpriv); +	struct ieee80211_hdr *hdr = rtl_get_hdr(skb); +	__le16 fc = rtl_get_fc(skb); +	struct rtl_sta_info *sta_entry; + +	if (!priv_sta || !ieee80211_is_data(fc)) +		return; + +	if (rtl92e_is_special_data(mac->hw, skb, true)) +		return; + +	if (is_multicast_ether_addr(ieee80211_get_DA(hdr)) || +	    is_broadcast_ether_addr(ieee80211_get_DA(hdr))) +		return; + +	if (sta) { +		/* Check if aggregation has to be enabled for this tid */ +		sta_entry = (struct rtl_sta_info *)sta->drv_priv; +		if ((sta->ht_cap.ht_supported) && +		    !(skb->protocol == cpu_to_be16(ETH_P_PAE))) { +			if (ieee80211_is_data_qos(fc)) { +				u8 tid = rtl_get_tid(skb); +				if (_rtl_tx_aggr_check(rtlpriv, sta_entry, +						       tid)) { +					sta_entry->tids[tid].agg.agg_state = +						RTL_AGG_PROGRESS; +					ieee80211_start_tx_ba_session(sta, tid, +								      5000); +				} +			} +		} +	} +} + +static void rtl_rate_init(void *ppriv, +			  struct ieee80211_supported_band *sband, +			  struct cfg80211_chan_def *chandef, +			  struct ieee80211_sta *sta, void *priv_sta) +{ +} + +static void *rtl_rate_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	return rtlpriv; +} + +static void rtl_rate_free(void *rtlpriv) +{ +	return; +} + +static void *rtl_rate_alloc_sta(void *ppriv, +				struct ieee80211_sta *sta, gfp_t gfp) +{ +	struct rtl_priv *rtlpriv = ppriv; +	struct rtl_rate_priv *rate_priv; + +	rate_priv = kzalloc(sizeof(*rate_priv), gfp); +	if (!rate_priv) { +		RT_TRACE(COMP_ERR, DBG_EMERG, +			 ("Unable to allocate private rc structure\n")); +		return NULL; +	} + +	rtlpriv->rate_priv = rate_priv; + +	return rate_priv; +} + +static void rtl_rate_free_sta(void *rtlpriv, +			      struct ieee80211_sta *sta, void *priv_sta) +{ +	struct rtl_rate_priv *rate_priv = priv_sta; +	kfree(rate_priv); +} + +static struct rate_control_ops rtl_rate_ops = { +	.name = "rtl_rc_92e", +	.alloc = rtl_rate_alloc, +	.free = rtl_rate_free, +	.alloc_sta = rtl_rate_alloc_sta, +	.free_sta = rtl_rate_free_sta, +	.rate_init = rtl_rate_init, +	.tx_status = rtl_tx_status, +	.get_rate = rtl_get_rate, +}; + +int rtl92e_rate_control_register(void) +{ +	return ieee80211_rate_control_register(&rtl_rate_ops); +} + +void rtl92e_rate_control_unregister(void) +{ +	ieee80211_rate_control_unregister(&rtl_rate_ops); +} diff --git a/drivers/staging/rtl8192ee/rc.h b/drivers/staging/rtl8192ee/rc.h new file mode 100644 index 00000000000..928f570b4b8 --- /dev/null +++ b/drivers/staging/rtl8192ee/rc.h @@ -0,0 +1,47 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010  Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __RTL_RC_H__ +#define __RTL_RC_H__ + +#define B_MODE_MAX_RIX 3 +#define G_MODE_MAX_RIX 11 +#define A_MODE_MAX_RIX 7 + +/* in mac80211 mcs0-mcs15 is idx0-idx15*/ +#define N_MODE_MCS7_RIX 7 +#define N_MODE_MCS15_RIX 15 + +#define AC_MODE_MCS7_RIX 7 +#define AC_MODE_MCS8_RIX 8 +#define AC_MODE_MCS9_RIX 9 + +struct rtl_rate_priv { +	u8 ht_cap; +}; + +int rtl92e_rate_control_register(void); +void rtl92e_rate_control_unregister(void); +#endif diff --git a/drivers/staging/rtl8192ee/regd.c b/drivers/staging/rtl8192ee/regd.c new file mode 100644 index 00000000000..7272fae68ec --- /dev/null +++ b/drivers/staging/rtl8192ee/regd.c @@ -0,0 +1,448 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010  Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#include "wifi.h" +#include "regd.h" + +static struct country_code_to_enum_rd allcountries[] = { +	{COUNTRY_CODE_FCC, "US"}, +	{COUNTRY_CODE_IC, "US"}, +	{COUNTRY_CODE_ETSI, "EC"}, +	{COUNTRY_CODE_SPAIN, "EC"}, +	{COUNTRY_CODE_FRANCE, "EC"}, +	{COUNTRY_CODE_MKK, "JP"}, +	{COUNTRY_CODE_MKK1, "JP"}, +	{COUNTRY_CODE_ISRAEL, "EC"}, +	{COUNTRY_CODE_TELEC, "JP"}, +	{COUNTRY_CODE_MIC, "JP"}, +	{COUNTRY_CODE_GLOBAL_DOMAIN, "JP"}, +	{COUNTRY_CODE_WORLD_WIDE_13, "EC"}, +	{COUNTRY_CODE_TELEC_NETGEAR, "EC"}, +}; + +/* + *Only these channels all allow active + *scan on all world regulatory domains + */ +#define RTL819x_2GHZ_CH01_11	\ +	REG_RULE(2412-10, 2462+10, 40, 0, 20, 0) + +/* + *We enable active scan on these a case + *by case basis by regulatory domain + */ +#define RTL819x_2GHZ_CH12_13	\ +	REG_RULE(2467-10, 2472+10, 40, 0, 20,\ +	NL80211_RRF_PASSIVE_SCAN) + +#define RTL819x_2GHZ_CH14	\ +	REG_RULE(2484-10, 2484+10, 40, 0, 20, \ +	NL80211_RRF_PASSIVE_SCAN | \ +	NL80211_RRF_NO_OFDM) + +/* 5G chan 36 - chan 64*/ +#define RTL819x_5GHZ_5150_5350	\ +	REG_RULE(5150-10, 5350+10, 80, 0, 30, \ +	NL80211_RRF_PASSIVE_SCAN | \ +	NL80211_RRF_NO_IBSS) + +/* 5G chan 100 - chan 165*/ +#define RTL819x_5GHZ_5470_5850	\ +	REG_RULE(5470-10, 5850+10, 80, 0, 30, \ +	NL80211_RRF_PASSIVE_SCAN | \ +	NL80211_RRF_NO_IBSS) + +/* 5G chan 149 - chan 165*/ +#define RTL819x_5GHZ_5725_5850	\ +	REG_RULE(5725-10, 5850+10, 80, 0, 30, \ +	NL80211_RRF_PASSIVE_SCAN | \ +	NL80211_RRF_NO_IBSS) + +#define RTL819x_5GHZ_ALL	\ +	(RTL819x_5GHZ_5150_5350, RTL819x_5GHZ_5470_5850) + +static const struct ieee80211_regdomain rtl_regdom_11 = { +	.n_reg_rules = 1, +	.alpha2 = "99", +	.reg_rules = { +		      RTL819x_2GHZ_CH01_11, +		      } +}; + +static const struct ieee80211_regdomain rtl_regdom_12_13 = { +	.n_reg_rules = 2, +	.alpha2 = "99", +	.reg_rules = { +		      RTL819x_2GHZ_CH01_11, +			  RTL819x_2GHZ_CH12_13, +		      } +}; + +static const struct ieee80211_regdomain rtl_regdom_no_midband = { +	.n_reg_rules = 3, +	.alpha2 = "99", +	.reg_rules = { +		      RTL819x_2GHZ_CH01_11, +			  RTL819x_5GHZ_5150_5350, +			  RTL819x_5GHZ_5725_5850, +		      } +}; + +static const struct ieee80211_regdomain rtl_regdom_60_64 = { +	.n_reg_rules = 3, +	.alpha2 = "99", +	.reg_rules = { +		      RTL819x_2GHZ_CH01_11, +			  RTL819x_2GHZ_CH12_13, +			  RTL819x_5GHZ_5725_5850, +		      } +}; + +static const struct ieee80211_regdomain rtl_regdom_14_60_64 = { +	.n_reg_rules = 4, +	.alpha2 = "99", +	.reg_rules = { +		      RTL819x_2GHZ_CH01_11, +			  RTL819x_2GHZ_CH12_13, +			  RTL819x_2GHZ_CH14, +			  RTL819x_5GHZ_5725_5850, +		      } +}; + +static const struct ieee80211_regdomain rtl_regdom_14 = { +	.n_reg_rules = 3, +	.alpha2 = "99", +	.reg_rules = { +		      RTL819x_2GHZ_CH01_11, +			  RTL819x_2GHZ_CH12_13, +			  RTL819x_2GHZ_CH14, +		      } +}; + +static bool _rtl_is_radar_freq(u16 center_freq) +{ +	return center_freq >= 5260 && center_freq <= 5700; +} + +static void _rtl_reg_apply_beaconing_flags(struct wiphy *wiphy, +					   enum nl80211_reg_initiator initiator) +{ +	enum ieee80211_band band; +	struct ieee80211_supported_band *sband; +	const struct ieee80211_reg_rule *reg_rule; +	struct ieee80211_channel *ch; +	unsigned int i; + +	for (band = 0; band < IEEE80211_NUM_BANDS; band++) { +		if (!wiphy->bands[band]) +			continue; + +		sband = wiphy->bands[band]; + +		for (i = 0; i < sband->n_channels; i++) { +			ch = &sband->channels[i]; +			if (_rtl_is_radar_freq(ch->center_freq) || +			    (ch->flags & IEEE80211_CHAN_RADAR)) +				continue; +			if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) { +				reg_rule = freq_reg_info(wiphy, +							 ch->center_freq); +				if (IS_ERR(reg_rule)) +					continue; + +				/* +				 *If 11d had a rule for this channel ensure +				 *we enable adhoc/beaconing if it allows us to +				 *use it. Note that we would have disabled it +				 *by applying our static world regdomain by +				 *default during init, prior to calling our +				 *regulatory_hint(). +				 */ + +				if (!(reg_rule->flags & NL80211_RRF_NO_IBSS)) +					ch->flags &= ~IEEE80211_CHAN_NO_IBSS; +				if (!(reg_rule->flags & +				      NL80211_RRF_PASSIVE_SCAN)) +					ch->flags &= +					    ~IEEE80211_CHAN_PASSIVE_SCAN; +			} else { +				if (ch->beacon_found) +					ch->flags &= ~(IEEE80211_CHAN_NO_IBSS | +						   IEEE80211_CHAN_PASSIVE_SCAN); +			} +		} +	} +} + +/* Allows active scan scan on Ch 12 and 13 */ +static void _rtl_reg_apply_active_scan_flags(struct wiphy *wiphy, +					     enum nl80211_reg_initiator +					     initiator) +{ +	struct ieee80211_supported_band *sband; +	struct ieee80211_channel *ch; +	const struct ieee80211_reg_rule *reg_rule; + +	if (!wiphy->bands[IEEE80211_BAND_2GHZ]) +		return; +	sband = wiphy->bands[IEEE80211_BAND_2GHZ]; + +	/* +	 *If no country IE has been received always enable active scan +	 *on these channels. This is only done for specific regulatory SKUs +	 */ +	if (initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE) { +		ch = &sband->channels[11];	/* CH 12 */ +		if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN) +			ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN; +		ch = &sband->channels[12];	/* CH 13 */ +		if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN) +			ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN; +		return; +	} + +	/* +	 *If a country IE has been recieved check its rule for this +	 *channel first before enabling active scan. The passive scan +	 *would have been enforced by the initial processing of our +	 *custom regulatory domain. +	 */ + +	ch = &sband->channels[11];	/* CH 12 */ +	reg_rule = freq_reg_info(wiphy, ch->center_freq); +	if (!IS_ERR(reg_rule)) { +		if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN)) +			if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN) +				ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN; +	} + +	ch = &sband->channels[12];	/* CH 13 */ +	reg_rule = freq_reg_info(wiphy, ch->center_freq); +	if (!IS_ERR(reg_rule)) { +		if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN)) +			if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN) +				ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN; +	} +} + +/* + *Always apply Radar/DFS rules on + *freq range 5260 MHz - 5700 MHz + */ +static void _rtl_reg_apply_radar_flags(struct wiphy *wiphy) +{ +	struct ieee80211_supported_band *sband; +	struct ieee80211_channel *ch; +	unsigned int i; + +	if (!wiphy->bands[IEEE80211_BAND_5GHZ]) +		return; + +	sband = wiphy->bands[IEEE80211_BAND_5GHZ]; + +	for (i = 0; i < sband->n_channels; i++) { +		ch = &sband->channels[i]; +		if (!_rtl_is_radar_freq(ch->center_freq)) +			continue; + +		/* +		 *We always enable radar detection/DFS on this +		 *frequency range. Additionally we also apply on +		 *this frequency range: +		 *- If STA mode does not yet have DFS supports disable +		 * active scanning +		 *- If adhoc mode does not support DFS yet then disable +		 * adhoc in the frequency. +		 *- If AP mode does not yet support radar detection/DFS +		 *do not allow AP mode +		 */ +		if (!(ch->flags & IEEE80211_CHAN_DISABLED)) +			ch->flags |= IEEE80211_CHAN_RADAR | +			    IEEE80211_CHAN_NO_IBSS | +			    IEEE80211_CHAN_PASSIVE_SCAN; +	} +} + +static void _rtl_reg_apply_world_flags(struct wiphy *wiphy, +				       enum nl80211_reg_initiator initiator, +				       struct rtl_regulatory *reg) +{ +	_rtl_reg_apply_beaconing_flags(wiphy, initiator); +	_rtl_reg_apply_active_scan_flags(wiphy, initiator); +	return; +} + +static void _rtl_dump_channel_map(struct wiphy *wiphy) +{ +	enum ieee80211_band band; +	struct ieee80211_supported_band *sband; +	struct ieee80211_channel *ch; +	unsigned int i; + +	for (band = 0; band < IEEE80211_NUM_BANDS; band++) { +		if (!wiphy->bands[band]) +			continue; +		sband = wiphy->bands[band]; +		for (i = 0; i < sband->n_channels; i++) +			ch = &sband->channels[i]; +	} +} + +static int _rtl92e_reg_notifier_apply(struct wiphy *wiphy, +				      struct regulatory_request *request, +				      struct rtl_regulatory *reg) +{ +	/* We always apply this */ +	_rtl_reg_apply_radar_flags(wiphy); + +	switch (request->initiator) { +	case NL80211_REGDOM_SET_BY_DRIVER: +	case NL80211_REGDOM_SET_BY_CORE: +	case NL80211_REGDOM_SET_BY_USER: +		break; +	case NL80211_REGDOM_SET_BY_COUNTRY_IE: +		_rtl_reg_apply_world_flags(wiphy, request->initiator, reg); +		break; +	} + +	_rtl_dump_channel_map(wiphy); + +	return 0; +} + +static const struct ieee80211_regdomain *_rtl_regdomain_select( +						struct rtl_regulatory *reg) +{ +	switch (reg->country_code) { +	case COUNTRY_CODE_FCC: +		return &rtl_regdom_no_midband; +	case COUNTRY_CODE_IC: +		return &rtl_regdom_11; +	case COUNTRY_CODE_ETSI: +	case COUNTRY_CODE_TELEC_NETGEAR: +		return &rtl_regdom_60_64; +	case COUNTRY_CODE_SPAIN: +	case COUNTRY_CODE_FRANCE: +	case COUNTRY_CODE_ISRAEL: +	case COUNTRY_CODE_WORLD_WIDE_13: +		return &rtl_regdom_12_13; +	case COUNTRY_CODE_MKK: +	case COUNTRY_CODE_MKK1: +	case COUNTRY_CODE_TELEC: +	case COUNTRY_CODE_MIC: +		return &rtl_regdom_14_60_64; +	case COUNTRY_CODE_GLOBAL_DOMAIN: +		return &rtl_regdom_14; +	default: +		return &rtl_regdom_no_midband; +	} +} + +static int _rtl92e_regd_init_wiphy(struct rtl_regulatory *reg, +				   struct wiphy *wiphy, +				   void (*reg_notifier)(struct wiphy *wiphy, +						        struct regulatory_request * +						        request)) +{ +	const struct ieee80211_regdomain *regd; + +	wiphy->reg_notifier = reg_notifier; + +	wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG; +	wiphy->regulatory_flags &= ~REGULATORY_STRICT_REG; +	wiphy->regulatory_flags &= ~REGULATORY_DISABLE_BEACON_HINTS; + +	regd = _rtl_regdomain_select(reg); +	wiphy_apply_custom_regulatory(wiphy, regd); +	_rtl_reg_apply_radar_flags(wiphy); +	_rtl_reg_apply_world_flags(wiphy, NL80211_REGDOM_SET_BY_DRIVER, reg); +	return 0; +} + +static struct country_code_to_enum_rd *_rtl_regd_find_country(u16 countrycode) +{ +	int i; + +	for (i = 0; i < ARRAY_SIZE(allcountries); i++) { +		if (allcountries[i].countrycode == countrycode) +			return &allcountries[i]; +	} +	return NULL; +} + +int rtl92e_regd_init(struct ieee80211_hw *hw, +		     void (*reg_notifier)(struct wiphy *wiphy, +					  struct regulatory_request *request)) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct wiphy *wiphy = hw->wiphy; +	struct country_code_to_enum_rd *country = NULL; + +	if (wiphy == NULL || &rtlpriv->regd == NULL) +		return -EINVAL; + +	/* init country_code from efuse channel plan */ +	rtlpriv->regd.country_code = rtlpriv->efuse.channel_plan; + +	RT_TRACE(COMP_REGD, DBG_TRACE, +		 (KERN_DEBUG "rtl: EEPROM regdomain: 0x%0x\n", +		  rtlpriv->regd.country_code)); + +	if (rtlpriv->regd.country_code >= COUNTRY_CODE_MAX) { +		RT_TRACE(COMP_REGD, DBG_DMESG, +			 ("rtl: EEPROM indicates invalid contry code world wide 13 should be used\n")); + +		rtlpriv->regd.country_code = COUNTRY_CODE_WORLD_WIDE_13; +	} + +	country = _rtl_regd_find_country(rtlpriv->regd.country_code); + +	if (country) { +		rtlpriv->regd.alpha2[0] = country->iso_name[0]; +		rtlpriv->regd.alpha2[1] = country->iso_name[1]; +	} else { +		rtlpriv->regd.alpha2[0] = '0'; +		rtlpriv->regd.alpha2[1] = '0'; +	} + +	RT_TRACE(COMP_REGD, DBG_TRACE, +		 (KERN_DEBUG "rtl: Country alpha2 being used: %c%c\n", +		  rtlpriv->regd.alpha2[0], rtlpriv->regd.alpha2[1])); + +	_rtl92e_regd_init_wiphy(&rtlpriv->regd, wiphy, reg_notifier); + +	return 0; +} + +void rtl92e_reg_notifier(struct wiphy *wiphy, +			 struct regulatory_request *request) +{ +	struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); +	struct rtl_priv *rtlpriv = rtl_priv(hw); + +	RT_TRACE(COMP_REGD, DBG_LOUD, ("\n")); + +	_rtl92e_reg_notifier_apply(wiphy, request, &rtlpriv->regd); +} diff --git a/drivers/staging/rtl8192ee/regd.h b/drivers/staging/rtl8192ee/regd.h new file mode 100644 index 00000000000..1f26f0e5261 --- /dev/null +++ b/drivers/staging/rtl8192ee/regd.h @@ -0,0 +1,63 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010  Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __RTL_REGD_H__ +#define __RTL_REGD_H__ + +/* for kernel 3.14 , both value are changed to IEEE80211_CHAN_NO_IR*/ +#define IEEE80211_CHAN_NO_IBSS IEEE80211_CHAN_NO_IR +#define IEEE80211_CHAN_PASSIVE_SCAN IEEE80211_CHAN_NO_IR + +struct country_code_to_enum_rd { +	u16 countrycode; +	const char *iso_name; +}; + +enum country_code_type_t { +	COUNTRY_CODE_FCC = 0, +	COUNTRY_CODE_IC = 1, +	COUNTRY_CODE_ETSI = 2, +	COUNTRY_CODE_SPAIN = 3, +	COUNTRY_CODE_FRANCE = 4, +	COUNTRY_CODE_MKK = 5, +	COUNTRY_CODE_MKK1 = 6, +	COUNTRY_CODE_ISRAEL = 7, +	COUNTRY_CODE_TELEC = 8, +	COUNTRY_CODE_MIC = 9, +	COUNTRY_CODE_GLOBAL_DOMAIN = 10, +	COUNTRY_CODE_WORLD_WIDE_13 = 11, +	COUNTRY_CODE_TELEC_NETGEAR = 12, + +	/*add new channel plan above this line */ +	COUNTRY_CODE_MAX +}; + +int rtl92e_regd_init(struct ieee80211_hw *hw, +		     void (*reg_notifier)(struct wiphy *wiphy, +					  struct regulatory_request *request)); +void rtl92e_reg_notifier(struct wiphy *wiphy, +			 struct regulatory_request *request); + +#endif diff --git a/drivers/staging/rtl8192ee/rtl8192ee/def.h b/drivers/staging/rtl8192ee/rtl8192ee/def.h new file mode 100644 index 00000000000..7566c1e8bae --- /dev/null +++ b/drivers/staging/rtl8192ee/rtl8192ee/def.h @@ -0,0 +1,106 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010  Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __RTL92E_DEF_H__ +#define __RTL92E_DEF_H__ + +#define RX_DESC_NUM_92E					512 + +#define HAL_PRIME_CHNL_OFFSET_DONT_CARE			0 +#define HAL_PRIME_CHNL_OFFSET_LOWER			1 +#define HAL_PRIME_CHNL_OFFSET_UPPER			2 + +#define RX_MPDU_QUEUE					0 + +#define IS_HT_RATE(_rate)	\ +	(_rate >= DESC92C_RATEMCS0) +#define IS_CCK_RATE(_rate)	\ +	(_rate >= DESC92C_RATE1M && _rate <= DESC92C_RATE11M) +#define IS_OFDM_RATE(_rate)	\ +	(_rate >= DESC92C_RATE6M && _rate <= DESC92C_RATE54M) + + +enum version_8192e { +	VERSION_TEST_CHIP_2T2R_8192E = 0x0024, +	VERSION_NORMAL_CHIP_2T2R_8192E = 0x102C, +	VERSION_UNKNOWN = 0xFF, +}; + +enum rx_packet_type { +	NORMAL_RX, +	TX_REPORT1, +	TX_REPORT2, +	HIS_REPORT, +	C2H_PACKET, +}; + +enum rtl_desc_qsel { +	QSLT_BK = 0x2, +	QSLT_BE = 0x0, +	QSLT_VI = 0x5, +	QSLT_VO = 0x7, +	QSLT_BEACON = 0x10, +	QSLT_HIGH = 0x11, +	QSLT_MGNT = 0x12, +	QSLT_CMD = 0x13, +}; + +enum rtl_desc92c_rate { +	DESC92C_RATE1M = 0x00, +	DESC92C_RATE2M = 0x01, +	DESC92C_RATE5_5M = 0x02, +	DESC92C_RATE11M = 0x03, + +	DESC92C_RATE6M = 0x04, +	DESC92C_RATE9M = 0x05, +	DESC92C_RATE12M = 0x06, +	DESC92C_RATE18M = 0x07, +	DESC92C_RATE24M = 0x08, +	DESC92C_RATE36M = 0x09, +	DESC92C_RATE48M = 0x0a, +	DESC92C_RATE54M = 0x0b, + +	DESC92C_RATEMCS0 = 0x0c, +	DESC92C_RATEMCS1 = 0x0d, +	DESC92C_RATEMCS2 = 0x0e, +	DESC92C_RATEMCS3 = 0x0f, +	DESC92C_RATEMCS4 = 0x10, +	DESC92C_RATEMCS5 = 0x11, +	DESC92C_RATEMCS6 = 0x12, +	DESC92C_RATEMCS7 = 0x13, +	DESC92C_RATEMCS8 = 0x14, +	DESC92C_RATEMCS9 = 0x15, +	DESC92C_RATEMCS10 = 0x16, +	DESC92C_RATEMCS11 = 0x17, +	DESC92C_RATEMCS12 = 0x18, +	DESC92C_RATEMCS13 = 0x19, +	DESC92C_RATEMCS14 = 0x1a, +	DESC92C_RATEMCS15 = 0x1b, +}; +#endif diff --git a/drivers/staging/rtl8192ee/rtl8192ee/dm.c b/drivers/staging/rtl8192ee/rtl8192ee/dm.c new file mode 100644 index 00000000000..41c2d98e81d --- /dev/null +++ b/drivers/staging/rtl8192ee/rtl8192ee/dm.c @@ -0,0 +1,1258 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010  Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#include "../wifi.h" +#include "../base.h" +#include "../pci.h" +#include "reg.h" +#include "def.h" +#include "phy.h" +#include "dm.h" +#include "fw.h" +#include "trx.h" + +struct dig_t dm_dig; + +static const u32 ofdmswing_table[OFDM_TABLE_SIZE] = { +	0x7f8001fe,		/* 0, +6.0dB */ +	0x788001e2,		/* 1, +5.5dB */ +	0x71c001c7,		/* 2, +5.0dB */ +	0x6b8001ae,		/* 3, +4.5dB */ +	0x65400195,		/* 4, +4.0dB */ +	0x5fc0017f,		/* 5, +3.5dB */ +	0x5a400169,		/* 6, +3.0dB */ +	0x55400155,		/* 7, +2.5dB */ +	0x50800142,		/* 8, +2.0dB */ +	0x4c000130,		/* 9, +1.5dB */ +	0x47c0011f,		/* 10, +1.0dB */ +	0x43c0010f,		/* 11, +0.5dB */ +	0x40000100,		/* 12, +0dB */ +	0x3c8000f2,		/* 13, -0.5dB */ +	0x390000e4,		/* 14, -1.0dB */ +	0x35c000d7,		/* 15, -1.5dB */ +	0x32c000cb,		/* 16, -2.0dB */ +	0x300000c0,		/* 17, -2.5dB */ +	0x2d4000b5,		/* 18, -3.0dB */ +	0x2ac000ab,		/* 19, -3.5dB */ +	0x288000a2,		/* 20, -4.0dB */ +	0x26000098,		/* 21, -4.5dB */ +	0x24000090,		/* 22, -5.0dB */ +	0x22000088,		/* 23, -5.5dB */ +	0x20000080,		/* 24, -6.0dB */ +	0x1e400079,		/* 25, -6.5dB */ +	0x1c800072,		/* 26, -7.0dB */ +	0x1b00006c,		/* 27. -7.5dB */ +	0x19800066,		/* 28, -8.0dB */ +	0x18000060,		/* 29, -8.5dB */ +	0x16c0005b,		/* 30, -9.0dB */ +	0x15800056,		/* 31, -9.5dB */ +	0x14400051,		/* 32, -10.0dB */ +	0x1300004c,		/* 33, -10.5dB */ +	0x12000048,		/* 34, -11.0dB */ +	0x11000044,		/* 35, -11.5dB */ +	0x10000040,		/* 36, -12.0dB */ +	0x0f00003c,		/* 37, -12.5dB */ +	0x0e400039,		/* 38, -13.0dB */ +	0x0d800036,		/* 39, -13.5dB */ +	0x0cc00033,		/* 40, -14.0dB */ +	0x0c000030,		/* 41, -14.5dB */ +	0x0b40002d,		/* 42, -15.0dB */ +}; + +static const u8 cckswing_table_ch1ch13[CCK_TABLE_SIZE][8] = { +	{0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04}, /* 0, +0dB */ +	{0x33, 0x32, 0x2b, 0x23, 0x1a, 0x11, 0x08, 0x04}, /* 1, -0.5dB */ +	{0x30, 0x2f, 0x29, 0x21, 0x19, 0x10, 0x08, 0x03}, /* 2, -1.0dB */ +	{0x2d, 0x2d, 0x27, 0x1f, 0x18, 0x0f, 0x08, 0x03}, /* 3, -1.5dB */ +	{0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03}, /* 4, -2.0dB */ +	{0x28, 0x28, 0x22, 0x1c, 0x15, 0x0d, 0x07, 0x03}, /* 5, -2.5dB */ +	{0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03}, /* 6, -3.0dB */ +	{0x24, 0x23, 0x1f, 0x19, 0x13, 0x0c, 0x06, 0x03}, /* 7, -3.5dB */ +	{0x22, 0x21, 0x1d, 0x18, 0x11, 0x0b, 0x06, 0x02}, /* 8, -4.0dB */ +	{0x20, 0x20, 0x1b, 0x16, 0x11, 0x08, 0x05, 0x02}, /* 9, -4.5dB */ +	{0x1f, 0x1e, 0x1a, 0x15, 0x10, 0x0a, 0x05, 0x02}, /* 10, -5.0dB */ +	{0x1d, 0x1c, 0x18, 0x14, 0x0f, 0x0a, 0x05, 0x02}, /* 11, -5.5dB */ +	{0x1b, 0x1a, 0x17, 0x13, 0x0e, 0x09, 0x04, 0x02}, /* 12, -6.0dB */ +	{0x1a, 0x19, 0x16, 0x12, 0x0d, 0x09, 0x04, 0x02}, /* 13, -6.5dB */ +	{0x18, 0x17, 0x15, 0x11, 0x0c, 0x08, 0x04, 0x02}, /* 14, -7.0dB */ +	{0x17, 0x16, 0x13, 0x10, 0x0c, 0x08, 0x04, 0x02}, /* 15, -7.5dB */ +	{0x16, 0x15, 0x12, 0x0f, 0x0b, 0x07, 0x04, 0x01}, /* 16, -8.0dB */ +	{0x14, 0x14, 0x11, 0x0e, 0x0b, 0x07, 0x03, 0x02}, /* 17, -8.5dB */ +	{0x13, 0x13, 0x10, 0x0d, 0x0a, 0x06, 0x03, 0x01}, /* 18, -9.0dB */ +	{0x12, 0x12, 0x0f, 0x0c, 0x09, 0x06, 0x03, 0x01}, /* 19, -9.5dB */ +	{0x11, 0x11, 0x0f, 0x0c, 0x09, 0x06, 0x03, 0x01}, /* 20, -10.0dB */ +	{0x10, 0x10, 0x0e, 0x0b, 0x08, 0x05, 0x03, 0x01}, /* 21, -10.5dB */ +	{0x0f, 0x0f, 0x0d, 0x0b, 0x08, 0x05, 0x03, 0x01}, /* 22, -11.0dB */ +	{0x0e, 0x0e, 0x0c, 0x0a, 0x08, 0x05, 0x02, 0x01}, /* 23, -11.5dB */ +	{0x0d, 0x0d, 0x0c, 0x0a, 0x07, 0x05, 0x02, 0x01}, /* 24, -12.0dB */ +	{0x0d, 0x0c, 0x0b, 0x09, 0x07, 0x04, 0x02, 0x01}, /* 25, -12.5dB */ +	{0x0c, 0x0c, 0x0a, 0x09, 0x06, 0x04, 0x02, 0x01}, /* 26, -13.0dB */ +	{0x0b, 0x0b, 0x0a, 0x08, 0x06, 0x04, 0x02, 0x01}, /* 27, -13.5dB */ +	{0x0b, 0x0a, 0x09, 0x08, 0x06, 0x04, 0x02, 0x01}, /* 28, -14.0dB */ +	{0x0a, 0x0a, 0x09, 0x07, 0x05, 0x03, 0x02, 0x01}, /* 29, -14.5dB */ +	{0x0a, 0x09, 0x08, 0x07, 0x05, 0x03, 0x02, 0x01}, /* 30, -15.0dB */ +	{0x09, 0x09, 0x08, 0x06, 0x05, 0x03, 0x01, 0x01}, /* 31, -15.5dB */ +	{0x09, 0x08, 0x07, 0x06, 0x04, 0x03, 0x01, 0x01}  /* 32, -16.0dB */ +}; + +static const u8 cckswing_table_ch14[CCK_TABLE_SIZE][8] = { +	{0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00}, /* 0, +0dB */ +	{0x33, 0x32, 0x2b, 0x19, 0x00, 0x00, 0x00, 0x00}, /* 1, -0.5dB */ +	{0x30, 0x2f, 0x29, 0x18, 0x00, 0x00, 0x00, 0x00}, /* 2, -1.0dB */ +	{0x2d, 0x2d, 0x17, 0x17, 0x00, 0x00, 0x00, 0x00}, /* 3, -1.5dB */ +	{0x2b, 0x2a, 0x25, 0x15, 0x00, 0x00, 0x00, 0x00}, /* 4, -2.0dB */ +	{0x28, 0x28, 0x24, 0x14, 0x00, 0x00, 0x00, 0x00}, /* 5, -2.5dB */ +	{0x26, 0x25, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00}, /* 6, -3.0dB */ +	{0x24, 0x23, 0x1f, 0x12, 0x00, 0x00, 0x00, 0x00}, /* 7, -3.5dB */ +	{0x22, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x00, 0x00}, /* 8, -4.0dB */ +	{0x20, 0x20, 0x1b, 0x10, 0x00, 0x00, 0x00, 0x00}, /* 9, -4.5dB */ +	{0x1f, 0x1e, 0x1a, 0x0f, 0x00, 0x00, 0x00, 0x00}, /* 10, -5.0dB */ +	{0x1d, 0x1c, 0x18, 0x0e, 0x00, 0x00, 0x00, 0x00}, /* 11, -5.5dB */ +	{0x1b, 0x1a, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00}, /* 12, -6.0dB */ +	{0x1a, 0x19, 0x16, 0x0d, 0x00, 0x00, 0x00, 0x00}, /* 13, -6.5dB */ +	{0x18, 0x17, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00}, /* 14, -7.0dB */ +	{0x17, 0x16, 0x13, 0x0b, 0x00, 0x00, 0x00, 0x00}, /* 15, -7.5dB */ +	{0x16, 0x15, 0x12, 0x0b, 0x00, 0x00, 0x00, 0x00}, /* 16, -8.0dB */ +	{0x14, 0x14, 0x11, 0x0a, 0x00, 0x00, 0x00, 0x00}, /* 17, -8.5dB */ +	{0x13, 0x13, 0x10, 0x0a, 0x00, 0x00, 0x00, 0x00}, /* 18, -9.0dB */ +	{0x12, 0x12, 0x0f, 0x09, 0x00, 0x00, 0x00, 0x00}, /* 19, -9.5dB */ +	{0x11, 0x11, 0x0f, 0x09, 0x00, 0x00, 0x00, 0x00}, /* 20, -10.0dB */ +	{0x10, 0x10, 0x0e, 0x08, 0x00, 0x00, 0x00, 0x00}, /* 21, -10.5dB */ +	{0x0f, 0x0f, 0x0d, 0x08, 0x00, 0x00, 0x00, 0x00}, /* 22, -11.0dB */ +	{0x0e, 0x0e, 0x0c, 0x07, 0x00, 0x00, 0x00, 0x00}, /* 23, -11.5dB */ +	{0x0d, 0x0d, 0x0c, 0x07, 0x00, 0x00, 0x00, 0x00}, /* 24, -12.0dB */ +	{0x0d, 0x0c, 0x0b, 0x06, 0x00, 0x00, 0x00, 0x00}, /* 25, -12.5dB */ +	{0x0c, 0x0c, 0x0a, 0x06, 0x00, 0x00, 0x00, 0x00}, /* 26, -13.0dB */ +	{0x0b, 0x0b, 0x0a, 0x06, 0x00, 0x00, 0x00, 0x00}, /* 27, -13.5dB */ +	{0x0b, 0x0a, 0x09, 0x05, 0x00, 0x00, 0x00, 0x00}, /* 28, -14.0dB */ +	{0x0a, 0x0a, 0x09, 0x05, 0x00, 0x00, 0x00, 0x00}, /* 29, -14.5dB */ +	{0x0a, 0x09, 0x08, 0x05, 0x00, 0x00, 0x00, 0x00}, /* 30, -15.0dB */ +	{0x09, 0x09, 0x08, 0x05, 0x00, 0x00, 0x00, 0x00}, /* 31, -15.5dB */ +	{0x09, 0x08, 0x07, 0x04, 0x00, 0x00, 0x00, 0x00}  /* 32, -16.0dB */ +}; + +static void rtl92ee_dm_diginit(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	dm_dig.cur_igvalue = rtl_get_bbreg(hw, DM_REG_IGI_A_11N, +						DM_BIT_IGI_11N); +	dm_dig.rssi_lowthresh = DM_DIG_THRESH_LOW; +	dm_dig.rssi_highthresh = DM_DIG_THRESH_HIGH; +	dm_dig.fa_lowthresh = DM_FALSEALARM_THRESH_LOW; +	dm_dig.fa_highthresh = DM_FALSEALARM_THRESH_HIGH; +	dm_dig.rx_gain_range_max = DM_DIG_MAX; +	dm_dig.rx_gain_range_min = DM_DIG_MIN; +	dm_dig.backoff_val = DM_DIG_BACKOFF_DEFAULT; +	dm_dig.backoff_val_range_max = DM_DIG_BACKOFF_MAX; +	dm_dig.backoff_val_range_min = DM_DIG_BACKOFF_MIN; +	dm_dig.pre_cck_cca_thres = 0xff; +	dm_dig.cur_cck_cca_thres = 0x83; +	dm_dig.forbidden_igi = DM_DIG_MIN; +	dm_dig.large_fa_hit = 0; +	dm_dig.recover_cnt = 0; +	dm_dig.dig_dynamic_min_0 = DM_DIG_MIN; +	dm_dig.dig_dynamic_min_1 = DM_DIG_MIN; +	dm_dig.b_media_connect_0 = false; +	dm_dig.b_media_connect_1 = false; +	rtlpriv->dm.b_dm_initialgain_enable = true; +	dm_dig.bt30_cur_igi = 0x32; +} + +static void rtl92ee_dm_false_alarm_counter_statistics(struct ieee80211_hw *hw) +{ +	u32 ret_value; +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct false_alarm_statistics *falsealm_cnt = &(rtlpriv->falsealm_cnt); + +	rtl_set_bbreg(hw, DM_REG_OFDM_FA_HOLDC_11N, BIT(31), 1); +	rtl_set_bbreg(hw, DM_REG_OFDM_FA_RSTD_11N, BIT(31), 1); + +	ret_value = rtl_get_bbreg(hw, DM_REG_OFDM_FA_TYPE1_11N, MASKDWORD); +	falsealm_cnt->cnt_fast_fsync_fail = (ret_value & 0xffff); +	falsealm_cnt->cnt_sb_search_fail = ((ret_value & 0xffff0000) >> 16); + +	ret_value = rtl_get_bbreg(hw, DM_REG_OFDM_FA_TYPE2_11N, MASKDWORD); +	falsealm_cnt->cnt_ofdm_cca = (ret_value & 0xffff); +	falsealm_cnt->cnt_parity_fail = ((ret_value & 0xffff0000) >> 16); + +	ret_value = rtl_get_bbreg(hw, DM_REG_OFDM_FA_TYPE3_11N, MASKDWORD); +	falsealm_cnt->cnt_rate_illegal = (ret_value & 0xffff); +	falsealm_cnt->cnt_crc8_fail = ((ret_value & 0xffff0000) >> 16); + +	ret_value = rtl_get_bbreg(hw, DM_REG_OFDM_FA_TYPE4_11N, MASKDWORD); +	falsealm_cnt->cnt_mcs_fail = (ret_value & 0xffff); + +	falsealm_cnt->cnt_ofdm_fail = falsealm_cnt->cnt_parity_fail + +				      falsealm_cnt->cnt_rate_illegal + +				      falsealm_cnt->cnt_crc8_fail + +				      falsealm_cnt->cnt_mcs_fail + +				      falsealm_cnt->cnt_fast_fsync_fail + +				      falsealm_cnt->cnt_sb_search_fail; + +	ret_value = rtl_get_bbreg(hw, DM_REG_SC_CNT_11N, MASKDWORD); +	falsealm_cnt->cnt_bw_lsc = (ret_value & 0xffff); +	falsealm_cnt->cnt_bw_usc = ((ret_value & 0xffff0000) >> 16); + +	rtl_set_bbreg(hw, DM_REG_CCK_FA_RST_11N, BIT(12), 1); +	rtl_set_bbreg(hw, DM_REG_CCK_FA_RST_11N, BIT(14), 1); + +	ret_value = rtl_get_bbreg(hw, DM_REG_CCK_FA_LSB_11N, MASKBYTE0); +	falsealm_cnt->cnt_cck_fail = ret_value; + +	ret_value = rtl_get_bbreg(hw, DM_REG_CCK_FA_MSB_11N, MASKBYTE3); +	falsealm_cnt->cnt_cck_fail += (ret_value & 0xff) << 8; + +	ret_value = rtl_get_bbreg(hw, DM_REG_CCK_CCA_CNT_11N, MASKDWORD); +	falsealm_cnt->cnt_cck_cca = ((ret_value & 0xff) << 8) | +				    ((ret_value & 0xFF00) >> 8); + +	falsealm_cnt->cnt_all = falsealm_cnt->cnt_fast_fsync_fail + +				falsealm_cnt->cnt_sb_search_fail + +				falsealm_cnt->cnt_parity_fail + +				falsealm_cnt->cnt_rate_illegal + +				falsealm_cnt->cnt_crc8_fail + +				falsealm_cnt->cnt_mcs_fail + +				falsealm_cnt->cnt_cck_fail; + +	falsealm_cnt->cnt_cca_all = falsealm_cnt->cnt_ofdm_cca + +				    falsealm_cnt->cnt_cck_cca; + +	/*reset false alarm counter registers*/ +	rtl_set_bbreg(hw, DM_REG_OFDM_FA_RSTC_11N, BIT(31), 1); +	rtl_set_bbreg(hw, DM_REG_OFDM_FA_RSTC_11N, BIT(31), 0); +	rtl_set_bbreg(hw, DM_REG_OFDM_FA_RSTD_11N, BIT(27), 1); +	rtl_set_bbreg(hw, DM_REG_OFDM_FA_RSTD_11N, BIT(27), 0); +	/*update ofdm counter*/ +	rtl_set_bbreg(hw, DM_REG_OFDM_FA_HOLDC_11N, BIT(31), 0); +	rtl_set_bbreg(hw, DM_REG_OFDM_FA_RSTD_11N, BIT(31), 0); +	/*reset CCK CCA counter*/ +	rtl_set_bbreg(hw, DM_REG_CCK_FA_RST_11N, BIT(13) | BIT(12), 0); +	rtl_set_bbreg(hw, DM_REG_CCK_FA_RST_11N, BIT(13) | BIT(12), 2); +	/*reset CCK FA counter*/ +	rtl_set_bbreg(hw, DM_REG_CCK_FA_RST_11N, BIT(15) | BIT(14), 0); +	rtl_set_bbreg(hw, DM_REG_CCK_FA_RST_11N, BIT(15) | BIT(14), 2); + + +	RT_TRACE(COMP_DIG, DBG_TRACE, +		 ("cnt_parity_fail = %d, cnt_rate_illegal = %d, " +		  "cnt_crc8_fail = %d, cnt_mcs_fail = %d\n", +		  falsealm_cnt->cnt_parity_fail, +		  falsealm_cnt->cnt_rate_illegal, +		  falsealm_cnt->cnt_crc8_fail, falsealm_cnt->cnt_mcs_fail)); + +	RT_TRACE(COMP_DIG, DBG_TRACE, +		 ("cnt_ofdm_fail = %x, cnt_cck_fail = %x, cnt_all = %x\n", +		  falsealm_cnt->cnt_ofdm_fail, +		  falsealm_cnt->cnt_cck_fail, falsealm_cnt->cnt_all)); +} + +static void rtl92ee_dm_cck_packet_detection_thresh(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u8 cur_cck_cca_thresh; +	if (rtlpriv->mac80211.link_state >= MAC80211_LINKED) { +		if (dm_dig.rssi_val_min > 25) { +			cur_cck_cca_thresh = 0xcd; +		} else if ((dm_dig.rssi_val_min <= 25) && +			   (dm_dig.rssi_val_min > 10)) { +			cur_cck_cca_thresh = 0x83; +		} else { +			if (rtlpriv->falsealm_cnt.cnt_cck_fail > 1000) +				cur_cck_cca_thresh = 0x83; +			else +				cur_cck_cca_thresh = 0x40; +		} +	} else { +		if (rtlpriv->falsealm_cnt.cnt_cck_fail > 1000) +			cur_cck_cca_thresh = 0x83; +		else +			cur_cck_cca_thresh = 0x40; +	} +	rtl92ee_dm_write_cck_cca_thres(hw, cur_cck_cca_thresh); +} + +static void rtl92ee_dm_dig(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +	u8 dig_dynamic_min , dig_maxofmin; +	bool bfirstconnect , bfirstdisconnect; +	u8 dm_dig_max, dm_dig_min; +	u8 current_igi = dm_dig.cur_igvalue; +	u8 offset; + +	/* AP, BT */ +	if (mac->act_scanning == true) +		return; + +	dig_dynamic_min = dm_dig.dig_dynamic_min_0; +	bfirstconnect = (mac->link_state >= MAC80211_LINKED) && +			(dm_dig.b_media_connect_0 == false); +	bfirstdisconnect = (mac->link_state < MAC80211_LINKED) && +			   (dm_dig.b_media_connect_0 == true); + +	dm_dig_max = 0x5a; +	dm_dig_min = DM_DIG_MIN; +	dig_maxofmin = DM_DIG_MAX_AP; + +	if (mac->link_state >= MAC80211_LINKED) { +		if ((dm_dig.rssi_val_min + 10) > dm_dig_max) +			dm_dig.rx_gain_range_max = dm_dig_max; +		else if ((dm_dig.rssi_val_min + 10) < dm_dig_min) +			dm_dig.rx_gain_range_max = dm_dig_min; +		else +			dm_dig.rx_gain_range_max = dm_dig.rssi_val_min + 10; + +		if (rtlpriv->dm.b_one_entry_only) { +			offset = 0; +			if (dm_dig.rssi_val_min - offset < dm_dig_min) +				dig_dynamic_min = dm_dig_min; +			else if (dm_dig.rssi_val_min - offset > +				 dig_maxofmin) +				dig_dynamic_min = dig_maxofmin; +			else +				dig_dynamic_min = dm_dig.rssi_val_min - offset; +		} else { +			dig_dynamic_min = dm_dig_min; +		} + +	} else { +		dm_dig.rx_gain_range_max = dm_dig_max; +		dig_dynamic_min = dm_dig_min; +		RT_TRACE(COMP_DIG, DBG_LOUD, ("no link\n")); +	} + +	if (rtlpriv->falsealm_cnt.cnt_all > 10000) { +		if (dm_dig.large_fa_hit != 3) +			dm_dig.large_fa_hit++; +		if (dm_dig.forbidden_igi < current_igi) { +			dm_dig.forbidden_igi = current_igi; +			dm_dig.large_fa_hit = 1; +		} + +		if (dm_dig.large_fa_hit >= 3) { +			if (dm_dig.forbidden_igi + 1 > dm_dig.rx_gain_range_max) +				dm_dig.rx_gain_range_min = +						dm_dig.rx_gain_range_max; +			else +				dm_dig.rx_gain_range_min = +						dm_dig.forbidden_igi + 1; +			dm_dig.recover_cnt = 3600; +		} +	} else { +		if (dm_dig.recover_cnt != 0) { +			dm_dig.recover_cnt--; +		} else { +			if (dm_dig.large_fa_hit < 3) { +				if ((dm_dig.forbidden_igi - 1) < +				    dig_dynamic_min) { +					dm_dig.forbidden_igi = dig_dynamic_min; +					dm_dig.rx_gain_range_min = +								dig_dynamic_min; +				} else { +					dm_dig.forbidden_igi--; +					dm_dig.rx_gain_range_min = +						dm_dig.forbidden_igi + 1; +				} +			} else { +				dm_dig.large_fa_hit = 0; +			} +		} +	} + +	if (rtlpriv->dm.dbginfo.num_qry_beacon_pkt < 5) +		dm_dig.rx_gain_range_min = dm_dig_min; + +	if (dm_dig.rx_gain_range_min > dm_dig.rx_gain_range_max) +		dm_dig.rx_gain_range_min = dm_dig.rx_gain_range_max; + +	if (mac->link_state >= MAC80211_LINKED) { +		if (bfirstconnect) { +			if (dm_dig.rssi_val_min <= dig_maxofmin) +				current_igi = dm_dig.rssi_val_min; +			else +				current_igi = dig_maxofmin; + +			dm_dig.large_fa_hit = 0; +		} else { +			if (rtlpriv->falsealm_cnt.cnt_all > DM_DIG_FA_TH2) +				current_igi += 4; +			else if (rtlpriv->falsealm_cnt.cnt_all > DM_DIG_FA_TH1) +				current_igi += 2; +			else if (rtlpriv->falsealm_cnt.cnt_all < DM_DIG_FA_TH0) +				current_igi -= 2; + +			if (rtlpriv->dm.dbginfo.num_qry_beacon_pkt < 5 && +			    rtlpriv->falsealm_cnt.cnt_all < DM_DIG_FA_TH1) +				current_igi = dm_dig.rx_gain_range_min; +		} +	} else { +		if (bfirstdisconnect) { +			current_igi = dm_dig.rx_gain_range_min; +		} else { +			if (rtlpriv->falsealm_cnt.cnt_all > 10000) +				current_igi += 4; +			else if (rtlpriv->falsealm_cnt.cnt_all > 8000) +				current_igi += 2; +			else if (rtlpriv->falsealm_cnt.cnt_all < 500) +				current_igi -= 2; +		} +	} + +	if (current_igi > dm_dig.rx_gain_range_max) +		current_igi = dm_dig.rx_gain_range_max; +	if (current_igi < dm_dig.rx_gain_range_min) +		current_igi = dm_dig.rx_gain_range_min; + +	rtl92ee_dm_write_dig(hw , current_igi); +	dm_dig.b_media_connect_0 = ((mac->link_state >= MAC80211_LINKED) ? +				   true : false); +	dm_dig.dig_dynamic_min_0 = dig_dynamic_min; +} + +void rtl92ee_dm_write_cck_cca_thres(struct ieee80211_hw *hw, u8 cur_thres) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	if (dm_dig.cur_cck_cca_thres != cur_thres) +		rtl_write_byte(rtlpriv, DM_REG_CCK_CCA_11N, cur_thres); + +	dm_dig.pre_cck_cca_thres = dm_dig.cur_cck_cca_thres; +	dm_dig.cur_cck_cca_thres = cur_thres; +} + +void rtl92ee_dm_write_dig(struct ieee80211_hw *hw, u8 current_igi) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	if (dm_dig.stop_dig) +		return; + +	if (dm_dig.cur_igvalue != current_igi) { +		rtl_set_bbreg(hw, ROFDM0_XAAGCCORE1, 0x7f, current_igi); +		if (rtlpriv->phy.rf_type != RF_1T1R) +			rtl_set_bbreg(hw, ROFDM0_XBAGCCORE1, 0x7f, current_igi); +	} +	dm_dig.pre_igvalue = dm_dig.cur_igvalue; +	dm_dig.cur_igvalue = current_igi; +} + +static void rtl92ee_rssi_dump_to_register(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	rtl_write_byte(rtlpriv, RA_RSSIDUMP, +		       rtlpriv->stats.rx_rssi_percentage[0]); +	rtl_write_byte(rtlpriv, RB_RSSIDUMP, +		       rtlpriv->stats.rx_rssi_percentage[1]); +	/*It seems the following values is not initialized. +	  *According to Windows code, +	  *these value will only be valid when JAGUAR chips*/ +	/* Rx EVM */ +	rtl_write_byte(rtlpriv, RS1_RXEVMDUMP, rtlpriv->stats.rx_evm_dbm[0]); +	rtl_write_byte(rtlpriv, RS2_RXEVMDUMP, rtlpriv->stats.rx_evm_dbm[1]); +	/* Rx SNR */ +	rtl_write_byte(rtlpriv, RA_RXSNRDUMP, +		       (u8)(rtlpriv->stats.rx_snr_db[0])); +	rtl_write_byte(rtlpriv, RB_RXSNRDUMP, +		       (u8)(rtlpriv->stats.rx_snr_db[1])); +	/* Rx Cfo_Short */ +	rtl_write_word(rtlpriv, RA_CFOSHORTDUMP, +		       rtlpriv->stats.rx_cfo_short[0]); +	rtl_write_word(rtlpriv, RB_CFOSHORTDUMP, +		       rtlpriv->stats.rx_cfo_short[1]); +	/* Rx Cfo_Tail */ +	rtl_write_word(rtlpriv, RA_CFOLONGDUMP, rtlpriv->stats.rx_cfo_tail[0]); +	rtl_write_word(rtlpriv, RB_CFOLONGDUMP, rtlpriv->stats.rx_cfo_tail[1]); +} + +static void rtl92ee_dm_find_minimum_rssi(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_dig *rtl_dm_dig = &(rtlpriv->dm.dm_digtable); +	struct rtl_mac *mac = rtl_mac(rtlpriv); + +	/* Determine the minimum RSSI  */ +	if ((mac->link_state < MAC80211_LINKED) && +	    (rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb == 0)) { +		rtl_dm_dig->min_undecorated_pwdb_for_dm = 0; +		RT_TRACE(COMP_BB_POWERSAVING, DBG_LOUD, +			 ("Not connected to any\n")); +	} +	if (mac->link_state >= MAC80211_LINKED) { +		if (mac->opmode == NL80211_IFTYPE_AP || +		    mac->opmode == NL80211_IFTYPE_ADHOC) { +			rtl_dm_dig->min_undecorated_pwdb_for_dm = +				rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb; +			RT_TRACE(COMP_BB_POWERSAVING, DBG_LOUD, +			      ("AP Client PWDB = 0x%lx\n", +			       rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb)); +		} else { +			rtl_dm_dig->min_undecorated_pwdb_for_dm = +			    rtlpriv->dm.undecorated_smoothed_pwdb; +			RT_TRACE(COMP_BB_POWERSAVING, DBG_LOUD, +				("STA Default Port PWDB = 0x%x\n", +				rtl_dm_dig->min_undecorated_pwdb_for_dm)); +		} +	} else { +		rtl_dm_dig->min_undecorated_pwdb_for_dm = +			rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb; +		RT_TRACE(COMP_BB_POWERSAVING, DBG_LOUD, +			("AP Ext Port or disconnet PWDB = 0x%x\n", +			rtl_dm_dig->min_undecorated_pwdb_for_dm)); +	} +	RT_TRACE(COMP_DIG, DBG_LOUD, ("MinUndecoratedPWDBForDM =%d\n", +		rtl_dm_dig->min_undecorated_pwdb_for_dm)); +} + +static void rtl92ee_dm_check_rssi_monitor(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_mac *mac = rtl_mac(rtlpriv); +	struct rtl_dm *dm = rtl_dm(rtlpriv); +	struct rtl_sta_info *drv_priv; +	u8 h2c[4] = { 0 }; +	long max = 0, min = 0xff; +	u8 i = 0; + +	if (mac->opmode == NL80211_IFTYPE_AP || +	    mac->opmode == NL80211_IFTYPE_ADHOC || +	    mac->opmode == NL80211_IFTYPE_MESH_POINT) { +		/* AP & ADHOC & MESH */ +		spin_lock_bh(&rtlpriv->locks.entry_list_lock); +		list_for_each_entry(drv_priv, &rtlpriv->entry_list, list) { +			struct rssi_sta *stat = &(drv_priv->rssi_stat); +			if (stat->undecorated_smoothed_pwdb < min) +				min = stat->undecorated_smoothed_pwdb; +			if (stat->undecorated_smoothed_pwdb > max) +				max = stat->undecorated_smoothed_pwdb; + +			h2c[3] = 0; +			h2c[2] = (u8) (dm->undecorated_smoothed_pwdb & 0xFF); +			h2c[1] = 0x20; +			h2c[0] = ++i; +			rtl92ee_fill_h2c_cmd(hw, H2C_92E_RSSI_REPORT, 4, h2c); +		} +		spin_unlock_bh(&rtlpriv->locks.entry_list_lock); + +		/* If associated entry is found */ +		if (max != 0) { +			dm->entry_max_undecoratedsmoothed_pwdb = max; +			RTPRINT(rtlpriv, FDM, DM_PWDB, +				"EntryMaxPWDB = 0x%lx(%ld)\n", max, max); +		} else { +			dm->entry_max_undecoratedsmoothed_pwdb = 0; +		} +		/* If associated entry is found */ +		if (min != 0xff) { +			dm->entry_min_undecoratedsmoothed_pwdb = min; +			RTPRINT(rtlpriv, FDM, DM_PWDB, +				"EntryMinPWDB = 0x%lx(%ld)\n", min, min); +		} else { +			dm->entry_min_undecoratedsmoothed_pwdb = 0; +		} +	} + +	/* Indicate Rx signal strength to FW. */ +	if (dm->b_useramask) { +		h2c[3] = 0; +		h2c[2] = (u8) (dm->undecorated_smoothed_pwdb & 0xFF); +		h2c[1] = 0x20; +		h2c[0] = 0; +		rtl92ee_fill_h2c_cmd(hw, H2C_92E_RSSI_REPORT, 4, h2c); +	} else { +		rtl_write_byte(rtlpriv, 0x4fe, dm->undecorated_smoothed_pwdb); +	} +	rtl92ee_rssi_dump_to_register(hw); +	rtl92ee_dm_find_minimum_rssi(hw); +	dm_dig.rssi_val_min = dm->dm_digtable.min_undecorated_pwdb_for_dm; +} + +static void rtl92ee_dm_init_primary_cca_check(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_hal *rtlhal = rtl_hal(rtlpriv); +	struct dynamic_primary_cca *primarycca = &(rtlpriv->primarycca); + +	rtlhal->rts_en = 0; +	primarycca->dup_rts_flag = 0; +	primarycca->intf_flag = 0; +	primarycca->intf_type = 0; +	primarycca->monitor_flag = 0; +	primarycca->ch_offset = 0; +	primarycca->mf_state = 0; +} + +static bool rtl92ee_dm_is_edca_turbo_disable(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); + +	if (rtlpriv->mac80211.mode == WIRELESS_MODE_B) +		return true; + +	return false; +} + +void rtl92ee_dm_init_edca_turbo(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); + +	rtlpriv->dm.bcurrent_turbo_edca = false; +	rtlpriv->dm.bis_cur_rdlstate = false; +	rtlpriv->dm.bis_any_nonbepkts = false; +} + +static void rtl92ee_dm_check_edca_turbo(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); + +	static u64 last_txok_cnt; +	static u64 last_rxok_cnt; +	u64 cur_txok_cnt = 0; +	u64 cur_rxok_cnt = 0; +	u32 edca_be_ul = 0x5ea42b; +	u32 edca_be_dl = 0x5ea42b; /*not sure*/ +	u32 edca_be = 0x5ea42b; +	bool b_is_cur_rdlstate; +	bool b_edca_turbo_on = false; + +	if (rtlpriv->dm.dbginfo.num_non_be_pkt > 0x100) +		rtlpriv->dm.bis_any_nonbepkts = true; +	rtlpriv->dm.dbginfo.num_non_be_pkt = 0; + +	cur_txok_cnt = rtlpriv->stats.txbytesunicast - last_txok_cnt; +	cur_rxok_cnt = rtlpriv->stats.rxbytesunicast - last_rxok_cnt; + +	/*b_bias_on_rx = false;*/ +	b_edca_turbo_on = ((!rtlpriv->dm.bis_any_nonbepkts) && +			   (!rtlpriv->dm.b_disable_framebursting)) ? +			  true : false; + +	if (rtl92ee_dm_is_edca_turbo_disable(hw)) +		goto dm_CheckEdcaTurbo_EXIT; + +	if (b_edca_turbo_on) { +		b_is_cur_rdlstate = (cur_rxok_cnt > cur_txok_cnt * 4) ? +				    true : false; + +		edca_be = b_is_cur_rdlstate ? edca_be_dl : edca_be_ul; +		rtl_write_dword(rtlpriv , REG_EDCA_BE_PARAM , edca_be); +		rtlpriv->dm.bis_cur_rdlstate = b_is_cur_rdlstate; +		rtlpriv->dm.bcurrent_turbo_edca = true; +	} else { +		if (rtlpriv->dm.bcurrent_turbo_edca) { +			u8 tmp = AC0_BE; +			rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_AC_PARAM, +						      (u8 *) (&tmp)); +		} +		rtlpriv->dm.bcurrent_turbo_edca = false; +	} + +dm_CheckEdcaTurbo_EXIT: +	rtlpriv->dm.bis_any_nonbepkts = false; +	last_txok_cnt = rtlpriv->stats.txbytesunicast; +	last_rxok_cnt = rtlpriv->stats.rxbytesunicast; +} + +static void rtl92ee_dm_dynamic_edcca(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u8 reg_c50 , reg_c58; +	bool b_fw_current_in_ps_mode = false; + +	rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_FW_PSMODE_STATUS, +				      (u8 *)(&b_fw_current_in_ps_mode)); +	if (b_fw_current_in_ps_mode) +		return; + +	reg_c50 = rtl_get_bbreg(hw, ROFDM0_XAAGCCORE1, MASKBYTE0); +	reg_c58 = rtl_get_bbreg(hw, ROFDM0_XBAGCCORE1, MASKBYTE0); + +	if (reg_c50 > 0x28 && reg_c58 > 0x28) { +		if (!rtlpriv->rtlhal.b_pre_edcca_enable) { +			rtl_write_byte(rtlpriv, ROFDM0_ECCATHRESHOLD, 0x03); +			rtl_write_byte(rtlpriv, ROFDM0_ECCATHRESHOLD + 2, 0x00); +			rtlpriv->rtlhal.b_pre_edcca_enable = true; +		} +	} else if (reg_c50 < 0x25 && reg_c58 < 0x25) { +		if (rtlpriv->rtlhal.b_pre_edcca_enable) { +			rtl_write_byte(rtlpriv, ROFDM0_ECCATHRESHOLD, 0x7f); +			rtl_write_byte(rtlpriv, ROFDM0_ECCATHRESHOLD + 2, 0x7f); +			rtlpriv->rtlhal.b_pre_edcca_enable = false; +		} +	} +} + +static void rtl92ee_dm_adaptivity(struct ieee80211_hw *hw) +{ +	rtl92ee_dm_dynamic_edcca(hw); +} + +static void rtl92ee_dm_write_dynamic_cca(struct ieee80211_hw *hw, u8 cur_mf_state) +{ +	struct dynamic_primary_cca *primarycca = &(rtl_priv(hw)->primarycca); + +	if (primarycca->mf_state != cur_mf_state) +		rtl_set_bbreg(hw, DM_REG_L1SBD_PD_CH_11N, BIT(8) | BIT(7), +			      cur_mf_state); + +	primarycca->mf_state = cur_mf_state; +} + +static void rtl92ee_dm_dynamic_primary_cca_ckeck(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct false_alarm_statistics *falsealm_cnt = &(rtlpriv->falsealm_cnt); +	struct dynamic_primary_cca *primarycca = &(rtlpriv->primarycca); +	bool is40mhz = false; +	u64 ofdm_cca, ofdm_fa, bw_usc_cnt, bw_lsc_cnt; +	u8 sec_ch_offset; +	u8 cur_mf_state; +	static u8 count_down = MONITOR_TIME; + +	ofdm_cca = falsealm_cnt->cnt_ofdm_cca; +	ofdm_fa = falsealm_cnt->cnt_ofdm_fail; +	bw_usc_cnt = falsealm_cnt->cnt_bw_usc; +	bw_lsc_cnt = falsealm_cnt->cnt_bw_lsc; +	is40mhz = rtlpriv->mac80211.bw_40; +	sec_ch_offset = rtlpriv->mac80211.cur_40_prime_sc; +	/* NIC: 2: sec is below,  1: sec is above */ + +	if (rtlpriv->mac80211.opmode == NL80211_IFTYPE_AP) { +		cur_mf_state = MF_USC_LSC; +		rtl92ee_dm_write_dynamic_cca(hw, cur_mf_state); +		return; +	} + +	if (rtlpriv->mac80211.link_state < MAC80211_LINKED) +		return; + +	if (is40mhz) +		return; + +	if (primarycca->pricca_flag == 0) { +		/* Primary channel is above +		 * NOTE: duplicate CTS can remove this condition*/ +		if (sec_ch_offset == 2) { +			if ((ofdm_cca > OFDMCCA_TH) && +			    (bw_lsc_cnt > (bw_usc_cnt + BW_IND_BIAS)) && +			    (ofdm_fa > (ofdm_cca >> 1))) { +				primarycca->intf_type = 1; +				primarycca->intf_flag = 1; +				cur_mf_state = MF_USC; +				rtl92ee_dm_write_dynamic_cca(hw, cur_mf_state); +				primarycca->pricca_flag = 1; +			} else if ((ofdm_cca > OFDMCCA_TH) && +				   (bw_lsc_cnt > (bw_usc_cnt + BW_IND_BIAS)) && +				   (ofdm_fa < (ofdm_cca >> 1))) { +				primarycca->intf_type = 2; +				primarycca->intf_flag = 1; +				cur_mf_state = MF_USC; +				rtl92ee_dm_write_dynamic_cca(hw, cur_mf_state); +				primarycca->pricca_flag = 1; +				primarycca->dup_rts_flag = 1; +				rtlpriv->rtlhal.rts_en = 1; +			} else { +				primarycca->intf_type = 0; +				primarycca->intf_flag = 0; +				cur_mf_state = MF_USC_LSC; +				rtl92ee_dm_write_dynamic_cca(hw, cur_mf_state); +				rtlpriv->rtlhal.rts_en = 0; +				primarycca->dup_rts_flag = 0; +			} +		} else if (sec_ch_offset == 1) { +			if ((ofdm_cca > OFDMCCA_TH) && +			    (bw_usc_cnt > (bw_lsc_cnt + BW_IND_BIAS)) && +			    (ofdm_fa > (ofdm_cca >> 1))) { +				primarycca->intf_type = 1; +				primarycca->intf_flag = 1; +				cur_mf_state = MF_LSC; +				rtl92ee_dm_write_dynamic_cca(hw, cur_mf_state); +				primarycca->pricca_flag = 1; +			} else if ((ofdm_cca > OFDMCCA_TH) && +				   (bw_usc_cnt > (bw_lsc_cnt + BW_IND_BIAS)) && +				   (ofdm_fa < (ofdm_cca >> 1))) { +				primarycca->intf_type = 2; +				primarycca->intf_flag = 1; +				cur_mf_state = MF_LSC; +				rtl92ee_dm_write_dynamic_cca(hw, cur_mf_state); +				primarycca->pricca_flag = 1; +				primarycca->dup_rts_flag = 1; +				rtlpriv->rtlhal.rts_en = 1; +			} else { +				primarycca->intf_type = 0; +				primarycca->intf_flag = 0; +				cur_mf_state = MF_USC_LSC; +				rtl92ee_dm_write_dynamic_cca(hw, cur_mf_state); +				rtlpriv->rtlhal.rts_en = 0; +				primarycca->dup_rts_flag = 0; +			} +		} +	} else {/* PrimaryCCA->PriCCA_flag == 1 */ +		count_down--; +		if (count_down == 0) { +			count_down = MONITOR_TIME; +			primarycca->pricca_flag = 0; +			cur_mf_state = MF_USC_LSC; +			/* default */ +			rtl92ee_dm_write_dynamic_cca(hw, cur_mf_state); +			rtlpriv->rtlhal.rts_en = 0; +			primarycca->dup_rts_flag = 0; +			primarycca->intf_type = 0; +			primarycca->intf_flag = 0; +		} +	} +} + +static void rtl92ee_dm_dynamic_atc_switch(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw)); +	u8 crystal_cap; +	u32 packet_count; +	int cfo_khz_a , cfo_khz_b , cfo_ave = 0, adjust_xtal = 0; +	int cfo_ave_diff; + +	if (rtlpriv->mac80211.link_state < MAC80211_LINKED) { +		if (rtldm->atc_status == ATC_STATUS_OFF) { +			rtl_set_bbreg(hw, ROFDM1_CFOTRACKING, BIT(11), +				      ATC_STATUS_ON); +			rtldm->atc_status = ATC_STATUS_ON; +		} +		/* Disable CFO tracking for BT */ +		if (rtlpriv->cfg->ops->get_btc_status()) { +			if (!rtlpriv->btcoexist.btc_ops->btc_is_bt_disabled(rtlpriv)) { +				RT_TRACE(COMP_BT_COEXIST, DBG_LOUD, +					("odm_DynamicATCSwitch(): " +					"Disable CFO tracking for BT!!\n")); +				return; +			} +		} +		/* Reset Crystal Cap */ +		if (rtldm->crystal_cap != rtlpriv->efuse.crystalcap) { +			rtldm->crystal_cap = rtlpriv->efuse.crystalcap; +			crystal_cap = rtldm->crystal_cap & 0x3f; +			rtl_set_bbreg(hw, REG_MAC_PHY_CTRL, 0xFFF000, +				      (crystal_cap | (crystal_cap << 6))); +		} +	} else { +		cfo_khz_a = (int)(rtldm->cfo_tail[0] * 3125) / 1280; +		cfo_khz_b = (int)(rtldm->cfo_tail[1] * 3125) / 1280; +		packet_count = rtldm->packet_count; + +		if (packet_count == rtldm->packet_count_pre) +			return; + +		rtldm->packet_count_pre = packet_count; + +		if (rtlpriv->phy.rf_type == RF_1T1R) +			cfo_ave = cfo_khz_a; +		else +			cfo_ave = (int)(cfo_khz_a + cfo_khz_b) >> 1; + +		cfo_ave_diff = (rtldm->cfo_ave_pre >= cfo_ave) ? +			       (rtldm->cfo_ave_pre - cfo_ave) : +			       (cfo_ave - rtldm->cfo_ave_pre); + +		if (cfo_ave_diff > 20 && rtldm->large_cfo_hit == 0) { +			rtldm->large_cfo_hit = 1; +			return; +		} else { +			rtldm->large_cfo_hit = 0; +		} + +		rtldm->cfo_ave_pre = cfo_ave; + +		if (cfo_ave >= -rtldm->cfo_threshold && +		    cfo_ave <= rtldm->cfo_threshold && rtldm->is_freeze == 0) { +			if (rtldm->cfo_threshold == CFO_THRESHOLD_XTAL) { +				rtldm->cfo_threshold = CFO_THRESHOLD_XTAL + 10; +				rtldm->is_freeze = 1; +			} else { +				rtldm->cfo_threshold = CFO_THRESHOLD_XTAL; +			} +		} + +		if (cfo_ave > rtldm->cfo_threshold && rtldm->crystal_cap < 0x3f) +			adjust_xtal = ((cfo_ave - CFO_THRESHOLD_XTAL) >> 2) + 1; +		else if ((cfo_ave < -rtlpriv->dm.cfo_threshold) && +			 rtlpriv->dm.crystal_cap > 0) +			adjust_xtal = ((cfo_ave + CFO_THRESHOLD_XTAL) >> 2) - 1; + +		if (adjust_xtal != 0) { +			rtldm->is_freeze = 0; +			rtldm->crystal_cap += adjust_xtal; + +			if (rtldm->crystal_cap > 0x3f) +				rtldm->crystal_cap = 0x3f; +			else if (rtldm->crystal_cap < 0) +				rtldm->crystal_cap = 0; + +			crystal_cap = rtldm->crystal_cap & 0x3f; +			rtl_set_bbreg(hw, REG_MAC_PHY_CTRL, 0xFFF000, +				      (crystal_cap | (crystal_cap << 6))); +		} + +		if (cfo_ave < CFO_THRESHOLD_ATC && +		    cfo_ave > -CFO_THRESHOLD_ATC) { +			if (rtldm->atc_status == ATC_STATUS_ON) { +				rtl_set_bbreg(hw, ROFDM1_CFOTRACKING, BIT(11), +					      ATC_STATUS_OFF); +				rtldm->atc_status = ATC_STATUS_OFF; +			} +		} else { +			if (rtldm->atc_status == ATC_STATUS_OFF) { +				rtl_set_bbreg(hw, ROFDM1_CFOTRACKING, BIT(11), +					      ATC_STATUS_ON); +				rtldm->atc_status = ATC_STATUS_ON; +			} +		} +	} +} + +static void rtl92ee_dm_init_txpower_tracking(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_dm *dm = rtl_dm(rtlpriv); +	u8 path; + +	dm->btxpower_tracking = true; +	dm->default_ofdm_index = 30; +	dm->default_cck_index = 20; + +	dm->bb_swing_idx_cck_base = dm->default_cck_index; +	dm->cck_index = dm->default_cck_index; + +	for (path = RF90_PATH_A; path < MAX_RF_PATH; path++) { +		dm->bb_swing_idx_ofdm_base[path] = dm->default_ofdm_index; +		dm->ofdm_index[path] = dm->default_ofdm_index; +		dm->delta_power_index[path] = 0; +		dm->delta_power_index_last[path] = 0; +		dm->power_index_offset[path] = 0; +	} +} + +void rtl92ee_dm_init_rate_adaptive_mask(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rate_adaptive *p_ra = &(rtlpriv->ra); + +	p_ra->ratr_state = DM_RATR_STA_INIT; +	p_ra->pre_ratr_state = DM_RATR_STA_INIT; + +	if (rtlpriv->dm.dm_type == DM_TYPE_BYDRIVER) +		rtlpriv->dm.b_useramask = true; +	else +		rtlpriv->dm.b_useramask = false; + +	p_ra->ldpc_thres = 35; +	p_ra->use_ldpc = false; +	p_ra->high_rssi_thresh_for_ra = 50; +	p_ra->low_rssi_thresh_for_ra = 20; + +} + +static bool _rtl92ee_dm_ra_state_check(struct ieee80211_hw *hw, +				      s32 rssi, u8 *ratr_state) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rate_adaptive *p_ra = &(rtlpriv->ra); +	const u8 go_up_gap = 5; +	u32 high_rssithresh_for_ra = p_ra->high_rssi_thresh_for_ra; +	u32 low_rssithresh_for_ra = p_ra->low_rssi_thresh_for_ra; +	u8 state; + +	/* Threshold Adjustment: +	 * when RSSI state trends to go up one or two levels, +	 * make sure RSSI is high enough. +	 * Here GoUpGap is added to solve +	 * the boundary's level alternation issue. +	 */ +	switch (*ratr_state) { +	case DM_RATR_STA_INIT: +	case DM_RATR_STA_HIGH: +			break; + +	case DM_RATR_STA_MIDDLE: +			high_rssithresh_for_ra += go_up_gap; +			break; + +	case DM_RATR_STA_LOW: +			high_rssithresh_for_ra += go_up_gap; +			low_rssithresh_for_ra += go_up_gap; +			break; + +	default: +			RT_TRACE(COMP_RATR, DBG_DMESG, +				("wrong rssi level setting %d !", *ratr_state)); +			break; +	} + +	/* Decide RATRState by RSSI. */ +	if (rssi > high_rssithresh_for_ra) +		state = DM_RATR_STA_HIGH; +	else if (rssi > low_rssithresh_for_ra) +		state = DM_RATR_STA_MIDDLE; +	else +		state = DM_RATR_STA_LOW; + +	if (*ratr_state != state) { +		*ratr_state = state; +		return true; +	} + +	return false; +} + +static void rtl92ee_dm_refresh_rate_adaptive_mask(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +	struct rate_adaptive *p_ra = &(rtlpriv->ra); +	struct ieee80211_sta *sta = NULL; + +	if (is_hal_stop(rtlhal)) { +		RT_TRACE(COMP_RATE, DBG_LOUD, +			 ("driver is going to unload\n")); +		return; +	} + +	if (!rtlpriv->dm.b_useramask) { +		RT_TRACE(COMP_RATE, DBG_LOUD, +			 ("driver does not control rate adaptive mask\n")); +		return; +	} + +	if (mac->link_state == MAC80211_LINKED && +		mac->opmode == NL80211_IFTYPE_STATION) { + +		if (rtlpriv->dm.undecorated_smoothed_pwdb < p_ra->ldpc_thres) { +			p_ra->use_ldpc = true; +			p_ra->lower_rts_rate = true; +		} else if (rtlpriv->dm.undecorated_smoothed_pwdb > +			   (p_ra->ldpc_thres - 5)) { +			p_ra->use_ldpc = false; +			p_ra->lower_rts_rate = false; +		} +		if (_rtl92ee_dm_ra_state_check(hw, +					rtlpriv->dm.undecorated_smoothed_pwdb, +					&(p_ra->ratr_state))) { + +			rcu_read_lock(); +			sta = rtl_find_sta(hw, mac->bssid); +			if (sta) +				rtlpriv->cfg->ops->update_rate_tbl(hw, sta, +							      p_ra->ratr_state); +			rcu_read_unlock(); + +			p_ra->pre_ratr_state = p_ra->ratr_state; +		} +	} +} + +static void rtl92ee_dm_init_dynamic_atc_switch(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); + +	rtlpriv->dm.crystal_cap = rtlpriv->efuse.crystalcap; + +	rtlpriv->dm.atc_status = rtl_get_bbreg(hw, ROFDM1_CFOTRACKING, BIT(11)); +	rtlpriv->dm.cfo_threshold = CFO_THRESHOLD_XTAL; +} + +void rtl92ee_dm_init(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); + +	rtlpriv->dm.dm_type = DM_TYPE_BYDRIVER; + +	rtl92ee_dm_diginit(hw); +	rtl92ee_dm_init_rate_adaptive_mask(hw); +	rtl92ee_dm_init_primary_cca_check(hw); +	rtl92ee_dm_init_edca_turbo(hw); +	rtl92ee_dm_init_txpower_tracking(hw); +	rtl92ee_dm_init_dynamic_atc_switch(hw); +} + +static void rtl92ee_dm_common_info_self_update(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u8 cnt = 0; +	struct rtl_sta_info *drv_priv; + +	rtlpriv->dm.b_one_entry_only = false; + +	if (rtlpriv->mac80211.opmode == NL80211_IFTYPE_STATION && +		rtlpriv->mac80211.link_state >= MAC80211_LINKED) { +		rtlpriv->dm.b_one_entry_only = true; +		return; +	} + +	if (rtlpriv->mac80211.opmode == NL80211_IFTYPE_AP || +	    rtlpriv->mac80211.opmode == NL80211_IFTYPE_ADHOC || +	    rtlpriv->mac80211.opmode == NL80211_IFTYPE_MESH_POINT) { +		spin_lock_bh(&rtlpriv->locks.entry_list_lock); +		list_for_each_entry(drv_priv, &rtlpriv->entry_list, list) { +			cnt++; +		} +		spin_unlock_bh(&rtlpriv->locks.entry_list_lock); + +		if (cnt == 1) +			rtlpriv->dm.b_one_entry_only = true; +	} +} + +void rtl92ee_dm_dynamic_arfb_select(struct ieee80211_hw *hw, +				    u8 rate, bool collision_state) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); + +	if (rate >= DESC92C_RATEMCS8  && rate <= DESC92C_RATEMCS12) { +		if (collision_state == 1) { +			if (rate == DESC92C_RATEMCS12) { +				rtl_write_dword(rtlpriv, REG_DARFRC, 0x0); +				rtl_write_dword(rtlpriv, REG_DARFRC + 4, +						0x07060501); +			} else if (rate == DESC92C_RATEMCS11) { +				rtl_write_dword(rtlpriv, REG_DARFRC, 0x0); +				rtl_write_dword(rtlpriv, REG_DARFRC + 4, +						0x07070605); +			} else if (rate == DESC92C_RATEMCS10) { +				rtl_write_dword(rtlpriv, REG_DARFRC, 0x0); +				rtl_write_dword(rtlpriv, REG_DARFRC + 4, +						0x08080706); +			} else if (rate == DESC92C_RATEMCS9) { +				rtl_write_dword(rtlpriv, REG_DARFRC, 0x0); +				rtl_write_dword(rtlpriv, REG_DARFRC + 4, +						0x08080707); +			} else { +				rtl_write_dword(rtlpriv, REG_DARFRC, 0x0); +				rtl_write_dword(rtlpriv, REG_DARFRC + 4, +						0x09090808); +			} +		} else {   /* collision_state == 0 */ +			if (rate == DESC92C_RATEMCS12) { +				rtl_write_dword(rtlpriv, REG_DARFRC, +						0x05010000); +				rtl_write_dword(rtlpriv, REG_DARFRC + 4, +						0x09080706); +			} else if (rate == DESC92C_RATEMCS11) { +				rtl_write_dword(rtlpriv, REG_DARFRC, +						0x06050000); +				rtl_write_dword(rtlpriv, REG_DARFRC + 4, +						0x09080807); +			} else if (rate == DESC92C_RATEMCS10) { +				rtl_write_dword(rtlpriv, REG_DARFRC, +						0x07060000); +				rtl_write_dword(rtlpriv, REG_DARFRC + 4, +						0x0a090908); +			} else if (rate == DESC92C_RATEMCS9) { +				rtl_write_dword(rtlpriv, REG_DARFRC, +						0x07070000); +				rtl_write_dword(rtlpriv, REG_DARFRC + 4, +						0x0a090808); +			} else { +				rtl_write_dword(rtlpriv, REG_DARFRC, +						0x08080000); +				rtl_write_dword(rtlpriv, REG_DARFRC + 4, +						0x0b0a0909); +			} +		} +	} else {  /* MCS13~MCS15,  1SS, G-mode */ +		if (collision_state == 1) { +			if (rate == DESC92C_RATEMCS15) { +				rtl_write_dword(rtlpriv, REG_DARFRC, +						0x00000000); +				rtl_write_dword(rtlpriv, REG_DARFRC + 4, +						0x05040302); +			} else if (rate == DESC92C_RATEMCS14) { +				rtl_write_dword(rtlpriv, REG_DARFRC, +						0x00000000); +				rtl_write_dword(rtlpriv, REG_DARFRC + 4, +						0x06050302); +			} else if (rate == DESC92C_RATEMCS13) { +				rtl_write_dword(rtlpriv, REG_DARFRC, +						0x00000000); +				rtl_write_dword(rtlpriv, REG_DARFRC + 4, +						0x07060502); +			} else { +				rtl_write_dword(rtlpriv, REG_DARFRC, +						0x00000000); +				rtl_write_dword(rtlpriv, REG_DARFRC + 4, +						0x06050402); +			} +		} else{   /* collision_state == 0 */ +			if (rate == DESC92C_RATEMCS15) { +				rtl_write_dword(rtlpriv, REG_DARFRC, +						0x03020000); +				rtl_write_dword(rtlpriv, REG_DARFRC + 4, +						0x07060504); +			} else if (rate == DESC92C_RATEMCS14) { +				rtl_write_dword(rtlpriv, REG_DARFRC, +						0x03020000); +				rtl_write_dword(rtlpriv, REG_DARFRC + 4, +						0x08070605); +			} else if (rate == DESC92C_RATEMCS13) { +				rtl_write_dword(rtlpriv, REG_DARFRC, +						0x05020000); +				rtl_write_dword(rtlpriv, REG_DARFRC + 4, +						0x09080706); +			} else { +				rtl_write_dword(rtlpriv, REG_DARFRC, +						0x04020000); +				rtl_write_dword(rtlpriv, REG_DARFRC + 4, +						0x08070605); +			} +		} +	} +} + +void rtl92ee_dm_watchdog(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); +	bool b_fw_current_inpsmode = false; +	bool b_fw_ps_awake = true; + +	rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_FW_PSMODE_STATUS, +				      (u8 *) (&b_fw_current_inpsmode)); +	rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_FWLPS_RF_ON, +				      (u8 *) (&b_fw_ps_awake)); +	if (ppsc->p2p_ps_info.p2p_ps_mode) +		b_fw_ps_awake = false; + +	if ((ppsc->rfpwr_state == ERFON) && +	    ((!b_fw_current_inpsmode) && b_fw_ps_awake) && +	    (!ppsc->rfchange_inprogress)) { +		rtl92ee_dm_common_info_self_update(hw); +		rtl92ee_dm_false_alarm_counter_statistics(hw); +		rtl92ee_dm_check_rssi_monitor(hw); +		rtl92ee_dm_dig(hw); +		rtl92ee_dm_adaptivity(hw); +		rtl92ee_dm_cck_packet_detection_thresh(hw); +		rtl92ee_dm_refresh_rate_adaptive_mask(hw); +		rtl92ee_dm_check_edca_turbo(hw); +		rtl92ee_dm_dynamic_atc_switch(hw); +		rtl92ee_dm_dynamic_primary_cca_ckeck(hw); +	} +} diff --git a/drivers/staging/rtl8192ee/rtl8192ee/dm.h b/drivers/staging/rtl8192ee/rtl8192ee/dm.h new file mode 100644 index 00000000000..30b8fa6d3f7 --- /dev/null +++ b/drivers/staging/rtl8192ee/rtl8192ee/dm.h @@ -0,0 +1,343 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010  Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef	__RTL92E_DM_H__ +#define __RTL92E_DM_H__ + +#define	OFDMCCA_TH				500 +#define	BW_IND_BIAS				500 +#define	MF_USC					2 +#define	MF_LSC					1 +#define	MF_USC_LSC				0 +#define	MONITOR_TIME				30 + +#define	MAIN_ANT				0 +#define	AUX_ANT					1 +#define	MAIN_ANT_CG_TRX				1 +#define	AUX_ANT_CG_TRX				0 +#define	MAIN_ANT_CGCS_RX			0 +#define	AUX_ANT_CGCS_RX				1 + +/*RF REG LIST*/ +#define	DM_REG_RF_MODE_11N			0x00 +#define	DM_REG_RF_0B_11N			0x0B +#define	DM_REG_CHNBW_11N			0x18 +#define	DM_REG_T_METER_11N			0x24 +#define	DM_REG_RF_25_11N			0x25 +#define	DM_REG_RF_26_11N			0x26 +#define	DM_REG_RF_27_11N			0x27 +#define	DM_REG_RF_2B_11N			0x2B +#define	DM_REG_RF_2C_11N			0x2C +#define	DM_REG_RXRF_A3_11N			0x3C +#define	DM_REG_T_METER_92D_11N			0x42 +#define	DM_REG_T_METER_92E_11N			0x42 + + + +/*BB REG LIST*/ +/*PAGE 8 */ +#define	DM_REG_BB_CTRL_11N			0x800 +#define	DM_REG_RF_PIN_11N			0x804 +#define	DM_REG_PSD_CTRL_11N			0x808 +#define	DM_REG_TX_ANT_CTRL_11N			0x80C +#define	DM_REG_BB_PWR_SAV5_11N			0x818 +#define	DM_REG_CCK_RPT_FORMAT_11N		0x824 +#define	DM_REG_RX_DEFUALT_A_11N			0x858 +#define	DM_REG_RX_DEFUALT_B_11N			0x85A +#define	DM_REG_BB_PWR_SAV3_11N			0x85C +#define	DM_REG_ANTSEL_CTRL_11N			0x860 +#define	DM_REG_RX_ANT_CTRL_11N			0x864 +#define	DM_REG_PIN_CTRL_11N			0x870 +#define	DM_REG_BB_PWR_SAV1_11N			0x874 +#define	DM_REG_ANTSEL_PATH_11N			0x878 +#define	DM_REG_BB_3WIRE_11N			0x88C +#define	DM_REG_SC_CNT_11N			0x8C4 +#define	DM_REG_PSD_DATA_11N			0x8B4 +/*PAGE 9*/ +#define	DM_REG_ANT_MAPPING1_11N			0x914 +#define	DM_REG_ANT_MAPPING2_11N			0x918 +/*PAGE A*/ +#define	DM_REG_CCK_ANTDIV_PARA1_11N		0xA00 +#define	DM_REG_CCK_CCA_11N			0xA0A +#define	DM_REG_CCK_ANTDIV_PARA2_11N		0xA0C +#define	DM_REG_CCK_ANTDIV_PARA3_11N		0xA10 +#define	DM_REG_CCK_ANTDIV_PARA4_11N		0xA14 +#define	DM_REG_CCK_FILTER_PARA1_11N		0xA22 +#define	DM_REG_CCK_FILTER_PARA2_11N		0xA23 +#define	DM_REG_CCK_FILTER_PARA3_11N		0xA24 +#define	DM_REG_CCK_FILTER_PARA4_11N		0xA25 +#define	DM_REG_CCK_FILTER_PARA5_11N		0xA26 +#define	DM_REG_CCK_FILTER_PARA6_11N		0xA27 +#define	DM_REG_CCK_FILTER_PARA7_11N		0xA28 +#define	DM_REG_CCK_FILTER_PARA8_11N		0xA29 +#define	DM_REG_CCK_FA_RST_11N			0xA2C +#define	DM_REG_CCK_FA_MSB_11N			0xA58 +#define	DM_REG_CCK_FA_LSB_11N			0xA5C +#define	DM_REG_CCK_CCA_CNT_11N			0xA60 +#define	DM_REG_BB_PWR_SAV4_11N			0xA74 +/*PAGE B */ +#define	DM_REG_LNA_SWITCH_11N			0xB2C +#define	DM_REG_PATH_SWITCH_11N			0xB30 +#define	DM_REG_RSSI_CTRL_11N			0xB38 +#define	DM_REG_CONFIG_ANTA_11N			0xB68 +#define	DM_REG_RSSI_BT_11N			0xB9C +/*PAGE C */ +#define	DM_REG_OFDM_FA_HOLDC_11N		0xC00 +#define	DM_REG_RX_PATH_11N			0xC04 +#define	DM_REG_TRMUX_11N			0xC08 +#define	DM_REG_OFDM_FA_RSTC_11N			0xC0C +#define	DM_REG_RXIQI_MATRIX_11N			0xC14 +#define	DM_REG_TXIQK_MATRIX_LSB1_11N		0xC4C +#define	DM_REG_IGI_A_11N			0xC50 +#define	DM_REG_ANTDIV_PARA2_11N			0xC54 +#define	DM_REG_IGI_B_11N			0xC58 +#define	DM_REG_ANTDIV_PARA3_11N			0xC5C +#define DM_REG_L1SBD_PD_CH_11N			0XC6C +#define	DM_REG_BB_PWR_SAV2_11N			0xC70 +#define	DM_REG_RX_OFF_11N			0xC7C +#define	DM_REG_TXIQK_MATRIXA_11N		0xC80 +#define	DM_REG_TXIQK_MATRIXB_11N		0xC88 +#define	DM_REG_TXIQK_MATRIXA_LSB2_11N		0xC94 +#define	DM_REG_TXIQK_MATRIXB_LSB2_11N		0xC9C +#define	DM_REG_RXIQK_MATRIX_LSB_11N		0xCA0 +#define	DM_REG_ANTDIV_PARA1_11N			0xCA4 +#define	DM_REG_OFDM_FA_TYPE1_11N		0xCF0 +/*PAGE D */ +#define	DM_REG_OFDM_FA_RSTD_11N			0xD00 +#define	DM_REG_OFDM_FA_TYPE2_11N		0xDA0 +#define	DM_REG_OFDM_FA_TYPE3_11N		0xDA4 +#define	DM_REG_OFDM_FA_TYPE4_11N		0xDA8 +/*PAGE E */ +#define	DM_REG_TXAGC_A_6_18_11N			0xE00 +#define	DM_REG_TXAGC_A_24_54_11N		0xE04 +#define	DM_REG_TXAGC_A_1_MCS32_11N		0xE08 +#define	DM_REG_TXAGC_A_MCS0_3_11N		0xE10 +#define	DM_REG_TXAGC_A_MCS4_7_11N		0xE14 +#define	DM_REG_TXAGC_A_MCS8_11_11N		0xE18 +#define	DM_REG_TXAGC_A_MCS12_15_11N		0xE1C +#define	DM_REG_FPGA0_IQK_11N			0xE28 +#define	DM_REG_TXIQK_TONE_A_11N			0xE30 +#define	DM_REG_RXIQK_TONE_A_11N			0xE34 +#define	DM_REG_TXIQK_PI_A_11N			0xE38 +#define	DM_REG_RXIQK_PI_A_11N			0xE3C +#define	DM_REG_TXIQK_11N			0xE40 +#define	DM_REG_RXIQK_11N			0xE44 +#define	DM_REG_IQK_AGC_PTS_11N			0xE48 +#define	DM_REG_IQK_AGC_RSP_11N			0xE4C +#define	DM_REG_BLUETOOTH_11N			0xE6C +#define	DM_REG_RX_WAIT_CCA_11N			0xE70 +#define	DM_REG_TX_CCK_RFON_11N			0xE74 +#define	DM_REG_TX_CCK_BBON_11N			0xE78 +#define	DM_REG_OFDM_RFON_11N			0xE7C +#define	DM_REG_OFDM_BBON_11N			0xE80 +#define		DM_REG_TX2RX_11N		0xE84 +#define	DM_REG_TX2TX_11N			0xE88 +#define	DM_REG_RX_CCK_11N			0xE8C +#define	DM_REG_RX_OFDM_11N			0xED0 +#define	DM_REG_RX_WAIT_RIFS_11N			0xED4 +#define	DM_REG_RX2RX_11N			0xED8 +#define	DM_REG_STANDBY_11N			0xEDC +#define	DM_REG_SLEEP_11N			0xEE0 +#define	DM_REG_PMPD_ANAEN_11N			0xEEC + + +/*MAC REG LIST*/ +#define	DM_REG_BB_RST_11N			0x02 +#define	DM_REG_ANTSEL_PIN_11N			0x4C +#define	DM_REG_EARLY_MODE_11N			0x4D0 +#define	DM_REG_RSSI_MONITOR_11N			0x4FE +#define	DM_REG_EDCA_VO_11N			0x500 +#define	DM_REG_EDCA_VI_11N			0x504 +#define	DM_REG_EDCA_BE_11N			0x508 +#define	DM_REG_EDCA_BK_11N			0x50C +#define	DM_REG_TXPAUSE_11N			0x522 +#define	DM_REG_RESP_TX_11N			0x6D8 +#define	DM_REG_ANT_TRAIN_PARA1_11N		0x7b0 +#define	DM_REG_ANT_TRAIN_PARA2_11N		0x7b4 + + +/*DIG Related*/ +#define	DM_BIT_IGI_11N				0x0000007F + + + +#define HAL_DM_DIG_DISABLE			BIT(0) +#define HAL_DM_HIPWR_DISABLE			BIT(1) + +#define OFDM_TABLE_LENGTH			43 +#define CCK_TABLE_LENGTH			33 + +#define OFDM_TABLE_SIZE				43 +#define CCK_TABLE_SIZE				33 + +#define BW_AUTO_SWITCH_HIGH_LOW			25 +#define BW_AUTO_SWITCH_LOW_HIGH			30 + +#define DM_DIG_THRESH_HIGH			40 +#define DM_DIG_THRESH_LOW			35 + +#define DM_FALSEALARM_THRESH_LOW		400 +#define DM_FALSEALARM_THRESH_HIGH		1000 + +#define DM_DIG_MAX				0x3e +#define DM_DIG_MIN				0x1e + +#define DM_DIG_MAX_AP				0x32 +#define DM_DIG_MIN_AP				0x20 + +#define DM_DIG_FA_UPPER				0x3e +#define DM_DIG_FA_LOWER				0x1e +#define DM_DIG_FA_TH0				0x200 +#define DM_DIG_FA_TH1				0x300 +#define DM_DIG_FA_TH2				0x400 + +#define DM_DIG_BACKOFF_MAX			12 +#define DM_DIG_BACKOFF_MIN			-4 +#define DM_DIG_BACKOFF_DEFAULT			10 + +#define RXPATHSELECTION_SS_TH_lOW		30 +#define RXPATHSELECTION_DIFF_TH			18 + +#define DM_RATR_STA_INIT			0 +#define DM_RATR_STA_HIGH			1 +#define DM_RATR_STA_MIDDLE			2 +#define DM_RATR_STA_LOW				3 + +#define CTS2SELF_THVAL				30 +#define REGC38_TH				20 + +#define WAIOTTHVal				25 + +#define TXHIGHPWRLEVEL_NORMAL			0 +#define TXHIGHPWRLEVEL_LEVEL1			1 +#define TXHIGHPWRLEVEL_LEVEL2			2 +#define TXHIGHPWRLEVEL_BT1			3 +#define TXHIGHPWRLEVEL_BT2			4 + +#define DM_TYPE_BYFW				0 +#define DM_TYPE_BYDRIVER			1 + +#define TX_POWER_NEAR_FIELD_THRESH_LVL2		74 +#define TX_POWER_NEAR_FIELD_THRESH_LVL1		67 +#define TXPWRTRACK_MAX_IDX			6 + +/* Dynamic ATC switch */ +#define ATC_STATUS_OFF				0x0	/* enable */ +#define	ATC_STATUS_ON				0x1	/* disable */ +#define	CFO_THRESHOLD_XTAL			10	/* kHz */ +#define	CFO_THRESHOLD_ATC			80	/* kHz */ + +/* RSSI Dump Message */ +#define RA_RSSIDUMP				0xcb0 +#define RB_RSSIDUMP				0xcb1 +#define RS1_RXEVMDUMP				0xcb2 +#define RS2_RXEVMDUMP				0xcb3 +#define RA_RXSNRDUMP				0xcb4 +#define RB_RXSNRDUMP				0xcb5 +#define RA_CFOSHORTDUMP				0xcb6 +#define RB_CFOSHORTDUMP				0xcb8 +#define RA_CFOLONGDUMP				0xcba +#define RB_CFOLONGDUMP				0xcbc + +struct ps_t { +	u8 pre_ccastate; +	u8 cur_ccasate; +	u8 pre_rfstate; +	u8 cur_rfstate; +	long rssi_val_min; + +}; + +struct dig_t { +	u8 dig_enable_flag; +	u8 dig_ext_port_stage; +	u32 rssi_lowthresh; +	u32 rssi_highthresh; + +	u32 fa_lowthresh; +	u32 fa_highthresh; + +	u8 cursta_connectctate; +	u8 presta_connectstate; +	u8 curmultista_connectstate; + +	u8 pre_igvalue; +	u8 cur_igvalue; +	u8 backup_igvalue; +	u8 bt30_cur_igi; +	u8 stop_dig; + +	char backoff_val; +	char backoff_val_range_max; +	char backoff_val_range_min; +	u8 rx_gain_range_max; +	u8 rx_gain_range_min; +	u8 rssi_val_min; + +	u8 pre_cck_cca_thres; +	u8 cur_cck_cca_thres; +	u8 pre_cck_pd_state; +	u8 cur_cck_pd_state; + +	u8 large_fa_hit; +	u8 forbidden_igi; +	u32 recover_cnt; + +	char th_l2h_ini; +	char th_edcca_hl_diff; +	char igi_base; +	u8 igi_target; +	bool force_edcca; +	u8 adapen_rssi; + +	u8 dig_dynamic_min_0; +	u8 dig_dynamic_min_1; +	bool b_media_connect_0; +	bool b_media_connect_1; + +	u32 antdiv_rssi_max; +	u32 rssi_max; +}; + +enum pwr_track_control_method { +	BBSWING, +	TXAGC +}; + +extern struct dig_t dm_dig; +void rtl92ee_dm_init(struct ieee80211_hw *hw); +void rtl92ee_dm_watchdog(struct ieee80211_hw *hw); +void rtl92ee_dm_write_cck_cca_thres(struct ieee80211_hw *hw, +				    u8 cur_thres); +void rtl92ee_dm_write_dig(struct ieee80211_hw *hw, u8 current_igi); +void rtl92ee_dm_init_edca_turbo(struct ieee80211_hw *hw); +void rtl92ee_dm_init_rate_adaptive_mask(struct ieee80211_hw *hw); +void rtl92ee_dm_dynamic_arfb_select(struct ieee80211_hw *hw, +				    u8 rate, bool collision_state); +#endif diff --git a/drivers/staging/rtl8192ee/rtl8192ee/fw.c b/drivers/staging/rtl8192ee/rtl8192ee/fw.c new file mode 100644 index 00000000000..ea6cafa80f4 --- /dev/null +++ b/drivers/staging/rtl8192ee/rtl8192ee/fw.c @@ -0,0 +1,945 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010  Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#include "../wifi.h" +#include "../pci.h" +#include "../base.h" +#include "reg.h" +#include "def.h" +#include "fw.h" +#include "dm.h" + +static void _rtl92ee_enable_fw_download(struct ieee80211_hw *hw, bool enable) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u8 tmp; + +	if (enable) { +		rtl_write_byte(rtlpriv, REG_MCUFWDL, 0x05); + +		tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL + 2); +		rtl_write_byte(rtlpriv, REG_MCUFWDL + 2, tmp & 0xf7); +	} else { + +		tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL); +		rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp & 0xfe); +	} +} + +static void _rtl92ee_fw_block_write(struct ieee80211_hw *hw, +				    const u8 *buffer, u32 size) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u32 blockSize = sizeof(u32); +	u8 *bufferPtr = (u8 *) buffer; +	u32 *pu4BytePtr = (u32 *) buffer; +	u32 i, offset, blockCount, remainSize; + +	blockCount = size / blockSize; +	remainSize = size % blockSize; + +	for (i = 0; i < blockCount; i++) { +		offset = i * blockSize; +		rtl_write_dword(rtlpriv, (FW_8192C_START_ADDRESS + offset), +				*(pu4BytePtr + i)); +	} + +	if (remainSize) { +		offset = blockCount * blockSize; +		bufferPtr += offset; +		for (i = 0; i < remainSize; i++) { +			rtl_write_byte(rtlpriv, +				       (FW_8192C_START_ADDRESS + offset + i), +				       *(bufferPtr + i)); +		} +	} +} + +static void _rtl92ee_fw_page_write(struct ieee80211_hw *hw, u32 page, +				   const u8 *buffer, u32 size) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u8 value8; +	u8 u8page = (u8) (page & 0x07); + +	value8 = (rtl_read_byte(rtlpriv, REG_MCUFWDL + 2) & 0xF8) | u8page; +	rtl_write_byte(rtlpriv, (REG_MCUFWDL + 2), value8); + +	_rtl92ee_fw_block_write(hw, buffer, size); +} + +static void _rtl92ee_fill_dummy(u8 *pfwbuf, u32 *pfwlen) +{ +	u32 fwlen = *pfwlen; +	u8 remain = (u8) (fwlen % 4); + +	remain = (remain == 0) ? 0 : (4 - remain); + +	while (remain > 0) { +		pfwbuf[fwlen] = 0; +		fwlen++; +		remain--; +	} + +	*pfwlen = fwlen; +} + +static void _rtl92ee_write_fw(struct ieee80211_hw *hw, +			      enum version_8192e version, +			      u8 *buffer, u32 size) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u8 *bufferPtr = (u8 *) buffer; +	u32 pageNums, remainSize; +	u32 page, offset; + +	RT_TRACE(COMP_FW, DBG_LOUD , ("FW size is %d bytes,\n", size)); + +	_rtl92ee_fill_dummy(bufferPtr, &size); + +	pageNums = size / FW_8192C_PAGE_SIZE; +	remainSize = size % FW_8192C_PAGE_SIZE; + +	if (pageNums > 8) { +		RT_TRACE(COMP_ERR, DBG_EMERG, +			 ("Page numbers should not greater then 8\n")); +	} + +	for (page = 0; page < pageNums; page++) { +		offset = page * FW_8192C_PAGE_SIZE; +		_rtl92ee_fw_page_write(hw, page, (bufferPtr + offset), +				      FW_8192C_PAGE_SIZE); +		udelay(2); +	} + +	if (remainSize) { +		offset = pageNums * FW_8192C_PAGE_SIZE; +		page = pageNums; +		_rtl92ee_fw_page_write(hw, page, (bufferPtr + offset), +				       remainSize); +	} + +} + +static int _rtl92ee_fw_free_to_go(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	int err = -EIO; +	u32 counter = 0; +	u32 value32; + +	do { +		value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL); +	} while ((counter++ < FW_8192C_POLLING_TIMEOUT_COUNT) && +		 (!(value32 & FWDL_ChkSum_rpt))); + +	if (counter >= FW_8192C_POLLING_TIMEOUT_COUNT) { +		RT_TRACE(COMP_ERR, DBG_EMERG, +			 ("chksum report faill ! REG_MCUFWDL:0x%08x .\n", +			  value32)); +		goto exit; +	} + +	RT_TRACE(COMP_FW, DBG_TRACE, +		 ("Checksum report OK ! REG_MCUFWDL:0x%08x .\n", value32)); + +	value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL); +	value32 |= MCUFWDL_RDY; +	value32 &= ~WINTINI_RDY; +	rtl_write_dword(rtlpriv, REG_MCUFWDL, value32); + +	rtl92ee_firmware_selfreset(hw); +	counter = 0; + +	do { +		value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL); +		if (value32 & WINTINI_RDY) { +			RT_TRACE(COMP_FW, DBG_LOUD , +				("Polling FW ready success!! REG_MCUFWDL:" +				"0x%08x. count = %d\n", value32, counter)); +			err = 0; +			goto exit; +		} + +		udelay(FW_8192C_POLLING_DELAY*10); + +	} while (counter++ < FW_8192C_POLLING_TIMEOUT_COUNT); + +	RT_TRACE(COMP_ERR, DBG_EMERG, +		 ("Polling FW ready fail!! REG_MCUFWDL:0x%08x. count = %d\n", +		 value32, counter)); + +exit: +	return err; +} + +int rtl92ee_download_fw(struct ieee80211_hw *hw, bool buse_wake_on_wlan_fw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); +	struct rtl92c_firmware_header *pfwheader; +	u8 *pfwdata; +	u32 fwsize; +	int err; +	enum version_8192e version = rtlhal->version; + +	if (!rtlhal->pfirmware) +		return 1; + +	pfwheader = (struct rtl92c_firmware_header *)rtlhal->pfirmware; +	rtlhal->fw_version = pfwheader->version; +	rtlhal->fw_subversion = pfwheader->subversion; +	pfwdata = (u8 *) rtlhal->pfirmware; +	fwsize = rtlhal->fwsize; +	RT_TRACE(COMP_FW, DBG_DMESG, +		 ("normal Firmware SIZE %d\n" , fwsize)); + +	if (IS_FW_HEADER_EXIST(pfwheader)) { +		RT_TRACE(COMP_FW, DBG_DMESG, +			 ("Firmware Version(%d), Signature(%#x), Size(%d)\n", +			  pfwheader->version, pfwheader->signature, +			  (int)sizeof(struct rtl92c_firmware_header))); + +		pfwdata = pfwdata + sizeof(struct rtl92c_firmware_header); +		fwsize = fwsize - sizeof(struct rtl92c_firmware_header); +	} else { +		RT_TRACE(COMP_FW, DBG_DMESG, +			 ("Firmware no Header, Signature(%#x)\n", +			  pfwheader->signature)); +	} + +	if (rtlhal->b_mac_func_enable) { +		if (rtl_read_byte(rtlpriv, REG_MCUFWDL) & BIT(7)) { +			rtl_write_byte(rtlpriv, REG_MCUFWDL, 0); +			rtl92ee_firmware_selfreset(hw); +		} +	} +	_rtl92ee_enable_fw_download(hw, true); +	_rtl92ee_write_fw(hw, version, pfwdata, fwsize); +	_rtl92ee_enable_fw_download(hw, false); + +	err = _rtl92ee_fw_free_to_go(hw); +	if (err) { +		RT_TRACE(COMP_ERR, DBG_EMERG, +			 ("Firmware is not ready to run!\n")); +	} else { +		RT_TRACE(COMP_FW, DBG_LOUD , +			 ("Firmware is ready to run!\n")); +	} + +	return 0; +} + +static bool _rtl92ee_check_fw_read_last_h2c(struct ieee80211_hw *hw, u8 boxnum) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u8 val_hmetfr; +	bool result = false; + +	val_hmetfr = rtl_read_byte(rtlpriv, REG_HMETFR); +	if (((val_hmetfr >> boxnum) & BIT(0)) == 0) +		result = true; +	return result; +} + +static void _rtl92ee_fill_h2c_command(struct ieee80211_hw *hw, u8 element_id, +				      u32 cmd_len, u8 *p_cmdbuffer) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); +	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); +	u8 boxnum; +	u16 box_reg = 0, box_extreg = 0; +	u8 u1b_tmp; +	bool isfw_read = false; +	u8 buf_index = 0; +	bool bwrite_sucess = false; +	u8 wait_h2c_limmit = 100; +	u8 boxcontent[4], boxextcontent[4]; +	u32 h2c_waitcounter = 0; +	unsigned long flag; +	u8 idx; + +	if (ppsc->dot11_psmode != EACTIVE || +		ppsc->inactive_pwrstate == ERFOFF) { +		RT_TRACE(COMP_CMD, DBG_LOUD , +			("FillH2CCommand8192E(): " +			"Return because RF is off!!!\n")); +		return; +	} + +	RT_TRACE(COMP_CMD, DBG_LOUD , ("come in\n")); + +	/* 1. Prevent race condition in setting H2C cmd. +	 * (copy from MgntActSet_RF_State().) +	 */ +	while (true) { +		spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag); +		if (rtlhal->b_h2c_setinprogress) { +			RT_TRACE(COMP_CMD, DBG_LOUD , +				 ("H2C set in progress! Wait to set.." +				  "element_id(%d).\n", element_id)); + +			while (rtlhal->b_h2c_setinprogress) { +				spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, +						       flag); +				h2c_waitcounter++; +				RT_TRACE(COMP_CMD, DBG_LOUD , +					 ("Wait 100 us (%d times)...\n", +					  h2c_waitcounter)); +				udelay(100); + +				if (h2c_waitcounter > 1000) +					return; +				spin_lock_irqsave(&rtlpriv->locks.h2c_lock, +						  flag); +			} +			spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag); +		} else { +			rtlhal->b_h2c_setinprogress = true; +			spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag); +			break; +		} +	} + +	while (!bwrite_sucess) { +		/*	cosa remove this because never reach this. */ +		/*wait_writeh2c_limmit--; +		if (wait_writeh2c_limmit == 0) { +			RT_TRACE(COMP_ERR, DBG_EMERG, +				 ("Write H2C fail because no trigger " +				  "for FW INT!\n")); +			break; +		} +		*/ +		/* 2. Find the last BOX number which has been writen. */ +		boxnum = rtlhal->last_hmeboxnum; +		switch (boxnum) { +		case 0: +			box_reg = REG_HMEBOX_0; +			box_extreg = REG_HMEBOX_EXT_0; +			break; +		case 1: +			box_reg = REG_HMEBOX_1; +			box_extreg = REG_HMEBOX_EXT_1; +			break; +		case 2: +			box_reg = REG_HMEBOX_2; +			box_extreg = REG_HMEBOX_EXT_2; +			break; +		case 3: +			box_reg = REG_HMEBOX_3; +			box_extreg = REG_HMEBOX_EXT_3; +			break; +		default: +			RT_TRACE(COMP_ERR, DBG_EMERG, +				 ("switch case not process\n")); +			break; +		} + +		/* 3. Check if the box content is empty. */ +		isfw_read = false; +		u1b_tmp = rtl_read_byte(rtlpriv, REG_CR); + +		if (u1b_tmp != 0xea) { +			isfw_read = true; +		} else { +			if (rtl_read_byte(rtlpriv, REG_TXDMA_STATUS) == 0xea || +			    rtl_read_byte(rtlpriv, REG_TXPKT_EMPTY) == 0xea) +				rtl_write_byte(rtlpriv, REG_SYS_CFG1 + 3, 0xff); +		} + +		if (isfw_read == true) { +			wait_h2c_limmit = 100; +			isfw_read = _rtl92ee_check_fw_read_last_h2c(hw, boxnum); +			while (!isfw_read) { +				wait_h2c_limmit--; +				if (wait_h2c_limmit == 0) { +					RT_TRACE(COMP_CMD, DBG_LOUD , +						("Wating too long for FW" +						"read clear HMEBox(%d)!!!\n", +						boxnum)); +					break; +				} +				udelay(10); +				isfw_read = _rtl92ee_check_fw_read_last_h2c(hw, +									boxnum); +				u1b_tmp = rtl_read_byte(rtlpriv, 0x130); +				RT_TRACE(COMP_CMD, DBG_LOUD , +					 ("Wating for FW read clear HMEBox(%d)!!! 0x130 = %2x\n", +					 boxnum, u1b_tmp)); +			} +		} + +		/* If Fw has not read the last +		 H2C cmd, break and give up this H2C. */ +		if (!isfw_read) { +			RT_TRACE(COMP_CMD, DBG_LOUD , +				 ("Write H2C reg BOX[%d] fail, Fw don't read.\n", +				 boxnum)); +			break; +		} +		/* 4. Fill the H2C cmd into box */ +		memset(boxcontent, 0, sizeof(boxcontent)); +		memset(boxextcontent, 0, sizeof(boxextcontent)); +		boxcontent[0] = element_id; +		RT_TRACE(COMP_CMD, DBG_LOUD , +			 ("Write element_id box_reg(%4x) = %2x\n", +			  box_reg, element_id)); + +		switch (cmd_len) { +		case 1: +		case 2: +		case 3: +			/*boxcontent[0] &= ~(BIT(7));*/ +			memcpy((u8 *) (boxcontent) + 1, +			       p_cmdbuffer + buf_index, cmd_len); + +			for (idx = 0; idx < 4; idx++) { +				rtl_write_byte(rtlpriv, box_reg + idx, +					       boxcontent[idx]); +			} +			break; +		case 4: +		case 5: +		case 6: +		case 7: +			/*boxcontent[0] |= (BIT(7));*/ +			memcpy((u8 *) (boxextcontent), +			       p_cmdbuffer + buf_index+3, cmd_len-3); +			memcpy((u8 *) (boxcontent) + 1, +			       p_cmdbuffer + buf_index, 3); + +			for (idx = 0; idx < 4; idx++) { +				rtl_write_byte(rtlpriv, box_extreg + idx, +					       boxextcontent[idx]); +			} + +			for (idx = 0; idx < 4; idx++) { +				rtl_write_byte(rtlpriv, box_reg + idx, +					       boxcontent[idx]); +			} +			break; +		default: +			RT_TRACE(COMP_ERR, DBG_EMERG, +				 ("switch case not process\n")); +			break; +		} + +		bwrite_sucess = true; + +		rtlhal->last_hmeboxnum = boxnum + 1; +		if (rtlhal->last_hmeboxnum == 4) +			rtlhal->last_hmeboxnum = 0; + +		RT_TRACE(COMP_CMD, DBG_LOUD , +			 ("pHalData->last_hmeboxnum  = %d\n", +			  rtlhal->last_hmeboxnum)); +	} + +	spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag); +	rtlhal->b_h2c_setinprogress = false; +	spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag); + +	RT_TRACE(COMP_CMD, DBG_LOUD , ("go out\n")); +} + +void rtl92ee_fill_h2c_cmd(struct ieee80211_hw *hw, +			 u8 element_id, u32 cmd_len, u8 *p_cmdbuffer) +{ +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); +	u32 tmp_cmdbuf[2]; + +	if (rtlhal->bfw_ready == false) { +		RT_ASSERT(false, ("return H2C cmd because of Fw " +				  "download fail!!!\n")); +		return; +	} + +	memset(tmp_cmdbuf, 0, 8); +	memcpy(tmp_cmdbuf, p_cmdbuffer, cmd_len); +	_rtl92ee_fill_h2c_command(hw, element_id, cmd_len, (u8 *)&tmp_cmdbuf); + +	return; +} + +void rtl92ee_firmware_selfreset(struct ieee80211_hw *hw) +{ +	u8 u1b_tmp; +	struct rtl_priv *rtlpriv = rtl_priv(hw); + +	u1b_tmp = rtl_read_byte(rtlpriv, REG_RSV_CTRL + 1); +	rtl_write_byte(rtlpriv, REG_RSV_CTRL + 1, (u1b_tmp & (~BIT(0)))); + +	u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1); +	rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, (u1b_tmp & (~BIT(2)))); + +	udelay(50); + +	u1b_tmp = rtl_read_byte(rtlpriv, REG_RSV_CTRL + 1); +	rtl_write_byte(rtlpriv, REG_RSV_CTRL + 1, (u1b_tmp | BIT(0))); + +	u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1); +	rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, (u1b_tmp | BIT(2))); + +	RT_TRACE(COMP_INIT, DBG_LOUD , +		 ("  _8051Reset92E(): 8051 reset success .\n")); +} + +void rtl92ee_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u8 u1_h2c_set_pwrmode[H2C_92E_PWEMODE_LENGTH] = { 0 }; +	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); +	u8 rlbm , power_state = 0; +	RT_TRACE(COMP_POWER, DBG_LOUD , ("FW LPS mode = %d\n", mode)); + +	SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, ((mode) ? 1 : 0)); +	rlbm = 0;/*YJ, temp, 120316. FW now not support RLBM = 2.*/ +	SET_H2CCMD_PWRMODE_PARM_RLBM(u1_h2c_set_pwrmode, rlbm); +	SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode, +					 (rtlpriv->mac80211.p2p) ? +					 ppsc->smart_ps : 1); +	SET_H2CCMD_PWRMODE_PARM_AWAKE_INTERVAL(u1_h2c_set_pwrmode, +					       ppsc->reg_max_lps_awakeintvl); +	SET_H2CCMD_PWRMODE_PARM_ALL_QUEUE_UAPSD(u1_h2c_set_pwrmode, 0); +	if (mode == FW_PS_ACTIVE_MODE) +		power_state |= FW_PWR_STATE_ACTIVE; +	else +		power_state |= FW_PWR_STATE_RF_OFF; +	SET_H2CCMD_PWRMODE_PARM_PWR_STATE(u1_h2c_set_pwrmode, power_state); + +	RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG, +		      "rtl92c_set_fw_pwrmode(): u1_h2c_set_pwrmode\n", +		      u1_h2c_set_pwrmode, H2C_92E_PWEMODE_LENGTH); +	rtl92ee_fill_h2c_cmd(hw, H2C_92E_SETPWRMODE, H2C_92E_PWEMODE_LENGTH, +			     u1_h2c_set_pwrmode); + +} + +void rtl92ee_set_fw_media_status_rpt_cmd(struct ieee80211_hw *hw, u8 mstatus) +{ +	u8 parm[3] = { 0 , 0 , 0 }; +	/* parm[0]: bit0 = 0-->Disconnect, bit0 = 1-->Connect +	 *          bit1 = 0-->update Media Status to MACID +	 *          bit1 = 1-->update Media Status from MACID to MACID_End +	 * parm[1]: MACID, if this is INFRA_STA, MacID = 0 +	 * parm[2]: MACID_End*/ + +	SET_H2CCMD_MSRRPT_PARM_OPMODE(parm, mstatus); +	SET_H2CCMD_MSRRPT_PARM_MACID_IND(parm, 0); + +	rtl92ee_fill_h2c_cmd(hw, H2C_92E_MSRRPT, 3, parm); +} + +static bool _rtl92ee_cmd_send_packet(struct ieee80211_hw *hw, +				     struct sk_buff *skb) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); +	struct rtl8192_tx_ring *ring; +	struct rtl_tx_desc *pdesc; +	unsigned long flags; +	struct sk_buff *pskb = NULL; + +	ring = &rtlpci->tx_ring[BEACON_QUEUE]; + +	pskb = __skb_dequeue(&ring->queue); +	if (pskb) +		kfree_skb(pskb); + +	spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags); +	/*this is wrong, fill_tx_cmddesc needs update*/ +	pdesc = &ring->desc[0]; + +	rtlpriv->cfg->ops->fill_tx_cmddesc(hw, (u8 *) pdesc, 1, 1, skb); + +	__skb_queue_tail(&ring->queue, skb); + +	spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags); + +	return true; +} + +#define BEACON_PG		0 /* ->1 */ +#define PSPOLL_PG		2 +#define NULL_PG			3 +#define PROBERSP_PG		4 /* ->5 */ + +#define TOTAL_RESERVED_PKT_LEN	768 + + + +static u8 reserved_page_packet[TOTAL_RESERVED_PKT_LEN] = { +	/* page 0 beacon */ +	0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, +	0xFF, 0xFF, 0x00, 0xE0, 0x4C, 0x02, 0xB1, 0x78, +	0xEC, 0x1A, 0x59, 0x0B, 0xAD, 0xD4, 0x20, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x64, 0x00, 0x10, 0x04, 0x00, 0x05, 0x54, 0x65, +	0x73, 0x74, 0x32, 0x01, 0x08, 0x82, 0x84, 0x0B, +	0x16, 0x24, 0x30, 0x48, 0x6C, 0x03, 0x01, 0x06, +	0x06, 0x02, 0x00, 0x00, 0x2A, 0x01, 0x02, 0x32, +	0x04, 0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, +	0x09, 0x03, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x3D, 0x00, 0xDD, 0x07, 0x00, 0xE0, 0x4C, +	0x02, 0x02, 0x00, 0x00, 0xDD, 0x18, 0x00, 0x50, +	0xF2, 0x01, 0x01, 0x00, 0x00, 0x50, 0xF2, 0x04, +	0x01, 0x00, 0x00, 0x50, 0xF2, 0x04, 0x01, 0x00, + +	/* page 1 beacon */ +	0x00, 0x50, 0xF2, 0x02, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x10, 0x00, 0x28, 0x8C, 0x00, 0x12, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + +	/* page 2  ps-poll */ +	0xA4, 0x10, 0x01, 0xC0, 0xEC, 0x1A, 0x59, 0x0B, +	0xAD, 0xD4, 0x00, 0xE0, 0x4C, 0x02, 0xB1, 0x78, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x18, 0x00, 0x28, 0x8C, 0x00, 0x12, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + +	/* page 3  null */ +	0x48, 0x01, 0x00, 0x00, 0xEC, 0x1A, 0x59, 0x0B, +	0xAD, 0xD4, 0x00, 0xE0, 0x4C, 0x02, 0xB1, 0x78, +	0xEC, 0x1A, 0x59, 0x0B, 0xAD, 0xD4, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x72, 0x00, 0x28, 0x8C, 0x00, 0x12, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + +	/* page 4  probe_resp */ +	0x50, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10, +	0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42, +	0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00, +	0x9E, 0x46, 0x15, 0x32, 0x27, 0xF2, 0x2D, 0x00, +	0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69, +	0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C, +	0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96, +	0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A, +	0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C, +	0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18, +	0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02, +	0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + +	/* page 5  probe_resp */ +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + + + +void rtl92ee_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +	struct sk_buff *skb = NULL; + +	u32 totalpacketlen; +	bool rtstatus; +	u8 u1RsvdPageLoc[5] = { 0 }; +	bool b_dlok = false; + +	u8 *beacon; +	u8 *p_pspoll; +	u8 *nullfunc; +	u8 *p_probersp; +	/*--------------------------------------------------------- +				(1) beacon +	---------------------------------------------------------*/ +	beacon = &reserved_page_packet[BEACON_PG * 128]; +	SET_80211_HDR_ADDRESS2(beacon, mac->mac_addr); +	SET_80211_HDR_ADDRESS3(beacon, mac->bssid); + +	/*------------------------------------------------------- +				(2) ps-poll +	--------------------------------------------------------*/ +	p_pspoll = &reserved_page_packet[PSPOLL_PG * 128]; +	SET_80211_PS_POLL_AID(p_pspoll, (mac->assoc_id | 0xc000)); +	SET_80211_PS_POLL_BSSID(p_pspoll, mac->bssid); +	SET_80211_PS_POLL_TA(p_pspoll, mac->mac_addr); + +	SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1RsvdPageLoc, PSPOLL_PG); + +	/*-------------------------------------------------------- +				(3) null data +	---------------------------------------------------------*/ +	nullfunc = &reserved_page_packet[NULL_PG * 128]; +	SET_80211_HDR_ADDRESS1(nullfunc, mac->bssid); +	SET_80211_HDR_ADDRESS2(nullfunc, mac->mac_addr); +	SET_80211_HDR_ADDRESS3(nullfunc, mac->bssid); + +	SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1RsvdPageLoc, NULL_PG); + +	/*--------------------------------------------------------- +				(4) probe response +	----------------------------------------------------------*/ +	p_probersp = &reserved_page_packet[PROBERSP_PG * 128]; +	SET_80211_HDR_ADDRESS1(p_probersp, mac->bssid); +	SET_80211_HDR_ADDRESS2(p_probersp, mac->mac_addr); +	SET_80211_HDR_ADDRESS3(p_probersp, mac->bssid); + +	SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1RsvdPageLoc, PROBERSP_PG); + +	totalpacketlen = TOTAL_RESERVED_PKT_LEN; + +	RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD , +		      "rtl92ee_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n", +		      &reserved_page_packet[0], totalpacketlen); +	RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD , +		      "rtl92ee_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n", +		      u1RsvdPageLoc, 3); + + +	skb = dev_alloc_skb(totalpacketlen); +	memcpy((u8 *) skb_put(skb, totalpacketlen), +	       &reserved_page_packet, totalpacketlen); + +	rtstatus = _rtl92ee_cmd_send_packet(hw, skb); + +	if (rtstatus) +		b_dlok = true; + +	if (b_dlok) { +		RT_TRACE(COMP_POWER, DBG_LOUD , +			 ("Set RSVD page location to Fw.\n")); +		RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD , +			      "H2C_RSVDPAGE:\n", u1RsvdPageLoc, 3); +		rtl92ee_fill_h2c_cmd(hw, H2C_92E_RSVDPAGE, +				     sizeof(u1RsvdPageLoc), u1RsvdPageLoc); +	} else +		RT_TRACE(COMP_ERR, DBG_WARNING, +			 ("Set RSVD page location to Fw FAIL!!!!!!.\n")); +} + +/*Shoud check FW support p2p or not.*/ +static void rtl92ee_set_p2p_ctw_period_cmd(struct ieee80211_hw *hw, u8 ctwindow) +{ +	u8 u1_ctwindow_period[1] = {ctwindow}; + +	rtl92ee_fill_h2c_cmd(hw, H2C_92E_P2P_PS_CTW_CMD, 1, u1_ctwindow_period); + +} + +void rtl92ee_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_ps_ctl *rtlps = rtl_psc(rtl_priv(hw)); +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); +	struct rtl_p2p_ps_info *p2pinfo = &(rtlps->p2p_ps_info); +	struct p2p_ps_offload_t *p2p_ps_offload = &rtlhal->p2p_ps_offload; +	u8 i; +	u16 ctwindow; +	u32 start_time, tsf_low; + +	switch (p2p_ps_state) { +	case P2P_PS_DISABLE: +		RT_TRACE(COMP_FW, DBG_LOUD , ("P2P_PS_DISABLE\n")); +		memset(p2p_ps_offload, 0, 1); +		break; +	case P2P_PS_ENABLE: +		RT_TRACE(COMP_FW, DBG_LOUD , ("P2P_PS_ENABLE\n")); +		/* update CTWindow value. */ +		if (p2pinfo->ctwindow > 0) { +			p2p_ps_offload->CTWindow_En = 1; +			ctwindow = p2pinfo->ctwindow; +			rtl92ee_set_p2p_ctw_period_cmd(hw, ctwindow); +		} +		/* hw only support 2 set of NoA */ +		for (i = 0 ; i < p2pinfo->noa_num ; i++) { +			/* To control the register setting for which NOA*/ +			rtl_write_byte(rtlpriv, 0x5cf, (i << 4)); +			if (i == 0) +				p2p_ps_offload->NoA0_En = 1; +			else +				p2p_ps_offload->NoA1_En = 1; +			/* config P2P NoA Descriptor Register */ +			rtl_write_dword(rtlpriv, 0x5E0, +					p2pinfo->noa_duration[i]); +			rtl_write_dword(rtlpriv, 0x5E4, +					p2pinfo->noa_interval[i]); + +			/*Get Current TSF value */ +			tsf_low = rtl_read_dword(rtlpriv, REG_TSFTR); + +			start_time = p2pinfo->noa_start_time[i]; +			if (p2pinfo->noa_count_type[i] != 1) { +				while (start_time <= (tsf_low + (50 * 1024))) { +					start_time += p2pinfo->noa_interval[i]; +					if (p2pinfo->noa_count_type[i] != 255) +						p2pinfo->noa_count_type[i]--; +				} +			} +			rtl_write_dword(rtlpriv, 0x5E8, start_time); +			rtl_write_dword(rtlpriv, 0x5EC, +					p2pinfo->noa_count_type[i]); +		} +		if ((p2pinfo->opp_ps == 1) || (p2pinfo->noa_num > 0)) { +			/* rst p2p circuit */ +			rtl_write_byte(rtlpriv, REG_DUAL_TSF_RST, BIT(4)); +			p2p_ps_offload->Offload_En = 1; + +			if (P2P_ROLE_GO == rtlpriv->mac80211.p2p) { +				p2p_ps_offload->role = 1; +				p2p_ps_offload->AllStaSleep = 0; +			} else { +				p2p_ps_offload->role = 0; +			} +			p2p_ps_offload->discovery = 0; +		} +		break; +	case P2P_PS_SCAN: +		RT_TRACE(COMP_FW, DBG_LOUD , ("P2P_PS_SCAN\n")); +		p2p_ps_offload->discovery = 1; +		break; +	case P2P_PS_SCAN_DONE: +		RT_TRACE(COMP_FW, DBG_LOUD , ("P2P_PS_SCAN_DONE\n")); +		p2p_ps_offload->discovery = 0; +		p2pinfo->p2p_ps_state = P2P_PS_ENABLE; +		break; +	default: +		break; +	} + +	rtl92ee_fill_h2c_cmd(hw, H2C_92E_P2P_PS_OFFLOAD, 1, +			     (u8 *)p2p_ps_offload); + +} + +static void _rtl92ee_c2h_ra_report_handler(struct ieee80211_hw *hw, +					   u8 *cmd_buf, u8 cmd_len) +{ +	u8 rate = cmd_buf[0] & 0x3F; +	bool collision_state = cmd_buf[3] & BIT(0); + +	rtl92ee_dm_dynamic_arfb_select(hw, rate, collision_state); +} + +static void _rtl92ee_c2h_content_parsing(struct ieee80211_hw *hw, u8 c2h_cmd_id, +					 u8 c2h_cmd_len, u8 *tmp_buf) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); + +	switch (c2h_cmd_id) { +	case C2H_8192E_DBG: +		RT_TRACE(COMP_FW, DBG_TRACE , ("[C2H], C2H_8723BE_DBG!!\n")); +		break; +	case C2H_8192E_TXBF: +		RT_TRACE(COMP_FW, DBG_TRACE , ("[C2H], C2H_8192E_TXBF!!\n")); +		break; +	case C2H_8192E_TX_REPORT: +		RT_TRACE(COMP_FW, DBG_TRACE , ("[C2H], C2H_8723BE_TX_REPORT!\n")); +		break; +	case C2H_8192E_BT_INFO: +		RT_TRACE(COMP_FW, DBG_TRACE , ("[C2H], C2H_8723BE_BT_INFO!!\n")); +		rtlpriv->btcoexist.btc_ops->btc_btinfo_notify(rtlpriv, tmp_buf, +							      c2h_cmd_len); +		break; +	case C2H_8192E_BT_MP: +		RT_TRACE(COMP_FW, DBG_TRACE, ("[C2H], C2H_8723BE_BT_MP!!\n")); +		break; +	case C2H_8192E_RA_RPT: +		_rtl92ee_c2h_ra_report_handler(hw, tmp_buf, c2h_cmd_len); +		break; +	default: +		RT_TRACE(COMP_FW, DBG_TRACE, +			 ("[C2H], Unkown packet!! CmdId(%#X)!\n", c2h_cmd_id)); +		break; +	} +} + +void rtl92ee_c2h_packet_handler(struct ieee80211_hw *hw, u8 *buffer, u8 len) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u8 c2h_cmd_id = 0, c2h_cmd_seq = 0, c2h_cmd_len = 0; +	u8 *tmp_buf = NULL; + +	c2h_cmd_id = buffer[0]; +	c2h_cmd_seq = buffer[1]; +	c2h_cmd_len = len - 2; +	tmp_buf = buffer + 2; + +	RT_TRACE(COMP_FW, DBG_TRACE, +		("[C2H packet], c2hCmdId = 0x%x, c2hCmdSeq = 0x%x, c2hCmdLen =%d\n", +		c2h_cmd_id, c2h_cmd_seq, c2h_cmd_len)); + +	RT_PRINT_DATA(rtlpriv, COMP_FW, DBG_TRACE, +		      "[C2H packet], Content Hex:\n", tmp_buf, c2h_cmd_len); + +	_rtl92ee_c2h_content_parsing(hw, c2h_cmd_id, c2h_cmd_len, tmp_buf); +} diff --git a/drivers/staging/rtl8192ee/rtl8192ee/fw.h b/drivers/staging/rtl8192ee/rtl8192ee/fw.h new file mode 100644 index 00000000000..143992d5f62 --- /dev/null +++ b/drivers/staging/rtl8192ee/rtl8192ee/fw.h @@ -0,0 +1,213 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010  Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __RTL92E__FW__H__ +#define __RTL92E__FW__H__ + +#define FW_8192C_SIZE				0x8000 +#define FW_8192C_START_ADDRESS			0x1000 +#define FW_8192C_END_ADDRESS			0x5FFF +#define FW_8192C_PAGE_SIZE			4096 +#define FW_8192C_POLLING_DELAY			5 +#define FW_8192C_POLLING_TIMEOUT_COUNT		3000 + +#define IS_FW_HEADER_EXIST(_pfwhdr)	\ +	((_pfwhdr->signature&0xFFF0) == 0x92E0) +#define USE_OLD_WOWLAN_DEBUG_FW 0 + +#define H2C_92E_RSVDPAGE_LOC_LEN		5 +#define H2C_92E_PWEMODE_LENGTH			5 +#define H2C_92E_JOINBSSRPT_LENGTH		1 +#define H2C_92E_AP_OFFLOAD_LENGTH		3 +#define H2C_92E_WOWLAN_LENGTH			3 +#define H2C_92E_KEEP_ALIVE_CTRL_LENGTH		3 +#if (USE_OLD_WOWLAN_DEBUG_FW == 0) +#define H2C_92E_REMOTE_WAKE_CTRL_LEN		1 +#else +#define H2C_92E_REMOTE_WAKE_CTRL_LEN		3 +#endif +#define H2C_92E_AOAC_GLOBAL_INFO_LEN		2 +#define H2C_92E_AOAC_RSVDPAGE_LOC_LEN		7 + + +/* Fw PS state for RPWM. +*BIT[2:0] = HW state +*BIT[3] = Protocol PS state,  1: register active state, 0: register sleep state +*BIT[4] = sub-state +*/ +#define	FW_PS_RF_ON		BIT(2) +#define	FW_PS_REGISTER_ACTIVE	BIT(3) + +#define	FW_PS_ACK		BIT(6) +#define	FW_PS_TOGGLE		BIT(7) + + /* 92E RPWM value*/ + /* BIT[0] = 1: 32k, 0: 40M*/ +#define	FW_PS_CLOCK_OFF		BIT(0)		/* 32k */ +#define	FW_PS_CLOCK_ON		0		/* 40M */ + +#define	FW_PS_STATE_MASK		(0x0F) +#define	FW_PS_STATE_HW_MASK		(0x07) +#define	FW_PS_STATE_INT_MASK		(0x3F) + +#define	FW_PS_STATE(x)			(FW_PS_STATE_MASK & (x)) + +#define	FW_PS_STATE_ALL_ON_92E		(FW_PS_CLOCK_ON) +#define	FW_PS_STATE_RF_ON_92E		(FW_PS_CLOCK_ON) +#define	FW_PS_STATE_RF_OFF_92E		(FW_PS_CLOCK_ON) +#define	FW_PS_STATE_RF_OFF_LOW_PWR	(FW_PS_CLOCK_OFF) + +/* For 92E H2C PwrMode Cmd ID 5.*/ +#define	FW_PWR_STATE_ACTIVE	((FW_PS_RF_ON) | (FW_PS_REGISTER_ACTIVE)) +#define	FW_PWR_STATE_RF_OFF	0 + +#define	FW_PS_IS_ACK(x)		((x) & FW_PS_ACK) + +#define	IS_IN_LOW_POWER_STATE_92E(FwPSState)		\ +	(FW_PS_STATE(FwPSState) == FW_PS_CLOCK_OFF) + +#define	FW_PWR_STATE_ACTIVE	((FW_PS_RF_ON) | (FW_PS_REGISTER_ACTIVE)) +#define	FW_PWR_STATE_RF_OFF	0 + +struct rtl92c_firmware_header { +	u16 signature; +	u8 category; +	u8 function; +	u16 version; +	u8 subversion; +	u8 rsvd1; +	u8 month; +	u8 date; +	u8 hour; +	u8 minute; +	u16 ramcodeSize; +	u16 rsvd2; +	u32 svnindex; +	u32 rsvd3; +	u32 rsvd4; +	u32 rsvd5; +}; + +enum rtl8192c_h2c_cmd { +	H2C_92E_RSVDPAGE = 0, +	H2C_92E_MSRRPT = 1, +	H2C_92E_SCAN = 2, +	H2C_92E_KEEP_ALIVE_CTRL = 3, +	H2C_92E_DISCONNECT_DECISION = 4, +#if (USE_OLD_WOWLAN_DEBUG_FW == 1) +	H2C_92E_WO_WLAN = 5, +#endif +	H2C_92E_INIT_OFFLOAD = 6, +#if (USE_OLD_WOWLAN_DEBUG_FW == 1) +	H2C_92E_REMOTE_WAKE_CTRL = 7, +#endif +	H2C_92E_AP_OFFLOAD = 8, +	H2C_92E_BCN_RSVDPAGE = 9, +	H2C_92E_PROBERSP_RSVDPAGE = 10, + +	H2C_92E_SETPWRMODE = 0x20, +	H2C_92E_PS_TUNING_PARA = 0x21, +	H2C_92E_PS_TUNING_PARA2 = 0x22, +	H2C_92E_PS_LPS_PARA = 0x23, +	H2C_92E_P2P_PS_OFFLOAD = 024, + +#if (USE_OLD_WOWLAN_DEBUG_FW == 0) +	H2C_92E_WO_WLAN = 0x80, +	H2C_92E_REMOTE_WAKE_CTRL = 0x81, +	H2C_92E_AOAC_GLOBAL_INFO = 0x82, +	H2C_92E_AOAC_RSVDPAGE = 0x83, +#endif +	H2C_92E_RA_MASK = 0x40, +	H2C_92E_RSSI_REPORT = 0x42, +	H2C_92E_SELECTIVE_SUSPEND_ROF_CMD, +	H2C_92E_P2P_PS_MODE, +	H2C_92E_PSD_RESULT, +	/*Not defined CTW CMD for P2P yet*/ +	H2C_92E_P2P_PS_CTW_CMD, +	MAX_92E_H2CCMD +}; + +enum rtl8192e_c2h_evt { +	C2H_8192E_DBG = 0, +	C2H_8192E_LB = 1, +	C2H_8192E_TXBF = 2, +	C2H_8192E_TX_REPORT = 3, +	C2H_8192E_BT_INFO = 9, +	C2H_8192E_BT_MP = 11, +	C2H_8192E_RA_RPT = 12, +	MAX_8192E_C2HEVENT +}; + +#define pagenum_128(_len)	\ +	(u32)(((_len) >> 7) + ((_len) & 0x7F ? 1 : 0)) + +#define SET_H2CCMD_PWRMODE_PARM_MODE(__ph2ccmd, __val)			\ +	SET_BITS_TO_LE_1BYTE(__ph2ccmd, 0, 8, __val) +#define SET_H2CCMD_PWRMODE_PARM_RLBM(__pH2CCmd, __val)			\ +	SET_BITS_TO_LE_1BYTE((__pH2CCmd)+1, 0, 4, __val) +#define SET_H2CCMD_PWRMODE_PARM_SMART_PS(__pH2CCmd, __val)		\ +	SET_BITS_TO_LE_1BYTE((__pH2CCmd)+1, 4, 4, __val) +#define SET_H2CCMD_PWRMODE_PARM_AWAKE_INTERVAL(__pH2CCmd, __val)	\ +	SET_BITS_TO_LE_1BYTE((__pH2CCmd)+2, 0, 8, __val) +#define SET_H2CCMD_PWRMODE_PARM_ALL_QUEUE_UAPSD(__pH2CCmd, __val)	\ +	SET_BITS_TO_LE_1BYTE((__pH2CCmd)+3, 0, 8, __val) +#define SET_H2CCMD_PWRMODE_PARM_PWR_STATE(__pH2CCmd, __val)		\ +	SET_BITS_TO_LE_1BYTE((__pH2CCmd)+4, 0, 8, __val) +#define GET_92E_H2CCMD_PWRMODE_PARM_MODE(__pH2CCmd)			\ +	LE_BITS_TO_1BYTE(__pH2CCmd, 0, 8) + +#define SET_H2CCMD_JOINBSSRPT_PARM_OPMODE(__ph2ccmd, __val)		\ +	SET_BITS_TO_LE_1BYTE(__ph2ccmd, 0, 8, __val) +#define SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(__ph2ccmd, __val)		\ +	SET_BITS_TO_LE_1BYTE(__ph2ccmd, 0, 8, __val) +#define SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(__ph2ccmd, __val)		\ +	SET_BITS_TO_LE_1BYTE((__ph2ccmd)+1, 0, 8, __val) +#define SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(__ph2ccmd, __val)		\ +	SET_BITS_TO_LE_1BYTE((__ph2ccmd)+2, 0, 8, __val) + +/* _MEDIA_STATUS_RPT_PARM_CMD1 */ +#define SET_H2CCMD_MSRRPT_PARM_OPMODE(__pH2CCmd, __Value)		\ +	SET_BITS_TO_LE_1BYTE(__pH2CCmd, 0, 1, __Value) +#define SET_H2CCMD_MSRRPT_PARM_MACID_IND(__pH2CCmd, __Value)		\ +	SET_BITS_TO_LE_1BYTE(__pH2CCmd, 1, 1, __Value) +#define SET_H2CCMD_MSRRPT_PARM_MACID(__pH2CCmd, __Value)		\ +	SET_BITS_TO_LE_1BYTE(__pH2CCmd+1, 0, 8, __Value) +#define SET_H2CCMD_MSRRPT_PARM_MACID_END(__pH2CCmd, __Value)		\ +	SET_BITS_TO_LE_1BYTE(__pH2CCmd+2, 0, 8, __Value) + + +int rtl92ee_download_fw(struct ieee80211_hw *hw, bool buse_wake_on_wlan_fw); +void rtl92ee_fill_h2c_cmd(struct ieee80211_hw *hw, u8 element_id, +			  u32 cmd_len, u8 *p_cmdbuffer); +void rtl92ee_firmware_selfreset(struct ieee80211_hw *hw); +void rtl92ee_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode); +void rtl92ee_set_fw_media_status_rpt_cmd(struct ieee80211_hw *hw, u8 mstatus); +void rtl92ee_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished); +void rtl92ee_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state); +void rtl92ee_c2h_packet_handler(struct ieee80211_hw *hw, u8 *buffer, u8 len); +#endif diff --git a/drivers/staging/rtl8192ee/rtl8192ee/hw.c b/drivers/staging/rtl8192ee/rtl8192ee/hw.c new file mode 100644 index 00000000000..26af119e2ca --- /dev/null +++ b/drivers/staging/rtl8192ee/rtl8192ee/hw.c @@ -0,0 +1,2544 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010  Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#include "../wifi.h" +#include "../efuse.h" +#include "../base.h" +#include "../regd.h" +#include "../cam.h" +#include "../ps.h" +#include "../pci.h" +#include "reg.h" +#include "def.h" +#include "phy.h" +#include "dm.h" +#include "fw.h" +#include "led.h" +#include "hw.h" +#include "pwrseqcmd.h" +#include "pwrseq.h" + +#define LLT_CONFIG	5 + +static void _rtl92ee_set_bcn_ctrl_reg(struct ieee80211_hw *hw, +				      u8 set_bits, u8 clear_bits) +{ +	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); +	struct rtl_priv *rtlpriv = rtl_priv(hw); + +	rtlpci->reg_bcn_ctrl_val |= set_bits; +	rtlpci->reg_bcn_ctrl_val &= ~clear_bits; + +	rtl_write_byte(rtlpriv, REG_BCN_CTRL, (u8) rtlpci->reg_bcn_ctrl_val); +} + +static void _rtl92ee_stop_tx_beacon(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u8 tmp; + +	tmp = rtl_read_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2); +	rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2, tmp & (~BIT(6))); +	rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 1, 0x64); +	tmp = rtl_read_byte(rtlpriv, REG_TBTT_PROHIBIT + 2); +	tmp &= ~(BIT(0)); +	rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 2, tmp); +} + +static void _rtl92ee_resume_tx_beacon(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u8 tmp; + +	tmp = rtl_read_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2); +	rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2, tmp | BIT(6)); +	rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 1, 0xff); +	tmp = rtl_read_byte(rtlpriv, REG_TBTT_PROHIBIT + 2); +	tmp |= BIT(0); +	rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 2, tmp); +} + +static void _rtl92ee_enable_bcn_sub_func(struct ieee80211_hw *hw) +{ +	_rtl92ee_set_bcn_ctrl_reg(hw, 0, BIT(1)); +} + +static void _rtl92ee_return_beacon_queue_skb(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); +	struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[BEACON_QUEUE]; + +	while (skb_queue_len(&ring->queue)) { +		struct rtl_tx_buffer_desc *entry = +						&ring->buffer_desc[ring->idx]; +		struct sk_buff *skb = __skb_dequeue(&ring->queue); + +		pci_unmap_single(rtlpci->pdev, +				 rtlpriv->cfg->ops->get_desc( +				 (u8 *) entry, true, HW_DESC_TXBUFF_ADDR), +				 skb->len, PCI_DMA_TODEVICE); +		kfree_skb(skb); +		ring->idx = (ring->idx + 1) % ring->entries; +	} + +} +static void _rtl92ee_disable_bcn_sub_func(struct ieee80211_hw *hw) +{ +	_rtl92ee_set_bcn_ctrl_reg(hw, BIT(1), 0); +} + +static void _rtl92ee_set_fw_clock_on(struct ieee80211_hw *hw, +	u8 rpwm_val, bool b_need_turn_off_ckk) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); +	bool b_support_remote_wake_up; +	u32 count = 0 , isr_regaddr , content; +	bool b_schedule_timer = b_need_turn_off_ckk; +	rtlpriv->cfg->ops->get_hw_reg(hw, HAL_DEF_WOWLAN, +				      (u8 *) (&b_support_remote_wake_up)); + +	if (!rtlhal->bfw_ready) +		return; +	if (!rtlpriv->psc.b_fw_current_inpsmode) +		return; + +	while (1) { +		spin_lock_bh(&rtlpriv->locks.fw_ps_lock); +		if (rtlhal->bfw_clk_change_in_progress) { +			while (rtlhal->bfw_clk_change_in_progress) { +				spin_unlock_bh(&rtlpriv->locks.fw_ps_lock); +				count++; +				udelay(100); +				if (count > 1000) +					return; +				spin_lock_bh(&rtlpriv->locks.fw_ps_lock); +			} +			spin_unlock_bh(&rtlpriv->locks.fw_ps_lock); +		} else { +			rtlhal->bfw_clk_change_in_progress = false; +			spin_unlock_bh(&rtlpriv->locks.fw_ps_lock); +			break; +		} +	} + +	if (IS_IN_LOW_POWER_STATE_92E(rtlhal->fw_ps_state)) { +		rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_SET_RPWM, +					      (u8 *) (&rpwm_val)); +		if (FW_PS_IS_ACK(rpwm_val)) { +			isr_regaddr = REG_HISR; +			content = rtl_read_dword(rtlpriv, isr_regaddr); +			while (!(content & IMR_CPWM) && (count < 500)) { +				udelay(50); +				count++; +				content = rtl_read_dword(rtlpriv, isr_regaddr); +			} + +			if (content & IMR_CPWM) { +				rtl_write_word(rtlpriv , isr_regaddr, 0x0100); +				rtlhal->fw_ps_state = FW_PS_STATE_RF_ON_92E; +				RT_TRACE(COMP_POWER, DBG_LOUD, +					 ("Receive CPWM INT!!! PSState = %X\n", +					 rtlhal->fw_ps_state)); +			} +		} + +		spin_lock_bh(&rtlpriv->locks.fw_ps_lock); +		rtlhal->bfw_clk_change_in_progress = false; +		spin_unlock_bh(&rtlpriv->locks.fw_ps_lock); +		if (b_schedule_timer) { +			mod_timer(&rtlpriv->works.fw_clockoff_timer, +				  jiffies + MSECS(10)); +		} + +	} else  { +		spin_lock_bh(&rtlpriv->locks.fw_ps_lock); +		rtlhal->bfw_clk_change_in_progress = false; +		spin_unlock_bh(&rtlpriv->locks.fw_ps_lock); +	} + + +} + +static void _rtl92ee_set_fw_clock_off(struct ieee80211_hw *hw, u8 rpwm_val) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); +	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); +	struct rtl8192_tx_ring *ring; +	enum rf_pwrstate rtstate; +	bool b_schedule_timer = false; +	u8 queue; + +	if (!rtlhal->bfw_ready) +		return; +	if (!rtlpriv->psc.b_fw_current_inpsmode) +		return; +	if (!rtlhal->ballow_sw_to_change_hwclc) +		return; + +	rtlpriv->cfg->ops->get_hw_reg(hw , HW_VAR_RF_STATE , (u8 *)(&rtstate)); +	if (rtstate == ERFOFF || rtlpriv->psc.inactive_pwrstate == ERFOFF) +		return; + +	for (queue = 0; queue < RTL_PCI_MAX_TX_QUEUE_COUNT; queue++) { +		ring = &rtlpci->tx_ring[queue]; +		if (skb_queue_len(&ring->queue)) { +			b_schedule_timer = true; +			break; +		} +	} + +	if (b_schedule_timer) { +		mod_timer(&rtlpriv->works.fw_clockoff_timer, +			  jiffies + MSECS(10)); +		return; +	} + +	if (FW_PS_STATE(rtlhal->fw_ps_state) != FW_PS_STATE_RF_OFF_LOW_PWR) { +		spin_lock_bh(&rtlpriv->locks.fw_ps_lock); +		if (!rtlhal->bfw_clk_change_in_progress) { +			rtlhal->bfw_clk_change_in_progress = true; +			spin_unlock_bh(&rtlpriv->locks.fw_ps_lock); +			rtlhal->fw_ps_state = FW_PS_STATE(rpwm_val); +			rtl_write_word(rtlpriv, REG_HISR, 0x0100); +			rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SET_RPWM, +						      (u8 *) (&rpwm_val)); +			spin_lock_bh(&rtlpriv->locks.fw_ps_lock); +			rtlhal->bfw_clk_change_in_progress = false; +			spin_unlock_bh(&rtlpriv->locks.fw_ps_lock); +		} else { +			spin_unlock_bh(&rtlpriv->locks.fw_ps_lock); +			mod_timer(&rtlpriv->works.fw_clockoff_timer, +				  jiffies + MSECS(10)); +		} +	} +} + +static void _rtl92ee_set_fw_ps_rf_on(struct ieee80211_hw *hw) +{ +	u8 rpwm_val = 0; +	rpwm_val |= (FW_PS_STATE_RF_OFF_92E | FW_PS_ACK); +	_rtl92ee_set_fw_clock_on(hw, rpwm_val, true); +} + +static void _rtl92ee_set_fw_ps_rf_off_low_power(struct ieee80211_hw *hw) +{ +	u8 rpwm_val = 0; +	rpwm_val |= FW_PS_STATE_RF_OFF_LOW_PWR; +	_rtl92ee_set_fw_clock_off(hw, rpwm_val); +} +void rtl92ee_fw_clk_off_timer_callback(unsigned long data) +{ +	struct ieee80211_hw *hw = (struct ieee80211_hw *)data; + +	_rtl92ee_set_fw_ps_rf_off_low_power(hw); +} + +static void _rtl92ee_fwlps_leave(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); +	bool b_fw_current_inps = false; +	u8 rpwm_val = 0, fw_pwrmode = FW_PS_ACTIVE_MODE; + +	if (ppsc->b_low_power_enable) { +		rpwm_val = (FW_PS_STATE_ALL_ON_92E | FW_PS_ACK);/* RF on */ +		_rtl92ee_set_fw_clock_on(hw, rpwm_val, false); +		rtlhal->ballow_sw_to_change_hwclc = false; +		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_H2C_FW_PWRMODE, +					      (u8 *) (&fw_pwrmode)); +		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_FW_PSMODE_STATUS, +					      (u8 *) (&b_fw_current_inps)); +	} else { +		rpwm_val = FW_PS_STATE_ALL_ON_92E;	/* RF on */ +		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SET_RPWM, +					      (u8 *) (&rpwm_val)); +		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_H2C_FW_PWRMODE, +					      (u8 *) (&fw_pwrmode)); +		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_FW_PSMODE_STATUS, +					      (u8 *) (&b_fw_current_inps)); +	} +} + +static void _rtl92ee_fwlps_enter(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); +	bool b_fw_current_inps = true; +	u8 rpwm_val; + +	if (ppsc->b_low_power_enable) { +		rpwm_val = FW_PS_STATE_RF_OFF_LOW_PWR;	/* RF off */ +		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_FW_PSMODE_STATUS, +					      (u8 *) (&b_fw_current_inps)); +		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_H2C_FW_PWRMODE, +					      (u8 *) (&ppsc->fwctrl_psmode)); +		rtlhal->ballow_sw_to_change_hwclc = true; +		_rtl92ee_set_fw_clock_off(hw, rpwm_val); +	} else { +		rpwm_val = FW_PS_STATE_RF_OFF_92E;	/* RF off */ +		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_FW_PSMODE_STATUS, +					      (u8 *) (&b_fw_current_inps)); +		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_H2C_FW_PWRMODE, +					      (u8 *) (&ppsc->fwctrl_psmode)); +		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SET_RPWM, +					      (u8 *) (&rpwm_val)); +	} +} + +void rtl92ee_get_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); +	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + +	switch (variable) { +	case HW_VAR_RCR: +		*((u32 *) (val)) = rtlpci->receive_config; +		break; +	case HW_VAR_RF_STATE: +		*((enum rf_pwrstate *)(val)) = ppsc->rfpwr_state; +		break; +	case HW_VAR_FWLPS_RF_ON:{ +		enum rf_pwrstate rfState; +		u32 val_rcr; + +		rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_RF_STATE, +					      (u8 *) (&rfState)); +		if (rfState == ERFOFF) { +			*((bool *) (val)) = true; +		} else { +			val_rcr = rtl_read_dword(rtlpriv, REG_RCR); +			val_rcr &= 0x00070000; +			if (val_rcr) +				*((bool *) (val)) = false; +			else +				*((bool *) (val)) = true; +		} +		break; } +	case HW_VAR_FW_PSMODE_STATUS: +		*((bool *) (val)) = ppsc->b_fw_current_inpsmode; +		break; +	case HW_VAR_CORRECT_TSF:{ +		u64 tsf; +		u32 *ptsf_low = (u32 *) &tsf; +		u32 *ptsf_high = ((u32 *) &tsf) + 1; + +		*ptsf_high = rtl_read_dword(rtlpriv, (REG_TSFTR + 4)); +		*ptsf_low = rtl_read_dword(rtlpriv, REG_TSFTR); + +		*((u64 *) (val)) = tsf; + +		break; } +	default: +		RT_TRACE(COMP_ERR, DBG_LOUD, +			 ("switch case not process %x\n", variable)); +		break; +	} +} + +static void _rtl92ee_download_rsvd_page(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u8 tmp_regcr, tmp_reg422; +	u8 bcnvalid_reg, txbc_reg; +	u8 count = 0, dlbcn_count = 0; +	bool b_recover = false; + +	/*Set REG_CR bit 8. DMA beacon by SW.*/ +	tmp_regcr = rtl_read_byte(rtlpriv, REG_CR + 1); +	rtl_write_byte(rtlpriv, REG_CR + 1, tmp_regcr | BIT(0)); + +	/* Disable Hw protection for a time which revserd for Hw sending beacon. +	 * Fix download reserved page packet fail +	 * that access collision with the protection time. +	 * 2010.05.11. Added by tynli. */ +	_rtl92ee_set_bcn_ctrl_reg(hw, 0, BIT(3)); +	_rtl92ee_set_bcn_ctrl_reg(hw, BIT(4), 0); + +	/* Set FWHW_TXQ_CTRL 0x422[6]= 0 to +	 * tell Hw the packet is not a real beacon frame. +	 */ +	tmp_reg422 = rtl_read_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2); +	rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2, tmp_reg422 & (~BIT(6))); + +	if (tmp_reg422 & BIT(6)) +		b_recover = true; + +	do { +		/* Clear beacon valid check bit */ +		bcnvalid_reg = rtl_read_byte(rtlpriv, REG_DWBCN0_CTRL + 2); +		rtl_write_byte(rtlpriv, REG_DWBCN0_CTRL + 2, +			       bcnvalid_reg | BIT(0)); + +		/* Return Beacon TCB */ +		_rtl92ee_return_beacon_queue_skb(hw); + +		/* download rsvd page */ +		rtl92ee_set_fw_rsvdpagepkt(hw, false); + +		txbc_reg = rtl_read_byte(rtlpriv, REG_MGQ_TXBD_NUM + 3); +		count = 0; +		while ((txbc_reg & BIT(4)) && count < 20) { +			count++; +			udelay(10); +			txbc_reg = rtl_read_byte(rtlpriv, REG_MGQ_TXBD_NUM + 3); +		} +		rtl_write_byte(rtlpriv, REG_MGQ_TXBD_NUM + 3, +			       txbc_reg | BIT(4)); + +		/* check rsvd page download OK. */ +		bcnvalid_reg = rtl_read_byte(rtlpriv, REG_DWBCN0_CTRL + 2); +		count = 0; +		while (!(bcnvalid_reg & BIT(0)) && count < 20) { +			count++; +			udelay(50); +			bcnvalid_reg = rtl_read_byte(rtlpriv, +						     REG_DWBCN0_CTRL + 2); +		} + +		if (bcnvalid_reg & BIT(0)) +			rtl_write_byte(rtlpriv, REG_DWBCN0_CTRL + 2, BIT(0)); + +		dlbcn_count++; +	} while (!(bcnvalid_reg & BIT(0)) && dlbcn_count < 5); + +	if (!(bcnvalid_reg & BIT(0))) +		RT_TRACE(COMP_INIT, DBG_LOUD, ("Download RSVD page failed!\n")); + +	/* Enable Bcn */ +	_rtl92ee_set_bcn_ctrl_reg(hw, BIT(3), 0); +	_rtl92ee_set_bcn_ctrl_reg(hw, 0, BIT(4)); + +	if (b_recover) +		rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2, tmp_reg422); + +	tmp_regcr = rtl_read_byte(rtlpriv, REG_CR + 1); +	rtl_write_byte(rtlpriv, REG_CR + 1, tmp_regcr & (~BIT(0))); + +} + +void rtl92ee_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +	struct rtl_efuse *efuse = rtl_efuse(rtl_priv(hw)); +	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); +	u8 idx; + +	switch (variable) { +	case HW_VAR_ETHER_ADDR:{ +		for (idx = 0; idx < ETH_ALEN; idx++) { +			rtl_write_byte(rtlpriv, (REG_MACID + idx), val[idx]); +		} +		break; } +	case HW_VAR_BASIC_RATE:{ +		u16 b_rate_cfg = ((u16 *) val)[0]; +		b_rate_cfg = b_rate_cfg & 0x15f; +		b_rate_cfg |= 0x01; +		b_rate_cfg = (b_rate_cfg | 0xd) & (~BIT(1)); +		rtl_write_byte(rtlpriv, REG_RRSR, b_rate_cfg & 0xff); +		rtl_write_byte(rtlpriv, REG_RRSR + 1, (b_rate_cfg >> 8) & 0xff); +		break; } +	case HW_VAR_BSSID: +		for (idx = 0; idx < ETH_ALEN; idx++) { +			rtl_write_byte(rtlpriv, (REG_BSSID + idx), val[idx]); +		} +		break; +	case HW_VAR_SIFS: +		rtl_write_byte(rtlpriv, REG_SIFS_CTX + 1, val[0]); +		rtl_write_byte(rtlpriv, REG_SIFS_TRX + 1, val[1]); + +		rtl_write_byte(rtlpriv, REG_SPEC_SIFS + 1, val[0]); +		rtl_write_byte(rtlpriv, REG_MAC_SPEC_SIFS + 1, val[0]); + +		if (!mac->ht_enable) +			rtl_write_word(rtlpriv, REG_RESP_SIFS_OFDM, 0x0e0e); +		else +			rtl_write_word(rtlpriv, REG_RESP_SIFS_OFDM, +				       *((u16 *) val)); +		break; +	case HW_VAR_SLOT_TIME:{ +		u8 e_aci; + +		RT_TRACE(COMP_MLME, DBG_TRACE, +			 ("HW_VAR_SLOT_TIME %x\n", val[0])); + +		rtl_write_byte(rtlpriv, REG_SLOT, val[0]); + +		for (e_aci = 0; e_aci < AC_MAX; e_aci++) { +			rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_AC_PARAM, +						      (u8 *) (&e_aci)); +		} +		break; } +	case HW_VAR_ACK_PREAMBLE:{ +		u8 reg_tmp; +		u8 short_preamble = (bool) (*(u8 *) val); +		reg_tmp = (rtlpriv->mac80211.cur_40_prime_sc) << 5; +		if (short_preamble) +			reg_tmp |= 0x80; +		rtl_write_byte(rtlpriv, REG_RRSR + 2, reg_tmp); +		rtlpriv->mac80211.short_preamble = short_preamble; +		break; } +	case HW_VAR_WPA_CONFIG: +		rtl_write_byte(rtlpriv, REG_SECCFG, *((u8 *) val)); +		break; +	case HW_VAR_AMPDU_FACTOR:{ +		u8 regtoset_normal[4] = { 0x41, 0xa8, 0x72, 0xb9 }; +		u8 fac; +		u8 *reg = NULL; +		u8 i = 0; + +		reg = regtoset_normal; + +		fac = *((u8 *) val); +		if (fac <= 3) { +			fac = (1 << (fac + 2)); +			if (fac > 0xf) +				fac = 0xf; +				for (i = 0; i < 4; i++) { +				if ((reg[i] & 0xf0) > (fac << 4)) +					reg[i] = (reg[i] & 0x0f) | (fac << 4); +				if ((reg[i] & 0x0f) > fac) +					reg[i] = (reg[i] & 0xf0) | fac; +					rtl_write_byte(rtlpriv, +						       (REG_AGGLEN_LMT + i), +						       reg[i]); +				} +				RT_TRACE(COMP_MLME, DBG_LOUD, +					("Set HW_VAR_AMPDU_FACTOR:%#x\n", fac)); +		} +		break; } +	case HW_VAR_AC_PARAM:{ +		u8 e_aci = *((u8 *) val); + +		if (rtlpci->acm_method != eAcmWay2_SW) +			rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_ACM_CTRL, +						      (u8 *) (&e_aci)); +		break; } +	case HW_VAR_ACM_CTRL:{ +		u8 e_aci = *((u8 *) val); +		union aci_aifsn *aifs = (union aci_aifsn *)(&(mac->ac[0].aifs)); + +		u8 acm = aifs->f.acm; +		u8 acm_ctrl = rtl_read_byte(rtlpriv, REG_ACMHWCTRL); + +		acm_ctrl = acm_ctrl | ((rtlpci->acm_method == 2) ? 0x0 : 0x1); + +		if (acm) { +			switch (e_aci) { +			case AC0_BE: +				acm_ctrl |= AcmHw_BeqEn; +				break; +			case AC2_VI: +				acm_ctrl |= AcmHw_ViqEn; +				break; +			case AC3_VO: +				acm_ctrl |= AcmHw_VoqEn; +				break; +			default: +				RT_TRACE(COMP_ERR, DBG_WARNING, +					 ("HW_VAR_ACM_CTRL acm set " +					  "failed: eACI is %d\n", acm)); +				break; +			} +		} else { +			switch (e_aci) { +			case AC0_BE: +				acm_ctrl &= (~AcmHw_BeqEn); +				break; +			case AC2_VI: +				acm_ctrl &= (~AcmHw_ViqEn); +				break; +			case AC3_VO: +				acm_ctrl &= (~AcmHw_BeqEn); +				break; +			default: +				RT_TRACE(COMP_ERR, DBG_LOUD, +					 ("switch case not process \n")); +				break; +			} +		} + +		RT_TRACE(COMP_QOS, DBG_TRACE, +			 ("SetHwReg8190pci(): [HW_VAR_ACM_CTRL] Write 0x%X\n", +			  acm_ctrl)); +		rtl_write_byte(rtlpriv, REG_ACMHWCTRL, acm_ctrl); +		break; } +	case HW_VAR_RCR:{ +		rtl_write_dword(rtlpriv, REG_RCR, ((u32 *) (val))[0]); +		rtlpci->receive_config = ((u32 *) (val))[0]; +		break; } +	case HW_VAR_RETRY_LIMIT:{ +		u8 retry_limit = ((u8 *) (val))[0]; + +		rtl_write_word(rtlpriv, REG_RETRY_LIMIT, +			       retry_limit << RETRY_LIMIT_SHORT_SHIFT | +			       retry_limit << RETRY_LIMIT_LONG_SHIFT); +		break; } +	case HW_VAR_DUAL_TSF_RST: +		rtl_write_byte(rtlpriv, REG_DUAL_TSF_RST, (BIT(0) | BIT(1))); +		break; +	case HW_VAR_EFUSE_BYTES: +		efuse->efuse_usedbytes = *((u16 *) val); +		break; +	case HW_VAR_EFUSE_USAGE: +		efuse->efuse_usedpercentage = *((u8 *) val); +		break; +	case HW_VAR_IO_CMD: +		rtl92ee_phy_set_io_cmd(hw, (*(enum io_type *)val)); +		break; +	case HW_VAR_SET_RPWM:{ +		u8 rpwm_val; + +		rpwm_val = rtl_read_byte(rtlpriv, REG_PCIE_HRPWM); +		udelay(1); + +		if (rpwm_val & BIT(7)) { +			rtl_write_byte(rtlpriv, REG_PCIE_HRPWM, (*(u8 *) val)); +		} else { +			rtl_write_byte(rtlpriv, REG_PCIE_HRPWM, +				       ((*(u8 *) val) | BIT(7))); +		} +		break; } +	case HW_VAR_H2C_FW_PWRMODE: +		rtl92ee_set_fw_pwrmode_cmd(hw, (*(u8 *) val)); +		break; +	case HW_VAR_FW_PSMODE_STATUS: +		ppsc->b_fw_current_inpsmode = *((bool *) val); +		break; +	case HW_VAR_RESUME_CLK_ON: +		_rtl92ee_set_fw_ps_rf_on(hw); +		break; +	case HW_VAR_FW_LPS_ACTION:{ +		bool b_enter_fwlps = *((bool *) val); + +		if (b_enter_fwlps) +			_rtl92ee_fwlps_enter(hw); +		else +			_rtl92ee_fwlps_leave(hw); +		break; } +	case HW_VAR_H2C_FW_JOINBSSRPT:{ +		u8 mstatus = (*(u8 *) val); + +		if (mstatus == RT_MEDIA_CONNECT) { +			rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_AID, NULL); +			_rtl92ee_download_rsvd_page(hw); +		} +		rtl92ee_set_fw_media_status_rpt_cmd(hw, mstatus); +		break; } +	case HW_VAR_H2C_FW_P2P_PS_OFFLOAD: +		rtl92ee_set_p2p_ps_offload_cmd(hw , (*(u8 *) val)); +		break; +	case HW_VAR_AID:{ +		u16 u2btmp; +		u2btmp = rtl_read_word(rtlpriv, REG_BCN_PSR_RPT); +		u2btmp &= 0xC000; +		rtl_write_word(rtlpriv, REG_BCN_PSR_RPT, +			       (u2btmp | mac->assoc_id)); +		break; } +	case HW_VAR_CORRECT_TSF:{ +		u8 btype_ibss = ((u8 *) (val))[0]; + +		if (btype_ibss == true) +			_rtl92ee_stop_tx_beacon(hw); + +		_rtl92ee_set_bcn_ctrl_reg(hw, 0, BIT(3)); + +		rtl_write_dword(rtlpriv, REG_TSFTR, +				(u32) (mac->tsf & 0xffffffff)); +		rtl_write_dword(rtlpriv, REG_TSFTR + 4, +				(u32) ((mac->tsf >> 32) & 0xffffffff)); + +		_rtl92ee_set_bcn_ctrl_reg(hw, BIT(3), 0); + +		if (btype_ibss == true) +			_rtl92ee_resume_tx_beacon(hw); +		break; } +	case HW_VAR_KEEP_ALIVE: { +		u8 array[2]; +		array[0] = 0xff; +		array[1] = *((u8 *)val); +		rtl92ee_fill_h2c_cmd(hw, H2C_92E_KEEP_ALIVE_CTRL, 2, array); +		break; } +	default: +		RT_TRACE(COMP_ERR, DBG_LOUD, +			 ("switch case not process %x\n", variable)); +		break; +	} +} + +static bool _rtl92ee_llt_table_init(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u8 txpktbuf_bndy; +	u8 u8tmp, testcnt = 0; + +	txpktbuf_bndy = 0xFA; + +	rtl_write_dword(rtlpriv, REG_RQPN, 0x80E90808); + +	rtl_write_byte(rtlpriv, REG_TRXFF_BNDY, txpktbuf_bndy); +	rtl_write_word(rtlpriv, REG_TRXFF_BNDY + 2, 0x3d00 - 1); + +	rtl_write_byte(rtlpriv, REG_DWBCN0_CTRL + 1, txpktbuf_bndy); +	rtl_write_byte(rtlpriv, REG_DWBCN1_CTRL + 1, txpktbuf_bndy); + +	rtl_write_byte(rtlpriv, REG_BCNQ_BDNY, txpktbuf_bndy); +	rtl_write_byte(rtlpriv, REG_BCNQ1_BDNY, txpktbuf_bndy); + +	rtl_write_byte(rtlpriv, REG_MGQ_BDNY, txpktbuf_bndy); +	rtl_write_byte(rtlpriv, 0x45D, txpktbuf_bndy); + +	rtl_write_byte(rtlpriv, REG_PBP, 0x31); +	rtl_write_byte(rtlpriv, REG_RX_DRVINFO_SZ, 0x4); + +	u8tmp = rtl_read_byte(rtlpriv, REG_AUTO_LLT + 2); +	rtl_write_byte(rtlpriv, REG_AUTO_LLT + 2, u8tmp | BIT(0)); + +	while (u8tmp & BIT(0)) { +		u8tmp = rtl_read_byte(rtlpriv, REG_AUTO_LLT + 2); +		udelay(10); +		testcnt++; +		if (testcnt > 10) +			break; +	} + +	return true; +} + +static void _rtl92ee_gen_refresh_led_state(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); +	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); +	struct rtl_led *pLed0 = &(pcipriv->ledctl.sw_led0); + +	if (rtlpriv->rtlhal.up_first_time) +		return; + +	if (ppsc->rfoff_reason == RF_CHANGE_BY_IPS) +		rtl92ee_sw_led_on(hw, pLed0); +	else if (ppsc->rfoff_reason == RF_CHANGE_BY_INIT) +		rtl92ee_sw_led_on(hw, pLed0); +	else +		rtl92ee_sw_led_off(hw, pLed0); +} + +static bool _rtl92ee_init_mac(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + +	u8 bytetmp; +	u16 wordtmp; +	u32 dwordtmp; + +	rtl_write_byte(rtlpriv, REG_RSV_CTRL, 0x0); + +	dwordtmp = rtl_read_dword(rtlpriv, REG_SYS_CFG1); +	if (dwordtmp & BIT(24)) { +		rtl_write_byte(rtlpriv, 0x7c, 0xc3); +	} else { +		bytetmp = rtl_read_byte(rtlpriv, 0x16); +		rtl_write_byte(rtlpriv, 0x16, bytetmp | BIT(4) | BIT(6)); +		rtl_write_byte(rtlpriv, 0x7c, 0x83); +	} +	/* 1. 40Mhz crystal source*/ +	bytetmp = rtl_read_byte(rtlpriv, REG_AFE_CTRL2); +	bytetmp &= 0xfb; +	rtl_write_byte(rtlpriv, REG_AFE_CTRL2, bytetmp); + +	dwordtmp = rtl_read_dword(rtlpriv, REG_AFE_CTRL4); +	dwordtmp &= 0xfffffc7f; +	rtl_write_dword(rtlpriv, REG_AFE_CTRL4, dwordtmp); + +	/* 2. 92E AFE parameter +	  *MP chip then check version */ +	bytetmp = rtl_read_byte(rtlpriv, REG_AFE_CTRL2); +	bytetmp &= 0xbf; +	rtl_write_byte(rtlpriv, REG_AFE_CTRL2, bytetmp); + +	dwordtmp = rtl_read_dword(rtlpriv, REG_AFE_CTRL4); +	dwordtmp &= 0xffdfffff; +	rtl_write_dword(rtlpriv, REG_AFE_CTRL4, dwordtmp); + +	/* HW Power on sequence */ +	if (!rtl92e_hal_pwrseqcmdparsing(rtlpriv, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, +		PWR_INTF_PCI_MSK, Rtl8192E_NIC_ENABLE_FLOW)) { +		RT_TRACE(COMP_INIT, DBG_LOUD, +			 ("init MAC Fail as rtl92e_hal_pwrseqcmdparsing\n")); +		return false; +	} + +	/* Release MAC IO register reset */ +	bytetmp = rtl_read_byte(rtlpriv, REG_CR); +	bytetmp = 0xff; +	rtl_write_byte(rtlpriv, REG_CR, bytetmp); +	mdelay(2); +	bytetmp = 0x7f; +	rtl_write_byte(rtlpriv, REG_HWSEQ_CTRL, bytetmp); +	mdelay(2); + +	/* Add for wakeup online */ +	bytetmp = rtl_read_byte(rtlpriv, REG_SYS_CLKR); +	rtl_write_byte(rtlpriv, REG_SYS_CLKR, bytetmp | BIT(3)); +	bytetmp = rtl_read_byte(rtlpriv, REG_GPIO_MUXCFG + 1); +	rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG + 1, bytetmp & (~BIT(4))); +	/* Release MAC IO register reset */ +	rtl_write_word(rtlpriv, REG_CR, 0x2ff); + +	if (!rtlhal->b_mac_func_enable) { +		if (_rtl92ee_llt_table_init(hw) == false) { +			RT_TRACE(COMP_INIT, DBG_LOUD, +				 ("LLT table init fail \n")); +			return false; +		} +	} + +	rtl_write_dword(rtlpriv, REG_HISR, 0xffffffff); +	rtl_write_dword(rtlpriv, REG_HISRE, 0xffffffff); + +	wordtmp = rtl_read_word(rtlpriv, REG_TRXDMA_CTRL); +	wordtmp &= 0xf; +	wordtmp |= 0xF5B1; +	rtl_write_word(rtlpriv, REG_TRXDMA_CTRL, wordtmp); +	/* Reported Tx status from HW for rate adaptive.*/ +	rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 1, 0x1F); + +	/* Set RCR register */ +	rtl_write_dword(rtlpriv, REG_RCR, rtlpci->receive_config); +	rtl_write_word(rtlpriv, REG_RXFLTMAP2, 0xffff); + +	/* Set TCR register */ +	rtl_write_dword(rtlpriv, REG_TCR, rtlpci->transmit_config); + +	/* Set TX/RX descriptor physical address(from OS API). */ +	rtl_write_dword(rtlpriv, REG_BCNQ_DESA, +			((u64) rtlpci->tx_ring[BEACON_QUEUE].buffer_desc_dma) & +			DMA_BIT_MASK(32)); +	rtl_write_dword(rtlpriv, REG_MGQ_DESA, +			(u64) rtlpci->tx_ring[MGNT_QUEUE].buffer_desc_dma & +			DMA_BIT_MASK(32)); +	rtl_write_dword(rtlpriv, REG_VOQ_DESA, +			(u64) rtlpci->tx_ring[VO_QUEUE].buffer_desc_dma & +			DMA_BIT_MASK(32)); +	rtl_write_dword(rtlpriv, REG_VIQ_DESA, +			(u64) rtlpci->tx_ring[VI_QUEUE].buffer_desc_dma & +			DMA_BIT_MASK(32)); + +	rtl_write_dword(rtlpriv, REG_BEQ_DESA, +			(u64) rtlpci->tx_ring[BE_QUEUE].buffer_desc_dma & +			DMA_BIT_MASK(32)); + +	dwordtmp = rtl_read_dword(rtlpriv, REG_BEQ_DESA); + +	rtl_write_dword(rtlpriv, REG_BKQ_DESA, +			(u64) rtlpci->tx_ring[BK_QUEUE].buffer_desc_dma & +			DMA_BIT_MASK(32)); +	rtl_write_dword(rtlpriv, REG_HQ0_DESA, +			(u64) rtlpci->tx_ring[HIGH_QUEUE].buffer_desc_dma & +			DMA_BIT_MASK(32)); + +	rtl_write_dword(rtlpriv, REG_RX_DESA, +			(u64) rtlpci->rx_ring[RX_MPDU_QUEUE].dma & +			DMA_BIT_MASK(32)); + +	/* if we want to support 64 bit DMA, we should set it here, +	 * but now we do not support 64 bit DMA*/ + + +	rtl_write_dword(rtlpriv, REG_TSFTIMER_HCI, 0x3fffffff); + +	bytetmp = rtl_read_byte(rtlpriv, REG_PCIE_CTRL_REG + 3); +	rtl_write_byte(rtlpriv, REG_PCIE_CTRL_REG + 3, bytetmp | 0xF7); + +	rtl_write_dword(rtlpriv, REG_INT_MIG, 0); + +	rtl_write_dword(rtlpriv, REG_MCUTST_1, 0x0); + +	rtl_write_word(rtlpriv, REG_MGQ_TXBD_NUM, +		       TX_DESC_NUM_92E | ((RTL8192EE_SEG_NUM << 12) & 0x3000)); +	rtl_write_word(rtlpriv, REG_VOQ_TXBD_NUM, +		       TX_DESC_NUM_92E | ((RTL8192EE_SEG_NUM << 12) & 0x3000)); +	rtl_write_word(rtlpriv, REG_VIQ_TXBD_NUM, +		       TX_DESC_NUM_92E | ((RTL8192EE_SEG_NUM << 12) & 0x3000)); +	rtl_write_word(rtlpriv, REG_BEQ_TXBD_NUM, +		       TX_DESC_NUM_92E | ((RTL8192EE_SEG_NUM << 12) & 0x3000)); +	rtl_write_word(rtlpriv, REG_VOQ_TXBD_NUM, +		       TX_DESC_NUM_92E | ((RTL8192EE_SEG_NUM << 12) & 0x3000)); +	rtl_write_word(rtlpriv, REG_BKQ_TXBD_NUM, +		       TX_DESC_NUM_92E | ((RTL8192EE_SEG_NUM << 12) & 0x3000)); +	rtl_write_word(rtlpriv, REG_HI0Q_TXBD_NUM, +		       TX_DESC_NUM_92E | ((RTL8192EE_SEG_NUM << 12) & 0x3000)); +	rtl_write_word(rtlpriv, REG_HI1Q_TXBD_NUM, +		       TX_DESC_NUM_92E | ((RTL8192EE_SEG_NUM << 12) & 0x3000)); +	rtl_write_word(rtlpriv, REG_HI2Q_TXBD_NUM, +		       TX_DESC_NUM_92E | ((RTL8192EE_SEG_NUM << 12) & 0x3000)); +	rtl_write_word(rtlpriv, REG_HI3Q_TXBD_NUM, +		       TX_DESC_NUM_92E | ((RTL8192EE_SEG_NUM << 12) & 0x3000)); +	rtl_write_word(rtlpriv, REG_HI4Q_TXBD_NUM, +		       TX_DESC_NUM_92E | ((RTL8192EE_SEG_NUM << 12) & 0x3000)); +	rtl_write_word(rtlpriv, REG_HI5Q_TXBD_NUM, +		       TX_DESC_NUM_92E | ((RTL8192EE_SEG_NUM << 12) & 0x3000)); +	rtl_write_word(rtlpriv, REG_HI6Q_TXBD_NUM, +		       TX_DESC_NUM_92E | ((RTL8192EE_SEG_NUM << 12) & 0x3000)); +	rtl_write_word(rtlpriv, REG_HI7Q_TXBD_NUM, +		       TX_DESC_NUM_92E | ((RTL8192EE_SEG_NUM << 12) & 0x3000)); +	/*Rx*/ +#if (DMA_IS_64BIT == 1) +	rtl_write_word(rtlpriv, REG_RX_RXBD_NUM, +		       RX_DESC_NUM_92E | +		       ((RTL8192EE_SEG_NUM << 13) & 0x6000) | 0x8000); +#else +	rtl_write_word(rtlpriv, REG_RX_RXBD_NUM, +		       RX_DESC_NUM_92E | +		       ((RTL8192EE_SEG_NUM << 13) & 0x6000) | 0x0000); +#endif + +	rtl_write_dword(rtlpriv, REG_TSFTIMER_HCI, 0XFFFFFFFF); + +	_rtl92ee_gen_refresh_led_state(hw); +	return true; +} + +static void _rtl92ee_hw_configure(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); +	u32 reg_rrsr; + +	reg_rrsr = RATE_ALL_CCK | RATE_ALL_OFDM_AG; +	/* Init value for RRSR. */ +	rtl_write_dword(rtlpriv, REG_RRSR, reg_rrsr); + +	/* ARFB table 9 for 11ac 5G 2SS */ +	rtl_write_dword(rtlpriv, REG_ARFR0, 0x00000010); +	rtl_write_dword(rtlpriv, REG_ARFR0 + 4, 0x3e0ff000); + +	/* ARFB table 10 for 11ac 5G 1SS */ +	rtl_write_dword(rtlpriv, REG_ARFR1, 0x00000010); +	rtl_write_dword(rtlpriv, REG_ARFR1 + 4, 0x000ff000); + +	/* Set SLOT time */ +	rtl_write_byte(rtlpriv, REG_SLOT, 0x09); + +	/* CF-End setting. */ +	rtl_write_word(rtlpriv, REG_FWHW_TXQ_CTRL, 0x1F80); + +	/* Set retry limit */ +	rtl_write_word(rtlpriv, REG_RETRY_LIMIT, 0x0707); + +	/* BAR settings */ +	rtl_write_dword(rtlpriv, REG_BAR_MODE_CTRL, 0x0201ffff); + +	/* Set Data / Response auto rate fallack retry count */ +	rtl_write_dword(rtlpriv, REG_DARFRC, 0x01000000); +	rtl_write_dword(rtlpriv, REG_DARFRC + 4, 0x07060504); +	rtl_write_dword(rtlpriv, REG_RARFRC, 0x01000000); +	rtl_write_dword(rtlpriv, REG_RARFRC + 4, 0x07060504); + +	/* Beacon related, for rate adaptive */ +	rtl_write_byte(rtlpriv, REG_ATIMWND, 0x2); +	rtl_write_byte(rtlpriv, REG_BCN_MAX_ERR, 0xff); + +	rtlpci->reg_bcn_ctrl_val = 0x1d; +	rtl_write_byte(rtlpriv, REG_BCN_CTRL, rtlpci->reg_bcn_ctrl_val); + +	/* Marked out by Bruce, 2010-09-09. +	 * This register is configured for the 2nd Beacon (multiple BSSID). +	 * We shall disable this register if we only support 1 BSSID. +	 * vivi guess 92d also need this, also 92d now doesnot set this reg +	 */ +	rtl_write_byte(rtlpriv, REG_BCN_CTRL_1, 0); + +	/* TBTT prohibit hold time. Suggested by designer TimChen. */ +	rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 1 , 0xff); /* 8 ms */ + +	rtl_write_byte(rtlpriv, REG_PIFS, 0); +	rtl_write_byte(rtlpriv, REG_AGGR_BREAK_TIME, 0x16); + +	rtl_write_word(rtlpriv, REG_NAV_PROT_LEN, 0x0040); +	rtl_write_word(rtlpriv, REG_PROT_MODE_CTRL, 0x08ff); + +	/* For Rx TP. Suggested by SD1 Richard. Added by tynli. 2010.04.12.*/ +	rtl_write_dword(rtlpriv, REG_FAST_EDCA_CTRL, 0x03086666); + +	/* ACKTO for IOT issue. */ +	rtl_write_byte(rtlpriv, REG_ACKTO, 0x40); + +	/* Set Spec SIFS (used in NAV) */ +	rtl_write_word(rtlpriv, REG_SPEC_SIFS, 0x100a); +	rtl_write_word(rtlpriv, REG_MAC_SPEC_SIFS, 0x100a); + +	/* Set SIFS for CCK */ +	rtl_write_word(rtlpriv, REG_SIFS_CTX, 0x100a); + +	/* Set SIFS for OFDM */ +	rtl_write_word(rtlpriv, REG_SIFS_TRX, 0x100a); + +	/* Note Data sheet don't define */ +	rtl_write_word(rtlpriv, 0x4C7, 0x80); + +	rtl_write_byte(rtlpriv, REG_RX_PKT_LIMIT, 0x20); + +	rtl_write_word(rtlpriv, REG_MAX_AGGR_NUM, 0x1717); + +	/* Set Multicast Address. 2009.01.07. by tynli. */ +	rtl_write_dword(rtlpriv, REG_MAR, 0xffffffff); +	rtl_write_dword(rtlpriv, REG_MAR + 4, 0xffffffff); +} + +static void _rtl92ee_enable_aspm_back_door(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); +	u32 tmp32 = 0, count = 0; +	u8 tmp8 = 0; + +	rtl_write_word(rtlpriv, REG_BACKDOOR_DBI_DATA, 0x78); +	rtl_write_byte(rtlpriv, REG_BACKDOOR_DBI_DATA + 2, 0x2); +	tmp8 = rtl_read_byte(rtlpriv, REG_BACKDOOR_DBI_DATA + 2); +	count = 0; +	while (tmp8 && count < 20) { +		udelay(10); +		tmp8 = rtl_read_byte(rtlpriv, REG_BACKDOOR_DBI_DATA + 2); +		count++; +	} + +	if (0 == tmp8) { +		tmp32 = rtl_read_dword(rtlpriv, REG_BACKDOOR_DBI_RDATA); +		if ((tmp32 & 0xff00) != 0x2000) { +			tmp32 &= 0xffff00ff; +			rtl_write_dword(rtlpriv, REG_BACKDOOR_DBI_WDATA, +					tmp32 | BIT(13)); +			rtl_write_word(rtlpriv, REG_BACKDOOR_DBI_DATA, 0xf078); +			rtl_write_byte(rtlpriv, REG_BACKDOOR_DBI_DATA + 2, 0x1); + +			tmp8 = rtl_read_byte(rtlpriv , REG_BACKDOOR_DBI_DATA + 2); +			count = 0; +			while (tmp8 && count < 20) { +				udelay(10); +				tmp8 = rtl_read_byte(rtlpriv, +						     REG_BACKDOOR_DBI_DATA + 2); +				count++; +			} +		} +	} + +	rtl_write_word(rtlpriv, REG_BACKDOOR_DBI_DATA, 0x70c); +	rtl_write_byte(rtlpriv, REG_BACKDOOR_DBI_DATA + 2, 0x2); +	tmp8 = rtl_read_byte(rtlpriv, REG_BACKDOOR_DBI_DATA + 2); +	count = 0; +	while (tmp8 && count < 20) { +		udelay(10); +		tmp8 = rtl_read_byte(rtlpriv, REG_BACKDOOR_DBI_DATA + 2); +		count++; +	} +	if (0 == tmp8) { +		tmp32 = rtl_read_dword(rtlpriv, REG_BACKDOOR_DBI_RDATA); +		rtl_write_dword(rtlpriv, REG_BACKDOOR_DBI_WDATA, +				tmp32 | BIT(31)); +		rtl_write_word(rtlpriv, REG_BACKDOOR_DBI_DATA, 0xf70c); +		rtl_write_byte(rtlpriv, REG_BACKDOOR_DBI_DATA + 2, 0x1); +	} + +	tmp8 = rtl_read_byte(rtlpriv, REG_BACKDOOR_DBI_DATA + 2); +	count = 0; +	while (tmp8 && count < 20) { +		udelay(10); +		tmp8 = rtl_read_byte(rtlpriv, REG_BACKDOOR_DBI_DATA + 2); +		count++; +	} + + +	rtl_write_word(rtlpriv, REG_BACKDOOR_DBI_DATA, 0x718); +	rtl_write_byte(rtlpriv, REG_BACKDOOR_DBI_DATA + 2, 0x2); +	tmp8 = rtl_read_byte(rtlpriv, REG_BACKDOOR_DBI_DATA + 2); +	count = 0; +	while (tmp8 && count < 20) { +		udelay(10); +		tmp8 = rtl_read_byte(rtlpriv, REG_BACKDOOR_DBI_DATA + 2); +		count++; +	} +	if (ppsc->b_support_backdoor || (0 == tmp8)) { +		tmp32 = rtl_read_dword(rtlpriv, REG_BACKDOOR_DBI_RDATA); +		rtl_write_dword(rtlpriv, REG_BACKDOOR_DBI_WDATA, +				tmp32 | BIT(11) | BIT(12)); +		rtl_write_word(rtlpriv, REG_BACKDOOR_DBI_DATA, 0xf718); +		rtl_write_byte(rtlpriv, REG_BACKDOOR_DBI_DATA + 2, 0x1); +	} +	tmp8 = rtl_read_byte(rtlpriv, REG_BACKDOOR_DBI_DATA + 2); +	count = 0; +	while (tmp8 && count < 20) { +		udelay(10); +		tmp8 = rtl_read_byte(rtlpriv, REG_BACKDOOR_DBI_DATA + 2); +		count++; +	} +} + +void rtl92ee_enable_hw_security_config(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u8 sec_reg_value; +	u8 tmp; + +	RT_TRACE(COMP_INIT, DBG_DMESG, +		 ("PairwiseEncAlgorithm = %d GroupEncAlgorithm = %d\n", +		  rtlpriv->sec.pairwise_enc_algorithm, +		  rtlpriv->sec.group_enc_algorithm)); + +	if (rtlpriv->cfg->mod_params->sw_crypto || rtlpriv->sec.use_sw_sec) { +		RT_TRACE(COMP_SEC, DBG_DMESG, ("not open hw encryption\n")); +		return; +	} + +	sec_reg_value = SCR_TxEncEnable | SCR_RxDecEnable; + +	if (rtlpriv->sec.use_defaultkey) { +		sec_reg_value |= SCR_TxUseDK; +		sec_reg_value |= SCR_RxUseDK; +	} + +	sec_reg_value |= (SCR_RXBCUSEDK | SCR_TXBCUSEDK); + +	tmp = rtl_read_byte(rtlpriv, REG_CR + 1); +	rtl_write_byte(rtlpriv, REG_CR + 1, tmp | BIT(1)); + +	RT_TRACE(COMP_SEC, DBG_DMESG, +		 ("The SECR-value %x \n", sec_reg_value)); + +	rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_WPA_CONFIG, &sec_reg_value); + +} + +int rtl92ee_hw_init(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); +	bool rtstatus = true; +	int err = 0; +	u8 tmp_u1b , u1byte; +	u32 tmp_u4b; + +	RT_TRACE(COMP_INIT , DBG_LOUD , (" Rtl8192EE hw init\n")); +	rtlpriv->rtlhal.being_init_adapter = true; +	rtlpriv->intf_ops->disable_aspm(hw); + +	tmp_u1b = rtl_read_byte(rtlpriv, REG_SYS_CLKR+1); +	u1byte = rtl_read_byte(rtlpriv, REG_CR); +	if ((tmp_u1b & BIT(3)) && (u1byte != 0 && u1byte != 0xEA)) { +		rtlhal->b_mac_func_enable = true; +	} else { +		rtlhal->b_mac_func_enable = false; +		rtlhal->fw_ps_state = FW_PS_STATE_ALL_ON_92E; +	} + +	rtstatus = _rtl92ee_init_mac(hw); + +	rtl_write_byte(rtlpriv, 0x577, 0x03); + +	/*for Crystal 40 Mhz setting */ +	rtl_write_byte(rtlpriv, REG_AFE_CTRL4, 0x2A); +	rtl_write_byte(rtlpriv, REG_AFE_CTRL4 + 1, 0x00); +	rtl_write_byte(rtlpriv, REG_AFE_CTRL2, 0x83); + +	/*Forced the antenna b to wifi */ +	if (rtlpriv->btcoexist.btc_info.btcoexist == 1) { +		rtl_write_byte(rtlpriv, 0x64, 0); +		rtl_write_byte(rtlpriv, 0x65, 1); +	} +	if (rtstatus != true) { +		RT_TRACE(COMP_ERR, DBG_EMERG, ("Init MAC failed\n")); +		err = 1; +		return err; +	} +	rtlhal->rx_tag = 0; +	rtl_write_word(rtlpriv, REG_PCIE_CTRL_REG, 0x8000); +	err = rtl92ee_download_fw(hw , false); +	if (err) { +		RT_TRACE(COMP_ERR, DBG_WARNING, +			 ("Failed to download FW. Init HW without FW now..\n")); +		err = 1; +		rtlhal->bfw_ready = false; +		return err; +	} else { +		rtlhal->bfw_ready = true; +	} +	/*fw related variable initialize */ +	ppsc->b_fw_current_inpsmode = false; +	rtlhal->fw_ps_state = FW_PS_STATE_ALL_ON_92E; +	rtlhal->bfw_clk_change_in_progress = false; +	rtlhal->ballow_sw_to_change_hwclc = false; +	rtlhal->last_hmeboxnum = 0; + + +	rtl92ee_phy_mac_config(hw); + +	rtl92ee_phy_bb_config(hw); + +	rtl92ee_phy_rf_config(hw); + +	rtlphy->rfreg_chnlval[0] = rtl_get_rfreg(hw, RF90_PATH_A, +						 RF_CHNLBW, RFREG_OFFSET_MASK); +	rtlphy->rfreg_chnlval[1] = rtl_get_rfreg(hw, RF90_PATH_B, +						 RF_CHNLBW, RFREG_OFFSET_MASK); +	rtlphy->backup_rf_0x1a = (u32) rtl_get_rfreg(hw, RF90_PATH_A, RF_RX_G1, +						     RFREG_OFFSET_MASK); +	rtlphy->rfreg_chnlval[0] = (rtlphy->rfreg_chnlval[0] & 0xfffff3ff) | +				   BIT(10) | BIT(11); + +	rtl_set_rfreg(hw, RF90_PATH_A, RF_CHNLBW, RFREG_OFFSET_MASK, +		      rtlphy->rfreg_chnlval[0]); +	rtl_set_rfreg(hw, RF90_PATH_B, RF_CHNLBW, RFREG_OFFSET_MASK, +		      rtlphy->rfreg_chnlval[0]); + +	/*---- Set CCK and OFDM Block "ON"----*/ +	rtl_set_bbreg(hw, RFPGA0_RFMOD, BCCKEN, 0x1); +	rtl_set_bbreg(hw, RFPGA0_RFMOD, BOFDMEN, 0x1); + +	/* Must set this, +	 * otherwise the rx sensitivity will be very pool. Maddest +	 */ +	rtl_set_rfreg(hw, RF90_PATH_A, 0xB1, RFREG_OFFSET_MASK, 0x54418); + +	/*Set Hardware(MAC default setting.)*/ +	_rtl92ee_hw_configure(hw); + +	rtlhal->b_mac_func_enable = true; + +	stg_rtl_cam_reset_all_entry(hw); +	rtl92ee_enable_hw_security_config(hw); + +	ppsc->rfpwr_state = ERFON; + +	rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_ETHER_ADDR, mac->mac_addr); +	_rtl92ee_enable_aspm_back_door(hw); +	rtlpriv->intf_ops->enable_aspm(hw); + +	rtl92ee_bt_hw_init(hw); + +	rtlpriv->rtlhal.being_init_adapter = false; + +	if (ppsc->rfpwr_state == ERFON) { +		if (rtlphy->iqk_initialized) { +			rtl92ee_phy_iq_calibrate(hw, true); +		} else { +			rtl92ee_phy_iq_calibrate(hw, false); +			rtlphy->iqk_initialized = true; +		} +	} + +	rtlphy->rfpath_rx_enable[0] = true; +	if (rtlphy->rf_type == RF_2T2R) +		rtlphy->rfpath_rx_enable[1] = true; + +	stg_efuse_one_byte_read(hw, 0x1FA, &tmp_u1b); +	if (!(tmp_u1b & BIT(0))) { +		rtl_set_rfreg(hw, RF90_PATH_A, 0x15, 0x0F, 0x05); +		RT_TRACE(COMP_INIT, DBG_LOUD, ("PA BIAS path A\n")); +	} + +	if ((!(tmp_u1b & BIT(1))) && (rtlphy->rf_type == RF_2T2R)) { +		rtl_set_rfreg(hw, RF90_PATH_B, 0x15, 0x0F, 0x05); +		RT_TRACE(COMP_INIT, DBG_LOUD, ("PA BIAS path B\n")); +	} + +	rtl_write_byte(rtlpriv, REG_NAV_UPPER, ((30000 + 127) / 128)); + +	/*Fixed LDPC rx hang issue. */ +	tmp_u4b = rtl_read_dword(rtlpriv, REG_SYS_SWR_CTRL1); +	rtl_write_byte(rtlpriv, REG_SYS_SWR_CTRL2, 0x75); +	tmp_u4b =  (tmp_u4b & 0xfff00fff) | (0x7E << 12); +	rtl_write_dword(rtlpriv, REG_SYS_SWR_CTRL1, tmp_u4b); + +	rtl92ee_dm_init(hw); + +	rtl_write_dword(rtlpriv, 0x4fc, 0); + +	RT_TRACE(COMP_INIT , DBG_LOUD , ("end of Rtl8192EE hw init %x\n" , err)); +	return 0; +} + +static enum version_8192e _rtl92ee_read_chip_version(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	enum version_8192e version = VERSION_UNKNOWN; +	u32 value32; + +	rtlphy->rf_type = RF_2T2R; + +	value32 = rtl_read_dword(rtlpriv, REG_SYS_CFG1); +	if (value32 & TRP_VAUX_EN) +		version = (enum version_8192e) VERSION_TEST_CHIP_2T2R_8192E; +	else +		version = (enum version_8192e) VERSION_NORMAL_CHIP_2T2R_8192E; + +	RT_TRACE(COMP_INIT, DBG_LOUD, +		 ("Chip RF Type: %s\n", (rtlphy->rf_type == RF_2T2R) ? +		  "RF_2T2R" : "RF_1T1R")); + +	return version; +} + +static int _rtl92ee_set_media_status(struct ieee80211_hw *hw, +				     enum nl80211_iftype type) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u8 bt_msr = rtl_read_byte(rtlpriv, MSR); +	enum led_ctl_mode ledaction = LED_CTL_NO_LINK; +	u8 mode = MSR_NOLINK; +	bt_msr &= 0xfc; + +	switch (type) { +	case NL80211_IFTYPE_UNSPECIFIED: +		mode = MSR_NOLINK; +		RT_TRACE(COMP_INIT, DBG_TRACE, +			 ("Set Network type to NO LINK!\n")); +		break; +	case NL80211_IFTYPE_ADHOC: +	case NL80211_IFTYPE_MESH_POINT: +		mode = MSR_ADHOC; +		RT_TRACE(COMP_INIT, DBG_TRACE, +			 ("Set Network type to Ad Hoc!\n")); +		break; +	case NL80211_IFTYPE_STATION: +		mode = MSR_INFRA; +		ledaction = LED_CTL_LINK; +		RT_TRACE(COMP_INIT, DBG_TRACE, +			 ("Set Network type to STA!\n")); +		break; +	case NL80211_IFTYPE_AP: +		mode = MSR_AP; +		ledaction = LED_CTL_LINK; +		RT_TRACE(COMP_INIT, DBG_TRACE, +			 ("Set Network type to AP!\n")); +		break; +	default: +		RT_TRACE(COMP_ERR, DBG_EMERG, +			 ("Network type %d not support!\n", type)); +		return 1; +		break; +	} + +	/* MSR_INFRA == Link in infrastructure network; +	 * MSR_ADHOC == Link in ad hoc network; +	 * Therefore, check link state is necessary. +	 * +	 * MSR_AP == AP mode; link state is not cared here. +	 */ +	if (mode != MSR_AP && rtlpriv->mac80211.link_state < MAC80211_LINKED) { +		mode = MSR_NOLINK; +		ledaction = LED_CTL_NO_LINK; +	} + +	if (mode == MSR_NOLINK || mode == MSR_INFRA) { +		_rtl92ee_stop_tx_beacon(hw); +		_rtl92ee_enable_bcn_sub_func(hw); +	} else if (mode == MSR_ADHOC || mode == MSR_AP) { +		_rtl92ee_resume_tx_beacon(hw); +		_rtl92ee_disable_bcn_sub_func(hw); +	} else { +		RT_TRACE(COMP_ERR, DBG_WARNING, +			 ("Set HW_VAR_MEDIA_STATUS: " +			  "No such media status(%x).\n", mode)); +	} + +	rtl_write_byte(rtlpriv, (MSR), bt_msr | mode); +	rtlpriv->cfg->ops->led_control(hw, ledaction); +	if (mode == MSR_AP) +		rtl_write_byte(rtlpriv, REG_BCNTCFG + 1, 0x00); +	else +		rtl_write_byte(rtlpriv, REG_BCNTCFG + 1, 0x66); +	return 0; +} + +void rtl92ee_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); +	u32 reg_rcr = rtlpci->receive_config; + +	if (rtlpriv->psc.rfpwr_state != ERFON) +		return; + +	if (check_bssid == true) { +		reg_rcr |= (RCR_CBSSID_DATA | RCR_CBSSID_BCN); +		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR, +					      (u8 *) (®_rcr)); +		_rtl92ee_set_bcn_ctrl_reg(hw, 0, BIT(4)); +	} else if (check_bssid == false) { +		reg_rcr &= (~(RCR_CBSSID_DATA | RCR_CBSSID_BCN)); +		_rtl92ee_set_bcn_ctrl_reg(hw, BIT(4), 0); +		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR, +					      (u8 *) (®_rcr)); +	} +} + +int rtl92ee_set_network_type(struct ieee80211_hw *hw, enum nl80211_iftype type) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); + +	if (_rtl92ee_set_media_status(hw, type)) +		return -EOPNOTSUPP; + +	if (rtlpriv->mac80211.link_state == MAC80211_LINKED) { +		if (type != NL80211_IFTYPE_AP && +		    type != NL80211_IFTYPE_MESH_POINT) +			rtl92ee_set_check_bssid(hw, true); +	} else { +		rtl92ee_set_check_bssid(hw, false); +	} + +	return 0; +} + +/* don't set REG_EDCA_BE_PARAM here because mac80211 will send pkt when scan */ +void rtl92ee_set_qos(struct ieee80211_hw *hw, int aci) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	rtl92ee_dm_init_edca_turbo(hw); +	switch (aci) { +	case AC1_BK: +		rtl_write_dword(rtlpriv, REG_EDCA_BK_PARAM, 0xa44f); +		break; +	case AC0_BE: +		/* rtl_write_dword(rtlpriv, REG_EDCA_BE_PARAM, u4b_ac_param); */ +		break; +	case AC2_VI: +		rtl_write_dword(rtlpriv, REG_EDCA_VI_PARAM, 0x5e4322); +		break; +	case AC3_VO: +		rtl_write_dword(rtlpriv, REG_EDCA_VO_PARAM, 0x2f3222); +		break; +	default: +		RT_ASSERT(false, ("invalid aci: %d !\n", aci)); +		break; +	} +} + +static void rtl92ee_clear_interrupt(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u32 tmp; + +	tmp = rtl_read_dword(rtlpriv, REG_HISR); +	rtl_write_dword(rtlpriv, REG_HISR, tmp); + +	tmp = rtl_read_dword(rtlpriv, REG_HISRE); +	rtl_write_dword(rtlpriv, REG_HISRE, tmp); + +	tmp = rtl_read_dword(rtlpriv, REG_HSISR); +	rtl_write_dword(rtlpriv, REG_HSISR, tmp); +} + +void rtl92ee_enable_interrupt(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + +	rtl92ee_clear_interrupt(hw);/*clear it here first*/ + +	rtl_write_dword(rtlpriv, REG_HIMR, rtlpci->irq_mask[0] & 0xFFFFFFFF); +	rtl_write_dword(rtlpriv, REG_HIMRE, rtlpci->irq_mask[1] & 0xFFFFFFFF); +	rtlpci->irq_enabled = true; +} + +void rtl92ee_disable_interrupt(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + +	rtl_write_dword(rtlpriv, REG_HIMR, IMR_DISABLED); +	rtl_write_dword(rtlpriv, REG_HIMRE, IMR_DISABLED); +	rtlpci->irq_enabled = false; +	/*synchronize_irq(rtlpci->pdev->irq);*/ +} + +static void _rtl92ee_poweroff_adapter(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); +	u8 u1b_tmp; +	rtlhal->b_mac_func_enable = false; + +	RT_TRACE(COMP_INIT , DBG_LOUD , ("POWER OFF adapter \n")); + +	/* Run LPS WL RFOFF flow */ +	rtl92e_hal_pwrseqcmdparsing(rtlpriv, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, +				 PWR_INTF_PCI_MSK, Rtl8192E_NIC_LPS_ENTER_FLOW); +	/* turn off RF */ +	rtl_write_byte(rtlpriv, REG_RF_CTRL, 0x00); + +	/* ==== Reset digital sequence   ======  */ +	if ((rtl_read_byte(rtlpriv, REG_MCUFWDL) & BIT(7)) && rtlhal->bfw_ready) +		rtl92ee_firmware_selfreset(hw); + +	/* Reset MCU  */ +	u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1); +	rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, (u1b_tmp & (~BIT(2)))); + +	/* reset MCU ready status */ +	rtl_write_byte(rtlpriv, REG_MCUFWDL, 0x00); + +	/* HW card disable configuration. */ +	rtl92e_hal_pwrseqcmdparsing(rtlpriv, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, +				 PWR_INTF_PCI_MSK, Rtl8192E_NIC_DISABLE_FLOW); + +	/* Reset MCU IO Wrapper */ +	u1b_tmp = rtl_read_byte(rtlpriv, REG_RSV_CTRL + 1); +	rtl_write_byte(rtlpriv, REG_RSV_CTRL + 1, (u1b_tmp & (~BIT(0)))); +	u1b_tmp = rtl_read_byte(rtlpriv, REG_RSV_CTRL + 1); +	rtl_write_byte(rtlpriv, REG_RSV_CTRL + 1, (u1b_tmp | BIT(0))); + +	/* lock ISO/CLK/Power control register */ +	rtl_write_byte(rtlpriv, REG_RSV_CTRL, 0x0E); +} + +void rtl92ee_card_disable(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +	enum nl80211_iftype opmode; + +	RT_TRACE(COMP_INIT , DBG_LOUD , ("RTL8192ee card disable\n")); + +	RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC); + +	mac->link_state = MAC80211_NOLINK; +	opmode = NL80211_IFTYPE_UNSPECIFIED; + +	_rtl92ee_set_media_status(hw, opmode); + +	if (rtlpriv->rtlhal.driver_is_goingto_unload || +	    ppsc->rfoff_reason > RF_CHANGE_BY_PS) +		rtlpriv->cfg->ops->led_control(hw, LED_CTL_POWER_OFF); + +	_rtl92ee_poweroff_adapter(hw); + +	/* after power off we should do iqk again */ +	rtlpriv->phy.iqk_initialized = false; +} + +void rtl92ee_interrupt_recognized(struct ieee80211_hw *hw, +				  u32 *p_inta, u32 *p_intb) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + +	*p_inta = rtl_read_dword(rtlpriv, ISR) & rtlpci->irq_mask[0]; +	rtl_write_dword(rtlpriv, ISR, *p_inta); + +	*p_intb = rtl_read_dword(rtlpriv, REG_HISRE) & rtlpci->irq_mask[1]; +	rtl_write_dword(rtlpriv, REG_HISRE, *p_intb); +} + +void rtl92ee_set_beacon_related_registers(struct ieee80211_hw *hw) +{ + +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); +	u16 bcn_interval, atim_window; + +	bcn_interval = mac->beacon_interval; +	atim_window = 2;	/*FIX MERGE */ +	rtl92ee_disable_interrupt(hw); +	rtl_write_word(rtlpriv, REG_ATIMWND, atim_window); +	rtl_write_word(rtlpriv, REG_BCN_INTERVAL, bcn_interval); +	rtl_write_word(rtlpriv, REG_BCNTCFG, 0x660f); +	rtl_write_byte(rtlpriv, REG_RXTSF_OFFSET_CCK, 0x18); +	rtl_write_byte(rtlpriv, REG_RXTSF_OFFSET_OFDM, 0x18); +	rtl_write_byte(rtlpriv, 0x606, 0x30); +	rtlpci->reg_bcn_ctrl_val |= BIT(3); +	rtl_write_byte(rtlpriv, REG_BCN_CTRL, (u8) rtlpci->reg_bcn_ctrl_val); +} + +void rtl92ee_set_beacon_interval(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +	u16 bcn_interval = mac->beacon_interval; + +	RT_TRACE(COMP_BEACON, DBG_DMESG, +		 ("beacon_interval:%d\n", bcn_interval)); +	rtl_write_word(rtlpriv, REG_BCN_INTERVAL, bcn_interval); +} + +void rtl92ee_update_interrupt_mask(struct ieee80211_hw *hw, +				   u32 add_msr, u32 rm_msr) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + +	RT_TRACE(COMP_INTR, DBG_LOUD, +		 ("add_msr:%x, rm_msr:%x\n", add_msr, rm_msr)); + +	if (add_msr) +		rtlpci->irq_mask[0] |= add_msr; +	if (rm_msr) +		rtlpci->irq_mask[0] &= (~rm_msr); +	rtl92ee_disable_interrupt(hw); +	rtl92ee_enable_interrupt(hw); +} + +static u8 _rtl92ee_get_chnl_group(u8 chnl) +{ +	u8 group = 0; + +	if (chnl <= 14) { +		if (1 <= chnl && chnl <= 2) +			group = 0; +		else if (3 <= chnl && chnl <= 5) +			group = 1; +		else if (6 <= chnl && chnl <= 8) +			group = 2; +		else if (9 <= chnl && chnl <= 11) +			group = 3; +		else if (12 <= chnl && chnl <= 14) +			group = 4; +	} else { +		if (36 <= chnl && chnl <= 42) +			group = 0; +		else if (44 <= chnl && chnl <= 48) +			group = 1; +		else if (50 <= chnl && chnl <= 58) +			group = 2; +		else if (60 <= chnl && chnl <= 64) +			group = 3; +		else if (100 <= chnl && chnl <= 106) +			group = 4; +		else if (108 <= chnl && chnl <= 114) +			group = 5; +		else if (116 <= chnl && chnl <= 122) +			group = 6; +		else if (124 <= chnl && chnl <= 130) +			group = 7; +		else if (132 <= chnl && chnl <= 138) +			group = 8; +		else if (140 <= chnl && chnl <= 144) +			group = 9; +		else if (149 <= chnl && chnl <= 155) +			group = 10; +		else if (157 <= chnl && chnl <= 161) +			group = 11; +		else if (165 <= chnl && chnl <= 171) +			group = 12; +		else if (173 <= chnl && chnl <= 177) +			group = 13; +	} +	return group; +} + +static void _rtl8192ee_read_power_value_fromprom(struct ieee80211_hw *hw, +						 struct txpower_info_2g *pwr2g, +						 struct txpower_info_5g *pwr5g, +						 bool autoload_fail, u8 *hwinfo) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u32 rf, addr = EEPROM_TX_PWR_INX, group, i = 0; + +	RT_TRACE(COMP_INIT, DBG_LOUD, +		 ("hal_ReadPowerValueFromPROM92E(): PROMContent[0x%x]= 0x%x\n", +		 (addr + 1), hwinfo[addr + 1])); +	if (0xFF == hwinfo[addr+1])  /*YJ, add, 120316*/ +		autoload_fail = true; + +	if (autoload_fail) { +		RT_TRACE(COMP_INIT, DBG_LOUD, +			 ("auto load fail : Use Default value!\n")); +		for (rf = 0 ; rf < MAX_RF_PATH ; rf++) { +			/* 2.4G default value */ +			for (group = 0 ; group < MAX_CHNL_GROUP_24G; group++) { +				pwr2g->index_cck_base[rf][group] = 0x2D; +				pwr2g->index_bw40_base[rf][group] = 0x2D; +			} +			for (i = 0; i < MAX_TX_COUNT; i++) { +				if (i == 0) { +					pwr2g->bw20_diff[rf][0] = 0x02; +					pwr2g->ofdm_diff[rf][0] = 0x04; +				} else { +					pwr2g->bw20_diff[rf][i] = 0xFE; +					pwr2g->bw40_diff[rf][i] = 0xFE; +					pwr2g->cck_diff[rf][i] = 0xFE; +					pwr2g->ofdm_diff[rf][i] = 0xFE; +				} +			} + +			/*5G default value*/ +			for (group = 0 ; group < MAX_CHNL_GROUP_5G; group++) +				pwr5g->index_bw40_base[rf][group] = 0x2A; + +			for (i = 0; i < MAX_TX_COUNT; i++) { +				if (i == 0) { +					pwr5g->ofdm_diff[rf][0] = 0x04; +					pwr5g->bw20_diff[rf][0] = 0x00; +					pwr5g->bw80_diff[rf][0] = 0xFE; +					pwr5g->bw160_diff[rf][0] = 0xFE; +				} else { +					pwr5g->ofdm_diff[rf][0] = 0xFE; +					pwr5g->bw20_diff[rf][0] = 0xFE; +					pwr5g->bw40_diff[rf][0] = 0xFE; +					pwr5g->bw80_diff[rf][0] = 0xFE; +					pwr5g->bw160_diff[rf][0] = 0xFE; +				} +			} +		} +		return; +	} + +	rtl_priv(hw)->efuse.b_txpwr_fromeprom = true; + +	for (rf = 0 ; rf < MAX_RF_PATH ; rf++) { +		/*2.4G default value*/ +		for (group = 0 ; group < MAX_CHNL_GROUP_24G; group++) { +			pwr2g->index_cck_base[rf][group] = hwinfo[addr++]; +			if (pwr2g->index_cck_base[rf][group] == 0xFF) +				pwr2g->index_cck_base[rf][group] = 0x2D; + +		} +		for (group = 0 ; group < MAX_CHNL_GROUP_24G - 1; group++) { +			pwr2g->index_bw40_base[rf][group] = hwinfo[addr++]; +			if (pwr2g->index_bw40_base[rf][group] == 0xFF) +				pwr2g->index_bw40_base[rf][group] = 0x2D; +		} +		for (i = 0; i < MAX_TX_COUNT; i++) { +			if (i == 0) { +				pwr2g->bw40_diff[rf][i] = 0; +				if (hwinfo[addr] == 0xFF) { +					pwr2g->bw20_diff[rf][i] = 0x02; +				} else { +					pwr2g->bw20_diff[rf][i] = (hwinfo[addr] +								   & 0xf0) >> 4; +					if (pwr2g->bw20_diff[rf][i] & BIT(3)) +						pwr2g->bw20_diff[rf][i] |= 0xF0; +				} + +				if (hwinfo[addr] == 0xFF) { +					pwr2g->ofdm_diff[rf][i] = 0x04; +				} else { +					pwr2g->ofdm_diff[rf][i] = (hwinfo[addr] +								   & 0x0f); +					if (pwr2g->ofdm_diff[rf][i] & BIT(3)) +						pwr2g->ofdm_diff[rf][i] |= 0xF0; +				} +				pwr2g->cck_diff[rf][i] = 0; +				addr++; +			} else { +				if (hwinfo[addr] == 0xFF) { +					pwr2g->bw40_diff[rf][i] = 0xFE; +				} else { +					pwr2g->bw40_diff[rf][i] = (hwinfo[addr] +								   & 0xf0) >> 4; +					if (pwr2g->bw40_diff[rf][i] & BIT(3)) +						pwr2g->bw40_diff[rf][i] |= 0xF0; +				} + +				if (hwinfo[addr] == 0xFF) { +					pwr2g->bw20_diff[rf][i] = 0xFE; +				} else { +					pwr2g->bw20_diff[rf][i] = (hwinfo[addr] +								   & 0x0f); +					if (pwr2g->bw20_diff[rf][i] & BIT(3)) +						pwr2g->bw20_diff[rf][i] |= 0xF0; +				} +				addr++; + +				if (hwinfo[addr] == 0xFF) { +					pwr2g->ofdm_diff[rf][i] = 0xFE; +				} else { +					pwr2g->ofdm_diff[rf][i] = (hwinfo[addr] +								   & 0xf0) >> 4; +					if (pwr2g->ofdm_diff[rf][i] & BIT(3)) +						pwr2g->ofdm_diff[rf][i] |= 0xF0; +				} + +				if (hwinfo[addr] == 0xFF) { +					pwr2g->cck_diff[rf][i] = 0xFE; +				} else { +					pwr2g->cck_diff[rf][i] = (hwinfo[addr] +								  & 0x0f); +					if (pwr2g->cck_diff[rf][i] & BIT(3)) +						pwr2g->cck_diff[rf][i] |= 0xF0; +				} +				addr++; +			} +		} + +		/*5G default value*/ +		for (group = 0 ; group < MAX_CHNL_GROUP_5G; group++) { +			pwr5g->index_bw40_base[rf][group] = hwinfo[addr++]; +			if (pwr5g->index_bw40_base[rf][group] == 0xFF) +				pwr5g->index_bw40_base[rf][group] = 0xFE; +		} + +		for (i = 0; i < MAX_TX_COUNT; i++) { +			if (i == 0) { +				pwr5g->bw40_diff[rf][i] = 0; + +				if (hwinfo[addr] == 0xFF) { +					pwr5g->bw20_diff[rf][i] = 0; +				} else { +					pwr5g->bw20_diff[rf][0] = (hwinfo[addr] +								   & 0xf0) >> 4; +					if (pwr5g->bw20_diff[rf][i] & BIT(3)) +						pwr5g->bw20_diff[rf][i] |= 0xF0; +				} + +				if (hwinfo[addr] == 0xFF) { +					pwr5g->ofdm_diff[rf][i] = 0x04; +				} else { +					pwr5g->ofdm_diff[rf][0] = (hwinfo[addr] +								   & 0x0f); +					if (pwr5g->ofdm_diff[rf][i] & BIT(3)) +						pwr5g->ofdm_diff[rf][i] |= 0xF0; +				} +				addr++; +			} else { +				if (hwinfo[addr] == 0xFF) { +					pwr5g->bw40_diff[rf][i] = 0xFE; +				} else { +					pwr5g->bw40_diff[rf][i] = (hwinfo[addr] +								  & 0xf0) >> 4; +					if (pwr5g->bw40_diff[rf][i] & BIT(3)) +					pwr5g->bw40_diff[rf][i] |= 0xF0; +				} + +				if (hwinfo[addr] == 0xFF) { +					pwr5g->bw20_diff[rf][i] = 0xFE; +				} else { +					pwr5g->bw20_diff[rf][i] = (hwinfo[addr] +								   & 0x0f); +					if (pwr5g->bw20_diff[rf][i] & BIT(3)) +					pwr5g->bw20_diff[rf][i] |= 0xF0; +				} +				addr++; +			} +		} + +		if (hwinfo[addr] == 0xFF) { +			pwr5g->ofdm_diff[rf][1] = 0xFE; +			pwr5g->ofdm_diff[rf][2] = 0xFE; +		} else { +			pwr5g->ofdm_diff[rf][1] = (hwinfo[addr] & 0xf0) >> 4; +			pwr5g->ofdm_diff[rf][2] = (hwinfo[addr] & 0x0f); +		} +		addr++; + +		if (hwinfo[addr] == 0xFF) +			pwr5g->ofdm_diff[rf][3] = 0xFE; +		else +			pwr5g->ofdm_diff[rf][3] = (hwinfo[addr] & 0x0f); +		addr++; + +		for (i = 1; i < MAX_TX_COUNT; i++) { +			if (pwr5g->ofdm_diff[rf][i] == 0xFF) +				pwr5g->ofdm_diff[rf][i] = 0xFE; +			else if (pwr5g->ofdm_diff[rf][i] & BIT(3)) +				pwr5g->ofdm_diff[rf][i] |= 0xF0; +		} + +		for (i = 0; i < MAX_TX_COUNT; i++) { +			if (hwinfo[addr] == 0xFF) { +				pwr5g->bw80_diff[rf][i] = 0xFE; +			} else { +				pwr5g->bw80_diff[rf][i] = (hwinfo[addr] & 0xf0) +							  >> 4; +				if (pwr5g->bw80_diff[rf][i] & BIT(3)) +					pwr5g->bw80_diff[rf][i] |= 0xF0; +			} + +			if (hwinfo[addr] == 0xFF) { +				pwr5g->bw160_diff[rf][i] = 0xFE; +			} else { +				pwr5g->bw160_diff[rf][i] = (hwinfo[addr] & 0x0f); +				if (pwr5g->bw160_diff[rf][i] & BIT(3)) +					pwr5g->bw160_diff[rf][i] |= 0xF0; +			} +			addr++; +		} +	} +} +static void _rtl92ee_read_txpower_info_from_hwpg(struct ieee80211_hw *hw, +						 bool autoload_fail, u8 *hwinfo) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_efuse *efu = rtl_efuse(rtl_priv(hw)); +	struct txpower_info_2g pwr2g; +	struct txpower_info_5g pwr5g; +	u8 channel5g[CHANNEL_MAX_NUMBER_5G] = { +		36, 38, 40, 42, 44, 46, 48, 50, 52, 54, +		56, 58, 60, 62, 64, 100, 102, 104, 106, +		108, 110, 112, 114, 116, 118, 120, 122, +		124, 126, 128, 130, 132, 134, 136, 138, +		140, 142, 144, 149, 151, 153, 155, 157, +		159, 161, 163, 165, 167, 168, 169, 171, +		173, 175, 177}; +	u8 channel5g_80m[CHANNEL_MAX_NUMBER_5G_80M] = { +		42, 58, 106, 122, 138, 155, 171}; +	u8 rf, idx; +	u8 i; + +	_rtl8192ee_read_power_value_fromprom(hw, &pwr2g, &pwr5g, +					     autoload_fail, hwinfo); + +	for (rf = 0; rf < MAX_RF_PATH; rf++) { +		for (i = 0; i < 14; i++) { +			idx = _rtl92ee_get_chnl_group(i + 1); + +			if (i == CHANNEL_MAX_NUMBER_2G - 1) { +				efu->txpwrlevel_cck[rf][i] = +						pwr2g.index_cck_base[rf][5]; +				efu->txpwrlevel_ht40_1s[rf][i] = +						pwr2g.index_bw40_base[rf][idx]; +			} else { +				efu->txpwrlevel_cck[rf][i] = +						pwr2g.index_cck_base[rf][idx]; +				efu->txpwrlevel_ht40_1s[rf][i] = +						pwr2g.index_bw40_base[rf][idx]; +			} +		} +		for (i = 0; i < CHANNEL_MAX_NUMBER_5G; i++) { +			idx = _rtl92ee_get_chnl_group(channel5g[i]); +			efu->txpwr_5g_bw40base[rf][i] = +					pwr5g.index_bw40_base[rf][idx]; +		} +		for (i = 0; i < CHANNEL_MAX_NUMBER_5G_80M; i++) { +			u8 upper, lower; +			idx = _rtl92ee_get_chnl_group(channel5g_80m[i]); +			upper = pwr5g.index_bw40_base[rf][idx]; +			lower = pwr5g.index_bw40_base[rf][idx + 1]; + +			efu->txpwr_5g_bw80base[rf][i] = (upper + lower) / 2; +		} +		for (i = 0; i < MAX_TX_COUNT; i++) { +			efu->txpwr_cckdiff[rf][i] = pwr2g.cck_diff[rf][i]; +			efu->txpwr_legacyhtdiff[rf][i] = pwr2g.ofdm_diff[rf][i]; +			efu->txpwr_ht20diff[rf][i] = pwr2g.bw20_diff[rf][i]; +			efu->txpwr_ht40diff[rf][i] = pwr2g.bw40_diff[rf][i]; + +			efu->txpwr_5g_ofdmdiff[rf][i] = pwr5g.ofdm_diff[rf][i]; +			efu->txpwr_5g_bw20diff[rf][i] = pwr5g.bw20_diff[rf][i]; +			efu->txpwr_5g_bw40diff[rf][i] = pwr5g.bw40_diff[rf][i]; +			efu->txpwr_5g_bw80diff[rf][i] = pwr5g.bw80_diff[rf][i]; +		} +	} + +	if (!autoload_fail) +		efu->eeprom_thermalmeter = hwinfo[EEPROM_THERMAL_METER_92E]; +	else +		efu->eeprom_thermalmeter = EEPROM_DEFAULT_THERMALMETER; + +	if (efu->eeprom_thermalmeter == 0xff || autoload_fail) { +		efu->b_apk_thermalmeterignore = true; +		efu->eeprom_thermalmeter = EEPROM_DEFAULT_THERMALMETER; +	} + +	efu->thermalmeter[0] = efu->eeprom_thermalmeter; +	RTPRINT(rtlpriv, FINIT, INIT_TxPower, +		"thermalmeter = 0x%x\n", efu->eeprom_thermalmeter); + +	if (!autoload_fail) { +		efu->eeprom_regulatory = hwinfo[EEPROM_RF_BOARD_OPTION_92E] +					 & 0x07; +		if (hwinfo[EEPROM_RF_BOARD_OPTION_92E] == 0xFF) +			efu->eeprom_regulatory = 0; +	} else { +		efu->eeprom_regulatory = 0; +	} +	RTPRINT(rtlpriv, FINIT, INIT_TxPower, +		"eeprom_regulatory = 0x%x\n", efu->eeprom_regulatory); +} + +static void _rtl92ee_read_adapter_info(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); +	u16 i, usvalue; +	u8 hwinfo[HWSET_MAX_SIZE]; +	u16 eeprom_id; + +	if (rtlefuse->epromtype == EEPROM_BOOT_EFUSE) { +		stg_rtl_efuse92e_shadow_map_update(hw); + +		memcpy(hwinfo, &rtlefuse->efuse_map[EFUSE_INIT_MAP][0], +		       HWSET_MAX_SIZE); +	} else if (rtlefuse->epromtype == EEPROM_93C46) { +		RT_TRACE(COMP_ERR, DBG_EMERG, +			 ("RTL819X Not boot from eeprom, check it !!")); +		return; +	}  else { +		RT_TRACE(COMP_ERR, DBG_EMERG, +			 ("boot from neither eeprom nor efuse, check it !!")); +		return; +	} + +	RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_LOUD, "MAP \n", +		      hwinfo, HWSET_MAX_SIZE); + +	eeprom_id = *((u16 *) &hwinfo[0]); +	if (eeprom_id != RTL8192E_EEPROM_ID) { +		RT_TRACE(COMP_ERR, DBG_WARNING, +			 ("EEPROM ID(%#x) is invalid!!\n", eeprom_id)); +		rtlefuse->autoload_failflag = true; +	} else { +		RT_TRACE(COMP_INIT, DBG_LOUD, ("Autoload OK\n")); +		rtlefuse->autoload_failflag = false; +	} + +	if (rtlefuse->autoload_failflag == true) +		return; +	/*VID DID SVID SDID*/ +	rtlefuse->eeprom_vid = *(u16 *) &hwinfo[EEPROM_VID]; +	rtlefuse->eeprom_did = *(u16 *) &hwinfo[EEPROM_DID]; +	rtlefuse->eeprom_svid = *(u16 *) &hwinfo[EEPROM_SVID]; +	rtlefuse->eeprom_smid = *(u16 *) &hwinfo[EEPROM_SMID]; +	RT_TRACE(COMP_INIT, DBG_LOUD, ("EEPROMId = 0x%4x\n", eeprom_id)); +	RT_TRACE(COMP_INIT, DBG_LOUD, +		 ("EEPROM VID = 0x%4x\n", rtlefuse->eeprom_vid)); +	RT_TRACE(COMP_INIT, DBG_LOUD, +		 ("EEPROM DID = 0x%4x\n", rtlefuse->eeprom_did)); +	RT_TRACE(COMP_INIT, DBG_LOUD, +		 ("EEPROM SVID = 0x%4x\n", rtlefuse->eeprom_svid)); +	RT_TRACE(COMP_INIT, DBG_LOUD, +		 ("EEPROM SMID = 0x%4x\n", rtlefuse->eeprom_smid)); +	/*customer ID*/ +	rtlefuse->eeprom_oemid = *(u8 *) &hwinfo[EEPROM_CUSTOMER_ID]; +	if (rtlefuse->eeprom_oemid == 0xFF) +		rtlefuse->eeprom_oemid = 0; + +	RT_TRACE(COMP_INIT, DBG_LOUD, +		 ("EEPROM Customer ID: 0x%2x\n", rtlefuse->eeprom_oemid)); +	/*EEPROM version*/ +	rtlefuse->eeprom_version = *(u8 *) &hwinfo[EEPROM_VERSION]; +	/*mac address*/ +	for (i = 0; i < 6; i += 2) { +		usvalue = *(u16 *) &hwinfo[EEPROM_MAC_ADDR + i]; +		*((u16 *) (&rtlefuse->dev_addr[i])) = usvalue; +	} + +	RT_TRACE(COMP_INIT, DBG_DMESG, +		 ("dev_addr: %pM\n", rtlefuse->dev_addr)); +	/*channel plan */ +	rtlefuse->eeprom_channelplan = *(u8 *) &hwinfo[EEPROM_CHANNELPLAN]; +	/* set channel paln to world wide 13 */ +	rtlefuse->channel_plan = COUNTRY_CODE_WORLD_WIDE_13; +	/*tx power*/ +	_rtl92ee_read_txpower_info_from_hwpg(hw, rtlefuse->autoload_failflag, +					     hwinfo); + +	rtl92ee_read_bt_coexist_info_from_hwpg(hw, rtlefuse->autoload_failflag, +					       hwinfo); + +	/*board type*/ +	rtlefuse->board_type = (((*(u8 *) &hwinfo[EEPROM_RF_BOARD_OPTION_92E]) +				& 0xE0) >> 5); +	if ((*(u8 *) &hwinfo[EEPROM_RF_BOARD_OPTION_92E]) == 0xFF) +		rtlefuse->board_type = 0; + +	rtlhal->boad_type = rtlefuse->board_type; +	/*parse xtal*/ +	rtlefuse->crystalcap = hwinfo[EEPROM_XTAL_92E]; +	if (hwinfo[EEPROM_XTAL_92E] == 0xFF) +		rtlefuse->crystalcap = 0x20; + +	/*antenna diversity*/ +	rtlefuse->antenna_div_type = NO_ANTDIV; +	rtlefuse->antenna_div_cfg = 0; + +	if (rtlhal->oem_id == RT_CID_DEFAULT) { +		switch (rtlefuse->eeprom_oemid) { +		case EEPROM_CID_DEFAULT: +			if (rtlefuse->eeprom_did == 0x818B) { +				if ((rtlefuse->eeprom_svid == 0x10EC) && +				    (rtlefuse->eeprom_smid == 0x001B)) +					rtlhal->oem_id = RT_CID_819x_Lenovo; +			} else { +				rtlhal->oem_id = RT_CID_DEFAULT; +			} +			break; +		default: +			rtlhal->oem_id = RT_CID_DEFAULT; +			break; +		} +	} +} + +static void _rtl92ee_hal_customized_behavior(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + +	pcipriv->ledctl.bled_opendrain = true; + +	RT_TRACE(COMP_INIT, DBG_DMESG, +		 ("RT Customized ID: 0x%02X\n", rtlhal->oem_id)); +} + +void rtl92ee_read_eeprom_info(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); +	u8 tmp_u1b; + +	rtlhal->version = _rtl92ee_read_chip_version(hw); +	if (get_rf_type(rtlphy) == RF_1T1R) +		rtlpriv->dm.brfpath_rxenable[0] = true; +	else +		rtlpriv->dm.brfpath_rxenable[0] = +		    rtlpriv->dm.brfpath_rxenable[1] = true; +	RT_TRACE(COMP_INIT, DBG_LOUD, ("VersionID = 0x%4x\n", +						rtlhal->version)); +	tmp_u1b = rtl_read_byte(rtlpriv, REG_9346CR); +	if (tmp_u1b & BIT(4)) { +		RT_TRACE(COMP_INIT, DBG_DMESG, ("Boot from EEPROM\n")); +		rtlefuse->epromtype = EEPROM_93C46; +	} else { +		RT_TRACE(COMP_INIT, DBG_DMESG, ("Boot from EFUSE\n")); +		rtlefuse->epromtype = EEPROM_BOOT_EFUSE; +	} +	if (tmp_u1b & BIT(5)) { +		RT_TRACE(COMP_INIT, DBG_LOUD, ("Autoload OK\n")); +		rtlefuse->autoload_failflag = false; +		_rtl92ee_read_adapter_info(hw); +	} else { +		RT_TRACE(COMP_ERR, DBG_EMERG, ("Autoload ERR!!\n")); +	} +	_rtl92ee_hal_customized_behavior(hw); + +	rtlphy->rfpath_rx_enable[0] = true; +	if (rtlphy->rf_type == RF_2T2R) +		rtlphy->rfpath_rx_enable[1] = true; +} + +static u8 _rtl92ee_mrate_idx_to_arfr_id(struct ieee80211_hw *hw, u8 rate_index) +{ +	u8 ret = 0; + +	switch (rate_index) { +	case RATR_INX_WIRELESS_NGB: +		ret = 0; +		break; +	case RATR_INX_WIRELESS_N: +	case RATR_INX_WIRELESS_NG: +		ret = 4; +		break; +	case RATR_INX_WIRELESS_NB: +		ret = 2; +		break; +	case RATR_INX_WIRELESS_GB: +		ret = 6; +		break; +	case RATR_INX_WIRELESS_G: +		ret = 7; +		break; +	case RATR_INX_WIRELESS_B: +		ret = 8; +		break; +	default: +		ret = 0; +		break; +	} +	return ret; +} + +static void rtl92ee_update_hal_rate_mask(struct ieee80211_hw *hw, +					 struct ieee80211_sta *sta, +					 u8 rssi_level) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +	struct rtl_sta_info *sta_entry = NULL; +	u32 ratr_bitmap; +	u8 ratr_index; +	u8 b_curtxbw_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) +			     ? 1 : 0; +	u8 b_curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ? +				1 : 0; +	u8 b_curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ? +				1 : 0; +	enum wireless_mode wirelessmode = 0; +	bool b_shortgi = false; +	u8 rate_mask[7] = {0}; +	u8 macid = 0; +	/*u8 mimo_ps = IEEE80211_SMPS_OFF;*/ +	sta_entry = (struct rtl_sta_info *) sta->drv_priv; +	wirelessmode = sta_entry->wireless_mode; +	if (mac->opmode == NL80211_IFTYPE_STATION || +	    mac->opmode == NL80211_IFTYPE_MESH_POINT) +		b_curtxbw_40mhz = mac->bw_40; +	else if (mac->opmode == NL80211_IFTYPE_AP || +		 mac->opmode == NL80211_IFTYPE_ADHOC) +		macid = sta->aid + 1; + +	ratr_bitmap = sta->supp_rates[0]; +	if (mac->opmode == NL80211_IFTYPE_ADHOC) +		ratr_bitmap = 0xfff; + +	ratr_bitmap |= (sta->ht_cap.mcs.rx_mask[1] << 20 | +			sta->ht_cap.mcs.rx_mask[0] << 12); + +	switch (wirelessmode) { +	case WIRELESS_MODE_B: +		ratr_index = RATR_INX_WIRELESS_B; +		if (ratr_bitmap & 0x0000000c) +			ratr_bitmap &= 0x0000000d; +		else +			ratr_bitmap &= 0x0000000f; +		break; +	case WIRELESS_MODE_G: +		ratr_index = RATR_INX_WIRELESS_GB; + +		if (rssi_level == 1) +			ratr_bitmap &= 0x00000f00; +		else if (rssi_level == 2) +			ratr_bitmap &= 0x00000ff0; +		else +			ratr_bitmap &= 0x00000ff5; +		break; +	case WIRELESS_MODE_N_24G: +		if (b_curtxbw_40mhz) +			ratr_index = RATR_INX_WIRELESS_NGB; +		else +			ratr_index = RATR_INX_WIRELESS_NB; + +		if (rtlphy->rf_type == RF_1T1R) { +			if (b_curtxbw_40mhz) { +				if (rssi_level == 1) +					ratr_bitmap &= 0x000f0000; +				else if (rssi_level == 2) +					ratr_bitmap &= 0x000ff000; +				else +					ratr_bitmap &= 0x000ff015; +			} else { +				if (rssi_level == 1) +					ratr_bitmap &= 0x000f0000; +				else if (rssi_level == 2) +					ratr_bitmap &= 0x000ff000; +				else +					ratr_bitmap &= 0x000ff005; +			} +		} else { +			if (b_curtxbw_40mhz) { +				if (rssi_level == 1) +					ratr_bitmap &= 0x0f8f0000; +				else if (rssi_level == 2) +					ratr_bitmap &= 0x0ffff000; +				else +					ratr_bitmap &= 0x0ffff015; +			} else { +				if (rssi_level == 1) +					ratr_bitmap &= 0x0f8f0000; +				else if (rssi_level == 2) +					ratr_bitmap &= 0x0ffff000; +				else +					ratr_bitmap &= 0x0ffff005; +			} +		} + +		if ((b_curtxbw_40mhz && b_curshortgi_40mhz) || +		    (!b_curtxbw_40mhz && b_curshortgi_20mhz)) { + +			if (macid == 0) +				b_shortgi = true; +			else if (macid == 1) +				b_shortgi = false; +		} +		break; +	default: +		ratr_index = RATR_INX_WIRELESS_NGB; + +		if (rtlphy->rf_type == RF_1T1R) +			ratr_bitmap &= 0x000ff0ff; +		else +			ratr_bitmap &= 0x0f8ff0ff; +		break; +	} +	ratr_index = _rtl92ee_mrate_idx_to_arfr_id(hw, ratr_index); +	sta_entry->ratr_index = ratr_index; + +	RT_TRACE(COMP_RATR, DBG_DMESG, +		 ("ratr_bitmap :%x\n", ratr_bitmap)); +	*(u32 *) &rate_mask = (ratr_bitmap & 0x0fffffff) | +				       (ratr_index << 28); +	rate_mask[0] = macid; +	rate_mask[1] = ratr_index | (b_shortgi ? 0x80 : 0x00); +	rate_mask[2] = b_curtxbw_40mhz; +	rate_mask[3] = (u8)(ratr_bitmap & 0x000000ff); +	rate_mask[4] = (u8)((ratr_bitmap & 0x0000ff00) >> 8); +	rate_mask[5] = (u8)((ratr_bitmap & 0x00ff0000) >> 16); +	rate_mask[6] = (u8)((ratr_bitmap & 0xff000000) >> 24); +	RT_TRACE(COMP_RATR, DBG_DMESG, +		 ("Rate_index:%x, ratr_val:%x, %x:%x:%x:%x:%x:%x:%x\n", +		  ratr_index, ratr_bitmap, rate_mask[0], rate_mask[1], +		  rate_mask[2], rate_mask[3], rate_mask[4], +		  rate_mask[5], rate_mask[6])); +	rtl92ee_fill_h2c_cmd(hw, H2C_92E_RA_MASK, 7, rate_mask); +	_rtl92ee_set_bcn_ctrl_reg(hw, BIT(3), 0); +} + + +void rtl92ee_update_hal_rate_tbl(struct ieee80211_hw *hw, +				 struct ieee80211_sta *sta, u8 rssi_level) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); + +	if (rtlpriv->dm.b_useramask) +		rtl92ee_update_hal_rate_mask(hw, sta, rssi_level); +} + +void rtl92ee_update_channel_access_setting(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +	u16 sifs_timer; + +	rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SLOT_TIME, +				      (u8 *) &mac->slot_time); +	if (!mac->ht_enable) +		sifs_timer = 0x0a0a; +	else +		sifs_timer = 0x0e0e; +	rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SIFS, (u8 *) &sifs_timer); +} + +bool rtl92ee_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 *valid) +{ +	*valid = 1; +	return true; +} + +void rtl92ee_set_key(struct ieee80211_hw *hw, u32 key_index, +		     u8 *p_macaddr, bool is_group, u8 enc_algo, +		     bool is_wepkey, bool clear_all) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); +	u8 *macaddr = p_macaddr; +	u32 entry_id = 0; +	bool is_pairwise = false; + +	static u8 cam_const_addr[4][6] = { +		{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, +		{0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, +		{0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, +		{0x00, 0x00, 0x00, 0x00, 0x00, 0x03} +	}; +	static u8 cam_const_broad[] = { +		0xff, 0xff, 0xff, 0xff, 0xff, 0xff +	}; + +	if (clear_all) { +		u8 idx = 0; +		u8 cam_offset = 0; +		u8 clear_number = 5; + +		RT_TRACE(COMP_SEC, DBG_DMESG, ("clear_all\n")); + +		for (idx = 0; idx < clear_number; idx++) { +			stg_rtl_cam_mark_invalid(hw, cam_offset + idx); +			stg_rtl_cam_empty_entry(hw, cam_offset + idx); + +			if (idx < 5) { +				memset(rtlpriv->sec.key_buf[idx], 0, +				       MAX_KEY_LEN); +				rtlpriv->sec.key_len[idx] = 0; +			} +		} + +	} else { +		switch (enc_algo) { +		case WEP40_ENCRYPTION: +			enc_algo = CAM_WEP40; +			break; +		case WEP104_ENCRYPTION: +			enc_algo = CAM_WEP104; +			break; +		case TKIP_ENCRYPTION: +			enc_algo = CAM_TKIP; +			break; +		case AESCCMP_ENCRYPTION: +			enc_algo = CAM_AES; +			break; +		default: +			RT_TRACE(COMP_ERR, DBG_LOUD, +				 ("switch case not process \n")); +			enc_algo = CAM_TKIP; +			break; +		} + +		if (is_wepkey || rtlpriv->sec.use_defaultkey) { +			macaddr = cam_const_addr[key_index]; +			entry_id = key_index; +		} else { +			if (is_group) { +				macaddr = cam_const_broad; +				entry_id = key_index; +			} else { +				if (mac->opmode == NL80211_IFTYPE_AP || +				    mac->opmode == NL80211_IFTYPE_MESH_POINT) { +					entry_id = stg_rtl_cam_get_free_entry(hw, +								     p_macaddr); +					if (entry_id >=  TOTAL_CAM_ENTRY) { +						RT_TRACE(COMP_SEC, DBG_EMERG, +							 ("Can not find free hw security cam entry\n")); +						return; +					} +				} else { +					entry_id = CAM_PAIRWISE_KEY_POSITION; +				} + +				key_index = PAIRWISE_KEYIDX; +				is_pairwise = true; +			} +		} + +		if (rtlpriv->sec.key_len[key_index] == 0) { +			RT_TRACE(COMP_SEC, DBG_DMESG, +				 ("delete one entry, entry_id is %d\n", +				 entry_id)); +			if (mac->opmode == NL80211_IFTYPE_AP || +			    mac->opmode == NL80211_IFTYPE_MESH_POINT) +				stg_rtl_cam_del_entry(hw, p_macaddr); +			stg_rtl_cam_delete_one_entry(hw, p_macaddr, entry_id); +		} else { +			RT_TRACE(COMP_SEC, DBG_DMESG, ("add one entry\n")); +			if (is_pairwise) { +				RT_TRACE(COMP_SEC, DBG_DMESG, +					 ("set Pairwiase key\n")); + +				stg_rtl_cam_add_one_entry(hw, macaddr, key_index, +					       entry_id, enc_algo, +					       CAM_CONFIG_NO_USEDK, +					       rtlpriv->sec.key_buf[key_index]); +			} else { +				RT_TRACE(COMP_SEC, DBG_DMESG, +					 ("set group key\n")); + +				if (mac->opmode == NL80211_IFTYPE_ADHOC) { +					stg_rtl_cam_add_one_entry(hw, +						rtlefuse->dev_addr, +						PAIRWISE_KEYIDX, +						CAM_PAIRWISE_KEY_POSITION, +						enc_algo, CAM_CONFIG_NO_USEDK, +						rtlpriv->sec.key_buf[entry_id]); +				} + +				stg_rtl_cam_add_one_entry(hw, macaddr, key_index, +						entry_id, enc_algo, +						CAM_CONFIG_NO_USEDK, +						rtlpriv->sec.key_buf[entry_id]); +			} +		} +	} +} + +void rtl92ee_read_bt_coexist_info_from_hwpg(struct ieee80211_hw *hw, +					    bool auto_load_fail, u8 *hwinfo) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u8 value; + +	if (!auto_load_fail) { +		value = hwinfo[EEPROM_RF_BOARD_OPTION_92E]; +		if (((value & 0xe0) >> 5) == 0x1) +			rtlpriv->btcoexist.btc_info.btcoexist = 1; +		else +			rtlpriv->btcoexist.btc_info.btcoexist = 0; + +		rtlpriv->btcoexist.btc_info.bt_type = BT_RTL8192E; +		rtlpriv->btcoexist.btc_info.ant_num = ANT_TOTAL_X2; +	} else { +		rtlpriv->btcoexist.btc_info.btcoexist = 1; +		rtlpriv->btcoexist.btc_info.bt_type = BT_RTL8192E; +		rtlpriv->btcoexist.btc_info.ant_num = ANT_TOTAL_X1; +	} +} + +void rtl92ee_bt_reg_init(struct ieee80211_hw *hw) +{ +	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + +	/* 0:Low, 1:High, 2:From Efuse. */ +	rtlpcipriv->btcoexist.b_reg_bt_iso = 2; +	/* 0:Idle, 1:None-SCO, 2:SCO, 3:From Counter. */ +	rtlpcipriv->btcoexist.b_reg_bt_sco = 3; +	/* 0:Disable BT control A-MPDU, 1:Enable BT control A-MPDU. */ +	rtlpcipriv->btcoexist.b_reg_bt_sco = 0; +} + +void rtl92ee_bt_hw_init(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); + +	if (rtlpriv->cfg->ops->get_btc_status()) { +		rtlpriv->btcoexist.btc_ops->btc_init_hw_config(rtlpriv); +	} +} + +void rtl92ee_suspend(struct ieee80211_hw *hw) +{ +} + +void rtl92ee_resume(struct ieee80211_hw *hw) +{ +} + +/* Turn on AAP (RCR:bit 0) for promicuous mode. */ +void rtl92ee_allow_all_destaddr(struct ieee80211_hw *hw, +				bool allow_all_da, bool write_into_reg) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + +	if (allow_all_da)	/* Set BIT0 */ +		rtlpci->receive_config |= RCR_AAP; +	else			/* Clear BIT0 */ +		rtlpci->receive_config &= ~RCR_AAP; + +	if (write_into_reg) +		rtl_write_dword(rtlpriv, REG_RCR, rtlpci->receive_config); + +	RT_TRACE(COMP_TURBO | COMP_INIT, DBG_LOUD, +		 ("receive_config = 0x%08X, write_into_reg =%d\n", +		  rtlpci->receive_config, write_into_reg)); +} diff --git a/drivers/staging/rtl8192ee/rtl8192ee/hw.h b/drivers/staging/rtl8192ee/rtl8192ee/hw.h new file mode 100644 index 00000000000..e99d7bde1c6 --- /dev/null +++ b/drivers/staging/rtl8192ee/rtl8192ee/hw.h @@ -0,0 +1,67 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010  Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __RTL92E_HW_H__ +#define __RTL92E_HW_H__ + + +void rtl92ee_get_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val); +void rtl92ee_read_eeprom_info(struct ieee80211_hw *hw); +void rtl92ee_interrupt_recognized(struct ieee80211_hw *hw, +				  u32 *p_inta, u32 *p_intb); +int rtl92ee_hw_init(struct ieee80211_hw *hw); +void rtl92ee_card_disable(struct ieee80211_hw *hw); +void rtl92ee_enable_interrupt(struct ieee80211_hw *hw); +void rtl92ee_disable_interrupt(struct ieee80211_hw *hw); +int rtl92ee_set_network_type(struct ieee80211_hw *hw, enum nl80211_iftype type); +void rtl92ee_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid); +void rtl92ee_set_qos(struct ieee80211_hw *hw, int aci); +void rtl92ee_set_beacon_related_registers(struct ieee80211_hw *hw); +void rtl92ee_set_beacon_interval(struct ieee80211_hw *hw); +void rtl92ee_update_interrupt_mask(struct ieee80211_hw *hw, +				   u32 add_msr, u32 rm_msr); +void rtl92ee_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val); +void rtl92ee_update_hal_rate_tbl(struct ieee80211_hw *hw, +				 struct ieee80211_sta *sta, u8 rssi_level); +void rtl92ee_update_channel_access_setting(struct ieee80211_hw *hw); +bool rtl92ee_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 *valid); +void rtl92ee_enable_hw_security_config(struct ieee80211_hw *hw); +void rtl92ee_set_key(struct ieee80211_hw *hw, u32 key_index, +		     u8 *p_macaddr, bool is_group, u8 enc_algo, +		     bool is_wepkey, bool clear_all); +void rtl92ee_read_bt_coexist_info_from_hwpg(struct ieee80211_hw *hw, +					    bool autoload_fail, u8 *hwinfo); +void rtl92ee_bt_reg_init(struct ieee80211_hw *hw); +void rtl92ee_bt_hw_init(struct ieee80211_hw *hw); +void rtl92ee_suspend(struct ieee80211_hw *hw); +void rtl92ee_resume(struct ieee80211_hw *hw); +void rtl92ee_allow_all_destaddr(struct ieee80211_hw *hw, bool allow_all_da, +				bool write_into_reg); +void rtl92ee_fw_clk_off_timer_callback(unsigned long data); +#endif diff --git a/drivers/staging/rtl8192ee/rtl8192ee/led.c b/drivers/staging/rtl8192ee/rtl8192ee/led.c new file mode 100644 index 00000000000..3b459c93a84 --- /dev/null +++ b/drivers/staging/rtl8192ee/rtl8192ee/led.c @@ -0,0 +1,134 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010  Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#include "../wifi.h" +#include "../pci.h" +#include "led.h" +#include "reg.h" + +static void _rtl92ee_init_led(struct ieee80211_hw *hw, +			      struct rtl_led *pled, enum rtl_led_pin ledpin) +{ +	pled->hw = hw; +	pled->ledpin = ledpin; +	pled->b_ledon = false; +} + +void rtl92ee_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled) +{ +	u32 ledcfg; +	struct rtl_priv *rtlpriv = rtl_priv(hw); + +	RT_TRACE(COMP_LED, DBG_LOUD, +		 ("LedAddr:%X ledpin =%d\n", REG_LEDCFG2, pled->ledpin)); + +	switch (pled->ledpin) { +	case LED_PIN_GPIO0: +		break; +	case LED_PIN_LED0: +		ledcfg = rtl_read_dword(rtlpriv, REG_GPIO_PIN_CTRL) | BIT(21); +		ledcfg &= ~BIT(13) & ~BIT(29); +		rtl_write_dword(rtlpriv, REG_GPIO_PIN_CTRL, ledcfg); +		break; +	case LED_PIN_LED1: +		break; +	default: +		RT_TRACE(COMP_ERR, DBG_EMERG, +			 ("switch case not process\n")); +		break; +	} +	pled->b_ledon = true; +} + +void rtl92ee_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u32 ledcfg; + +	RT_TRACE(COMP_LED, DBG_LOUD, +		 ("LedAddr:%X ledpin =%d\n", REG_LEDCFG2, pled->ledpin)); + +	switch (pled->ledpin) { +	case LED_PIN_GPIO0: +		break; +	case LED_PIN_LED0: +		ledcfg = rtl_read_dword(rtlpriv , REG_GPIO_PIN_CTRL) | ~BIT(21); +		ledcfg &= ~BIT(29); +		rtl_write_dword(rtlpriv, REG_GPIO_PIN_CTRL, ledcfg); +		break; +	case LED_PIN_LED1: +		break; +	default: +		RT_TRACE(COMP_ERR, DBG_LOUD, +			 ("switch case not process\n")); +		break; +	} +	pled->b_ledon = false; +} + +void rtl92ee_init_sw_leds(struct ieee80211_hw *hw) +{ +	struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); +	_rtl92ee_init_led(hw, &(pcipriv->ledctl.sw_led0), LED_PIN_LED0); +	_rtl92ee_init_led(hw, &(pcipriv->ledctl.sw_led1), LED_PIN_LED1); +} + +static void _rtl92ee_sw_led_control(struct ieee80211_hw *hw, +				    enum led_ctl_mode ledaction) +{ +	struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); +	struct rtl_led *pLed0 = &(pcipriv->ledctl.sw_led0); +	switch (ledaction) { +	case LED_CTL_POWER_ON: +	case LED_CTL_LINK: +	case LED_CTL_NO_LINK: +		rtl92ee_sw_led_on(hw, pLed0); +		break; +	case LED_CTL_POWER_OFF: +		rtl92ee_sw_led_off(hw, pLed0); +		break; +	default: +		break; +	} +} + +void rtl92ee_led_control(struct ieee80211_hw *hw, enum led_ctl_mode ledaction) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + +	if ((ppsc->rfoff_reason > RF_CHANGE_BY_PS) && +	    (ledaction == LED_CTL_TX || +	     ledaction == LED_CTL_RX || +	     ledaction == LED_CTL_SITE_SURVEY || +	     ledaction == LED_CTL_LINK || +	     ledaction == LED_CTL_NO_LINK || +	     ledaction == LED_CTL_START_TO_LINK || +	     ledaction == LED_CTL_POWER_ON)) { +		return; +	} +	RT_TRACE(COMP_LED, DBG_TRACE, ("ledaction %d,\n", ledaction)); +	_rtl92ee_sw_led_control(hw, ledaction); +} diff --git a/drivers/staging/rtl8192ee/rtl8192ee/led.h b/drivers/staging/rtl8192ee/rtl8192ee/led.h new file mode 100644 index 00000000000..7302eda535d --- /dev/null +++ b/drivers/staging/rtl8192ee/rtl8192ee/led.h @@ -0,0 +1,37 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010  Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __RTL92E_LED_H__ +#define __RTL92E_LED_H__ + +void rtl92ee_init_sw_leds(struct ieee80211_hw *hw); +void rtl92ee_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled); +void rtl92ee_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled); +void rtl92ee_led_control(struct ieee80211_hw *hw, enum led_ctl_mode ledaction); +#endif diff --git a/drivers/staging/rtl8192ee/rtl8192ee/phy.c b/drivers/staging/rtl8192ee/rtl8192ee/phy.c new file mode 100644 index 00000000000..beef284615e --- /dev/null +++ b/drivers/staging/rtl8192ee/rtl8192ee/phy.c @@ -0,0 +1,3282 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010  Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#include "../wifi.h" +#include "../pci.h" +#include "../ps.h" +#include "reg.h" +#include "def.h" +#include "phy.h" +#include "rf.h" +#include "dm.h" +#include "table.h" + +static u32 _rtl92ee_phy_rf_serial_read(struct ieee80211_hw *hw, +				       enum radio_path rfpath, u32 offset); +static void _rtl92ee_phy_rf_serial_write(struct ieee80211_hw *hw, +					 enum radio_path rfpath, u32 offset, +					 u32 data); +static u32 _rtl92ee_phy_calculate_bit_shift(u32 bitmask); +static bool _rtl92ee_phy_bb8192ee_config_parafile(struct ieee80211_hw *hw); +static bool _rtl92ee_phy_config_mac_with_headerfile(struct ieee80211_hw *hw); +static bool _rtl92ee_phy_config_bb_with_headerfile(struct ieee80211_hw *hw, +						   u8 configtype); +static bool _rtl92ee_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw, +						     u8 configtype); +static void _rtl92ee_phy_init_bb_rf_register_definition(struct ieee80211_hw *hw); +static bool _rtl92ee_phy_set_sw_chnl_cmdarray(struct swchnlcmd *cmdtable, +					      u32 cmdtableidx, u32 cmdtablesz, +					      enum swchnlcmd_id cmdid, +					      u32 para1, u32 para2, +					      u32 msdelay); +static bool _rtl92ee_phy_sw_chnl_step_by_step(struct ieee80211_hw *hw, +					      u8 channel, u8 *stage, +					      u8 *step, u32 *delay); +static long _rtl92ee_phy_txpwr_idx_to_dbm(struct ieee80211_hw *hw, +					  enum wireless_mode wirelessmode, +					  u8 txpwridx); +static void rtl92ee_phy_set_rf_on(struct ieee80211_hw *hw); +static void rtl92ee_phy_set_io(struct ieee80211_hw *hw); + +u32 rtl92ee_phy_query_bb_reg(struct ieee80211_hw *hw, u32 regaddr, u32 bitmask) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u32 returnvalue, originalvalue, bitshift; + +	RT_TRACE(COMP_RF, DBG_TRACE, +		 ("regaddr(%#x), bitmask(%#x)\n", regaddr, bitmask)); +	originalvalue = rtl_read_dword(rtlpriv, regaddr); +	bitshift = _rtl92ee_phy_calculate_bit_shift(bitmask); +	returnvalue = (originalvalue & bitmask) >> bitshift; + +	RT_TRACE(COMP_RF, DBG_TRACE, +		 ("BBR MASK = 0x%x Addr[0x%x]= 0x%x\n", +		  bitmask, regaddr, originalvalue)); + +	return returnvalue; +} + +void rtl92ee_phy_set_bb_reg(struct ieee80211_hw *hw, u32 regaddr, +			    u32 bitmask, u32 data) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u32 originalvalue, bitshift; + +	RT_TRACE(COMP_RF, DBG_TRACE, +		 ("regaddr(%#x), bitmask(%#x), data(%#x)\n", +		  regaddr, bitmask, data)); + +	if (bitmask != MASKDWORD) { +		originalvalue = rtl_read_dword(rtlpriv, regaddr); +		bitshift = _rtl92ee_phy_calculate_bit_shift(bitmask); +		data = ((originalvalue & (~bitmask)) | (data << bitshift)); +	} + +	rtl_write_dword(rtlpriv, regaddr, data); + +	RT_TRACE(COMP_RF, DBG_TRACE, +		 ("regaddr(%#x), bitmask(%#x), data(%#x)\n", +		  regaddr, bitmask, data)); +} + +u32 rtl92ee_phy_query_rf_reg(struct ieee80211_hw *hw, +			     enum radio_path rfpath, u32 regaddr, u32 bitmask) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u32 original_value, readback_value, bitshift; +	unsigned long flags; + +	RT_TRACE(COMP_RF, DBG_TRACE, +		 ("regaddr(%#x), rfpath(%#x), bitmask(%#x)\n", +		  regaddr, rfpath, bitmask)); + +	spin_lock_irqsave(&rtlpriv->locks.rf_lock, flags); + + +	original_value = _rtl92ee_phy_rf_serial_read(hw , rfpath, regaddr); +	bitshift = _rtl92ee_phy_calculate_bit_shift(bitmask); +	readback_value = (original_value & bitmask) >> bitshift; + +	spin_unlock_irqrestore(&rtlpriv->locks.rf_lock, flags); + +	RT_TRACE(COMP_RF, DBG_TRACE, +		 ("regaddr(%#x), rfpath(%#x), bitmask(%#x), original_value(%#x)\n", +		  regaddr, rfpath, bitmask, original_value)); + +	return readback_value; +} + +void rtl92ee_phy_set_rf_reg(struct ieee80211_hw *hw, +			    enum radio_path rfpath, +			    u32 addr, u32 bitmask, u32 data) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u32 original_value, bitshift; +	unsigned long flags; + +	RT_TRACE(COMP_RF, DBG_TRACE, +		 ("regaddr(%#x), bitmask(%#x), data(%#x), rfpath(%#x)\n", +		  addr, bitmask, data, rfpath)); + +	spin_lock_irqsave(&rtlpriv->locks.rf_lock, flags); + +	if (bitmask != RFREG_OFFSET_MASK) { +		original_value = _rtl92ee_phy_rf_serial_read(hw, rfpath, addr); +		bitshift = _rtl92ee_phy_calculate_bit_shift(bitmask); +		data = (original_value & (~bitmask)) | (data << bitshift); +	} + +	_rtl92ee_phy_rf_serial_write(hw, rfpath, addr, data); + +	spin_unlock_irqrestore(&rtlpriv->locks.rf_lock, flags); + +	RT_TRACE(COMP_RF, DBG_TRACE, +		 ("regaddr(%#x), bitmask(%#x), data(%#x), rfpath(%#x)\n", +		  addr, bitmask, data, rfpath)); +} + +static u32 _rtl92ee_phy_rf_serial_read(struct ieee80211_hw *hw, +				       enum radio_path rfpath, u32 offset) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	struct bb_reg_def *pphyreg = &rtlphy->phyreg_def[rfpath]; +	u32 newoffset; +	u32 tmplong, tmplong2; +	u8 rfpi_enable = 0; +	u32 retvalue; + +	offset &= 0xff; +	newoffset = offset; +	if (RT_CANNOT_IO(hw)) { +		RT_TRACE(COMP_ERR, DBG_EMERG, ("return all one\n")); +		return 0xFFFFFFFF; +	} +	tmplong = rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, MASKDWORD); +	if (rfpath == RF90_PATH_A) +		tmplong2 = tmplong; +	else +		tmplong2 = rtl_get_bbreg(hw, pphyreg->rfhssi_para2, MASKDWORD); +	tmplong2 = (tmplong2 & (~BLSSIREADADDRESS)) | +		   (newoffset << 23) | BLSSIREADEDGE; +	rtl_set_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, MASKDWORD, +		      tmplong & (~BLSSIREADEDGE)); +	mdelay(1); +	rtl_set_bbreg(hw, pphyreg->rfhssi_para2, MASKDWORD, tmplong2); +	mdelay(1); +	mdelay(1); +	if (rfpath == RF90_PATH_A) +		rfpi_enable = (u8) rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER1, +						 BIT(8)); +	else if (rfpath == RF90_PATH_B) +		rfpi_enable = (u8) rtl_get_bbreg(hw, RFPGA0_XB_HSSIPARAMETER1, +						 BIT(8)); +	if (rfpi_enable) +		retvalue = rtl_get_bbreg(hw, pphyreg->rflssi_readbackpi, +					 BLSSIREADBACKDATA); +	else +		retvalue = rtl_get_bbreg(hw, pphyreg->rflssi_readback, +					 BLSSIREADBACKDATA); +	RT_TRACE(COMP_RF, DBG_TRACE, +		 ("RFR-%d Addr[0x%x]= 0x%x\n", +		  rfpath, pphyreg->rflssi_readback, retvalue)); +	return retvalue; +} + +static void _rtl92ee_phy_rf_serial_write(struct ieee80211_hw *hw, +					 enum radio_path rfpath, u32 offset, +					 u32 data) +{ +	u32 data_and_addr; +	u32 newoffset; +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	struct bb_reg_def *pphyreg = &rtlphy->phyreg_def[rfpath]; + +	if (RT_CANNOT_IO(hw)) { +		RT_TRACE(COMP_ERR, DBG_EMERG, ("stop\n")); +		return; +	} +	offset &= 0xff; +	newoffset = offset; +	data_and_addr = ((newoffset << 20) | (data & 0x000fffff)) & 0x0fffffff; +	rtl_set_bbreg(hw, pphyreg->rf3wire_offset, MASKDWORD, data_and_addr); +	RT_TRACE(COMP_RF, DBG_TRACE, +		 ("RFW-%d Addr[0x%x]= 0x%x\n", rfpath, +		  pphyreg->rf3wire_offset, data_and_addr)); +} + +static u32 _rtl92ee_phy_calculate_bit_shift(u32 bitmask) +{ +	u32 i; + +	for (i = 0; i <= 31; i++) { +		if (((bitmask >> i) & 0x1) == 1) +			break; +	} +	return i; +} + +bool rtl92ee_phy_mac_config(struct ieee80211_hw *hw) +{ +	bool rtstatus = _rtl92ee_phy_config_mac_with_headerfile(hw); + +	return rtstatus; +} + +bool rtl92ee_phy_bb_config(struct ieee80211_hw *hw) +{ +	bool rtstatus = true; +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u16 regval; +	u32 tmp; +	u8 crystal_cap; + +	_rtl92ee_phy_init_bb_rf_register_definition(hw); +	regval = rtl_read_word(rtlpriv, REG_SYS_FUNC_EN); +	rtl_write_word(rtlpriv, REG_SYS_FUNC_EN, +		       regval | BIT(13) | BIT(0) | BIT(1)); + +	rtl_write_byte(rtlpriv, REG_RF_CTRL, RF_EN | RF_RSTB | RF_SDMRSTB); +	rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, +		       FEN_PPLL | FEN_PCIEA | FEN_DIO_PCIE | +		       FEN_BB_GLB_RSTn | FEN_BBRSTB); + +	rtl_write_byte(rtlpriv, REG_AFE_XTAL_CTRL + 1, 0x80); + +	tmp = rtl_read_dword(rtlpriv, 0x4c); +	rtl_write_dword(rtlpriv, 0x4c, tmp | BIT(23)); + +	rtstatus = _rtl92ee_phy_bb8192ee_config_parafile(hw); + +	crystal_cap = rtlpriv->efuse.eeprom_crystalcap & 0x3F; +	rtl_set_bbreg(hw, REG_MAC_PHY_CTRL, 0xFFF000, +		      (crystal_cap | (crystal_cap << 6))); +	return rtstatus; +} + +bool rtl92ee_phy_rf_config(struct ieee80211_hw *hw) +{ +	return rtl92ee_phy_rf6052_config(hw); +} + +static bool _check_condition(struct ieee80211_hw *hw, +				     const u32  condition) +{ +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); +	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); +	u32 _board = rtlefuse->board_type; /*need efuse define*/ +	u32 _interface = rtlhal->interface; +	u32 _platform = 0x08;/*SupportPlatform */ +	u32 cond = condition; + +	if (condition == 0xCDCDCDCD) +		return true; +	cond = condition & 0xFF; +	if ((_board != cond) && (cond != 0xFF)) +		return false; +	cond = condition & 0xFF00; +	cond = cond >> 8; +	if ((_interface & cond) == 0 && cond != 0x07) +		return false; +	cond = condition & 0xFF0000; +	cond = cond >> 16; +	if ((_platform & cond) == 0 && cond != 0x0F) +		return false; +	return true; +} + +static void _rtl92ee_config_rf_reg(struct ieee80211_hw *hw, u32 addr, u32 data, +				   enum radio_path rfpath, u32 regaddr) +{ +	if (addr == 0xfe || addr == 0xffe) { +		mdelay(50); +	} else { +		rtl_set_rfreg(hw, rfpath, regaddr, RFREG_OFFSET_MASK, data); +		udelay(1); + +		if (addr == 0xb6) { +			u32 getvalue; +			u8 count = 0; +			getvalue = rtl_get_rfreg(hw, rfpath, addr, MASKDWORD); +			udelay(1); + +			while ((getvalue >> 8) != (data >> 8)) { +				count++; +				rtl_set_rfreg(hw, rfpath, regaddr, +					      RFREG_OFFSET_MASK, data); +				udelay(1); +				getvalue = rtl_get_rfreg(hw, rfpath, addr, +							 MASKDWORD); +				if (count > 5) +					break; +			} +		} + +		if (addr == 0xb2) { +			u32 getvalue; +			u8 count = 0; +			getvalue = rtl_get_rfreg(hw, rfpath, addr, MASKDWORD); + +			udelay(1); + +			while (getvalue != data) { +				count++; +				rtl_set_rfreg(hw, rfpath, regaddr, +					      RFREG_OFFSET_MASK, data); +				udelay(1); +				rtl_set_rfreg(hw, rfpath, 0x18, +					      RFREG_OFFSET_MASK, 0x0fc07); +				udelay(1); +				getvalue = rtl_get_rfreg(hw, rfpath, addr, +							 MASKDWORD); +				if (count > 5) +					break; +			} +		} +	} +} + +static void _rtl92ee_config_rf_radio_a(struct ieee80211_hw *hw, +				       u32 addr, u32 data) +{ +	u32 content = 0x1000; /*RF Content: radio_a_txt*/ +	u32 maskforphyset = (u32)(content & 0xE000); + +	_rtl92ee_config_rf_reg(hw, addr, data, RF90_PATH_A, +			       addr | maskforphyset); +} + +static void _rtl92ee_config_rf_radio_b(struct ieee80211_hw *hw, +				       u32 addr, u32 data) +{ +	u32 content = 0x1001; /*RF Content: radio_b_txt*/ +	u32 maskforphyset = (u32)(content & 0xE000); + +	_rtl92ee_config_rf_reg(hw, addr, data, RF90_PATH_B, +			       addr | maskforphyset); +} + +static void _rtl92ee_config_bb_reg(struct ieee80211_hw *hw, +				   u32 addr, u32 data) +{ +	if (addr == 0xfe) +		mdelay(50); +	else if (addr == 0xfd) +		mdelay(5); +	else if (addr == 0xfc) +		mdelay(1); +	else if (addr == 0xfb) +		udelay(50); +	else if (addr == 0xfa) +		udelay(5); +	else if (addr == 0xf9) +		udelay(1); +	else +		rtl_set_bbreg(hw, addr, MASKDWORD , data); + +	udelay(1); +} + +static void _rtl92ee_phy_init_tx_power_by_rate(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); + +	u8 band = BAND_ON_2_4G, rf = 0, txnum = 0, sec = 0; + +	for (; band <= BAND_ON_5G; ++band) +		for (; rf < TX_PWR_BY_RATE_NUM_RF; ++rf) +			for (; txnum < TX_PWR_BY_RATE_NUM_RF; ++txnum) +				for (; sec < TX_PWR_BY_RATE_NUM_SECTION; ++sec) +					rtlphy->tx_power_by_rate_offset +						     [band][rf][txnum][sec] = 0; +} + +static void _rtl92ee_phy_set_txpower_by_rate_base(struct ieee80211_hw *hw, +						  u8 band, u8 path, +						  u8 rate_section, u8 txnum, u8 value) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); + +	if (path > RF90_PATH_D) { +		RT_TRACE(COMP_INIT, DBG_LOUD, ("Invalid Rf Path %d\n", path)); +		return; +	} +	if (band == BAND_ON_2_4G) { +		switch (rate_section) { +		case CCK: +			rtlphy->txpwr_by_rate_base_24g[path][txnum][0] = value; +			break; +		case OFDM: +			rtlphy->txpwr_by_rate_base_24g[path][txnum][1] = value; +			break; +		case HT_MCS0_MCS7: +			rtlphy->txpwr_by_rate_base_24g[path][txnum][2] = value; +			break; +		case HT_MCS8_MCS15: +			rtlphy->txpwr_by_rate_base_24g[path][txnum][3] = value; +			break; +		default: +			RT_TRACE(COMP_INIT, DBG_LOUD, +				 ("Invalid RateSection %d in 2.4G, Rf %d,%dTx\n", +				  rate_section, path, txnum)); +			break; +		}; +	} else { +		RT_TRACE(COMP_INIT, DBG_LOUD, ("Invalid Band %d\n", band)); +	} +} + +static u8 _rtl92ee_phy_get_txpower_by_rate_base(struct ieee80211_hw *hw, u8 band, +						u8 path, u8 txnum, u8 rate_section) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	u8 value = 0; +	if (path > RF90_PATH_D) { +		RT_TRACE(COMP_INIT, DBG_LOUD, ("Invalid Rf Path %d\n", path)); +		return 0; +	} +	if (band == BAND_ON_2_4G) { +		switch (rate_section) { +		case CCK: +			value = rtlphy->txpwr_by_rate_base_24g[path][txnum][0]; +			break; +		case OFDM: +			value = rtlphy->txpwr_by_rate_base_24g[path][txnum][1]; +			break; +		case HT_MCS0_MCS7: +			value = rtlphy->txpwr_by_rate_base_24g[path][txnum][2]; +			break; +		case HT_MCS8_MCS15: +			value = rtlphy->txpwr_by_rate_base_24g[path][txnum][3]; +			break; +		default: +			RT_TRACE(COMP_INIT, DBG_LOUD, +				 ("Invalid RateSection %d in 2.4G, Rf %d,%dTx\n", +				  rate_section, path, txnum)); +			break; +		}; +	} else { +		RT_TRACE(COMP_INIT, DBG_LOUD, ("Invalid Band %d()\n", band)); +	} +	return value; +} + +static void _rtl92ee_phy_store_txpower_by_rate_base(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	u16 raw = 0; +	u8 base = 0, path = 0; + +	for (path = RF90_PATH_A; path <= RF90_PATH_B; ++path) { +		if (path == RF90_PATH_A) { +			raw = (u16) (rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G][path][RF_1TX][3] >> 24) & 0xFF; +			base = (raw >> 4) * 10 + (raw & 0xF); +			_rtl92ee_phy_set_txpower_by_rate_base(hw, BAND_ON_2_4G, +							      path, CCK, RF_1TX, +							      base); +		} else if (path == RF90_PATH_B) { +			raw = (u16) (rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G][path][RF_1TX][3] >> 0) & 0xFF; +			base = (raw >> 4) * 10 + (raw & 0xF); +			_rtl92ee_phy_set_txpower_by_rate_base(hw, BAND_ON_2_4G, +							      path, CCK, RF_1TX, +							      base); +		} +		raw = (u16) (rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G][path][RF_1TX][1] >> 24) & 0xFF; +		base = (raw >> 4) * 10 + (raw & 0xF); +		_rtl92ee_phy_set_txpower_by_rate_base(hw, BAND_ON_2_4G, path, +						      OFDM, RF_1TX, base); + +		raw = (u16) (rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G][path][RF_1TX][5] >> 24) & 0xFF; +		base = (raw >> 4) * 10 + (raw & 0xF); +		_rtl92ee_phy_set_txpower_by_rate_base(hw, BAND_ON_2_4G, path, +						      HT_MCS0_MCS7, RF_1TX, +						      base); + +		raw = (u16) (rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G][path][RF_2TX][7] >> 24) & 0xFF; +		base = (raw >> 4) * 10 + (raw & 0xF); +		_rtl92ee_phy_set_txpower_by_rate_base(hw, BAND_ON_2_4G, path, +						      HT_MCS8_MCS15, RF_2TX, +						      base); +	} +} + +static void _phy_convert_txpower_dbm_to_relative_value(u32 *data, u8 start, +						       u8 end, u8 base) +{ +	char i = 0; +	u8 tmp = 0; +	u32 temp_data = 0; + +	for (i = 3; i >= 0; --i) { +		if (i >= start && i <= end) { +			/* Get the exact value */ +			tmp = (u8) (*data >> (i * 8)) & 0xF; +			tmp += ((u8) ((*data >> (i * 8 + 4)) & 0xF)) * 10; + +			/* Change the value to a relative value */ +			tmp = (tmp > base) ? tmp - base : base - tmp; +		} else { +			tmp = (u8) (*data >> (i * 8)) & 0xFF; +		} +		temp_data <<= 8; +		temp_data |= tmp; +	} +	*data = temp_data; +} + +static void _rtl92ee_phy_convert_txpower_dbm_to_relative_value(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	u8 base = 0, rf = 0, band = BAND_ON_2_4G; + +	for (rf = RF90_PATH_A; rf <= RF90_PATH_B; ++rf) { +		if (rf == RF90_PATH_A) { +			base = _rtl92ee_phy_get_txpower_by_rate_base(hw, band, +								     rf, RF_1TX, +								     CCK); +			_phy_convert_txpower_dbm_to_relative_value( +				&(rtlphy->tx_power_by_rate_offset[band][rf][RF_1TX][2]), +				1, 1, base); +			_phy_convert_txpower_dbm_to_relative_value( +				&(rtlphy->tx_power_by_rate_offset[band][rf][RF_1TX][3]), +				1, 3, base); +		} else if (rf == RF90_PATH_B) { +			base = _rtl92ee_phy_get_txpower_by_rate_base(hw, band, +								     rf, RF_1TX, +								     CCK); +			_phy_convert_txpower_dbm_to_relative_value( +				&(rtlphy->tx_power_by_rate_offset[band][rf][RF_1TX][3]), +				0, 0, base); +			_phy_convert_txpower_dbm_to_relative_value( +				&(rtlphy->tx_power_by_rate_offset[band][rf][RF_1TX][2]), +				1, 3, base); +		} +		base = _rtl92ee_phy_get_txpower_by_rate_base(hw, band, rf, +							     RF_1TX, OFDM); +		_phy_convert_txpower_dbm_to_relative_value( +			&(rtlphy->tx_power_by_rate_offset[band][rf][RF_1TX][0]), +			0, 3, base); +		_phy_convert_txpower_dbm_to_relative_value( +			&(rtlphy->tx_power_by_rate_offset[band][rf][RF_1TX][1]), +			0, 3, base); + +		base = _rtl92ee_phy_get_txpower_by_rate_base(hw, band, rf, +							     RF_1TX, +							     HT_MCS0_MCS7); +		_phy_convert_txpower_dbm_to_relative_value( +			&(rtlphy->tx_power_by_rate_offset[band][rf][RF_1TX][4]), +			0, 3, base); +		_phy_convert_txpower_dbm_to_relative_value( +			&(rtlphy->tx_power_by_rate_offset[band][rf][RF_1TX][5]), +			0, 3, base); +		base = _rtl92ee_phy_get_txpower_by_rate_base(hw, band, rf, +							     RF_2TX, +							     HT_MCS8_MCS15); +		_phy_convert_txpower_dbm_to_relative_value( +			&(rtlphy->tx_power_by_rate_offset[band][rf][RF_2TX][6]), +			0, 3, base); +		_phy_convert_txpower_dbm_to_relative_value( +			&(rtlphy->tx_power_by_rate_offset[band][rf][RF_2TX][7]), +			0, 3, base); +	} +	RT_TRACE(COMP_POWER, DBG_TRACE, +		 ("<== _rtl92ee_phy_convert_txpower_dbm_to_relative_value()\n")); +} + +static void _rtl92ee_phy_txpower_by_rate_configuration(struct ieee80211_hw *hw) +{ +	_rtl92ee_phy_store_txpower_by_rate_base(hw); +	_rtl92ee_phy_convert_txpower_dbm_to_relative_value(hw); +} + +static bool _rtl92ee_phy_bb8192ee_config_parafile(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); +	bool rtstatus; + +	rtstatus = _rtl92ee_phy_config_bb_with_headerfile(hw, +						       BASEBAND_CONFIG_PHY_REG); +	if (!rtstatus) { +		RT_TRACE(COMP_ERR, DBG_EMERG, ("Write BB Reg Fail!!")); +		return false; +	} + +	_rtl92ee_phy_init_tx_power_by_rate(hw); +	if (rtlefuse->autoload_failflag == false) { +		rtlphy->pwrgroup_cnt = 0; +		rtstatus = _rtl92ee_phy_config_bb_with_pgheaderfile(hw, +						       BASEBAND_CONFIG_PHY_REG); +	} +	_rtl92ee_phy_txpower_by_rate_configuration(hw); +	if (!rtstatus) { +		RT_TRACE(COMP_ERR, DBG_EMERG, ("BB_PG Reg Fail!!")); +		return false; +	} +	rtstatus = _rtl92ee_phy_config_bb_with_headerfile(hw, +						       BASEBAND_CONFIG_AGC_TAB); +	if (!rtstatus) { +		RT_TRACE(COMP_ERR, DBG_EMERG, ("AGC Table Fail\n")); +		return false; +	} +	rtlphy->bcck_high_power = (bool) (rtl_get_bbreg(hw, +						       RFPGA0_XA_HSSIPARAMETER2, +						       0x200)); + +	return true; +} + +static bool _rtl92ee_phy_config_mac_with_headerfile(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u32 i; +	u32 arraylength; +	u32 *ptrarray; + +	RT_TRACE(COMP_INIT, DBG_TRACE, ("Read Rtl8192EMACPHY_Array\n")); +	arraylength = RTL8192EE_MAC_ARRAY_LEN; +	ptrarray = RTL8192EE_MAC_ARRAY; +	RT_TRACE(COMP_INIT, DBG_LOUD, +		 ("Img:RTL8192EE_MAC_ARRAY LEN %d\n" , arraylength)); +	for (i = 0; i < arraylength; i = i + 2) +		rtl_write_byte(rtlpriv, ptrarray[i], (u8) ptrarray[i + 1]); +	return true; +} + +static bool _rtl92ee_phy_config_bb_with_headerfile(struct ieee80211_hw *hw, +						   u8 configtype) +{ +	#define READ_NEXT_PAIR(v1, v2, i) \ +		do { \ +			i += 2; \ +			v1 = array[i]; \ +			v2 = array[i+1]; \ +		} while (0) + +	int i; +	u32 *array; +	u16 len; +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u32 v1 = 0, v2 = 0; + +	if (configtype == BASEBAND_CONFIG_PHY_REG) { +		len = RTL8192EE_PHY_REG_ARRAY_LEN; +		array = RTL8192EE_PHY_REG_ARRAY; + +		for (i = 0; i < len; i = i + 2) { +			v1 = array[i]; +			v2 = array[i+1]; +			if (v1 < 0xcdcdcdcd) { +				_rtl92ee_config_bb_reg(hw, v1, v2); +			} else {/*This line is the start line of branch.*/ +				/* to protect READ_NEXT_PAIR not overrun */ +				if (i >= len - 2) +					break; + +				if (!_check_condition(hw , array[i])) { +					/*Discard the following pairs*/ +					READ_NEXT_PAIR(v1, v2, i); +					while (v2 != 0xDEAD && +					       v2 != 0xCDEF && +					       v2 != 0xCDCD && i < len - 2) +					    READ_NEXT_PAIR(v1, v2, i); +					i -= 2; /* prevent from for-loop += 2*/ +				} else{/* Configure matched pairs and +				       * skip to end of if-else. */ +					READ_NEXT_PAIR(v1, v2, i); +					while (v2 != 0xDEAD && +					       v2 != 0xCDEF && +					       v2 != 0xCDCD && i < len - 2) { +						_rtl92ee_config_bb_reg(hw, v1, +								       v2); +						READ_NEXT_PAIR(v1, v2, i); +					} + +					while (v2 != 0xDEAD && i < len - 2) +						READ_NEXT_PAIR(v1, v2, i); +				} +			} +		} +	} else if (configtype == BASEBAND_CONFIG_AGC_TAB) { +			len = RTL8192EE_AGC_TAB_ARRAY_LEN; +			array = RTL8192EE_AGC_TAB_ARRAY; + +			for (i = 0; i < len; i = i + 2) { +				v1 = array[i]; +				v2 = array[i+1]; +				if (v1 < 0xCDCDCDCD) { +					rtl_set_bbreg(hw, array[i], MASKDWORD, +						      array[i + 1]); +					udelay(1); +					continue; +			    } else{/*This line is the start line of branch.*/ +				  /* to protect READ_NEXT_PAIR not overrun */ +					if (i >= len - 2) +						break; + +					if (!_check_condition(hw , array[i])) { +						/*Discard the following pairs*/ +						READ_NEXT_PAIR(v1, v2, i); +						while (v2 != 0xDEAD && +						       v2 != 0xCDEF && +						       v2 != 0xCDCD && +						       i < len - 2) +						    READ_NEXT_PAIR(v1, v2, i); +						i -= 2; /* prevent from for-loop += 2*/ +					} else {/* Configure matched pairs and +					       * skip to end of if-else.*/ +						READ_NEXT_PAIR(v1, v2, i); +						while (v2 != 0xDEAD && +						       v2 != 0xCDEF && +						       v2 != 0xCDCD && +						       i < len - 2) { +							rtl_set_bbreg(hw, +								      array[i], +								      MASKDWORD, +								      array[i + 1]); +							udelay(1); +							READ_NEXT_PAIR(v1 , v2 , i); +						} + +						while (v2 != 0xDEAD && +						       i < len - 2) +							READ_NEXT_PAIR(v1 , v2 , i); +					} +				} +				RT_TRACE(COMP_INIT, DBG_TRACE, +					 ("The agctab_array_table[0] is %x Rtl818EEPHY_REGArray[1] is %x\n", +					  array[i], +					  array[i + 1])); +		} +	} +	return true; +} + +static u8 _rtl92ee_get_rate_section_index(u32 regaddr) +{ +	u8 index = 0; + +	switch (regaddr) { +	case RTXAGC_A_RATE18_06: +		index = 0; +		break; +	case RTXAGC_A_RATE54_24: +		index = 1; +		break; +	case RTXAGC_A_CCK1_MCS32: +		index = 2; +		break; +	case RTXAGC_B_CCK11_A_CCK2_11: +		index = 3; +		break; +	case RTXAGC_A_MCS03_MCS00: +		index = 4; +		break; +	case RTXAGC_A_MCS07_MCS04: +		index = 5; +		break; +	case RTXAGC_A_MCS11_MCS08: +		index = 6; +		break; +	case RTXAGC_A_MCS15_MCS12: +		index = 7; +		break; +	case RTXAGC_B_RATE18_06: +		index = 0; +		break; +	case RTXAGC_B_RATE54_24: +		index = 1; +		break; +	case RTXAGC_B_CCK1_55_MCS32: +		index = 2; +		break; +	case RTXAGC_B_MCS03_MCS00: +		index = 4; +		break; +	case RTXAGC_B_MCS07_MCS04: +		index = 5; +		break; +	case RTXAGC_B_MCS11_MCS08: +		index = 6; +		break; +	case RTXAGC_B_MCS15_MCS12: +		index = 7; +		break; +	default: +		regaddr &= 0xFFF; +		if (regaddr >= 0xC20 && regaddr <= 0xC4C) +			index = (u8) ((regaddr - 0xC20) / 4); +		else if (regaddr >= 0xE20 && regaddr <= 0xE4C) +			index = (u8) ((regaddr - 0xE20) / 4); +		break; +	}; +	return index; +} + +static void _rtl92ee_store_tx_power_by_rate(struct ieee80211_hw *hw, +					    enum band_type band, +					    enum radio_path rfpath, +					    u32 txnum, u32 regaddr, +					    u32 bitmask, u32 data) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	u8 section = _rtl92ee_get_rate_section_index(regaddr); + +	if (band != BAND_ON_2_4G && band != BAND_ON_5G) { +		RT_TRACE(FPHY, PHY_TXPWR, ("Invalid Band %d\n", band)); +		return; +	} + +	if (rfpath > MAX_RF_PATH - 1) { +		RT_TRACE(FPHY, PHY_TXPWR, ("Invalid RfPath %d\n", rfpath)); +		return; +	} +	if (txnum > MAX_RF_PATH - 1) { +		RT_TRACE(FPHY, PHY_TXPWR, ("Invalid TxNum %d\n", txnum)); +		return; +	} + +	rtlphy->tx_power_by_rate_offset[band][rfpath][txnum][section] = data; +} + +static bool _rtl92ee_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw, +						     u8 configtype) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	int i; +	u32 *phy_regarray_table_pg; +	u16 phy_regarray_pg_len; +	u32 v1 = 0, v2 = 0, v3 = 0, v4 = 0, v5 = 0, v6 = 0; + +	phy_regarray_pg_len = RTL8192EE_PHY_REG_ARRAY_PG_LEN; +	phy_regarray_table_pg = RTL8192EE_PHY_REG_ARRAY_PG; + +	if (configtype == BASEBAND_CONFIG_PHY_REG) { +		for (i = 0; i < phy_regarray_pg_len; i = i + 6) { +			v1 = phy_regarray_table_pg[i]; +			v2 = phy_regarray_table_pg[i+1]; +			v3 = phy_regarray_table_pg[i+2]; +			v4 = phy_regarray_table_pg[i+3]; +			v5 = phy_regarray_table_pg[i+4]; +			v6 = phy_regarray_table_pg[i+5]; + +			if (v1 < 0xcdcdcdcd) { +				_rtl92ee_store_tx_power_by_rate(hw, v1, v2, v3, +								v4, v5, v6); +				continue; +			} +		} +	} else { +		RT_TRACE(COMP_SEND, DBG_TRACE, +			 ("configtype != BaseBand_Config_PHY_REG\n")); +	} +	return true; +} + +bool rtl92ee_phy_config_rf_with_headerfile(struct ieee80211_hw  *hw, +					   enum radio_path rfpath) +{ +	#define READ_NEXT_RF_PAIR(v1, v2, i) \ +		do { \ +			i += 2; \ +			v1 = array[i]; \ +			v2 = array[i+1]; \ +		} while (0) + +	int i; +	u32 *array; +	u16 len; +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u32 v1 = 0, v2 = 0; + +	switch (rfpath) { +	case RF90_PATH_A: +		len = RTL8192EE_RADIOA_ARRAY_LEN; +		array = RTL8192EE_RADIOA_ARRAY; +		RT_TRACE(COMP_INIT, DBG_LOUD, +			 ("Radio_A:RTL8192EE_RADIOA_ARRAY %d\n" , len)); +		RT_TRACE(COMP_INIT, DBG_LOUD, ("Radio No %x\n", rfpath)); +		for (i = 0; i < len; i = i + 2) { +			v1 = array[i]; +			v2 = array[i+1]; +			if (v1 < 0xcdcdcdcd) { +				_rtl92ee_config_rf_radio_a(hw, v1, v2); +				continue; +			} else {/*This line is the start line of branch.*/ +				/* to protect READ_NEXT_PAIR not overrun */ +				if (i >= len - 2) +					break; + +				if (!_check_condition(hw , array[i])) { +					/*Discard the following pairs*/ +					READ_NEXT_RF_PAIR(v1, v2, i); +					while (v2 != 0xDEAD && +					       v2 != 0xCDEF && +					       v2 != 0xCDCD && i < len - 2) +						READ_NEXT_RF_PAIR(v1, v2, i); +					i -= 2; /* prevent from for-loop += 2*/ +				} else {/* Configure matched pairs and +					 * skip to end of if-else.*/ +					READ_NEXT_RF_PAIR(v1, v2, i); +					while (v2 != 0xDEAD && +					       v2 != 0xCDEF && +					       v2 != 0xCDCD && i < len - 2) { +						_rtl92ee_config_rf_radio_a(hw, +									   v1, +									   v2); +						READ_NEXT_RF_PAIR(v1, v2, i); +					} + +					while (v2 != 0xDEAD && i < len - 2) +						READ_NEXT_RF_PAIR(v1, v2, i); +				} +			} +		} +		break; + +	case RF90_PATH_B: +		len = RTL8192EE_RADIOB_ARRAY_LEN; +		array = RTL8192EE_RADIOB_ARRAY; +		RT_TRACE(COMP_INIT, DBG_LOUD, +			 ("Radio_A:RTL8192EE_RADIOB_ARRAY %d\n" , len)); +		RT_TRACE(COMP_INIT, DBG_LOUD, ("Radio No %x\n", rfpath)); +		for (i = 0; i < len; i = i + 2) { +			v1 = array[i]; +			v2 = array[i+1]; +			if (v1 < 0xcdcdcdcd) { +				_rtl92ee_config_rf_radio_b(hw, v1, v2); +				continue; +			} else {/*This line is the start line of branch.*/ +				/* to protect READ_NEXT_PAIR not overrun */ +				if (i >= len - 2) +					break; + +				if (!_check_condition(hw , array[i])) { +					/*Discard the following pairs*/ +					READ_NEXT_RF_PAIR(v1, v2, i); +					while (v2 != 0xDEAD && +					       v2 != 0xCDEF && +					       v2 != 0xCDCD && i < len - 2) +						READ_NEXT_RF_PAIR(v1, v2, i); +					i -= 2; /* prevent from for-loop += 2*/ +				} else {/* Configure matched pairs and +					 * skip to end of if-else.*/ +					READ_NEXT_RF_PAIR(v1, v2, i); +					while (v2 != 0xDEAD && +					       v2 != 0xCDEF && +					       v2 != 0xCDCD && i < len - 2) { +						_rtl92ee_config_rf_radio_b(hw, +									   v1, +									   v2); +						READ_NEXT_RF_PAIR(v1, v2, i); +					} + +					while (v2 != 0xDEAD && i < len - 2) +						READ_NEXT_RF_PAIR(v1, v2, i); +				} +			} +		} +		break; +	case RF90_PATH_C: +		RT_TRACE(COMP_ERR, DBG_EMERG, +			 ("switch case not process\n")); +		break; +	case RF90_PATH_D: +		RT_TRACE(COMP_ERR, DBG_EMERG, +			 ("switch case not process\n")); +		break; +	} +	return true; +} + +void rtl92ee_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); + +	rtlphy->default_initialgain[0] = +		(u8) rtl_get_bbreg(hw, ROFDM0_XAAGCCORE1, MASKBYTE0); +	rtlphy->default_initialgain[1] = +		(u8) rtl_get_bbreg(hw, ROFDM0_XBAGCCORE1, MASKBYTE0); +	rtlphy->default_initialgain[2] = +		(u8) rtl_get_bbreg(hw, ROFDM0_XCAGCCORE1, MASKBYTE0); +	rtlphy->default_initialgain[3] = +		(u8) rtl_get_bbreg(hw, ROFDM0_XDAGCCORE1, MASKBYTE0); + +	RT_TRACE(COMP_INIT, DBG_TRACE, +		 ("Default initial gain (c50 = 0x%x, c58 = 0x%x, c60 = 0x%x, c68 = 0x%x\n", +		  rtlphy->default_initialgain[0], +		  rtlphy->default_initialgain[1], +		  rtlphy->default_initialgain[2], +		  rtlphy->default_initialgain[3])); + +	rtlphy->framesync = (u8) rtl_get_bbreg(hw, +					       ROFDM0_RXDETECTOR3, MASKBYTE0); +	rtlphy->framesync_c34 = rtl_get_bbreg(hw, +					      ROFDM0_RXDETECTOR2, MASKDWORD); + +	RT_TRACE(COMP_INIT, DBG_TRACE, +		 ("Default framesync (0x%x) = 0x%x\n", +		  ROFDM0_RXDETECTOR3, rtlphy->framesync)); +} + +static void _rtl92ee_phy_init_bb_rf_register_definition(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); + +	rtlphy->phyreg_def[RF90_PATH_A].rfintfs = RFPGA0_XAB_RFINTERFACESW; +	rtlphy->phyreg_def[RF90_PATH_B].rfintfs = RFPGA0_XAB_RFINTERFACESW; + +	rtlphy->phyreg_def[RF90_PATH_A].rfintfo = RFPGA0_XA_RFINTERFACEOE; +	rtlphy->phyreg_def[RF90_PATH_B].rfintfo = RFPGA0_XB_RFINTERFACEOE; + +	rtlphy->phyreg_def[RF90_PATH_A].rfintfe = RFPGA0_XA_RFINTERFACEOE; +	rtlphy->phyreg_def[RF90_PATH_B].rfintfe = RFPGA0_XB_RFINTERFACEOE; + +	rtlphy->phyreg_def[RF90_PATH_A].rf3wire_offset = +							RFPGA0_XA_LSSIPARAMETER; +	rtlphy->phyreg_def[RF90_PATH_B].rf3wire_offset = +							RFPGA0_XB_LSSIPARAMETER; + +	rtlphy->phyreg_def[RF90_PATH_A].rfhssi_para2 = RFPGA0_XA_HSSIPARAMETER2; +	rtlphy->phyreg_def[RF90_PATH_B].rfhssi_para2 = RFPGA0_XB_HSSIPARAMETER2; + +	rtlphy->phyreg_def[RF90_PATH_A].rflssi_readback = +							 RFPGA0_XA_LSSIREADBACK; +	rtlphy->phyreg_def[RF90_PATH_B].rflssi_readback = +							 RFPGA0_XB_LSSIREADBACK; + +	rtlphy->phyreg_def[RF90_PATH_A].rflssi_readbackpi = +						      TRANSCEIVEA_HSPI_READBACK; +	rtlphy->phyreg_def[RF90_PATH_B].rflssi_readbackpi = +						      TRANSCEIVEB_HSPI_READBACK; +} + +void rtl92ee_phy_get_txpower_level(struct ieee80211_hw *hw, long *powerlevel) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	u8 txpwr_level; +	long txpwr_dbm; + +	txpwr_level = rtlphy->cur_cck_txpwridx; +	txpwr_dbm = _rtl92ee_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_B, +						  txpwr_level); +	txpwr_level = rtlphy->cur_ofdm24g_txpwridx; +	if (_rtl92ee_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_G, txpwr_level) > +	    txpwr_dbm) +		txpwr_dbm = _rtl92ee_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_G, +							  txpwr_level); +	txpwr_level = rtlphy->cur_ofdm24g_txpwridx; +	if (_rtl92ee_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_N_24G, +					  txpwr_level) > txpwr_dbm) +		txpwr_dbm = _rtl92ee_phy_txpwr_idx_to_dbm(hw, +							  WIRELESS_MODE_N_24G, +							  txpwr_level); +	*powerlevel = txpwr_dbm; +} + +static u8 _rtl92ee_phy_get_ratesection_intxpower_byrate(enum radio_path path, +							u8 rate) +{ +	u8 rate_section = 0; + +	switch (rate) { +	case DESC92C_RATE1M: +		rate_section = 2; +		break; + +	case DESC92C_RATE2M: +	case DESC92C_RATE5_5M: +		if (path == RF90_PATH_A) +			rate_section = 3; +		else if (path == RF90_PATH_B) +			rate_section = 2; +		break; + +	case DESC92C_RATE11M: +		rate_section = 3; +		break; + +	case DESC92C_RATE6M: +	case DESC92C_RATE9M: +	case DESC92C_RATE12M: +	case DESC92C_RATE18M: +		rate_section = 0; +		break; + +	case DESC92C_RATE24M: +	case DESC92C_RATE36M: +	case DESC92C_RATE48M: +	case DESC92C_RATE54M: +		rate_section = 1; +		break; + +	case DESC92C_RATEMCS0: +	case DESC92C_RATEMCS1: +	case DESC92C_RATEMCS2: +	case DESC92C_RATEMCS3: +		rate_section = 4; +		break; + +	case DESC92C_RATEMCS4: +	case DESC92C_RATEMCS5: +	case DESC92C_RATEMCS6: +	case DESC92C_RATEMCS7: +		rate_section = 5; +		break; + +	case DESC92C_RATEMCS8: +	case DESC92C_RATEMCS9: +	case DESC92C_RATEMCS10: +	case DESC92C_RATEMCS11: +		rate_section = 6; +		break; + +	case DESC92C_RATEMCS12: +	case DESC92C_RATEMCS13: +	case DESC92C_RATEMCS14: +	case DESC92C_RATEMCS15: +		rate_section = 7; +		break; + +	default: +		RT_ASSERT(true, ("Rate_Section is Illegal\n")); +		break; +	} + +	return rate_section; +} + +static u8 _rtl92ee_get_txpower_by_rate(struct ieee80211_hw *hw, +				       enum band_type band, +				       enum radio_path rf, u8 rate) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	u8 shift = 0, sec, tx_num; +	char diff = 0; + +	sec = _rtl92ee_phy_get_ratesection_intxpower_byrate(rf, rate); +	tx_num = RF_TX_NUM_NONIMPLEMENT; + +	if (tx_num == RF_TX_NUM_NONIMPLEMENT) { +		if ((rate >= DESC92C_RATEMCS8 && rate <= DESC92C_RATEMCS15)) +			tx_num = RF_2TX; +		else +			tx_num = RF_1TX; +	} + +	switch (rate) { +	case DESC92C_RATE1M: +		shift = 0; +		break; +	case DESC92C_RATE2M: +		shift = 8; +		break; +	case DESC92C_RATE5_5M: +		shift = 16; +		break; +	case DESC92C_RATE11M: +		shift = 24; +		break; + +	case DESC92C_RATE6M: +		shift = 0; +		break; +	case DESC92C_RATE9M: +		shift = 8; +		break; +	case DESC92C_RATE12M: +		shift = 16; +		break; +	case DESC92C_RATE18M: +		shift = 24; +		break; + +	case DESC92C_RATE24M: +		shift = 0; +		break; +	case DESC92C_RATE36M: +		shift = 8; +		break; +	case DESC92C_RATE48M: +		shift = 16; +		break; +	case DESC92C_RATE54M: +		shift = 24; +		break; + +	case DESC92C_RATEMCS0: +		shift = 0; +		break; +	case DESC92C_RATEMCS1: +		shift = 8; +		break; +	case DESC92C_RATEMCS2: +		shift = 16; +		break; +	case DESC92C_RATEMCS3: +		shift = 24; +		break; + +	case DESC92C_RATEMCS4: +		shift = 0; +		break; +	case DESC92C_RATEMCS5: +		shift = 8; +		break; +	case DESC92C_RATEMCS6: +		shift = 16; +		break; +	case DESC92C_RATEMCS7: +		shift = 24; +		break; + +	case DESC92C_RATEMCS8: +		shift = 0; +		break; +	case DESC92C_RATEMCS9: +		shift = 8; +		break; +	case DESC92C_RATEMCS10: +		shift = 16; +		break; +	case DESC92C_RATEMCS11: +		shift = 24; +		break; + +	case DESC92C_RATEMCS12: +		shift = 0; +		break; +	case DESC92C_RATEMCS13: +		shift = 8; +		break; +	case DESC92C_RATEMCS14: +		shift = 16; +		break; +	case DESC92C_RATEMCS15: +		shift = 24; +		break; + +	default: +		RT_ASSERT(true, ("Rate_Section is Illegal\n")); +		break; +	} + +	diff = (u8) (rtlphy->tx_power_by_rate_offset[band][rf][tx_num][sec] >> +		     shift) & 0xff; + +	return	diff; +} + +static u8 _rtl92ee_get_txpower_index(struct ieee80211_hw *hw, +				     enum radio_path rfpath, u8 rate, +				     u8 bw, u8 channel) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_efuse *rtlefuse = rtl_efuse(rtlpriv); +	u8 index = (channel - 1); +	u8 tx_power = 0; +	u8 diff = 0; + +	if (channel < 1 || channel > 14) { +		index = 0; +		RT_TRACE(COMP_POWER_TRACKING, DBG_DMESG, +			 ("Illegal channel!!\n")); +	} + +	if (IS_CCK_RATE(rate)) +		tx_power = rtlefuse->txpwrlevel_cck[rfpath][index]; +	else if (DESC92C_RATE6M <= rate) +		tx_power = rtlefuse->txpwrlevel_ht40_1s[rfpath][index]; + +	/* OFDM-1T*/ +	if (DESC92C_RATE6M <= rate && rate <= DESC92C_RATE54M && +	    !IS_CCK_RATE(rate)) +		tx_power += rtlefuse->txpwr_legacyhtdiff[rfpath][TX_1S]; + +	/* BW20-1S, BW20-2S */ +	if (bw == HT_CHANNEL_WIDTH_20) { +		if (DESC92C_RATEMCS0 <= rate && rate <= DESC92C_RATEMCS15) +			tx_power += rtlefuse->txpwr_ht20diff[rfpath][TX_1S]; +		if (DESC92C_RATEMCS8 <= rate && rate <= DESC92C_RATEMCS15) +			tx_power += rtlefuse->txpwr_ht20diff[rfpath][TX_2S]; +	} else if (bw == HT_CHANNEL_WIDTH_20_40) {/* BW40-1S, BW40-2S */ +		if (DESC92C_RATEMCS0 <= rate && rate <= DESC92C_RATEMCS15) +			tx_power += rtlefuse->txpwr_ht40diff[rfpath][TX_1S]; +		if (DESC92C_RATEMCS8 <= rate && rate <= DESC92C_RATEMCS15) +			tx_power += rtlefuse->txpwr_ht40diff[rfpath][TX_2S]; +	} + +	if (rtlefuse->eeprom_regulatory != 2) +		diff = _rtl92ee_get_txpower_by_rate(hw, BAND_ON_2_4G, +						    rfpath, rate); + +	tx_power += diff; + +	if (tx_power > MAX_POWER_INDEX) +		tx_power = MAX_POWER_INDEX; + +	return tx_power; +} + +static void _rtl92ee_set_txpower_index(struct ieee80211_hw *hw, u8 pwr_idx, +				       enum radio_path rfpath, u8 rate) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); + +	if (rfpath == RF90_PATH_A) { +		switch (rate) { +		case DESC92C_RATE1M: +			rtl_set_bbreg(hw, RTXAGC_A_CCK1_MCS32, +				      MASKBYTE1, pwr_idx); +			break; +		case DESC92C_RATE2M: +			rtl_set_bbreg(hw, RTXAGC_B_CCK11_A_CCK2_11, +				      MASKBYTE1, pwr_idx); +			break; +		case DESC92C_RATE5_5M: +			rtl_set_bbreg(hw, RTXAGC_B_CCK11_A_CCK2_11, +				      MASKBYTE2, pwr_idx); +			break; +		case DESC92C_RATE11M: +			rtl_set_bbreg(hw, RTXAGC_B_CCK11_A_CCK2_11, +				      MASKBYTE3, pwr_idx); +			break; +		case DESC92C_RATE6M: +			rtl_set_bbreg(hw, RTXAGC_A_RATE18_06, +				      MASKBYTE0, pwr_idx); +			break; +		case DESC92C_RATE9M: +			rtl_set_bbreg(hw, RTXAGC_A_RATE18_06, +				      MASKBYTE1, pwr_idx); +			break; +		case DESC92C_RATE12M: +			rtl_set_bbreg(hw, RTXAGC_A_RATE18_06, +				      MASKBYTE2, pwr_idx); +			break; +		case DESC92C_RATE18M: +			rtl_set_bbreg(hw, RTXAGC_A_RATE18_06, +				      MASKBYTE3, pwr_idx); +			break; +		case DESC92C_RATE24M: +			rtl_set_bbreg(hw, RTXAGC_A_RATE54_24, +				      MASKBYTE0, pwr_idx); +			break; +		case DESC92C_RATE36M: +			rtl_set_bbreg(hw, RTXAGC_A_RATE54_24, +				      MASKBYTE1, pwr_idx); +			break; +		case DESC92C_RATE48M: +			rtl_set_bbreg(hw, RTXAGC_A_RATE54_24, +				      MASKBYTE2, pwr_idx); +			break; +		case DESC92C_RATE54M: +			rtl_set_bbreg(hw, RTXAGC_A_RATE54_24, +				      MASKBYTE3, pwr_idx); +			break; +		case DESC92C_RATEMCS0: +			rtl_set_bbreg(hw, RTXAGC_A_MCS03_MCS00, +				      MASKBYTE0, pwr_idx); +			break; +		case DESC92C_RATEMCS1: +			rtl_set_bbreg(hw, RTXAGC_A_MCS03_MCS00, +				      MASKBYTE1, pwr_idx); +			break; +		case DESC92C_RATEMCS2: +			rtl_set_bbreg(hw, RTXAGC_A_MCS03_MCS00, +				      MASKBYTE2, pwr_idx); +			break; +		case DESC92C_RATEMCS3: +			rtl_set_bbreg(hw, RTXAGC_A_MCS03_MCS00, +				      MASKBYTE3, pwr_idx); +			break; +		case DESC92C_RATEMCS4: +			rtl_set_bbreg(hw, RTXAGC_A_MCS07_MCS04, +				      MASKBYTE0, pwr_idx); +			break; +		case DESC92C_RATEMCS5: +			rtl_set_bbreg(hw, RTXAGC_A_MCS07_MCS04, +				      MASKBYTE1, pwr_idx); +			break; +		case DESC92C_RATEMCS6: +			rtl_set_bbreg(hw, RTXAGC_A_MCS07_MCS04, +				      MASKBYTE2, pwr_idx); +			break; +		case DESC92C_RATEMCS7: +			rtl_set_bbreg(hw, RTXAGC_A_MCS07_MCS04, +				      MASKBYTE3, pwr_idx); +			break; +		case DESC92C_RATEMCS8: +			rtl_set_bbreg(hw, RTXAGC_A_MCS11_MCS08, +				      MASKBYTE0, pwr_idx); +			break; +		case DESC92C_RATEMCS9: +			rtl_set_bbreg(hw, RTXAGC_A_MCS11_MCS08, +				      MASKBYTE1, pwr_idx); +			break; +		case DESC92C_RATEMCS10: +			rtl_set_bbreg(hw, RTXAGC_A_MCS11_MCS08, +				      MASKBYTE2, pwr_idx); +			break; +		case DESC92C_RATEMCS11: +			rtl_set_bbreg(hw, RTXAGC_A_MCS11_MCS08, +				      MASKBYTE3, pwr_idx); +			break; +		case DESC92C_RATEMCS12: +			rtl_set_bbreg(hw, RTXAGC_A_MCS15_MCS12, +				      MASKBYTE0, pwr_idx); +			break; +		case DESC92C_RATEMCS13: +			rtl_set_bbreg(hw, RTXAGC_A_MCS15_MCS12, +				      MASKBYTE1, pwr_idx); +			break; +		case DESC92C_RATEMCS14: +			rtl_set_bbreg(hw, RTXAGC_A_MCS15_MCS12, +				      MASKBYTE2, pwr_idx); +			break; +		case DESC92C_RATEMCS15: +			rtl_set_bbreg(hw, RTXAGC_A_MCS15_MCS12, +				      MASKBYTE3, pwr_idx); +			break; +		default: +			RT_TRACE(COMP_POWER, DBG_LOUD, ("Invalid Rate!!\n")); +			break; +		} +	} else if (rfpath == RF90_PATH_B) { +		switch (rate) { +		case DESC92C_RATE1M: +			rtl_set_bbreg(hw, RTXAGC_B_CCK1_55_MCS32, +				      MASKBYTE1, pwr_idx); +			break; +		case DESC92C_RATE2M: +			rtl_set_bbreg(hw, RTXAGC_B_CCK1_55_MCS32, +				      MASKBYTE2, pwr_idx); +			break; +		case DESC92C_RATE5_5M: +			rtl_set_bbreg(hw, RTXAGC_B_CCK1_55_MCS32, +				      MASKBYTE3, pwr_idx); +			break; +		case DESC92C_RATE11M: +			rtl_set_bbreg(hw, RTXAGC_B_CCK11_A_CCK2_11, +				      MASKBYTE0, pwr_idx); +			break; +		case DESC92C_RATE6M: +			rtl_set_bbreg(hw, RTXAGC_B_RATE18_06, +				      MASKBYTE0, pwr_idx); +			break; +		case DESC92C_RATE9M: +			rtl_set_bbreg(hw, RTXAGC_B_RATE18_06, +				      MASKBYTE1, pwr_idx); +			break; +		case DESC92C_RATE12M: +			rtl_set_bbreg(hw, RTXAGC_B_RATE18_06, +				      MASKBYTE2, pwr_idx); +			break; +		case DESC92C_RATE18M: +			rtl_set_bbreg(hw, RTXAGC_B_RATE18_06, +				      MASKBYTE3, pwr_idx); +			break; +		case DESC92C_RATE24M: +			rtl_set_bbreg(hw, RTXAGC_B_RATE54_24, +				      MASKBYTE0, pwr_idx); +			break; +		case DESC92C_RATE36M: +			rtl_set_bbreg(hw, RTXAGC_B_RATE54_24, +				      MASKBYTE1, pwr_idx); +			break; +		case DESC92C_RATE48M: +			rtl_set_bbreg(hw, RTXAGC_B_RATE54_24, +				      MASKBYTE2, pwr_idx); +			break; +		case DESC92C_RATE54M: +			rtl_set_bbreg(hw, RTXAGC_B_RATE54_24, +				      MASKBYTE3, pwr_idx); +			break; +		case DESC92C_RATEMCS0: +			rtl_set_bbreg(hw, RTXAGC_B_MCS03_MCS00, +				      MASKBYTE0, pwr_idx); +			break; +		case DESC92C_RATEMCS1: +			rtl_set_bbreg(hw, RTXAGC_B_MCS03_MCS00, +				      MASKBYTE1, pwr_idx); +			break; +		case DESC92C_RATEMCS2: +			rtl_set_bbreg(hw, RTXAGC_B_MCS03_MCS00, +				      MASKBYTE2, pwr_idx); +			break; +		case DESC92C_RATEMCS3: +			rtl_set_bbreg(hw, RTXAGC_B_MCS03_MCS00, +				      MASKBYTE3, pwr_idx); +			break; +		case DESC92C_RATEMCS4: +			rtl_set_bbreg(hw, RTXAGC_B_MCS07_MCS04, +				      MASKBYTE0, pwr_idx); +			break; +		case DESC92C_RATEMCS5: +			rtl_set_bbreg(hw, RTXAGC_B_MCS07_MCS04, +				      MASKBYTE1, pwr_idx); +			break; +		case DESC92C_RATEMCS6: +			rtl_set_bbreg(hw, RTXAGC_B_MCS07_MCS04, +				      MASKBYTE2, pwr_idx); +			break; +		case DESC92C_RATEMCS7: +			rtl_set_bbreg(hw, RTXAGC_B_MCS07_MCS04, +				      MASKBYTE3, pwr_idx); +			break; +		case DESC92C_RATEMCS8: +			rtl_set_bbreg(hw, RTXAGC_B_MCS11_MCS08, +				      MASKBYTE0, pwr_idx); +			break; +		case DESC92C_RATEMCS9: +			rtl_set_bbreg(hw, RTXAGC_B_MCS11_MCS08, +				      MASKBYTE1, pwr_idx); +			break; +		case DESC92C_RATEMCS10: +			rtl_set_bbreg(hw, RTXAGC_B_MCS11_MCS08, +				      MASKBYTE2, pwr_idx); +			break; +		case DESC92C_RATEMCS11: +			rtl_set_bbreg(hw, RTXAGC_B_MCS11_MCS08, +				      MASKBYTE3, pwr_idx); +			break; +		case DESC92C_RATEMCS12: +			rtl_set_bbreg(hw, RTXAGC_B_MCS15_MCS12, +				      MASKBYTE0, pwr_idx); +			break; +		case DESC92C_RATEMCS13: +			rtl_set_bbreg(hw, RTXAGC_B_MCS15_MCS12, +				      MASKBYTE1, pwr_idx); +			break; +		case DESC92C_RATEMCS14: +			rtl_set_bbreg(hw, RTXAGC_B_MCS15_MCS12, +				      MASKBYTE2, pwr_idx); +			break; +		case DESC92C_RATEMCS15: +			rtl_set_bbreg(hw, RTXAGC_B_MCS15_MCS12, +				      MASKBYTE3, pwr_idx); +			break; +		default: +			RT_TRACE(COMP_POWER, DBG_LOUD, ("Invalid Rate!!\n")); +			break; +		} +	} else { +		RT_TRACE(COMP_POWER, DBG_LOUD, ("Invalid RFPath!!\n")); +	} +} + +static void rtl92ee_phy_set_txpower_index_by_rate_array(struct ieee80211_hw *hw, +							enum radio_path rfpath, u8 bw, +							u8 channel, u8 *rates, u8 size) +{ +	u8 i; +	u8 power_index; +	for (i = 0; i < size; i++) { +		power_index = _rtl92ee_get_txpower_index(hw, rfpath, rates[i], +							 bw, channel); +		_rtl92ee_set_txpower_index(hw, power_index, rfpath, rates[i]); +	} +} + +static void rtl92ee_phy_set_txpower_index_by_rate_section(struct ieee80211_hw *hw, +							  enum radio_path rfpath, +							  u8 channel, +							  enum rate_section section) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_hal *rtlhal = rtl_hal(rtlpriv); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); + +	if (section == CCK) { +		u8 cck_rates[] = {DESC92C_RATE1M, DESC92C_RATE2M, +				  DESC92C_RATE5_5M, DESC92C_RATE11M}; +		if (rtlhal->current_bandtype == BAND_ON_2_4G) +			rtl92ee_phy_set_txpower_index_by_rate_array(hw, rfpath, +							rtlphy->current_chan_bw, +							channel, cck_rates, 4); +	} else if (section == OFDM) { +		u8 ofdm_rates[] = {DESC92C_RATE6M, DESC92C_RATE9M, +				   DESC92C_RATE12M, DESC92C_RATE18M, +				   DESC92C_RATE24M, DESC92C_RATE36M, +				   DESC92C_RATE48M, DESC92C_RATE54M}; +		rtl92ee_phy_set_txpower_index_by_rate_array(hw, rfpath, +							rtlphy->current_chan_bw, +							channel, ofdm_rates, 8); +	} else if (section == HT_MCS0_MCS7) { +		u8 ht_rates1t[]  = {DESC92C_RATEMCS0, DESC92C_RATEMCS1, +				    DESC92C_RATEMCS2, DESC92C_RATEMCS3, +				    DESC92C_RATEMCS4, DESC92C_RATEMCS5, +				    DESC92C_RATEMCS6, DESC92C_RATEMCS7}; +		rtl92ee_phy_set_txpower_index_by_rate_array(hw, rfpath, +							rtlphy->current_chan_bw, +							channel, ht_rates1t, 8); +	} else if (section == HT_MCS8_MCS15) { +		u8 ht_rates2t[]  = {DESC92C_RATEMCS8, DESC92C_RATEMCS9, +				    DESC92C_RATEMCS10, DESC92C_RATEMCS11, +				    DESC92C_RATEMCS12, DESC92C_RATEMCS13, +				    DESC92C_RATEMCS14, DESC92C_RATEMCS15}; +		rtl92ee_phy_set_txpower_index_by_rate_array(hw, rfpath, +							rtlphy->current_chan_bw, +							channel, ht_rates2t, 8); +	} else +		RT_TRACE(FPHY, PHY_TXPWR, +			 ("Invalid RateSection %d\n", section)); +} + +void rtl92ee_phy_set_txpower_level(struct ieee80211_hw *hw, u8 channel) +{ +	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); +	struct rtl_phy *rtlphy = &(rtl_priv(hw)->phy); +	enum radio_path rfpath; + +	if (rtlefuse->b_txpwr_fromeprom == false) +		return; +	for (rfpath = RF90_PATH_A; rfpath < rtlphy->num_total_rfpath; +	     rfpath++) { +		rtl92ee_phy_set_txpower_index_by_rate_section(hw, rfpath, +							      channel, CCK); +		rtl92ee_phy_set_txpower_index_by_rate_section(hw, rfpath, +							      channel, OFDM); +		rtl92ee_phy_set_txpower_index_by_rate_section(hw, rfpath, +							      channel, +							      HT_MCS0_MCS7); +		if (rtlphy->num_total_rfpath >= 2) +			rtl92ee_phy_set_txpower_index_by_rate_section(hw, +								rfpath, channel, +								HT_MCS8_MCS15); +	} +} + +static long _rtl92ee_phy_txpwr_idx_to_dbm(struct ieee80211_hw *hw, +					  enum wireless_mode wirelessmode, +					  u8 txpwridx) +{ +	long offset; +	long pwrout_dbm; + +	switch (wirelessmode) { +	case WIRELESS_MODE_B: +		offset = -7; +		break; +	case WIRELESS_MODE_G: +	case WIRELESS_MODE_N_24G: +		offset = -8; +		break; +	default: +		offset = -8; +		break; +	} +	pwrout_dbm = txpwridx / 2 + offset; +	return pwrout_dbm; +} + +void rtl92ee_phy_scan_operation_backup(struct ieee80211_hw *hw, u8 operation) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); +	enum io_type iotype; + +	if (!is_hal_stop(rtlhal)) { +		switch (operation) { +		case SCAN_OPT_BACKUP_BAND0: +			iotype = IO_CMD_PAUSE_BAND0_DM_BY_SCAN; +			rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_IO_CMD, +						      (u8 *)&iotype); + +			break; +		case SCAN_OPT_RESTORE: +			iotype = IO_CMD_RESUME_DM_BY_SCAN; +			rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_IO_CMD, +						      (u8 *)&iotype); +			break; +		default: +			RT_TRACE(COMP_ERR, DBG_EMERG, +				 ("Unknown Scan Backup operation.\n")); +			break; +		} +	} +} + +void rtl92ee_phy_set_bw_mode_callback(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +	u8 reg_bw_opmode; +	u8 reg_prsr_rsc; + +	RT_TRACE(COMP_SCAN, DBG_TRACE, +		 ("Switch to %s bandwidth\n", +		  rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20 ? +		  "20MHz" : "40MHz")); + +	if (is_hal_stop(rtlhal)) { +		rtlphy->set_bwmode_inprogress = false; +		return; +	} + +	reg_bw_opmode = rtl_read_byte(rtlpriv, REG_BWOPMODE); +	reg_prsr_rsc = rtl_read_byte(rtlpriv, REG_RRSR + 2); + +	switch (rtlphy->current_chan_bw) { +	case HT_CHANNEL_WIDTH_20: +		reg_bw_opmode |= BW_OPMODE_20MHZ; +		rtl_write_byte(rtlpriv, REG_BWOPMODE, reg_bw_opmode); +		break; +	case HT_CHANNEL_WIDTH_20_40: +		reg_bw_opmode &= ~BW_OPMODE_20MHZ; +		rtl_write_byte(rtlpriv, REG_BWOPMODE, reg_bw_opmode); +		reg_prsr_rsc = (reg_prsr_rsc & 0x90) | +			       (mac->cur_40_prime_sc << 5); +		rtl_write_byte(rtlpriv, REG_RRSR + 2, reg_prsr_rsc); +		break; +	default: +		RT_TRACE(COMP_ERR, DBG_EMERG, +			 ("unknown bandwidth: %#X\n", rtlphy->current_chan_bw)); +		break; +	} + +	switch (rtlphy->current_chan_bw) { +	case HT_CHANNEL_WIDTH_20: +		rtl_set_bbreg(hw, RFPGA0_RFMOD, BRFMOD, 0x0); +		rtl_set_bbreg(hw, RFPGA1_RFMOD, BRFMOD, 0x0); +		rtl_set_bbreg(hw, ROFDM0_TXPSEUDONOISEWGT, +			      (BIT(31) | BIT(30)), 0); +		break; +	case HT_CHANNEL_WIDTH_20_40: +		rtl_set_bbreg(hw, RFPGA0_RFMOD, BRFMOD, 0x1); +		rtl_set_bbreg(hw, RFPGA1_RFMOD, BRFMOD, 0x1); +		rtl_set_bbreg(hw, RCCK0_SYSTEM, BCCK_SIDEBAND, +			      (mac->cur_40_prime_sc >> 1)); +		rtl_set_bbreg(hw, ROFDM1_LSTF, 0xC00, +			      mac->cur_40_prime_sc); + +		rtl_set_bbreg(hw, 0x818, (BIT(26) | BIT(27)), +			      (mac->cur_40_prime_sc == +			       HAL_PRIME_CHNL_OFFSET_LOWER) ? 2 : 1); +		break; +	default: +		RT_TRACE(COMP_ERR, DBG_EMERG, +			 ("unknown bandwidth: %#X\n", rtlphy->current_chan_bw)); +		break; +	} +	rtl92ee_phy_rf6052_set_bandwidth(hw, rtlphy->current_chan_bw); +	rtlphy->set_bwmode_inprogress = false; +	RT_TRACE(COMP_SCAN, DBG_LOUD, ("\n")); +} + +void rtl92ee_phy_set_bw_mode(struct ieee80211_hw *hw, +			     enum nl80211_channel_type ch_type) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); +	u8 tmp_bw = rtlphy->current_chan_bw; + +	if (rtlphy->set_bwmode_inprogress) +		return; +	rtlphy->set_bwmode_inprogress = true; +	if ((!is_hal_stop(rtlhal)) && !(RT_CANNOT_IO(hw))) { +		rtl92ee_phy_set_bw_mode_callback(hw); +	} else { +		RT_TRACE(COMP_ERR, DBG_WARNING, +			 ("false driver sleep or unload\n")); +		rtlphy->set_bwmode_inprogress = false; +		rtlphy->current_chan_bw = tmp_bw; +	} +} + +void rtl92ee_phy_sw_chnl_callback(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	u32 delay; + +	RT_TRACE(COMP_SCAN, DBG_TRACE, +		 ("switch to channel%d\n", rtlphy->current_channel)); +	if (is_hal_stop(rtlhal)) +		return; +	do { +		if (!rtlphy->sw_chnl_inprogress) +			break; +		if (!_rtl92ee_phy_sw_chnl_step_by_step +		    (hw, rtlphy->current_channel, &rtlphy->sw_chnl_stage, +		     &rtlphy->sw_chnl_step, &delay)) { +			if (delay > 0) +				mdelay(delay); +			else +				continue; +		} else { +			rtlphy->sw_chnl_inprogress = false; +		} +		break; +	} while (true); +	RT_TRACE(COMP_SCAN, DBG_TRACE, ("\n")); +} + +u8 rtl92ee_phy_sw_chnl(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + +	if (rtlphy->sw_chnl_inprogress) +		return 0; +	if (rtlphy->set_bwmode_inprogress) +		return 0; +	RT_ASSERT((rtlphy->current_channel <= 14), +		  ("WIRELESS_MODE_G but channel>14")); +	rtlphy->sw_chnl_inprogress = true; +	rtlphy->sw_chnl_stage = 0; +	rtlphy->sw_chnl_step = 0; +	if (!(is_hal_stop(rtlhal)) && !(RT_CANNOT_IO(hw))) { +		rtl92ee_phy_sw_chnl_callback(hw); +		RT_TRACE(COMP_CHAN, DBG_LOUD, +			 ("sw_chnl_inprogress false schdule workitem current channel %d\n", +			 rtlphy->current_channel)); +		rtlphy->sw_chnl_inprogress = false; +	} else { +		RT_TRACE(COMP_CHAN, DBG_LOUD, +			 ("sw_chnl_inprogress false driver sleep or unload\n")); +		rtlphy->sw_chnl_inprogress = false; +	} +	return 1; +} + +static bool _rtl92ee_phy_sw_chnl_step_by_step(struct ieee80211_hw *hw, +					      u8 channel, u8 *stage, u8 *step, +					      u32 *delay) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	struct swchnlcmd precommoncmd[MAX_PRECMD_CNT]; +	u32 precommoncmdcnt; +	struct swchnlcmd postcommoncmd[MAX_POSTCMD_CNT]; +	u32 postcommoncmdcnt; +	struct swchnlcmd rfdependcmd[MAX_RFDEPENDCMD_CNT]; +	u32 rfdependcmdcnt; +	struct swchnlcmd *currentcmd = NULL; +	u8 rfpath; +	u8 num_total_rfpath = rtlphy->num_total_rfpath; + +	precommoncmdcnt = 0; +	_rtl92ee_phy_set_sw_chnl_cmdarray(precommoncmd, precommoncmdcnt++, +					  MAX_PRECMD_CNT, +					  CMDID_SET_TXPOWEROWER_LEVEL, 0, 0, 0); +	_rtl92ee_phy_set_sw_chnl_cmdarray(precommoncmd, precommoncmdcnt++, +					  MAX_PRECMD_CNT, CMDID_END, 0, 0, 0); + +	postcommoncmdcnt = 0; + +	_rtl92ee_phy_set_sw_chnl_cmdarray(postcommoncmd, postcommoncmdcnt++, +					  MAX_POSTCMD_CNT, CMDID_END, 0, 0, 0); + +	rfdependcmdcnt = 0; + +	RT_ASSERT((channel >= 1 && channel <= 14), +		  ("illegal channel for Zebra: %d\n", channel)); + +	_rtl92ee_phy_set_sw_chnl_cmdarray(rfdependcmd, rfdependcmdcnt++, +					  MAX_RFDEPENDCMD_CNT, +					  CMDID_RF_WRITEREG, +					  RF_CHNLBW, channel, 10); + +	_rtl92ee_phy_set_sw_chnl_cmdarray(rfdependcmd, rfdependcmdcnt++, +					  MAX_RFDEPENDCMD_CNT, CMDID_END, +					  0, 0, 0); + +	do { +		switch (*stage) { +		case 0: +			currentcmd = &precommoncmd[*step]; +			break; +		case 1: +			currentcmd = &rfdependcmd[*step]; +			break; +		case 2: +			currentcmd = &postcommoncmd[*step]; +			break; +		default: +			RT_TRACE(COMP_ERR, DBG_EMERG, +				 ("Invalid 'stage' = %d, Check it!\n" , +				  *stage)); +			return true; +			break; +		} + +		if (currentcmd->cmdid == CMDID_END) { +			if ((*stage) == 2) { +				return true; +			} else { +				(*stage)++; +				(*step) = 0; +				continue; +			} +		} + +		switch (currentcmd->cmdid) { +		case CMDID_SET_TXPOWEROWER_LEVEL: +			rtl92ee_phy_set_txpower_level(hw, channel); +			break; +		case CMDID_WRITEPORT_ULONG: +			rtl_write_dword(rtlpriv, currentcmd->para1, +					currentcmd->para2); +			break; +		case CMDID_WRITEPORT_USHORT: +			rtl_write_word(rtlpriv, currentcmd->para1, +				       (u16) currentcmd->para2); +			break; +		case CMDID_WRITEPORT_UCHAR: +			rtl_write_byte(rtlpriv, currentcmd->para1, +				       (u8) currentcmd->para2); +			break; +		case CMDID_RF_WRITEREG: +			for (rfpath = 0; rfpath < num_total_rfpath; rfpath++) { +				rtlphy->rfreg_chnlval[rfpath] = +					((rtlphy->rfreg_chnlval[rfpath] & +					  0xfffff00) | currentcmd->para2); + +				rtl_set_rfreg(hw, (enum radio_path)rfpath, +					      currentcmd->para1, +					      0x3ff, +					      rtlphy->rfreg_chnlval[rfpath]); +			} +			break; +		default: +			RT_TRACE(COMP_ERR, DBG_EMERG, +				 ("switch case not process\n")); +			break; +		} + +		break; +	} while (true); + +	(*delay) = currentcmd->msdelay; +	(*step)++; +	return false; +} + +static bool _rtl92ee_phy_set_sw_chnl_cmdarray(struct swchnlcmd *cmdtable, +					      u32 cmdtableidx, u32 cmdtablesz, +					      enum swchnlcmd_id cmdid, +					      u32 para1, u32 para2, u32 msdelay) +{ +	struct swchnlcmd *pcmd; + +	if (cmdtable == NULL) { +		RT_ASSERT(false, ("cmdtable cannot be NULL.\n")); +		return false; +	} + +	if (cmdtableidx >= cmdtablesz) +		return false; + +	pcmd = cmdtable + cmdtableidx; +	pcmd->cmdid = cmdid; +	pcmd->para1 = para1; +	pcmd->para2 = para2; +	pcmd->msdelay = msdelay; +	return true; +} + +static u8 _rtl92ee_phy_path_a_iqk(struct ieee80211_hw *hw, bool config_pathb) +{ +	u32 reg_eac, reg_e94, reg_e9c; +	u8 result = 0x00; +	/* path-A IQK setting */ +	/* PA/PAD controlled by 0x0 */ +	rtl_set_bbreg(hw, RFPGA0_IQK, MASKDWORD, 0x00000000); +	rtl_set_rfreg(hw, RF90_PATH_A, 0xdf, RFREG_OFFSET_MASK, 0x180); +	rtl_set_bbreg(hw, RFPGA0_IQK, MASKDWORD, 0x80800000); + +	rtl_set_bbreg(hw, RTx_IQK_Tone_A, MASKDWORD, 0x18008c1c); +	rtl_set_bbreg(hw, RRx_IQK_Tone_A, MASKDWORD, 0x38008c1c); +	rtl_set_bbreg(hw, RTx_IQK_Tone_B, MASKDWORD, 0x38008c1c); +	rtl_set_bbreg(hw, RRx_IQK_Tone_B, MASKDWORD, 0x38008c1c); + +	rtl_set_bbreg(hw, RTx_IQK_PI_A, MASKDWORD, 0x82140303); +	rtl_set_bbreg(hw, RRx_IQK_PI_A, MASKDWORD, 0x68160000); + +	/*LO calibration setting*/ +	rtl_set_bbreg(hw, RIQK_AGC_Rsp, MASKDWORD, 0x00462911); + +	/*One shot, path A LOK & IQK*/ +	rtl_set_bbreg(hw, RIQK_AGC_Pts, MASKDWORD, 0xf9000000); +	rtl_set_bbreg(hw, RIQK_AGC_Pts, MASKDWORD, 0xf8000000); + +	mdelay(IQK_DELAY_TIME); + +	reg_eac = rtl_get_bbreg(hw, 0xeac, MASKDWORD); +	reg_e94 = rtl_get_bbreg(hw, 0xe94, MASKDWORD); +	reg_e9c = rtl_get_bbreg(hw, 0xe9c, MASKDWORD); + +	if (!(reg_eac & BIT(28)) && +	    (((reg_e94 & 0x03FF0000) >> 16) != 0x142) && +	    (((reg_e9c & 0x03FF0000) >> 16) != 0x42)) +		result |= 0x01; +	else +		return result; + +	return result; +} + +static u8 _rtl92ee_phy_path_b_iqk(struct ieee80211_hw *hw) +{ +	u32 reg_eac, reg_eb4, reg_ebc; +	u8 result = 0x00; + +	/* PA/PAD controlled by 0x0 */ +	rtl_set_bbreg(hw, RFPGA0_IQK, MASKDWORD, 0x00000000); +	rtl_set_rfreg(hw, RF90_PATH_B, 0xdf, RFREG_OFFSET_MASK, 0x180); +	rtl_set_bbreg(hw, RFPGA0_IQK, MASKDWORD, 0x80800000); + +	rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0x00000000); +	rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0x80800000); + +	rtl_set_bbreg(hw, RTx_IQK_Tone_A, MASKDWORD, 0x38008c1c); +	rtl_set_bbreg(hw, RRx_IQK_Tone_A, MASKDWORD, 0x38008c1c); +	rtl_set_bbreg(hw, RTx_IQK_Tone_B, MASKDWORD, 0x18008c1c); +	rtl_set_bbreg(hw, RRx_IQK_Tone_B, MASKDWORD, 0x38008c1c); + +	rtl_set_bbreg(hw, RTx_IQK_PI_B, MASKDWORD, 0x821403e2); +	rtl_set_bbreg(hw, RRx_IQK_PI_B, MASKDWORD, 0x68160000); + +	/* LO calibration setting */ +	rtl_set_bbreg(hw, RIQK_AGC_Rsp, MASKDWORD, 0x00462911); + +	/*One shot, path B LOK & IQK*/ +	rtl_set_bbreg(hw, RIQK_AGC_Pts, MASKDWORD, 0xfa000000); +	rtl_set_bbreg(hw, RIQK_AGC_Pts, MASKDWORD, 0xf8000000); + +	mdelay(IQK_DELAY_TIME); + +	reg_eac = rtl_get_bbreg(hw, 0xeac, MASKDWORD); +	reg_eb4 = rtl_get_bbreg(hw, 0xeb4, MASKDWORD); +	reg_ebc = rtl_get_bbreg(hw, 0xebc, MASKDWORD); + +	if (!(reg_eac & BIT(31)) && +	    (((reg_eb4 & 0x03FF0000) >> 16) != 0x142) && +	    (((reg_ebc & 0x03FF0000) >> 16) != 0x42)) +		result |= 0x01; +	else +		return result; + +	return result; +} + +static u8 _rtl92ee_phy_path_a_rx_iqk(struct ieee80211_hw *hw, bool config_pathb) +{ +	u32 reg_eac, reg_e94, reg_e9c, reg_ea4 , u32temp; +	u8 result = 0x00; + +	/*Get TXIMR Setting*/ +	/*Modify RX IQK mode table*/ +	rtl_set_bbreg(hw, RFPGA0_IQK, MASKDWORD, 0x00000000); + +	rtl_set_rfreg(hw, RF90_PATH_A, RF_WE_LUT, RFREG_OFFSET_MASK, 0x800a0); +	rtl_set_rfreg(hw, RF90_PATH_A, RF_RCK_OS, RFREG_OFFSET_MASK, 0x30000); +	rtl_set_rfreg(hw, RF90_PATH_A, RF_TXPA_G1, RFREG_OFFSET_MASK, 0x0000f); +	rtl_set_rfreg(hw, RF90_PATH_A, RF_TXPA_G2, RFREG_OFFSET_MASK, 0xf117b); + +	/*PA/PAD control by 0x56, and set = 0x0*/ +	rtl_set_rfreg(hw, RF90_PATH_A, 0xdf, RFREG_OFFSET_MASK, 0x980); +	rtl_set_rfreg(hw, RF90_PATH_A, 0x56, RFREG_OFFSET_MASK, 0x51000); + +	/*enter IQK mode*/ +	rtl_set_bbreg(hw, RFPGA0_IQK, MASKDWORD, 0x80800000); + +	/*IQK Setting*/ +	rtl_set_bbreg(hw, RTx_IQK, MASKDWORD, 0x01007c00); +	rtl_set_bbreg(hw, RRx_IQK, MASKDWORD, 0x01004800); + +	/*path a IQK setting*/ +	rtl_set_bbreg(hw, RTx_IQK_Tone_A, MASKDWORD, 0x18008c1c); +	rtl_set_bbreg(hw, RRx_IQK_Tone_A, MASKDWORD, 0x38008c1c); +	rtl_set_bbreg(hw, RTx_IQK_Tone_B, MASKDWORD, 0x38008c1c); +	rtl_set_bbreg(hw, RRx_IQK_Tone_B, MASKDWORD, 0x38008c1c); + +	rtl_set_bbreg(hw, RTx_IQK_PI_A, MASKDWORD, 0x82160c1f); +	rtl_set_bbreg(hw, RRx_IQK_PI_A, MASKDWORD, 0x68160c1f); + +	/*LO calibration Setting*/ +	rtl_set_bbreg(hw, RIQK_AGC_Rsp, MASKDWORD, 0x0046a911); + +	/*one shot, path A LOK & iqk*/ +	rtl_set_bbreg(hw, RIQK_AGC_Pts, MASKDWORD, 0xfa000000); +	rtl_set_bbreg(hw, RIQK_AGC_Pts, MASKDWORD, 0xf8000000); + +	mdelay(IQK_DELAY_TIME); + +	/* Check failed */ +	reg_eac = rtl_get_bbreg(hw, RRx_Power_After_IQK_A_2, MASKDWORD); +	reg_e94 = rtl_get_bbreg(hw, RTx_Power_Before_IQK_A, MASKDWORD); +	reg_e9c = rtl_get_bbreg(hw, RTx_Power_After_IQK_A, MASKDWORD); + +	if (!(reg_eac & BIT(28)) && +	    (((reg_e94 & 0x03FF0000) >> 16) != 0x142) && +	    (((reg_e9c & 0x03FF0000) >> 16) != 0x42)) { +		result |= 0x01; +	} else { +		/*	PA/PAD controlled by 0x0 */ +		rtl_set_bbreg(hw, RFPGA0_IQK, MASKDWORD, 0x00000000); +		rtl_set_rfreg(hw, RF90_PATH_A, 0xdf, RFREG_OFFSET_MASK, 0x180); +		return result; +	} + +	u32temp = 0x80007C00 | (reg_e94 & 0x3FF0000)  | +		  ((reg_e9c & 0x3FF0000) >> 16); +	rtl_set_bbreg(hw, RTx_IQK, MASKDWORD, u32temp); +	/*RX IQK*/ +	/*Modify RX IQK mode table*/ +	rtl_set_bbreg(hw, RFPGA0_IQK, MASKDWORD, 0x00000000); + +	rtl_set_rfreg(hw, RF90_PATH_A, RF_WE_LUT, RFREG_OFFSET_MASK, 0x800a0); + +	rtl_set_rfreg(hw, RF90_PATH_A, RF_RCK_OS, RFREG_OFFSET_MASK, 0x30000); +	rtl_set_rfreg(hw, RF90_PATH_A, RF_TXPA_G1, RFREG_OFFSET_MASK, 0x0000f); +	rtl_set_rfreg(hw, RF90_PATH_A, RF_TXPA_G2, RFREG_OFFSET_MASK, 0xf7ffa); + +	/*PA/PAD control by 0x56, and set = 0x0*/ +	rtl_set_rfreg(hw, RF90_PATH_A, 0xdf, RFREG_OFFSET_MASK, 0x980); +	rtl_set_rfreg(hw, RF90_PATH_A, 0x56, RFREG_OFFSET_MASK, 0x51000); + +	/*enter IQK mode*/ +	rtl_set_bbreg(hw, RFPGA0_IQK, MASKDWORD, 0x80800000); + +	/*IQK Setting*/ +	rtl_set_bbreg(hw, RRx_IQK, MASKDWORD, 0x01004800); + +	/*path a IQK setting*/ +	rtl_set_bbreg(hw, RTx_IQK_Tone_A, MASKDWORD, 0x38008c1c); +	rtl_set_bbreg(hw, RRx_IQK_Tone_A, MASKDWORD, 0x18008c1c); +	rtl_set_bbreg(hw, RTx_IQK_Tone_B, MASKDWORD, 0x38008c1c); +	rtl_set_bbreg(hw, RRx_IQK_Tone_B, MASKDWORD, 0x38008c1c); + +	rtl_set_bbreg(hw, RTx_IQK_PI_A, MASKDWORD, 0x82160c1f); +	rtl_set_bbreg(hw, RRx_IQK_PI_A, MASKDWORD, 0x28160c1f); + +	/*LO calibration Setting*/ +	rtl_set_bbreg(hw, RIQK_AGC_Rsp, MASKDWORD, 0x0046a891); +	/*one shot, path A LOK & iqk*/ +	rtl_set_bbreg(hw, RIQK_AGC_Pts, MASKDWORD, 0xfa000000); +	rtl_set_bbreg(hw, RIQK_AGC_Pts, MASKDWORD, 0xf8000000); + +	mdelay(IQK_DELAY_TIME); +	/*Check failed*/ +	reg_eac = rtl_get_bbreg(hw, RRx_Power_After_IQK_A_2, MASKDWORD); +	reg_ea4 = rtl_get_bbreg(hw, RRx_Power_Before_IQK_A_2, MASKDWORD); + +	/*PA/PAD controlled by 0x0*/ +	/*leave IQK mode*/ +	rtl_set_bbreg(hw, RFPGA0_IQK, MASKDWORD, 0x00000000); +	rtl_set_rfreg(hw, RF90_PATH_A, 0xdf, RFREG_OFFSET_MASK, 0x180); +	/*if Tx is OK, check whether Rx is OK*/ +	if (!(reg_eac & BIT(27)) && +	    (((reg_ea4 & 0x03FF0000) >> 16) != 0x132) && +	    (((reg_eac & 0x03FF0000) >> 16) != 0x36)) +		result |= 0x02; + +	return result; +} + +static u8 _rtl92ee_phy_path_b_rx_iqk(struct ieee80211_hw *hw, bool config_pathb) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u32 reg_eac, reg_eb4, reg_ebc, reg_ecc, reg_ec4, u32temp; +	u8 result = 0x00; + +	/*Get TXIMR Setting*/ +	/*Modify RX IQK mode table*/ +	rtl_set_bbreg(hw, RFPGA0_IQK, MASKDWORD, 0x00000000); + +	rtl_set_rfreg(hw, RF90_PATH_B, RF_WE_LUT, RFREG_OFFSET_MASK, 0x800a0); +	rtl_set_rfreg(hw, RF90_PATH_B, RF_RCK_OS, RFREG_OFFSET_MASK, 0x30000); +	rtl_set_rfreg(hw, RF90_PATH_B, RF_TXPA_G1, RFREG_OFFSET_MASK, 0x0000f); +	rtl_set_rfreg(hw, RF90_PATH_B, RF_TXPA_G2, RFREG_OFFSET_MASK, 0xf117b); + +	/*PA/PAD all off*/ +	rtl_set_rfreg(hw, RF90_PATH_B, 0xdf, RFREG_OFFSET_MASK, 0x980); +	rtl_set_rfreg(hw, RF90_PATH_B, 0x56, RFREG_OFFSET_MASK, 0x51000); + +	rtl_set_bbreg(hw, RFPGA0_IQK, MASKDWORD, 0x80800000); + +	/*IQK Setting*/ +	rtl_set_bbreg(hw, RTx_IQK, MASKDWORD, 0x01007c00); +	rtl_set_bbreg(hw, RRx_IQK, MASKDWORD, 0x01004800); + +	/*path a IQK setting*/ +	rtl_set_bbreg(hw, RTx_IQK_Tone_A, MASKDWORD, 0x38008c1c); +	rtl_set_bbreg(hw, RRx_IQK_Tone_A, MASKDWORD, 0x38008c1c); +	rtl_set_bbreg(hw, RTx_IQK_Tone_B, MASKDWORD, 0x18008c1c); +	rtl_set_bbreg(hw, RRx_IQK_Tone_B, MASKDWORD, 0x38008c1c); + +	rtl_set_bbreg(hw, RTx_IQK_PI_B, MASKDWORD, 0x82160c1f); +	rtl_set_bbreg(hw, RRx_IQK_PI_B, MASKDWORD, 0x68160c1f); + +	/*LO calibration Setting*/ +	rtl_set_bbreg(hw, RIQK_AGC_Rsp, MASKDWORD, 0x0046a911); + +	/*one shot, path A LOK & iqk*/ +	rtl_set_bbreg(hw, RIQK_AGC_Pts, MASKDWORD, 0xfa000000); +	rtl_set_bbreg(hw, RIQK_AGC_Pts, MASKDWORD, 0xf8000000); + +	mdelay(IQK_DELAY_TIME); + +	/* Check failed */ +	reg_eac = rtl_get_bbreg(hw, RRx_Power_After_IQK_A_2, MASKDWORD); +	reg_eb4 = rtl_get_bbreg(hw, RTx_Power_Before_IQK_B, MASKDWORD); +	reg_ebc = rtl_get_bbreg(hw, RTx_Power_After_IQK_B, MASKDWORD); + +	if (!(reg_eac & BIT(31)) && +	    (((reg_eb4 & 0x03FF0000) >> 16) != 0x142) && +	    (((reg_ebc & 0x03FF0000) >> 16) != 0x42)) { +		result |= 0x01; +	} else { +		/*	PA/PAD controlled by 0x0 */ +		rtl_set_bbreg(hw, RFPGA0_IQK, MASKDWORD, 0x00000000); +		rtl_set_rfreg(hw, RF90_PATH_B, 0xdf, RFREG_OFFSET_MASK, 0x180); +		return result; +	} + +	u32temp = 0x80007C00 | (reg_eb4 & 0x3FF0000) | +		  ((reg_ebc & 0x3FF0000) >> 16); +	rtl_set_bbreg(hw, RTx_IQK, MASKDWORD, u32temp); +	/*RX IQK*/ +	/*Modify RX IQK mode table*/ +	rtl_set_bbreg(hw, RFPGA0_IQK, MASKDWORD, 0x00000000); +	rtl_set_rfreg(hw, RF90_PATH_B, RF_WE_LUT, RFREG_OFFSET_MASK, 0x800a0); + +	rtl_set_rfreg(hw, RF90_PATH_B, RF_RCK_OS, RFREG_OFFSET_MASK, 0x30000); +	rtl_set_rfreg(hw, RF90_PATH_B, RF_TXPA_G1, RFREG_OFFSET_MASK, 0x0000f); +	rtl_set_rfreg(hw, RF90_PATH_B, RF_TXPA_G2, RFREG_OFFSET_MASK, 0xf7ffa); + +	/*PA/PAD all off*/ +	rtl_set_rfreg(hw, RF90_PATH_B, 0xdf, RFREG_OFFSET_MASK, 0x980); +	rtl_set_rfreg(hw, RF90_PATH_B, 0x56, RFREG_OFFSET_MASK, 0x51000); + +	/*enter IQK mode*/ +	rtl_set_bbreg(hw, RFPGA0_IQK, MASKDWORD, 0x80800000); + +	/*IQK Setting*/ +	rtl_set_bbreg(hw, RRx_IQK, MASKDWORD, 0x01004800); + +	/*path b IQK setting*/ +	rtl_set_bbreg(hw, RTx_IQK_Tone_A, MASKDWORD, 0x38008c1c); +	rtl_set_bbreg(hw, RRx_IQK_Tone_A, MASKDWORD, 0x38008c1c); +	rtl_set_bbreg(hw, RTx_IQK_Tone_B, MASKDWORD, 0x38008c1c); +	rtl_set_bbreg(hw, RRx_IQK_Tone_B, MASKDWORD, 0x18008c1c); + +	rtl_set_bbreg(hw, RTx_IQK_PI_B, MASKDWORD, 0x82160c1f); +	rtl_set_bbreg(hw, RRx_IQK_PI_B, MASKDWORD, 0x28160c1f); + +	/*LO calibration Setting*/ +	rtl_set_bbreg(hw, RIQK_AGC_Rsp, MASKDWORD, 0x0046a891); +	/*one shot, path A LOK & iqk*/ +	rtl_set_bbreg(hw, RIQK_AGC_Pts, MASKDWORD, 0xfa000000); +	rtl_set_bbreg(hw, RIQK_AGC_Pts, MASKDWORD, 0xf8000000); + +	mdelay(IQK_DELAY_TIME); +	/*Check failed*/ +	reg_eac = rtl_get_bbreg(hw, RRx_Power_After_IQK_A_2, MASKDWORD); +	reg_ec4 = rtl_get_bbreg(hw, RRx_Power_Before_IQK_B_2, MASKDWORD); +	reg_ecc = rtl_get_bbreg(hw, RRx_Power_After_IQK_B_2, MASKDWORD); +	/*PA/PAD controlled by 0x0*/ +	/*leave IQK mode*/ +	rtl_set_bbreg(hw, RFPGA0_IQK, MASKDWORD, 0x00000000); +	rtl_set_rfreg(hw, RF90_PATH_B, 0xdf, RFREG_OFFSET_MASK, 0x180); +	/*if Tx is OK, check whether Rx is OK*/ +	if (!(reg_eac & BIT(30)) && +	    (((reg_ec4 & 0x03FF0000) >> 16) != 0x132) && +	    (((reg_ecc & 0x03FF0000) >> 16) != 0x36)) +		result |= 0x02; +	else +		RT_TRACE(COMP_RF, DBG_LOUD, ("Path B Rx IQK fail!!\n")); + +	return result; +} + +static void _rtl92ee_phy_path_a_fill_iqk_matrix(struct ieee80211_hw *hw, +						bool b_iqk_ok, long result[][8], +						u8 final_candidate, +						bool btxonly) +{ +	u32 oldval_0, x, tx0_a, reg; +	long y, tx0_c; + +	if (final_candidate == 0xFF) { +		return; +	} else if (b_iqk_ok) { +		oldval_0 = (rtl_get_bbreg(hw, ROFDM0_XATXIQIMBALANCE, +					  MASKDWORD) >> 22) & 0x3FF; +		x = result[final_candidate][0]; +		if ((x & 0x00000200) != 0) +			x = x | 0xFFFFFC00; +		tx0_a = (x * oldval_0) >> 8; +		rtl_set_bbreg(hw, ROFDM0_XATXIQIMBALANCE, 0x3FF, tx0_a); +		rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD, BIT(31), +			      ((x * oldval_0 >> 7) & 0x1)); +		y = result[final_candidate][1]; +		if ((y & 0x00000200) != 0) +			y = y | 0xFFFFFC00; +		tx0_c = (y * oldval_0) >> 8; +		rtl_set_bbreg(hw, ROFDM0_XCTXAFE, 0xF0000000, +			      ((tx0_c & 0x3C0) >> 6)); +		rtl_set_bbreg(hw, ROFDM0_XATXIQIMBALANCE, 0x003F0000, +			      (tx0_c & 0x3F)); +		rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD, BIT(29), +			      ((y * oldval_0 >> 7) & 0x1)); + +		if (btxonly) +			return; + +		reg = result[final_candidate][2]; +		rtl_set_bbreg(hw, ROFDM0_XARXIQIMBALANCE, 0x3FF, reg); + +		reg = result[final_candidate][3] & 0x3F; +		rtl_set_bbreg(hw, ROFDM0_XARXIQIMBALANCE, 0xFC00, reg); + +		reg = (result[final_candidate][3] >> 6) & 0xF; +		rtl_set_bbreg(hw, ROFDM0_RXIQEXTANTA, 0xF0000000, reg); +	} +} + +static void _rtl92ee_phy_path_b_fill_iqk_matrix(struct ieee80211_hw *hw, +						bool b_iqk_ok, long result[][8], +						u8 final_candidate, +						bool btxonly) +{ +	u32 oldval_1, x, tx1_a, reg; +	long y, tx1_c; + +	if (final_candidate == 0xFF) { +		return; +	} else if (b_iqk_ok) { +		oldval_1 = (rtl_get_bbreg(hw, ROFDM0_XATXIQIMBALANCE, +					  MASKDWORD) >> 22) & 0x3FF; +		x = result[final_candidate][4]; +		if ((x & 0x00000200) != 0) +			x = x | 0xFFFFFC00; +		tx1_a = (x * oldval_1) >> 8; +		rtl_set_bbreg(hw, ROFDM0_XATXIQIMBALANCE, 0x3FF, tx1_a); +		rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD, BIT(27), +			      ((x * oldval_1 >> 7) & 0x1)); +		y = result[final_candidate][5]; +		if ((y & 0x00000200) != 0) +			y = y | 0xFFFFFC00; +		tx1_c = (y * oldval_1) >> 8; +		rtl_set_bbreg(hw, ROFDM0_XDTXAFE, 0xF0000000, +			      ((tx1_c & 0x3C0) >> 6)); +		rtl_set_bbreg(hw, ROFDM0_XBTXIQIMBALANCE, 0x003F0000, +			      (tx1_c & 0x3F)); +		rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD, BIT(25), +			      ((y * oldval_1 >> 7) & 0x1)); + +		if (btxonly) +			return; + +		reg = result[final_candidate][6]; +		rtl_set_bbreg(hw, ROFDM0_XBRXIQIMBALANCE, 0x3FF, reg); + +		reg = result[final_candidate][7] & 0x3F; +		rtl_set_bbreg(hw, ROFDM0_XBRXIQIMBALANCE, 0xFC00, reg); + +		reg = (result[final_candidate][7] >> 6) & 0xF; +		rtl_set_bbreg(hw, ROFDM0_AGCRSSITABLE, 0xF0000000, reg); +	} +} + +static void _rtl92ee_phy_save_adda_registers(struct ieee80211_hw *hw, +					     u32 *addareg, u32 *addabackup, +					     u32 registernum) +{ +	u32 i; + +	for (i = 0; i < registernum; i++) +		addabackup[i] = rtl_get_bbreg(hw, addareg[i], MASKDWORD); +} + +static void _rtl92ee_phy_save_mac_registers(struct ieee80211_hw *hw, +					    u32 *macreg, u32 *macbackup) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u32 i; + +	for (i = 0; i < (IQK_MAC_REG_NUM - 1); i++) +		macbackup[i] = rtl_read_byte(rtlpriv, macreg[i]); + +	macbackup[i] = rtl_read_dword(rtlpriv, macreg[i]); +} + +static void _rtl92ee_phy_reload_adda_registers(struct ieee80211_hw *hw, +					       u32 *addareg, u32 *addabackup, +					       u32 regiesternum) +{ +	u32 i; + +	for (i = 0; i < regiesternum; i++) +		rtl_set_bbreg(hw, addareg[i], MASKDWORD, addabackup[i]); +} + +static void _rtl92ee_phy_reload_mac_registers(struct ieee80211_hw *hw, +					      u32 *macreg, u32 *macbackup) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u32 i; + +	for (i = 0; i < (IQK_MAC_REG_NUM - 1); i++) +		rtl_write_byte(rtlpriv, macreg[i], (u8) macbackup[i]); +	rtl_write_dword(rtlpriv, macreg[i], macbackup[i]); +} + +static void _rtl92ee_phy_path_adda_on(struct ieee80211_hw *hw, u32 *addareg, +				      bool is_patha_on, bool is2t) +{ +	u32 pathon; +	u32 i; + +	pathon = is_patha_on ? 0x0fc01616 : 0x0fc01616; +	if (!is2t) { +		pathon = 0x0fc01616; +		rtl_set_bbreg(hw, addareg[0], MASKDWORD, 0x0fc01616); +	} else { +		rtl_set_bbreg(hw, addareg[0], MASKDWORD, pathon); +	} + +	for (i = 1; i < IQK_ADDA_REG_NUM; i++) +		rtl_set_bbreg(hw, addareg[i], MASKDWORD, pathon); +} + +static void _rtl92ee_phy_mac_setting_calibration(struct ieee80211_hw *hw, +						 u32 *macreg, u32 *macbackup) +{ +	rtl_set_bbreg(hw, 0x520, 0x00ff0000, 0xff); +} + +static void _rtl92ee_phy_path_a_standby(struct ieee80211_hw *hw) +{ +	rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0x0); +	rtl_set_rfreg(hw, RF90_PATH_A, 0, RFREG_OFFSET_MASK, 0x10000); +	rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0x80800000); +} + +static bool _rtl92ee_phy_simularity_compare(struct ieee80211_hw *hw, +					    long result[][8], u8 c1, u8 c2) +{ +	u32 i, j, diff, simularity_bitmap, bound; + +	u8 final_candidate[2] = { 0xFF, 0xFF }; +	bool bresult = true/*, is2t = true*/; +	s32 tmp1, tmp2; + +	bound = 8; + +	simularity_bitmap = 0; + +	for (i = 0; i < bound; i++) { +		if ((i == 1) || (i == 3) || (i == 5) || (i == 7)) { +			if ((result[c1][i] & 0x00000200) != 0) +				tmp1 = result[c1][i] | 0xFFFFFC00; +			else +				tmp1 = result[c1][i]; + +			if ((result[c2][i] & 0x00000200) != 0) +				tmp2 = result[c2][i] | 0xFFFFFC00; +			else +				tmp2 = result[c2][i]; +		} else { +			tmp1 = result[c1][i]; +			tmp2 = result[c2][i]; +		} + +		diff = (tmp1 > tmp2) ? (tmp1 - tmp2) : (tmp2 - tmp1); + +		if (diff > MAX_TOLERANCE) { +			if ((i == 2 || i == 6) && !simularity_bitmap) { +				if (result[c1][i] + result[c1][i + 1] == 0) +					final_candidate[(i / 4)] = c2; +				else if (result[c2][i] + result[c2][i + 1] == 0) +					final_candidate[(i / 4)] = c1; +				else +					simularity_bitmap |= (1 << i); +			} else { +				simularity_bitmap |= (1 << i); +			} +		} +	} + +	if (simularity_bitmap == 0) { +		for (i = 0; i < (bound / 4); i++) { +			if (final_candidate[i] != 0xFF) { +				for (j = i * 4; j < (i + 1) * 4 - 2; j++) +					result[3][j] = +						result[final_candidate[i]][j]; +				bresult = false; +			} +		} +		return bresult; +	} else { +		if (!(simularity_bitmap & 0x03)) {/*path A TX OK*/ +			for (i = 0; i < 2; i++) +				result[3][i] = result[c1][i]; +		} +		if (!(simularity_bitmap & 0x0c)) {/*path A RX OK*/ +			for (i = 2; i < 4; i++) +				result[3][i] = result[c1][i]; +		} +		if (!(simularity_bitmap & 0x30)) {/*path B TX OK*/ +			for (i = 4; i < 6; i++) +				result[3][i] = result[c1][i]; +		} +		if (!(simularity_bitmap & 0xc0)) {/*path B RX OK*/ +			for (i = 6; i < 8; i++) +				result[3][i] = result[c1][i]; +		} +		return false; +	} +} + +static void _rtl92ee_phy_iq_calibrate(struct ieee80211_hw *hw, +				      long result[][8], u8 t, bool is2t) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	u32 i; +	u8 patha_ok, pathb_ok; +	u8 tmp_0xc50 = (u8) rtl_get_bbreg(hw, 0xc50, MASKBYTE0); +	u8 tmp_0xc58 = (u8) rtl_get_bbreg(hw, 0xc58, MASKBYTE0); +	u32 adda_reg[IQK_ADDA_REG_NUM] = { +		0x85c, 0xe6c, 0xe70, 0xe74, +		0xe78, 0xe7c, 0xe80, 0xe84, +		0xe88, 0xe8c, 0xed0, 0xed4, +		0xed8, 0xedc, 0xee0, 0xeec +	}; + +	u32 iqk_mac_reg[IQK_MAC_REG_NUM] = { +		0x522, 0x550, 0x551, 0x040 +	}; + +	u32 iqk_bb_reg[IQK_BB_REG_NUM] = { +		ROFDM0_TRXPATHENABLE, ROFDM0_TRMUXPAR, +		RFPGA0_XCD_RFINTERFACESW, 0xb68, 0xb6c, +		0x870, 0x860, +		0x864, 0x800 +	}; + +	const u32 retrycount = 2; + + +	if (t == 0) { +		_rtl92ee_phy_save_adda_registers(hw, adda_reg, +						 rtlphy->adda_backup, +						 IQK_ADDA_REG_NUM); +		_rtl92ee_phy_save_mac_registers(hw, iqk_mac_reg, +						rtlphy->iqk_mac_backup); +		_rtl92ee_phy_save_adda_registers(hw, iqk_bb_reg, +						 rtlphy->iqk_bb_backup, +						 IQK_BB_REG_NUM); +	} + +	_rtl92ee_phy_path_adda_on(hw, adda_reg, true, is2t); + +	/*BB setting*/ +	rtl_set_bbreg(hw, RFPGA0_RFMOD, BIT(24), 0x00); +	rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, MASKDWORD, 0x03a05600); +	rtl_set_bbreg(hw, ROFDM0_TRMUXPAR, MASKDWORD, 0x000800e4); +	rtl_set_bbreg(hw, RFPGA0_XCD_RFINTERFACESW, MASKDWORD, 0x22208200); + +	rtl_set_bbreg(hw, RFPGA0_XAB_RFINTERFACESW, BIT(10), 0x01); +	rtl_set_bbreg(hw, RFPGA0_XAB_RFINTERFACESW, BIT(26), 0x01); +	rtl_set_bbreg(hw, RFPGA0_XA_RFINTERFACEOE, BIT(10), 0x01); +	rtl_set_bbreg(hw, RFPGA0_XB_RFINTERFACEOE, BIT(10), 0x01); + +	_rtl92ee_phy_mac_setting_calibration(hw, iqk_mac_reg, +					     rtlphy->iqk_mac_backup); +	/* Page B init*/ +	/* IQ calibration setting*/ +	rtl_set_bbreg(hw, RFPGA0_IQK, MASKDWORD, 0x80800000); +	rtl_set_bbreg(hw, RTx_IQK, MASKDWORD, 0x01007c00); +	rtl_set_bbreg(hw, RRx_IQK, MASKDWORD, 0x01004800); + +	for (i = 0; i < retrycount; i++) { +		patha_ok = _rtl92ee_phy_path_a_iqk(hw, is2t); + +		if (patha_ok == 0x01) { +			RT_TRACE(COMP_RF, DBG_LOUD, +				 ("Path A Tx IQK Success!!\n")); +			result[t][0] = (rtl_get_bbreg(hw, +						      RTx_Power_Before_IQK_A, +						      MASKDWORD) & 0x3FF0000) +						      >> 16; +			result[t][1] = (rtl_get_bbreg(hw, RTx_Power_After_IQK_A, +						      MASKDWORD) & 0x3FF0000) +						      >> 16; +			break; +		} else { +			RT_TRACE(COMP_RF, DBG_LOUD, +				 ("Path A Tx IQK Fail!!, ret = 0x%x\n", +				  patha_ok)); +		} +	} + +	for (i = 0 ; i < retrycount ; i++) { +		patha_ok = _rtl92ee_phy_path_a_rx_iqk(hw, is2t); + +		if (patha_ok == 0x03) { +			RT_TRACE(COMP_RF, DBG_LOUD, +				 ("Path A Rx IQK Success!!\n")); +			result[t][2] = (rtl_get_bbreg(hw, +						      RRx_Power_Before_IQK_A_2, +						      MASKDWORD) & 0x3FF0000) +						      >> 16; +			result[t][3] = (rtl_get_bbreg(hw, +						      RRx_Power_After_IQK_A_2, +						      MASKDWORD) & 0x3FF0000) +						      >> 16; +			break; +		} else { +			RT_TRACE(COMP_RF, DBG_LOUD, +				 ("Path A Rx IQK Fail!!, ret = 0x%x\n", +				  patha_ok)); +		} +	} + +	if (0x00 == patha_ok) +		RT_TRACE(COMP_RF, DBG_LOUD, ("Path A IQK failed!!, ret = 0\n")); + +	if (is2t) { +		_rtl92ee_phy_path_a_standby(hw); +		/* Turn Path B ADDA on */ +		_rtl92ee_phy_path_adda_on(hw, adda_reg, false, is2t); + +		/* IQ calibration setting */ +		rtl_set_bbreg(hw, RFPGA0_IQK, MASKDWORD, 0x80800000); +		rtl_set_bbreg(hw, RTx_IQK, MASKDWORD, 0x01007c00); +		rtl_set_bbreg(hw, RRx_IQK, MASKDWORD, 0x01004800); + +		for (i = 0 ; i < retrycount ; i++) { +			pathb_ok = _rtl92ee_phy_path_b_iqk(hw); +			if (pathb_ok == 0x01) { +				RT_TRACE(COMP_RF, DBG_LOUD, +					 ("Path B Tx IQK Success!!\n")); +				result[t][4] = (rtl_get_bbreg(hw, +							RTx_Power_Before_IQK_B, +							MASKDWORD) & 0x3FF0000) +							>> 16; +				result[t][5] = (rtl_get_bbreg(hw, +							RTx_Power_After_IQK_B, +							MASKDWORD) & 0x3FF0000) +							>> 16; +				break; +			} else { +				RT_TRACE(COMP_RF, DBG_LOUD, +					 ("Path B Tx IQK Fail!!, ret = 0x%x\n", +					   pathb_ok)); +			} +		} + +		for (i = 0 ; i < retrycount ; i++) { +			pathb_ok = _rtl92ee_phy_path_b_rx_iqk(hw, is2t); +			if (pathb_ok == 0x03) { +				RT_TRACE(COMP_RF, DBG_LOUD, +					 ("Path B Rx IQK Success!!\n")); +				result[t][6] = (rtl_get_bbreg(hw, +						       RRx_Power_Before_IQK_B_2, +						       MASKDWORD) & 0x3FF0000) +						       >> 16; +				result[t][7] = (rtl_get_bbreg(hw, +						       RRx_Power_After_IQK_B_2, +						       MASKDWORD) & 0x3FF0000) +						       >> 16; +				break; +			} else { +				RT_TRACE(COMP_RF, DBG_LOUD, +					 ("Path B Rx IQK Fail!!, ret = 0x%x\n", +					 pathb_ok)); +			} +		} + +		if (0x00 == pathb_ok) +			RT_TRACE(COMP_RF, DBG_LOUD, +				 ("Path B IQK failed!!, ret = 0\n")); +	} +	/* Back to BB mode, load original value */ +	RT_TRACE(COMP_RF, DBG_LOUD, +		 ("IQK:Back to BB mode, load original value!\n")); +	rtl_set_bbreg(hw, RFPGA0_IQK, MASKDWORD, 0); + +	if (t != 0) { +		/* Reload ADDA power saving parameters */ +		_rtl92ee_phy_reload_adda_registers(hw, adda_reg, +						   rtlphy->adda_backup, +						   IQK_ADDA_REG_NUM); + +		/* Reload MAC parameters */ +		_rtl92ee_phy_reload_mac_registers(hw, iqk_mac_reg, +						  rtlphy->iqk_mac_backup); + +		_rtl92ee_phy_reload_adda_registers(hw, iqk_bb_reg, +						   rtlphy->iqk_bb_backup, +						   IQK_BB_REG_NUM); + +		/* Restore RX initial gain */ +		rtl_set_bbreg(hw, 0xc50, MASKBYTE0, 0x50); +		rtl_set_bbreg(hw, 0xc50, MASKBYTE0, tmp_0xc50); +		if (is2t) { +			rtl_set_bbreg(hw, 0xc50, MASKBYTE0, 0x50); +			rtl_set_bbreg(hw, 0xc58, MASKBYTE0, tmp_0xc58); +		} + +		/* load 0xe30 IQC default value */ +		rtl_set_bbreg(hw, RTx_IQK_Tone_A, MASKDWORD, 0x01008c00); +		rtl_set_bbreg(hw, RRx_IQK_Tone_A, MASKDWORD, 0x01008c00); +	} +	RT_TRACE(COMP_RF, DBG_LOUD, ("_rtl92ee_phy_iq_calibrate() <==\n")); +} + +static void _rtl92ee_phy_lc_calibrate(struct ieee80211_hw *hw, bool is2t) +{ +	u8 tmpreg; +	u32 rf_a_mode = 0, rf_b_mode = 0, lc_cal; +	struct rtl_priv *rtlpriv = rtl_priv(hw); + +	tmpreg = rtl_read_byte(rtlpriv, 0xd03); + +	if ((tmpreg & 0x70) != 0) +		rtl_write_byte(rtlpriv, 0xd03, tmpreg & 0x8F); +	else +		rtl_write_byte(rtlpriv, REG_TXPAUSE, 0xFF); + +	if ((tmpreg & 0x70) != 0) { +		rf_a_mode = rtl_get_rfreg(hw, RF90_PATH_A, 0x00, MASK12BITS); + +		if (is2t) +			rf_b_mode = rtl_get_rfreg(hw, RF90_PATH_B, 0x00, +						  MASK12BITS); + +		rtl_set_rfreg(hw, RF90_PATH_A, 0x00, MASK12BITS, +			      (rf_a_mode & 0x8FFFF) | 0x10000); + +		if (is2t) +			rtl_set_rfreg(hw, RF90_PATH_B, 0x00, MASK12BITS, +				      (rf_b_mode & 0x8FFFF) | 0x10000); +	} +	lc_cal = rtl_get_rfreg(hw, RF90_PATH_A, 0x18, MASK12BITS); + +	rtl_set_rfreg(hw, RF90_PATH_A, 0x18, MASK12BITS, lc_cal | 0x08000); + +	mdelay(100); + +	if ((tmpreg & 0x70) != 0) { +		rtl_write_byte(rtlpriv, 0xd03, tmpreg); +		rtl_set_rfreg(hw, RF90_PATH_A, 0x00, MASK12BITS, rf_a_mode); + +		if (is2t) +			rtl_set_rfreg(hw, RF90_PATH_B, 0x00, MASK12BITS, +				      rf_b_mode); +	} else { +		rtl_write_byte(rtlpriv, REG_TXPAUSE, 0x00); +	} +	RT_TRACE(COMP_INIT , DBG_LOUD , ("\n")); +} + +static void _rtl92ee_phy_set_rfpath_switch(struct ieee80211_hw *hw, +					   bool bmain, bool is2t) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); +	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); +	RT_TRACE(COMP_INIT , DBG_LOUD , ("\n")); + +	if (is_hal_stop(rtlhal)) { +		u8 u1btmp; +		u1btmp = rtl_read_byte(rtlpriv, REG_LEDCFG0); +		rtl_write_byte(rtlpriv, REG_LEDCFG0, u1btmp | BIT(7)); +		rtl_set_bbreg(hw, rFPGA0_XAB_RFPARAMETER, BIT(13), 0x01); +	} +	if (is2t) { +		if (bmain) +			rtl_set_bbreg(hw, RFPGA0_XB_RFINTERFACEOE, +				      BIT(5) | BIT(6), 0x1); +		else +			rtl_set_bbreg(hw, RFPGA0_XB_RFINTERFACEOE, +				      BIT(5) | BIT(6), 0x2); +	} else { +		rtl_set_bbreg(hw, RFPGA0_XAB_RFINTERFACESW, BIT(8) | BIT(9), 0); +		rtl_set_bbreg(hw, 0x914, MASKLWORD, 0x0201); + +		/* We use the RF definition of MAIN and AUX, +		 * left antenna and right antenna repectively. +		 * Default output at AUX.*/ +		if (bmain) { +			rtl_set_bbreg(hw, RFPGA0_XA_RFINTERFACEOE, +				      BIT(14) | BIT(13) | BIT(12), 0); +			rtl_set_bbreg(hw, RFPGA0_XB_RFINTERFACEOE, +				      BIT(5) | BIT(4) | BIT(3), 0); +			if (rtlefuse->antenna_div_type == CGCS_RX_HW_ANTDIV) +				rtl_set_bbreg(hw, rConfig_ram64x16, BIT(31), 0); +		} else { +			rtl_set_bbreg(hw, RFPGA0_XA_RFINTERFACEOE, +				      BIT(14) | BIT(13) | BIT(12), 1); +			rtl_set_bbreg(hw, RFPGA0_XB_RFINTERFACEOE, +				      BIT(5) | BIT(4) | BIT(3), 1); +			if (rtlefuse->antenna_div_type == CGCS_RX_HW_ANTDIV) +				rtl_set_bbreg(hw, rConfig_ram64x16, BIT(31), 1); +		} +	} +} + +#undef IQK_ADDA_REG_NUM +#undef IQK_DELAY_TIME + +static u8 rtl92ee_get_rightchnlplace_for_iqk(u8 chnl) +{ +	u8 channel_all[59] = { +		1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, +		36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, +		60, 62, 64, 100, 102, 104, 106, 108, 110, 112, +		114, 116, 118, 120, 122, 124, 126, 128,	130, +		132, 134, 136, 138, 140, 149, 151, 153, 155, +		157, 159, 161, 163, 165 +	}; +	u8 place = chnl; + +	if (chnl > 14) { +		for (place = 14; place < sizeof(channel_all); place++) { +			if (channel_all[place] == chnl) +				return place - 13; +		} +	} + +	return 0; +} + +void rtl92ee_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	long result[4][8]; +	u8 i, final_candidate; +	bool b_patha_ok, b_pathb_ok; +	long reg_e94, reg_e9c, reg_ea4, reg_eac; +	long reg_eb4, reg_ebc, reg_ec4, reg_ecc; +	bool is12simular, is13simular, is23simular; +	u8 idx; +	u32 iqk_bb_reg[IQK_BB_REG_NUM] = { +		ROFDM0_XARXIQIMBALANCE, +		ROFDM0_XBRXIQIMBALANCE, +		ROFDM0_ECCATHRESHOLD, +		ROFDM0_AGCRSSITABLE, +		ROFDM0_XATXIQIMBALANCE, +		ROFDM0_XBTXIQIMBALANCE, +		ROFDM0_XCTXAFE, +		ROFDM0_XDTXAFE, +		ROFDM0_RXIQEXTANTA +	}; + +	if (b_recovery) { +		_rtl92ee_phy_reload_adda_registers(hw, iqk_bb_reg, +						   rtlphy->iqk_bb_backup, 9); +		return; +	} + +	for (i = 0; i < 8; i++) { +		result[0][i] = 0; +		result[1][i] = 0; +		result[2][i] = 0; + +		if ((i == 0) || (i == 2) || (i == 4)  || (i == 6)) +			result[3][i] = 0x100; +		else +			result[3][i] = 0; +	} +	final_candidate = 0xff; +	b_patha_ok = false; +	b_pathb_ok = false; +	is12simular = false; +	is23simular = false; +	is13simular = false; +	for (i = 0; i < 3; i++) { +		_rtl92ee_phy_iq_calibrate(hw, result, i, true); +		if (i == 1) { +			is12simular = _rtl92ee_phy_simularity_compare(hw, +								      result, +								      0, 1); +			if (is12simular) { +				final_candidate = 0; +				break; +			} +		} + +		if (i == 2) { +			is13simular = _rtl92ee_phy_simularity_compare(hw, +								      result, +								      0, 2); +			if (is13simular) { +				final_candidate = 0; +				break; +			} +			is23simular = _rtl92ee_phy_simularity_compare(hw, +								      result, +								      1, 2); +			if (is23simular) +				final_candidate = 1; +			else +				final_candidate = 3; +		} +	} +	for (i = 0; i < 4; i++) { +		reg_e94 = result[i][0]; +		reg_e9c = result[i][1]; +		reg_ea4 = result[i][2]; +		reg_eac = result[i][3]; +		reg_eb4 = result[i][4]; +		reg_ebc = result[i][5]; +		reg_ec4 = result[i][6]; +		reg_ecc = result[i][7]; +	} +	if (final_candidate != 0xff) { +		reg_e94 = result[final_candidate][0]; +		rtlphy->reg_e94 = reg_e94; +		reg_e9c = result[final_candidate][1]; +		rtlphy->reg_e9c = reg_e9c; +		reg_ea4 = result[final_candidate][2]; +		reg_eac = result[final_candidate][3]; +		reg_eb4 = result[final_candidate][4]; +		rtlphy->reg_eb4 = reg_eb4; +		reg_ebc = result[final_candidate][5]; +		rtlphy->reg_ebc = reg_ebc; +		reg_ec4 = result[final_candidate][6]; +		reg_ecc = result[final_candidate][7]; +		b_patha_ok = true; +		b_pathb_ok = true; +	} else { +		rtlphy->reg_e94 = 0x100; +		rtlphy->reg_eb4 = 0x100; +		rtlphy->reg_e9c = 0x0; +		rtlphy->reg_ebc = 0x0; +	} + +	if (reg_e94 != 0) /*&&(reg_ea4 != 0) */ +		_rtl92ee_phy_path_a_fill_iqk_matrix(hw, b_patha_ok, result, +						    final_candidate, +						    (reg_ea4 == 0)); + +	_rtl92ee_phy_path_b_fill_iqk_matrix(hw, b_pathb_ok, result, +					    final_candidate, +					    (reg_ec4 == 0)); + +	idx = rtl92ee_get_rightchnlplace_for_iqk(rtlphy->current_channel); + +	/* To Fix BSOD when final_candidate is 0xff +	 * by sherry 20120321 */ +	if (final_candidate < 4) { +		for (i = 0; i < IQK_MATRIX_REG_NUM; i++) +			rtlphy->iqk_matrix_regsetting[idx].value[0][i] = +				result[final_candidate][i]; + +		rtlphy->iqk_matrix_regsetting[idx].b_iqk_done = true; +	} +	_rtl92ee_phy_save_adda_registers(hw, iqk_bb_reg, +					 rtlphy->iqk_bb_backup, 9); +} + +void rtl92ee_phy_lc_calibrate(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	struct rtl_hal *rtlhal = &(rtlpriv->rtlhal); +	u32 timeout = 2000, timecount = 0; + +	while (rtlpriv->mac80211.act_scanning && timecount < timeout) { +		udelay(50); +		timecount += 50; +	} + +	rtlphy->lck_inprogress = true; +	RTPRINT(rtlpriv, FINIT, INIT_IQK, +		"LCK:Start!!! currentband %x delay %d ms\n", +		 rtlhal->current_bandtype, timecount); + +	_rtl92ee_phy_lc_calibrate(hw, false); + +	rtlphy->lck_inprogress = false; +} + +void rtl92ee_phy_ap_calibrate(struct ieee80211_hw *hw, char delta) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); + +	if (rtlphy->b_apk_done) +		return; + +	return; +} + +void rtl92ee_phy_set_rfpath_switch(struct ieee80211_hw *hw, bool bmain) +{ +	_rtl92ee_phy_set_rfpath_switch(hw, bmain, false); +} + +bool rtl92ee_phy_set_io_cmd(struct ieee80211_hw *hw, enum io_type iotype) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	bool b_postprocessing = false; + +	RT_TRACE(COMP_CMD, DBG_TRACE, +		 ("-->IO Cmd(%#x), set_io_inprogress(%d)\n", +		  iotype, rtlphy->set_io_inprogress)); +	do { +		switch (iotype) { +		case IO_CMD_RESUME_DM_BY_SCAN: +			RT_TRACE(COMP_CMD, DBG_TRACE, +				 ("[IO CMD] Resume DM after scan.\n")); +			b_postprocessing = true; +			break; +		case IO_CMD_PAUSE_BAND0_DM_BY_SCAN: +			RT_TRACE(COMP_CMD, DBG_TRACE, +				 ("[IO CMD] Pause DM before scan.\n")); +			b_postprocessing = true; +			break; +		default: +			RT_TRACE(COMP_ERR, DBG_EMERG, +				 ("switch case not process\n")); +			break; +		} +	} while (false); +	if (b_postprocessing && !rtlphy->set_io_inprogress) { +		rtlphy->set_io_inprogress = true; +		rtlphy->current_io_type = iotype; +	} else { +		return false; +	} +	rtl92ee_phy_set_io(hw); +	RT_TRACE(COMP_CMD, DBG_TRACE, ("IO Type(%#x)\n", iotype)); +	return true; +} + +static void rtl92ee_phy_set_io(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); + +	RT_TRACE(COMP_CMD, DBG_TRACE, +		 ("--->Cmd(%#x), set_io_inprogress(%d)\n", +		  rtlphy->current_io_type, rtlphy->set_io_inprogress)); +	switch (rtlphy->current_io_type) { +	case IO_CMD_RESUME_DM_BY_SCAN: +		rtl92ee_dm_write_dig(hw , rtlphy->initgain_backup.xaagccore1); +		rtl92ee_dm_write_cck_cca_thres(hw, rtlphy->initgain_backup.cca); +		RT_TRACE(COMP_CMD, DBG_TRACE , ("no set txpower\n")); +		rtl92ee_phy_set_txpower_level(hw, rtlphy->current_channel); +		break; +	case IO_CMD_PAUSE_BAND0_DM_BY_SCAN: +		/* 8192eebt */ +		rtlphy->initgain_backup.xaagccore1 = dm_dig.cur_igvalue; +		rtl92ee_dm_write_dig(hw, 0x17); +		rtlphy->initgain_backup.cca = dm_dig.cur_cck_cca_thres; +		rtl92ee_dm_write_cck_cca_thres(hw, 0x40); +		break; +	default: +		RT_TRACE(COMP_ERR, DBG_EMERG, +			 ("switch case not process\n")); +		break; +	} +	rtlphy->set_io_inprogress = false; +	RT_TRACE(COMP_CMD, DBG_TRACE, +		 ("(%#x)\n", rtlphy->current_io_type)); +} + +static void rtl92ee_phy_set_rf_on(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); + +	rtl_write_byte(rtlpriv, REG_SPS0_CTRL, 0x2b); +	rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE3); +	/*rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x00);*/ +	rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE2); +	rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE3); +	rtl_write_byte(rtlpriv, REG_TXPAUSE, 0x00); +} + +static void _rtl92ee_phy_set_rf_sleep(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); + +	rtl_write_byte(rtlpriv, REG_TXPAUSE, 0xFF); +	rtl_set_rfreg(hw, RF90_PATH_A, 0x00, RFREG_OFFSET_MASK, 0x00); + +	rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE2); +	rtl_write_byte(rtlpriv, REG_SPS0_CTRL, 0x22); +} + +static bool _rtl92ee_phy_set_rf_power_state(struct ieee80211_hw *hw, +					    enum rf_pwrstate rfpwr_state) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); +	bool bresult = true; +	u8 i, queue_id; +	struct rtl8192_tx_ring *ring = NULL; + +	switch (rfpwr_state) { +	case ERFON: +		if ((ppsc->rfpwr_state == ERFOFF) && +		    RT_IN_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC)) { +			bool rtstatus; +			u32 init_count = 0; +			do { +				init_count++; +				RT_TRACE(COMP_RF, DBG_DMESG, +					 ("IPS Set eRf nic enable\n")); +				rtstatus = stg_rtl_ps_enable_nic(hw); +			} while (!rtstatus && (init_count < 10)); +			RT_CLEAR_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC); +		} else { +			RT_TRACE(COMP_RF, DBG_DMESG, +				 ("Set ERFON sleeped:%d ms\n", +				  jiffies_to_msecs(jiffies - +						   ppsc->last_sleep_jiffies))); +			ppsc->last_awake_jiffies = jiffies; +			rtl92ee_phy_set_rf_on(hw); +		} +		if (mac->link_state == MAC80211_LINKED) +			rtlpriv->cfg->ops->led_control(hw, LED_CTL_LINK); +		else +			rtlpriv->cfg->ops->led_control(hw, LED_CTL_NO_LINK); +		break; +	case ERFOFF: +		for (queue_id = 0, i = 0; +		     queue_id < RTL_PCI_MAX_TX_QUEUE_COUNT;) { +			ring = &pcipriv->dev.tx_ring[queue_id]; +			if (skb_queue_len(&ring->queue) == 0) { +				queue_id++; +				continue; +			} else { +				RT_TRACE(COMP_ERR, DBG_WARNING, +					 ("eRf Off/Sleep: %d times TcbBusyQueue[%d] =%d before " +					  "doze!\n", (i + 1), queue_id, +					  skb_queue_len(&ring->queue))); + +				udelay(10); +				i++; +			} +			if (i >= MAX_DOZE_WAITING_TIMES_9x) { +				RT_TRACE(COMP_ERR, DBG_WARNING, +					 ("\n ERFSLEEP: %d times TcbBusyQueue[%d] = %d !\n", +					  MAX_DOZE_WAITING_TIMES_9x, +					  queue_id, +					  skb_queue_len(&ring->queue))); +				break; +			} +		} + +		if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_HALT_NIC) { +			RT_TRACE(COMP_RF, DBG_DMESG, +				 ("IPS Set eRf nic disable\n")); +			stg_rtl_ps_disable_nic(hw); +			RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC); +		} else { +			if (ppsc->rfoff_reason == RF_CHANGE_BY_IPS) { +				rtlpriv->cfg->ops->led_control(hw, +							       LED_CTL_NO_LINK); +			} else { +				rtlpriv->cfg->ops->led_control(hw, +							     LED_CTL_POWER_OFF); +			} +		} +		break; +	case ERFSLEEP: +		if (ppsc->rfpwr_state == ERFOFF) +			break; +		for (queue_id = 0, i = 0; +		     queue_id < RTL_PCI_MAX_TX_QUEUE_COUNT;) { +			ring = &pcipriv->dev.tx_ring[queue_id]; +			if (skb_queue_len(&ring->queue) == 0) { +				queue_id++; +				continue; +			} else { +				RT_TRACE(COMP_ERR, DBG_WARNING, +					 ("eRf Off/Sleep: %d times TcbBusyQueue[%d] =%d before doze!\n", +					  (i + 1), queue_id, +					  skb_queue_len(&ring->queue))); +				udelay(10); +				i++; +			} +			if (i >= MAX_DOZE_WAITING_TIMES_9x) { +				RT_TRACE(COMP_ERR, DBG_WARNING, +					 ("\n ERFSLEEP: %d times TcbBusyQueue[%d] = %d !\n", +					  MAX_DOZE_WAITING_TIMES_9x, +					  queue_id, +					  skb_queue_len(&ring->queue))); +				break; +			} +		} +		RT_TRACE(COMP_RF, DBG_DMESG, +			 ("Set ERFSLEEP awaked:%d ms\n", +			  jiffies_to_msecs(jiffies - +					   ppsc->last_awake_jiffies))); +		ppsc->last_sleep_jiffies = jiffies; +		_rtl92ee_phy_set_rf_sleep(hw); +		break; +	default: +		RT_TRACE(COMP_ERR, DBG_EMERG, +			 ("switch case not process\n")); +		bresult = false; +		break; +	} +	if (bresult) +		ppsc->rfpwr_state = rfpwr_state; +	return bresult; +} + +bool rtl92ee_phy_set_rf_power_state(struct ieee80211_hw *hw, +				    enum rf_pwrstate rfpwr_state) +{ +	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + +	bool bresult = false; + +	if (rfpwr_state == ppsc->rfpwr_state) +		return bresult; +	bresult = _rtl92ee_phy_set_rf_power_state(hw, rfpwr_state); +	return bresult; +} diff --git a/drivers/staging/rtl8192ee/rtl8192ee/phy.h b/drivers/staging/rtl8192ee/rtl8192ee/phy.h new file mode 100644 index 00000000000..5be6c4866e1 --- /dev/null +++ b/drivers/staging/rtl8192ee/rtl8192ee/phy.h @@ -0,0 +1,154 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010  Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __RTL92E_PHY_H__ +#define __RTL92E_PHY_H__ + +/*It must always set to 4, otherwise read efuse table secquence will be wrong.*/ +#define MAX_TX_COUNT				4 +#define TX_1S					0 +#define TX_2S					1 +#define TX_3S					2 +#define TX_4S					3 + +#define MAX_POWER_INDEX				0x3f + +#define MAX_PRECMD_CNT				16 +#define MAX_RFDEPENDCMD_CNT			16 +#define MAX_POSTCMD_CNT				16 + +#define MAX_DOZE_WAITING_TIMES_9x		64 + +#define RT_CANNOT_IO(hw)			false +#define HIGHPOWER_RADIOA_ARRAYLEN		22 + +#define IQK_ADDA_REG_NUM			16 +#define IQK_MAC_REG_NUM				4 +#define IQK_BB_REG_NUM				9 +#define MAX_TOLERANCE				5 +#define	IQK_DELAY_TIME				10 +#define	index_mapping_NUM			15 + +#define	APK_BB_REG_NUM				5 +#define	APK_AFE_REG_NUM				16 +#define	APK_CURVE_REG_NUM			4 +#define	PATH_NUM				2 + +#define LOOP_LIMIT				5 +#define MAX_STALL_TIME				50 +#define AntennaDiversityValue			0x80 +#define MAX_TXPWR_IDX_NMODE_92S			63 +#define Reset_Cnt_Limit				3 + +#define RF6052_MAX_PATH				2 + +#define CT_OFFSET_MAC_ADDR			0X16 + +#define CT_OFFSET_CCK_TX_PWR_IDX		0x5A +#define CT_OFFSET_HT401S_TX_PWR_IDX		0x60 +#define CT_OFFSET_HT402S_TX_PWR_IDX_DIFF	0x66 +#define CT_OFFSET_HT20_TX_PWR_IDX_DIFF		0x69 +#define CT_OFFSET_OFDM_TX_PWR_IDX_DIFF		0x6C + +#define CT_OFFSET_HT40_MAX_PWR_OFFSET		0x6F +#define CT_OFFSET_HT20_MAX_PWR_OFFSET		0x72 + +#define CT_OFFSET_CHANNEL_PLAH			0x75 +#define CT_OFFSET_THERMAL_METER			0x78 +#define CT_OFFSET_RF_OPTION			0x79 +#define CT_OFFSET_VERSION			0x7E +#define CT_OFFSET_CUSTOMER_ID			0x7F + +#define RTL92C_MAX_PATH_NUM			2 + +enum swchnlcmd_id { +	CMDID_END, +	CMDID_SET_TXPOWEROWER_LEVEL, +	CMDID_BBREGWRITE10, +	CMDID_WRITEPORT_ULONG, +	CMDID_WRITEPORT_USHORT, +	CMDID_WRITEPORT_UCHAR, +	CMDID_RF_WRITEREG, +}; + +struct swchnlcmd { +	enum swchnlcmd_id cmdid; +	u32 para1; +	u32 para2; +	u32 msdelay; +}; + +enum baseband_config_type { +	BASEBAND_CONFIG_PHY_REG = 0, +	BASEBAND_CONFIG_AGC_TAB = 1, +}; + +enum ant_div_type { +	NO_ANTDIV = 0xFF, +	CG_TRX_HW_ANTDIV = 0x01, +	CGCS_RX_HW_ANTDIV = 0x02, +	FIXED_HW_ANTDIV = 0x03, +	CG_TRX_SMART_ANTDIV = 0x04, +	CGCS_RX_SW_ANTDIV = 0x05, + +}; +extern u32 rtl92ee_phy_query_bb_reg(struct ieee80211_hw *hw, +				    u32 regaddr, u32 bitmask); +extern void rtl92ee_phy_set_bb_reg(struct ieee80211_hw *hw, +				   u32 regaddr, u32 bitmask, u32 data); +extern u32 rtl92ee_phy_query_rf_reg(struct ieee80211_hw *hw, +				    enum radio_path rfpath, u32 regaddr, +				    u32 bitmask); +extern void rtl92ee_phy_set_rf_reg(struct ieee80211_hw *hw, +				   enum radio_path rfpath, u32 regaddr, +				   u32 bitmask, u32 data); +extern bool rtl92ee_phy_mac_config(struct ieee80211_hw *hw); +extern bool rtl92ee_phy_bb_config(struct ieee80211_hw *hw); +extern bool rtl92ee_phy_rf_config(struct ieee80211_hw *hw); +extern void rtl92ee_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw); +extern void rtl92ee_phy_get_txpower_level(struct ieee80211_hw *hw, +					  long *powerlevel); +extern void rtl92ee_phy_set_txpower_level(struct ieee80211_hw *hw, u8 channel); +extern void rtl92ee_phy_scan_operation_backup(struct ieee80211_hw *hw, +					      u8 operation); +extern void rtl92ee_phy_set_bw_mode_callback(struct ieee80211_hw *hw); +extern void rtl92ee_phy_set_bw_mode(struct ieee80211_hw *hw, +				    enum nl80211_channel_type ch_type); +extern void rtl92ee_phy_sw_chnl_callback(struct ieee80211_hw *hw); +extern u8 rtl92ee_phy_sw_chnl(struct ieee80211_hw *hw); +extern void rtl92ee_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery); +void rtl92ee_phy_ap_calibrate(struct ieee80211_hw *hw, char delta); +void rtl92ee_phy_lc_calibrate(struct ieee80211_hw *hw); +void rtl92ee_phy_set_rfpath_switch(struct ieee80211_hw *hw, bool bmain); +bool rtl92ee_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, +					   enum radio_path rfpath); +bool rtl92ee_phy_set_io_cmd(struct ieee80211_hw *hw, enum io_type iotype); +extern bool rtl92ee_phy_set_rf_power_state(struct ieee80211_hw *hw, +					   enum rf_pwrstate rfpwr_state); +#endif diff --git a/drivers/staging/rtl8192ee/rtl8192ee/pwrseq.c b/drivers/staging/rtl8192ee/rtl8192ee/pwrseq.c new file mode 100644 index 00000000000..08a2df8dfd2 --- /dev/null +++ b/drivers/staging/rtl8192ee/rtl8192ee/pwrseq.c @@ -0,0 +1,108 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010  Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#include "pwrseqcmd.h" +#include "pwrseq.h" + + +/* +    drivers should parse below arrays and do the corresponding actions +*/ +/*3 Power on  Array*/ +struct wlan_pwr_cfg rtl8192E_power_on_flow[RTL8192E_TRANS_CARDEMU_TO_ACT_STEPS + +					   RTL8192E_TRANS_END_STEPS] = { +	RTL8192E_TRANS_CARDEMU_TO_ACT +	RTL8192E_TRANS_END +}; + +/*3Radio off GPIO Array */ +struct wlan_pwr_cfg rtl8192E_radio_off_flow[RTL8192E_TRANS_ACT_TO_CARDEMU_STEPS +					    + RTL8192E_TRANS_END_STEPS] = { +	RTL8192E_TRANS_ACT_TO_CARDEMU +	RTL8192E_TRANS_END +}; + +/*3Card Disable Array*/ +struct wlan_pwr_cfg rtl8192E_card_disable_flow +					[RTL8192E_TRANS_ACT_TO_CARDEMU_STEPS + +					 RTL8192E_TRANS_CARDEMU_TO_PDN_STEPS + +					 RTL8192E_TRANS_END_STEPS] = { +	RTL8192E_TRANS_ACT_TO_CARDEMU +	RTL8192E_TRANS_CARDEMU_TO_CARDDIS +	RTL8192E_TRANS_END +}; + +/*3 Card Enable Array*/ +struct wlan_pwr_cfg rtl8192E_card_enable_flow +					[RTL8192E_TRANS_ACT_TO_CARDEMU_STEPS + +					 RTL8192E_TRANS_CARDEMU_TO_PDN_STEPS + +					 RTL8192E_TRANS_END_STEPS] = { +	RTL8192E_TRANS_CARDDIS_TO_CARDEMU +	RTL8192E_TRANS_CARDEMU_TO_ACT +	RTL8192E_TRANS_END +}; + +/*3Suspend Array*/ +struct wlan_pwr_cfg rtl8192E_suspend_flow[RTL8192E_TRANS_ACT_TO_CARDEMU_STEPS + +					  RTL8192E_TRANS_CARDEMU_TO_SUS_STEPS + +					  RTL8192E_TRANS_END_STEPS] = { +	RTL8192E_TRANS_ACT_TO_CARDEMU +	RTL8192E_TRANS_CARDEMU_TO_SUS +	RTL8192E_TRANS_END +}; + +/*3 Resume Array*/ +struct wlan_pwr_cfg rtl8192E_resume_flow[RTL8192E_TRANS_ACT_TO_CARDEMU_STEPS + +					 RTL8192E_TRANS_CARDEMU_TO_SUS_STEPS + +					 RTL8192E_TRANS_END_STEPS] = { +	RTL8192E_TRANS_SUS_TO_CARDEMU +	RTL8192E_TRANS_CARDEMU_TO_ACT +	RTL8192E_TRANS_END +}; + +/*3HWPDN Array*/ +struct wlan_pwr_cfg rtl8192E_hwpdn_flow[RTL8192E_TRANS_ACT_TO_CARDEMU_STEPS + +					RTL8192E_TRANS_CARDEMU_TO_PDN_STEPS + +					RTL8192E_TRANS_END_STEPS] = { +	RTL8192E_TRANS_ACT_TO_CARDEMU +	RTL8192E_TRANS_CARDEMU_TO_PDN +	RTL8192E_TRANS_END +}; + +/*3 Enter LPS */ +struct wlan_pwr_cfg rtl8192E_enter_lps_flow[RTL8192E_TRANS_ACT_TO_LPS_STEPS + +					    RTL8192E_TRANS_END_STEPS] = { +	/*FW behavior*/ +	RTL8192E_TRANS_ACT_TO_LPS +	RTL8192E_TRANS_END +}; + +/*3 Leave LPS */ +struct wlan_pwr_cfg rtl8192E_leave_lps_flow[RTL8192E_TRANS_LPS_TO_ACT_STEPS + +					    RTL8192E_TRANS_END_STEPS] = { +	/*FW behavior*/ +	RTL8192E_TRANS_LPS_TO_ACT +	RTL8192E_TRANS_END +}; diff --git a/drivers/staging/rtl8192ee/rtl8192ee/pwrseq.h b/drivers/staging/rtl8192ee/rtl8192ee/pwrseq.h new file mode 100644 index 00000000000..52889721322 --- /dev/null +++ b/drivers/staging/rtl8192ee/rtl8192ee/pwrseq.h @@ -0,0 +1,355 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010  Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __RTL92E_PWRSEQ_H__ +#define __RTL92E_PWRSEQ_H__ + +#include "pwrseqcmd.h" +/* +	Check document WM-20110607-Paul-RTL8192E_Power_Architecture-R02.vsd +	There are 6 HW Power States: +	0: POFF--Power Off +	1: PDN--Power Down +	2: CARDEMU--Card Emulation +	3: ACT--Active Mode +	4: LPS--Low Power State +	5: SUS--Suspend + +	The transision from different states are defined below +	TRANS_CARDEMU_TO_ACT +	TRANS_ACT_TO_CARDEMU +	TRANS_CARDEMU_TO_SUS +	TRANS_SUS_TO_CARDEMU +	TRANS_CARDEMU_TO_PDN +	TRANS_ACT_TO_LPS +	TRANS_LPS_TO_ACT + +	TRANS_END +	PWR SEQ Version: rtl8192E_PwrSeq_V09.h +*/ + +#define	RTL8192E_TRANS_CARDEMU_TO_ACT_STEPS	18 +#define	RTL8192E_TRANS_ACT_TO_CARDEMU_STEPS	18 +#define	RTL8192E_TRANS_CARDEMU_TO_SUS_STEPS	18 +#define	RTL8192E_TRANS_SUS_TO_CARDEMU_STEPS	18 +#define	RTL8192E_TRANS_CARDEMU_TO_PDN_STEPS	18 +#define	RTL8192E_TRANS_PDN_TO_CARDEMU_STEPS	18 +#define	RTL8192E_TRANS_ACT_TO_LPS_STEPS		23 +#define	RTL8192E_TRANS_LPS_TO_ACT_STEPS		23 +#define	RTL8192E_TRANS_END_STEPS		1 + + +#define RTL8192E_TRANS_CARDEMU_TO_ACT					\ +	/* format */							\ +	/* comments here */						\ +	/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value },*/\ +	/* disable HWPDN 0x04[15]=0*/					\ +	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\ +	 PWR_BASEADDR_MAC , PWR_CMD_WRITE, BIT(7), 0},			\ +	/* disable SW LPS 0x04[10]=0*/					\ +	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\ +	 PWR_BASEADDR_MAC , PWR_CMD_WRITE, BIT(2), 0},			\ +	/* disable WL suspend*/						\ +	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\ +	 PWR_BASEADDR_MAC , PWR_CMD_WRITE, (BIT(4)|BIT(3)), 0},		\ +	/* wait till 0x04[17] = 1    power ready*/			\ +	{0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\ +	 PWR_BASEADDR_MAC , PWR_CMD_POLLING, BIT(1), BIT(1)},		\ +	/* release WLON reset  0x04[16]=1*/				\ +	{0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\ +	 PWR_BASEADDR_MAC , PWR_CMD_WRITE, BIT(0), BIT(0)},		\ +	/* polling until return 0*/					\ +	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\ +	 PWR_BASEADDR_MAC , PWR_CMD_WRITE, BIT(0), BIT(0)},		\ +	/**/								\ +	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\ +	 PWR_BASEADDR_MAC , PWR_CMD_POLLING, BIT(0), 0}, + + +#define RTL8192E_TRANS_ACT_TO_CARDEMU					\ +	/* format */							\ +	/* comments here */						\ +	/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value },*/\ +	/*0x1F[7:0] = 0 turn off RF*/					\ +	{0x001F, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\ +	 PWR_BASEADDR_MAC , PWR_CMD_WRITE, 0xFF, 0},			\ +	/*0x4C[23]=0x4E[7]=0, switch DPDT_SEL_P output from register 0x65[2] */\ +	{0x004E, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\ +	 PWR_BASEADDR_MAC , PWR_CMD_WRITE, BIT(7), 0},			\ +	/*0x04[9] = 1 turn off MAC by HW state machine*/		\ +	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\ +	 PWR_BASEADDR_MAC , PWR_CMD_WRITE, BIT(1), BIT(1)},		\ +	/*wait till 0x04[9] = 0 polling until return 0 to disable*/	\ +	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\ +	 PWR_BASEADDR_MAC , PWR_CMD_POLLING, BIT(1), 0}, + + +#define RTL8192E_TRANS_CARDEMU_TO_SUS					\ +	/* format */							\ +	/* comments here */						\ +	/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value },*/\ +	/*0x04[12:11] = 2b'11 enable WL suspend for PCIe*/		\ +	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,	\ +	 PWR_BASEADDR_MAC , PWR_CMD_WRITE, BIT(4) | BIT(3), (BIT(4) | BIT(3))},\ +	/*0x04[12:11] = 2b'01 enable WL suspend*/			\ +	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK,			\ +	 PWR_INTF_USB_MSK | PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC,	\ +	 PWR_CMD_WRITE, BIT(3)|BIT(4), BIT(3)},				\ +	/*0x04[12:11] = 2b'11 enable WL suspend for PCIe*/		\ +	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,	\ +	 PWR_BASEADDR_MAC , PWR_CMD_WRITE, BIT(3) | BIT(4), BIT(3) | BIT(4)},\ +	/*Set SDIO suspend local register*/				\ +	{0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,	\ +	 PWR_BASEADDR_SDIO , PWR_CMD_WRITE, BIT(0), BIT(0)},		\ +	 /*wait power state to suspend*/				\ +	{0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,	\ +	 PWR_BASEADDR_SDIO , PWR_CMD_POLLING, BIT(1), 0}, + + +#define RTL8192E_TRANS_SUS_TO_CARDEMU					\ +	/* format */							\ +	/* comments here */						\ +	/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value },*/\ +	/*Set SDIO suspend local register*/				\ +	{0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,	\ +	 PWR_BASEADDR_SDIO , PWR_CMD_WRITE, BIT(0), 0},			\ +	/*wait power state to suspend*/					\ +	{0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,	\ +	 PWR_BASEADDR_SDIO , PWR_CMD_POLLING, BIT(1), BIT(1)},		\ +	/*0x04[12:11] = 2b'01enable WL suspend*/			\ +	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\ +	 PWR_BASEADDR_MAC , PWR_CMD_WRITE, BIT(3) | BIT(4), 0}, + + +#define RTL8192E_TRANS_CARDEMU_TO_CARDDIS				\ +	/* format */							\ +	/* comments here */						\ +	/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value },*/\ +	/*0x07=0x20 , SOP option to disable BG/MB*/			\ +	{0x0007, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,	\ +	 PWR_BASEADDR_MAC , PWR_CMD_WRITE, 0xFF, 0x20},			\ +	/*Unlock small LDO Register*/					\ +	{0x00CC, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,	\ +	 PWR_BASEADDR_MAC , PWR_CMD_WRITE, BIT(2), BIT(2)},		\ +	/*Disable small LDO*/						\ +	{0x0011, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,	\ +	 PWR_BASEADDR_MAC , PWR_CMD_WRITE, BIT(0), 0},			\ +	/*0x04[12:11] = 2b'01 enable WL suspend*/			\ +	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK,			\ +	 PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK,PWR_BASEADDR_MAC,		\ +	 PWR_CMD_WRITE, BIT(3)|BIT(4), BIT(3)},				\ +	/*0x04[10] = 1, enable SW LPS*/					\ +	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,	\ +	 PWR_BASEADDR_MAC , PWR_CMD_WRITE, BIT(2), BIT(2)},		\ +	/*Set SDIO suspend local register*/				\ +	{0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,	\ +	 PWR_BASEADDR_SDIO , PWR_CMD_WRITE, BIT(0), BIT(0)},		\ +	/*wait power state to suspend*/					\ +	{0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,	\ +	 PWR_BASEADDR_SDIO , PWR_CMD_POLLING, BIT(1), 0}, + + +#define RTL8192E_TRANS_CARDDIS_TO_CARDEMU				\ +	/* format */							\ +	/* comments here */						\ +	/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value },*/\ +	/*Set SDIO suspend local register*/				\ +	{0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,	\ +	 PWR_BASEADDR_SDIO , PWR_CMD_WRITE, BIT(0), 0},			\ +	/*wait power state to suspend*/					\ +	{0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,	\ +	 PWR_BASEADDR_SDIO , PWR_CMD_POLLING, BIT(1), BIT(1)},		\ +	/*Enable small LDO*/						\ +	{0x0011, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,	\ +	 PWR_BASEADDR_MAC , PWR_CMD_WRITE, BIT(0), BIT(0)},		\ +	/*Lock small LDO Register*/					\ +	{0x00CC, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,	\ +	 PWR_BASEADDR_MAC , PWR_CMD_WRITE, BIT(2), 0},			\ +	/*0x04[12:11] = 2b'01enable WL suspend*/			\ +	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\ +	 PWR_BASEADDR_MAC , PWR_CMD_WRITE, BIT(3) | BIT(4), 0}, + + +#define RTL8192E_TRANS_CARDEMU_TO_PDN					\ +	/* format */							\ +	/* comments here */						\ +	/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value },*/\ +	/* 0x04[16] = 0*/						\ +	{0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\ +	 PWR_BASEADDR_MAC , PWR_CMD_WRITE, BIT(0), 0},			\ +	/* 0x04[15] = 1*/						\ +	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\ +	 PWR_BASEADDR_MAC , PWR_CMD_WRITE, BIT(7), BIT(7)}, + + +#define RTL8192E_TRANS_PDN_TO_CARDEMU					\ +	/* format */							\ +	/* comments here */						\ +	/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value },*/\ +	/* 0x04[15] = 0*/						\ +	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\ +	 PWR_BASEADDR_MAC , PWR_CMD_WRITE, BIT(7), 0}, + + +#define RTL8192E_TRANS_ACT_TO_LPS					\ +	/* format */							\ +	/* comments here */						\ +	/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value },*/\ +	/*PCIe DMA stop*/						\ +	{0x0301, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,	\ +	 PWR_BASEADDR_MAC , PWR_CMD_WRITE, 0xFF, 0xFF},			\ +	/*Tx Pause*/							\ +	{0x0522, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\ +	 PWR_BASEADDR_MAC , PWR_CMD_WRITE, 0xFF, 0xFF},			\ +	/*Should be zero if no packet is transmitting*/			\ +	{0x05F8, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\ +	 PWR_BASEADDR_MAC , PWR_CMD_POLLING, 0xFF, 0},			\ +	/*Should be zero if no packet is transmitting*/			\ +	{0x05F9, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\ +	 PWR_BASEADDR_MAC , PWR_CMD_POLLING, 0xFF, 0},			\ +	/*Should be zero if no packet is transmitting*/			\ +	{0x05FA, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\ +	 PWR_BASEADDR_MAC , PWR_CMD_POLLING, 0xFF, 0},			\ +	/*Should be zero if no packet is transmitting*/			\ +	{0x05FB, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\ +	 PWR_BASEADDR_MAC , PWR_CMD_POLLING, 0xFF, 0},			\ +	/*CCK and OFDM are disabled,and clock are gated*/		\ +	{0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\ +	 PWR_BASEADDR_MAC , PWR_CMD_WRITE, BIT(0), 0},			\ +	/*Delay 1us*/							\ +	{0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\ +	 PWR_BASEADDR_MAC , PWR_CMD_DELAY, 0, PWRSEQ_DELAY_US},		\ +	/*Whole BB is reset*/						\ +	{0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\ +	 PWR_BASEADDR_MAC , PWR_CMD_WRITE, BIT(1), 0},			\ +	/*Reset MAC TRX*/						\ +	{0x0100, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\ +	 PWR_BASEADDR_MAC , PWR_CMD_WRITE, 0xFF, 0x03},			\ +	/*check if removed later*/					\ +	{0x0101, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\ +	 PWR_BASEADDR_MAC , PWR_CMD_WRITE, BIT(1), 0},			\ +	/*When driver enter Sus/ Disable, enable LOP for BT*/		\ +	{0x0093, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,	\ +	 PWR_BASEADDR_MAC , PWR_CMD_WRITE, 0xFF, 0x00},			\ +	/*Respond TxOK to scheduler*/					\ +	{0x0553, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\ +	 PWR_BASEADDR_MAC , PWR_CMD_WRITE, BIT(5), BIT(5)}, + + +#define RTL8192E_TRANS_LPS_TO_ACT					\ +	/* format */							\ +	/* comments here */						\ +	/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value },*/\ +	/*SDIO RPWM, For Repeatly In and out, Taggle bit should be changed*/\ +	{0x0080, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,	\ +	 PWR_BASEADDR_SDIO , PWR_CMD_WRITE, 0xFF, 0x84},			\ +	/*USB RPWM*/							\ +	{0xFE58, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK,	\ +	 PWR_BASEADDR_MAC , PWR_CMD_WRITE, 0xFF, 0x84},			\ +	/*PCIe RPWM*/							\ +	{0x0361, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,	\ +	 PWR_BASEADDR_MAC , PWR_CMD_WRITE, 0xFF, 0x84},			\ +	/*Delay*/							\ +	{0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\ +	 PWR_BASEADDR_MAC , PWR_CMD_DELAY, 0, PWRSEQ_DELAY_MS},		\ +	/*0x08[4] = 0 switch TSF to 40M*/				\ +	{0x0008, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\ +	 PWR_BASEADDR_MAC , PWR_CMD_WRITE, BIT(4), 0},			\ +	/*Polling 0x109[7]=0  TSF in 40M*/				\ +	{0x0109, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\ +	 PWR_BASEADDR_MAC , PWR_CMD_POLLING, BIT(7), 0},			\ +	/*0x101[1] = 1*/						\ +	{0x0101, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\ +	 PWR_BASEADDR_MAC , PWR_CMD_WRITE, BIT(1), BIT(1)},		\ +	/*0x100[7:0] = 0xFF  enable WMAC TRX*/				\ +	{0x0100, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\ +	 PWR_BASEADDR_MAC , PWR_CMD_WRITE, 0xFF, 0xFF},			\ +	/* 0x02[1:0] = 2b'11 enable BB macro*/				\ +	{0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\ +	 PWR_BASEADDR_MAC , PWR_CMD_WRITE, BIT(1) | BIT(0), BIT(1) | BIT(0)},\ +	/*0x522 = 0*/							\ +	{0x0522, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\ +	 PWR_BASEADDR_MAC , PWR_CMD_WRITE, 0xFF, 0},			\ +	/*Clear ISR*/							\ +	{0x013D, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\ +	 PWR_BASEADDR_MAC , PWR_CMD_WRITE, 0xFF, 0xFF}, + + +#define RTL8192E_TRANS_END						\ +	/* format */							\ +	/* comments here */						\ +	/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value },*/\ +	{0xFFFF, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\ +	 0, PWR_CMD_END, 0, 0}, + +extern struct wlan_pwr_cfg rtl8192E_power_on_flow +					[RTL8192E_TRANS_CARDEMU_TO_ACT_STEPS + +					 RTL8192E_TRANS_END_STEPS]; +extern struct wlan_pwr_cfg rtl8192E_radio_off_flow +					[RTL8192E_TRANS_ACT_TO_CARDEMU_STEPS + +					 RTL8192E_TRANS_END_STEPS]; +extern struct wlan_pwr_cfg rtl8192E_card_disable_flow +					[RTL8192E_TRANS_ACT_TO_CARDEMU_STEPS + +					 RTL8192E_TRANS_CARDEMU_TO_PDN_STEPS + +					 RTL8192E_TRANS_END_STEPS]; +extern struct wlan_pwr_cfg rtl8192E_card_enable_flow +					[RTL8192E_TRANS_ACT_TO_CARDEMU_STEPS + +					 RTL8192E_TRANS_CARDEMU_TO_PDN_STEPS + +					 RTL8192E_TRANS_END_STEPS]; +extern struct wlan_pwr_cfg rtl8192E_suspend_flow +					[RTL8192E_TRANS_ACT_TO_CARDEMU_STEPS + +					 RTL8192E_TRANS_CARDEMU_TO_SUS_STEPS + +					 RTL8192E_TRANS_END_STEPS]; +extern struct wlan_pwr_cfg rtl8192E_resume_flow +					[RTL8192E_TRANS_ACT_TO_CARDEMU_STEPS + +					 RTL8192E_TRANS_CARDEMU_TO_SUS_STEPS + +					 RTL8192E_TRANS_END_STEPS]; +extern struct wlan_pwr_cfg rtl8192E_hwpdn_flow +					[RTL8192E_TRANS_ACT_TO_CARDEMU_STEPS + +					 RTL8192E_TRANS_CARDEMU_TO_PDN_STEPS + +					 RTL8192E_TRANS_END_STEPS]; +extern struct wlan_pwr_cfg rtl8192E_enter_lps_flow +					[RTL8192E_TRANS_ACT_TO_LPS_STEPS + +					 RTL8192E_TRANS_END_STEPS]; +extern struct wlan_pwr_cfg rtl8192E_leave_lps_flow +					[RTL8192E_TRANS_LPS_TO_ACT_STEPS + +					 RTL8192E_TRANS_END_STEPS]; + + +/* RTL8192EE Power Configuration CMDs for PCIe interface */ +#define Rtl8192E_NIC_PWR_ON_FLOW	rtl8192E_power_on_flow +#define Rtl8192E_NIC_RF_OFF_FLOW	rtl8192E_radio_off_flow +#define Rtl8192E_NIC_DISABLE_FLOW	rtl8192E_card_disable_flow +#define Rtl8192E_NIC_ENABLE_FLOW	rtl8192E_card_enable_flow +#define Rtl8192E_NIC_SUSPEND_FLOW	rtl8192E_suspend_flow +#define Rtl8192E_NIC_RESUME_FLOW	rtl8192E_resume_flow +#define Rtl8192E_NIC_PDN_FLOW		rtl8192E_hwpdn_flow +#define Rtl8192E_NIC_LPS_ENTER_FLOW	rtl8192E_enter_lps_flow +#define Rtl8192E_NIC_LPS_LEAVE_FLOW	rtl8192E_leave_lps_flow +#endif diff --git a/drivers/staging/rtl8192ee/rtl8192ee/pwrseqcmd.c b/drivers/staging/rtl8192ee/rtl8192ee/pwrseqcmd.c new file mode 100644 index 00000000000..efb00f62236 --- /dev/null +++ b/drivers/staging/rtl8192ee/rtl8192ee/pwrseqcmd.c @@ -0,0 +1,139 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010  Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#include "pwrseq.h" + + +/* +*	Description: +*		This routine deal with the Power Configuration CMDs +*		 parsing for RTL8723/RTL8188E Series IC. +*	Assumption: +*		We should follow specific format which was released from HW SD. +* +*	2011.07.07, added by Roger. +*/ +bool rtl92e_hal_pwrseqcmdparsing(struct rtl_priv *rtlpriv, u8 cut_version, +			       u8 fab_version, u8 interface_type, +			       struct wlan_pwr_cfg pwrcfgcmd[]) + +{ +	struct wlan_pwr_cfg pwr_cfg_cmd = {0}; +	bool b_polling_bit = false; +	u32 ary_idx = 0; +	u8 value = 0; +	u32 offset = 0; +	u32 polling_count = 0; +	u32 max_polling_cnt = 5000; + +	do { +		pwr_cfg_cmd = pwrcfgcmd[ary_idx]; +		RT_TRACE(COMP_INIT, DBG_TRACE, +			 ("offset(%#x), cut_msk(%#x), fab_msk(%#x), interface_msk(%#x), base(%#x), cmd(%#x), msk(%#x), value(%#x)\n", +			  GET_PWR_CFG_OFFSET(pwr_cfg_cmd), +			  GET_PWR_CFG_CUT_MASK(pwr_cfg_cmd), +			  GET_PWR_CFG_FAB_MASK(pwr_cfg_cmd), +			  GET_PWR_CFG_INTF_MASK(pwr_cfg_cmd), +			  GET_PWR_CFG_BASE(pwr_cfg_cmd), +			  GET_PWR_CFG_CMD(pwr_cfg_cmd), +			  GET_PWR_CFG_MASK(pwr_cfg_cmd), +			  GET_PWR_CFG_VALUE(pwr_cfg_cmd))); + +		if ((GET_PWR_CFG_FAB_MASK(pwr_cfg_cmd)&fab_version) && +		    (GET_PWR_CFG_CUT_MASK(pwr_cfg_cmd)&cut_version) && +		    (GET_PWR_CFG_INTF_MASK(pwr_cfg_cmd)&interface_type)) { +			switch (GET_PWR_CFG_CMD(pwr_cfg_cmd)) { +			case PWR_CMD_READ: +				RT_TRACE(COMP_INIT, DBG_TRACE, +					 ("PWR_CMD_READ\n")); +				break; + +			case PWR_CMD_WRITE: +				RT_TRACE(COMP_INIT, DBG_TRACE, +					 ("PWR_CMD_WRITE\n")); +				offset = GET_PWR_CFG_OFFSET(pwr_cfg_cmd); + +				/*Read the value from system register*/ +				value = rtl_read_byte(rtlpriv, offset); +				value &= (~(GET_PWR_CFG_MASK(pwr_cfg_cmd))); +				value |= (GET_PWR_CFG_VALUE(pwr_cfg_cmd) & +					  GET_PWR_CFG_MASK(pwr_cfg_cmd)); + +				/*Write value back to sytem register*/ +				rtl_write_byte(rtlpriv, offset, value); +				break; + +			case PWR_CMD_POLLING: +				RT_TRACE(COMP_INIT, DBG_TRACE, +					 ("PWR_CMD_POLLING\n")); +				b_polling_bit = false; +				offset = GET_PWR_CFG_OFFSET(pwr_cfg_cmd); + +				do { +					value = rtl_read_byte(rtlpriv, offset); + +					value &= GET_PWR_CFG_MASK(pwr_cfg_cmd); +					if (value == +					    (GET_PWR_CFG_VALUE(pwr_cfg_cmd) & +					     GET_PWR_CFG_MASK(pwr_cfg_cmd))) +						b_polling_bit = true; +					else +						udelay(10); + +					if (polling_count++ > max_polling_cnt) { +						RT_TRACE(COMP_INIT, DBG_LOUD, +							 ("polling fail\n")); +						return false; +					} +				} while (!b_polling_bit); + +				break; + +			case PWR_CMD_DELAY: +				RT_TRACE(COMP_INIT, DBG_TRACE, +					 ("PWR_CMD_DELAY\n")); +				if (GET_PWR_CFG_VALUE(pwr_cfg_cmd) == +				    PWRSEQ_DELAY_US) +					udelay(GET_PWR_CFG_OFFSET(pwr_cfg_cmd)); +				else +					mdelay(GET_PWR_CFG_OFFSET(pwr_cfg_cmd)); +				break; + +			case PWR_CMD_END: +				RT_TRACE(COMP_INIT, DBG_TRACE, +					 ("PWR_CMD_END\n")); +				return true; +				break; + +			default: +				RT_ASSERT(false, ("Unknown CMD!!\n")); +				break; +			} +		} + +		ary_idx++; +	} while (1); +	return true; +} diff --git a/drivers/staging/rtl8192ee/rtl8192ee/pwrseqcmd.h b/drivers/staging/rtl8192ee/rtl8192ee/pwrseqcmd.h new file mode 100644 index 00000000000..ec40ea8b8c2 --- /dev/null +++ b/drivers/staging/rtl8192ee/rtl8192ee/pwrseqcmd.h @@ -0,0 +1,69 @@ +#ifndef __RTL92E_PWRSEQCMD_H__ +#define __RTL92E_PWRSEQCMD_H__ + +#include "../wifi.h" +/*---------------------------------------------*/ +/* The value of cmd: 4 bits */ +/*---------------------------------------------*/ +#define	PWR_CMD_READ		0x00 +#define PWR_CMD_WRITE		0x01 +#define PWR_CMD_POLLING		0x02 +#define PWR_CMD_DELAY		0x03 +#define PWR_CMD_END		0x04 + +/* define the base address of each block */ +#define PWR_BASEADDR_MAC	0x00 +#define PWR_BASEADDR_USB	0x01 +#define PWR_BASEADDR_PCIE	0x02 +#define PWR_BASEADDR_SDIO	0x03 + +#define	PWR_INTF_SDIO_MSK	BIT(0) +#define	PWR_INTF_USB_MSK	BIT(1) +#define	PWR_INTF_PCI_MSK	BIT(2) +#define	PWR_INTF_ALL_MSK	(BIT(0) | BIT(1) | BIT(2) | BIT(3)) + +#define	PWR_FAB_TSMC_MSK	BIT(0) +#define	PWR_FAB_UMC_MSK		BIT(1) +#define	PWR_FAB_ALL_MSK		(BIT(0) | BIT(1) | BIT(2) | BIT(3)) + +#define	PWR_CUT_TESTCHIP_MSK	BIT(0) +#define	PWR_CUT_A_MSK		BIT(1) +#define	PWR_CUT_B_MSK		BIT(2) +#define	PWR_CUT_C_MSK		BIT(3) +#define	PWR_CUT_D_MSK		BIT(4) +#define	PWR_CUT_E_MSK		BIT(5) +#define	PWR_CUT_F_MSK		BIT(6) +#define	PWR_CUT_G_MSK		BIT(7) +#define	PWR_CUT_ALL_MSK		0xFF + + +enum pwrseq_delay_unit { +	PWRSEQ_DELAY_US, +	PWRSEQ_DELAY_MS, +}; + +struct wlan_pwr_cfg { +	u16 offset; +	u8 cut_msk; +	u8 fab_msk:4; +	u8 interface_msk:4; +	u8 base:4; +	u8 cmd:4; +	u8 msk; +	u8 value; +}; + +#define	GET_PWR_CFG_OFFSET(__PWR_CMD)		__PWR_CMD.offset +#define	GET_PWR_CFG_CUT_MASK(__PWR_CMD)		__PWR_CMD.cut_msk +#define	GET_PWR_CFG_FAB_MASK(__PWR_CMD)		__PWR_CMD.fab_msk +#define	GET_PWR_CFG_INTF_MASK(__PWR_CMD)	__PWR_CMD.interface_msk +#define	GET_PWR_CFG_BASE(__PWR_CMD)		__PWR_CMD.base +#define	GET_PWR_CFG_CMD(__PWR_CMD)		__PWR_CMD.cmd +#define	GET_PWR_CFG_MASK(__PWR_CMD)		__PWR_CMD.msk +#define	GET_PWR_CFG_VALUE(__PWR_CMD)		__PWR_CMD.value + +bool rtl92e_hal_pwrseqcmdparsing(struct rtl_priv *rtlpriv, u8 cut_version, +			      u8 fab_version, u8 interface_type, +			      struct wlan_pwr_cfg pwrcfgcmd[]); + +#endif diff --git a/drivers/staging/rtl8192ee/rtl8192ee/reg.h b/drivers/staging/rtl8192ee/rtl8192ee/reg.h new file mode 100644 index 00000000000..08c07577239 --- /dev/null +++ b/drivers/staging/rtl8192ee/rtl8192ee/reg.h @@ -0,0 +1,2240 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010  Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __RTL92E_REG_H__ +#define __RTL92E_REG_H__ + +#define TXPKT_BUF_SELECT			0x69 +#define RXPKT_BUF_SELECT			0xA5 +#define DISABLE_TRXPKT_BUF_ACCESS		0x0 + +#define REG_SYS_ISO_CTRL			0x0000 +#define REG_SYS_FUNC_EN				0x0002 +#define REG_APS_FSMCO				0x0004 +#define REG_SYS_CLKR				0x0008 +#define REG_9346CR				0x000A +#define REG_EE_VPD				0x000C +#define REG_SYS_SWR_CTRL1			0x0010 +#define REG_SPS0_CTRL				0x0011 +#define REG_SYS_SWR_CTRL2			0x0014 +#define REG_SYS_SWR_CTRL3			0x0018 +#define REG_RSV_CTRL				0x001C +#define REG_RF_CTRL				0x001F +#define REG_LPLDO_CTRL				0x0023 +#define REG_AFE_CTRL1				0x0024 +#define REG_AFE_XTAL_CTRL			0x0024 +#define REG_AFE_CTRL2				0x0028 +#define REG_MAC_PHY_CTRL			0x002c +#define REG_AFE_CTRL3				0x002c +#define REG_EFUSE_CTRL				0x0030 +#define REG_EFUSE_TEST				0x0034 +#define REG_PWR_DATA				0x0038 +#define REG_CAL_TIMER				0x003C +#define REG_ACLK_MON				0x003E +#define REG_GPIO_MUXCFG				0x0040 +#define REG_GPIO_IO_SEL				0x0042 +#define REG_MAC_PINMUX_CFG			0x0043 +#define REG_GPIO_PIN_CTRL			0x0044 +#define REG_GPIO_INTM				0x0048 +#define REG_LEDCFG0				0x004C +#define REG_LEDCFG1				0x004D +#define REG_LEDCFG2				0x004E +#define REG_LEDCFG3				0x004F +#define REG_FSIMR				0x0050 +#define REG_FSISR				0x0054 +#define REG_HSIMR				0x0058 +#define REG_HSISR				0x005c +#define REG_SDIO_CTRL				0x0070 +#define REG_OPT_CTRL				0x0074 +#define REG_GPIO_OUTPUT				0x006c +#define REG_AFE_CTRL4				0x0078 +#define REG_MCUFWDL				0x0080 + +#define REG_HIMR				0x00B0 +#define REG_HISR				0x00B4 +#define REG_HIMRE				0x00B8 +#define REG_HISRE				0x00BC + +#define REG_EFUSE_ACCESS			0x00CF +#define REG_HPON_FSM				0x00EC +#define REG_SYS_CFG1				0x00F0 +#define REG_SYS_CFG2				0x00FC + + +#define REG_CR					0x0100 +#define REG_PBP					0x0104 +#define REG_PKT_BUFF_ACCESS_CTRL		0x0106 +#define REG_TRXDMA_CTRL				0x010C +#define REG_TRXFF_BNDY				0x0114 +#define REG_TRXFF_STATUS			0x0118 +#define REG_RXFF_PTR				0x011C + +#define REG_CPWM				0x012F +#define REG_FWIMR				0x0130 +#define REG_FWISR				0x0134 +#define REG_PKTBUF_DBG_CTRL			0x0140 +#define REG_RXPKTBUF_CTRL			0x0142 +#define REG_PKTBUF_DBG_DATA_L			0x0144 +#define REG_PKTBUF_DBG_DATA_H			0x0148 + +#define REG_TC0_CTRL				0x0150 +#define REG_TC1_CTRL				0x0154 +#define REG_TC2_CTRL				0x0158 +#define REG_TC3_CTRL				0x015C +#define REG_TC4_CTRL				0x0160 +#define REG_TCUNIT_BASE				0x0164 +#define REG_RSVD3				0x0168 +#define REG_C2HEVT_MSG_NORMAL			0x01A0 +#define REG_C2HEVT_CLEAR			0x01AF +#define REG_MCUTST_1				0x01c0 +#define REG_MCUTST_WOWLAN			0x01C7 +#define REG_FMETHR				0x01C8 +#define REG_HMETFR				0x01CC +#define REG_HMEBOX_0				0x01D0 +#define REG_HMEBOX_1				0x01D4 +#define REG_HMEBOX_2				0x01D8 +#define REG_HMEBOX_3				0x01DC + +#define REG_LLT_INIT				0x01E0 + +#define REG_HMEBOX_EXT_0			0x01F0 +#define REG_HMEBOX_EXT_1			0x01F4 +#define REG_HMEBOX_EXT_2			0x01F8 +#define REG_HMEBOX_EXT_3			0x01FC + +/*----------------------------------------------------- + * + *	0x0200h ~ 0x027Fh	TXDMA Configuration + * + *-----------------------------------------------------*/ +#define REG_RQPN				0x0200 +#define REG_FIFOPAGE				0x0204 +#define REG_DWBCN0_CTRL				0x0208 +#define REG_TXDMA_OFFSET_CHK			0x020C +#define REG_TXDMA_STATUS			0x0210 +#define REG_RQPN_NPQ				0x0214 +#define REG_AUTO_LLT				0x0224 +#define REG_DWBCN1_CTRL				0x0228 + +/*----------------------------------------------------- + * + *	0x0280h ~ 0x02FFh	RXDMA Configuration + * + *-----------------------------------------------------*/ +#define REG_RXDMA_AGG_PG_TH			0x0280 +#define REG_FW_UPD_RDPTR			0x0284 +#define REG_RXDMA_CONTROL			0x0286 +#define REG_RXPKT_NUM				0x0287 +#define REG_RXDMA_STATUS			0x0288 +#define REG_RXDMA_PRO				0x0290 +#define REG_EARLY_MODE_CONTROL			0x02BC +#define REG_RSVD5				0x02F0 +#define REG_RSVD6				0x02F4 + +/*----------------------------------------------------- + * + *	0x0300h ~ 0x03FFh	PCIe + * + *-----------------------------------------------------*/ +#define	REG_PCIE_CTRL_REG			0x0300 +#define	REG_INT_MIG				0x0304 +#define	REG_BCNQ_DESA				0x0308 +#define	REG_MGQ_DESA				0x0310 +#define	REG_VOQ_DESA				0x0318 +#define	REG_VIQ_DESA				0x0320 +#define	REG_BEQ_DESA				0x0328 +#define	REG_BKQ_DESA				0x0330 +#define	REG_RX_DESA				0x0338 +#define	REG_HQ0_DESA				0x0340 +#define	REG_HQ1_DESA				0x0348 +#define	REG_HQ2_DESA				0x0350 +#define	REG_HQ3_DESA				0x0358 +#define	REG_HQ4_DESA				0x0360 +#define	REG_HQ5_DESA				0x0368 +#define	REG_HQ6_DESA				0x0370 +#define	REG_HQ7_DESA				0x0378 +#define	REG_MGQ_TXBD_NUM			0x0380 +#define	REG_RX_RXBD_NUM				0x0382 +#define	REG_VOQ_TXBD_NUM			0x0384 +#define	REG_VIQ_TXBD_NUM			0x0386 +#define	REG_BEQ_TXBD_NUM			0x0388 +#define	REG_BKQ_TXBD_NUM			0x038A +#define	REG_HI0Q_TXBD_NUM			0x038C +#define	REG_HI1Q_TXBD_NUM			0x038E +#define	REG_HI2Q_TXBD_NUM			0x0390 +#define	REG_HI3Q_TXBD_NUM			0x0392 +#define	REG_HI4Q_TXBD_NUM			0x0394 +#define	REG_HI5Q_TXBD_NUM			0x0396 +#define	REG_HI6Q_TXBD_NUM			0x0398 +#define	REG_HI7Q_TXBD_NUM			0x039A +#define	REG_TSFTIMER_HCI			0x039C +/*Read Write Point*/ +#define	REG_VOQ_TXBD_IDX			0x03A0 +#define	REG_VIQ_TXBD_IDX			0x03A4 +#define	REG_BEQ_TXBD_IDX			0x03A8 +#define	REG_BKQ_TXBD_IDX			0x03AC +#define	REG_MGQ_TXBD_IDX			0x03B0 +#define	REG_RXQ_TXBD_IDX			0x03B4 + +#define	REG_HI0Q_TXBD_IDX			0x03B8 +#define	REG_HI1Q_TXBD_IDX			0x03BC +#define	REG_HI2Q_TXBD_IDX			0x03C0 +#define	REG_HI3Q_TXBD_IDX			0x03C4 + +#define	REG_HI4Q_TXBD_IDX			0x03C8 +#define	REG_HI5Q_TXBD_IDX			0x03CC +#define	REG_HI6Q_TXBD_IDX			0x03D0 +#define	REG_HI7Q_TXBD_IDX			0x03D4 +#define	REG_PCIE_HCPWM				0x03D8 +#define	REG_PCIE_CTRL2				0x03DB +#define	REG_PCIE_HRPWM				0x03DC +#define	REG_H2C_MSG_DRV2FW_INFO			0x03E0 +#define	REG_PCIE_C2H_MSG_REQUEST		0x03E4 +#define	REG_BACKDOOR_DBI_WDATA			0x03E8 +#define	REG_BACKDOOR_DBI_RDATA			0x03EC +#define	REG_BACKDOOR_DBI_DATA			0x03F0 +#define	REG_MDIO				0x03F4 +#define	REG_MDIO_DATA				0x03F8 + +#define	REG_HDAQ_DESA_NODEF			0x0000 +#define	REG_CMDQ_DESA_NODEF			0x0000 +/* spec version 11 + *----------------------------------------------------- + * + *	0x0400h ~ 0x047Fh	Protocol Configuration + * + *-----------------------------------------------------*/ +#define REG_VOQ_INFORMATION			0x0400 +#define REG_VIQ_INFORMATION			0x0404 +#define REG_BEQ_INFORMATION			0x0408 +#define REG_BKQ_INFORMATION			0x040C +#define REG_MGQ_INFORMATION			0x0410 +#define REG_HGQ_INFORMATION			0x0414 +#define REG_BCNQ_INFORMATION			0x0418 +#define REG_TXPKT_EMPTY				0x041A + + +#define REG_FWHW_TXQ_CTRL			0x0420 +#define REG_HWSEQ_CTRL				0x0423 +#define REG_BCNQ_BDNY				0x0424 +#define REG_MGQ_BDNY				0x0425 +#define REG_LIFECTRL_CTRL			0x0426 +#define REG_MULTI_BCNQ_OFFSET			0x0427 +#define REG_SPEC_SIFS				0x0428 +#define REG_RETRY_LIMIT				0x042A +#define REG_TXBF_CTRL				0x042C +#define REG_DARFRC				0x0430 +#define REG_RARFRC				0x0438 +#define REG_RRSR				0x0440 +#define REG_ARFR0				0x0444 +#define REG_ARFR1				0x044C +#define REG_AMPDU_MAX_TIME			0x0456 +#define REG_BCNQ1_BDNY				0x0457 +#define REG_AGGLEN_LMT				0x0458 +#define REG_AMPDU_MIN_SPACE			0x045C +#define REG_TXPKTBUF_WMAC_LBK_BF_HD		0x045D +#define REG_NDPA_OPT_CTRL			0x045F +#define REG_FAST_EDCA_CTRL			0x0460 +#define REG_RD_RESP_PKT_TH			0x0463 +#define REG_POWER_STAGE1			0x04B4 +#define REG_POWER_STAGE2			0x04B8 +#define REG_AMPDU_BURST_MODE			0x04BC +#define REG_PKT_VO_VI_LIFE_TIME			0x04C0 +#define REG_PKT_BE_BK_LIFE_TIME			0x04C2 +#define REG_STBC_SETTING			0x04C4 +#define REG_PROT_MODE_CTRL			0x04C8 +#define REG_MAX_AGGR_NUM			0x04CA +#define REG_RTS_MAX_AGGR_NUM			0x04CB +#define REG_BAR_MODE_CTRL			0x04CC +#define REG_RA_TRY_RATE_AGG_LMT			0x04CF +#define REG_MACID_PKT_DROP0			0x04D0 + +/*----------------------------------------------------- + * + *	0x0500h ~ 0x05FFh	EDCA Configuration + * + *-----------------------------------------------------*/ +#define REG_EDCA_VO_PARAM			0x0500 +#define REG_EDCA_VI_PARAM			0x0504 +#define REG_EDCA_BE_PARAM			0x0508 +#define REG_EDCA_BK_PARAM			0x050C +#define REG_BCNTCFG				0x0510 +#define REG_PIFS				0x0512 +#define REG_RDG_PIFS				0x0513 +#define REG_SIFS_CTX				0x0514 +#define REG_SIFS_TRX				0x0516 +#define REG_AGGR_BREAK_TIME			0x051A +#define REG_SLOT				0x051B +#define REG_TX_PTCL_CTRL			0x0520 +#define REG_TXPAUSE				0x0522 +#define REG_DIS_TXREQ_CLR			0x0523 +#define REG_RD_CTRL				0x0524 + +#define REG_TBTT_PROHIBIT			0x0540 +#define REG_RD_NAV_NXT				0x0544 +#define REG_NAV_PROT_LEN			0x0546 +#define REG_BCN_CTRL				0x0550 +#define REG_BCN_CTRL_1				0x0551 +#define REG_MBID_NUM				0x0552 +#define REG_DUAL_TSF_RST			0x0553 +#define REG_BCN_INTERVAL			0x0554 +#define REG_DRVERLYINT				0x0558 +#define REG_BCNDMATIM				0x0559 +#define REG_ATIMWND				0x055A +#define REG_BCN_MAX_ERR				0x055D +#define REG_RXTSF_OFFSET_CCK			0x055E +#define REG_RXTSF_OFFSET_OFDM			0x055F +#define REG_TSFTR				0x0560 +#define REG_CTWND				0x0572 +#define REG_PSTIMER				0x0580 +#define REG_TIMER0				0x0584 +#define REG_TIMER1				0x0588 +#define REG_BCN_PREDL_ITV			0x058F +#define REG_ACMHWCTRL				0x05C0 + +/*----------------------------------------------------- + * + *	0x0600h ~ 0x07FFh	WMAC Configuration + * + *-----------------------------------------------------*/ +#define REG_MAC_CR				0x0600 +#define REG_BWOPMODE				0x0603 +#define REG_TCR					0x0604 +#define REG_RCR					0x0608 +#define REG_RX_PKT_LIMIT			0x060C +#define REG_RX_DLK_TIME				0x060D +#define REG_RX_DRVINFO_SZ			0x060F + +#define REG_MACID				0x0610 +#define REG_BSSID				0x0618 +#define REG_MAR					0x0620 +#define REG_MBIDCAMCFG				0x0628 + +#define REG_USTIME_EDCA				0x0638 +#define REG_MAC_SPEC_SIFS			0x063A +#define REG_RESP_SIFS_CCK			0x063C +#define REG_RESP_SIFS_OFDM			0x063E +#define REG_ACKTO				0x0640 +#define REG_CTS2TO				0x0641 +#define REG_EIFS				0x0642 + +#define	REG_NAV_UPPER				0x0652 + +/* Security*/ +#define REG_CAMCMD				0x0670 +#define REG_CAMWRITE				0x0674 +#define REG_CAMREAD				0x0678 +#define REG_CAMDBG				0x067C +#define REG_SECCFG				0x0680 + +/* Power*/ +#define REG_WOW_CTRL				0x0690 +#define REG_PS_RX_INFO				0x0692 +#define REG_UAPSD_TID				0x0693 +#define REG_WKFMCAM_NUM				0x0698 +#define REG_WKFMCAM_RWD				0x069C +#define REG_RXFLTMAP0				0x06A0 +#define REG_RXFLTMAP1				0x06A2 +#define REG_RXFLTMAP2				0x06A4 +#define REG_BCN_PSR_RPT				0x06A8 +#define REG_BT_COEX_TABLE			0x06C0 +#define REG_BFMER0_INFO				0x06E4 +#define REG_BFMER1_INFO				0x06EC +#define REG_CSI_RPT_PARAM_BW20			0x06F4 +#define REG_CSI_RPT_PARAM_BW40			0x06F8 +#define REG_CSI_RPT_PARAM_BW80			0x06FC +/* Hardware Port 2*/ +#define REG_MACID1				0x0700 +#define REG_BSSID1				0x0708 +#define REG_BFMEE_SEL				0x0714 +#define REG_SND_PTCL_CTRL			0x0718 + + +#define	CR9346					REG_9346CR +#define	MSR					(REG_CR + 2) +#define	ISR					REG_HISR +#define	TSFR					REG_TSFTR + +#define	MACIDR0					REG_MACID +#define	MACIDR4					(REG_MACID + 4) + +#define PBP					REG_PBP + +#define	IDR0					MACIDR0 +#define	IDR4					MACIDR4 + +#define	UNUSED_REGISTER				0x1BF +#define	DCAM					UNUSED_REGISTER +#define	PSR					UNUSED_REGISTER +#define BBADDR					UNUSED_REGISTER +#define	PHYDATAR				UNUSED_REGISTER + +#define	INVALID_BBRF_VALUE			0x12345678 + +#define	MAX_MSS_DENSITY_2T			0x13 +#define	MAX_MSS_DENSITY_1T			0x0A + +#define	CMDEEPROM_EN				BIT(5) +#define	CMDEEPROM_SEL				BIT(4) +#define	CMD9346CR_9356SEL			BIT(4) +#define	AUTOLOAD_EEPROM				(CMDEEPROM_EN | CMDEEPROM_SEL) +#define	AUTOLOAD_EFUSE				CMDEEPROM_EN + +#define	GPIOSEL_GPIO				0 +#define	GPIOSEL_ENBT				BIT(5) + +#define	GPIO_IN					REG_GPIO_PIN_CTRL +#define	GPIO_OUT				(REG_GPIO_PIN_CTRL + 1) +#define	GPIO_IO_SEL				(REG_GPIO_PIN_CTRL + 2) +#define	GPIO_MOD				(REG_GPIO_PIN_CTRL + 3) + +#define	MSR_NOLINK				0x00 +#define	MSR_ADHOC				0x01 +#define	MSR_INFRA				0x02 +#define	MSR_AP					0x03 + +#define	RRSR_RSC_OFFSET				21 +#define	RRSR_SHORT_OFFSET			23 +#define	RRSR_RSC_BW_40M				0x600000 +#define	RRSR_RSC_UPSUBCHNL			0x400000 +#define	RRSR_RSC_LOWSUBCHNL			0x200000 +#define	RRSR_SHORT				0x800000 +#define	RRSR_1M					BIT(0) +#define	RRSR_2M					BIT(1) +#define	RRSR_5_5M				BIT(2) +#define	RRSR_11M				BIT(3) +#define	RRSR_6M					BIT(4) +#define	RRSR_9M					BIT(5) +#define	RRSR_12M				BIT(6) +#define	RRSR_18M				BIT(7) +#define	RRSR_24M				BIT(8) +#define	RRSR_36M				BIT(9) +#define	RRSR_48M				BIT(10) +#define	RRSR_54M				BIT(11) +#define	RRSR_MCS0				BIT(12) +#define	RRSR_MCS1				BIT(13) +#define	RRSR_MCS2				BIT(14) +#define	RRSR_MCS3				BIT(15) +#define	RRSR_MCS4				BIT(16) +#define	RRSR_MCS5				BIT(17) +#define	RRSR_MCS6				BIT(18) +#define	RRSR_MCS7				BIT(19) +#define	BRSR_ACKSHORTPMB			BIT(23) + +#define	RATR_1M					0x00000001 +#define	RATR_2M					0x00000002 +#define	RATR_55M				0x00000004 +#define	RATR_11M				0x00000008 +#define	RATR_6M					0x00000010 +#define	RATR_9M					0x00000020 +#define	RATR_12M				0x00000040 +#define	RATR_18M				0x00000080 +#define	RATR_24M				0x00000100 +#define	RATR_36M				0x00000200 +#define	RATR_48M				0x00000400 +#define	RATR_54M				0x00000800 +#define	RATR_MCS0				0x00001000 +#define	RATR_MCS1				0x00002000 +#define	RATR_MCS2				0x00004000 +#define	RATR_MCS3				0x00008000 +#define	RATR_MCS4				0x00010000 +#define	RATR_MCS5				0x00020000 +#define	RATR_MCS6				0x00040000 +#define	RATR_MCS7				0x00080000 +#define	RATR_MCS8				0x00100000 +#define	RATR_MCS9				0x00200000 +#define	RATR_MCS10				0x00400000 +#define	RATR_MCS11				0x00800000 +#define	RATR_MCS12				0x01000000 +#define	RATR_MCS13				0x02000000 +#define	RATR_MCS14				0x04000000 +#define	RATR_MCS15				0x08000000 + +#define RATE_1M					BIT(0) +#define RATE_2M					BIT(1) +#define RATE_5_5M				BIT(2) +#define RATE_11M				BIT(3) +#define RATE_6M					BIT(4) +#define RATE_9M					BIT(5) +#define RATE_12M				BIT(6) +#define RATE_18M				BIT(7) +#define RATE_24M				BIT(8) +#define RATE_36M				BIT(9) +#define RATE_48M				BIT(10) +#define RATE_54M				BIT(11) +#define RATE_MCS0				BIT(12) +#define RATE_MCS1				BIT(13) +#define RATE_MCS2				BIT(14) +#define RATE_MCS3				BIT(15) +#define RATE_MCS4				BIT(16) +#define RATE_MCS5				BIT(17) +#define RATE_MCS6				BIT(18) +#define RATE_MCS7				BIT(19) +#define RATE_MCS8				BIT(20) +#define RATE_MCS9				BIT(21) +#define RATE_MCS10				BIT(22) +#define RATE_MCS11				BIT(23) +#define RATE_MCS12				BIT(24) +#define RATE_MCS13				BIT(25) +#define RATE_MCS14				BIT(26) +#define RATE_MCS15				BIT(27) + +#define	RATE_ALL_CCK		(RATR_1M | RATR_2M | RATR_55M | RATR_11M) +#define	RATE_ALL_OFDM_AG	(RATR_6M | RATR_9M | RATR_12M | RATR_18M |\ +				 RATR_24M | RATR_36M | RATR_48M | RATR_54M) +#define	RATE_ALL_OFDM_1SS	(RATR_MCS0 | RATR_MCS1 | RATR_MCS2 |\ +				 RATR_MCS3 | RATR_MCS4 | RATR_MCS5 |\ +				 RATR_MCS6 | RATR_MCS7) +#define	RATE_ALL_OFDM_2SS	(RATR_MCS8 | RATR_MCS9 | RATR_MCS10 |\ +				 RATR_MCS11 | RATR_MCS12 | RATR_MCS13 |\ +				 RATR_MCS14 | RATR_MCS15) + +#define	BW_OPMODE_20MHZ				BIT(2) +#define	BW_OPMODE_5G				BIT(1) +#define	CAM_VALID				BIT(15) +#define	CAM_NOTVALID				0x0000 +#define	CAM_USEDK				BIT(5) + +#define	CAM_NONE				0x0 +#define	CAM_WEP40				0x01 +#define	CAM_TKIP				0x02 +#define	CAM_AES					0x04 +#define	CAM_WEP104				0x05 + +#define	TOTAL_CAM_ENTRY				32 +#define	HALF_CAM_ENTRY				16 + +#define	CAM_WRITE				BIT(16) +#define	CAM_READ				0x00000000 +#define	CAM_POLLINIG				BIT(31) + +#define	SCR_USEDK				0x01 +#define	SCR_TXSEC_ENABLE			0x02 +#define	SCR_RXSEC_ENABLE			0x04 + + +/********************************************* +*       8192EE IMR/ISR bits +**********************************************/ +#define	IMR_DISABLED				0x0 +/* IMR DW0(0x0060-0063) Bit 0-31 */ +#define	IMR_TIMER2				BIT(31) +#define	IMR_TIMER1				BIT(30) +#define	IMR_PSTIMEOUT				BIT(29) +#define	IMR_GTINT4				BIT(28) +#define	IMR_GTINT3				BIT(27) +#define	IMR_TBDER				BIT(26) +#define	IMR_TBDOK				BIT(25) +#define	IMR_TSF_BIT32_TOGGLE			BIT(24) +#define	IMR_BCNDMAINT0				BIT(20) +#define	IMR_BCNDOK0				BIT(16) +#define	IMR_BCNDMAINT_E				BIT(14) +#define	IMR_ATIMEND				BIT(12) +#define	IMR_HISR1_IND_INT			BIT(11) +#define	IMR_C2HCMD				BIT(10) +#define	IMR_CPWM2				BIT(9) +#define	IMR_CPWM				BIT(8) +#define	IMR_HIGHDOK				BIT(7) +#define	IMR_MGNTDOK				BIT(6) +#define	IMR_BKDOK				BIT(5) +#define	IMR_BEDOK				BIT(4) +#define	IMR_VIDOK				BIT(3) +#define	IMR_VODOK				BIT(2) +#define	IMR_RDU					BIT(1) +#define	IMR_ROK					BIT(0) + +/* IMR DW1(0x00B4-00B7) Bit 0-31 */ +#define	IMR_MCUERR				BIT(28) +#define	IMR_BCNDMAINT7				BIT(27) +#define	IMR_BCNDMAINT6				BIT(26) +#define	IMR_BCNDMAINT5				BIT(25) +#define	IMR_BCNDMAINT4				BIT(24) +#define	IMR_BCNDMAINT3				BIT(23) +#define	IMR_BCNDMAINT2				BIT(22) +#define	IMR_BCNDMAINT1				BIT(21) +#define	IMR_BCNDOK7				BIT(20) +#define	IMR_BCNDOK6				BIT(19) +#define	IMR_BCNDOK5				BIT(18) +#define	IMR_BCNDOK4				BIT(17) +#define	IMR_BCNDOK3				BIT(16) +#define	IMR_BCNDOK2				BIT(15) +#define	IMR_BCNDOK1				BIT(14) +#define	IMR_ATIMEND_E				BIT(13) +#define	IMR_TXERR				BIT(11) +#define	IMR_RXERR				BIT(10) +#define	IMR_TXFOVW				BIT(9) +#define	IMR_RXFOVW				BIT(8) + + +#define	HWSET_MAX_SIZE				512 +#define EFUSE_MAX_SECTION			64 +#define EFUSE_REAL_CONTENT_LEN			256 +#define EFUSE_OOB_PROTECT_BYTES			18 + + +#define	EEPROM_DEFAULT_TSSI			0x0 +#define EEPROM_DEFAULT_TXPOWERDIFF		0x0 +#define EEPROM_DEFAULT_CRYSTALCAP		0x5 +#define EEPROM_DEFAULT_BOARDTYPE		0x02 +#define EEPROM_DEFAULT_TXPOWER			0x1010 +#define	EEPROM_DEFAULT_HT2T_TXPWR		0x10 + +#define	EEPROM_DEFAULT_LEGACYHTTXPOWERDIFF	0x3 +#define	EEPROM_DEFAULT_THERMALMETER		0x1A +#define	EEPROM_DEFAULT_ANTTXPOWERDIFF		0x0 +#define	EEPROM_DEFAULT_TXPWDIFF_CRYSTALCAP	0x5 +#define	EEPROM_DEFAULT_TXPOWERLEVEL		0x22 +#define	EEPROM_DEFAULT_HT40_2SDIFF		0x0 +#define EEPROM_DEFAULT_HT20_DIFF		2 +#define	EEPROM_DEFAULT_LEGACYHTTXPOWERDIFF	0x3 +#define EEPROM_DEFAULT_HT40_PWRMAXOFFSET	0 +#define EEPROM_DEFAULT_HT20_PWRMAXOFFSET	0 + +#define RF_OPTION1				0x79 +#define RF_OPTION2				0x7A +#define RF_OPTION3				0x7B +#define RF_OPTION4				0x7C + +#define EEPROM_DEFAULT_PID			0x1234 +#define EEPROM_DEFAULT_VID			0x5678 +#define EEPROM_DEFAULT_CUSTOMERID		0xAB +#define EEPROM_DEFAULT_SUBCUSTOMERID		0xCD +#define EEPROM_DEFAULT_VERSION			0 + +#define	EEPROM_CHANNEL_PLAN_FCC			0x0 +#define	EEPROM_CHANNEL_PLAN_IC			0x1 +#define	EEPROM_CHANNEL_PLAN_ETSI		0x2 +#define	EEPROM_CHANNEL_PLAN_SPAIN		0x3 +#define	EEPROM_CHANNEL_PLAN_FRANCE		0x4 +#define	EEPROM_CHANNEL_PLAN_MKK			0x5 +#define	EEPROM_CHANNEL_PLAN_MKK1		0x6 +#define	EEPROM_CHANNEL_PLAN_ISRAEL		0x7 +#define	EEPROM_CHANNEL_PLAN_TELEC		0x8 +#define	EEPROM_CHANNEL_PLAN_GLOBAL_DOMAIN	0x9 +#define	EEPROM_CHANNEL_PLAN_WORLD_WIDE_13	0xA +#define	EEPROM_CHANNEL_PLAN_NCC			0xB +#define	EEPROM_CHANNEL_PLAN_BY_HW_MASK		0x80 + +#define EEPROM_CID_DEFAULT			0x0 +#define EEPROM_CID_TOSHIBA			0x4 +#define	EEPROM_CID_CCX				0x10 +#define	EEPROM_CID_QMI				0x0D +#define EEPROM_CID_WHQL				0xFE + +#define	RTL8192E_EEPROM_ID			0x8129 + +#define EEPROM_HPON				0x02 +#define EEPROM_CLK				0x06 +#define EEPROM_TESTR				0x08 + + +#define EEPROM_TXPOWERCCK			0x10 +#define	EEPROM_TXPOWERHT40_1S			0x16 +#define EEPROM_TXPOWERHT20DIFF			0x1B +#define EEPROM_TXPOWER_OFDMDIFF			0x1B + + + +#define	EEPROM_TX_PWR_INX			0x10 + +#define	EEPROM_CHANNELPLAN			0xB8 +#define	EEPROM_XTAL_92E				0xB9 +#define	EEPROM_THERMAL_METER_92E		0xBA +#define	EEPROM_IQK_LCK_92E			0xBB + +#define	EEPROM_RF_BOARD_OPTION_92E		0xC1 +#define	EEPROM_RF_FEATURE_OPTION_92E		0xC2 +#define	EEPROM_RF_BT_SETTING_92E		0xC3 +#define	EEPROM_VERSION				0xC4 +#define	EEPROM_CUSTOMER_ID			0xC5 +#define	EEPROM_RF_ANTENNA_OPT_92E		0xC9 + +#define	EEPROM_MAC_ADDR				0xD0 +#define EEPROM_VID				0xD6 +#define EEPROM_DID				0xD8 +#define EEPROM_SVID				0xDA +#define EEPROM_SMID				0xDC + +#define	STOPBECON				BIT(6) +#define	STOPHIGHT				BIT(5) +#define	STOPMGT					BIT(4) +#define	STOPVO					BIT(3) +#define	STOPVI					BIT(2) +#define	STOPBE					BIT(1) +#define	STOPBK					BIT(0) + +#define	RCR_APPFCS				BIT(31) +#define	RCR_APP_MIC				BIT(30) +#define	RCR_APP_ICV				BIT(29) +#define	RCR_APP_PHYST_RXFF			BIT(28) +#define	RCR_APP_BA_SSN				BIT(27) +#define	RCR_ENMBID				BIT(24) +#define	RCR_LSIGEN				BIT(23) +#define	RCR_MFBEN				BIT(22) +#define	RCR_HTC_LOC_CTRL			BIT(14) +#define	RCR_AMF					BIT(13) +#define	RCR_ACF					BIT(12) +#define	RCR_ADF					BIT(11) +#define	RCR_AICV				BIT(9) +#define	RCR_ACRC32				BIT(8) +#define	RCR_CBSSID_BCN				BIT(7) +#define	RCR_CBSSID_DATA				BIT(6) +#define	RCR_CBSSID				RCR_CBSSID_DATA +#define	RCR_APWRMGT				BIT(5) +#define	RCR_ADD3				BIT(4) +#define	RCR_AB					BIT(3) +#define	RCR_AM					BIT(2) +#define	RCR_APM					BIT(1) +#define	RCR_AAP					BIT(0) +#define	RCR_MXDMA_OFFSET			8 +#define	RCR_FIFO_OFFSET				13 + +#define RSV_CTRL				0x001C +#define RD_CTRL					0x0524 + +#define REG_USB_INFO				0xFE17 +#define REG_USB_SPECIAL_OPTION			0xFE55 +#define REG_USB_DMA_AGG_TO			0xFE5B +#define REG_USB_AGG_TO				0xFE5C +#define REG_USB_AGG_TH				0xFE5D + +#define REG_USB_VID				0xFE60 +#define REG_USB_PID				0xFE62 +#define REG_USB_OPTIONAL			0xFE64 +#define REG_USB_CHIRP_K				0xFE65 +#define REG_USB_PHY				0xFE66 +#define REG_USB_MAC_ADDR			0xFE70 +#define REG_USB_HRPWM				0xFE58 +#define REG_USB_HCPWM				0xFE57 + +#define SW18_FPWM				BIT(3) + +#define ISO_MD2PP				BIT(0) +#define ISO_UA2USB				BIT(1) +#define ISO_UD2CORE				BIT(2) +#define ISO_PA2PCIE				BIT(3) +#define ISO_PD2CORE				BIT(4) +#define ISO_IP2MAC				BIT(5) +#define ISO_DIOP				BIT(6) +#define ISO_DIOE				BIT(7) +#define ISO_EB2CORE				BIT(8) +#define ISO_DIOR				BIT(9) + +#define PWC_EV25V				BIT(14) +#define PWC_EV12V				BIT(15) + +#define FEN_BBRSTB				BIT(0) +#define FEN_BB_GLB_RSTn				BIT(1) +#define FEN_USBA				BIT(2) +#define FEN_UPLL				BIT(3) +#define FEN_USBD				BIT(4) +#define FEN_DIO_PCIE				BIT(5) +#define FEN_PCIEA				BIT(6) +#define FEN_PPLL				BIT(7) +#define FEN_PCIED				BIT(8) +#define FEN_DIOE				BIT(9) +#define FEN_CPUEN				BIT(10) +#define FEN_DCORE				BIT(11) +#define FEN_ELDR				BIT(12) +#define FEN_DIO_RF				BIT(13) +#define FEN_HWPDN				BIT(14) +#define FEN_MREGEN				BIT(15) + +#define PFM_LDALL				BIT(0) +#define PFM_ALDN				BIT(1) +#define PFM_LDKP				BIT(2) +#define PFM_WOWL				BIT(3) +#define EnPDN					BIT(4) +#define PDN_PL					BIT(5) +#define APFM_ONMAC				BIT(8) +#define APFM_OFF				BIT(9) +#define APFM_RSM				BIT(10) +#define AFSM_HSUS				BIT(11) +#define AFSM_PCIE				BIT(12) +#define APDM_MAC				BIT(13) +#define APDM_HOST				BIT(14) +#define APDM_HPDN				BIT(15) +#define RDY_MACON				BIT(16) +#define SUS_HOST				BIT(17) +#define ROP_ALD					BIT(20) +#define ROP_PWR					BIT(21) +#define ROP_SPS					BIT(22) +#define SOP_MRST				BIT(25) +#define SOP_FUSE				BIT(26) +#define SOP_ABG					BIT(27) +#define SOP_AMB					BIT(28) +#define SOP_RCK					BIT(29) +#define SOP_A8M					BIT(30) +#define XOP_BTCK				BIT(31) + +#define ANAD16V_EN				BIT(0) +#define ANA8M					BIT(1) +#define MACSLP					BIT(4) +#define LOADER_CLK_EN				BIT(5) +#define _80M_SSC_DIS				BIT(7) +#define _80M_SSC_EN_HO				BIT(8) +#define PHY_SSC_RSTB				BIT(9) +#define SEC_CLK_EN				BIT(10) +#define MAC_CLK_EN				BIT(11) +#define SYS_CLK_EN				BIT(12) +#define RING_CLK_EN				BIT(13) + +#define	BOOT_FROM_EEPROM			BIT(4) +#define	EEPROM_EN				BIT(5) + +#define AFE_BGEN				BIT(0) +#define AFE_MBEN				BIT(1) +#define MAC_ID_EN				BIT(7) + +#define WLOCK_ALL				BIT(0) +#define WLOCK_00				BIT(1) +#define WLOCK_04				BIT(2) +#define WLOCK_08				BIT(3) +#define WLOCK_40				BIT(4) +#define R_DIS_PRST_0				BIT(5) +#define R_DIS_PRST_1				BIT(6) +#define LOCK_ALL_EN				BIT(7) + +#define RF_EN					BIT(0) +#define RF_RSTB					BIT(1) +#define RF_SDMRSTB				BIT(2) + +#define LDA15_EN				BIT(0) +#define LDA15_STBY				BIT(1) +#define LDA15_OBUF				BIT(2) +#define LDA15_REG_VOS				BIT(3) +#define _LDA15_VOADJ(x)				(((x) & 0x7) << 4) + +#define LDV12_EN				BIT(0) +#define LDV12_SDBY				BIT(1) +#define LPLDO_HSM				BIT(2) +#define LPLDO_LSM_DIS				BIT(3) +#define _LDV12_VADJ(x)				(((x) & 0xF) << 4) + +#define XTAL_EN					BIT(0) +#define XTAL_BSEL				BIT(1) +#define _XTAL_BOSC(x)				(((x) & 0x3) << 2) +#define _XTAL_CADJ(x)				(((x) & 0xF) << 4) +#define XTAL_GATE_USB				BIT(8) +#define _XTAL_USB_DRV(x)			(((x) & 0x3) << 9) +#define XTAL_GATE_AFE				BIT(11) +#define _XTAL_AFE_DRV(x)			(((x) & 0x3) << 12) +#define XTAL_RF_GATE				BIT(14) +#define _XTAL_RF_DRV(x)				(((x) & 0x3) << 15) +#define XTAL_GATE_DIG				BIT(17) +#define _XTAL_DIG_DRV(x)			(((x) & 0x3) << 18) +#define XTAL_BT_GATE				BIT(20) +#define _XTAL_BT_DRV(x)				(((x) & 0x3) << 21) +#define _XTAL_GPIO(x)				(((x) & 0x7) << 23) + +#define CKDLY_AFE				BIT(26) +#define CKDLY_USB				BIT(27) +#define CKDLY_DIG				BIT(28) +#define CKDLY_BT				BIT(29) + +#define APLL_EN					BIT(0) +#define APLL_320_EN				BIT(1) +#define APLL_FREF_SEL				BIT(2) +#define APLL_EDGE_SEL				BIT(3) +#define APLL_WDOGB				BIT(4) +#define APLL_LPFEN				BIT(5) + +#define APLL_REF_CLK_13MHZ			0x1 +#define APLL_REF_CLK_19_2MHZ			0x2 +#define APLL_REF_CLK_20MHZ			0x3 +#define APLL_REF_CLK_25MHZ			0x4 +#define APLL_REF_CLK_26MHZ			0x5 +#define APLL_REF_CLK_38_4MHZ			0x6 +#define APLL_REF_CLK_40MHZ			0x7 + +#define APLL_320EN				BIT(14) +#define APLL_80EN				BIT(15) +#define APLL_1MEN				BIT(24) + +#define ALD_EN					BIT(18) +#define EF_PD					BIT(19) +#define EF_FLAG					BIT(31) + +#define EF_TRPT					BIT(7) +#define LDOE25_EN				BIT(31) + +#define RSM_EN					BIT(0) +#define Timer_EN				BIT(4) + +#define TRSW0EN					BIT(2) +#define TRSW1EN					BIT(3) +#define EROM_EN					BIT(4) +#define EnBT					BIT(5) +#define EnUart					BIT(8) +#define Uart_910				BIT(9) +#define EnPMAC					BIT(10) +#define SIC_SWRST				BIT(11) +#define EnSIC					BIT(12) +#define SIC_23					BIT(13) +#define EnHDP					BIT(14) +#define SIC_LBK					BIT(15) + +#define LED0PL					BIT(4) +#define LED1PL					BIT(12) +#define LED0DIS					BIT(7) + +#define MCUFWDL_EN				BIT(0) +#define MCUFWDL_RDY				BIT(1) +#define FWDL_ChkSum_rpt				BIT(2) +#define MACINI_RDY				BIT(3) +#define BBINI_RDY				BIT(4) +#define RFINI_RDY				BIT(5) +#define WINTINI_RDY				BIT(6) +#define CPRST					BIT(23) + +#define XCLK_VLD				BIT(0) +#define ACLK_VLD				BIT(1) +#define UCLK_VLD				BIT(2) +#define PCLK_VLD				BIT(3) +#define PCIRSTB					BIT(4) +#define V15_VLD					BIT(5) +#define TRP_B15V_EN				BIT(7) +#define SIC_IDLE				BIT(8) +#define BD_MAC2					BIT(9) +#define BD_MAC1					BIT(10) +#define IC_MACPHY_MODE				BIT(11) +#define VENDOR_ID				BIT(19) +#define PAD_HWPD_IDN				BIT(22) +#define TRP_VAUX_EN				BIT(23) +#define TRP_BT_EN				BIT(24) +#define BD_PKG_SEL				BIT(25) +#define BD_HCI_SEL				BIT(26) +#define TYPE_ID					BIT(27) + +#define CHIP_VER_RTL_MASK			0xF000 +#define CHIP_VER_RTL_SHIFT			12 + +#define REG_LBMODE				(REG_CR + 3) + +#define HCI_TXDMA_EN				BIT(0) +#define HCI_RXDMA_EN				BIT(1) +#define TXDMA_EN				BIT(2) +#define RXDMA_EN				BIT(3) +#define PROTOCOL_EN				BIT(4) +#define SCHEDULE_EN				BIT(5) +#define MACTXEN					BIT(6) +#define MACRXEN					BIT(7) +#define ENSWBCN					BIT(8) +#define ENSEC					BIT(9) + +#define _NETTYPE(x)				(((x) & 0x3) << 16) +#define MASK_NETTYPE				0x30000 +#define NT_NO_LINK				0x0 +#define NT_LINK_AD_HOC				0x1 +#define NT_LINK_AP				0x2 +#define NT_AS_AP				0x3 + +#define _LBMODE(x)				(((x) & 0xF) << 24) +#define MASK_LBMODE				0xF000000 +#define LOOPBACK_NORMAL				0x0 +#define LOOPBACK_IMMEDIATELY			0xB +#define LOOPBACK_MAC_DELAY			0x3 +#define LOOPBACK_PHY				0x1 +#define LOOPBACK_DMA				0x7 + +#define GET_RX_PAGE_SIZE(value)			((value) & 0xF) +#define GET_TX_PAGE_SIZE(value)			(((value) & 0xF0) >> 4) +#define _PSRX_MASK				0xF +#define _PSTX_MASK				0xF0 +#define _PSRX(x)				(x) +#define _PSTX(x)				((x) << 4) + +#define PBP_64					0x0 +#define PBP_128					0x1 +#define PBP_256					0x2 +#define PBP_512					0x3 +#define PBP_1024				0x4 + +#define RXDMA_ARBBW_EN				BIT(0) +#define RXSHFT_EN				BIT(1) +#define RXDMA_AGG_EN				BIT(2) +#define QS_VO_QUEUE				BIT(8) +#define QS_VI_QUEUE				BIT(9) +#define QS_BE_QUEUE				BIT(10) +#define QS_BK_QUEUE				BIT(11) +#define QS_MANAGER_QUEUE			BIT(12) +#define QS_HIGH_QUEUE				BIT(13) + +#define HQSEL_VOQ				BIT(0) +#define HQSEL_VIQ				BIT(1) +#define HQSEL_BEQ				BIT(2) +#define HQSEL_BKQ				BIT(3) +#define HQSEL_MGTQ				BIT(4) +#define HQSEL_HIQ				BIT(5) + +#define _TXDMA_HIQ_MAP(x)			(((x)&0x3) << 14) +#define _TXDMA_MGQ_MAP(x)			(((x)&0x3) << 12) +#define _TXDMA_BKQ_MAP(x)			(((x)&0x3) << 10) +#define _TXDMA_BEQ_MAP(x)			(((x)&0x3) << 8) +#define _TXDMA_VIQ_MAP(x)			(((x)&0x3) << 6) +#define _TXDMA_VOQ_MAP(x)			(((x)&0x3) << 4) + +#define QUEUE_LOW				1 +#define QUEUE_NORMAL				2 +#define QUEUE_HIGH				3 + +#define _LLT_NO_ACTIVE				0x0 +#define _LLT_WRITE_ACCESS			0x1 +#define _LLT_READ_ACCESS			0x2 + +#define _LLT_INIT_DATA(x)			((x) & 0xFF) +#define _LLT_INIT_ADDR(x)			(((x) & 0xFF) << 8) +#define _LLT_OP(x)					(((x) & 0x3) << 30) +#define _LLT_OP_VALUE(x)			(((x) >> 30) & 0x3) + +#define BB_WRITE_READ_MASK			(BIT(31) | BIT(30)) +#define BB_WRITE_EN				BIT(30) +#define BB_READ_EN				BIT(31) + +#define _HPQ(x)					((x) & 0xFF) +#define _LPQ(x)					(((x) & 0xFF) << 8) +#define _PUBQ(x)				(((x) & 0xFF) << 16) +#define _NPQ(x)					((x) & 0xFF) + +#define HPQ_PUBLIC_DIS				BIT(24) +#define LPQ_PUBLIC_DIS				BIT(25) +#define LD_RQPN					BIT(31) + +#define BCN_VALID				BIT(16) +#define BCN_HEAD(x)				(((x) & 0xFF) << 8) +#define	BCN_HEAD_MASK				0xFF00 + +#define BLK_DESC_NUM_SHIFT			4 +#define BLK_DESC_NUM_MASK			0xF + +#define DROP_DATA_EN				BIT(9) + +#define EN_AMPDU_RTY_NEW			BIT(7) + +#define _INIRTSMCS_SEL(x)			((x) & 0x3F) + +#define _SPEC_SIFS_CCK(x)			((x) & 0xFF) +#define _SPEC_SIFS_OFDM(x)			(((x) & 0xFF) << 8) + +#define RATE_REG_BITMAP_ALL			0xFFFFF + +#define _RRSC_BITMAP(x)				((x) & 0xFFFFF) + +#define _RRSR_RSC(x)				(((x) & 0x3) << 21) +#define RRSR_RSC_RESERVED			0x0 +#define RRSR_RSC_UPPER_SUBCHANNEL		0x1 +#define RRSR_RSC_LOWER_SUBCHANNEL		0x2 +#define RRSR_RSC_DUPLICATE_MODE			0x3 + +#define USE_SHORT_G1				BIT(20) + +#define _AGGLMT_MCS0(x)				((x) & 0xF) +#define _AGGLMT_MCS1(x)				(((x) & 0xF) << 4) +#define _AGGLMT_MCS2(x)				(((x) & 0xF) << 8) +#define _AGGLMT_MCS3(x)				(((x) & 0xF) << 12) +#define _AGGLMT_MCS4(x)				(((x) & 0xF) << 16) +#define _AGGLMT_MCS5(x)				(((x) & 0xF) << 20) +#define _AGGLMT_MCS6(x)				(((x) & 0xF) << 24) +#define _AGGLMT_MCS7(x)				(((x) & 0xF) << 28) + +#define	RETRY_LIMIT_SHORT_SHIFT			8 +#define	RETRY_LIMIT_LONG_SHIFT			0 + +#define _DARF_RC1(x)				((x) & 0x1F) +#define _DARF_RC2(x)				(((x) & 0x1F) << 8) +#define _DARF_RC3(x)				(((x) & 0x1F) << 16) +#define _DARF_RC4(x)				(((x) & 0x1F) << 24) +#define _DARF_RC5(x)				((x) & 0x1F) +#define _DARF_RC6(x)				(((x) & 0x1F) << 8) +#define _DARF_RC7(x)				(((x) & 0x1F) << 16) +#define _DARF_RC8(x)				(((x) & 0x1F) << 24) + +#define _RARF_RC1(x)				((x) & 0x1F) +#define _RARF_RC2(x)				(((x) & 0x1F) << 8) +#define _RARF_RC3(x)				(((x) & 0x1F) << 16) +#define _RARF_RC4(x)				(((x) & 0x1F) << 24) +#define _RARF_RC5(x)				((x) & 0x1F) +#define _RARF_RC6(x)				(((x) & 0x1F) << 8) +#define _RARF_RC7(x)				(((x) & 0x1F) << 16) +#define _RARF_RC8(x)				(((x) & 0x1F) << 24) + +#define AC_PARAM_TXOP_LIMIT_OFFSET		16 +#define AC_PARAM_ECW_MAX_OFFSET			12 +#define AC_PARAM_ECW_MIN_OFFSET			8 +#define AC_PARAM_AIFS_OFFSET			0 + +#define _AIFS(x)				(x) +#define _ECW_MAX_MIN(x)				((x) << 8) +#define _TXOP_LIMIT(x)				((x) << 16) + +#define _BCNIFS(x)				((x) & 0xFF) +#define _BCNECW(x)				((((x) & 0xF)) << 8) + +#define _LRL(x)					((x) & 0x3F) +#define _SRL(x)					(((x) & 0x3F) << 8) + +#define _SIFS_CCK_CTX(x)			((x) & 0xFF) +#define _SIFS_CCK_TRX(x)			(((x) & 0xFF) << 8); + +#define _SIFS_OFDM_CTX(x)			((x) & 0xFF) +#define _SIFS_OFDM_TRX(x)			(((x) & 0xFF) << 8); + +#define _TBTT_PROHIBIT_HOLD(x)			(((x) & 0xFF) << 8) + +#define DIS_EDCA_CNT_DWN			BIT(11) + +#define EN_MBSSID				BIT(1) +#define EN_TXBCN_RPT				BIT(2) +#define	EN_BCN_FUNCTION				BIT(3) + +#define TSFTR_RST				BIT(0) +#define TSFTR1_RST				BIT(1) + +#define STOP_BCNQ				BIT(6) + +#define	DIS_TSF_UDT0_NORMAL_CHIP		BIT(4) +#define	DIS_TSF_UDT0_TEST_CHIP			BIT(5) + +#define	AcmHw_HwEn				BIT(0) +#define	AcmHw_BeqEn				BIT(1) +#define	AcmHw_ViqEn				BIT(2) +#define	AcmHw_VoqEn				BIT(3) +#define	AcmHw_BeqStatus				BIT(4) +#define	AcmHw_ViqStatus				BIT(5) +#define	AcmHw_VoqStatus				BIT(6) + +#define APSDOFF					BIT(6) +#define APSDOFF_STATUS				BIT(7) + +#define BW_20MHZ				BIT(2) + +#define RATE_BITMAP_ALL				0xFFFFF + +#define RATE_RRSR_CCK_ONLY_1M			0xFFFF1 + +#define TSFRST					BIT(0) +#define DIS_GCLK				BIT(1) +#define PAD_SEL					BIT(2) +#define PWR_ST					BIT(6) +#define PWRBIT_OW_EN				BIT(7) +#define ACRC					BIT(8) +#define CFENDFORM				BIT(9) +#define ICV					BIT(10) + +#define AAP					BIT(0) +#define APM					BIT(1) +#define AM					BIT(2) +#define AB					BIT(3) +#define ADD3					BIT(4) +#define APWRMGT					BIT(5) +#define CBSSID					BIT(6) +#define CBSSID_DATA				BIT(6) +#define CBSSID_BCN				BIT(7) +#define ACRC32					BIT(8) +#define AICV					BIT(9) +#define ADF					BIT(11) +#define ACF					BIT(12) +#define AMF					BIT(13) +#define HTC_LOC_CTRL				BIT(14) +#define UC_DATA_EN				BIT(16) +#define BM_DATA_EN				BIT(17) +#define MFBEN					BIT(22) +#define LSIGEN					BIT(23) +#define EnMBID					BIT(24) +#define APP_BASSN				BIT(27) +#define APP_PHYSTS				BIT(28) +#define APP_ICV					BIT(29) +#define APP_MIC					BIT(30) +#define APP_FCS					BIT(31) + +#define _MIN_SPACE(x)				((x) & 0x7) +#define _SHORT_GI_PADDING(x)			(((x) & 0x1F) << 3) + +#define RXERR_TYPE_OFDM_PPDU			0 +#define RXERR_TYPE_OFDM_FALSE_ALARM		1 +#define	RXERR_TYPE_OFDM_MPDU_OK			2 +#define RXERR_TYPE_OFDM_MPDU_FAIL		3 +#define RXERR_TYPE_CCK_PPDU			4 +#define RXERR_TYPE_CCK_FALSE_ALARM		5 +#define RXERR_TYPE_CCK_MPDU_OK			6 +#define RXERR_TYPE_CCK_MPDU_FAIL		7 +#define RXERR_TYPE_HT_PPDU			8 +#define RXERR_TYPE_HT_FALSE_ALARM		9 +#define RXERR_TYPE_HT_MPDU_TOTAL		10 +#define RXERR_TYPE_HT_MPDU_OK			11 +#define RXERR_TYPE_HT_MPDU_FAIL			12 +#define RXERR_TYPE_RX_FULL_DROP			15 + +#define RXERR_COUNTER_MASK			0xFFFFF +#define RXERR_RPT_RST				BIT(27) +#define _RXERR_RPT_SEL(type)			((type) << 28) + +#define	SCR_TxUseDK				BIT(0) +#define	SCR_RxUseDK				BIT(1) +#define	SCR_TxEncEnable				BIT(2) +#define	SCR_RxDecEnable				BIT(3) +#define	SCR_SKByA2				BIT(4) +#define	SCR_NoSKMC				BIT(5) +#define SCR_TXBCUSEDK				BIT(6) +#define SCR_RXBCUSEDK				BIT(7) + +#define USB_IS_HIGH_SPEED			0 +#define USB_IS_FULL_SPEED			1 +#define USB_SPEED_MASK				BIT(5) + +#define USB_NORMAL_SIE_EP_MASK			0xF +#define USB_NORMAL_SIE_EP_SHIFT			4 + +#define USB_TEST_EP_MASK			0x30 +#define USB_TEST_EP_SHIFT			4 + +#define USB_AGG_EN				BIT(3) + +#define MAC_ADDR_LEN				6 +#define LAST_ENTRY_OF_TX_PKT_BUFFER		175 + +#define POLLING_LLT_THRESHOLD			20 +#define POLLING_READY_TIMEOUT_COUNT		3000 + +#define	MAX_MSS_DENSITY_2T			0x13 +#define	MAX_MSS_DENSITY_1T			0x0A + +#define EPROM_CMD_OPERATING_MODE_MASK		((1 << 7) | (1 << 6)) +#define EPROM_CMD_CONFIG			0x3 +#define EPROM_CMD_LOAD				1 + +#define	HWSET_MAX_SIZE_92S			HWSET_MAX_SIZE + +#define	HAL_8192C_HW_GPIO_WPS_BIT		BIT(2) + +#define	RPMAC_RESET				0x100 +#define	RPMAC_TXSTART				0x104 +#define	RPMAC_TXLEGACYSIG			0x108 +#define	RPMAC_TXHTSIG1				0x10c +#define	RPMAC_TXHTSIG2				0x110 +#define	RPMAC_PHYDEBUG				0x114 +#define	RPMAC_TXPACKETNUM			0x118 +#define	RPMAC_TXIDLE				0x11c +#define	RPMAC_TXMACHEADER0			0x120 +#define	RPMAC_TXMACHEADER1			0x124 +#define	RPMAC_TXMACHEADER2			0x128 +#define	RPMAC_TXMACHEADER3			0x12c +#define	RPMAC_TXMACHEADER4			0x130 +#define	RPMAC_TXMACHEADER5			0x134 +#define	RPMAC_TXDADATYPE			0x138 +#define	RPMAC_TXRANDOMSEED			0x13c +#define	RPMAC_CCKPLCPPREAMBLE			0x140 +#define	RPMAC_CCKPLCPHEADER			0x144 +#define	RPMAC_CCKCRC16				0x148 +#define	RPMAC_OFDMRXCRC32OK			0x170 +#define	RPMAC_OFDMRXCRC32Er			0x174 +#define	RPMAC_OFDMRXPARITYER			0x178 +#define	RPMAC_OFDMRXCRC8ER			0x17c +#define	RPMAC_CCKCRXRC16ER			0x180 +#define	RPMAC_CCKCRXRC32ER			0x184 +#define	RPMAC_CCKCRXRC32OK			0x188 +#define	RPMAC_TXSTATUS				0x18c + +#define	RFPGA0_RFMOD				0x800 + +#define	RFPGA0_TXINFO				0x804 +#define	RFPGA0_PSDFUNCTION			0x808 + +#define	RFPGA0_TXGAINSTAGE			0x80c + +#define	RFPGA0_RFTIMING1			0x810 +#define	RFPGA0_RFTIMING2			0x814 + +#define	RFPGA0_XA_HSSIPARAMETER1		0x820 +#define	RFPGA0_XA_HSSIPARAMETER2		0x824 +#define	RFPGA0_XB_HSSIPARAMETER1		0x828 +#define	RFPGA0_XB_HSSIPARAMETER2		0x82c + +#define	RFPGA0_XA_LSSIPARAMETER			0x840 +#define	RFPGA0_XB_LSSIPARAMETER			0x844 + +#define	RFPGA0_RFWAKEUPPARAMETER		0x850 +#define	RFPGA0_RFSLEEPUPPARAMETER		0x854 + +#define	RFPGA0_XAB_SWITCHCONTROL		0x858 +#define	RFPGA0_XCD_SWITCHCONTROL		0x85c + +#define	RFPGA0_XA_RFINTERFACEOE			0x860 +#define	RFPGA0_XB_RFINTERFACEOE			0x864 + +#define	RFPGA0_XAB_RFINTERFACESW		0x870 +#define	RFPGA0_XCD_RFINTERFACESW		0x874 + +#define	rFPGA0_XAB_RFPARAMETER			0x878 +#define	rFPGA0_XCD_RFPARAMETER			0x87c + +#define	RFPGA0_ANALOGPARAMETER1			0x880 +#define	RFPGA0_ANALOGPARAMETER2			0x884 +#define	RFPGA0_ANALOGPARAMETER3			0x888 +#define	RFPGA0_ANALOGPARAMETER4			0x88c + +#define	RFPGA0_XA_LSSIREADBACK			0x8a0 +#define	RFPGA0_XB_LSSIREADBACK			0x8a4 +#define	RFPGA0_XC_LSSIREADBACK			0x8a8 +#define	RFPGA0_XD_LSSIREADBACK			0x8ac + +#define	RFPGA0_PSDREPORT			0x8b4 +#define	TRANSCEIVEA_HSPI_READBACK		0x8b8 +#define	TRANSCEIVEB_HSPI_READBACK		0x8bc +#define	REG_SC_CNT				0x8c4 +#define	RFPGA0_XAB_RFINTERFACERB		0x8e0 +#define	RFPGA0_XCD_RFINTERFACERB		0x8e4 + +#define	RFPGA1_RFMOD				0x900 + +#define	RFPGA1_TXBLOCK				0x904 +#define	RFPGA1_DEBUGSELECT			0x908 +#define	RFPGA1_TXINFO				0x90c + +#define	RCCK0_SYSTEM				0xa00 + +#define	RCCK0_AFESETTING			0xa04 +#define	RCCK0_CCA				0xa08 + +#define	RCCK0_RXAGC1				0xa0c +#define	RCCK0_RXAGC2				0xa10 + +#define	RCCK0_RXHP				0xa14 + +#define	RCCK0_DSPPARAMETER1			0xa18 +#define	RCCK0_DSPPARAMETER2			0xa1c + +#define	RCCK0_TXFILTER1				0xa20 +#define	RCCK0_TXFILTER2				0xa24 +#define	RCCK0_DEBUGPORT				0xa28 +#define	RCCK0_FALSEALARMREPORT			0xa2c +#define	RCCK0_TRSSIREPORT			0xa50 +#define	RCCK0_RXREPORT				0xa54 +#define	RCCK0_FACOUNTERLOWER			0xa5c +#define	RCCK0_FACOUNTERUPPER			0xa58 +#define	RCCK0_CCA_CNT				0xa60 + + +/* PageB(0xB00) */ +#define	rPdp_AntA				0xb00 +#define	rPdp_AntA_4				0xb04 +#define	rPdp_AntA_8				0xb08 +#define	rPdp_AntA_C				0xb0c +#define	rPdp_AntA_10				0xb10 +#define	rPdp_AntA_14				0xb14 +#define	rPdp_AntA_18				0xb18 +#define	rPdp_AntA_1C				0xb1c +#define	rPdp_AntA_20				0xb20 +#define	rPdp_AntA_24				0xb24 + +#define	rConfig_Pmpd_AntA			0xb28 +#define	rConfig_ram64x16			0xb2c + +#define	rBndA					0xb30 +#define	rHssiPar				0xb34 + +#define	rConfig_AntA				0xb68 +#define	rConfig_AntB				0xb6c + +#define	rPdp_AntB				0xb70 +#define	rPdp_AntB_4				0xb74 +#define	rPdp_AntB_8				0xb78 +#define	rPdp_AntB_C				0xb7c +#define	rPdp_AntB_10				0xb80 +#define	rPdp_AntB_14				0xb84 +#define	rPdp_AntB_18				0xb88 +#define	rPdp_AntB_1C				0xb8c +#define	rPdp_AntB_20				0xb90 +#define	rPdp_AntB_24				0xb94 + +#define	rConfig_Pmpd_AntB			0xb98 + +#define	rBndB					0xba0 + +#define	rAPK					0xbd8 +#define	rPm_Rx0_AntA				0xbdc +#define	rPm_Rx1_AntA				0xbe0 +#define	rPm_Rx2_AntA				0xbe4 +#define	rPm_Rx3_AntA				0xbe8 +#define	rPm_Rx0_AntB				0xbec +#define	rPm_Rx1_AntB				0xbf0 +#define	rPm_Rx2_AntB				0xbf4 +#define	rPm_Rx3_AntB				0xbf8 + +/*Page C*/ +#define	ROFDM0_LSTF				0xc00 + +#define	ROFDM0_TRXPATHENABLE			0xc04 +#define	ROFDM0_TRMUXPAR				0xc08 +#define	ROFDM0_TRSWISOLATION			0xc0c + +#define	ROFDM0_XARXAFE				0xc10 +#define	ROFDM0_XARXIQIMBALANCE			0xc14 +#define	ROFDM0_XBRXAFE				0xc18 +#define	ROFDM0_XBRXIQIMBALANCE			0xc1c +#define	ROFDM0_XCRXAFE				0xc20 +#define	ROFDM0_XCRXIQIMBANLANCE			0xc24 +#define	ROFDM0_XDRXAFE				0xc28 +#define	ROFDM0_XDRXIQIMBALANCE			0xc2c + +#define	ROFDM0_RXDETECTOR1			0xc30 +#define	ROFDM0_RXDETECTOR2			0xc34 +#define	ROFDM0_RXDETECTOR3			0xc38 +#define	ROFDM0_RXDETECTOR4			0xc3c + +#define	ROFDM0_RXDSP				0xc40 +#define	ROFDM0_CFOANDDAGC			0xc44 +#define	ROFDM0_CCADROPTHRESHOLD			0xc48 +#define	ROFDM0_ECCATHRESHOLD			0xc4c + +#define	ROFDM0_XAAGCCORE1			0xc50 +#define	ROFDM0_XAAGCCORE2			0xc54 +#define	ROFDM0_XBAGCCORE1			0xc58 +#define	ROFDM0_XBAGCCORE2			0xc5c +#define	ROFDM0_XCAGCCORE1			0xc60 +#define	ROFDM0_XCAGCCORE2			0xc64 +#define	ROFDM0_XDAGCCORE1			0xc68 +#define	ROFDM0_XDAGCCORE2			0xc6c + +#define	ROFDM0_AGCPARAMETER1			0xc70 +#define	ROFDM0_AGCPARAMETER2			0xc74 +#define	ROFDM0_AGCRSSITABLE			0xc78 +#define	ROFDM0_HTSTFAGC				0xc7c + +#define	ROFDM0_XATXIQIMBALANCE			0xc80 +#define	ROFDM0_XATXAFE				0xc84 +#define	ROFDM0_XBTXIQIMBALANCE			0xc88 +#define	ROFDM0_XBTXAFE				0xc8c +#define	ROFDM0_XCTXIQIMBALANCE			0xc90 +#define	ROFDM0_XCTXAFE				0xc94 +#define	ROFDM0_XDTXIQIMBALANCE			0xc98 +#define	ROFDM0_XDTXAFE				0xc9c + +#define ROFDM0_RXIQEXTANTA			0xca0 +#define	ROFDM0_TXCOEFF1				0xca4 +#define	ROFDM0_TXCOEFF2				0xca8 +#define	ROFDM0_TXCOEFF3				0xcac +#define	ROFDM0_TXCOEFF4				0xcb0 +#define	ROFDM0_TXCOEFF5				0xcb4 +#define	ROFDM0_TXCOEFF6				0xcb8 + +#define	ROFDM0_RXHPPARAMETER			0xce0 +#define	ROFDM0_TXPSEUDONOISEWGT			0xce4 +#define	ROFDM0_FRAMESYNC			0xcf0 +#define	ROFDM0_DFSREPORT			0xcf4 + + +#define	ROFDM1_LSTF				0xd00 +#define	ROFDM1_TRXPATHENABLE			0xd04 + +#define	ROFDM1_CF0				0xd08 +#define	ROFDM1_CSI1				0xd10 +#define	ROFDM1_SBD				0xd14 +#define	ROFDM1_CSI2				0xd18 +#define	ROFDM1_CFOTRACKING			0xd2c +#define	ROFDM1_TRXMESAURE1			0xd34 +#define	ROFDM1_INTFDET				0xd3c +#define	ROFDM1_PSEUDONOISESTATEAB		0xd50 +#define	ROFDM1_PSEUDONOISESTATECD		0xd54 +#define	ROFDM1_RXPSEUDONOISEWGT			0xd58 + +#define	ROFDM_PHYCOUNTER1			0xda0 +#define	ROFDM_PHYCOUNTER2			0xda4 +#define	ROFDM_PHYCOUNTER3			0xda8 + +#define	ROFDM_SHORTCFOAB			0xdac +#define	ROFDM_SHORTCFOCD			0xdb0 +#define	ROFDM_LONGCFOAB				0xdb4 +#define	ROFDM_LONGCFOCD				0xdb8 +#define	ROFDM_TAILCF0AB				0xdbc +#define	ROFDM_TAILCF0CD				0xdc0 +#define	ROFDM_PWMEASURE1			0xdc4 +#define	ROFDM_PWMEASURE2			0xdc8 +#define	ROFDM_BWREPORT				0xdcc +#define	ROFDM_AGCREPORT				0xdd0 +#define	ROFDM_RXSNR				0xdd4 +#define	ROFDM_RXEVMCSI				0xdd8 +#define	ROFDM_SIGREPORT				0xddc + +#define	RTXAGC_A_RATE18_06			0xe00 +#define	RTXAGC_A_RATE54_24			0xe04 +#define	RTXAGC_A_CCK1_MCS32			0xe08 +#define	RTXAGC_A_MCS03_MCS00			0xe10 +#define	RTXAGC_A_MCS07_MCS04			0xe14 +#define	RTXAGC_A_MCS11_MCS08			0xe18 +#define	RTXAGC_A_MCS15_MCS12			0xe1c + +#define	RTXAGC_B_RATE18_06			0x830 +#define	RTXAGC_B_RATE54_24			0x834 +#define	RTXAGC_B_CCK1_55_MCS32			0x838 +#define	RTXAGC_B_MCS03_MCS00			0x83c +#define	RTXAGC_B_MCS07_MCS04			0x848 +#define	RTXAGC_B_MCS11_MCS08			0x84c +#define	RTXAGC_B_MCS15_MCS12			0x868 +#define	RTXAGC_B_CCK11_A_CCK2_11		0x86c + +#define	RFPGA0_IQK				0xe28 +#define	RTx_IQK_Tone_A				0xe30 +#define	RRx_IQK_Tone_A				0xe34 +#define	RTx_IQK_PI_A				0xe38 +#define	RRx_IQK_PI_A				0xe3c + +#define	RTx_IQK					0xe40 +#define	RRx_IQK					0xe44 +#define	RIQK_AGC_Pts				0xe48 +#define	RIQK_AGC_Rsp				0xe4c +#define	RTx_IQK_Tone_B				0xe50 +#define	RRx_IQK_Tone_B				0xe54 +#define	RTx_IQK_PI_B				0xe58 +#define	RRx_IQK_PI_B				0xe5c +#define	RIQK_AGC_Cont				0xe60 + +#define	RBlue_Tooth				0xe6c +#define	RRx_Wait_CCA				0xe70 +#define	RTx_CCK_RFON				0xe74 +#define	RTx_CCK_BBON				0xe78 +#define	RTx_OFDM_RFON				0xe7c +#define	RTx_OFDM_BBON				0xe80 +#define	RTx_To_Rx				0xe84 +#define	RTx_To_Tx				0xe88 +#define	RRx_CCK					0xe8c + +#define	RTx_Power_Before_IQK_A			0xe94 +#define	RTx_Power_After_IQK_A			0xe9c + +#define	RRx_Power_Before_IQK_A			0xea0 +#define	RRx_Power_Before_IQK_A_2		0xea4 +#define	RRx_Power_After_IQK_A			0xea8 +#define	RRx_Power_After_IQK_A_2			0xeac + +#define	RTx_Power_Before_IQK_B			0xeb4 +#define	RTx_Power_After_IQK_B			0xebc + +#define	RRx_Power_Before_IQK_B			0xec0 +#define	RRx_Power_Before_IQK_B_2		0xec4 +#define	RRx_Power_After_IQK_B			0xec8 +#define	RRx_Power_After_IQK_B_2			0xecc + +#define	RRx_OFDM				0xed0 +#define	RRx_Wait_RIFS				0xed4 +#define	RRx_TO_Rx				0xed8 +#define	RStandby				0xedc +#define	RSleep					0xee0 +#define	RPMPD_ANAEN				0xeec + +#define	RZEBRA1_HSSIENABLE			0x0 +#define	RZEBRA1_TRXENABLE1			0x1 +#define	RZEBRA1_TRXENABLE2			0x2 +#define	RZEBRA1_AGC				0x4 +#define	RZEBRA1_CHARGEPUMP			0x5 +#define	RZEBRA1_CHANNEL				0x7 + +#define	RZEBRA1_TXGAIN				0x8 +#define	RZEBRA1_TXLPF				0x9 +#define	RZEBRA1_RXLPF				0xb +#define	RZEBRA1_RXHPFCORNER			0xc + +#define	RGLOBALCTRL				0 +#define	RRTL8256_TXLPF				19 +#define	RRTL8256_RXLPF				11 +#define	RRTL8258_TXLPF				0x11 +#define	RRTL8258_RXLPF				0x13 +#define	RRTL8258_RSSILPF			0xa + +#define	RF_AC					0x00 + +#define	RF_IQADJ_G1				0x01 +#define	RF_IQADJ_G2				0x02 +#define	RF_POW_TRSW				0x05 + +#define	RF_GAIN_RX				0x06 +#define	RF_GAIN_TX				0x07 + +#define	RF_TXM_IDAC				0x08 +#define	RF_BS_IQGEN				0x0F + +#define	RF_MODE1				0x10 +#define	RF_MODE2				0x11 + +#define	RF_RX_AGC_HP				0x12 +#define	RF_TX_AGC				0x13 +#define	RF_BIAS					0x14 +#define	RF_IPA					0x15 +#define	RF_POW_ABILITY				0x17 +#define	RF_MODE_AG				0x18 +#define	RRFCHANNEL				0x18 +#define	RF_CHNLBW				0x18 +#define	RF_TOP					0x19 + +#define	RF_RX_G1				0x1A +#define	RF_RX_G2				0x1B + +#define	RF_RX_BB2				0x1C +#define	RF_RX_BB1				0x1D + +#define	RF_RCK1					0x1E +#define	RF_RCK2					0x1F + +#define	RF_TX_G1				0x20 +#define	RF_TX_G2				0x21 +#define	RF_TX_G3				0x22 + +#define	RF_TX_BB1				0x23 +#define	RF_T_METER				0x42 + +#define	RF_SYN_G1				0x25 +#define	RF_SYN_G2				0x26 +#define	RF_SYN_G3				0x27 +#define	RF_SYN_G4				0x28 +#define	RF_SYN_G5				0x29 +#define	RF_SYN_G6				0x2A +#define	RF_SYN_G7				0x2B +#define	RF_SYN_G8				0x2C + +#define	RF_RCK_OS				0x30 +#define	RF_TXPA_G1				0x31 +#define	RF_TXPA_G2				0x32 +#define	RF_TXPA_G3				0x33 + +#define	RF_TX_BIAS_A				0x35 +#define	RF_TX_BIAS_D				0x36 +#define	RF_LOBF_9				0x38 +#define	RF_RXRF_A3				0x3C +#define	RF_TRSW					0x3F + +#define	RF_TXRF_A2				0x41 +#define	RF_TXPA_G4				0x46 +#define	RF_TXPA_A4				0x4B + +#define	RF_WE_LUT				0xEF + +#define	BBBRESETB				0x100 +#define	BGLOBALRESETB				0x200 +#define	BOFDMTXSTART				0x4 +#define	BCCKTXSTART				0x8 +#define	BCRC32DEBUG				0x100 +#define	BPMACLOOPBACK				0x10 +#define	BTXLSIG					0xffffff +#define	BOFDMTXRATE				0xf +#define	BOFDMTXRESERVED				0x10 +#define	BOFDMTXLENGTH				0x1ffe0 +#define	BOFDMTXPARITY				0x20000 +#define	BTXHTSIG1				0xffffff +#define	BTXHTMCSRATE				0x7f +#define	BTXHTBW					0x80 +#define	BTXHTLENGTH				0xffff00 +#define	BTXHTSIG2				0xffffff +#define	BTXHTSMOOTHING				0x1 +#define	BTXHTSOUNDING				0x2 +#define	BTXHTRESERVED				0x4 +#define	BTXHTAGGREATION				0x8 +#define	BTXHTSTBC				0x30 +#define	BTXHTADVANCECODING			0x40 +#define	BTXHTSHORTGI				0x80 +#define	BTXHTNUMBERHT_LTF			0x300 +#define	BTXHTCRC8				0x3fc00 +#define	BCOUNTERRESET				0x10000 +#define	BNUMOFOFDMTX				0xffff +#define	BNUMOFCCKTX				0xffff0000 +#define	BTXIDLEINTERVAL				0xffff +#define	BOFDMSERVICE				0xffff0000 +#define	BTXMACHEADER				0xffffffff +#define	BTXDATAINIT				0xff +#define	BTXHTMODE				0x100 +#define	BTXDATATYPE				0x30000 +#define	BTXRANDOMSEED				0xffffffff +#define	BCCKTXPREAMBLE				0x1 +#define	BCCKTXSFD				0xffff0000 +#define	BCCKTXSIG				0xff +#define	BCCKTXSERVICE				0xff00 +#define	BCCKLENGTHEXT				0x8000 +#define	BCCKTXLENGHT				0xffff0000 +#define	BCCKTXCRC16				0xffff +#define	BCCKTXSTATUS				0x1 +#define	BOFDMTXSTATUS				0x2 +#define IS_BB_REG_OFFSET_92S(_Offset)	\ +	((_Offset >= 0x800) && (_Offset <= 0xfff)) + +#define	BRFMOD					0x1 +#define	BJAPANMODE				0x2 +#define	BCCKTXSC				0x30 +#define	BCCKEN					0x1000000 +#define	BOFDMEN					0x2000000 + +#define	BOFDMRXADCPHASE				0x10000 +#define	BOFDMTXDACPHASE				0x40000 +#define	BXATXAGC				0x3f + +#define	BXBTXAGC				0xf00 +#define	BXCTXAGC				0xf000 +#define	BXDTXAGC				0xf0000 + +#define	BPASTART				0xf0000000 +#define	BTRSTART				0x00f00000 +#define	BRFSTART				0x0000f000 +#define	BBBSTART				0x000000f0 +#define	BBBCCKSTART				0x0000000f +#define	BPAEND					0xf +#define	BTREND					0x0f000000 +#define	BRFEND					0x000f0000 +#define	BCCAMASK				0x000000f0 +#define	BR2RCCAMASK				0x00000f00 +#define	BHSSI_R2TDELAY				0xf8000000 +#define	BHSSI_T2RDELAY				0xf80000 +#define	BCONTXHSSI				0x400 +#define	BIGFROMCCK				0x200 +#define	BAGCADDRESS				0x3f +#define	BRXHPTX					0x7000 +#define	BRXHP2RX				0x38000 +#define	BRXHPCCKINI				0xc0000 +#define	BAGCTXCODE				0xc00000 +#define	BAGCRXCODE				0x300000 + +#define	B3WIREDATALENGTH			0x800 +#define	B3WIREADDREAALENGTH			0x400 + +#define	B3WIRERFPOWERDOWN			0x1 +#define	B5GPAPEPOLARITY				0x40000000 +#define	B2GPAPEPOLARITY				0x80000000 +#define	BRFSW_TXDEFAULTANT			0x3 +#define	BRFSW_TXOPTIONANT			0x30 +#define	BRFSW_RXDEFAULTANT			0x300 +#define	BRFSW_RXOPTIONANT			0x3000 +#define	BRFSI_3WIREDATA				0x1 +#define	BRFSI_3WIRECLOCK			0x2 +#define	BRFSI_3WIRELOAD				0x4 +#define	BRFSI_3WIRERW				0x8 +#define	BRFSI_3WIRE				0xf + +#define	BRFSI_RFENV				0x10 + +#define	BRFSI_TRSW				0x20 +#define	BRFSI_TRSWB				0x40 +#define	BRFSI_ANTSW				0x100 +#define	BRFSI_ANTSWB				0x200 +#define	BRFSI_PAPE				0x400 +#define	BRFSI_PAPE5G				0x800 +#define	BBANDSELECT				0x1 +#define	BHTSIG2_GI				0x80 +#define	BHTSIG2_SMOOTHING			0x01 +#define	BHTSIG2_SOUNDING			0x02 +#define	BHTSIG2_AGGREATON			0x08 +#define	BHTSIG2_STBC				0x30 +#define	BHTSIG2_ADVCODING			0x40 +#define	BHTSIG2_NUMOFHTLTF			0x300 +#define	BHTSIG2_CRC8				0x3fc +#define	BHTSIG1_MCS				0x7f +#define	BHTSIG1_BANDWIDTH			0x80 +#define	BHTSIG1_HTLENGTH			0xffff +#define	BLSIG_RATE				0xf +#define	BLSIG_RESERVED				0x10 +#define	BLSIG_LENGTH				0x1fffe +#define	BLSIG_PARITY				0x20 +#define	BCCKRXPHASE				0x4 + +#define	BLSSIREADADDRESS			0x7f800000 +#define	BLSSIREADEDGE				0x80000000 + +#define	BLSSIREADBACKDATA			0xfffff + +#define	BLSSIREADOKFLAG				0x1000 +#define	BCCKSAMPLERATE				0x8 +#define	BREGULATOR0STANDBY			0x1 +#define	BREGULATORPLLSTANDBY			0x2 +#define	BREGULATOR1STANDBY			0x4 +#define	BPLLPOWERUP				0x8 +#define	BDPLLPOWERUP				0x10 +#define	BDA10POWERUP				0x20 +#define	BAD7POWERUP				0x200 +#define	BDA6POWERUP				0x2000 +#define	BXTALPOWERUP				0x4000 +#define	B40MDCLKPOWERUP				0x8000 +#define	BDA6DEBUGMODE				0x20000 +#define	BDA6SWING				0x380000 + +#define	BADCLKPHASE				0x4000000 +#define	B80MCLKDELAY				0x18000000 +#define	BAFEWATCHDOGENABLE			0x20000000 + +#define	BXTALCAP01				0xc0000000 +#define	BXTALCAP23				0x3 +#define	BXTALCAP92X				0x0f000000 +#define BXTALCAP				0x0f000000 + +#define	BINTDIFCLKENABLE			0x400 +#define	BEXTSIGCLKENABLE			0x800 +#define	BBANDGAP_MBIAS_POWERUP			0x10000 +#define	BAD11SH_GAIN				0xc0000 +#define	BAD11NPUT_RANGE				0x700000 +#define	BAD110P_CURRENT				0x3800000 +#define	BLPATH_LOOPBACK				0x4000000 +#define	BQPATH_LOOPBACK				0x8000000 +#define	BAFE_LOOPBACK				0x10000000 +#define	BDA10_SWING				0x7e0 +#define	BDA10_REVERSE				0x800 +#define	BDA_CLK_SOURCE				0x1000 +#define	BDA7INPUT_RANGE				0x6000 +#define	BDA7_GAIN				0x38000 +#define	BDA7OUTPUT_CM_MODE			0x40000 +#define	BDA7INPUT_CM_MODE			0x380000 +#define	BDA7CURRENT				0xc00000 +#define	BREGULATOR_ADJUST			0x7000000 +#define	BAD11POWERUP_ATTX			0x1 +#define	BDA10PS_ATTX				0x10 +#define	BAD11POWERUP_ATRX			0x100 +#define	BDA10PS_ATRX				0x1000 +#define	BCCKRX_AGC_FORMAT			0x200 +#define	BPSDFFT_SAMPLE_POINT			0xc000 +#define	BPSD_AVERAGE_NUM			0x3000 +#define	BIQPATH_CONTROL				0xc00 +#define	BPSD_FREQ				0x3ff +#define	BPSD_ANTENNA_PATH			0x30 +#define	BPSD_IQ_SWITCH				0x40 +#define	BPSD_RX_TRIGGER				0x400000 +#define	BPSD_TX_TRIGGER				0x80000000 +#define	BPSD_SINE_TONE_SCALE			0x7f000000 +#define	BPSD_REPORT				0xffff + +#define	BOFDM_TXSC				0x30000000 +#define	BCCK_TXON				0x1 +#define	BOFDM_TXON				0x2 +#define	BDEBUG_PAGE				0xfff +#define	BDEBUG_ITEM				0xff +#define	BANTL					0x10 +#define	BANT_NONHT				0x100 +#define	BANT_HT1				0x1000 +#define	BANT_HT2				0x10000 +#define	BANT_HT1S1				0x100000 +#define	BANT_NONHTS1				0x1000000 + +#define	BCCK_BBMODE				0x3 +#define	BCCK_TXPOWERSAVING			0x80 +#define	BCCK_RXPOWERSAVING			0x40 + +#define	BCCK_SIDEBAND				0x10 + +#define	BCCK_SCRAMBLE				0x8 +#define	BCCK_ANTDIVERSITY			0x8000 +#define	BCCK_CARRIER_RECOVERY			0x4000 +#define	BCCK_TXRATE				0x3000 +#define	BCCK_DCCANCEL				0x0800 +#define	BCCK_ISICANCEL				0x0400 +#define	BCCK_MATCH_FILTER			0x0200 +#define	BCCK_EQUALIZER				0x0100 +#define	BCCK_PREAMBLE_DETECT			0x800000 +#define	BCCK_FAST_FALSECCA			0x400000 +#define	BCCK_CH_ESTSTART			0x300000 +#define	BCCK_CCA_COUNT				0x080000 +#define	BCCK_CS_LIM				0x070000 +#define	BCCK_BIST_MODE				0x80000000 +#define	BCCK_CCAMASK				0x40000000 +#define	BCCK_TX_DAC_PHASE			0x4 +#define	BCCK_RX_ADC_PHASE			0x20000000 +#define	BCCKR_CP_MODE				0x0100 +#define	BCCK_TXDC_OFFSET			0xf0 +#define	BCCK_RXDC_OFFSET			0xf +#define	BCCK_CCA_MODE				0xc000 +#define	BCCK_FALSECS_LIM			0x3f00 +#define	BCCK_CS_RATIO				0xc00000 +#define	BCCK_CORGBIT_SEL			0x300000 +#define	BCCK_PD_LIM				0x0f0000 +#define	BCCK_NEWCCA				0x80000000 +#define	BCCK_RXHP_OF_IG				0x8000 +#define	BCCK_RXIG				0x7f00 +#define	BCCK_LNA_POLARITY			0x800000 +#define	BCCK_RX1ST_BAIN				0x7f0000 +#define	BCCK_RF_EXTEND				0x20000000 +#define	BCCK_RXAGC_SATLEVEL			0x1f000000 +#define	BCCK_RXAGC_SATCOUNT			0xe0 +#define	bCCKRxRFSettle				0x1f +#define	BCCK_FIXED_RXAGC			0x8000 +#define	BCCK_ANTENNA_POLARITY			0x2000 +#define	BCCK_TXFILTER_TYPE			0x0c00 +#define	BCCK_RXAGC_REPORTTYPE			0x0300 +#define	BCCK_RXDAGC_EN				0x80000000 +#define	BCCK_RXDAGC_PERIOD			0x20000000 +#define	BCCK_RXDAGC_SATLEVEL			0x1f000000 +#define	BCCK_TIMING_RECOVERY			0x800000 +#define	BCCK_TXC0				0x3f0000 +#define	BCCK_TXC1				0x3f000000 +#define	BCCK_TXC2				0x3f +#define	BCCK_TXC3				0x3f00 +#define	BCCK_TXC4				0x3f0000 +#define	BCCK_TXC5				0x3f000000 +#define	BCCK_TXC6				0x3f +#define	BCCK_TXC7				0x3f00 +#define	BCCK_DEBUGPORT				0xff0000 +#define	BCCK_DAC_DEBUG				0x0f000000 +#define	BCCK_FALSEALARM_ENABLE			0x8000 +#define	BCCK_FALSEALARM_READ			0x4000 +#define	BCCK_TRSSI				0x7f +#define	BCCK_RXAGC_REPORT			0xfe +#define	BCCK_RXREPORT_ANTSEL			0x80000000 +#define	BCCK_RXREPORT_MFOFF			0x40000000 +#define	BCCK_RXREPORT_SQLOSS			0x20000000 +#define	BCCK_RXREPORT_PKTLOSS			0x10000000 +#define	BCCK_RXREPORT_LOCKEDBIT			0x08000000 +#define	BCCK_RXREPORT_RATEERROR			0x04000000 +#define	BCCK_RXREPORT_RXRATE			0x03000000 +#define	BCCK_RXFA_COUNTER_LOWER			0xff +#define	BCCK_RXFA_COUNTER_UPPER			0xff000000 +#define	BCCK_RXHPAGC_START			0xe000 +#define	BCCK_RXHPAGC_FINAL			0x1c00 +#define	BCCK_RXFALSEALARM_ENABLE		0x8000 +#define	BCCK_FACOUNTER_FREEZE			0x4000 +#define	BCCK_TXPATH_SEL				0x10000000 +#define	BCCK_DEFAULT_RXPATH			0xc000000 +#define	BCCK_OPTION_RXPATH			0x3000000 + +#define	BNUM_OFSTF				0x3 +#define	BSHIFT_L				0xc0 +#define	BGI_TH					0xc +#define	BRXPATH_A				0x1 +#define	BRXPATH_B				0x2 +#define	BRXPATH_C				0x4 +#define	BRXPATH_D				0x8 +#define	BTXPATH_A				0x1 +#define	BTXPATH_B				0x2 +#define	BTXPATH_C				0x4 +#define	BTXPATH_D				0x8 +#define	BTRSSI_FREQ				0x200 +#define	BADC_BACKOFF				0x3000 +#define	BDFIR_BACKOFF				0xc000 +#define	BTRSSI_LATCH_PHASE			0x10000 +#define	BRX_LDC_OFFSET				0xff +#define	BRX_QDC_OFFSET				0xff00 +#define	BRX_DFIR_MODE				0x1800000 +#define	BRX_DCNF_TYPE				0xe000000 +#define	BRXIQIMB_A				0x3ff +#define	BRXIQIMB_B				0xfc00 +#define	BRXIQIMB_C				0x3f0000 +#define	BRXIQIMB_D				0xffc00000 +#define	BDC_DC_NOTCH				0x60000 +#define	BRXNB_NOTCH				0x1f000000 +#define	BPD_TH					0xf +#define	BPD_TH_OPT2				0xc000 +#define	BPWED_TH				0x700 +#define	BIFMF_WIN_L				0x800 +#define	BPD_OPTION				0x1000 +#define	BMF_WIN_L				0xe000 +#define	BBW_SEARCH_L				0x30000 +#define	BWIN_ENH_L				0xc0000 +#define	BBW_TH					0x700000 +#define	BED_TH2					0x3800000 +#define	BBW_OPTION				0x4000000 +#define	BRADIO_TH				0x18000000 +#define	BWINDOW_L				0xe0000000 +#define	BSBD_OPTION				0x1 +#define	BFRAME_TH				0x1c +#define	BFS_OPTION				0x60 +#define	BDC_SLOPE_CHECK				0x80 +#define	BFGUARD_COUNTER_DC_L			0xe00 +#define	BFRAME_WEIGHT_SHORT			0x7000 +#define	BSUB_TUNE				0xe00000 +#define	BFRAME_DC_LENGTH			0xe000000 +#define	BSBD_START_OFFSET			0x30000000 +#define	BFRAME_TH_2				0x7 +#define	BFRAME_GI2_TH				0x38 +#define	BGI2_SYNC_EN				0x40 +#define	BSARCH_SHORT_EARLY			0x300 +#define	BSARCH_SHORT_LATE			0xc00 +#define	BSARCH_GI2_LATE				0x70000 +#define	BCFOANTSUM				0x1 +#define	BCFOACC					0x2 +#define	BCFOSTARTOFFSET				0xc +#define	BCFOLOOPBACK				0x70 +#define	BCFOSUMWEIGHT				0x80 +#define	BDAGCENABLE				0x10000 +#define	BTXIQIMB_A				0x3ff +#define	BTXIQIMB_b				0xfc00 +#define	BTXIQIMB_C				0x3f0000 +#define	BTXIQIMB_D				0xffc00000 +#define	BTXIDCOFFSET				0xff +#define	BTXIQDCOFFSET				0xff00 +#define	BTXDFIRMODE				0x10000 +#define	BTXPESUDO_NOISEON			0x4000000 +#define	BTXPESUDO_NOISE_A			0xff +#define	BTXPESUDO_NOISE_B			0xff00 +#define	BTXPESUDO_NOISE_C			0xff0000 +#define	BTXPESUDO_NOISE_D			0xff000000 +#define	BCCA_DROPOPTION				0x20000 +#define	BCCA_DROPTHRES				0xfff00000 +#define	BEDCCA_H				0xf +#define	BEDCCA_L				0xf0 +#define	BLAMBDA_ED				0x300 +#define	BRX_INITIALGAIN				0x7f +#define	BRX_ANTDIV_EN				0x80 +#define	BRX_AGC_ADDRESS_FOR_LNA			0x7f00 +#define	BRX_HIGHPOWER_FLOW			0x8000 +#define	BRX_AGC_FREEZE_THRES			0xc0000 +#define	BRX_FREEZESTEP_AGC1			0x300000 +#define	BRX_FREEZESTEP_AGC2			0xc00000 +#define	BRX_FREEZESTEP_AGC3			0x3000000 +#define	BRX_FREEZESTEP_AGC0			0xc000000 +#define	BRXRSSI_CMP_EN				0x10000000 +#define	BRXQUICK_AGCEN				0x20000000 +#define	BRXAGC_FREEZE_THRES_MODE		0x40000000 +#define	BRX_OVERFLOW_CHECKTYPE			0x80000000 +#define	BRX_AGCSHIFT				0x7f +#define	BTRSW_TRI_ONLY				0x80 +#define	BPOWER_THRES				0x300 +#define	BRXAGC_EN				0x1 +#define	BRXAGC_TOGETHER_EN			0x2 +#define	BRXAGC_MIN				0x4 +#define	BRXHP_INI				0x7 +#define	BRXHP_TRLNA				0x70 +#define	BRXHP_RSSI				0x700 +#define	BRXHP_BBP1				0x7000 +#define	BRXHP_BBP2				0x70000 +#define	BRXHP_BBP3				0x700000 +#define	BRSSI_H					0x7f0000 +#define	BRSSI_GEN				0x7f000000 +#define	BRXSETTLE_TRSW				0x7 +#define	BRXSETTLE_LNA				0x38 +#define	BRXSETTLE_RSSI				0x1c0 +#define	BRXSETTLE_BBP				0xe00 +#define	BRXSETTLE_RXHP				0x7000 +#define	BRXSETTLE_ANTSW_RSSI			0x38000 +#define	BRXSETTLE_ANTSW				0xc0000 +#define	BRXPROCESS_TIME_DAGC			0x300000 +#define	BRXSETTLE_HSSI				0x400000 +#define	BRXPROCESS_TIME_BBPPW			0x800000 +#define	BRXANTENNA_POWER_SHIFT			0x3000000 +#define	BRSSI_TABLE_SELECT			0xc000000 +#define	BRXHP_FINAL				0x7000000 +#define	BRXHPSETTLE_BBP				0x7 +#define	BRXHTSETTLE_HSSI			0x8 +#define	BRXHTSETTLE_RXHP			0x70 +#define	BRXHTSETTLE_BBPPW			0x80 +#define	BRXHTSETTLE_IDLE			0x300 +#define	BRXHTSETTLE_RESERVED			0x1c00 +#define	BRXHT_RXHP_EN				0x8000 +#define	BRXAGC_FREEZE_THRES			0x30000 +#define	BRXAGC_TOGETHEREN			0x40000 +#define	BRXHTAGC_MIN				0x80000 +#define	BRXHTAGC_EN				0x100000 +#define	BRXHTDAGC_EN				0x200000 +#define	BRXHT_RXHP_BBP				0x1c00000 +#define	BRXHT_RXHP_FINAL			0xe0000000 +#define	BRXPW_RADIO_TH				0x3 +#define	BRXPW_RADIO_EN				0x4 +#define	BRXMF_HOLD				0x3800 +#define	BRXPD_DELAY_TH1				0x38 +#define	BRXPD_DELAY_TH2				0x1c0 +#define	BRXPD_DC_COUNT_MAX			0x600 +#define	BRXPD_DELAY_TH				0x8000 +#define	BRXPROCESS_DELAY			0xf0000 +#define	BRXSEARCHRANGE_GI2_EARLY		0x700000 +#define	BRXFRAME_FUARD_COUNTER_L		0x3800000 +#define	BRXSGI_GUARD_L				0xc000000 +#define	BRXSGI_SEARCH_L				0x30000000 +#define	BRXSGI_TH				0xc0000000 +#define	BDFSCNT0				0xff +#define	BDFSCNT1				0xff00 +#define	BDFSFLAG				0xf0000 +#define	BMF_WEIGHT_SUM				0x300000 +#define	BMINIDX_TH				0x7f000000 +#define	BDAFORMAT				0x40000 +#define	BTXCH_EMU_ENABLE			0x01000000 +#define	BTRSW_ISOLATION_A			0x7f +#define	BTRSW_ISOLATION_B			0x7f00 +#define	BTRSW_ISOLATION_C			0x7f0000 +#define	BTRSW_ISOLATION_D			0x7f000000 +#define	BEXT_LNA_GAIN				0x7c00 + +#define	BSTBC_EN				0x4 +#define	BANTENNA_MAPPING			0x10 +#define	BNSS					0x20 +#define	BCFO_ANTSUM_ID				0x200 +#define	BPHY_COUNTER_RESET			0x8000000 +#define	BCFO_REPORT_GET				0x4000000 +#define	BOFDM_CONTINUE_TX			0x10000000 +#define	BOFDM_SINGLE_CARRIER			0x20000000 +#define	BOFDM_SINGLE_TONE			0x40000000 +#define	BHT_DETECT				0x100 +#define	BCFOEN					0x10000 +#define	BCFOVALUE				0xfff00000 +#define	BSIGTONE_RE				0x3f +#define	BSIGTONE_IM				0x7f00 +#define	BCOUNTER_CCA				0xffff +#define	BCOUNTER_PARITYFAIL			0xffff0000 +#define	BCOUNTER_RATEILLEGAL			0xffff +#define	BCOUNTER_CRC8FAIL			0xffff0000 +#define	BCOUNTER_MCSNOSUPPORT			0xffff +#define	BCOUNTER_FASTSYNC			0xffff +#define	BSHORTCFO				0xfff +#define	BSHORTCFOT_LENGTH			12 +#define	BSHORTCFOF_LENGTH			11 +#define	BLONGCFO				0x7ff +#define	BLONGCFOT_LENGTH			11 +#define	BLONGCFOF_LENGTH			11 +#define	BTAILCFO				0x1fff +#define	BTAILCFOT_LENGTH			13 +#define	BTAILCFOF_LENGTH			12 +#define	BNOISE_EN_PWDB				0xffff +#define	BCC_POWER_DB				0xffff0000 +#define	BMOISE_PWDB				0xffff +#define	BPOWERMEAST_LENGTH			10 +#define	BPOWERMEASF_LENGTH			3 +#define	BRX_HT_BW				0x1 +#define	BRXSC					0x6 +#define	BRX_HT					0x8 +#define	BNB_INTF_DET_ON				0x1 +#define	BINTF_WIN_LEN_CFG			0x30 +#define	BNB_INTF_TH_CFG				0x1c0 +#define	BRFGAIN					0x3f +#define	BTABLESEL				0x40 +#define	BTRSW					0x80 +#define	BRXSNR_A				0xff +#define	BRXSNR_B				0xff00 +#define	BRXSNR_C				0xff0000 +#define	BRXSNR_D				0xff000000 +#define	BSNR_EVMT_LENGTH			8 +#define	BSNR_EVMF_LENGTH			1 +#define	BCSI1ST					0xff +#define	BCSI2ND					0xff00 +#define	BRXEVM1ST				0xff0000 +#define	BRXEVM2ND				0xff000000 +#define	BSIGEVM					0xff +#define	BPWDB					0xff00 +#define	BSGIEN					0x10000 + +#define	BSFACTOR_QMA1				0xf +#define	BSFACTOR_QMA2				0xf0 +#define	BSFACTOR_QMA3				0xf00 +#define	BSFACTOR_QMA4				0xf000 +#define	BSFACTOR_QMA5				0xf0000 +#define	BSFACTOR_QMA6				0xf0000 +#define	BSFACTOR_QMA7				0xf00000 +#define	BSFACTOR_QMA8				0xf000000 +#define	BSFACTOR_QMA9				0xf0000000 +#define	BCSI_SCHEME				0x100000 + +#define	BNOISE_LVL_TOP_SET			0x3 +#define	BCHSMOOTH				0x4 +#define	BCHSMOOTH_CFG1				0x38 +#define	BCHSMOOTH_CFG2				0x1c0 +#define	BCHSMOOTH_CFG3				0xe00 +#define	BCHSMOOTH_CFG4				0x7000 +#define	BMRCMODE				0x800000 +#define	BTHEVMCFG				0x7000000 + +#define	BLOOP_FIT_TYPE				0x1 +#define	BUPD_CFO				0x40 +#define	BUPD_CFO_OFFDATA			0x80 +#define	BADV_UPD_CFO				0x100 +#define	BADV_TIME_CTRL				0x800 +#define	BUPD_CLKO				0x1000 +#define	BFC					0x6000 +#define	BTRACKING_MODE				0x8000 +#define	BPHCMP_ENABLE				0x10000 +#define	BUPD_CLKO_LTF				0x20000 +#define	BCOM_CH_CFO				0x40000 +#define	BCSI_ESTI_MODE				0x80000 +#define	BADV_UPD_EQZ				0x100000 +#define	BUCHCFG					0x7000000 +#define	BUPDEQZ					0x8000000 + +#define	BRX_PESUDO_NOISE_ON			0x20000000 +#define	BRX_PESUDO_NOISE_A			0xff +#define	BRX_PESUDO_NOISE_B			0xff00 +#define	BRX_PESUDO_NOISE_C			0xff0000 +#define	BRX_PESUDO_NOISE_D			0xff000000 +#define	BRX_PESUDO_NOISESTATE_A			0xffff +#define	BRX_PESUDO_NOISESTATE_B			0xffff0000 +#define	BRX_PESUDO_NOISESTATE_C			0xffff +#define	BRX_PESUDO_NOISESTATE_D			0xffff0000 + +#define	BZEBRA1_HSSIENABLE			0x8 +#define	BZEBRA1_TRXCONTROL			0xc00 +#define	BZEBRA1_TRXGAINSETTING			0x07f +#define	BZEBRA1_RXCOUNTER			0xc00 +#define	BZEBRA1_TXCHANGEPUMP			0x38 +#define	BZEBRA1_RXCHANGEPUMP			0x7 +#define	BZEBRA1_CHANNEL_NUM			0xf80 +#define	BZEBRA1_TXLPFBW				0x400 +#define	BZEBRA1_RXLPFBW				0x600 + +#define	BRTL8256REG_MODE_CTRL1			0x100 +#define	BRTL8256REG_MODE_CTRL0			0x40 +#define	BRTL8256REG_TXLPFBW			0x18 +#define	BRTL8256REG_RXLPFBW			0x600 + +#define	BRTL8258_TXLPFBW			0xc +#define	BRTL8258_RXLPFBW			0xc00 +#define	BRTL8258_RSSILPFBW			0xc0 + +#define	BBYTE0					0x1 +#define	BBYTE1					0x2 +#define	BBYTE2					0x4 +#define	BBYTE3					0x8 +#define	BWORD0					0x3 +#define	BWORD1					0xc +#define	BWORD					0xf + +#define	MASKBYTE0				0xff +#define	MASKBYTE1				0xff00 +#define	MASKBYTE2				0xff0000 +#define	MASKBYTE3				0xff000000 +#define	MASKHWORD				0xffff0000 +#define	MASKLWORD				0x0000ffff +#define	MASKDWORD				0xffffffff +#define	MASK12BITS				0xfff +#define	MASKH4BITS				0xf0000000 +#define MASKOFDM_D				0xffc00000 +#define	MASKCCK					0x3f3f3f3f + +#define	MASK4BITS				0x0f +#define	MASK20BITS				0xfffff +#define RFREG_OFFSET_MASK			0xfffff + +#define	BENABLE					0x1 +#define	BDISABLE				0x0 + +#define	LEFT_ANTENNA				0x0 +#define	RIGHT_ANTENNA				0x1 + +#define	TCHECK_TXSTATUS				500 +#define	TUPDATE_RXCOUNTER			100 + +#define	REG_UN_used_register			0x01bf + +/* WOL bit information */ +#define	HAL92C_WOL_PTK_UPDATE_EVENT		BIT(0) +#define	HAL92C_WOL_GTK_UPDATE_EVENT		BIT(1) +#define	HAL92C_WOL_DISASSOC_EVENT		BIT(2) +#define	HAL92C_WOL_DEAUTH_EVENT			BIT(3) +#define	HAL92C_WOL_FW_DISCONNECT_EVENT		BIT(4) + +#define WOL_REASON_PTK_UPDATE			BIT(0) +#define WOL_REASON_GTK_UPDATE			BIT(1) +#define WOL_REASON_DISASSOC			BIT(2) +#define WOL_REASON_DEAUTH			BIT(3) +#define WOL_REASON_FW_DISCONNECT		BIT(4) +#endif diff --git a/drivers/staging/rtl8192ee/rtl8192ee/rf.c b/drivers/staging/rtl8192ee/rtl8192ee/rf.c new file mode 100644 index 00000000000..4f5a49ebca1 --- /dev/null +++ b/drivers/staging/rtl8192ee/rtl8192ee/rf.c @@ -0,0 +1,150 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010  Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#include "../wifi.h" +#include "reg.h" +#include "def.h" +#include "phy.h" +#include "rf.h" +#include "dm.h" + +static bool _rtl92ee_phy_rf6052_config_parafile(struct ieee80211_hw *hw); + +void rtl92ee_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw, u8 bandwidth) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); + +	switch (bandwidth) { +	case HT_CHANNEL_WIDTH_20: +		rtlphy->rfreg_chnlval[0] = ((rtlphy->rfreg_chnlval[0] & +					     0xfffff3ff) | BIT(10) | BIT(11)); +		rtl_set_rfreg(hw, RF90_PATH_A, RF_CHNLBW, RFREG_OFFSET_MASK, +			      rtlphy->rfreg_chnlval[0]); +		rtl_set_rfreg(hw, RF90_PATH_B, RF_CHNLBW, RFREG_OFFSET_MASK, +			      rtlphy->rfreg_chnlval[0]); +		break; +	case HT_CHANNEL_WIDTH_20_40: +		rtlphy->rfreg_chnlval[0] = ((rtlphy->rfreg_chnlval[0] & +					     0xfffff3ff) | BIT(10)); +		rtl_set_rfreg(hw, RF90_PATH_A, RF_CHNLBW, RFREG_OFFSET_MASK, +			      rtlphy->rfreg_chnlval[0]); +		rtl_set_rfreg(hw, RF90_PATH_B, RF_CHNLBW, RFREG_OFFSET_MASK, +			      rtlphy->rfreg_chnlval[0]); +		break; +	default: +		RT_TRACE(COMP_ERR, DBG_EMERG, +			 ("unknown bandwidth: %#X\n", bandwidth)); +		break; +	} +} + +bool rtl92ee_phy_rf6052_config(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); + +	if (rtlphy->rf_type == RF_1T1R) +		rtlphy->num_total_rfpath = 1; +	else +		rtlphy->num_total_rfpath = 2; +	return _rtl92ee_phy_rf6052_config_parafile(hw); +} + +static bool _rtl92ee_phy_rf6052_config_parafile(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	u32 u4_regvalue = 0; +	u8 rfpath; +	bool rtstatus = true; +	struct bb_reg_def *pphyreg; + +	for (rfpath = 0; rfpath < rtlphy->num_total_rfpath; rfpath++) { +		pphyreg = &rtlphy->phyreg_def[rfpath]; + +		switch (rfpath) { +		case RF90_PATH_A: +		case RF90_PATH_C: +			u4_regvalue = rtl_get_bbreg(hw, pphyreg->rfintfs, +						    BRFSI_RFENV); +			break; +		case RF90_PATH_B: +		case RF90_PATH_D: +			u4_regvalue = rtl_get_bbreg(hw, pphyreg->rfintfs, +						    BRFSI_RFENV << 16); +			break; +		} + +		rtl_set_bbreg(hw, pphyreg->rfintfe, BRFSI_RFENV << 16, 0x1); +		udelay(1); + +		rtl_set_bbreg(hw, pphyreg->rfintfo, BRFSI_RFENV, 0x1); +		udelay(1); + +		rtl_set_bbreg(hw, pphyreg->rfhssi_para2, +			      B3WIREADDREAALENGTH, 0x0); +		udelay(1); + +		rtl_set_bbreg(hw, pphyreg->rfhssi_para2, B3WIREDATALENGTH, 0x0); +		udelay(1); + +		switch (rfpath) { +		case RF90_PATH_A: +			rtstatus = rtl92ee_phy_config_rf_with_headerfile(hw, +						       (enum radio_path)rfpath); +			break; +		case RF90_PATH_B: +			rtstatus = rtl92ee_phy_config_rf_with_headerfile(hw, +						       (enum radio_path)rfpath); +			break; +		case RF90_PATH_C: +			break; +		case RF90_PATH_D: +			break; +		} + +		switch (rfpath) { +		case RF90_PATH_A: +		case RF90_PATH_C: +			rtl_set_bbreg(hw, pphyreg->rfintfs, +				      BRFSI_RFENV, u4_regvalue); +			break; +		case RF90_PATH_B: +		case RF90_PATH_D: +			rtl_set_bbreg(hw, pphyreg->rfintfs, +				      BRFSI_RFENV << 16, u4_regvalue); +			break; +		} +		if (!rtstatus) { +			RT_TRACE(COMP_INIT, DBG_TRACE, +				 ("Radio[%d] Fail!!", rfpath)); +			return false; +		} +	} + +	RT_TRACE(COMP_INIT, DBG_TRACE, ("\n")); +	return rtstatus; +} diff --git a/drivers/staging/rtl8192ee/rtl8192ee/rf.h b/drivers/staging/rtl8192ee/rtl8192ee/rf.h new file mode 100644 index 00000000000..5bc394af476 --- /dev/null +++ b/drivers/staging/rtl8192ee/rtl8192ee/rf.h @@ -0,0 +1,39 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010  Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __RTL92E_RF_H__ +#define __RTL92E_RF_H__ + +#define RF6052_MAX_TX_PWR		0x3F +#define RF6052_MAX_REG			0x3F + +extern void rtl92ee_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw, +					     u8 bandwidth); +extern bool rtl92ee_phy_rf6052_config(struct ieee80211_hw *hw); +#endif diff --git a/drivers/staging/rtl8192ee/rtl8192ee/sw.c b/drivers/staging/rtl8192ee/rtl8192ee/sw.c new file mode 100644 index 00000000000..f9c5729e2cd --- /dev/null +++ b/drivers/staging/rtl8192ee/rtl8192ee/sw.c @@ -0,0 +1,428 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010  Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#include <linux/vmalloc.h> +#include <linux/module.h> + +#include "../wifi.h" +#include "../core.h" +#include "../pci.h" +#include "reg.h" +#include "def.h" +#include "phy.h" +#include "dm.h" +#include "hw.h" +#include "sw.h" +#include "fw.h" +#include "trx.h" +#include "led.h" +#include "table.h" + +#include "../btcoexist/rtl_btc.h" + + +static void rtl92ee_init_aspm_vars(struct ieee80211_hw *hw) +{ +	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + +	/*close ASPM for AMD defaultly */ +	rtlpci->const_amdpci_aspm = 0; + +	/* +	 * ASPM PS mode. +	 * 0 - Disable ASPM, +	 * 1 - Enable ASPM without Clock Req, +	 * 2 - Enable ASPM with Clock Req, +	 * 3 - Alwyas Enable ASPM with Clock Req, +	 * 4 - Always Enable ASPM without Clock Req. +	 * set defult to RTL8192CE:3 RTL8192E:2 +	 * */ +	rtlpci->const_pci_aspm = 3; + +	/*Setting for PCI-E device */ +	rtlpci->const_devicepci_aspm_setting = 0x03; + +	/*Setting for PCI-E bridge */ +	rtlpci->const_hostpci_aspm_setting = 0x02; + +	/* +	 * In Hw/Sw Radio Off situation. +	 * 0 - Default, +	 * 1 - From ASPM setting without low Mac Pwr, +	 * 2 - From ASPM setting with low Mac Pwr, +	 * 3 - Bus D3 +	 * set default to RTL8192CE:0 RTL8192SE:2 +	 */ +	rtlpci->const_hwsw_rfoff_d3 = 0; + +	/* +	 * This setting works for those device with +	 * backdoor ASPM setting such as EPHY setting. +	 * 0 - Not support ASPM, +	 * 1 - Support ASPM, +	 * 2 - According to chipset. +	 */ +	rtlpci->const_support_pciaspm = 1; +} + +int rtl92ee_init_sw_vars(struct ieee80211_hw *hw) +{ +	int err = 0; +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); +	const struct firmware *firmware; +	char *fw_name = NULL; + +	rtl92ee_bt_reg_init(hw); + +	rtlpci->msi_support = true; +	rtlpriv->btcoexist.btc_ops = stg_rtl_btc_get_ops_pointer(); + +	rtlpriv->dm.b_dm_initialgain_enable = 1; +	rtlpriv->dm.dm_flag = 0; +	rtlpriv->dm.b_disable_framebursting = 0; +	/*rtlpriv->dm.thermalvalue = 0;*/ +	rtlpci->transmit_config = CFENDFORM | BIT(15); + +	/*just 2.4G band*/ +	rtlpriv->rtlhal.current_bandtype = BAND_ON_2_4G; +	rtlpriv->rtlhal.bandset = BAND_ON_2_4G; +	rtlpriv->rtlhal.macphymode = SINGLEMAC_SINGLEPHY; + +	rtlpci->receive_config = (RCR_APPFCS			| +				  RCR_APP_MIC			| +				  RCR_APP_ICV			| +				  RCR_APP_PHYST_RXFF		| +				  RCR_HTC_LOC_CTRL		| +				  RCR_AMF			| +				  RCR_ACF			| +				  RCR_ADF			| +				  RCR_AICV			| +				  RCR_ACRC32			| +				  RCR_AB			| +				  RCR_AM			| +				  RCR_APM			| +				  0); + +	rtlpci->irq_mask[0] = (u32) (IMR_PSTIMEOUT		| +				/*   IMR_TBDER			| +				     IMR_TBDOK			| +				     IMR_BCNDMAINT0		|*/ +				     IMR_C2HCMD			| +				     IMR_HIGHDOK		| +				     IMR_MGNTDOK		| +				     IMR_BKDOK			| +				     IMR_BEDOK			| +				     IMR_VIDOK			| +				     IMR_VODOK			| +				     IMR_RDU			| +				     IMR_ROK			| +				     0); +	rtlpci->irq_mask[1] = (u32) (IMR_RXFOVW | 0); + +	/* for debug level */ +	rtlpriv->dbg.global_debuglevel = rtlpriv->cfg->mod_params->debug; +	/* for LPS & IPS */ +	rtlpriv->psc.b_inactiveps = rtlpriv->cfg->mod_params->b_inactiveps; +	rtlpriv->psc.b_swctrl_lps = rtlpriv->cfg->mod_params->b_swctrl_lps; +	rtlpriv->psc.b_fwctrl_lps = rtlpriv->cfg->mod_params->b_fwctrl_lps; +	rtlpriv->psc.b_reg_fwctrl_lps = 3; +	rtlpriv->psc.reg_max_lps_awakeintvl = 5; +	/* for ASPM, you can close aspm through +	 * set const_support_pciaspm = 0 */ +	rtl92ee_init_aspm_vars(hw); + +	if (rtlpriv->psc.b_reg_fwctrl_lps == 1) +		rtlpriv->psc.fwctrl_psmode = FW_PS_MIN_MODE; +	else if (rtlpriv->psc.b_reg_fwctrl_lps == 2) +		rtlpriv->psc.fwctrl_psmode = FW_PS_MAX_MODE; +	else if (rtlpriv->psc.b_reg_fwctrl_lps == 3) +		rtlpriv->psc.fwctrl_psmode = FW_PS_DTIM_MODE; + +	/* for early mode */ +	rtlpriv->rtlhal.b_earlymode_enable = false; + +	/*low power */ +	rtlpriv->psc.b_low_power_enable = false; + + +	/* for firmware buf */ +	rtlpriv->rtlhal.pfirmware = vmalloc(0x8000); +	if (!rtlpriv->rtlhal.pfirmware) { +		RT_TRACE(COMP_ERR, DBG_EMERG, +			 ("Can't alloc buffer for fw.\n")); +		return 1; +	} + +	fw_name = "rtlwifi/rtl8192eefw.bin"; +	err = request_firmware(&firmware, fw_name, rtlpriv->io.dev); + +	if (err) { +		RT_TRACE(COMP_ERR, DBG_EMERG, +			 ("Failed to request firmware!\n")); +		return 1; +	} +	if (firmware->size > 0x8000) { +		RT_TRACE(COMP_ERR, DBG_EMERG, +			 ("Firmware is too big!\n")); +		release_firmware(firmware); +		return 1; +	} +	memcpy(rtlpriv->rtlhal.pfirmware, firmware->data, firmware->size); +	rtlpriv->rtlhal.fwsize = firmware->size; +	release_firmware(firmware); + +	return err; +} + +void rtl92ee_deinit_sw_vars(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); + +	if (rtlpriv->rtlhal.pfirmware) { +		vfree(rtlpriv->rtlhal.pfirmware); +		rtlpriv->rtlhal.pfirmware = NULL; +	} +} + +/* get bt coexist status */ +bool rtl92ee_get_btc_status(void) +{ +	return true; +} + + +static struct rtl_hal_ops rtl8192ee_hal_ops = { +	.init_sw_vars = rtl92ee_init_sw_vars, +	.deinit_sw_vars = rtl92ee_deinit_sw_vars, +	.read_eeprom_info = rtl92ee_read_eeprom_info, +	.interrupt_recognized = rtl92ee_interrupt_recognized,/*need check*/ +	.hw_init = rtl92ee_hw_init, +	.hw_disable = rtl92ee_card_disable, +	.hw_suspend = rtl92ee_suspend, +	.hw_resume = rtl92ee_resume, +	.enable_interrupt = rtl92ee_enable_interrupt, +	.disable_interrupt = rtl92ee_disable_interrupt, +	.set_network_type = rtl92ee_set_network_type, +	.set_chk_bssid = rtl92ee_set_check_bssid, +	.set_qos = rtl92ee_set_qos, +	.set_bcn_reg = rtl92ee_set_beacon_related_registers, +	.set_bcn_intv = rtl92ee_set_beacon_interval, +	.update_interrupt_mask = rtl92ee_update_interrupt_mask, +	.get_hw_reg = rtl92ee_get_hw_reg, +	.set_hw_reg = rtl92ee_set_hw_reg, +	.update_rate_tbl = rtl92ee_update_hal_rate_tbl, +	.pre_fill_tx_bd_desc = rtl92ee_pre_fill_tx_bd_desc, +	.rx_desc_buff_remained_cnt = rtl92ee_rx_desc_buff_remained_cnt, +	.rx_check_dma_ok = rtl92ee_rx_check_dma_ok, +	.fill_tx_desc = rtl92ee_tx_fill_desc, +	.fill_tx_cmddesc = rtl92ee_tx_fill_cmddesc, +	.query_rx_desc = rtl92ee_rx_query_desc, +	.set_channel_access = rtl92ee_update_channel_access_setting, +	.radio_onoff_checking = rtl92ee_gpio_radio_on_off_checking, +	.set_bw_mode = rtl92ee_phy_set_bw_mode, +	.switch_channel = rtl92ee_phy_sw_chnl, +	.dm_watchdog = rtl92ee_dm_watchdog, +	.scan_operation_backup = rtl92ee_phy_scan_operation_backup, +	.set_rf_power_state = rtl92ee_phy_set_rf_power_state, +	.led_control = rtl92ee_led_control, +	.set_desc = rtl92ee_set_desc, +	.get_desc = rtl92ee_get_desc, +	.is_tx_desc_closed = rtl92ee_is_tx_desc_closed, +	.enable_hw_sec = rtl92ee_enable_hw_security_config, +	.set_key = rtl92ee_set_key, +	.init_sw_leds = rtl92ee_init_sw_leds, +	.allow_all_destaddr = rtl92ee_allow_all_destaddr, +	.get_bbreg = rtl92ee_phy_query_bb_reg, +	.set_bbreg = rtl92ee_phy_set_bb_reg, +	.get_rfreg = rtl92ee_phy_query_rf_reg, +	.set_rfreg = rtl92ee_phy_set_rf_reg, +	.fill_h2c_cmd = rtl92ee_fill_h2c_cmd, +	.get_btc_status = rtl92ee_get_btc_status, +	.rx_command_packet = rtl92ee_rx_command_packet, +}; + +static struct rtl_mod_params rtl92ee_mod_params = { +	.sw_crypto = false, +	.b_inactiveps = true, +	.b_swctrl_lps = false, +	.b_fwctrl_lps = true, +	.debug = DBG_EMERG, +}; + +static struct rtl_hal_cfg rtl92ee_hal_cfg = { +	.bar_id = 2, +	.write_readback = true, +	.name = "rtl92ee_pci", +	.fw_name = "rtlwifi/rtl8192eefw.bin", +	.ops = &rtl8192ee_hal_ops, +	.mod_params = &rtl92ee_mod_params, + +	.maps[SYS_ISO_CTRL] = REG_SYS_ISO_CTRL, +	.maps[SYS_FUNC_EN] = REG_SYS_FUNC_EN, +	.maps[SYS_CLK] = REG_SYS_CLKR, +	.maps[MAC_RCR_AM] = AM, +	.maps[MAC_RCR_AB] = AB, +	.maps[MAC_RCR_ACRC32] = ACRC32, +	.maps[MAC_RCR_ACF] = ACF, +	.maps[MAC_RCR_AAP] = AAP, +	.maps[MAC_HIMR] = REG_HIMR, +	.maps[MAC_HIMRE] = REG_HIMRE, + +	.maps[EFUSE_ACCESS] = REG_EFUSE_ACCESS, + +	.maps[EFUSE_TEST] = REG_EFUSE_TEST, +	.maps[EFUSE_CTRL] = REG_EFUSE_CTRL, +	.maps[EFUSE_CLK] = 0, +	.maps[EFUSE_CLK_CTRL] = REG_EFUSE_CTRL, +	.maps[EFUSE_PWC_EV12V] = PWC_EV12V, +	.maps[EFUSE_FEN_ELDR] = FEN_ELDR, +	.maps[EFUSE_LOADER_CLK_EN] = LOADER_CLK_EN, +	.maps[EFUSE_ANA8M] = ANA8M, +	.maps[EFUSE_HWSET_MAX_SIZE] = HWSET_MAX_SIZE, +	.maps[EFUSE_MAX_SECTION_MAP] = EFUSE_MAX_SECTION, +	.maps[EFUSE_REAL_CONTENT_SIZE] = EFUSE_REAL_CONTENT_LEN, +	.maps[EFUSE_OOB_PROTECT_BYTES_LEN] = EFUSE_OOB_PROTECT_BYTES, + +	.maps[RWCAM] = REG_CAMCMD, +	.maps[WCAMI] = REG_CAMWRITE, +	.maps[RCAMO] = REG_CAMREAD, +	.maps[CAMDBG] = REG_CAMDBG, +	.maps[SECR] = REG_SECCFG, +	.maps[SEC_CAM_NONE] = CAM_NONE, +	.maps[SEC_CAM_WEP40] = CAM_WEP40, +	.maps[SEC_CAM_TKIP] = CAM_TKIP, +	.maps[SEC_CAM_AES] = CAM_AES, +	.maps[SEC_CAM_WEP104] = CAM_WEP104, + +	.maps[RTL_IMR_BCNDMAINT6] = IMR_BCNDMAINT6, +	.maps[RTL_IMR_BCNDMAINT5] = IMR_BCNDMAINT5, +	.maps[RTL_IMR_BCNDMAINT4] = IMR_BCNDMAINT4, +	.maps[RTL_IMR_BCNDMAINT3] = IMR_BCNDMAINT3, +	.maps[RTL_IMR_BCNDMAINT2] = IMR_BCNDMAINT2, +	.maps[RTL_IMR_BCNDMAINT1] = IMR_BCNDMAINT1, +/*	.maps[RTL_IMR_BCNDOK8] = IMR_BCNDOK8,     */   /*need check*/ +	.maps[RTL_IMR_BCNDOK7] = IMR_BCNDOK7, +	.maps[RTL_IMR_BCNDOK6] = IMR_BCNDOK6, +	.maps[RTL_IMR_BCNDOK5] = IMR_BCNDOK5, +	.maps[RTL_IMR_BCNDOK4] = IMR_BCNDOK4, +	.maps[RTL_IMR_BCNDOK3] = IMR_BCNDOK3, +	.maps[RTL_IMR_BCNDOK2] = IMR_BCNDOK2, +	.maps[RTL_IMR_BCNDOK1] = IMR_BCNDOK1, +/*	.maps[RTL_IMR_TIMEOUT2] = IMR_TIMEOUT2,*/ +/*	.maps[RTL_IMR_TIMEOUT1] = IMR_TIMEOUT1,*/ + +	.maps[RTL_IMR_TXFOVW] = IMR_TXFOVW, +	.maps[RTL_IMR_PSTIMEOUT] = IMR_PSTIMEOUT, +	.maps[RTL_IMR_BcnInt] = IMR_BCNDMAINT0, +	.maps[RTL_IMR_RXFOVW] = IMR_RXFOVW, +	.maps[RTL_IMR_RDU] = IMR_RDU, +	.maps[RTL_IMR_ATIMEND] = IMR_ATIMEND, +	.maps[RTL_IMR_BDOK] = IMR_BCNDOK0, +	.maps[RTL_IMR_MGNTDOK] = IMR_MGNTDOK, +	.maps[RTL_IMR_TBDER] = IMR_TBDER, +	.maps[RTL_IMR_HIGHDOK] = IMR_HIGHDOK, +	.maps[RTL_IMR_TBDOK] = IMR_TBDOK, +	.maps[RTL_IMR_BKDOK] = IMR_BKDOK, +	.maps[RTL_IMR_BEDOK] = IMR_BEDOK, +	.maps[RTL_IMR_VIDOK] = IMR_VIDOK, +	.maps[RTL_IMR_VODOK] = IMR_VODOK, +	.maps[RTL_IMR_ROK] = IMR_ROK, +	.maps[RTL_IBSS_INT_MASKS] = (IMR_BCNDMAINT0 | IMR_TBDOK | IMR_TBDER), + +	.maps[RTL_RC_CCK_RATE1M] = DESC92C_RATE1M, +	.maps[RTL_RC_CCK_RATE2M] = DESC92C_RATE2M, +	.maps[RTL_RC_CCK_RATE5_5M] = DESC92C_RATE5_5M, +	.maps[RTL_RC_CCK_RATE11M] = DESC92C_RATE11M, +	.maps[RTL_RC_OFDM_RATE6M] = DESC92C_RATE6M, +	.maps[RTL_RC_OFDM_RATE9M] = DESC92C_RATE9M, +	.maps[RTL_RC_OFDM_RATE12M] = DESC92C_RATE12M, +	.maps[RTL_RC_OFDM_RATE18M] = DESC92C_RATE18M, +	.maps[RTL_RC_OFDM_RATE24M] = DESC92C_RATE24M, +	.maps[RTL_RC_OFDM_RATE36M] = DESC92C_RATE36M, +	.maps[RTL_RC_OFDM_RATE48M] = DESC92C_RATE48M, +	.maps[RTL_RC_OFDM_RATE54M] = DESC92C_RATE54M, + +	.maps[RTL_RC_HT_RATEMCS7] = DESC92C_RATEMCS7, +	.maps[RTL_RC_HT_RATEMCS15] = DESC92C_RATEMCS15, +}; + +static struct pci_device_id rtl92ee_pci_ids[] = { +	{RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x818B, rtl92ee_hal_cfg)}, +	{}, +}; + +MODULE_DEVICE_TABLE(pci, rtl92ee_pci_ids); + +MODULE_AUTHOR("Realtek WlanFAE	<wlanfae@realtek.com>"); +MODULE_AUTHOR("Larry Finger	<Larry.Finger@lwfinger.net>"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Realtek 8192E 802.11n PCI wireless"); +MODULE_FIRMWARE("rtlwifi/rtl8192eefw.bin"); + +module_param_named(swenc, rtl92ee_mod_params.sw_crypto, bool, 0444); +module_param_named(debug, rtl92ee_mod_params.debug, int, 0444); +module_param_named(ips, rtl92ee_mod_params.b_inactiveps, bool, 0444); +module_param_named(swlps, rtl92ee_mod_params.b_swctrl_lps, bool, 0444); +module_param_named(fwlps, rtl92ee_mod_params.b_fwctrl_lps, bool, 0444); +MODULE_PARM_DESC(swenc, "using hardware crypto (default 0 [hardware])\n"); +MODULE_PARM_DESC(ips, "using no link power save (default 1 is open)\n"); +MODULE_PARM_DESC(fwlps, "using linked fw control power save (default 1 is open)\n"); +MODULE_PARM_DESC(debug, "Set debug level (0-5) (default 0)"); + +static SIMPLE_DEV_PM_OPS(rtlwifi_pm_ops, stg_rtl_pci_suspend, +			 stg_rtl_pci_resume); + +static struct pci_driver rtl92ee_driver = { +	.name = KBUILD_MODNAME, +	.id_table = rtl92ee_pci_ids, +	.probe = stg_rtl_pci_probe, +	.remove = stg_rtl_pci_disconnect, + +	.driver.pm = &rtlwifi_pm_ops, +}; + +static int __init rtl92ee_module_init(void) +{ +	int ret; +	ret = rtl_core_module_init(); +	if (ret) +		return ret; + +	ret = pci_register_driver(&rtl92ee_driver); +	if (ret) +		RT_ASSERT(false, (": No device found\n")); + +	return ret; +} + +static void __exit rtl92ee_module_exit(void) +{ +	pci_unregister_driver(&rtl92ee_driver); +	rtl_core_module_exit(); +} + +module_init(rtl92ee_module_init); +module_exit(rtl92ee_module_exit); diff --git a/drivers/staging/rtl8192ee/rtl8192ee/sw.h b/drivers/staging/rtl8192ee/rtl8192ee/sw.h new file mode 100644 index 00000000000..0170257a20c --- /dev/null +++ b/drivers/staging/rtl8192ee/rtl8192ee/sw.h @@ -0,0 +1,39 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010  Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __RTL92E_SW_H__ +#define __RTL92E_SW_H__ + +int rtl92ee_init_sw_vars(struct ieee80211_hw *hw); +void rtl92ee_deinit_sw_vars(struct ieee80211_hw *hw); +bool rtl92ee_get_btc_status(void); +int rtl_core_module_init(void); +void rtl_core_module_exit(void); + +#endif diff --git a/drivers/staging/rtl8192ee/rtl8192ee/table.c b/drivers/staging/rtl8192ee/rtl8192ee/table.c new file mode 100644 index 00000000000..c7eb9be53cc --- /dev/null +++ b/drivers/staging/rtl8192ee/rtl8192ee/table.c @@ -0,0 +1,882 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010  Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Created on  2010/ 5/18,  1:41 + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#include "table.h" +u32 RTL8192EE_PHY_REG_ARRAY[] = { +		0x800, 0x80040000, +		0x804, 0x00000003, +		0x808, 0x0000FC00, +		0x80C, 0x0000000A, +		0x810, 0x10001331, +		0x814, 0x020C3D10, +		0x818, 0x02220385, +		0x81C, 0x00000000, +		0x820, 0x01000100, +		0x824, 0x00390204, +		0x828, 0x01000100, +		0x82C, 0x00390204, +		0x830, 0x32323232, +		0x834, 0x30303030, +		0x838, 0x30303030, +		0x83C, 0x30303030, +		0x840, 0x00010000, +		0x844, 0x00010000, +		0x848, 0x28282828, +		0x84C, 0x28282828, +		0x850, 0x00000000, +		0x854, 0x00000000, +		0x858, 0x009A009A, +		0x85C, 0x01000014, +		0x860, 0x66F60000, +		0x864, 0x061F0000, +		0x868, 0x30303030, +		0x86C, 0x30303030, +		0x870, 0x00000000, +		0x874, 0x55004200, +		0x878, 0x08080808, +		0x87C, 0x00000000, +		0x880, 0xB0000C1C, +		0x884, 0x00000001, +		0x888, 0x00000000, +		0x88C, 0xCC0000C0, +		0x890, 0x00000800, +		0x894, 0xFFFFFFFE, +		0x898, 0x40302010, +		0x900, 0x00000000, +		0x904, 0x00000023, +		0x908, 0x00000000, +		0x90C, 0x81121313, +		0x910, 0x806C0001, +		0x914, 0x00000001, +		0x918, 0x00000000, +		0x91C, 0x00010000, +		0x924, 0x00000001, +		0x928, 0x00000000, +		0x92C, 0x00000000, +		0x930, 0x00000000, +		0x934, 0x00000000, +		0x938, 0x00000000, +		0x93C, 0x00000000, +		0x940, 0x00000000, +		0x944, 0x00000000, +		0x94C, 0x00000008, +		0xA00, 0x00D0C7C8, +		0xA04, 0x81FF000C, +		0xA08, 0x8C838300, +		0xA0C, 0x2E68120F, +		0xA10, 0x95009B78, +		0xA14, 0x1114D028, +		0xA18, 0x00881117, +		0xA1C, 0x89140F00, +		0xA20, 0x1A1B0000, +		0xA24, 0x090E1317, +		0xA28, 0x00000204, +		0xA2C, 0x00D30000, +		0xA70, 0x101FBF00, +		0xA74, 0x00000007, +		0xA78, 0x00000900, +		0xA7C, 0x225B0606, +		0xA80, 0x218075B1, +		0xB38, 0x00000000, +		0xC00, 0x48071D40, +		0xC04, 0x03A05633, +		0xC08, 0x000000E4, +		0xC0C, 0x6C6C6C6C, +		0xC10, 0x08800000, +		0xC14, 0x40000100, +		0xC18, 0x08800000, +		0xC1C, 0x40000100, +		0xC20, 0x00000000, +		0xC24, 0x00000000, +		0xC28, 0x00000000, +		0xC2C, 0x00000000, +		0xC30, 0x69E9AC47, +		0xC34, 0x469652AF, +		0xC38, 0x49795994, +		0xC3C, 0x0A97971C, +		0xC40, 0x1F7C403F, +		0xC44, 0x000100B7, +		0xC48, 0xEC020107, +		0xC4C, 0x007F037F, +	0xFF010718, 0xABCD, +		0xC50, 0x00340220, +	0xCDCDCDCD, 0xCDCD, +		0xC50, 0x00340020, +	0xFF010718, 0xDEAD, +		0xC54, 0x0080801F, +	0xFF010718, 0xABCD, +		0xC58, 0x00000220, +	0xCDCDCDCD, 0xCDCD, +		0xC58, 0x00000020, +	0xFF010718, 0xDEAD, +		0xC5C, 0x00248492, +		0xC60, 0x00000000, +		0xC64, 0x7112848B, +		0xC68, 0x47C00BFF, +		0xC6C, 0x00000036, +		0xC70, 0x00000600, +		0xC74, 0x02013169, +		0xC78, 0x0000001F, +		0xC7C, 0x00B91612, +	0xFF010718, 0xABCD, +		0xC80, 0x2D4000B5, +	0xCDCDCDCD, 0xCDCD, +		0xC80, 0x40000100, +	0xFF010718, 0xDEAD, +		0xC84, 0x21F60000, +	0xFF010718, 0xABCD, +		0xC88, 0x2D4000B5, +	0xCDCDCDCD, 0xCDCD, +		0xC88, 0x40000100, +	0xFF010718, 0xDEAD, +		0xC8C, 0xA0E40000, +		0xC90, 0x00121820, +		0xC94, 0x00000000, +		0xC98, 0x00121820, +		0xC9C, 0x00007F7F, +		0xCA0, 0x00000000, +		0xCA4, 0x000300A0, +		0xCA8, 0x00000000, +		0xCAC, 0x00000000, +		0xCB0, 0x00000000, +		0xCB4, 0x00000000, +		0xCB8, 0x00000000, +		0xCBC, 0x28000000, +		0xCC0, 0x00000000, +		0xCC4, 0x00000000, +		0xCC8, 0x00000000, +		0xCCC, 0x00000000, +		0xCD0, 0x00000000, +		0xCD4, 0x00000000, +		0xCD8, 0x64B22427, +		0xCDC, 0x00766932, +		0xCE0, 0x00222222, +		0xCE4, 0x00040000, +		0xCE8, 0x77644302, +		0xCEC, 0x2F97D40C, +		0xD00, 0x00080740, +		0xD04, 0x00020403, +		0xD08, 0x0000907F, +		0xD0C, 0x20010201, +		0xD10, 0xA0633333, +		0xD14, 0x3333BC43, +		0xD18, 0x7A8F5B6B, +		0xD1C, 0x0000007F, +		0xD2C, 0xCC979975, +		0xD30, 0x00000000, +		0xD34, 0x80608000, +		0xD38, 0x00000000, +		0xD3C, 0x00127353, +		0xD40, 0x00000000, +		0xD44, 0x00000000, +		0xD48, 0x00000000, +		0xD4C, 0x00000000, +		0xD50, 0x6437140A, +		0xD54, 0x00000000, +		0xD58, 0x00000282, +		0xD5C, 0x30032064, +		0xD60, 0x4653DE68, +		0xD64, 0x04518A3C, +		0xD68, 0x00002101, +		0xD6C, 0x2A201C16, +		0xD70, 0x1812362E, +		0xD74, 0x322C2220, +		0xD78, 0x000E3C24, +		0xD80, 0x01081008, +		0xD84, 0x00000800, +		0xD88, 0xF0B50000, +		0xE00, 0x30303030, +		0xE04, 0x30303030, +		0xE08, 0x03903030, +		0xE10, 0x30303030, +		0xE14, 0x30303030, +		0xE18, 0x30303030, +		0xE1C, 0x30303030, +		0xE28, 0x00000000, +		0xE30, 0x1000DC1F, +		0xE34, 0x10008C1F, +		0xE38, 0x02140102, +		0xE3C, 0x681604C2, +		0xE40, 0x01007C00, +		0xE44, 0x01004800, +		0xE48, 0xFB000000, +		0xE4C, 0x000028D1, +		0xE50, 0x1000DC1F, +		0xE54, 0x10008C1F, +		0xE58, 0x02140102, +		0xE5C, 0x28160D05, +		0xE60, 0x00000008, +		0xE68, 0x0FC05656, +		0xE6C, 0x03C09696, +		0xE70, 0x03C09696, +		0xE74, 0x0C005656, +		0xE78, 0x0C005656, +		0xE7C, 0x0C005656, +		0xE80, 0x0C005656, +		0xE84, 0x03C09696, +		0xE88, 0x0C005656, +		0xE8C, 0x03C09696, +		0xED0, 0x03C09696, +		0xED4, 0x03C09696, +		0xED8, 0x03C09696, +		0xEDC, 0x0000D6D6, +		0xEE0, 0x0000D6D6, +		0xEEC, 0x0FC01616, +		0xEE4, 0xB0000C1C, +		0xEE8, 0x00000001, +		0xF14, 0x00000003, +		0xF4C, 0x00000000, +		0xF00, 0x00000300, +}; + +u32 RTL8192EE_PHY_REG_ARRAY_PG[] = { +	0, 0, 0, 0x00000e08, 0x0000ff00, 0x00003200, +	0, 0, 1, 0x00000e08, 0x0000ff00, 0x00003200, +	0, 0, 0, 0x0000086c, 0xffffff00, 0x32323200, +	0, 0, 1, 0x0000086c, 0xffffff00, 0x32323200, +	0, 0, 0, 0x00000e00, 0xffffffff, 0x34343636, +	0, 0, 1, 0x00000e00, 0xffffffff, 0x34343636, +	0, 0, 0, 0x00000e04, 0xffffffff, 0x28283032, +	0, 0, 1, 0x00000e04, 0xffffffff, 0x28283032, +	0, 0, 0, 0x00000e10, 0xffffffff, 0x34363840, +	0, 0, 1, 0x00000e10, 0xffffffff, 0x34363840, +	0, 0, 0, 0x00000e14, 0xffffffff, 0x26283032, +	0, 0, 1, 0x00000e14, 0xffffffff, 0x26283032, +	0, 0, 1, 0x00000e18, 0xffffffff, 0x36384040, +	0, 0, 1, 0x00000e1c, 0xffffffff, 0x24262832, +	0, 1, 0, 0x00000838, 0xffffff00, 0x32323200, +	0, 1, 1, 0x00000838, 0xffffff00, 0x32323200, +	0, 1, 0, 0x0000086c, 0x000000ff, 0x00000032, +	0, 1, 1, 0x0000086c, 0x000000ff, 0x00000032, +	0, 1, 0, 0x00000830, 0xffffffff, 0x34343636, +	0, 1, 1, 0x00000830, 0xffffffff, 0x34343636, +	0, 1, 0, 0x00000834, 0xffffffff, 0x28283032, +	0, 1, 1, 0x00000834, 0xffffffff, 0x28283032, +	0, 1, 0, 0x0000083c, 0xffffffff, 0x34363840, +	0, 1, 1, 0x0000083c, 0xffffffff, 0x34363840, +	0, 1, 0, 0x00000848, 0xffffffff, 0x26283032, +	0, 1, 1, 0x00000848, 0xffffffff, 0x26283032, +	0, 1, 1, 0x0000084c, 0xffffffff, 0x36384040, +	0, 1, 1, 0x00000868, 0xffffffff, 0x24262832 +}; + +u32 RTL8192EE_RADIOA_ARRAY[] = { +		0x07F, 0x00000082, +		0x081, 0x0003FC00, +		0x000, 0x00030000, +		0x008, 0x00008400, +		0x018, 0x00000407, +		0x019, 0x00000012, +		0x01B, 0x00000064, +		0x01E, 0x00080009, +		0x01F, 0x00000880, +		0x02F, 0x0001A060, +		0x03F, 0x00000000, +		0x042, 0x000060C0, +		0x057, 0x000D0000, +		0x058, 0x000BE180, +		0x067, 0x00001552, +		0x083, 0x00000000, +		0x0B0, 0x000FF9F1, +		0x0B1, 0x00055418, +		0x0B2, 0x0008CC00, +		0x0B4, 0x00043083, +		0x0B5, 0x00008166, +		0x0B6, 0x0000803E, +		0x0B7, 0x0001C69F, +		0x0B8, 0x0000407F, +		0x0B9, 0x00080001, +		0x0BA, 0x00040001, +		0x0BB, 0x00000400, +		0x0BF, 0x000C0000, +		0x0C2, 0x00002400, +		0x0C3, 0x00000009, +		0x0C4, 0x00040C91, +		0x0C5, 0x00099999, +		0x0C6, 0x000000A3, +		0x0C7, 0x00088820, +		0x0C8, 0x00076C06, +		0x0C9, 0x00000000, +		0x0CA, 0x00080000, +		0x0DF, 0x00000180, +		0x0EF, 0x000001A0, +		0x051, 0x00069545, +		0x052, 0x0007E45E, +		0x053, 0x00000071, +		0x056, 0x00051FF3, +		0x035, 0x000000A8, +		0x035, 0x000001E2, +		0x035, 0x000002A8, +		0x036, 0x00001C24, +		0x036, 0x00009C24, +		0x036, 0x00011C24, +		0x036, 0x00019C24, +		0x018, 0x00000C07, +		0x05A, 0x00048000, +		0x019, 0x000739D0, +	0xFF010718, 0xABCD, +		0x034, 0x0000A093, +		0x034, 0x0000908F, +		0x034, 0x0000808C, +		0x034, 0x0000704D, +		0x034, 0x0000604A, +		0x034, 0x00005047, +		0x034, 0x0000400A, +		0x034, 0x00003007, +		0x034, 0x00002004, +		0x034, 0x00001001, +		0x034, 0x00000000, +	0xCDCDCDCD, 0xCDCD, +		0x034, 0x0000ADD7, +		0x034, 0x00009DD4, +		0x034, 0x00008DD1, +		0x034, 0x00007DCE, +		0x034, 0x00006DCB, +		0x034, 0x00005DC8, +		0x034, 0x00004DC5, +		0x034, 0x000034CC, +		0x034, 0x0000244F, +		0x034, 0x0000144C, +		0x034, 0x00000014, +	0xFF010718, 0xDEAD, +		0x000, 0x00030159, +		0x084, 0x00068180, +		0x086, 0x0000014E, +		0x087, 0x00048E00, +		0x08E, 0x00065540, +		0x08F, 0x00088000, +		0x0EF, 0x000020A0, +	0xFF010718, 0xABCD, +		0x03B, 0x000F07B0, +	0xCDCDCDCD, 0xCDCD, +		0x03B, 0x000F02B0, +	0xFF010718, 0xDEAD, +		0x03B, 0x000EF7B0, +		0x03B, 0x000D4FB0, +		0x03B, 0x000CF060, +		0x03B, 0x000B0090, +		0x03B, 0x000A0080, +		0x03B, 0x00090080, +		0x03B, 0x0008F780, +	0xFF010718, 0xABCD, +		0x03B, 0x000787B0, +	0xCDCDCDCD, 0xCDCD, +		0x03B, 0x00078730, +	0xFF010718, 0xDEAD, +		0x03B, 0x00060FB0, +		0x03B, 0x0005FFA0, +		0x03B, 0x00040620, +		0x03B, 0x00037090, +		0x03B, 0x00020080, +		0x03B, 0x0001F060, +		0x03B, 0x0000FFB0, +		0x0EF, 0x000000A0, +		0x0FE, 0x00000000, +		0x018, 0x0000FC07, +		0x0FE, 0x00000000, +		0x0FE, 0x00000000, +		0x0FE, 0x00000000, +		0x0FE, 0x00000000, +		0x01E, 0x00000001, +		0x01F, 0x00080000, +		0x000, 0x00033E70, +}; + +u32 RTL8192EE_RADIOB_ARRAY[] = { +		0x07F, 0x00000082, +		0x081, 0x0003FC00, +		0x000, 0x00030000, +		0x008, 0x00008400, +		0x018, 0x00000407, +		0x019, 0x00000012, +		0x01B, 0x00000064, +		0x01E, 0x00080009, +		0x01F, 0x00000880, +		0x02F, 0x0001A060, +		0x03F, 0x00000000, +		0x042, 0x000060C0, +		0x057, 0x000D0000, +		0x058, 0x000BE180, +		0x067, 0x00001552, +		0x07F, 0x00000082, +		0x081, 0x0003F000, +		0x083, 0x00000000, +		0x0DF, 0x00000180, +		0x0EF, 0x000001A0, +		0x051, 0x00069545, +		0x052, 0x0007E42E, +		0x053, 0x00000071, +		0x056, 0x00051FF3, +		0x035, 0x000000A8, +		0x035, 0x000001E0, +		0x035, 0x000002A8, +		0x036, 0x00001CA8, +		0x036, 0x00009C24, +		0x036, 0x00011C24, +		0x036, 0x00019C24, +		0x018, 0x00000C07, +		0x05A, 0x00048000, +		0x019, 0x000739D0, +	0xFF010718, 0xABCD, +		0x034, 0x0000A093, +		0x034, 0x0000908F, +		0x034, 0x0000808C, +		0x034, 0x0000704D, +		0x034, 0x0000604A, +		0x034, 0x00005047, +		0x034, 0x0000400A, +		0x034, 0x00003007, +		0x034, 0x00002004, +		0x034, 0x00001001, +		0x034, 0x00000000, +	0xCDCDCDCD, 0xCDCD, +		0x034, 0x0000ADD7, +		0x034, 0x00009DD4, +		0x034, 0x00008DD1, +		0x034, 0x00007DCE, +		0x034, 0x00006DCB, +		0x034, 0x00005DC8, +		0x034, 0x00004DC5, +		0x034, 0x000034CC, +		0x034, 0x0000244F, +		0x034, 0x0000144C, +		0x034, 0x00000014, +	0xFF010718, 0xDEAD, +		0x000, 0x00030159, +		0x084, 0x00068180, +		0x086, 0x000000CE, +		0x087, 0x00048A00, +		0x08E, 0x00065540, +		0x08F, 0x00088000, +		0x0EF, 0x000020A0, +	0xFF010718, 0xABCD, +		0x03B, 0x000F07B0, +	0xCDCDCDCD, 0xCDCD, +		0x03B, 0x000F02B0, +	0xFF010718, 0xDEAD, +		0x03B, 0x000EF7B0, +		0x03B, 0x000D4FB0, +		0x03B, 0x000CF060, +		0x03B, 0x000B0090, +		0x03B, 0x000A0080, +		0x03B, 0x00090080, +		0x03B, 0x0008F780, +	0xFF010718, 0xABCD, +		0x03B, 0x000787B0, +	0xCDCDCDCD, 0xCDCD, +		0x03B, 0x00078730, +	0xFF010718, 0xDEAD, +		0x03B, 0x00060FB0, +		0x03B, 0x0005FFA0, +		0x03B, 0x00040620, +		0x03B, 0x00037090, +		0x03B, 0x00020080, +		0x03B, 0x0001F060, +		0x03B, 0x0000FFB0, +		0x0EF, 0x000000A0, +		0x000, 0x00010159, +		0x0FE, 0x00000000, +		0x0FE, 0x00000000, +		0x0FE, 0x00000000, +		0x0FE, 0x00000000, +		0x01E, 0x00000001, +		0x01F, 0x00080000, +		0x000, 0x00033E70, +}; + +u32 RTL8192EE_MAC_ARRAY[] = { +		0x011, 0x000000EB, +		0x012, 0x00000007, +		0x014, 0x00000075, +		0x303, 0x000000A7, +		0x428, 0x0000000A, +		0x429, 0x00000010, +		0x430, 0x00000000, +		0x431, 0x00000000, +		0x432, 0x00000000, +		0x433, 0x00000001, +		0x434, 0x00000004, +		0x435, 0x00000005, +		0x436, 0x00000007, +		0x437, 0x00000008, +		0x43C, 0x00000004, +		0x43D, 0x00000005, +		0x43E, 0x00000007, +		0x43F, 0x00000008, +		0x440, 0x0000005D, +		0x441, 0x00000001, +		0x442, 0x00000000, +		0x444, 0x00000010, +		0x445, 0x00000000, +		0x446, 0x00000000, +		0x447, 0x00000000, +		0x448, 0x00000000, +		0x449, 0x000000F0, +		0x44A, 0x0000000F, +		0x44B, 0x0000003E, +		0x44C, 0x00000010, +		0x44D, 0x00000000, +		0x44E, 0x00000000, +		0x44F, 0x00000000, +		0x450, 0x00000000, +		0x451, 0x000000F0, +		0x452, 0x0000000F, +		0x453, 0x00000000, +		0x456, 0x0000005E, +		0x460, 0x00000066, +		0x461, 0x00000066, +		0x4C8, 0x000000FF, +		0x4C9, 0x00000008, +		0x4CC, 0x000000FF, +		0x4CD, 0x000000FF, +		0x4CE, 0x00000001, +		0x500, 0x00000026, +		0x501, 0x000000A2, +		0x502, 0x0000002F, +		0x503, 0x00000000, +		0x504, 0x00000028, +		0x505, 0x000000A3, +		0x506, 0x0000005E, +		0x507, 0x00000000, +		0x508, 0x0000002B, +		0x509, 0x000000A4, +		0x50A, 0x0000005E, +		0x50B, 0x00000000, +		0x50C, 0x0000004F, +		0x50D, 0x000000A4, +		0x50E, 0x00000000, +		0x50F, 0x00000000, +		0x512, 0x0000001C, +		0x514, 0x0000000A, +		0x516, 0x0000000A, +		0x525, 0x0000004F, +		0x540, 0x00000012, +		0x541, 0x00000064, +		0x550, 0x00000010, +		0x551, 0x00000010, +		0x559, 0x00000002, +		0x55C, 0x00000050, +		0x55D, 0x000000FF, +		0x605, 0x00000030, +		0x608, 0x0000000E, +		0x609, 0x0000002A, +		0x620, 0x000000FF, +		0x621, 0x000000FF, +		0x622, 0x000000FF, +		0x623, 0x000000FF, +		0x624, 0x000000FF, +		0x625, 0x000000FF, +		0x626, 0x000000FF, +		0x627, 0x000000FF, +		0x638, 0x00000050, +		0x63C, 0x0000000A, +		0x63D, 0x0000000A, +		0x63E, 0x0000000E, +		0x63F, 0x0000000E, +		0x640, 0x00000040, +		0x642, 0x00000040, +		0x643, 0x00000000, +		0x652, 0x000000C8, +		0x66E, 0x00000005, +		0x700, 0x00000021, +		0x701, 0x00000043, +		0x702, 0x00000065, +		0x703, 0x00000087, +		0x708, 0x00000021, +		0x709, 0x00000043, +		0x70A, 0x00000065, +		0x70B, 0x00000087, +}; + +u32 RTL8192EE_AGC_TAB_ARRAY[] = { +	0xFF010718, 0xABCD, +		0xC78, 0xFA000001, +		0xC78, 0xF9010001, +		0xC78, 0xF8020001, +		0xC78, 0xF7030001, +		0xC78, 0xF6040001, +		0xC78, 0xF5050001, +		0xC78, 0xF4060001, +		0xC78, 0xF3070001, +		0xC78, 0xF2080001, +		0xC78, 0xF1090001, +		0xC78, 0xF00A0001, +		0xC78, 0xEF0B0001, +		0xC78, 0xEE0C0001, +		0xC78, 0xED0D0001, +		0xC78, 0xEC0E0001, +		0xC78, 0xEB0F0001, +		0xC78, 0xEA100001, +		0xC78, 0xE9110001, +		0xC78, 0xE8120001, +		0xC78, 0xE7130001, +		0xC78, 0xE6140001, +		0xC78, 0xE5150001, +		0xC78, 0xE4160001, +		0xC78, 0xE3170001, +		0xC78, 0xE2180001, +		0xC78, 0xE1190001, +		0xC78, 0x8A1A0001, +		0xC78, 0x891B0001, +		0xC78, 0x881C0001, +		0xC78, 0x871D0001, +		0xC78, 0x861E0001, +		0xC78, 0x851F0001, +		0xC78, 0x84200001, +		0xC78, 0x83210001, +		0xC78, 0x82220001, +		0xC78, 0x6A230001, +		0xC78, 0x69240001, +		0xC78, 0x68250001, +		0xC78, 0x67260001, +		0xC78, 0x66270001, +		0xC78, 0x65280001, +		0xC78, 0x64290001, +		0xC78, 0x632A0001, +		0xC78, 0x622B0001, +		0xC78, 0x612C0001, +		0xC78, 0x602D0001, +		0xC78, 0x472E0001, +		0xC78, 0x462F0001, +		0xC78, 0x45300001, +		0xC78, 0x44310001, +		0xC78, 0x43320001, +		0xC78, 0x42330001, +		0xC78, 0x41340001, +		0xC78, 0x40350001, +		0xC78, 0x40360001, +		0xC78, 0x40370001, +		0xC78, 0x40380001, +		0xC78, 0x40390001, +		0xC78, 0x403A0001, +		0xC78, 0x403B0001, +		0xC78, 0x403C0001, +		0xC78, 0x403D0001, +		0xC78, 0x403E0001, +		0xC78, 0x403F0001, +	0xCDCDCDCD, 0xCDCD, +		0xC78, 0xFB000001, +		0xC78, 0xFB010001, +		0xC78, 0xFB020001, +		0xC78, 0xFB030001, +		0xC78, 0xFB040001, +		0xC78, 0xFB050001, +		0xC78, 0xFA060001, +		0xC78, 0xF9070001, +		0xC78, 0xF8080001, +		0xC78, 0xF7090001, +		0xC78, 0xF60A0001, +		0xC78, 0xF50B0001, +		0xC78, 0xF40C0001, +		0xC78, 0xF30D0001, +		0xC78, 0xF20E0001, +		0xC78, 0xF10F0001, +		0xC78, 0xF0100001, +		0xC78, 0xEF110001, +		0xC78, 0xEE120001, +		0xC78, 0xED130001, +		0xC78, 0xEC140001, +		0xC78, 0xEB150001, +		0xC78, 0xEA160001, +		0xC78, 0xE9170001, +		0xC78, 0xE8180001, +		0xC78, 0xE7190001, +		0xC78, 0xC81A0001, +		0xC78, 0xC71B0001, +		0xC78, 0xC61C0001, +		0xC78, 0x071D0001, +		0xC78, 0x061E0001, +		0xC78, 0x051F0001, +		0xC78, 0x04200001, +		0xC78, 0x03210001, +		0xC78, 0xAA220001, +		0xC78, 0xA9230001, +		0xC78, 0xA8240001, +		0xC78, 0xA7250001, +		0xC78, 0xA6260001, +		0xC78, 0x85270001, +		0xC78, 0x84280001, +		0xC78, 0x83290001, +		0xC78, 0x252A0001, +		0xC78, 0x242B0001, +		0xC78, 0x232C0001, +		0xC78, 0x222D0001, +		0xC78, 0x672E0001, +		0xC78, 0x662F0001, +		0xC78, 0x65300001, +		0xC78, 0x64310001, +		0xC78, 0x63320001, +		0xC78, 0x62330001, +		0xC78, 0x61340001, +		0xC78, 0x45350001, +		0xC78, 0x44360001, +		0xC78, 0x43370001, +		0xC78, 0x42380001, +		0xC78, 0x41390001, +		0xC78, 0x403A0001, +		0xC78, 0x403B0001, +		0xC78, 0x403C0001, +		0xC78, 0x403D0001, +		0xC78, 0x403E0001, +		0xC78, 0x403F0001, +	0xFF010718, 0xDEAD, +	0xFF010718, 0xABCD, +		0xC78, 0xFA400001, +		0xC78, 0xF9410001, +		0xC78, 0xF8420001, +		0xC78, 0xF7430001, +		0xC78, 0xF6440001, +		0xC78, 0xF5450001, +		0xC78, 0xF4460001, +		0xC78, 0xF3470001, +		0xC78, 0xF2480001, +		0xC78, 0xF1490001, +		0xC78, 0xF04A0001, +		0xC78, 0xEF4B0001, +		0xC78, 0xEE4C0001, +		0xC78, 0xED4D0001, +		0xC78, 0xEC4E0001, +		0xC78, 0xEB4F0001, +		0xC78, 0xEA500001, +		0xC78, 0xE9510001, +		0xC78, 0xE8520001, +		0xC78, 0xE7530001, +		0xC78, 0xE6540001, +		0xC78, 0xE5550001, +		0xC78, 0xE4560001, +		0xC78, 0xE3570001, +		0xC78, 0xE2580001, +		0xC78, 0xE1590001, +		0xC78, 0x8A5A0001, +		0xC78, 0x895B0001, +		0xC78, 0x885C0001, +		0xC78, 0x875D0001, +		0xC78, 0x865E0001, +		0xC78, 0x855F0001, +		0xC78, 0x84600001, +		0xC78, 0x83610001, +		0xC78, 0x82620001, +		0xC78, 0x6A630001, +		0xC78, 0x69640001, +		0xC78, 0x68650001, +		0xC78, 0x67660001, +		0xC78, 0x66670001, +		0xC78, 0x65680001, +		0xC78, 0x64690001, +		0xC78, 0x636A0001, +		0xC78, 0x626B0001, +		0xC78, 0x616C0001, +		0xC78, 0x606D0001, +		0xC78, 0x476E0001, +		0xC78, 0x466F0001, +		0xC78, 0x45700001, +		0xC78, 0x44710001, +		0xC78, 0x43720001, +		0xC78, 0x42730001, +		0xC78, 0x41740001, +		0xC78, 0x40750001, +		0xC78, 0x40760001, +		0xC78, 0x40770001, +		0xC78, 0x40780001, +		0xC78, 0x40790001, +		0xC78, 0x407A0001, +		0xC78, 0x407B0001, +		0xC78, 0x407C0001, +		0xC78, 0x407D0001, +		0xC78, 0x407E0001, +		0xC78, 0x407F0001, +		0xC50, 0x00040222, +		0xC50, 0x00040220, +	0xCDCDCDCD, 0xCDCD, +		0xC78, 0xFB400001, +		0xC78, 0xFB410001, +		0xC78, 0xFB420001, +		0xC78, 0xFB430001, +		0xC78, 0xFB440001, +		0xC78, 0xFB450001, +		0xC78, 0xFA460001, +		0xC78, 0xF9470001, +		0xC78, 0xF8480001, +		0xC78, 0xF7490001, +		0xC78, 0xF64A0001, +		0xC78, 0xF54B0001, +		0xC78, 0xF44C0001, +		0xC78, 0xF34D0001, +		0xC78, 0xF24E0001, +		0xC78, 0xF14F0001, +		0xC78, 0xF0500001, +		0xC78, 0xEF510001, +		0xC78, 0xEE520001, +		0xC78, 0xED530001, +		0xC78, 0xEC540001, +		0xC78, 0xEB550001, +		0xC78, 0xEA560001, +		0xC78, 0xE9570001, +		0xC78, 0xE8580001, +		0xC78, 0xE7590001, +		0xC78, 0xE65A0001, +		0xC78, 0xE55B0001, +		0xC78, 0xE45C0001, +		0xC78, 0xE35D0001, +		0xC78, 0xE25E0001, +		0xC78, 0xE15F0001, +		0xC78, 0x8A600001, +		0xC78, 0x89610001, +		0xC78, 0x88620001, +		0xC78, 0x87630001, +		0xC78, 0x86640001, +		0xC78, 0x85650001, +		0xC78, 0x84660001, +		0xC78, 0x83670001, +		0xC78, 0x82680001, +		0xC78, 0x6B690001, +		0xC78, 0x6A6A0001, +		0xC78, 0x696B0001, +		0xC78, 0x686C0001, +		0xC78, 0x676D0001, +		0xC78, 0x666E0001, +		0xC78, 0x656F0001, +		0xC78, 0x64700001, +		0xC78, 0x63710001, +		0xC78, 0x62720001, +		0xC78, 0x61730001, +		0xC78, 0x49740001, +		0xC78, 0x48750001, +		0xC78, 0x47760001, +		0xC78, 0x46770001, +		0xC78, 0x45780001, +		0xC78, 0x44790001, +		0xC78, 0x437A0001, +		0xC78, 0x427B0001, +		0xC78, 0x417C0001, +		0xC78, 0x407D0001, +		0xC78, 0x407E0001, +		0xC78, 0x407F0001, +		0xC50, 0x00040022, +		0xC50, 0x00040020, +	0xFF010718, 0xDEAD, +}; diff --git a/drivers/staging/rtl8192ee/rtl8192ee/table.h b/drivers/staging/rtl8192ee/rtl8192ee/table.h new file mode 100644 index 00000000000..e0f419823b3 --- /dev/null +++ b/drivers/staging/rtl8192ee/rtl8192ee/table.h @@ -0,0 +1,48 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010  Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Created on  2010/ 5/18,  1:41 + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __RTL92E_TABLE__H_ +#define __RTL92E_TABLE__H_ + +#include <linux/types.h> +#define RTL8192EE_PHY_REG_ARRAY_LEN	448 +extern u32 RTL8192EE_PHY_REG_ARRAY[]; +#define RTL8192EE_PHY_REG_ARRAY_PG_LEN	168 +extern u32 RTL8192EE_PHY_REG_ARRAY_PG[]; +#define	RTL8192EE_RADIOA_ARRAY_LEN	238 +extern u32 RTL8192EE_RADIOA_ARRAY[]; +#define	RTL8192EE_RADIOB_ARRAY_LEN	198 +extern u32 RTL8192EE_RADIOB_ARRAY[]; +#define RTL8192EE_MAC_ARRAY_LEN		202 +extern u32 RTL8192EE_MAC_ARRAY[]; +#define RTL8192EE_AGC_TAB_ARRAY_LEN	532 +extern u32 RTL8192EE_AGC_TAB_ARRAY[]; +#endif diff --git a/drivers/staging/rtl8192ee/rtl8192ee/trx.c b/drivers/staging/rtl8192ee/rtl8192ee/trx.c new file mode 100644 index 00000000000..c930f52ec8c --- /dev/null +++ b/drivers/staging/rtl8192ee/rtl8192ee/trx.c @@ -0,0 +1,1286 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010  Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#include "../wifi.h" +#include "../pci.h" +#include "../base.h" +#include "../stats.h" +#include "reg.h" +#include "def.h" +#include "phy.h" +#include "trx.h" +#include "led.h" +#include "dm.h" +#include "fw.h" + +static u8 _rtl92ee_map_hwqueue_to_fwqueue(struct sk_buff *skb, u8 hw_queue) +{ +	__le16 fc = rtl_get_fc(skb); + +	if (unlikely(ieee80211_is_beacon(fc))) +		return QSLT_BEACON; +	if (ieee80211_is_mgmt(fc) || ieee80211_is_ctl(fc)) +		return QSLT_MGNT; + +	return skb->priority; +} + +/* mac80211's rate_idx is like this: + * + * 2.4G band:rx_status->band == IEEE80211_BAND_2GHZ + * + * B/G rate: + * (rx_status->flag & RX_FLAG_HT) = 0, + * DESC92C_RATE1M-->DESC92C_RATE54M ==> idx is 0-->11, + * + * N rate: + * (rx_status->flag & RX_FLAG_HT) = 1, + * DESC92C_RATEMCS0-->DESC92C_RATEMCS15 ==> idx is 0-->15 + * + * 5G band:rx_status->band == IEEE80211_BAND_5GHZ + * A rate: + * (rx_status->flag & RX_FLAG_HT) = 0, + * DESC92C_RATE6M-->DESC92C_RATE54M ==> idx is 0-->7, + * + * N rate: + * (rx_status->flag & RX_FLAG_HT) = 1, + * DESC92C_RATEMCS0-->DESC92C_RATEMCS15 ==> idx is 0-->15 + */ +static int _rtl92ee_rate_mapping(struct ieee80211_hw *hw, +				 bool isht, u8 desc_rate) +{ +	int rate_idx; + +	if (!false) { +		if (IEEE80211_BAND_2GHZ == hw->conf.chandef.chan->band) { +			switch (desc_rate) { +			case DESC92C_RATE1M: +				rate_idx = 0; +				break; +			case DESC92C_RATE2M: +				rate_idx = 1; +				break; +			case DESC92C_RATE5_5M: +				rate_idx = 2; +				break; +			case DESC92C_RATE11M: +				rate_idx = 3; +				break; +			case DESC92C_RATE6M: +				rate_idx = 4; +				break; +			case DESC92C_RATE9M: +				rate_idx = 5; +				break; +			case DESC92C_RATE12M: +				rate_idx = 6; +				break; +			case DESC92C_RATE18M: +				rate_idx = 7; +				break; +			case DESC92C_RATE24M: +				rate_idx = 8; +				break; +			case DESC92C_RATE36M: +				rate_idx = 9; +				break; +			case DESC92C_RATE48M: +				rate_idx = 10; +				break; +			case DESC92C_RATE54M: +				rate_idx = 11; +				break; +			default: +				rate_idx = 0; +				break; +			} +		} else { +			switch (desc_rate) { +			case DESC92C_RATE6M: +				rate_idx = 0; +				break; +			case DESC92C_RATE9M: +				rate_idx = 1; +				break; +			case DESC92C_RATE12M: +				rate_idx = 2; +				break; +			case DESC92C_RATE18M: +				rate_idx = 3; +				break; +			case DESC92C_RATE24M: +				rate_idx = 4; +				break; +			case DESC92C_RATE36M: +				rate_idx = 5; +				break; +			case DESC92C_RATE48M: +				rate_idx = 6; +				break; +			case DESC92C_RATE54M: +				rate_idx = 7; +				break; +			default: +				rate_idx = 0; +				break; +			} +		} +	} else { +		switch (desc_rate) { +		case DESC92C_RATEMCS0: +			rate_idx = 0; +			break; +		case DESC92C_RATEMCS1: +			rate_idx = 1; +			break; +		case DESC92C_RATEMCS2: +			rate_idx = 2; +			break; +		case DESC92C_RATEMCS3: +			rate_idx = 3; +			break; +		case DESC92C_RATEMCS4: +			rate_idx = 4; +			break; +		case DESC92C_RATEMCS5: +			rate_idx = 5; +			break; +		case DESC92C_RATEMCS6: +			rate_idx = 6; +			break; +		case DESC92C_RATEMCS7: +			rate_idx = 7; +			break; +		case DESC92C_RATEMCS8: +			rate_idx = 8; +			break; +		case DESC92C_RATEMCS9: +			rate_idx = 9; +			break; +		case DESC92C_RATEMCS10: +			rate_idx = 10; +			break; +		case DESC92C_RATEMCS11: +			rate_idx = 11; +			break; +		case DESC92C_RATEMCS12: +			rate_idx = 12; +			break; +		case DESC92C_RATEMCS13: +			rate_idx = 13; +			break; +		case DESC92C_RATEMCS14: +			rate_idx = 14; +			break; +		case DESC92C_RATEMCS15: +			rate_idx = 15; +			break; +		default: +			rate_idx = 0; +			break; +		} +	} +	return rate_idx; +} + +static void _rtl92ee_query_rxphystatus(struct ieee80211_hw *hw, +				       struct rtl_stats *pstatus, u8 *pdesc, +				       struct rx_fwinfo *p_drvinfo, +				       bool bpacket_match_bssid, +				       bool bpacket_toself, +				       bool b_packet_beacon) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct phy_status_rpt *p_phystrpt = (struct phy_status_rpt *)p_drvinfo; +	char rx_pwr_all = 0, rx_pwr[4]; +	u8 rf_rx_num = 0, evm, pwdb_all; +	u8 i, max_spatial_stream; +	u32 rssi, total_rssi = 0; +	bool b_is_cck = pstatus->b_is_cck; +	u8 lan_idx , vga_idx; + +	/* Record it for next packet processing */ +	pstatus->b_packet_matchbssid = bpacket_match_bssid; +	pstatus->b_packet_toself = bpacket_toself; +	pstatus->b_packet_beacon = b_packet_beacon; +	pstatus->rx_mimo_signalquality[0] = -1; +	pstatus->rx_mimo_signalquality[1] = -1; + +	if (b_is_cck) { +		u8 cck_highpwr; +		u8 cck_agc_rpt; +		/* CCK Driver info Structure is not the same as OFDM packet. */ +		cck_agc_rpt = p_phystrpt->cck_agc_rpt_ofdm_cfosho_a; + +		/* (1)Hardware does not provide RSSI for CCK */ +		/* (2)PWDB, Average PWDB cacluated by +		 * hardware (for rate adaptive) */ +		cck_highpwr = (u8) rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, +						 BIT(9)); + +		lan_idx = ((cck_agc_rpt & 0xE0) >> 5); +		vga_idx = (cck_agc_rpt & 0x1f); +		switch (lan_idx) { +		case 7: /*VGA_idx = 27~2*/ +				if (vga_idx <= 27) +					rx_pwr_all = -100 + 2 * (27 - vga_idx); +				else +					rx_pwr_all = -100; +				break; +		case 6: /*VGA_idx = 2~0*/ +				rx_pwr_all = -48 + 2 * (2 - vga_idx); +				break; +		case 5: /*VGA_idx = 7~5*/ +				rx_pwr_all = -42 + 2 * (7 - vga_idx); +				break; +		case 4: /*VGA_idx = 7~4*/ +				rx_pwr_all = -36 + 2 * (7 - vga_idx); +				break; +		case 3: /*VGA_idx = 7~0*/ +				rx_pwr_all = -24 + 2 * (7 - vga_idx); +				break; +		case 2: /*VGA_idx = 5~0*/ +				if (cck_highpwr) +					rx_pwr_all = -12 + 2 * (5 - vga_idx); +				else +					rx_pwr_all = -6 + 2 * (5 - vga_idx); +				break; +		case 1: +				rx_pwr_all = 8 - 2 * vga_idx; +				break; +		case 0: +				rx_pwr_all = 14 - 2 * vga_idx; +				break; +		default: +				break; +		} +		rx_pwr_all += 16; +		pwdb_all = stg_rtl_query_rxpwrpercentage(rx_pwr_all); + +		if (!cck_highpwr) { +			if (pwdb_all >= 80) +				pwdb_all = ((pwdb_all - 80) << 1) + +					   ((pwdb_all - 80) >> 1) + 80; +			else if ((pwdb_all <= 78) && (pwdb_all >= 20)) +				pwdb_all += 3; +			if (pwdb_all > 100) +				pwdb_all = 100; +		} + +		pstatus->rx_pwdb_all = pwdb_all; +		pstatus->bt_rx_rssi_percentage = pwdb_all; +		pstatus->recvsignalpower = rx_pwr_all; + +		/* (3) Get Signal Quality (EVM) */ +		if (bpacket_match_bssid) { +			u8 sq, sq_rpt; + +			if (pstatus->rx_pwdb_all > 40) { +				sq = 100; +			} else { +				sq_rpt = p_phystrpt->cck_sig_qual_ofdm_pwdb_all; +				if (sq_rpt > 64) +					sq = 0; +				else if (sq_rpt < 20) +					sq = 100; +				else +					sq = ((64 - sq_rpt) * 100) / 44; +			} + +			pstatus->signalquality = sq; +			pstatus->rx_mimo_signalquality[0] = sq; +			pstatus->rx_mimo_signalquality[1] = -1; +		} +	} else { +		/* (1)Get RSSI for HT rate */ +		for (i = RF90_PATH_A; i < RF6052_MAX_PATH; i++) { +			/* we will judge RF RX path now. */ +			if (rtlpriv->dm.brfpath_rxenable[i]) +				rf_rx_num++; + +			rx_pwr[i] = ((p_phystrpt->path_agc[i].gain & 0x3f) * 2) +				    - 110; + +			pstatus->rx_pwr[i] = rx_pwr[i]; +			/* Translate DBM to percentage. */ +			rssi = stg_rtl_query_rxpwrpercentage(rx_pwr[i]); +			total_rssi += rssi; + +			pstatus->rx_mimo_signalstrength[i] = (u8)rssi; +		} + +		/* (2)PWDB, Average PWDB cacluated by +		 * hardware (for rate adaptive) */ +		rx_pwr_all = ((p_phystrpt->cck_sig_qual_ofdm_pwdb_all >> 1) +			      & 0x7f) - 110; + +		pwdb_all = stg_rtl_query_rxpwrpercentage(rx_pwr_all); +		pstatus->rx_pwdb_all = pwdb_all; +		pstatus->bt_rx_rssi_percentage = pwdb_all; +		pstatus->rxpower = rx_pwr_all; +		pstatus->recvsignalpower = rx_pwr_all; + +		/* (3)EVM of HT rate */ +		if (pstatus->rate >= DESC92C_RATEMCS8 && +		    pstatus->rate <= DESC92C_RATEMCS15) +			max_spatial_stream = 2; +		else +			max_spatial_stream = 1; + +		for (i = 0; i < max_spatial_stream; i++) { +			evm = stg_rtl_evm_db_to_percentage( +						p_phystrpt->stream_rxevm[i]); + +			if (bpacket_match_bssid) { +				/* Fill value in RFD, Get the first +				 * spatial stream only */ +				if (i == 0) +					pstatus->signalquality = (u8)(evm & +								      0xff); +				pstatus->rx_mimo_signalquality[i] = (u8)(evm & +									 0xff); +			} +		} + +		if (bpacket_match_bssid) { +			for (i = RF90_PATH_A; i <= RF90_PATH_B; i++) +				rtl_priv(hw)->dm.cfo_tail[i] = +					(int)p_phystrpt->path_cfotail[i]; + +			if (rtl_priv(hw)->dm.packet_count == 0xffffffff) +				rtl_priv(hw)->dm.packet_count = 0; +			else +				rtl_priv(hw)->dm.packet_count++; +		} +	} + +	/* UI BSS List signal strength(in percentage), +	 * make it good looking, from 0~100. */ +	if (b_is_cck) +		pstatus->signalstrength = (u8)(stg_rtl_signal_scale_mapping(hw, +								     pwdb_all)); +	else if (rf_rx_num != 0) +		pstatus->signalstrength = (u8)(stg_rtl_signal_scale_mapping(hw, +						      total_rssi /= rf_rx_num)); +} + +static void _rtl92ee_translate_rx_signal_stuff(struct ieee80211_hw *hw, +					       struct sk_buff *skb, +					       struct rtl_stats *pstatus, +					       u8 *pdesc, +					       struct rx_fwinfo *p_drvinfo) +{ +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); +	struct ieee80211_hdr *hdr; +	u8 *tmp_buf; +	u8 *praddr; +	u8 *psaddr; +	__le16 fc; +	u16 cpu_fc, type; +	bool b_packet_matchbssid, b_packet_toself, b_packet_beacon; + +	tmp_buf = skb->data + pstatus->rx_drvinfo_size + +		  pstatus->rx_bufshift + 24; + +	hdr = (struct ieee80211_hdr *)tmp_buf; +	fc = hdr->frame_control; +	cpu_fc = le16_to_cpu(fc); +	type = WLAN_FC_GET_TYPE(fc); +	praddr = hdr->addr1; +	psaddr = ieee80211_get_SA(hdr); +	ether_addr_copy(pstatus->psaddr, psaddr); + +	b_packet_matchbssid = ((IEEE80211_FTYPE_CTL != type) && +			       (ether_addr_equal(mac->bssid, +						(cpu_fc & IEEE80211_FCTL_TODS) ? +						hdr->addr1 : +						(cpu_fc & IEEE80211_FCTL_FROMDS) ? +						hdr->addr2 : hdr->addr3)) && +				(!pstatus->b_hwerror) && (!pstatus->b_crc) && +				(!pstatus->b_icv)); + +	b_packet_toself = b_packet_matchbssid && +			 (ether_addr_equal(praddr, rtlefuse->dev_addr)); + +	if (ieee80211_is_beacon(fc)) +		b_packet_beacon = true; +	else +		b_packet_beacon = false; + +	if (b_packet_beacon && b_packet_matchbssid) +		rtl_priv(hw)->dm.dbginfo.num_qry_beacon_pkt++; + +	if (b_packet_matchbssid && ieee80211_is_data_qos(fc) && +	    !is_multicast_ether_addr(ieee80211_get_DA(hdr))) { +		struct ieee80211_qos_hdr *hdr_qos = +					    (struct ieee80211_qos_hdr *)tmp_buf; +		u16 tid = le16_to_cpu(hdr_qos->qos_ctrl) & 0xf; +		if (tid != 0 && tid != 3) +			rtl_priv(hw)->dm.dbginfo.num_non_be_pkt++; +	} +	_rtl92ee_query_rxphystatus(hw, pstatus, pdesc, p_drvinfo, +				   b_packet_matchbssid, b_packet_toself, +				   b_packet_beacon); +	stg_rtl_process_phyinfo(hw, tmp_buf, pstatus); +} + +static void _rtl92ee_insert_emcontent(struct rtl_tcb_desc *ptcb_desc, +				      u8 *virtualaddress) +{ +	u32 dwtmp = 0; +	memset(virtualaddress, 0, 8); + +	SET_EARLYMODE_PKTNUM(virtualaddress, ptcb_desc->empkt_num); +	if (ptcb_desc->empkt_num == 1) { +		dwtmp = ptcb_desc->empkt_len[0]; +	} else { +		dwtmp = ptcb_desc->empkt_len[0]; +		dwtmp += ((dwtmp % 4) ? (4 - dwtmp % 4) : 0) + 4; +		dwtmp += ptcb_desc->empkt_len[1]; +	} +	SET_EARLYMODE_LEN0(virtualaddress, dwtmp); + +	if (ptcb_desc->empkt_num <= 3) { +		dwtmp = ptcb_desc->empkt_len[2]; +	} else { +		dwtmp = ptcb_desc->empkt_len[2]; +		dwtmp += ((dwtmp % 4) ? (4 - dwtmp % 4) : 0) + 4; +		dwtmp += ptcb_desc->empkt_len[3]; +	} +	SET_EARLYMODE_LEN1(virtualaddress, dwtmp); +	if (ptcb_desc->empkt_num <= 5) { +		dwtmp = ptcb_desc->empkt_len[4]; +	} else { +		dwtmp = ptcb_desc->empkt_len[4]; +		dwtmp += ((dwtmp % 4) ? (4 - dwtmp % 4) : 0) + 4; +		dwtmp += ptcb_desc->empkt_len[5]; +	} +	SET_EARLYMODE_LEN2_1(virtualaddress, dwtmp & 0xF); +	SET_EARLYMODE_LEN2_2(virtualaddress, dwtmp >> 4); +	if (ptcb_desc->empkt_num <= 7) { +		dwtmp = ptcb_desc->empkt_len[6]; +	} else { +		dwtmp = ptcb_desc->empkt_len[6]; +		dwtmp += ((dwtmp % 4) ? (4 - dwtmp % 4) : 0) + 4; +		dwtmp += ptcb_desc->empkt_len[7]; +	} +	SET_EARLYMODE_LEN3(virtualaddress, dwtmp); +	if (ptcb_desc->empkt_num <= 9) { +		dwtmp = ptcb_desc->empkt_len[8]; +	} else { +		dwtmp = ptcb_desc->empkt_len[8]; +		dwtmp += ((dwtmp % 4) ? (4 - dwtmp % 4) : 0) + 4; +		dwtmp += ptcb_desc->empkt_len[9]; +	} +	SET_EARLYMODE_LEN4(virtualaddress, dwtmp); +} + +bool rtl92ee_rx_query_desc(struct ieee80211_hw *hw, +			   struct rtl_stats *status, +			   struct ieee80211_rx_status *rx_status, +			   u8 *pdesc, struct sk_buff *skb) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rx_fwinfo *p_drvinfo; +	struct ieee80211_hdr *hdr; + +	u32 phystatus = GET_RX_DESC_PHYST(pdesc); +	status->length = (u16) GET_RX_DESC_PKT_LEN(pdesc); +	status->rx_drvinfo_size = (u8) GET_RX_DESC_DRV_INFO_SIZE(pdesc) * +				  RX_DRV_INFO_SIZE_UNIT; +	status->rx_bufshift = (u8)(GET_RX_DESC_SHIFT(pdesc) & 0x03); +	status->b_icv = (u16) GET_RX_DESC_ICV(pdesc); +	status->b_crc = (u16) GET_RX_DESC_CRC32(pdesc); +	status->b_hwerror = (status->b_crc | status->b_icv); +	status->decrypted = !GET_RX_DESC_SWDEC(pdesc); +	status->rate = (u8) GET_RX_DESC_RXMCS(pdesc); +	status->b_isampdu = (bool)(GET_RX_DESC_PAGGR(pdesc) == 1); +		status->timestamp_low = GET_RX_DESC_TSFL(pdesc); +	status->b_is_cck = RX_HAL_IS_CCK_RATE(status->rate); + +	status->macid = GET_RX_DESC_MACID(pdesc); +	if (GET_RX_STATUS_DESC_MAGIC_MATCH(pdesc)) +		status->wake_match = BIT(2); +	else if (GET_RX_STATUS_DESC_MAGIC_MATCH(pdesc)) +		status->wake_match = BIT(1); +	else if (GET_RX_STATUS_DESC_UNICAST_MATCH(pdesc)) +		status->wake_match = BIT(0); +	else +		status->wake_match = 0; +	if (status->wake_match) +		RT_TRACE(COMP_RXDESC , DBG_LOUD, +			 ("GGGGGGGGGGGGGet Wakeup Packet!! WakeMatch =%d\n", +			 status->wake_match)); +	rx_status->freq = hw->conf.chandef.chan->center_freq; +	rx_status->band = hw->conf.chandef.chan->band; + +	hdr = (struct ieee80211_hdr *)(skb->data + status->rx_drvinfo_size + +				       status->rx_bufshift + 24); + +	if (status->b_crc) +		rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; + +	if (status->rx_is40Mhzpacket) +		rx_status->flag |= RX_FLAG_40MHZ; + +	if (status->b_is_ht) +		rx_status->flag |= RX_FLAG_HT; + +	rx_status->flag |= RX_FLAG_MACTIME_MPDU; + +	/* hw will set status->decrypted true, if it finds the +	 * frame is open data frame or mgmt frame. */ +	/* So hw will not decryption robust managment frame +	 * for IEEE80211w but still set status->decrypted +	 * true, so here we should set it back to undecrypted +	 * for IEEE80211w frame, and mac80211 sw will help +	 * to decrypt it */ +	if (status->decrypted) { +		if (!hdr) { +			WARN_ON_ONCE(true); +			pr_err("decrypted is true but hdr NULL, from skb %p\n", +			       rtl_get_hdr(skb)); +			return false; +		} + +		if ((!_ieee80211_is_robust_mgmt_frame(hdr)) && +		    (ieee80211_has_protected(hdr->frame_control))) +			rx_status->flag |= RX_FLAG_DECRYPTED; +		else +			rx_status->flag &= ~RX_FLAG_DECRYPTED; +	} + +	/* rate_idx: index of data rate into band's +	 * supported rates or MCS index if HT rates +	 * are use (RX_FLAG_HT)*/ +	/* Notice: this is diff with windows define */ +	rx_status->rate_idx = _rtl92ee_rate_mapping(hw, +						    status->b_is_ht, +						    status->rate); + +	rx_status->mactime = status->timestamp_low; +	if (phystatus) { +		p_drvinfo = (struct rx_fwinfo *)(skb->data + +						 status->rx_bufshift + 24); + +		_rtl92ee_translate_rx_signal_stuff(hw, skb, status, pdesc, +						   p_drvinfo); +	} + +	/*rx_status->qual = status->signal; */ +	rx_status->signal = status->recvsignalpower + 10; +	/*rx_status->noise = -status->noise; */ +	if (status->packet_report_type == TX_REPORT2) { +		status->macid_valid_entry[0] = +			GET_RX_RPT2_DESC_MACID_VALID_1(pdesc); +		status->macid_valid_entry[1] = +			GET_RX_RPT2_DESC_MACID_VALID_2(pdesc); +	} +	return true; +} + +/*in Windows, this == Rx_92EE_Interrupt*/ +void rtl92ee_rx_check_dma_ok(struct ieee80211_hw *hw, u8 *header_desc, +			     u8 queue_index) +{ +	u8 first_seg; +	u8 last_seg; +	u16 total_len; +	u16 read_cnt = 0; +	if (header_desc == NULL) +		return; + +	total_len = (u16)GET_RX_BUFFER_DESC_TOTAL_LENGTH(header_desc); + +	first_seg = (u8)GET_RX_BUFFER_DESC_FS(header_desc); + +	last_seg = (u8)GET_RX_BUFFER_DESC_LS(header_desc); + +	while (total_len == 0 && first_seg == 0 && last_seg == 0) { +		read_cnt++; +		total_len = (u16)GET_RX_BUFFER_DESC_TOTAL_LENGTH(header_desc); +		first_seg = (u8)GET_RX_BUFFER_DESC_FS(header_desc); +		last_seg = (u8)GET_RX_BUFFER_DESC_LS(header_desc); + +		if (read_cnt > 20) +			break; +	} +} + +u16 rtl92ee_rx_desc_buff_remained_cnt(struct ieee80211_hw *hw , u8 queue_index) +{ +	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u16 read_point = 0 , write_point = 0 , remind_cnt = 0; +	u32 tmp_4byte = 0; +	static u16 last_read_point; +	static bool start_rx; + +	tmp_4byte = rtl_read_dword(rtlpriv, REG_RXQ_TXBD_IDX); +	read_point = (u16)((tmp_4byte>>16) & 0x7ff); +	write_point = (u16)(tmp_4byte & 0x7ff); + +	if (write_point != rtlpci->rx_ring[queue_index].next_rx_rp) { +		RT_TRACE(COMP_RXDESC, DBG_DMESG, +			 ("!!!write point is 0x%x, reg 0x3B4 value is 0x%x\n", +			  write_point, tmp_4byte)); +		tmp_4byte = rtl_read_dword(rtlpriv, REG_RXQ_TXBD_IDX); +		read_point = (u16)((tmp_4byte>>16) & 0x7ff); +		write_point = (u16)(tmp_4byte & 0x7ff); +	} + +	if (read_point > 0) +		start_rx = true; +	if (!start_rx) +		return 0; + +	if ((last_read_point > (RX_DESC_NUM_92E / 2)) && +	    (read_point <= (RX_DESC_NUM_92E / 2))) { +		remind_cnt = RX_DESC_NUM_92E - write_point; +	} else { +		remind_cnt = (read_point >= write_point) ? +			     (read_point - write_point) : +			     (RX_DESC_NUM_92E - write_point + read_point); +	} + +	if (remind_cnt == 0) +		return 0; + +	rtlpci->rx_ring[queue_index].next_rx_rp = write_point; + +	last_read_point = read_point; +	return remind_cnt; +} + +static u16 get_desc_addr_fr_q(u16 queue_index) +{ +	u16 desc_address = REG_BEQ_TXBD_IDX; + +	switch (queue_index) { +	case BK_QUEUE: +			desc_address = REG_BKQ_TXBD_IDX; +			break; +	case BE_QUEUE: +			desc_address = REG_BEQ_TXBD_IDX; +			break; +	case VI_QUEUE: +			desc_address = REG_VIQ_TXBD_IDX; +			break; +	case VO_QUEUE: +			desc_address = REG_VOQ_TXBD_IDX; +			break; +	case BEACON_QUEUE: +			desc_address = REG_BEQ_TXBD_IDX; +			break; +	case TXCMD_QUEUE: +			desc_address = REG_BEQ_TXBD_IDX; +			break; +	case MGNT_QUEUE: +			desc_address = REG_MGQ_TXBD_IDX; +			break; +	case HIGH_QUEUE: +			desc_address = REG_HI0Q_TXBD_IDX; +			break; +	case HCCA_QUEUE: +			desc_address = REG_BEQ_TXBD_IDX; +			break; +	default: +			break; +	} +	return desc_address; +} + +void rtl92ee_get_available_desc(struct ieee80211_hw *hw , u8 q_idx) +{ +	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u16 point_diff = 0; +	u16 current_tx_read_point = 0, current_tx_write_point = 0; +	u32 tmp_4byte; +	tmp_4byte = rtl_read_dword(rtlpriv, +				   get_desc_addr_fr_q(q_idx)); +	current_tx_read_point = (u16)((tmp_4byte >> 16) & 0x0fff); +	current_tx_write_point = (u16)((tmp_4byte) & 0x0fff); + +	point_diff = ((current_tx_read_point > current_tx_write_point) ? +		      (current_tx_read_point - current_tx_write_point) : +		      (TX_DESC_NUM_92E - current_tx_write_point + +		       current_tx_read_point)); + +	rtlpci->tx_ring[q_idx].avl_desc = point_diff; +} + +void rtl92ee_pre_fill_tx_bd_desc(struct ieee80211_hw *hw, +				 u8 *tx_bd_desc, u8 *desc, u8 queue_index, +				 struct sk_buff *skb, dma_addr_t addr) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); +	u32 pkt_len = skb->len; +	u16 desc_size = 40; /*tx desc size*/ +	u32 psblen = 0; +	u16 tx_page_size = 0; +	u32 total_packet_size = 0; +	u16 current_bd_desc; +	u8 i = 0; +	u16 real_desc_size = 0x28; +	u16	append_early_mode_size = 0; +#if (RTL8192EE_SEG_NUM == 0) +	u8 segmentnum = 2; +#elif (RTL8192EE_SEG_NUM == 1) +	u8 segmentnum = 4; +#elif (RTL8192EE_SEG_NUM == 2) +	u8 segmentnum = 8; +#endif + +	tx_page_size = 2; +	current_bd_desc = rtlpci->tx_ring[queue_index].cur_tx_wp; + + +	total_packet_size = desc_size+pkt_len; + +	if (rtlpriv->rtlhal.b_earlymode_enable)	{ +		if (queue_index < BEACON_QUEUE) { +			append_early_mode_size = 8; +			total_packet_size += append_early_mode_size; +		} +	} + +	if (tx_page_size > 0) { +		psblen = (pkt_len + real_desc_size + append_early_mode_size) / +			 (tx_page_size * 128); + +		if (psblen * (tx_page_size * 128) < total_packet_size) +			psblen += 1; +	} + +	/* Reset */ +	SET_TX_BUFF_DESC_LEN_0(tx_bd_desc , 0); +	SET_TX_BUFF_DESC_PSB(tx_bd_desc , 0); +	SET_TX_BUFF_DESC_OWN(tx_bd_desc , 0); + +	for (i = 1; i < segmentnum; i++) { +		SET_TXBUFFER_DESC_LEN_WITH_OFFSET(tx_bd_desc, i, 0); +		SET_TXBUFFER_DESC_AMSDU_WITH_OFFSET(tx_bd_desc, i, 0); +		SET_TXBUFFER_DESC_ADD_LOW_WITH_OFFSET(tx_bd_desc, i, 0); +#if (DMA_IS_64BIT == 1) +		SET_TXBUFFER_DESC_ADD_HIGT_WITH_OFFSET(tx_bd_desc, i, 0); +#endif +	} +	SET_TX_BUFF_DESC_LEN_1(tx_bd_desc, 0); +	SET_TX_BUFF_DESC_AMSDU_1(tx_bd_desc, 0); + +	SET_TX_BUFF_DESC_LEN_2(tx_bd_desc, 0); +	SET_TX_BUFF_DESC_AMSDU_2(tx_bd_desc, 0); +	SET_TX_BUFF_DESC_LEN_3(tx_bd_desc, 0); +	SET_TX_BUFF_DESC_AMSDU_3(tx_bd_desc, 0); +	/* Clear all status */ +	CLEAR_PCI_TX_DESC_CONTENT(desc, TX_DESC_SIZE); + +	if (rtlpriv->rtlhal.b_earlymode_enable) { +		if (queue_index < BEACON_QUEUE) { +			/* These macros need braces */ +			SET_TX_BUFF_DESC_LEN_0(tx_bd_desc , desc_size + 8); +		} else { +			SET_TX_BUFF_DESC_LEN_0(tx_bd_desc , desc_size); +		} +	} else { +		SET_TX_BUFF_DESC_LEN_0(tx_bd_desc , desc_size); +	} +	SET_TX_BUFF_DESC_PSB(tx_bd_desc , psblen); +	SET_TX_BUFF_DESC_ADDR_LOW_0(tx_bd_desc, +				    rtlpci->tx_ring[queue_index].dma + +				    (current_bd_desc * TX_DESC_SIZE)); + +	SET_TXBUFFER_DESC_LEN_WITH_OFFSET(tx_bd_desc, 1, pkt_len); +	/* don't using extendsion mode. */ +	SET_TXBUFFER_DESC_AMSDU_WITH_OFFSET(tx_bd_desc, 1, 0); +	SET_TXBUFFER_DESC_ADD_LOW_WITH_OFFSET(tx_bd_desc, 1, addr); + +	SET_TX_DESC_PKT_SIZE(desc, (u16)(pkt_len)); +	SET_TX_DESC_TX_BUFFER_SIZE(desc, (u16)(pkt_len)); +} + +void rtl92ee_tx_fill_desc(struct ieee80211_hw *hw, +			  struct ieee80211_hdr *hdr, u8 *pdesc_tx, +			  u8 *pbd_desc_tx, +			  struct ieee80211_tx_info *info, +			  struct ieee80211_sta *sta, +			  struct sk_buff *skb, +			  u8 hw_queue, struct rtl_tcb_desc *ptcb_desc) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); +	struct rtl_hal *rtlhal = rtl_hal(rtlpriv); +	u8 *pdesc = (u8 *)pdesc_tx; +	u16 seq_number; +	__le16 fc = hdr->frame_control; +	unsigned int buf_len = 0; +	u8 fw_qsel = _rtl92ee_map_hwqueue_to_fwqueue(skb, hw_queue); +	bool b_firstseg = ((hdr->seq_ctrl & +			    cpu_to_le16(IEEE80211_SCTL_FRAG)) == 0); +	bool b_lastseg = ((hdr->frame_control & +			   cpu_to_le16(IEEE80211_FCTL_MOREFRAGS)) == 0); +	dma_addr_t mapping; +	u8 bw_40 = 0; +	u8 short_gi = 0; + +	if (mac->opmode == NL80211_IFTYPE_STATION) { +		bw_40 = mac->bw_40; +	} else if (mac->opmode == NL80211_IFTYPE_AP || +		   mac->opmode == NL80211_IFTYPE_ADHOC) { +		if (sta) +			bw_40 = sta->ht_cap.cap & +				IEEE80211_HT_CAP_SUP_WIDTH_20_40; +	} +	seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4; +	stg_rtl_get_tcb_desc(hw, info, sta, skb, ptcb_desc); +	/* reserve 8 byte for AMPDU early mode */ +	if (rtlhal->b_earlymode_enable) { +		skb_push(skb, EM_HDR_LEN); +		memset(skb->data, 0, EM_HDR_LEN); +	} +	buf_len = skb->len; +	mapping = pci_map_single(rtlpci->pdev, skb->data, skb->len, +				 PCI_DMA_TODEVICE); +	if (pci_dma_mapping_error(rtlpci->pdev, mapping)) { +		RT_TRACE(COMP_SEND, DBG_TRACE, +			 ("DMA mapping error")); +		return; +	} +	if (pbd_desc_tx != NULL) +		rtl92ee_pre_fill_tx_bd_desc(hw, pbd_desc_tx, pdesc, hw_queue, +					    skb, mapping); + +	if (ieee80211_is_nullfunc(fc) || ieee80211_is_ctl(fc)) { +		b_firstseg = true; +		b_lastseg = true; +	} +	if (b_firstseg) { +		if (rtlhal->b_earlymode_enable) { +			SET_TX_DESC_PKT_OFFSET(pdesc, 1); +			SET_TX_DESC_OFFSET(pdesc, +					   USB_HWDESC_HEADER_LEN + EM_HDR_LEN); +			if (ptcb_desc->empkt_num) { +				RT_TRACE(COMP_SEND, DBG_TRACE, +					 ("Insert 8 byte.pTcb->EMPktNum:%d\n", +					  ptcb_desc->empkt_num)); +				_rtl92ee_insert_emcontent(ptcb_desc, +							  (u8 *)(skb->data)); +			} +		} else { +			SET_TX_DESC_OFFSET(pdesc, USB_HWDESC_HEADER_LEN); +		} + +		SET_TX_DESC_TX_RATE(pdesc, ptcb_desc->hw_rate); + +		if (ieee80211_is_mgmt(fc)) { +			ptcb_desc->use_driver_rate = true; +		} else { +			if (rtlpriv->ra.is_special_data) { +				ptcb_desc->use_driver_rate = true; +				SET_TX_DESC_TX_RATE(pdesc, DESC92C_RATE11M); +			} else { +				ptcb_desc->use_driver_rate = false; +			} +		} + +		if (ptcb_desc->hw_rate > DESC92C_RATEMCS0) +			short_gi = (ptcb_desc->use_shortgi) ? 1 : 0; +		else +			short_gi = (ptcb_desc->use_shortpreamble) ? 1 : 0; + +		if (info->flags & IEEE80211_TX_CTL_AMPDU) { +			SET_TX_DESC_AGG_ENABLE(pdesc, 1); +			SET_TX_DESC_MAX_AGG_NUM(pdesc, 0x14); +		} +		SET_TX_DESC_SEQ(pdesc, seq_number); +		SET_TX_DESC_RTS_ENABLE(pdesc, +				       ((ptcb_desc->b_rts_enable && +					 !ptcb_desc->b_cts_enable) ? 1 : 0)); +		SET_TX_DESC_HW_RTS_ENABLE(pdesc , 0); +		SET_TX_DESC_CTS2SELF(pdesc, +				     ((ptcb_desc->b_cts_enable) ? 1 : 0)); + +		SET_TX_DESC_RTS_RATE(pdesc, ptcb_desc->rts_rate); +		SET_TX_DESC_RTS_SC(pdesc, ptcb_desc->rts_sc); +		SET_TX_DESC_RTS_SHORT(pdesc, +				((ptcb_desc->rts_rate <= DESC92C_RATE54M) ? +				 (ptcb_desc->b_rts_use_shortpreamble ? 1 : 0) : +				 (ptcb_desc->b_rts_use_shortgi ? 1 : 0))); + +		if (ptcb_desc->btx_enable_sw_calc_duration) +			SET_TX_DESC_NAV_USE_HDR(pdesc, 1); + +		if (bw_40) { +			if (ptcb_desc->packet_bw == HT_CHANNEL_WIDTH_20_40) { +				SET_TX_DESC_DATA_BW(pdesc, 1); +				SET_TX_DESC_TX_SUB_CARRIER(pdesc, 3); +			} else { +				SET_TX_DESC_DATA_BW(pdesc, 0); +				SET_TX_DESC_TX_SUB_CARRIER(pdesc, +							   mac->cur_40_prime_sc); +			} +		} else { +			SET_TX_DESC_DATA_BW(pdesc, 0); +			SET_TX_DESC_TX_SUB_CARRIER(pdesc, 0); +		} + +		SET_TX_DESC_LINIP(pdesc, 0); +		if (sta) { +			u8 ampdu_density = sta->ht_cap.ampdu_density; +			SET_TX_DESC_AMPDU_DENSITY(pdesc, ampdu_density); +		} +		if (info->control.hw_key) { +			struct ieee80211_key_conf *key = info->control.hw_key; +			switch (key->cipher) { +			case WLAN_CIPHER_SUITE_WEP40: +			case WLAN_CIPHER_SUITE_WEP104: +			case WLAN_CIPHER_SUITE_TKIP: +				SET_TX_DESC_SEC_TYPE(pdesc, 0x1); +				break; +			case WLAN_CIPHER_SUITE_CCMP: +				SET_TX_DESC_SEC_TYPE(pdesc, 0x3); +				break; +			default: +				SET_TX_DESC_SEC_TYPE(pdesc, 0x0); +				break; +			} +		} + +		SET_TX_DESC_QUEUE_SEL(pdesc, fw_qsel); +		SET_TX_DESC_DATA_RATE_FB_LIMIT(pdesc, 0x1F); +		SET_TX_DESC_RTS_RATE_FB_LIMIT(pdesc, 0xF); +		SET_TX_DESC_DISABLE_FB(pdesc, +				       ptcb_desc->disable_ratefallback ? 1 : 0); +		SET_TX_DESC_USE_RATE(pdesc, ptcb_desc->use_driver_rate ? 1 : 0); + +		/*SET_TX_DESC_PWR_STATUS(pdesc, pwr_status);*/ +		/* Set TxRate and RTSRate in TxDesc  */ +		/* This prevent Tx initial rate of new-coming packets */ +		/* from being overwritten by retried  packet rate.*/ +		if (!ptcb_desc->use_driver_rate) { +			/*SET_TX_DESC_RTS_RATE(pdesc, 0x08); */ +			/* SET_TX_DESC_TX_RATE(pdesc, 0x0b); */ +		} +		if (ieee80211_is_data_qos(fc)) { +			if (mac->rdg_en) { +				RT_TRACE(COMP_SEND, DBG_TRACE, +					 ("Enable RDG function.\n")); +				SET_TX_DESC_RDG_ENABLE(pdesc, 1); +				SET_TX_DESC_HTC(pdesc, 1); +			} +		} +	} + +	SET_TX_DESC_FIRST_SEG(pdesc, (b_firstseg ? 1 : 0)); +	SET_TX_DESC_LAST_SEG(pdesc, (b_lastseg ? 1 : 0)); +	SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, mapping); +	if (rtlpriv->dm.b_useramask) { +		SET_TX_DESC_RATE_ID(pdesc, ptcb_desc->ratr_index); +		SET_TX_DESC_MACID(pdesc, ptcb_desc->mac_id); +	} else { +		SET_TX_DESC_RATE_ID(pdesc, 0xC + ptcb_desc->ratr_index); +		SET_TX_DESC_MACID(pdesc, ptcb_desc->ratr_index); +	} + +	SET_TX_DESC_MORE_FRAG(pdesc, (b_lastseg ? 0 : 1)); +	if (is_multicast_ether_addr(ieee80211_get_DA(hdr)) || +	    is_broadcast_ether_addr(ieee80211_get_DA(hdr))) { +		SET_TX_DESC_BMC(pdesc, 1); +	} +	RT_TRACE(COMP_SEND, DBG_TRACE, ("\n")); +} + +void rtl92ee_tx_fill_cmddesc(struct ieee80211_hw *hw, +			     u8 *pdesc, bool b_firstseg, +			     bool b_lastseg, struct sk_buff *skb) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); +	u8 fw_queue = QSLT_BEACON; + +	dma_addr_t mapping = pci_map_single(rtlpci->pdev, +					    skb->data, skb->len, +					    PCI_DMA_TODEVICE); + + +	u8 txdesc_len = 40; + +	if (pci_dma_mapping_error(rtlpci->pdev, mapping)) { +		RT_TRACE(COMP_SEND, DBG_TRACE, +			 ("DMA mapping error")); +		return; +	} +	CLEAR_PCI_TX_DESC_CONTENT(pdesc, txdesc_len); + +	if (b_firstseg) +		SET_TX_DESC_OFFSET(pdesc, txdesc_len); + +	SET_TX_DESC_TX_RATE(pdesc, DESC92C_RATE1M); + +	SET_TX_DESC_SEQ(pdesc, 0); + +	SET_TX_DESC_LINIP(pdesc, 0); + +	SET_TX_DESC_QUEUE_SEL(pdesc, fw_queue); + +	SET_TX_DESC_FIRST_SEG(pdesc, 1); +	SET_TX_DESC_LAST_SEG(pdesc, 1); + +	SET_TX_DESC_TX_BUFFER_SIZE(pdesc, (u16)(skb->len)); + +	SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, mapping); + +	SET_TX_DESC_RATE_ID(pdesc, 7); +	SET_TX_DESC_MACID(pdesc, 0); + +	SET_TX_DESC_OWN(pdesc, 1); + +	SET_TX_DESC_PKT_SIZE((u8 *)pdesc, (u16)(skb->len)); + +	SET_TX_DESC_FIRST_SEG(pdesc, 1); +	SET_TX_DESC_LAST_SEG(pdesc, 1); + +	SET_TX_DESC_OFFSET(pdesc, 40); + +	SET_TX_DESC_USE_RATE(pdesc, 1); + +	RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD, +		      "H2C Tx Cmd Content\n", pdesc, txdesc_len); +} + + +void rtl92ee_set_desc(struct ieee80211_hw *hw, u8 *pdesc, bool istx, +		      u8 desc_name, u8 *val) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u16 cur_tx_rp = 0; +	u16 cur_tx_wp = 0; +	static u16 last_txw_point; +	static bool over_run; +	u32 tmp = 0; +	u8 q_idx = *val; + +	if (istx) { +		switch (desc_name) { +		case HW_DESC_TX_NEXTDESC_ADDR: +			SET_TX_DESC_NEXT_DESC_ADDRESS(pdesc, *(u32 *)val); +			break; +		case HW_DESC_OWN:{ +			struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); +			struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[q_idx]; +			u16 max_tx_desc = ring->entries; +			if (q_idx == BEACON_QUEUE) { +				ring->cur_tx_wp = 0; +				ring->cur_tx_rp = 0; +				SET_TX_BUFF_DESC_OWN(pdesc, 1); +				return; +			} +			ring->cur_tx_wp = ((ring->cur_tx_wp + 1) % max_tx_desc); + +			if (over_run) { +				ring->cur_tx_wp = 0; +				over_run = false; +			} +			if (ring->avl_desc > 1) { +				ring->avl_desc--; + +				rtl_write_word(rtlpriv, +					       get_desc_addr_fr_q(q_idx), +				       ring->cur_tx_wp); + +				if (q_idx == 1) +					last_txw_point = cur_tx_wp; +			} + +			if (ring->avl_desc < (max_tx_desc - 15)) { +				u16 point_diff = 0; +				tmp = rtl_read_dword(rtlpriv, +						     get_desc_addr_fr_q(q_idx)); +				cur_tx_rp = (u16)((tmp >> 16) & 0x0fff); +				cur_tx_wp = (u16)(tmp & 0x0fff); + +				ring->cur_tx_wp = cur_tx_wp; +				ring->cur_tx_rp = cur_tx_rp; +				point_diff = ((cur_tx_rp > cur_tx_wp) ? +					      (cur_tx_rp - cur_tx_wp) : +					      (TX_DESC_NUM_92E - 1 - +					       cur_tx_wp + cur_tx_rp)); + +				ring->avl_desc = point_diff; +			} +		} +		break; +		} +	} else { +		switch (desc_name) { +		case HW_DESC_RX_PREPARE: +			SET_RX_BUFFER_DESC_LS(pdesc , 0); +			SET_RX_BUFFER_DESC_FS(pdesc , 0); +			SET_RX_BUFFER_DESC_TOTAL_LENGTH(pdesc , 0); + +			SET_RX_BUFFER_DESC_DATA_LENGTH(pdesc, +						       MAX_RECEIVE_BUFFER_SIZE + +						       RX_DESC_SIZE); + +			SET_RX_BUFFER_PHYSICAL_LOW(pdesc, *(u32 *)val); +			break; +		case HW_DESC_RXERO: +			SET_RX_DESC_EOR(pdesc, 1); +			break; +		default: +			RT_ASSERT(false, +				  ("ERR rxdesc :%d not process\n", desc_name)); +			break; +		} +	} +} + +u32 rtl92ee_get_desc(u8 *pdesc, bool istx, u8 desc_name) +{ +	u32 ret = 0; + +	if (istx) { +		switch (desc_name) { +		case HW_DESC_OWN: +			ret = GET_TX_DESC_OWN(pdesc); +			break; +		case HW_DESC_TXBUFF_ADDR: +			ret = GET_TXBUFFER_DESC_ADDR_LOW(pdesc, 1); +			break; +		default: +			RT_ASSERT(false, +				  ("ERR txdesc :%d not process\n", desc_name)); +			break; +		} +	} else { +		switch (desc_name) { +		case HW_DESC_OWN: +			ret = GET_RX_DESC_OWN(pdesc); +			break; +		case HW_DESC_RXPKT_LEN: +			ret = GET_RX_DESC_PKT_LEN(pdesc); +			break; +		case HW_DESC_RXBUFF_ADDR: +			ret = GET_RX_DESC_BUFF_ADDR(pdesc); +			break; +		default: +			RT_ASSERT(false, +				  ("ERR rxdesc :%d not process\n", desc_name)); +			break; +		} +	} +	return ret; +} + +bool rtl92ee_is_tx_desc_closed(struct ieee80211_hw *hw, u8 hw_queue, u16 index) +{ +	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u16 read_point, write_point, available_desc_num; +	bool ret = false; +	static u8 stop_report_cnt; +	struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[hw_queue]; + +	/*checking Read/Write Point each interrupt wastes CPU utilization.*/ +	if (stop_report_cnt > 15 || !rtlpriv->link_info.b_busytraffic) { +		u16 point_diff = 0; +		u16 cur_tx_rp, cur_tx_wp; +		u32 tmpu32; + +		tmpu32 = rtl_read_dword(rtlpriv, get_desc_addr_fr_q(hw_queue)); +		cur_tx_rp = (u16)((tmpu32 >> 16) & 0x0fff); +		cur_tx_wp = (u16)(tmpu32 & 0x0fff); + +		ring->cur_tx_wp = cur_tx_wp; +		ring->cur_tx_rp = cur_tx_rp; +		point_diff = ((cur_tx_rp > cur_tx_wp) ? +			      (cur_tx_rp - cur_tx_wp) : +			      (TX_DESC_NUM_92E - cur_tx_wp + cur_tx_rp)); + +		ring->avl_desc = point_diff; +	} + +	read_point = ring->cur_tx_rp; +	write_point = ring->cur_tx_wp; +	available_desc_num = ring->avl_desc; + +	if (write_point > read_point) { +		if (index < write_point && index >= read_point) +			ret = false; +		else +			ret = true; +	} else if (write_point < read_point) { +		if (index > write_point && index < read_point) +			ret = true; +		else +			ret = false; +	} else { +		if (index != read_point) +			ret = true; +	} + +	if (hw_queue == BEACON_QUEUE) +		ret = true; + +	if (rtlpriv->rtlhal.driver_is_goingto_unload || +	    rtlpriv->psc.rfoff_reason > RF_CHANGE_BY_PS) +		ret = true; + +	if (hw_queue < BEACON_QUEUE) { +		if (!ret) +			stop_report_cnt++; +		else +			stop_report_cnt = 0; +	} + +	return ret; +} + +u32 rtl92ee_rx_command_packet(struct ieee80211_hw *hw, +			      struct rtl_stats status, +			      struct sk_buff *skb) +{ +	u32 result = 0; +	struct rtl_priv *rtlpriv = rtl_priv(hw); + +	switch (status.packet_report_type) { +	case NORMAL_RX: +		result = 0; +		break; +	case C2H_PACKET: +		rtl92ee_c2h_packet_handler(hw, skb->data, (u8) skb->len); +		result = 1; +		break; +	default: +		RT_TRACE(COMP_RECV, DBG_TRACE, ("No this packet type!!\n")); +		break; +	} + +	return result; +} diff --git a/drivers/staging/rtl8192ee/rtl8192ee/trx.h b/drivers/staging/rtl8192ee/rtl8192ee/trx.h new file mode 100644 index 00000000000..c2cd5813a2b --- /dev/null +++ b/drivers/staging/rtl8192ee/rtl8192ee/trx.h @@ -0,0 +1,877 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010  Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __RTL92E_TRX_H__ +#define __RTL92E_TRX_H__ + + + +#if (DMA_IS_64BIT == 1) +#if (RTL8192EE_SEG_NUM == 2) +#define TX_BD_DESC_SIZE					128 +#elif (RTL8192EE_SEG_NUM == 1) +#define TX_BD_DESC_SIZE					64 +#elif (RTL8192EE_SEG_NUM == 0) +#define TX_BD_DESC_SIZE					32 +#endif +#else +#if (RTL8192EE_SEG_NUM == 2) +#define TX_BD_DESC_SIZE					64 +#elif (RTL8192EE_SEG_NUM == 1) +#define TX_BD_DESC_SIZE					32 +#elif (RTL8192EE_SEG_NUM == 0) +#define TX_BD_DESC_SIZE					16 +#endif +#endif + +#define TX_DESC_SIZE					64 + +#define RX_DRV_INFO_SIZE_UNIT				8 + +#define	TX_DESC_NEXT_DESC_OFFSET			40 +#define USB_HWDESC_HEADER_LEN				40 + +#define RX_DESC_SIZE					24 +#define MAX_RECEIVE_BUFFER_SIZE				8192 + +#define SET_TX_DESC_PKT_SIZE(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc, 0, 16, __val) +#define SET_TX_DESC_OFFSET(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc, 16, 8, __val) +#define SET_TX_DESC_BMC(__pdesc, __val)			\ +	SET_BITS_TO_LE_4BYTE(__pdesc, 24, 1, __val) +#define SET_TX_DESC_HTC(__pdesc, __val)			\ +	SET_BITS_TO_LE_4BYTE(__pdesc, 25, 1, __val) +#define SET_TX_DESC_LAST_SEG(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc, 26, 1, __val) +#define SET_TX_DESC_FIRST_SEG(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc, 27, 1, __val) +#define SET_TX_DESC_LINIP(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc, 28, 1, __val) +#define SET_TX_DESC_NO_ACM(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc, 29, 1, __val) +#define SET_TX_DESC_GF(__pdesc, __val)			\ +	SET_BITS_TO_LE_4BYTE(__pdesc, 30, 1, __val) +#define SET_TX_DESC_OWN(__pdesc, __val)			\ +	SET_BITS_TO_LE_4BYTE(__pdesc, 31, 1, __val) + +#define GET_TX_DESC_PKT_SIZE(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc, 0, 16) +#define GET_TX_DESC_OFFSET(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc, 16, 8) +#define GET_TX_DESC_BMC(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc, 24, 1) +#define GET_TX_DESC_HTC(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc, 25, 1) +#define GET_TX_DESC_LAST_SEG(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc, 26, 1) +#define GET_TX_DESC_FIRST_SEG(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc, 27, 1) +#define GET_TX_DESC_LINIP(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc, 28, 1) +#define GET_TX_DESC_NO_ACM(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc, 29, 1) +#define GET_TX_DESC_GF(__pdesc)				\ +	LE_BITS_TO_4BYTE(__pdesc, 30, 1) +#define GET_TX_DESC_OWN(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc, 31, 1) + +#define SET_TX_DESC_MACID(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+4, 0, 7, __val) +#define SET_TX_DESC_QUEUE_SEL(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+4, 8, 5, __val) +#define SET_TX_DESC_RDG_NAV_EXT(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+4, 13, 1, __val) +#define SET_TX_DESC_LSIG_TXOP_EN(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+4, 14, 1, __val) +#define SET_TX_DESC_PIFS(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+4, 15, 1, __val) +#define SET_TX_DESC_RATE_ID(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+4, 16, 5, __val) +#define SET_TX_DESC_EN_DESC_ID(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+4, 21, 1, __val) +#define SET_TX_DESC_SEC_TYPE(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+4, 22, 2, __val) +#define SET_TX_DESC_PKT_OFFSET(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+4, 24, 5, __val) +#define SET_TX_DESC_MORE_DATA(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+4, 29, 1, __val) +#define SET_TX_DESC_TXOP_PS_CAP(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+4, 30, 1, __val) +#define SET_TX_DESC_TXOP_PS_MODE(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+4, 31, 1, __val) + + +#define GET_TX_DESC_MACID(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+4, 0, 5) +#define GET_TX_DESC_AGG_ENABLE(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+4, 5, 1) +#define GET_TX_DESC_AGG_BREAK(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+4, 6, 1) +#define GET_TX_DESC_RDG_ENABLE(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+4, 7, 1) +#define GET_TX_DESC_QUEUE_SEL(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+4, 8, 5) +#define GET_TX_DESC_RDG_NAV_EXT(__pdesc)		\ +	LE_BITS_TO_4BYTE(__pdesc+4, 13, 1) +#define GET_TX_DESC_LSIG_TXOP_EN(__pdesc)		\ +	LE_BITS_TO_4BYTE(__pdesc+4, 14, 1) +#define GET_TX_DESC_PIFS(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+4, 15, 1) +#define GET_TX_DESC_RATE_ID(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+4, 16, 4) +#define GET_TX_DESC_NAV_USE_HDR(__pdesc)		\ +	LE_BITS_TO_4BYTE(__pdesc+4, 20, 1) +#define GET_TX_DESC_EN_DESC_ID(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+4, 21, 1) +#define GET_TX_DESC_SEC_TYPE(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+4, 22, 2) +#define GET_TX_DESC_PKT_OFFSET(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+4, 24, 5) + +#define SET_TX_DESC_PAID(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+8, 0, 9, __val) +#define SET_TX_DESC_CCA_RTS(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+8, 10, 2, __val) +#define SET_TX_DESC_AGG_ENABLE(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+8, 12, 1, __val) +#define SET_TX_DESC_RDG_ENABLE(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+8, 13, 1, __val) +#define SET_TX_DESC_NULL_0(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+8, 14, 1, __val) +#define SET_TX_DESC_NULL_1(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+8, 15, 1, __val) +#define SET_TX_DESC_BK(__pdesc, __val)			\ +	SET_BITS_TO_LE_4BYTE(__pdesc+8, 16, 1, __val) +#define SET_TX_DESC_MORE_FRAG(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+8, 17, 1, __val) +#define SET_TX_DESC_RAW(__pdesc, __val)			\ +	SET_BITS_TO_LE_4BYTE(__pdesc+8, 18, 1, __val) +#define SET_TX_DESC_SPE_RPT(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+8, 19, 1, __val) +#define SET_TX_DESC_AMPDU_DENSITY(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+8, 20, 3, __val) +#define SET_TX_DESC_BT_NULL(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+8, 23, 1, __val) +#define SET_TX_DESC_GID(__pdesc, __val)			\ +	SET_BITS_TO_LE_4BYTE(__pdesc+8, 24, 6, __val) + +#define SET_TX_DESC_WHEADER_LEN(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+12, 0, 4, __val) +#define SET_TX_DESC_CHK_EN(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+12, 4, 1, __val) +#define SET_TX_DESC_EARLY_RATE(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+12, 5, 1, __val) +#define SET_TX_DESC_HWSEQ_SEL(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+12, 6, 2, __val) +#define SET_TX_DESC_USE_RATE(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+12, 8, 1, __val) +#define SET_TX_DESC_DISABLE_RTS_FB(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+12, 9, 1, __val) +#define SET_TX_DESC_DISABLE_FB(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+12, 10, 1, __val) +#define SET_TX_DESC_CTS2SELF(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+12, 11, 1, __val) +#define SET_TX_DESC_RTS_ENABLE(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+12, 12, 1, __val) +#define SET_TX_DESC_HW_RTS_ENABLE(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+12, 13, 1, __val) +#define SET_TX_DESC_HW_PORT_ID(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+12, 14, 1, __val) +#define SET_TX_DESC_NAV_USE_HDR(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+12, 15, 1, __val) +#define SET_TX_DESC_USE_MAX_LEN(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+12, 16, 1, __val) +#define SET_TX_DESC_MAX_AGG_NUM(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+12, 17, 5, __val) +#define SET_TX_DESC_NDPA(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+12, 22, 2, __val) +#define SET_TX_DESC_AMPDU_MAX_TIME(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+12, 24, 8, __val) + + +/* Dword 4 */ +#define SET_TX_DESC_TX_RATE(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+16, 0, 7, __val) +#define SET_TX_DESC_TRY_RATE(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+16, 7, 1, __val) +#define SET_TX_DESC_DATA_RATE_FB_LIMIT(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+16, 8, 5, __val) +#define SET_TX_DESC_RTS_RATE_FB_LIMIT(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+16, 13, 4, __val) +#define SET_TX_DESC_RETRY_LIMIT_ENABLE(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+16, 17, 1, __val) +#define SET_TX_DESC_DATA_RETRY_LIMIT(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+16, 18, 6, __val) +#define SET_TX_DESC_RTS_RATE(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+16, 24, 5, __val) +#define SET_TX_DESC_PCTS_ENABLE(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+16, 29, 1, __val) +#define SET_TX_DESC_PCTS_MASK_IDX(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+16, 30, 2, __val) + + +/* Dword 5 */ +#define SET_TX_DESC_TX_SUB_CARRIER(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+20, 0, 4, __val) +#define SET_TX_DESC_DATA_SHORT(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+20, 4, 1, __val) +#define SET_TX_DESC_DATA_BW(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+20, 5, 2, __val) +#define SET_TX_DESC_DATA_LDPC(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+20, 7, 1, __val) +#define SET_TX_DESC_DATA_STBC(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+20, 8, 2, __val) +#define SET_TX_DESC_VCS_STBC(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+20, 10, 2, __val) +#define SET_TX_DESC_RTS_SHORT(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+20, 12, 1, __val) +#define SET_TX_DESC_RTS_SC(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+20, 13, 4, __val) +#define SET_TX_DESC_TX_ANT(__pdesc , __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+20, 24, 4, __val) +#define SET_TX_DESC_TX_POWER_0_PSET(__pdesc , __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+20, 28, 3, __val) + +/* Dword 6 */ +#define SET_TX_DESC_SW_DEFINE(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+24, 0, 12, __val) +#define SET_TX_DESC_ANTSEL_A(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+24, 16, 3, __val) +#define SET_TX_DESC_ANTSEL_B(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+24, 19, 3, __val) +#define SET_TX_DESC_ANTSEL_C(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+24, 22, 3, __val) +#define SET_TX_DESC_ANTSEL_D(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+24, 25, 3, __val) + +/* Dword 7 */ +#define SET_TX_DESC_TX_BUFFER_SIZE(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+28, 0, 16, __val) +#define SET_TX_DESC_USB_TXAGG_NUM(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+28, 24, 8, __val) + +/* Dword 8 */ +#define SET_TX_DESC_RTS_RC(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+32 , 0 , 6 , __val) +#define SET_TX_DESC_BAR_RTY_TH(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+32 , 6 , 2 , __val) +#define SET_TX_DESC_DATA_RC(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+32 , 8 , 6 , __val) +#define SET_TX_DESC_ENABLE_HW_SELECT(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+32 , 15 , 1 , __val) +#define SET_TX_DESC_NEXT_HEAD_PAGE(__pdesc , __val)(__pdesc, __val) \ +	SET_BITS_TO_LE_4BYTE(__pdesc+32 , 16 , 8 , __val) +#define SET_TX_DESC_TAIL_PAGE(__pdesc , __val)(__pdesc, __val)\ +	SET_BITS_TO_LE_4BYTE(__pdesc+32 , 24 , 8 , __val) + +/* Dword 9 */ +#define SET_TX_DESC_PADDING_LENGTH(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+36 , 0 , 11 , __val) +#define SET_TX_DESC_TXBF_PATH(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+36 , 11 , 1 , __val) +#define SET_TX_DESC_SEQ(__pdesc, __val)			\ +	SET_BITS_TO_LE_4BYTE(__pdesc+36 , 12 , 12 , __val) +#define SET_TX_DESC_FINAL_DATA_RATE(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+36 , 24 , 8 , __val) + +/* Dword 10 */ +#define SET_TX_DESC_TX_BUFFER_ADDRESS(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+40 , 0 , 32 , __val) + + +/* Dword 11*/ +#define SET_TX_DESC_NEXT_DESC_ADDRESS(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+48 , 0 , 32 , __val) + + +#define SET_EARLYMODE_PKTNUM(__paddr , __val)		\ +	SET_BITS_TO_LE_4BYTE(__paddr , 0 , 4 , __val) +#define SET_EARLYMODE_LEN0(__paddr , __val)		\ +	SET_BITS_TO_LE_4BYTE(__paddr , 4 , 15 , __val) +#define SET_EARLYMODE_LEN1(__paddr , __val)		\ +	SET_BITS_TO_LE_4BYTE(__paddr , 16 , 2 , __val) +#define SET_EARLYMODE_LEN1_1(__paddr , __val)		\ +	SET_BITS_TO_LE_4BYTE(__paddr , 19 , 13 , __val) +#define SET_EARLYMODE_LEN1_2(__paddr , __val)		\ +	SET_BITS_TO_LE_4BYTE(__paddr+4 , 0 , 2 , __val) +#define SET_EARLYMODE_LEN2(__paddr , __val)		\ +	SET_BITS_TO_LE_4BYTE(__paddr+4 , 2 , 15 ,  __val) +#define SET_EARLYMODE_LEN2_1(__paddr , __val)		\ +	SET_BITS_TO_LE_4BYTE(__paddr , 2 , 4 ,  __val) +#define SET_EARLYMODE_LEN2_2(__paddr , __val)		\ +	SET_BITS_TO_LE_4BYTE(__paddr+4 , 0 , 8 ,  __val) +#define SET_EARLYMODE_LEN3(__paddr , __val)		\ +	SET_BITS_TO_LE_4BYTE(__paddr+4 , 17 , 15, __val) +#define SET_EARLYMODE_LEN4(__paddr , __val)		\ +	SET_BITS_TO_LE_4BYTE(__paddr+4 , 20 , 12 , __val) + + +/* TX/RX buffer descriptor */ + +#define SET_TX_EXTBUFF_DESC_LEN(__pdesc, __val, __set)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+(__set*16) , 0 , 16 , __val) +#define SET_TX_EXTBUFF_DESC_ADDR_LOW(__pdesc, __val, __set)\ +	SET_BITS_TO_LE_4BYTE(__pdesc+(__set*16)+4 , 0 , 32 , __val) +#define SET_TX_EXTBUFF_DESC_ADDR_HIGH(__pdesc, __val , __set)\ +	SET_BITS_TO_LE_4BYTE(__pdesc+(__set*16)+8 , 0 , 32 , __val) + + + +/* for Txfilldescroptor92ee, fill the desc content. */ +#if (DMA_IS_64BIT == 1) +#define SET_TXBUFFER_DESC_LEN_WITH_OFFSET(__pdesc, __offset, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+(__offset*16), 0, 16, __val) +#define SET_TXBUFFER_DESC_AMSDU_WITH_OFFSET(__pdesc, __offset, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+(__offset*16), 31, 1, __val) +#define SET_TXBUFFER_DESC_ADD_LOW_WITH_OFFSET(__pdesc, __offset, __val) \ +	SET_BITS_TO_LE_4BYTE(__pdesc+(__offset*16)+4, 0, 32, __val) +#define SET_TXBUFFER_DESC_ADD_HIGT_WITH_OFFSET(__pdesc, __offset, __val)\ +	SET_BITS_TO_LE_4BYTE(__pdesc+(__offset*16)+8, 0, 32, __val) +#define GET_TXBUFFER_DESC_ADDR_LOW(__pdesc, __offset)			\ +	LE_BITS_TO_4BYTE(__pdesc+(__offset*16)+4, 0, 32) +#else +#define SET_TXBUFFER_DESC_LEN_WITH_OFFSET(__pdesc, __offset, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+(__offset*8), 0, 16, __val) +#define SET_TXBUFFER_DESC_AMSDU_WITH_OFFSET(__pdesc, __offset, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+(__offset*8), 31, 1, __val) +#define SET_TXBUFFER_DESC_ADD_LOW_WITH_OFFSET(__pdesc, __offset, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+(__offset*8)+4, 0, 32, __val) +#define SET_TXBUFFER_DESC_ADD_HIGT_WITH_OFFSET(__pdesc, __offset, __val) +#define GET_TXBUFFER_DESC_ADDR_LOW(__pdesc, __offset)			\ +	LE_BITS_TO_4BYTE(__pdesc+(__offset*8)+4, 0, 32) +#endif + +/* Dword 0 */ +#define SET_TX_BUFF_DESC_LEN_0(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc, 0, 14, __val) +#define SET_TX_BUFF_DESC_PSB(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc, 16, 15, __val) +#define SET_TX_BUFF_DESC_OWN(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc, 31, 1, __val) + +/* Dword 1 */ +#define SET_TX_BUFF_DESC_ADDR_LOW_0(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+4, 0, 32, __val) +#if (DMA_IS_64BIT == 1) +/* Dword 2 */ +#define SET_TX_BUFF_DESC_ADDR_HIGH_0(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+8, 0, 32, __val) +/* Dword 3 / RESERVED 0 */ +/* Dword 4 */ +#define SET_TX_BUFF_DESC_LEN_1(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+16, 0, 16, __val) +#define SET_TX_BUFF_DESC_AMSDU_1(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+16, 31, 1, __val) +/* Dword 5 */ +#define SET_TX_BUFF_DESC_ADDR_LOW_1(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+20, 0, 32, __val) +/* Dword 6 */ +#define SET_TX_BUFF_DESC_ADDR_HIGH_1(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+24, 0, 32, __val) +/* Dword 7 / RESERVED 0 */ +/* Dword 8 */ +#define SET_TX_BUFF_DESC_LEN_2(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+32, 0, 16, __val) +#define SET_TX_BUFF_DESC_AMSDU_2(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+32, 31, 1, __val) +/* Dword 9 */ +#define SET_TX_BUFF_DESC_ADDR_LOW_2(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+36, 0, 32, __val) +/* Dword 10 */ +#define SET_TX_BUFF_DESC_ADDR_HIGH_2(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+40, 0, 32, __val) +/* Dword 11 / RESERVED 0 */ +/* Dword 12 */ +#define SET_TX_BUFF_DESC_LEN_3(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+48, 0, 16, __val) +#define SET_TX_BUFF_DESC_AMSDU_3(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+48, 31, 1, __val) +/* Dword 13 */ +#define SET_TX_BUFF_DESC_ADDR_LOW_3(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+52, 0, 32, __val) +/* Dword 14 */ +#define SET_TX_BUFF_DESC_ADDR_HIGH_3(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+56, 0, 32, __val) +/* Dword 15 / RESERVED 0 */ +#else +#define SET_TX_BUFF_DESC_ADDR_HIGH_0(__pdesc, __val) +/* Dword 2 */ +#define SET_TX_BUFF_DESC_LEN_1(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+8, 0, 16, __val) +#define SET_TX_BUFF_DESC_AMSDU_1(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+8, 31, 1, __val) +/* Dword 3 */ +#define SET_TX_BUFF_DESC_ADDR_LOW_1(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+12, 0, 32, __val) +#define SET_TX_BUFF_DESC_ADDR_HIGH_1(__pdesc, __val) +/* Dword 4 */ +#define SET_TX_BUFF_DESC_LEN_2(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+16, 0, 16, __val) +#define SET_TX_BUFF_DESC_AMSDU_2(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+16, 31, 1, __val) +/* Dword 5 */ +#define SET_TX_BUFF_DESC_ADDR_LOW_2(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+20, 0, 32, __val) +#define SET_TX_BUFF_DESC_ADDR_HIGH_2(__pdesc, __val) +/* Dword 6 */ +#define SET_TX_BUFF_DESC_LEN_3(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+24, 0, 16, __val) +#define SET_TX_BUFF_DESC_AMSDU_3(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+24, 31, 1, __val) +/* Dword 7 */ +#define SET_TX_BUFF_DESC_ADDR_LOW_3(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+28, 0, 32, __val) +#define SET_TX_BUFF_DESC_ADDR_HIGH_3(__pdesc, __val) +#endif + +/* RX buffer  */ + +/* DWORD 0 */ +#define SET_RX_BUFFER_DESC_DATA_LENGTH(__pRxStatusDesc , __val)	\ +	SET_BITS_TO_LE_4BYTE(__pRxStatusDesc , 0, 14, __val) +#define SET_RX_BUFFER_DESC_LS(__pRxStatusDesc , __val)		\ +	SET_BITS_TO_LE_4BYTE(__pRxStatusDesc , 15, 1, __val) +#define SET_RX_BUFFER_DESC_FS(__pRxStatusDesc , __val)		\ +	SET_BITS_TO_LE_4BYTE(__pRxStatusDesc , 16, 1, __val) +#define SET_RX_BUFFER_DESC_TOTAL_LENGTH(__pRxStatusDesc , __val)	\ +	SET_BITS_TO_LE_4BYTE(__pRxStatusDesc , 16, 15, __val) + +#define GET_RX_BUFFER_DESC_OWN(__pRxStatusDesc)			\ +	LE_BITS_TO_4BYTE(__pRxStatusDesc , 31, 1) +#define GET_RX_BUFFER_DESC_LS(__pRxStatusDesc)			\ +	LE_BITS_TO_4BYTE(__pRxStatusDesc , 15, 1) +#define GET_RX_BUFFER_DESC_FS(__pRxStatusDesc)			\ +	LE_BITS_TO_4BYTE(__pRxStatusDesc , 16, 1) +#define GET_RX_BUFFER_DESC_TOTAL_LENGTH(__pRxStatusDesc)	\ +	LE_BITS_TO_4BYTE(__pRxStatusDesc , 16, 15) + + +/* DWORD 1 */ +#define SET_RX_BUFFER_PHYSICAL_LOW(__pRxStatusDesc , __val)	\ +	SET_BITS_TO_LE_4BYTE(__pRxStatusDesc+4, 0, 32, __val) + +/* DWORD 2 */ +#define SET_RX_BUFFER_PHYSICAL_HIGH(__pRxStatusDesc , __val)	\ +	SET_BITS_TO_LE_4BYTE(__pRxStatusDesc+8, 0, 32, __val) + +#define GET_RX_DESC_PKT_LEN(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc, 0, 14) +#define GET_RX_DESC_CRC32(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc, 14, 1) +#define GET_RX_DESC_ICV(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc, 15, 1) +#define GET_RX_DESC_DRV_INFO_SIZE(__pdesc)		\ +	LE_BITS_TO_4BYTE(__pdesc, 16, 4) +#define GET_RX_DESC_SECURITY(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc, 20, 3) +#define GET_RX_DESC_QOS(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc, 23, 1) +#define GET_RX_DESC_SHIFT(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc, 24, 2) +#define GET_RX_DESC_PHYST(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc, 26, 1) +#define GET_RX_DESC_SWDEC(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc, 27, 1) +#define GET_RX_DESC_LS(__pdesc)				\ +	LE_BITS_TO_4BYTE(__pdesc, 28, 1) +#define GET_RX_DESC_FS(__pdesc)				\ +	LE_BITS_TO_4BYTE(__pdesc, 29, 1) +#define GET_RX_DESC_EOR(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc, 30, 1) +#define GET_RX_DESC_OWN(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc, 31, 1) + +#define SET_RX_DESC_PKT_LEN(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc, 0, 14, __val) +#define SET_RX_DESC_EOR(__pdesc, __val)			\ +	SET_BITS_TO_LE_4BYTE(__pdesc, 30, 1, __val) +#define SET_RX_DESC_OWN(__pdesc, __val)			\ +	SET_BITS_TO_LE_4BYTE(__pdesc, 31, 1, __val) + +#define GET_RX_DESC_MACID(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+4, 0, 7) +#define GET_RX_DESC_TID(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+4, 8, 4) +#define GET_RX_DESC_MACID_VLD(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+4, 12, 1) +#define GET_RX_DESC_AMSDU(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+4, 13, 1) +#define GET_RX_DESC_RXID_MATCH(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+4, 14, 1) +#define GET_RX_DESC_PAGGR(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+4, 15, 1) +#define GET_RX_DESC_A1_FIT(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+4, 16, 4) +#define GET_RX_DESC_TCPOFFLOAD_CHKERR(__pdesc)		\ +	LE_BITS_TO_4BYTE(__pdesc+4, 20, 1) +#define GET_RX_DESC_TCPOFFLOAD_IPVER(__pdesc)		\ +	LE_BITS_TO_4BYTE(__pdesc+4, 21, 1) +#define GET_RX_DESC_TCPOFFLOAD_IS_TCPUDP(__pdesc)	\ +	LE_BITS_TO_4BYTE(__pdesc+4, 22, 1) +#define GET_RX_DESC_TCPOFFLOAD_CHK_VLD(__pdesc)		\ +	LE_BITS_TO_4BYTE(__pdesc+4, 23, 1) +#define GET_RX_DESC_PAM(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+4, 24, 1) +#define GET_RX_DESC_PWR(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+4, 25, 1) +#define GET_RX_DESC_MD(__pdesc)				\ +	LE_BITS_TO_4BYTE(__pdesc+4, 26, 1) +#define GET_RX_DESC_MF(__pdesc)				\ +	LE_BITS_TO_4BYTE(__pdesc+4, 27, 1) +#define GET_RX_DESC_TYPE(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+4, 28, 2) +#define GET_RX_DESC_MC(__pdesc)				\ +	LE_BITS_TO_4BYTE(__pdesc+4, 30, 1) +#define GET_RX_DESC_BC(__pdesc)				\ +	LE_BITS_TO_4BYTE(__pdesc+4, 31, 1) +#define GET_RX_DESC_SEQ(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+8, 0, 12) +#define GET_RX_DESC_FRAG(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+8, 12, 4) +#define GET_RX_DESC_RX_IS_QOS(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+8, 16, 1) + +#define GET_RX_DESC_RXMCS(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+12, 0, 7) +#define GET_RX_DESC_HTC(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+12, 10, 1) +#define GET_RX_STATUS_DESC_EOSP(__pdesc)		\ +	LE_BITS_TO_4BYTE(__pdesc+12, 11, 1) +#define GET_RX_STATUS_DESC_BSSID_FIT(__pdesc)		\ +	LE_BITS_TO_4BYTE(__pdesc+12, 12, 2) +#define GET_RX_STATUS_DESC_DMA_AGG_NUM(__pdesc)		\ +	LE_BITS_TO_4BYTE(__pdesc+12, 16, 8) +#define GET_RX_STATUS_DESC_PATTERN_MATCH(__pdesc)	\ +	LE_BITS_TO_4BYTE(__pdesc+12, 29, 1) +#define GET_RX_STATUS_DESC_UNICAST_MATCH(__pdesc)	\ +	LE_BITS_TO_4BYTE(__pdesc+12, 30, 1) +#define GET_RX_STATUS_DESC_MAGIC_MATCH(__pdesc)		\ +	LE_BITS_TO_4BYTE(__pdesc+12, 31, 1) + + +#define GET_RX_DESC_TSFL(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+20, 0, 32) + +#define GET_RX_DESC_BUFF_ADDR(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+24, 0, 32) +#define GET_RX_DESC_BUFF_ADDR64(__pdesc)		\ +	LE_BITS_TO_4BYTE(__pdesc+28, 0, 32) + +#define SET_RX_DESC_BUFF_ADDR(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+24, 0, 32, __val) +#define SET_RX_DESC_BUFF_ADDR64(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+28, 0, 32, __val) + + +/* TX report 2 format in Rx desc*/ + +#define GET_RX_RPT2_DESC_PKT_LEN(__pRxStatusDesc)	\ +	LE_BITS_TO_4BYTE(__pRxStatusDesc , 0, 9) +#define GET_RX_RPT2_DESC_MACID_VALID_1(__pRxStatusDesc)	\ +	LE_BITS_TO_4BYTE(__pRxStatusDesc+16, 0, 32) +#define GET_RX_RPT2_DESC_MACID_VALID_2(__pRxStatusDesc)	\ +	LE_BITS_TO_4BYTE(__pRxStatusDesc+20, 0, 32) + + +#define CLEAR_PCI_TX_DESC_CONTENT(__pdesc, _size)		\ +do {								\ +	if (_size > TX_DESC_NEXT_DESC_OFFSET)			\ +		memset(__pdesc, 0, TX_DESC_NEXT_DESC_OFFSET);	\ +	else							\ +		memset(__pdesc, 0, _size);			\ +} while (0) + +#define RX_HAL_IS_CCK_RATE(rxmcs)\ +	(rxmcs == DESC92C_RATE1M ||\ +	 rxmcs == DESC92C_RATE2M ||\ +	 rxmcs == DESC92C_RATE5_5M ||\ +	 rxmcs == DESC92C_RATE11M) + +#define IS_LITTLE_ENDIAN	1 + +struct phy_rx_agc_info_t { +	#if IS_LITTLE_ENDIAN +		u8 gain:7 , trsw:1; +	#else +		u8 trsw:1 , gain:7; +	#endif +}; +struct phy_status_rpt { +	struct phy_rx_agc_info_t path_agc[2]; +	u8 ch_corr[2]; +	u8 cck_sig_qual_ofdm_pwdb_all; +	u8 cck_agc_rpt_ofdm_cfosho_a; +	u8 cck_rpt_b_ofdm_cfosho_b; +	u8 rsvd_1; +	u8 noise_power_db_msb; +	u8 path_cfotail[2]; +	u8 pcts_mask[2]; +	u8 stream_rxevm[2]; +	u8 path_rxsnr[2]; +	u8 noise_power_db_lsb; +	u8 rsvd_2[3]; +	u8 stream_csi[2]; +	u8 stream_target_csi[2]; +	u8 sig_evm; +	u8 rsvd_3; +#if IS_LITTLE_ENDIAN +	u8 antsel_rx_keep_2:1;	/*ex_intf_flg:1;*/ +	u8 sgi_en:1; +	u8 rxsc:2; +	u8 idle_long:1; +	u8 r_ant_train_en:1; +	u8 ant_sel_b:1; +	u8 ant_sel:1; +#else	/* _BIG_ENDIAN_	*/ +	u8 ant_sel:1; +	u8 ant_sel_b:1; +	u8 r_ant_train_en:1; +	u8 idle_long:1; +	u8 rxsc:2; +	u8 sgi_en:1; +	u8 antsel_rx_keep_2:1;	/*ex_intf_flg:1;*/ +#endif +} __packed; + +struct rx_fwinfo { +	u8 gain_trsw[4]; +	u8 pwdb_all; +	u8 cfosho[4]; +	u8 cfotail[4]; +	char rxevm[2]; +	char rxsnr[4]; +	u8 pdsnr[2]; +	u8 csi_current[2]; +	u8 csi_target[2]; +	u8 sigevm; +	u8 max_ex_pwr; +	u8 ex_intf_flag:1; +	u8 sgi_en:1; +	u8 rxsc:2; +	u8 reserve:4; +} __packed; + +struct tx_desc { +	u32 pktsize:16; +	u32 offset:8; +	u32 bmc:1; +	u32 htc:1; +	u32 lastseg:1; +	u32 firstseg:1; +	u32 linip:1; +	u32 noacm:1; +	u32 gf:1; +	u32 own:1; + +	u32 macid:6; +	u32 rsvd0:2; +	u32 queuesel:5; +	u32 rd_nav_ext:1; +	u32 lsig_txop_en:1; +	u32 pifs:1; +	u32 rateid:4; +	u32 nav_usehdr:1; +	u32 en_descid:1; +	u32 sectype:2; +	u32 pktoffset:8; + +	u32 rts_rc:6; +	u32 data_rc:6; +	u32 agg_en:1; +	u32 rdg_en:1; +	u32 bar_retryht:2; +	u32 agg_break:1; +	u32 morefrag:1; +	u32 raw:1; +	u32 ccx:1; +	u32 ampdudensity:3; +	u32 bt_int:1; +	u32 ant_sela:1; +	u32 ant_selb:1; +	u32 txant_cck:2; +	u32 txant_l:2; +	u32 txant_ht:2; + +	u32 nextheadpage:8; +	u32 tailpage:8; +	u32 seq:12; +	u32 cpu_handle:1; +	u32 tag1:1; +	u32 trigger_int:1; +	u32 hwseq_en:1; + +	u32 rtsrate:5; +	u32 apdcfe:1; +	u32 qos:1; +	u32 hwseq_ssn:1; +	u32 userrate:1; +	u32 dis_rtsfb:1; +	u32 dis_datafb:1; +	u32 cts2self:1; +	u32 rts_en:1; +	u32 hwrts_en:1; +	u32 portid:1; +	u32 pwr_status:3; +	u32 waitdcts:1; +	u32 cts2ap_en:1; +	u32 txsc:2; +	u32 stbc:2; +	u32 txshort:1; +	u32 txbw:1; +	u32 rtsshort:1; +	u32 rtsbw:1; +	u32 rtssc:2; +	u32 rtsstbc:2; + +	u32 txrate:6; +	u32 shortgi:1; +	u32 ccxt:1; +	u32 txrate_fb_lmt:5; +	u32 rtsrate_fb_lmt:4; +	u32 retrylmt_en:1; +	u32 txretrylmt:6; +	u32 usb_txaggnum:8; + +	u32 txagca:5; +	u32 txagcb:5; +	u32 usemaxlen:1; +	u32 maxaggnum:5; +	u32 mcsg1maxlen:4; +	u32 mcsg2maxlen:4; +	u32 mcsg3maxlen:4; +	u32 mcs7sgimaxlen:4; + +	u32 txbuffersize:16; +	u32 sw_offset30:8; +	u32 sw_offset31:4; +	u32 rsvd1:1; +	u32 antsel_c:1; +	u32 null_0:1; +	u32 null_1:1; + +	u32 txbuffaddr; +	u32 txbufferaddr64; +	u32 nextdescaddress; +	u32 nextdescaddress64; + +	u32 reserve_pass_pcie_mm_limit[4]; +} __packed; + +struct rx_desc { +	u32 length:14; +	u32 crc32:1; +	u32 icverror:1; +	u32 drv_infosize:4; +	u32 security:3; +	u32 qos:1; +	u32 shift:2; +	u32 phystatus:1; +	u32 swdec:1; +	u32 lastseg:1; +	u32 firstseg:1; +	u32 eor:1; +	u32 own:1; + +	u32 macid:6; +	u32 tid:4; +	u32 hwrsvd:5; +	u32 paggr:1; +	u32 faggr:1; +	u32 a1_fit:4; +	u32 a2_fit:4; +	u32 pam:1; +	u32 pwr:1; +	u32 moredata:1; +	u32 morefrag:1; +	u32 type:2; +	u32 mc:1; +	u32 bc:1; + +	u32 seq:12; +	u32 frag:4; +	u32 nextpktlen:14; +	u32 nextind:1; +	u32 rsvd:1; + +	u32 rxmcs:6; +	u32 rxht:1; +	u32 amsdu:1; +	u32 splcp:1; +	u32 bandwidth:1; +	u32 htc:1; +	u32 tcpchk_rpt:1; +	u32 ipcchk_rpt:1; +	u32 tcpchk_valid:1; +	u32 hwpcerr:1; +	u32 hwpcind:1; +	u32 iv0:16; + +	u32 iv1; + +	u32 tsfl; + +	u32 bufferaddress; +	u32 bufferaddress64; + +} __packed; + +void rtl92ee_rx_check_dma_ok(struct ieee80211_hw *hw, u8 *header_desc, +			     u8 queue_index); +u16	rtl92ee_rx_desc_buff_remained_cnt(struct ieee80211_hw *hw, +					  u8 queue_index); +void rtl92ee_get_available_desc(struct ieee80211_hw *hw , u8 queue_index); +void rtl92ee_pre_fill_tx_bd_desc(struct ieee80211_hw *hw, +				 u8 *tx_bd_desc, u8 *desc, u8 queue_index, +				 struct sk_buff *skb, dma_addr_t addr); + + +void rtl92ee_tx_fill_desc(struct ieee80211_hw *hw, +			  struct ieee80211_hdr *hdr, u8 *pdesc_tx, +			  u8 *pbd_desc_tx, +			  struct ieee80211_tx_info *info, +			  struct ieee80211_sta *sta, +			  struct sk_buff *skb, +			  u8 hw_queue, struct rtl_tcb_desc *ptcb_desc); +bool rtl92ee_rx_query_desc(struct ieee80211_hw *hw, +			   struct rtl_stats *status, +			   struct ieee80211_rx_status *rx_status, +			   u8 *pdesc, struct sk_buff *skb); +void rtl92ee_set_desc(struct ieee80211_hw *hw, u8 *pdesc, bool istx, +		      u8 desc_name, u8 *val); + +u32 rtl92ee_get_desc(u8 *pdesc, bool istx, u8 desc_name); +bool rtl92ee_is_tx_desc_closed(struct ieee80211_hw *hw, u8 hw_queue, u16 index); +void rtl92ee_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc, +			     bool b_firstseg, bool b_lastseg, +			     struct sk_buff *skb); +u32 rtl92ee_rx_command_packet(struct ieee80211_hw *hw, +			      struct rtl_stats status, +			      struct sk_buff *skb); +#endif diff --git a/drivers/staging/rtl8192ee/stats.c b/drivers/staging/rtl8192ee/stats.c new file mode 100644 index 00000000000..7ac302b1a71 --- /dev/null +++ b/drivers/staging/rtl8192ee/stats.c @@ -0,0 +1,290 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010  Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ +#include "wifi.h" +#include "stats.h" + +u8 stg_rtl_query_rxpwrpercentage(char antpower) +{ +	if ((antpower <= -100) || (antpower >= 20)) +		return 0; +	else if (antpower >= 0) +		return 100; +	else +		return 100 + antpower; +} +EXPORT_SYMBOL(stg_rtl_query_rxpwrpercentage); + +u8 stg_rtl_evm_db_to_percentage(char value) +{ +	char ret_val; +	ret_val = value; + +	if (ret_val >= 0) +		ret_val = 0; +	if (ret_val <= -33) +		ret_val = -33; +	ret_val = 0 - ret_val; +	ret_val *= 3; +	if (ret_val == 99) +		ret_val = 100; + +	return ret_val; +} +EXPORT_SYMBOL(stg_rtl_evm_db_to_percentage); + +u8 rtl_evm_dbm_jaguar(char value) +{ +	char ret_val; +	ret_val = value; + +	/* -33dB~0dB to 33dB ~ 0dB*/ +	if (ret_val == -128) +		ret_val = 127; +	else if (ret_val < 0) +		ret_val = 0 - ret_val; + +	ret_val  = ret_val >> 1; +	return ret_val; +} +EXPORT_SYMBOL(rtl_evm_dbm_jaguar); + +static long rtl_translate_todbm(struct ieee80211_hw *hw, +				u8 signal_strength_index) +{ +	long signal_power; + +	signal_power = (long)((signal_strength_index + 1) >> 1); +	signal_power -= 95; +	return signal_power; +} + +long stg_rtl_signal_scale_mapping(struct ieee80211_hw *hw, long currsig) +{ +	long retsig; + +	if (currsig >= 61 && currsig <= 100) +		retsig = 90 + ((currsig - 60) / 4); +	else if (currsig >= 41 && currsig <= 60) +		retsig = 78 + ((currsig - 40) / 2); +	else if (currsig >= 31 && currsig <= 40) +		retsig = 66 + (currsig - 30); +	else if (currsig >= 21 && currsig <= 30) +		retsig = 54 + (currsig - 20); +	else if (currsig >= 5 && currsig <= 20) +		retsig = 42 + (((currsig - 5) * 2) / 3); +	else if (currsig == 4) +		retsig = 36; +	else if (currsig == 3) +		retsig = 27; +	else if (currsig == 2) +		retsig = 18; +	else if (currsig == 1) +		retsig = 9; +	else +		retsig = currsig; + +	return retsig; +} +EXPORT_SYMBOL(stg_rtl_signal_scale_mapping); + +static void rtl_process_ui_rssi(struct ieee80211_hw *hw, struct rtl_stats *pstatus) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	u8 rfpath; +	u32 last_rssi, tmpval; + +	if (!pstatus->b_packet_toself && !pstatus->b_packet_beacon) +		return; + +	rtlpriv->stats.pwdb_all_cnt += pstatus->rx_pwdb_all; +	rtlpriv->stats.rssi_calculate_cnt++; + +	if (rtlpriv->stats.ui_rssi.total_num++ >= PHY_RSSI_SLID_WIN_MAX) { +		rtlpriv->stats.ui_rssi.total_num = PHY_RSSI_SLID_WIN_MAX; +		last_rssi = rtlpriv->stats.ui_rssi.elements[ +			rtlpriv->stats.ui_rssi.index]; +		rtlpriv->stats.ui_rssi.total_val -= last_rssi; +	} +	rtlpriv->stats.ui_rssi.total_val += pstatus->signalstrength; +	rtlpriv->stats.ui_rssi.elements[rtlpriv->stats.ui_rssi.index++] = +	    pstatus->signalstrength; +	if (rtlpriv->stats.ui_rssi.index >= PHY_RSSI_SLID_WIN_MAX) +		rtlpriv->stats.ui_rssi.index = 0; +	tmpval = rtlpriv->stats.ui_rssi.total_val / +		rtlpriv->stats.ui_rssi.total_num; +	rtlpriv->stats.signal_strength = rtl_translate_todbm(hw, +		(u8) tmpval); +	pstatus->rssi = rtlpriv->stats.signal_strength; + +	if (pstatus->b_is_cck) +		return; + +	for (rfpath = RF90_PATH_A; rfpath < rtlphy->num_total_rfpath; +	     rfpath++) { +		if (rtlpriv->stats.rx_rssi_percentage[rfpath] == 0) { +			rtlpriv->stats.rx_rssi_percentage[rfpath] = +			    pstatus->rx_mimo_signalstrength[rfpath]; +		} +		if (pstatus->rx_mimo_signalstrength[rfpath] > +		    rtlpriv->stats.rx_rssi_percentage[rfpath]) { +			rtlpriv->stats.rx_rssi_percentage[rfpath] = +			    ((rtlpriv->stats.rx_rssi_percentage[rfpath] * +			      (RX_SMOOTH_FACTOR - 1)) + +			     (pstatus->rx_mimo_signalstrength[rfpath])) / +			    (RX_SMOOTH_FACTOR); +			rtlpriv->stats.rx_rssi_percentage[rfpath] = +			    rtlpriv->stats.rx_rssi_percentage[rfpath] + 1; +		} else { +			rtlpriv->stats.rx_rssi_percentage[rfpath] = +			    ((rtlpriv->stats.rx_rssi_percentage[rfpath] * +			      (RX_SMOOTH_FACTOR - 1)) + +			     (pstatus->rx_mimo_signalstrength[rfpath])) / +			    (RX_SMOOTH_FACTOR); +		} +		rtlpriv->stats.rx_snr_db[rfpath] = pstatus->rx_snr[rfpath]; +		rtlpriv->stats.rx_evm_dbm[rfpath] = +					pstatus->rx_mimo_evm_dbm[rfpath]; +		rtlpriv->stats.rx_cfo_short[rfpath] = +					pstatus->cfo_short[rfpath]; +		rtlpriv->stats.rx_cfo_tail[rfpath] = pstatus->cfo_tail[rfpath]; +	} +} + +static void rtl_update_rxsignalstatistics(struct ieee80211_hw *hw, +					  struct rtl_stats *pstatus) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	int weighting = 0; + +	if (rtlpriv->stats.recv_signal_power == 0) +		rtlpriv->stats.recv_signal_power = pstatus->recvsignalpower; +	if (pstatus->recvsignalpower > rtlpriv->stats.recv_signal_power) +		weighting = 5; +	else if (pstatus->recvsignalpower < rtlpriv->stats.recv_signal_power) +		weighting = (-5); +	rtlpriv->stats.recv_signal_power = (rtlpriv->stats.recv_signal_power * +		5 + pstatus->recvsignalpower + weighting) / 6; +} + +static void rtl_process_pwdb(struct ieee80211_hw *hw, struct rtl_stats *pstatus) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_sta_info *drv_priv = NULL; +	struct ieee80211_sta *sta = NULL; +	long undecorated_smoothed_pwdb; + +	rcu_read_lock(); +	if (rtlpriv->mac80211.opmode != NL80211_IFTYPE_STATION) +		sta = rtl_find_sta(hw, pstatus->psaddr); + +	/* adhoc or ap mode */ +	if (sta) { +		drv_priv = (struct rtl_sta_info *)sta->drv_priv; +		undecorated_smoothed_pwdb = +			drv_priv->rssi_stat.undecorated_smoothed_pwdb; +	} else { +		undecorated_smoothed_pwdb = +			rtlpriv->dm.undecorated_smoothed_pwdb; +	} + +	if (undecorated_smoothed_pwdb < 0) +		undecorated_smoothed_pwdb = pstatus->rx_pwdb_all; +	if (pstatus->rx_pwdb_all > (u32) undecorated_smoothed_pwdb) { +		undecorated_smoothed_pwdb = (((undecorated_smoothed_pwdb) * +		      (RX_SMOOTH_FACTOR - 1)) + +		     (pstatus->rx_pwdb_all)) / (RX_SMOOTH_FACTOR); +		undecorated_smoothed_pwdb = undecorated_smoothed_pwdb + 1; +	} else { +		undecorated_smoothed_pwdb = (((undecorated_smoothed_pwdb) * +		      (RX_SMOOTH_FACTOR - 1)) + +		     (pstatus->rx_pwdb_all)) / (RX_SMOOTH_FACTOR); +	} + +	if (sta) { +		drv_priv->rssi_stat.undecorated_smoothed_pwdb = +			undecorated_smoothed_pwdb; +	} else { +		rtlpriv->dm.undecorated_smoothed_pwdb = undecorated_smoothed_pwdb; +	} +	rcu_read_unlock(); + +	rtl_update_rxsignalstatistics(hw, pstatus); +} + +static void rtl_process_ui_link_quality(struct ieee80211_hw *hw, +					struct rtl_stats *pstatus) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u32 last_evm, n_stream, tmpval; + +	if (pstatus->signalquality == 0) +		return; + +	if (rtlpriv->stats.ui_link_quality.total_num++ >= +	    PHY_LINKQUALITY_SLID_WIN_MAX) { +		rtlpriv->stats.ui_link_quality.total_num = +		    PHY_LINKQUALITY_SLID_WIN_MAX; +		last_evm = rtlpriv->stats.ui_link_quality.elements[ +			rtlpriv->stats.ui_link_quality.index]; +		rtlpriv->stats.ui_link_quality.total_val -= last_evm; +	} +	rtlpriv->stats.ui_link_quality.total_val += pstatus->signalquality; +	rtlpriv->stats.ui_link_quality.elements[ +		rtlpriv->stats.ui_link_quality.index++] = +							pstatus->signalquality; +	if (rtlpriv->stats.ui_link_quality.index >= +	    PHY_LINKQUALITY_SLID_WIN_MAX) +		rtlpriv->stats.ui_link_quality.index = 0; +	tmpval = rtlpriv->stats.ui_link_quality.total_val / +	    rtlpriv->stats.ui_link_quality.total_num; +	rtlpriv->stats.signal_quality = tmpval; +	rtlpriv->stats.last_sigstrength_inpercent = tmpval; +	for (n_stream = 0; n_stream < 2; n_stream++) { +		if (pstatus->rx_mimo_signalquality[n_stream] != -1) { +			if (rtlpriv->stats.rx_evm_percentage[n_stream] == 0) { +				rtlpriv->stats.rx_evm_percentage[n_stream] = +				    pstatus->rx_mimo_signalquality[n_stream]; +			} +			rtlpriv->stats.rx_evm_percentage[n_stream] = +			    ((rtlpriv->stats.rx_evm_percentage[n_stream] +			      * (RX_SMOOTH_FACTOR - 1)) + +			     (pstatus->rx_mimo_signalquality[n_stream] * 1)) / +			    (RX_SMOOTH_FACTOR); +		} +	} +} + +void stg_rtl_process_phyinfo(struct ieee80211_hw *hw, u8 *buffer, +			     struct rtl_stats *pstatus) +{ +	if (!pstatus->b_packet_matchbssid) +		return; + +	rtl_process_ui_rssi(hw, pstatus); +	rtl_process_pwdb(hw, pstatus); +	rtl_process_ui_link_quality(hw, pstatus); +} +EXPORT_SYMBOL(stg_rtl_process_phyinfo); diff --git a/drivers/staging/rtl8192ee/stats.h b/drivers/staging/rtl8192ee/stats.h new file mode 100644 index 00000000000..07284278530 --- /dev/null +++ b/drivers/staging/rtl8192ee/stats.h @@ -0,0 +1,43 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010  Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __RTL_STATS_H__ +#define __RTL_STATS_H__ + +#define	PHY_RSSI_SLID_WIN_MAX			100 +#define	PHY_LINKQUALITY_SLID_WIN_MAX		20 +#define	PHY_BEACON_RSSI_SLID_WIN_MAX		10 + +/* Rx smooth factor */ +#define	RX_SMOOTH_FACTOR			20 + +u8 stg_rtl_query_rxpwrpercentage(char antpower); +u8 stg_rtl_evm_db_to_percentage(char value); +u8 rtl_evm_dbm_jaguar(char value); +long stg_rtl_signal_scale_mapping(struct ieee80211_hw *hw, long currsig); +void stg_rtl_process_phyinfo(struct ieee80211_hw *hw, u8 *buffer, +			     struct rtl_stats *pstatus); + +#endif diff --git a/drivers/staging/rtl8192ee/wifi.h b/drivers/staging/rtl8192ee/wifi.h new file mode 100644 index 00000000000..96fa261a70a --- /dev/null +++ b/drivers/staging/rtl8192ee/wifi.h @@ -0,0 +1,2644 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010  Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __RTL_WIFI_H__ +#define __RTL_WIFI_H__ + +#include <linux/interrupt.h> +#include <linux/sched.h> +#include <linux/firmware.h> +#include <linux/etherdevice.h> +#include <net/mac80211.h> +#include "debug.h" + + +#define RF_CHANGE_BY_INIT		0 +#define RF_CHANGE_BY_IPS		BIT(28) +#define RF_CHANGE_BY_PS			BIT(29) +#define RF_CHANGE_BY_HW			BIT(30) +#define RF_CHANGE_BY_SW			BIT(31) + +#define IQK_ADDA_REG_NUM		16 +#define IQK_MAC_REG_NUM			4 +#define IQK_THRESHOLD			8 + +#define MAX_KEY_LEN			61 +#define KEY_BUF_SIZE			5 + +/* QoS related. */ +/*aci: 0x00	Best Effort*/ +/*aci: 0x01	Background*/ +/*aci: 0x10	Video*/ +/*aci: 0x11	Voice*/ +/*Max: define total number.*/ +#define AC0_BE				0 +#define AC1_BK				1 +#define AC2_VI				2 +#define AC3_VO				3 +#define AC_MAX				4 +#define QOS_QUEUE_NUM			4 +#define RTL_MAC80211_NUM_QUEUE		5 + +#define QBSS_LOAD_SIZE			5 +#define MAX_WMMELE_LENGTH		64 + +#define TOTAL_CAM_ENTRY			32 + +/*slot time for 11g. */ +#define RTL_SLOT_TIME_9			9 +#define RTL_SLOT_TIME_20		20 + +/*related with tcp/ip. */ +/*if_ehther.h*/ +#define ETH_P_PAE			0x888E	/*Port Access Entity +						 *(IEEE 802.1X) */ +#define ETH_P_IP			0x0800	/*Internet Protocol packet */ +#define ETH_P_ARP			0x0806	/*Address Resolution packet */ +#define SNAP_SIZE			6 +#define PROTOC_TYPE_SIZE		2 + +/*related with 802.11 frame*/ +#define MAC80211_3ADDR_LEN		24 +#define MAC80211_4ADDR_LEN		30 + +#define CHANNEL_MAX_NUMBER		(14 + 24 + 21)	/* 14 is the max +							 * channel number */ +#define CHANNEL_MAX_NUMBER_2G		14 +#define CHANNEL_MAX_NUMBER_5G		54 /* Please refer to +					    *"phy_GetChnlGroup8812A" and +					    * "Hal_ReadTxPowerInfo8812A"*/ + +#define MAX_REGULATION_NUM			4 +#define MAX_RF_PATH_NUM	2 +#define MAX_RATE_SECTION_NUM		6 +#define MAX_2_4G_BANDWITH_NUM		2 +#define MAX_5G_BANDWITH_NUM		4 + + + + +#define CHANNEL_MAX_NUMBER_5G_80M	7 +#define CHANNEL_GROUP_MAX		(3 + 9)	/* ch1~3, ch4~9, ch10~14 +						 * total three groups */ +#define MAX_PG_GROUP			13 +#define	CHANNEL_GROUP_MAX_2G		3 +#define	CHANNEL_GROUP_IDX_5GL		3 +#define	CHANNEL_GROUP_IDX_5GM		6 +#define	CHANNEL_GROUP_IDX_5GH		9 +#define	CHANNEL_GROUP_MAX_5G		9 +#define CHANNEL_MAX_NUMBER_2G		14 +#define AVG_THERMAL_NUM			8 +#define AVG_THERMAL_NUM_92E		4 +#define AVG_THERMAL_NUM_88E		4 +#define AVG_THERMAL_NUM_8723BE		4 +#define MAX_TID_COUNT			9 +#define MAX_NUM_RATES			264 + +/*for 88E use*/ +/*It must always set to 4, otherwise read efuse table secquence will be wrong.*/ +#define MAX_TX_COUNT			4 +#define	MAX_RF_PATH			4 +#define	MAX_CHNL_GROUP_24G		6 +#define	MAX_CHNL_GROUP_5G		14 + +/* BK, BE, VI, VO, HCCA, MANAGEMENT, COMMAND, HIGH, BEACON. */ +#define MAX_TX_QUEUE			9 + +#define TX_PWR_BY_RATE_NUM_BAND		2 +#define TX_PWR_BY_RATE_NUM_RF		4 +#define TX_PWR_BY_RATE_NUM_SECTION	12 +#define MAX_BASE_NUM_IN_PHY_REG_PG_24G  6 +#define MAX_BASE_NUM_IN_PHY_REG_PG_5G	5 + +#define DELTA_SWINGIDX_SIZE	30 +#define BAND_NUM				3 +/*Now, it's just for 8192ee + *not OK yet, keep it 0*/ +#define DMA_IS_64BIT 0 +#define RTL8192EE_SEG_NUM		1 /* 0:2 seg, 1: 4 seg, 2: 8 seg */ + + +#define PACKET_NORMAL			0 +#define PACKET_DHCP			1 +#define PACKET_ARP			2 +#define PACKET_EAPOL			3 + +#define	MAX_SUPPORT_WOL_PATTERN_NUM	16 +#define	RSVD_WOL_PATTERN_NUM		1 +#define	WKFMCAM_ADDR_NUM		6 +#define	WKFMCAM_SIZE			24 + +#define	MAX_WOL_BIT_MASK_SIZE		16 +/* MIN LEN keeps 13 here */ +#define	MIN_WOL_PATTERN_SIZE		13 +#define	MAX_WOL_PATTERN_SIZE		128 + +#define	WAKE_ON_MAGIC_PACKET		BIT(0) +#define	WAKE_ON_PATTERN_MATCH		BIT(1) + +#define	WOL_REASON_PTK_UPDATE		BIT(0) +#define	WOL_REASON_GTK_UPDATE		BIT(1) +#define	WOL_REASON_DISASSOC		BIT(2) +#define	WOL_REASON_DEAUTH		BIT(3) +#define	WOL_REASON_AP_LOST		BIT(4) +#define	WOL_REASON_MAGIC_PKT		BIT(5) +#define	WOL_REASON_UNICAST_PKT		BIT(6) +#define	WOL_REASON_PATTERN_PKT		BIT(7) +#define	WOL_REASON_RTD3_SSID_MATCH	BIT(8) +#define	WOL_REASON_REALWOW_V2_WAKEUPPKT	BIT(9) +#define	WOL_REASON_REALWOW_V2_ACKLOST	BIT(10) + +struct txpower_info_2g { +	u8 index_cck_base[MAX_RF_PATH][MAX_CHNL_GROUP_24G]; +	u8 index_bw40_base[MAX_RF_PATH][MAX_CHNL_GROUP_24G]; +	/*If only one tx, only BW20 and OFDM are used.*/ +	u8 cck_diff[MAX_RF_PATH][MAX_TX_COUNT]; +	u8 ofdm_diff[MAX_RF_PATH][MAX_TX_COUNT]; +	u8 bw20_diff[MAX_RF_PATH][MAX_TX_COUNT]; +	u8 bw40_diff[MAX_RF_PATH][MAX_TX_COUNT]; +}; + +struct txpower_info_5g { +	u8 index_bw40_base[MAX_RF_PATH][MAX_CHNL_GROUP_5G]; +	/*If only one tx, only BW20, OFDM, BW80 and BW160 are used.*/ +	u8 ofdm_diff[MAX_RF_PATH][MAX_TX_COUNT]; +	u8 bw20_diff[MAX_RF_PATH][MAX_TX_COUNT]; +	u8 bw40_diff[MAX_RF_PATH][MAX_TX_COUNT]; +	u8 bw80_diff[MAX_RF_PATH][MAX_TX_COUNT]; +	u8 bw160_diff[MAX_RF_PATH][MAX_TX_COUNT]; +}; + + +/* for early mode */ +#define EM_HDR_LEN			8 +#define FCS_LEN				4 + +#define MAX_VIRTUAL_MAC			1 + +enum rf_tx_num { +	RF_1TX = 0, +	RF_2TX, +	RF_MAX_TX_NUM, +	RF_TX_NUM_NONIMPLEMENT, +}; + +enum rate_section { +	CCK = 0, +	OFDM, +	HT_MCS0_MCS7, +	HT_MCS8_MCS15, +	VHT_1SSMCS0_1SSMCS9, +	VHT_2SSMCS0_2SSMCS9, +}; + +enum intf_type { +	INTF_PCI = 0, +	INTF_USB = 1, +}; + +enum radio_path { +	RF90_PATH_A = 0, +	RF90_PATH_B = 1, +	RF90_PATH_C = 2, +	RF90_PATH_D = 3, +}; + +enum regulation_txpwr_lmt { +	TXPWR_LMT_FCC = 0, +	TXPWR_LMT_MKK = 1, +	TXPWR_LMT_ETSI = 2, +	TXPWR_LMT_WW = 3, + +	TXPWR_LMT_MAX_REGULATION_NUM = 4 +}; + + +enum rt_eeprom_type { +	EEPROM_93C46, +	EEPROM_93C56, +	EEPROM_BOOT_EFUSE, +}; + +enum rtl_status { +	RTL_STATUS_INTERFACE_START = 0, +}; + +enum hardware_type { +	HARDWARE_TYPE_RTL8192E, +	HARDWARE_TYPE_RTL8192U, +	HARDWARE_TYPE_RTL8192SE, +	HARDWARE_TYPE_RTL8192SU, +	HARDWARE_TYPE_RTL8192CE, +	HARDWARE_TYPE_RTL8192CU, +	HARDWARE_TYPE_RTL8192DE, +	HARDWARE_TYPE_RTL8192DU, +	HARDWARE_TYPE_RTL8723AE, +	HARDWARE_TYPE_RTL8188EE, +	HARDWARE_TYPE_RTL8723BE, +	HARDWARE_TYPE_RTL8192EE, +	HARDWARE_TYPE_RTL8821AE, +	HARDWARE_TYPE_RTL8812AE, +	/* keep it last */ +	HARDWARE_TYPE_NUM +}; + +enum scan_operation_backup_opt { +	SCAN_OPT_BACKUP_BAND0 = 0, +	SCAN_OPT_BACKUP_BAND1, +	SCAN_OPT_RESTORE, +	SCAN_OPT_MAX +}; + +/*RF state.*/ +enum rf_pwrstate { +	ERFON, +	ERFSLEEP, +	ERFOFF +}; + +struct bb_reg_def { +	u32 rfintfs; +	u32 rfintfi; +	u32 rfintfo; +	u32 rfintfe; +	u32 rf3wire_offset; +	u32 rflssi_select; +	u32 rftxgain_stage; +	u32 rfhssi_para1; +	u32 rfhssi_para2; +	u32 rfswitch_control; +	u32 rfagc_control1; +	u32 rfagc_control2; +	u32 rfrxiq_imbalance; +	u32 rfrx_afe; +	u32 rftxiq_imbalance; +	u32 rftx_afe; +	u32 rflssi_readback; +	u32 rflssi_readbackpi; +}; + +enum io_type { +	IO_CMD_PAUSE_BAND0_DM_BY_SCAN = 0, +	IO_CMD_PAUSE_BAND1_DM_BY_SCAN = 1, +	IO_CMD_RESUME_DM_BY_SCAN = 2, +}; + +enum hw_variables { +	HW_VAR_ETHER_ADDR, +	HW_VAR_MULTICAST_REG, +	HW_VAR_BASIC_RATE, +	HW_VAR_BSSID, +	HW_VAR_MEDIA_STATUS, +	HW_VAR_SECURITY_CONF, +	HW_VAR_BEACON_INTERVAL, +	HW_VAR_ATIM_WINDOW, +	HW_VAR_LISTEN_INTERVAL, +	HW_VAR_CS_COUNTER, +	HW_VAR_DEFAULTKEY0, +	HW_VAR_DEFAULTKEY1, +	HW_VAR_DEFAULTKEY2, +	HW_VAR_DEFAULTKEY3, +	HW_VAR_SIFS, +	HW_VAR_R2T_SIFS, +	HW_VAR_DIFS, +	HW_VAR_EIFS, +	HW_VAR_SLOT_TIME, +	HW_VAR_ACK_PREAMBLE, +	HW_VAR_CW_CONFIG, +	HW_VAR_CW_VALUES, +	HW_VAR_RATE_FALLBACK_CONTROL, +	HW_VAR_CONTENTION_WINDOW, +	HW_VAR_RETRY_COUNT, +	HW_VAR_TR_SWITCH, +	HW_VAR_COMMAND, +	HW_VAR_WPA_CONFIG, +	HW_VAR_AMPDU_MIN_SPACE, +	HW_VAR_SHORTGI_DENSITY, +	HW_VAR_AMPDU_FACTOR, +	HW_VAR_MCS_RATE_AVAILABLE, +	HW_VAR_AC_PARAM, +	HW_VAR_ACM_CTRL, +	HW_VAR_DIS_Req_Qsize, +	HW_VAR_CCX_CHNL_LOAD, +	HW_VAR_CCX_NOISE_HISTOGRAM, +	HW_VAR_CCX_CLM_NHM, +	HW_VAR_TxOPLimit, +	HW_VAR_TURBO_MODE, +	HW_VAR_RF_STATE, +	HW_VAR_RF_OFF_BY_HW, +	HW_VAR_BUS_SPEED, +	HW_VAR_SET_DEV_POWER, + +	HW_VAR_RCR, +	HW_VAR_RATR_0, +	HW_VAR_RRSR, +	HW_VAR_CPU_RST, +	HW_VAR_CECHK_BSSID, +	HW_VAR_LBK_MODE, +	HW_VAR_AES_11N_FIX, +	HW_VAR_USB_RX_AGGR, +	HW_VAR_USER_CONTROL_TURBO_MODE, +	HW_VAR_RETRY_LIMIT, +	HW_VAR_INIT_TX_RATE, +	HW_VAR_TX_RATE_REG, +	HW_VAR_EFUSE_USAGE, +	HW_VAR_EFUSE_BYTES, +	HW_VAR_AUTOLOAD_STATUS, +	HW_VAR_RF_2R_DISABLE, +	HW_VAR_SET_RPWM, +	HW_VAR_H2C_FW_PWRMODE, +	HW_VAR_H2C_FW_JOINBSSRPT, +	HW_VAR_H2C_FW_MEDIASTATUSRPT, +	HW_VAR_H2C_FW_P2P_PS_OFFLOAD, +	HW_VAR_FW_PSMODE_STATUS, +	HW_VAR_INIT_RTS_RATE, +	HW_VAR_RESUME_CLK_ON, +	HW_VAR_FW_LPS_ACTION, +	HW_VAR_1X1_RECV_COMBINE, +	HW_VAR_STOP_SEND_BEACON, +	HW_VAR_TSF_TIMER, +	HW_VAR_IO_CMD, + +	HW_VAR_RF_RECOVERY, +	HW_VAR_H2C_FW_UPDATE_GTK, +	HW_VAR_WF_MASK, +	HW_VAR_WF_CRC, +	HW_VAR_WF_IS_MAC_ADDR, +	HW_VAR_H2C_FW_OFFLOAD, +	HW_VAR_RESET_WFCRC, + +	HW_VAR_HANDLE_FW_C2H, +	HW_VAR_DL_FW_RSVD_PAGE, +	HW_VAR_AID, +	HW_VAR_HW_SEQ_ENABLE, +	HW_VAR_CORRECT_TSF, +	HW_VAR_BCN_VALID, +	HW_VAR_FWLPS_RF_ON, +	HW_VAR_DUAL_TSF_RST, +	HW_VAR_SWITCH_EPHY_WoWLAN, +	HW_VAR_INT_MIGRATION, +	HW_VAR_INT_AC, +	HW_VAR_RF_TIMING, + +	HAL_DEF_WOWLAN, +	HW_VAR_MRC, +	HW_VAR_KEEP_ALIVE, +	HW_VAR_NAV_UPPER, +}; + +enum rt_media_status { +	RT_MEDIA_DISCONNECT = 0, +	RT_MEDIA_CONNECT = 1 +}; + +enum rt_oem_id { +	RT_CID_DEFAULT = 0, +	RT_CID_8187_ALPHA0 = 1, +	RT_CID_8187_SERCOMM_PS = 2, +	RT_CID_8187_HW_LED = 3, +	RT_CID_8187_NETGEAR = 4, +	RT_CID_WHQL = 5, +	RT_CID_819x_CAMEO = 6, +	RT_CID_819x_RUNTOP = 7, +	RT_CID_819x_Senao = 8, +	RT_CID_TOSHIBA = 9, +	RT_CID_819x_Netcore = 10, +	RT_CID_Nettronix = 11, +	RT_CID_DLINK = 12, +	RT_CID_PRONET = 13, +	RT_CID_COREGA = 14, +	RT_CID_819x_ALPHA = 15, +	RT_CID_819x_Sitecom = 16, +	RT_CID_CCX = 17, +	RT_CID_819x_Lenovo = 18, +	RT_CID_819x_QMI = 19, +	RT_CID_819x_Edimax_Belkin = 20, +	RT_CID_819x_Sercomm_Belkin = 21, +	RT_CID_819x_CAMEO1 = 22, +	RT_CID_819x_MSI = 23, +	RT_CID_819x_Acer = 24, +	RT_CID_819x_HP = 27, +	RT_CID_819x_CLEVO = 28, +	RT_CID_819x_Arcadyan_Belkin = 29, +	RT_CID_819x_SAMSUNG = 30, +	RT_CID_819x_WNC_COREGA = 31, +	RT_CID_819x_Foxcoon = 32, +	RT_CID_819x_DELL = 33, +	RT_CID_819x_PRONETS = 34, +	RT_CID_819x_Edimax_ASUS = 35, +	RT_CID_NETGEAR = 36, +	RT_CID_PLANEX = 37, +	RT_CID_CC_C = 38, +}; + +enum hw_descs { +	HW_DESC_OWN, +	HW_DESC_RXOWN, +	HW_DESC_TX_NEXTDESC_ADDR, +	HW_DESC_TXBUFF_ADDR, +	HW_DESC_RXBUFF_ADDR, +	HW_DESC_RXPKT_LEN, +	HW_DESC_RXERO, +	HW_DESC_RX_PREPARE, +}; + +enum prime_sc { +	PRIME_CHNL_OFFSET_DONT_CARE = 0, +	PRIME_CHNL_OFFSET_LOWER = 1, +	PRIME_CHNL_OFFSET_UPPER = 2, +}; + +enum rf_type { +	RF_1T1R = 0, +	RF_1T2R = 1, +	RF_2T2R = 2, +	RF_2T2R_GREEN = 3, +}; + +enum ht_channel_width { +	HT_CHANNEL_WIDTH_20 = 0, +	HT_CHANNEL_WIDTH_20_40 = 1, +	HT_CHANNEL_WIDTH_80 = 2, +}; + +/* Ref: 802.11i sepc D10.0 7.3.2.25.1 +Cipher Suites Encryption Algorithms */ +enum rt_enc_alg { +	NO_ENCRYPTION = 0, +	WEP40_ENCRYPTION = 1, +	TKIP_ENCRYPTION = 2, +	RSERVED_ENCRYPTION = 3, +	AESCCMP_ENCRYPTION = 4, +	WEP104_ENCRYPTION = 5, +	AESCMAC_ENCRYPTION = 6,	/*IEEE802.11w */ +}; + +enum rtl_hal_state { +	_HAL_STATE_STOP = 0, +	_HAL_STATE_START = 1, +}; + +enum rtl_var_map { +	/*reg map */ +	SYS_ISO_CTRL = 0, +	SYS_FUNC_EN, +	SYS_CLK, +	MAC_RCR_AM, +	MAC_RCR_AB, +	MAC_RCR_ACRC32, +	MAC_RCR_ACF, +	MAC_RCR_AAP, +	MAC_HIMR, +	MAC_HIMRE, +	MAC_HSISR, + +	/*efuse map */ +	EFUSE_TEST, +	EFUSE_CTRL, +	EFUSE_CLK, +	EFUSE_CLK_CTRL, +	EFUSE_PWC_EV12V, +	EFUSE_FEN_ELDR, +	EFUSE_LOADER_CLK_EN, +	EFUSE_ANA8M, +	EFUSE_HWSET_MAX_SIZE, +	EFUSE_MAX_SECTION_MAP, +	EFUSE_REAL_CONTENT_SIZE, +	EFUSE_OOB_PROTECT_BYTES_LEN, +	EFUSE_ACCESS, +	/*CAM map */ +	RWCAM, +	WCAMI, +	RCAMO, +	CAMDBG, +	SECR, +	SEC_CAM_NONE, +	SEC_CAM_WEP40, +	SEC_CAM_TKIP, +	SEC_CAM_AES, +	SEC_CAM_WEP104, + +	/*IMR map */ +	RTL_IMR_BCNDMAINT6,	/*Beacon DMA Interrupt 6 */ +	RTL_IMR_BCNDMAINT5,	/*Beacon DMA Interrupt 5 */ +	RTL_IMR_BCNDMAINT4,	/*Beacon DMA Interrupt 4 */ +	RTL_IMR_BCNDMAINT3,	/*Beacon DMA Interrupt 3 */ +	RTL_IMR_BCNDMAINT2,	/*Beacon DMA Interrupt 2 */ +	RTL_IMR_BCNDMAINT1,	/*Beacon DMA Interrupt 1 */ +	RTL_IMR_BCNDOK8,	/*Beacon Queue DMA OK Interrup 8 */ +	RTL_IMR_BCNDOK7,	/*Beacon Queue DMA OK Interrup 7 */ +	RTL_IMR_BCNDOK6,	/*Beacon Queue DMA OK Interrup 6 */ +	RTL_IMR_BCNDOK5,	/*Beacon Queue DMA OK Interrup 5 */ +	RTL_IMR_BCNDOK4,	/*Beacon Queue DMA OK Interrup 4 */ +	RTL_IMR_BCNDOK3,	/*Beacon Queue DMA OK Interrup 3 */ +	RTL_IMR_BCNDOK2,	/*Beacon Queue DMA OK Interrup 2 */ +	RTL_IMR_BCNDOK1,	/*Beacon Queue DMA OK Interrup 1 */ +	RTL_IMR_TIMEOUT2,	/*Timeout interrupt 2 */ +	RTL_IMR_TIMEOUT1,	/*Timeout interrupt 1 */ +	RTL_IMR_TXFOVW,		/*Transmit FIFO Overflow */ +	RTL_IMR_PSTIMEOUT,	/*Power save time out interrupt */ +	RTL_IMR_BcnInt,		/*Beacon DMA Interrupt 0 */ +	RTL_IMR_RXFOVW,		/*Receive FIFO Overflow */ +	RTL_IMR_RDU,		/*Receive Descriptor Unavailable */ +	RTL_IMR_ATIMEND,	/*For 92C,ATIM Window End Interrupt */ +	RTL_IMR_BDOK,		/*Beacon Queue DMA OK Interrup */ +	RTL_IMR_HIGHDOK,	/*High Queue DMA OK Interrupt */ +	RTL_IMR_COMDOK,		/*Command Queue DMA OK Interrupt*/ +	RTL_IMR_TBDOK,		/*Transmit Beacon OK interrup */ +	RTL_IMR_MGNTDOK,	/*Management Queue DMA OK Interrupt */ +	RTL_IMR_TBDER,		/*For 92C,Transmit Beacon Error Interrupt */ +	RTL_IMR_BKDOK,		/*AC_BK DMA OK Interrupt */ +	RTL_IMR_BEDOK,		/*AC_BE DMA OK Interrupt */ +	RTL_IMR_VIDOK,		/*AC_VI DMA OK Interrupt */ +	RTL_IMR_VODOK,		/*AC_VO DMA Interrupt */ +	RTL_IMR_ROK,		/*Receive DMA OK Interrupt */ +	RTL_IMR_HSISR_IND,  /*HSISR Interrupt*/ +	RTL_IBSS_INT_MASKS,	/*(RTL_IMR_BcnInt | RTL_IMR_TBDOK | +				 * RTL_IMR_TBDER) */ +	RTL_IMR_C2HCMD,		/*fw interrupt*/ + +	/*CCK Rates, TxHT = 0 */ +	RTL_RC_CCK_RATE1M, +	RTL_RC_CCK_RATE2M, +	RTL_RC_CCK_RATE5_5M, +	RTL_RC_CCK_RATE11M, + +	/*OFDM Rates, TxHT = 0 */ +	RTL_RC_OFDM_RATE6M, +	RTL_RC_OFDM_RATE9M, +	RTL_RC_OFDM_RATE12M, +	RTL_RC_OFDM_RATE18M, +	RTL_RC_OFDM_RATE24M, +	RTL_RC_OFDM_RATE36M, +	RTL_RC_OFDM_RATE48M, +	RTL_RC_OFDM_RATE54M, + +	RTL_RC_HT_RATEMCS7, +	RTL_RC_HT_RATEMCS15, + +	RTL_RC_VHT_RATE_1SS_MCS7, +	RTL_RC_VHT_RATE_1SS_MCS8, +	RTL_RC_VHT_RATE_1SS_MCS9, +	RTL_RC_VHT_RATE_2SS_MCS7, +	RTL_RC_VHT_RATE_2SS_MCS8, +	RTL_RC_VHT_RATE_2SS_MCS9, + +	/*keep it last */ +	RTL_VAR_MAP_MAX, +}; + +/*Firmware PS mode for control LPS.*/ +enum _fw_ps_mode { +	FW_PS_ACTIVE_MODE = 0, +	FW_PS_MIN_MODE = 1, +	FW_PS_MAX_MODE = 2, +	FW_PS_DTIM_MODE = 3, +	FW_PS_VOIP_MODE = 4, +	FW_PS_UAPSD_WMM_MODE = 5, +	FW_PS_UAPSD_MODE = 6, +	FW_PS_IBSS_MODE = 7, +	FW_PS_WWLAN_MODE = 8, +	FW_PS_PM_Radio_Off = 9, +	FW_PS_PM_Card_Disable = 10, +}; + +enum rt_psmode { +	EACTIVE,		/*Active/Continuous access. */ +	EMAXPS,			/*Max power save mode. */ +	EFASTPS,		/*Fast power save mode. */ +	EAUTOPS,		/*Auto power save mode. */ +}; + +/*LED related.*/ +enum led_ctl_mode { +	LED_CTL_POWER_ON = 1, +	LED_CTL_LINK = 2, +	LED_CTL_NO_LINK = 3, +	LED_CTL_TX = 4, +	LED_CTL_RX = 5, +	LED_CTL_SITE_SURVEY = 6, +	LED_CTL_POWER_OFF = 7, +	LED_CTL_START_TO_LINK = 8, +	LED_CTL_START_WPS = 9, +	LED_CTL_STOP_WPS = 10, +}; + +enum rtl_led_pin { +	LED_PIN_GPIO0, +	LED_PIN_LED0, +	LED_PIN_LED1, +	LED_PIN_LED2 +}; + +/*QoS related.*/ +/*acm implementation method.*/ +enum acm_method { +	eAcmWay0_SwAndHw = 0, +	eAcmWay1_HW = 1, +	eAcmWay2_SW = 2, +}; + +enum macphy_mode { +	SINGLEMAC_SINGLEPHY = 0, +	DUALMAC_DUALPHY, +	DUALMAC_SINGLEPHY, +}; + +enum band_type { +	BAND_ON_2_4G = 0, +	BAND_ON_5G, +	BAND_ON_BOTH, +	BANDMAX +}; + +/*aci/aifsn Field. +Ref: WMM spec 2.2.2: WME Parameter Element, p.12.*/ +union aci_aifsn { +	u8 char_data; + +	struct { +		u8 aifsn:4; +		u8 acm:1; +		u8 aci:2; +		u8 reserved:1; +	} f;			/* Field */ +}; + +/*mlme related.*/ +enum wireless_mode { +	WIRELESS_MODE_UNKNOWN = 0x00, +	WIRELESS_MODE_A = 0x01, +	WIRELESS_MODE_B = 0x02, +	WIRELESS_MODE_G = 0x04, +	WIRELESS_MODE_AUTO = 0x08, +	WIRELESS_MODE_N_24G = 0x10, +	WIRELESS_MODE_N_5G = 0x20, +	WIRELESS_MODE_AC_5G = 0x40, +	WIRELESS_MODE_AC_24G = 0x80, +	WIRELESS_MODE_AC_ONLY = 0x100, +	WIRELESS_MODE_MAX = 0x800 +}; + +enum ratr_table_mode { +	RATR_INX_WIRELESS_NGB = 0, +	RATR_INX_WIRELESS_NG = 1, +	RATR_INX_WIRELESS_NB = 2, +	RATR_INX_WIRELESS_N = 3, +	RATR_INX_WIRELESS_GB = 4, +	RATR_INX_WIRELESS_G = 5, +	RATR_INX_WIRELESS_B = 6, +	RATR_INX_WIRELESS_MC = 7, +	RATR_INX_WIRELESS_AC_5N = 8, +	RATR_INX_WIRELESS_AC_24N = 9, +}; + +enum rtl_link_state { +	MAC80211_NOLINK = 0, +	MAC80211_LINKING = 1, +	MAC80211_LINKED = 2, +	MAC80211_LINKED_SCANNING = 3, +}; + +enum act_category { +	ACT_CAT_QOS = 1, +	ACT_CAT_DLS = 2, +	ACT_CAT_BA = 3, +	ACT_CAT_HT = 7, +	ACT_CAT_WMM = 17, +}; + +enum ba_action { +	ACT_ADDBAREQ = 0, +	ACT_ADDBARSP = 1, +	ACT_DELBA = 2, +}; + +enum rt_polarity_ctl { +	RT_POLARITY_LOW_ACT = 0, +	RT_POLARITY_HIGH_ACT = 1, +}; + +/* After 8188E, we use V2 reason define. 88C/8723A use V1 reason. */ +enum fw_wow_reason_v2 { +	FW_WOW_V2_PTK_UPDATE_EVENT = 0x01, +	FW_WOW_V2_GTK_UPDATE_EVENT = 0x02, +	FW_WOW_V2_DISASSOC_EVENT = 0x04, +	FW_WOW_V2_DEAUTH_EVENT = 0x08, +	FW_WOW_V2_FW_DISCONNECT_EVENT = 0x10, +	FW_WOW_V2_MAGIC_PKT_EVENT = 0x21, +	FW_WOW_V2_UNICAST_PKT_EVENT = 0x22, +	FW_WOW_V2_PATTERN_PKT_EVENT = 0x23, +	FW_WOW_V2_RTD3_SSID_MATCH_EVENT = 0x24, +	FW_WOW_V2_REALWOW_V2_WAKEUPPKT = 0x30, +	FW_WOW_V2_REALWOW_V2_ACKLOST = 0x31, +	FW_WOW_V2_REASON_MAX = 0xff, +}; + +enum wolpattern_type { +	UNICAST_PATTERN = 0, +	MULTICAST_PATTERN = 1, +	BROADCAST_PATTERN = 2, +	DONT_CARE_DA = 3, +	UNKNOWN_TYPE = 4, +}; + +struct octet_string { +	u8 *octet; +	u16 length; +}; + +struct rtl_hdr_3addr { +	__le16 frame_ctl; +	__le16 duration_id; +	u8 addr1[ETH_ALEN]; +	u8 addr2[ETH_ALEN]; +	u8 addr3[ETH_ALEN]; +	__le16 seq_ctl; +	u8 payload[0]; +} __packed; + +struct rtl_info_element { +	u8 id; +	u8 len; +	u8 data[0]; +} __packed; + +struct rtl_probe_rsp { +	struct rtl_hdr_3addr header; +	u32 time_stamp[2]; +	__le16 beacon_interval; +	__le16 capability; +	/*SSID, supported rates, FH params, DS params, +	   CF params, IBSS params, TIM (if beacon), RSN */ +	struct rtl_info_element info_element[0]; +} __packed; + +/*LED related.*/ +/*ledpin Identify how to implement this SW led.*/ +struct rtl_led { +	void *hw; +	enum rtl_led_pin ledpin; +	bool b_ledon; +}; + +struct rtl_led_ctl { +	bool bled_opendrain; +	struct rtl_led sw_led0; +	struct rtl_led sw_led1; +}; + +struct rtl_qos_parameters { +	__le16 cw_min; +	__le16 cw_max; +	u8 aifs; +	u8 flag; +	__le16 tx_op; +} __packed; + +struct rt_smooth_data { +	u32 elements[100];	/*array to store values */ +	u32 index;		/*index to current array to store */ +	u32 total_num;		/*num of valid elements */ +	u32 total_val;		/*sum of valid elements */ +}; + +struct rtl_ht_agg { +	u16 txq_id; +	u16 wait_for_ba; +	u16 start_idx; +	u64 bitmap; +	u32 rate_n_flags; +	u8 agg_state; +	u8 rx_agg_state; +}; + +struct rtl_tid_data { +	u16 seq_number; +	struct rtl_ht_agg agg; +}; + +struct rssi_sta { +	long undecorated_smoothed_pwdb; +}; + +struct rtl_sta_info { +	struct list_head list; +	u8 ratr_index; +	u8 wireless_mode; +	u8 mimo_ps; +	u8 mac_addr[6]; +	struct rtl_tid_data tids[MAX_TID_COUNT]; + +	/* just used for ap adhoc or mesh*/ +	struct rssi_sta rssi_stat; +} __packed; + +struct false_alarm_statistics { +	u32 cnt_parity_fail; +	u32 cnt_rate_illegal; +	u32 cnt_crc8_fail; +	u32 cnt_mcs_fail; +	u32 cnt_fast_fsync_fail; +	u32 cnt_sb_search_fail; +	u32 cnt_ofdm_fail; +	u32 cnt_cck_fail; +	u32 cnt_all; +	u32 cnt_ofdm_cca; +	u32 cnt_cck_cca; +	u32 cnt_cca_all; +	u32 cnt_bw_usc; +	u32 cnt_bw_lsc; +}; + +struct init_gain { +	u8 xaagccore1; +	u8 xbagccore1; +	u8 xcagccore1; +	u8 xdagccore1; +	u8 cca; + +}; + +struct wireless_stats { +	unsigned long txbytesunicast; +	unsigned long txbytesmulticast; +	unsigned long txbytesbroadcast; +	unsigned long rxbytesunicast; + +	long rx_snr_db[4]; +	/*Correct smoothed ss in Dbm, only used +	   in driver to report real power now. */ +	long recv_signal_power; +	long signal_quality; +	long last_sigstrength_inpercent; + +	u32 rssi_calculate_cnt; +	u32 pwdb_all_cnt; + +	/*Transformed, in dbm. Beautified signal +	   strength for UI, not correct. */ +	long signal_strength; + +	u8 rx_rssi_percentage[4]; +	u8 rx_evm_dbm[4]; +	u8 rx_evm_percentage[2]; + +	u16 rx_cfo_short[4]; +	u16 rx_cfo_tail[4]; + +	struct rt_smooth_data ui_rssi; +	struct rt_smooth_data ui_link_quality; +}; + +struct rate_adaptive { +	u8 rate_adaptive_disabled; +	u8 ratr_state; +	u16 reserve; + +	u32 high_rssi_thresh_for_ra; +	u32 high2low_rssi_thresh_for_ra; +	u8 low2high_rssi_thresh_for_ra; +	u32 low_rssi_thresh_for_ra; +	u32 upper_rssi_threshold_ratr; +	u32 middleupper_rssi_threshold_ratr; +	u32 middle_rssi_threshold_ratr; +	u32 middlelow_rssi_threshold_ratr; +	u32 low_rssi_threshold_ratr; +	u32 ultralow_rssi_threshold_ratr; +	u32 low_rssi_threshold_ratr_40m; +	u32 low_rssi_threshold_ratr_20m; +	u8 ping_rssi_enable; +	u32 ping_rssi_ratr; +	u32 ping_rssi_thresh_for_ra; +	u32 last_ratr; +	u8 pre_ratr_state; +	u8 ldpc_thres; +	bool use_ldpc; +	bool lower_rts_rate; +	bool is_special_data; +}; + +struct regd_pair_mapping { +	u16 reg_dmnenum; +	u16 reg_5ghz_ctl; +	u16 reg_2ghz_ctl; +}; + +struct dynamic_primary_cca { +	u8 pricca_flag; +	u8 intf_flag; +	u8 intf_type; +	u8 dup_rts_flag; +	u8 monitor_flag; +	u8 ch_offset; +	u8 mf_state; +}; + +struct rtl_regulatory { +	char alpha2[2]; +	u16 country_code; +	u16 max_power_level; +	u32 tp_scale; +	u16 current_rd; +	u16 current_rd_ext; +	int16_t power_limit; +	struct regd_pair_mapping *regpair; +}; + +struct rtl_rfkill { +	bool rfkill_state;	/*0 is off, 1 is on */ +}; + +/*for P2P PS**/ +#define	P2P_MAX_NOA_NUM		2 + +enum p2p_role { +	P2P_ROLE_DISABLE = 0, +	P2P_ROLE_DEVICE = 1, +	P2P_ROLE_CLIENT = 2, +	P2P_ROLE_GO = 3 +}; + +enum p2p_ps_state { +	P2P_PS_DISABLE = 0, +	P2P_PS_ENABLE = 1, +	P2P_PS_SCAN = 2, +	P2P_PS_SCAN_DONE = 3, +	P2P_PS_ALLSTASLEEP = 4, /* for P2P GO */ +}; + +enum p2p_ps_mode { +	P2P_PS_NONE = 0, +	P2P_PS_CTWINDOW = 1, +	P2P_PS_NOA = 2, +	P2P_PS_MIX = 3, /* CTWindow and NoA*/ +}; + +struct rtl_p2p_ps_info { +	enum p2p_ps_mode p2p_ps_mode; /* indicate p2p ps mode */ +	enum p2p_ps_state p2p_ps_state; /* indicate p2p ps state */ +	u8 noa_index; /* Identifies and instance of Notice of Absence timing. */ +	/* Client traffic window. A period of time in TU after TBTT. */ +	u8 ctwindow; +	u8 opp_ps; /* opportunistic power save. */ +	u8 noa_num; /* number of NoA descriptor in P2P IE. */ +	/* Count for owner, Type of client. */ +	u8 noa_count_type[P2P_MAX_NOA_NUM]; +	/* Max duration for owner, preferred or +	 * min acceptable duration for client. */ +	u32 noa_duration[P2P_MAX_NOA_NUM]; +	/* Length of interval for owner, preferred or +	 * max acceptable interval of client. */ +	u32 noa_interval[P2P_MAX_NOA_NUM]; +	/* schedule expressed in terms of the lower 4 bytes of the TSF timer. */ +	u32 noa_start_time[P2P_MAX_NOA_NUM]; +}; + +struct p2p_ps_offload_t { +	u8 Offload_En:1; +	u8 role:1; /* 1: Owner, 0: Client */ +	u8 CTWindow_En:1; +	u8 NoA0_En:1; +	u8 NoA1_En:1; +	u8 AllStaSleep:1; +	u8 discovery:1; +	u8 reserved:1; +}; + +#define IQK_MATRIX_REG_NUM	8 +/* Channels_2_4G_NUM + Channels_5G_20M_NUM + Channels_5G */ +#define IQK_MATRIX_SETTINGS_NUM	(14 + 24 + 21) +struct iqk_matrix_regs { +	bool b_iqk_done; +	long value[1][IQK_MATRIX_REG_NUM]; +}; + +struct rtl_phy { +	struct bb_reg_def phyreg_def[4];	/*Radio A/B/C/D */ +	struct init_gain initgain_backup; +	enum io_type current_io_type; + +	u8 rf_mode; +	u8 rf_type; +	u8 current_chan_bw; +	u8 set_bwmode_inprogress; +	u8 sw_chnl_inprogress; +	u8 sw_chnl_stage; +	u8 sw_chnl_step; +	u8 current_channel; +	u8 h2c_box_num; +	u8 set_io_inprogress; +	u8 lck_inprogress; +	bool iqk_inprogress; + +	/* record for power tracking */ +	s32 reg_e94; +	s32 reg_e9c; +	s32 reg_ea4; +	s32 reg_eac; +	s32 reg_eb4; +	s32 reg_ebc; +	s32 reg_ec4; +	s32 reg_ecc; +	u8 rfpienable; +	u8 reserve_0; +	u16 reserve_1; +	u32 reg_c04, reg_c08, reg_874; +	u32 adda_backup[16]; +	u32 iqk_mac_backup[IQK_MAC_REG_NUM]; +	u32 iqk_bb_backup[10]; +	bool iqk_initialized; + +	bool rfpath_rx_enable[MAX_RF_PATH]; +	/*Jaguar*/ +	u8 reg_837; +	/* Dul mac */ +	bool b_need_iqk; +	struct iqk_matrix_regs iqk_matrix_regsetting[IQK_MATRIX_SETTINGS_NUM]; + +	bool b_rfpi_enable; + +	u8 pwrgroup_cnt; +	u8 bcck_high_power; +	/* this is for 88E & 8723A */ +	u32 mcs_txpwrlevel_origoffset[MAX_PG_GROUP][16]; +	/* this is for 92EE */ +	u32 tx_power_by_rate_offset[TX_PWR_BY_RATE_NUM_BAND] +				   [TX_PWR_BY_RATE_NUM_RF] +				   [TX_PWR_BY_RATE_NUM_RF] +				   [TX_PWR_BY_RATE_NUM_SECTION]; +	u8 txpwr_by_rate_base_24g[TX_PWR_BY_RATE_NUM_RF] +				 [TX_PWR_BY_RATE_NUM_RF] +				 [MAX_BASE_NUM_IN_PHY_REG_PG_24G]; + +	u8 txpwr_by_rate_base_5g[TX_PWR_BY_RATE_NUM_RF] +				[TX_PWR_BY_RATE_NUM_RF] +				[MAX_BASE_NUM_IN_PHY_REG_PG_5G]; +	u8 default_initialgain[4]; + +	/* the current Tx power level */ +	u8 cur_cck_txpwridx; +	u8 cur_ofdm24g_txpwridx; +	u8 cur_bw20_txpwridx; +	u8 cur_bw40_txpwridx; + +	char txpwr_limit_2_4g[MAX_REGULATION_NUM] +				[MAX_2_4G_BANDWITH_NUM] +				[MAX_RATE_SECTION_NUM] +				[CHANNEL_MAX_NUMBER_2G] +				[MAX_RF_PATH_NUM]; +	char txpwr_limit_5g[MAX_REGULATION_NUM] +			   [MAX_5G_BANDWITH_NUM] +			   [MAX_RATE_SECTION_NUM] +			   [CHANNEL_MAX_NUMBER_5G] +			   [MAX_RF_PATH_NUM]; + +	u32 rfreg_chnlval[2]; +	bool b_apk_done; +	u32 reg_rf3c[2];	/* pathA / pathB  */ + +	u32 backup_rf_0x1a;/*92ee*/ +	/* bfsync */ +	u8 framesync; +	u32 framesync_c34; + +	u8 num_total_rfpath; +	u16 rf_pathmap; + +	enum rt_polarity_ctl polarity_ctl; +}; + +#define RTL_AGG_STOP						0 +#define RTL_AGG_PROGRESS					1 +#define RTL_AGG_START						2 +#define RTL_AGG_OPERATIONAL					3 +#define RTL_RX_AGG_START					1 +#define RTL_RX_AGG_STOP						0 + +struct rtl_priv; +struct rtl_io { +	struct device *dev; + +	/*PCI MEM map */ +	unsigned long pci_mem_end;	/*shared mem end        */ +	unsigned long pci_mem_start;	/*shared mem start */ + +	/*PCI IO map */ +	unsigned long pci_base_addr;	/*device I/O address */ + +	void (*write8_async)(struct rtl_priv *rtlpriv, u32 addr, u8 val); +	void (*write16_async)(struct rtl_priv *rtlpriv, u32 addr, u16 val); +	void (*write32_async)(struct rtl_priv *rtlpriv, u32 addr, u32 val); + +	u8 (*read8_sync)(struct rtl_priv *rtlpriv, u32 addr); +	u16 (*read16_sync)(struct rtl_priv *rtlpriv, u32 addr); +	u32 (*read32_sync)(struct rtl_priv *rtlpriv, u32 addr); + +}; + +struct rtl_mac { +	u8 mac_addr[ETH_ALEN]; +	u8 mac80211_registered; +	u8 beacon_enabled; + +	u32 tx_ss_num; +	u32 rx_ss_num; + +	struct ieee80211_supported_band bands[IEEE80211_NUM_BANDS]; +	struct ieee80211_hw *hw; +	struct ieee80211_vif *vif; +	enum nl80211_iftype opmode; + +	/*Probe Beacon management */ +	enum rtl_link_state link_state; + +	int n_channels; +	int n_bitrates; + +	bool offchan_deley; +	u8 p2p;	/*using p2p role*/ +	bool p2p_in_use; + +	/*filters */ +	u32 rx_conf; + +	bool act_scanning; +	u8 cnt_after_linked; +	bool skip_scan; + +	/* early mode */ +	/* skb wait queue */ +	struct sk_buff_head skb_waitq[MAX_TID_COUNT]; + +	/*RDG*/ +	bool rdg_en; + +	u8 ht_stbc_cap; +	u8 ht_cur_stbc; + +	/*vht support*/ +	u8 vht_enable; +	u8 bw_80; +	u8 vht_cur_ldpc; +	u8 vht_cur_stbc; +	u8 vht_stbc_cap; +	u8 vht_ldpc_cap; + +	/*AP*/ +	u8 bssid[6]; +	u32 vendor; +	u32 basic_rates; /* b/g rates */ +	u8 ht_enable; +	u8 bw_40; +	u8 mode;		/* wireless mode */ +	u8 slot_time; +	u8 short_preamble; +	u8 use_cts_protect; +	u8 cur_40_prime_sc; +	u8 cur_40_prime_sc_bk; +	u8 cur_80_prime_sc; +	u64 tsf; +	u8 retry_short; +	u8 retry_long; +	u16 assoc_id; +	bool bhiddenssid; + +	/*IBSS*/ +	int beacon_interval; + +	/*AMPDU*/ +	u8 min_space_cfg;	/*For Min spacing configurations */ +	u8 max_mss_density; +	u8 current_ampdu_factor; +	u8 current_ampdu_density; + +	/*QOS & EDCA */ +	struct ieee80211_tx_queue_params edca_param[RTL_MAC80211_NUM_QUEUE]; +	struct rtl_qos_parameters ac[AC_MAX]; +}; + +struct rtl_hal { +	struct ieee80211_hw *hw; + +	bool driver_is_goingto_unload; +	bool up_first_time; +	bool bfirst_init; +	bool being_init_adapter; +	bool b_bbrf_ready; +	bool b_mac_func_enable; +	bool b_pre_edcca_enable; + +	enum intf_type interface; +	u16 hw_type;		/*92c or 92d or 92s and so on */ +	u8 ic_class; +	u8 oem_id; +	u32 version;		/*version of chip */ +	u8 state;		/*stop 0, start 1 */ +	u8 boad_type; + +	u8 pa_mode; +	u8 pa_type_2g; +	u8 pa_type_5g; +	u8 lna_type_2g; +	u8 lna_type_5g; +	u8 external_pa_2g; +	u8 external_lna_2g; +	u8 external_pa_5g; +	u8 external_lna_5g; +	u8 rfe_type; + +	/*firmware */ +	u32 fwsize; +	u8 *pfirmware; +	u16 fw_version; +	u16 fw_subversion; +	bool b_h2c_setinprogress; +	u8 last_hmeboxnum; +	bool bfw_ready; + +	/*Reserve page start offset except beacon in TxQ. */ +	u8 fw_rsvdpage_startoffset; +	u8 h2c_txcmd_seq; +	u8 current_ra_rate; + +	/* FW Cmd IO related */ +	u16 fwcmd_iomap; +	u32 fwcmd_ioparam; +	bool set_fwcmd_inprogress; +	u8 current_fwcmd_io; + +	bool bfw_clk_change_in_progress; +	bool ballow_sw_to_change_hwclc; +	u8 fw_ps_state; +	 struct p2p_ps_offload_t p2p_ps_offload; +	/**/ +	bool driver_going2unload; + +	/*AMPDU init min space*/ +	u8 minspace_cfg;	/*For Min spacing configurations */ + +	/* Dul mac */ +	enum macphy_mode macphymode; +	enum band_type current_bandtype;	/* 0:2.4G, 1:5G */ +	enum band_type current_bandtypebackup; +	enum band_type bandset; +	/* dual MAC 0--Mac0 1--Mac1 */ +	u32 interfaceindex; +	/* just for DulMac S3S4 */ +	u8 macphyctl_reg; +	bool b_earlymode_enable; +	u8 max_earlymode_num; +	/* Dul mac*/ +	bool during_mac0init_radiob; +	bool during_mac1init_radioa; +	bool reloadtxpowerindex; +	/* True if IMR or IQK  have done +	for 2.4G in scan progress */ +	bool b_load_imrandiqk_setting_for2g; + +	bool disable_amsdu_8k; +	bool bmaster_of_dmsp; +	bool bslave_of_dmsp; + +	u16 rx_tag;/*for 92ee*/ +	u8 rts_en; + +	/*for wowlan*/ +	bool wow_enable; +	bool b_enter_pnp_sleep; +	bool b_wake_from_pnp_sleep; +	bool wow_enabled; +	__kernel_time_t last_suspend_sec; +	u32 wowlan_fwsize; +	u8 *p_wowlan_firmware; + +	u8 hw_rof_enable; /*Enable GPIO[9] as WL RF HW PDn source*/ + +	bool real_wow_v2_enable; +	bool re_init_llt_table; +}; + +struct rtl_security { +	/*default 0 */ +	bool use_sw_sec; + +	bool being_setkey; +	bool use_defaultkey; +	/*Encryption Algorithm for Unicast Packet */ +	enum rt_enc_alg pairwise_enc_algorithm; +	/*Encryption Algorithm for Brocast/Multicast */ +	enum rt_enc_alg group_enc_algorithm; +	/*Cam Entry Bitmap */ +	u32 hwsec_cam_bitmap; +	u8 hwsec_cam_sta_addr[TOTAL_CAM_ENTRY][ETH_ALEN]; +	/*local Key buffer, indx 0 is for +	   pairwise key 1-4 is for agoup key. */ +	u8 key_buf[KEY_BUF_SIZE][MAX_KEY_LEN]; +	u8 key_len[KEY_BUF_SIZE]; + +	/*The pointer of Pairwise Key, +	   it always points to KeyBuf[4] */ +	u8 *pairwise_key; +}; + +struct rtl_dig { +	u8 dig_enable_flag; +	u8 dig_ext_port_stage; + +	u32 rssi_lowthresh; +	u32 rssi_highthresh; + +	u32 fa_lowthresh; +	u32 fa_highthresh; + +	u8 cursta_connectstate; +	u8 presta_connectstate; +	u8 curmultista_connectstate; + +	u8 pre_igvalue; +	u8 cur_igvalue; + +	char backoff_val; +	char backoff_val_range_max; +	char backoff_val_range_min; +	u8 rx_gain_range_max; +	u8 rx_gain_range_min; +	u8 rssi_val_min; +	u8 min_undecorated_pwdb_for_dm; +	long last_min_undecorated_pwdb_for_dm; + +	u8 pre_cck_pd_state; +	u8 cur_cck_pd_state; + +	u8 large_fa_hit; +	u8 forbidden_igi; +	u32 recover_cnt; + +}; + +struct rtl_pstbl { +	u8 pre_ccastate; +	u8 cur_ccasate; + +	u8 pre_rfstate; +	u8 cur_rfstate; + +	long rssi_val_min; + +}; + +#define ASSOCIATE_ENTRY_NUM	(32 + 1) + +struct fast_ant_trainning { +	u8 bssid[6]; +	u8 antsel_rx_keep_0; +	u8 antsel_rx_keep_1; +	u8 antsel_rx_keep_2; +	u32 ant_sum_rssi[7]; +	u32 ant_rssi_cnt[7]; +	u32 ant_ave_rssi[7]; +	u8 fat_state; +	u32 train_idx; +	u8 antsel_a[ASSOCIATE_ENTRY_NUM]; +	u8 antsel_b[ASSOCIATE_ENTRY_NUM]; +	u8 antsel_c[ASSOCIATE_ENTRY_NUM]; +	u32 main_ant_sum[ASSOCIATE_ENTRY_NUM]; +	u32 aux_ant_sum[ASSOCIATE_ENTRY_NUM]; +	u32 main_ant_cnt[ASSOCIATE_ENTRY_NUM]; +	u32 aux_ant_cnt[ASSOCIATE_ENTRY_NUM]; +	u8 rx_idle_ant; +	bool b_becomelinked; +}; + +struct dm_phy_dbg_info { +	char rx_snrdb[4]; +	u64 num_qry_phy_status; +	u64 num_qry_phy_status_cck; +	u64 num_qry_phy_status_ofdm; +	u16 num_qry_beacon_pkt; +	u16 num_non_be_pkt; +	s32 rx_evm[4]; +}; + +struct rtl_dm { +	/*PHY status for DM */ +	long entry_min_undecoratedsmoothed_pwdb; +	long undecorated_smoothed_pwdb;	/*out dm */ +	long entry_max_undecoratedsmoothed_pwdb; +	bool b_dm_initialgain_enable; +	bool bdynamic_txpower_enable; +	bool bcurrent_turbo_edca; +	bool bis_any_nonbepkts;	/*out dm */ +	bool bis_cur_rdlstate; +	bool btxpower_trackinginit; +	bool b_disable_framebursting; +	bool b_cck_inch14; +	bool btxpower_tracking; +	bool b_useramask; +	bool brfpath_rxenable[4]; +	bool binform_fw_driverctrldm; +	bool bcurrent_mrc_switch; +	u8 txpowercount; + +	u8 thermalvalue_rxgain; +	u8 thermalvalue_iqk; +	u8 thermalvalue_lck; +	u8 thermalvalue; +	u8 thermalvalue_avg[AVG_THERMAL_NUM]; +	u8 thermalvalue_avg_index; +	bool bdone_txpower; +	u8 last_dtp_lvl; +	u8 dynamic_txhighpower_lvl;	/*Tx high power level */ +	u8 dm_flag;	/*Indicate if each dynamic mechanism's status. */ +	u8 dm_type; +	u8 txpower_track_control; +	bool binterrupt_migration; +	bool bdisable_tx_int; +	char ofdm_index[MAX_RF_PATH]; +	char cck_index; +	u8 default_ofdm_index; +	u8 default_cck_index; +	char delta_power_index[MAX_RF_PATH]; +	char delta_power_index_last[MAX_RF_PATH]; +	char power_index_offset[MAX_RF_PATH]; +	char aboslute_ofdm_swing_idx[MAX_RF_PATH]; +	char remnant_ofdm_swing_idx[MAX_RF_PATH]; +	char remnant_cck_idx; +	bool modify_txagc_flag_path_a; +	bool modify_txagc_flag_path_b; + +	bool b_one_entry_only; +	struct dm_phy_dbg_info dbginfo; +	/* Dynamic ATC switch */ + +	bool atc_status; +	bool large_cfo_hit; +	bool is_freeze; +	int cfo_tail[2]; +	int cfo_ave_pre; +	int crystal_cap; +	u8 cfo_threshold; +	u32 packet_count; +	u32 packet_count_pre; +	u8 tx_rate; + + +	/*88e tx power tracking*/ +	u8 bb_swing_idx_ofdm[2]; +	u8 bb_swing_idx_ofdm_current; +	u8 bb_swing_idx_ofdm_base[MAX_RF_PATH]; +	bool bb_swing_flag_Ofdm; +	u8 bb_swing_idx_cck; +	u8 bb_swing_idx_cck_current; +	u8 bb_swing_idx_cck_base; +	bool bb_swing_flag_cck; + +	char bb_swing_diff_2g; +	char bb_swing_diff_5g; + +	/* DMSP */ +	bool supp_phymode_switch; + +	/* DulMac */ +	struct rtl_dig dm_digtable; +	struct rtl_pstbl dm_pstable; +	struct fast_ant_trainning fat_table; + +	u8 linked_interval; + +	u64 last_tx_ok_cnt; +	u64 last_rx_ok_cnt; + +	bool cck_high_power; +}; + +#define	EFUSE_MAX_LOGICAL_SIZE		256 + +struct rtl_efuse { +	bool bautoLoad_ok; +	bool bootfromefuse; +	u16 max_physical_size; + +	u8 efuse_map[2][EFUSE_MAX_LOGICAL_SIZE]; +	u16 efuse_usedbytes; +	u8 efuse_usedpercentage; +	u8 autoload_failflag; +	u8 autoload_status; + +	short epromtype; +	u16 eeprom_vid; +	u16 eeprom_did; +	u16 eeprom_svid; +	u16 eeprom_smid; +	u8 eeprom_oemid; +	u16 eeprom_channelplan; +	u8 eeprom_version; + +	u8 dev_addr[6]; +	u8 board_type; +	u8 wowlan_enable; +	u8 antenna_div_cfg; +	u8 antenna_div_type; + +	bool b_txpwr_fromeprom; +	u8 eeprom_crystalcap; +	u8 eeprom_tssi[2]; +	u8 eeprom_tssi_5g[3][2]; /* for 5GL/5GM/5GH band. */ +	u8 eeprom_pwrlimit_ht20[CHANNEL_GROUP_MAX]; +	u8 eeprom_pwrlimit_ht40[CHANNEL_GROUP_MAX]; +	u8 eeprom_chnlarea_txpwr_cck[2][CHANNEL_GROUP_MAX_2G]; +	u8 eeprom_chnlarea_txpwr_ht40_1s[2][CHANNEL_GROUP_MAX]; +	u8 eeprom_chnlarea_txpwr_ht40_2sdiif[2][CHANNEL_GROUP_MAX]; + + +	u8 internal_pa_5g[2];	/* pathA / pathB */ +	u8 eeprom_c9; +	u8 eeprom_cc; + +	/*For power group */ +	u8 eeprom_pwrgroup[2][3]; +	u8 pwrgroup_ht20[2][CHANNEL_MAX_NUMBER]; +	u8 pwrgroup_ht40[2][CHANNEL_MAX_NUMBER]; + +	u8 txpwrlevel_cck[MAX_RF_PATH][CHANNEL_MAX_NUMBER_2G]; +	/*For HT 40MHZ pwr */ +	u8 txpwrlevel_ht40_1s[MAX_RF_PATH][CHANNEL_MAX_NUMBER]; +	/*For HT 40MHZ pwr */ +	u8 txpwrlevel_ht40_2s[MAX_RF_PATH][CHANNEL_MAX_NUMBER]; + +	/*--------------------------------------------------------* +	 * 8192CE\8192SE\8192DE\8723AE use the following 4 arrays, +	 * other ICs (8188EE\8723BE\8192EE\8812AE...) +	 * define new arrays in Windows code. +	 * BUT, in linux code, we use the same array for all ICs. +	 * +	 * The Correspondance relation between two arrays is: +	 * txpwr_cckdiff[][] == CCK_24G_Diff[][] +	 * txpwr_ht20diff[][] == BW20_24G_Diff[][] +	 * txpwr_ht40diff[][] == BW40_24G_Diff[][] +	 * txpwr_legacyhtdiff[][] == OFDM_24G_Diff[][] +	 * +	 * Sizes of these arrays are decided by the larger ones. +	 */ +	char txpwr_cckdiff[MAX_RF_PATH][CHANNEL_MAX_NUMBER]; +	char txpwr_ht20diff[MAX_RF_PATH][CHANNEL_MAX_NUMBER]; +	char txpwr_ht40diff[MAX_RF_PATH][CHANNEL_MAX_NUMBER]; +	char txpwr_legacyhtdiff[MAX_RF_PATH][CHANNEL_MAX_NUMBER]; +	/*--------------------------------------------------------*/ + +	u8 txpwr_5g_bw40base[MAX_RF_PATH][CHANNEL_MAX_NUMBER]; +	u8 txpwr_5g_bw80base[MAX_RF_PATH][CHANNEL_MAX_NUMBER_5G_80M]; +	char txpwr_5g_ofdmdiff[MAX_RF_PATH][MAX_TX_COUNT]; +	char txpwr_5g_bw20diff[MAX_RF_PATH][MAX_TX_COUNT]; +	char txpwr_5g_bw40diff[MAX_RF_PATH][MAX_TX_COUNT]; +	char txpwr_5g_bw80diff[MAX_RF_PATH][MAX_TX_COUNT]; + +	u8 txpwr_safetyflag;		/* Band edge enable flag */ +	u16 eeprom_txpowerdiff; +	u8 legacy_httxpowerdiff;	/* Legacy to HT rate power diff */ +	u8 antenna_txpwdiff[3]; + +	u8 eeprom_regulatory; +	u8 eeprom_thermalmeter; +	u8 thermalmeter[2];/*ThermalMeter, index 0 for RFIC0, and 1 for RFIC1 */ +	u16 tssi_13dbm; +	u8 crystalcap;		/* CrystalCap. */ +	u8 delta_iqk; +	u8 delta_lck; + +	u8 legacy_ht_txpowerdiff;	/*Legacy to HT rate power diff */ +	bool b_apk_thermalmeterignore; + +	bool b1x1_recvcombine; +	bool b1ss_support; + +	/*channel plan */ +	u8 channel_plan; +}; + +struct rtl_ps_ctl { +	bool pwrdomain_protect; +	bool b_in_powersavemode; +	bool rfchange_inprogress; +	bool b_swrf_processing; +	bool b_hwradiooff; +	/* +	 * just for PCIE ASPM +	 * If it supports ASPM, Offset[560h] = 0x40, +	 * otherwise Offset[560h] = 0x00. +	 * */ +	bool b_support_aspm; +	bool b_support_backdoor; + +	/*for LPS */ +	enum rt_psmode dot11_psmode;	/*Power save mode configured. */ +	bool b_swctrl_lps; +	bool b_fwctrl_lps; +	u8 fwctrl_psmode; +	/*For Fw control LPS mode */ +	u8 b_reg_fwctrl_lps; +	/*Record Fw PS mode status. */ +	bool b_fw_current_inpsmode; +	u8 reg_max_lps_awakeintvl; +	bool report_linked; +	bool b_low_power_enable;/*for 32k*/ + +	/*for IPS */ +	bool b_inactiveps; + +	u32 rfoff_reason; + +	/*RF OFF Level */ +	u32 cur_ps_level; +	u32 reg_rfps_level; + +	/*just for PCIE ASPM */ +	u8 const_amdpci_aspm; + +	enum rf_pwrstate inactive_pwrstate; +	enum rf_pwrstate rfpwr_state;	/*cur power state */ + +	/* for SW LPS*/ +	bool sw_ps_enabled; +	bool state; +	bool state_inap; +	bool multi_buffered; +	u16 nullfunc_seq; +	unsigned int dtim_counter; +	unsigned int sleep_ms; +	unsigned long last_sleep_jiffies; +	unsigned long last_awake_jiffies; +	unsigned long last_delaylps_stamp_jiffies; +	unsigned long last_dtim; +	unsigned long last_beacon; +	unsigned long last_action; +	unsigned long last_slept; + +	/*For P2P PS */ +	struct rtl_p2p_ps_info p2p_ps_info; +	u8 pwr_mode; +	u8 smart_ps; + +	/* wake up on line */ +	u8 wo_wlan_mode; +	u8 arp_offload_enable; +	u8 gtk_offload_enable; +	/* Used for WOL, indicates the reason for waking event.*/ +	u32 wakeup_reason; +	/* Record the last waking time for comparison with setting key. */ +	u64 last_wakeup_time; +}; + +struct rtl_stats { +	u8 psaddr[ETH_ALEN]; +	u32 mac_time[2]; +	s8 rssi; +	u8 signal; +	u8 noise; +	u8 rate;		/* hw desc rate */ +	u8 rawdata; +	u8 received_channel; +	u8 control; +	u8 mask; +	u8 freq; +	u16 len; +	u64 tsf; +	u32 beacon_time; +	u8 nic_type; +	u16 length; +	u8 signalquality;	/*in 0-100 index. */ +	/* +	 * Real power in dBm for this packet, +	 * no beautification and aggregation. +	 * */ +	s32 recvsignalpower; +	s8 rxpower;		/*in dBm Translate from PWdB */ +	u8 signalstrength;	/*in 0-100 index. */ +	u16 b_hwerror:1; +	u16 b_crc:1; +	u16 b_icv:1; +	u16 b_shortpreamble:1; +	u16 antenna:1; +	u16 decrypted:1; +	u16 wakeup:1; +	u32 timestamp_low; +	u32 timestamp_high; +	bool b_shift; + +	u8 rx_drvinfo_size; +	u8 rx_bufshift; +	bool b_isampdu; +	bool b_isfirst_ampdu; +	bool rx_is40Mhzpacket; +	u8 rx_packet_bw; +	u32 rx_pwdb_all; +	u8 rx_mimo_signalstrength[4];	/*in 0~100 index */ +	s8 rx_mimo_signalquality[4]; +	u8 rx_mimo_evm_dbm[4]; +	u16 cfo_short[4];		/* per-path's Cfo_short */ +	u16 cfo_tail[4]; + +	u8 rx_pwr[4]; /* per-path's pwdb */ +	u8 rx_snr[4]; /* per-path's SNR */ +	u8 bandwidth; +	u8 bt_coex_pwr_adjust; +	bool b_packet_matchbssid; +	bool b_is_cck; +	bool b_is_ht; +	bool b_packet_toself; +	bool b_packet_beacon;	/*for rssi */ +	char cck_adc_pwdb[4];	/*for rx path selection */ + +	bool b_is_vht; +	bool b_is_short_gi; +	u8 vht_nss; + +	u8 packet_report_type; + +	u32 macid; +	u8 wake_match; +	u32 bt_rx_rssi_percentage; +	u32 macid_valid_entry[2]; +}; + +struct rt_link_detect { +	/* count for raoming */ +	u32 bcn_rx_inperiod; +	u32 roam_times; + +	u32 num_tx_in4period[4]; +	u32 num_rx_in4period[4]; + +	u32 num_tx_inperiod; +	u32 num_rx_inperiod; + +	bool b_busytraffic; +	bool b_tx_busy_traffic; +	bool b_rx_busy_traffic; +	bool b_higher_busytraffic; +	bool b_higher_busyrxtraffic; + +	u32 tidtx_in4period[MAX_TID_COUNT][4]; +	u32 tidtx_inperiod[MAX_TID_COUNT]; +	bool higher_busytxtraffic[MAX_TID_COUNT]; +}; + +struct rtl_tcb_desc { +	u8 packet_bw:2; +	u8 b_multicast:1; +	u8 b_broadcast:1; + +	u8 b_rts_stbc:1; +	u8 b_rts_enable:1; +	u8 b_cts_enable:1; +	u8 b_rts_use_shortpreamble:1; +	u8 b_rts_use_shortgi:1; +	u8 rts_sc:1; +	u8 b_rts_bw:1; +	u8 rts_rate; + +	u8 use_shortgi:1; +	u8 use_shortpreamble:1; +	u8 use_driver_rate:1; +	u8 disable_ratefallback:1; + +	u8 ratr_index; +	u8 mac_id; +	u8 hw_rate; + +	u8 b_last_inipkt:1; +	u8 b_cmd_or_init:1; +	u8 queue_index; + +	/* early mode */ +	u8 empkt_num; +	/* The max value by HW */ +	u32 empkt_len[10]; +	bool btx_enable_sw_calc_duration; +	/* used for hal construct pkt, +	 * we may set desc when tx */ +	u8 self_desc; +}; + +struct rtl_wow_pattern { +	u8 type; +	u16 crc; +	u32 mask[4]; +}; + +struct proxim { +	bool proxim_on; + +	void *proximity_priv; +	int (*proxim_rx)(struct ieee80211_hw *hw, struct rtl_stats *status, +			 struct sk_buff *skb); +	u8  (*proxim_get_var)(struct ieee80211_hw *hw, u8 type); +}; + +struct rtl_hal_ops { +	int (*init_sw_vars)(struct ieee80211_hw *hw); +	void (*deinit_sw_vars)(struct ieee80211_hw *hw); +	void (*read_eeprom_info)(struct ieee80211_hw *hw); +	void (*interrupt_recognized)(struct ieee80211_hw *hw, +				     u32 *p_inta, u32 *p_intb); +	int (*hw_init)(struct ieee80211_hw *hw); +	void (*hw_disable)(struct ieee80211_hw *hw); +	void (*hw_suspend)(struct ieee80211_hw *hw); +	void (*hw_resume)(struct ieee80211_hw *hw); +	void (*enable_interrupt)(struct ieee80211_hw *hw); +	void (*disable_interrupt)(struct ieee80211_hw *hw); +	int (*set_network_type)(struct ieee80211_hw *hw, +				enum nl80211_iftype type); +	void (*set_chk_bssid)(struct ieee80211_hw *hw, +			      bool check_bssid); +	void (*set_bw_mode)(struct ieee80211_hw *hw, +			    enum nl80211_channel_type ch_type); +	u8 (*switch_channel)(struct ieee80211_hw *hw); +	void (*set_qos)(struct ieee80211_hw *hw, int aci); +	void (*set_bcn_reg)(struct ieee80211_hw *hw); +	void (*set_bcn_intv)(struct ieee80211_hw *hw); +	void (*update_interrupt_mask)(struct ieee80211_hw *hw, +				      u32 add_msr, u32 rm_msr); +	void (*get_hw_reg)(struct ieee80211_hw *hw, u8 variable, u8 *val); +	void (*set_hw_reg)(struct ieee80211_hw *hw, u8 variable, u8 *val); +	void (*update_rate_tbl)(struct ieee80211_hw *hw, +				struct ieee80211_sta *sta, u8 rssi_level); +	void (*pre_fill_tx_bd_desc)(struct ieee80211_hw *hw, u8 *tx_bd_desc, +				    u8 *desc, u8 queue_index, +				    struct sk_buff *skb, dma_addr_t addr); +	u16 (*rx_desc_buff_remained_cnt)(struct ieee80211_hw *hw, +					 u8 queue_index); +	void (*rx_check_dma_ok)(struct ieee80211_hw *hw, u8 *header_desc, +				u8 queue_index); +	void (*fill_tx_desc)(struct ieee80211_hw *hw, +			     struct ieee80211_hdr *hdr, +			     u8 *pdesc_tx, u8 *pbd_desc, +			     struct ieee80211_tx_info *info, +			     struct ieee80211_sta *sta, +			     struct sk_buff *skb, u8 hw_queue, +			     struct rtl_tcb_desc *ptcb_desc); +	void (*fill_tx_cmddesc)(struct ieee80211_hw *hw, u8 *pdesc, +				bool b_firstseg, bool b_lastseg, +				struct sk_buff *skb); +	bool (*query_rx_desc)(struct ieee80211_hw *hw, +			      struct rtl_stats *status, +			      struct ieee80211_rx_status *rx_status, +			      u8 *pdesc, struct sk_buff *skb); +	void (*set_channel_access)(struct ieee80211_hw *hw); +	bool (*radio_onoff_checking)(struct ieee80211_hw *hw, u8 *valid); +	void (*dm_watchdog)(struct ieee80211_hw *hw); +	void (*scan_operation_backup)(struct ieee80211_hw *hw, u8 operation); +	bool (*set_rf_power_state)(struct ieee80211_hw *hw, +				   enum rf_pwrstate rfpwr_state); +	void (*led_control)(struct ieee80211_hw *hw, +			    enum led_ctl_mode ledaction); +	void (*set_desc)(struct ieee80211_hw *hw, u8 *pdesc, bool istx, +			 u8 desc_name, u8 *val); +	u32 (*get_desc)(u8 *pdesc, bool istx, u8 desc_name); +	bool (*is_tx_desc_closed)(struct ieee80211_hw *hw, +				  u8 hw_queue, u16 index); +	void (*tx_polling)(struct ieee80211_hw *hw, u8 hw_queue); +	void (*enable_hw_sec)(struct ieee80211_hw *hw); +	void (*set_key)(struct ieee80211_hw *hw, u32 key_index, +			u8 *p_macaddr, bool is_group, u8 enc_algo, +			bool is_wepkey, bool clear_all); +	void (*init_sw_leds)(struct ieee80211_hw *hw); +	u32 (*get_bbreg)(struct ieee80211_hw *hw, u32 regaddr, u32 bitmask); +	void (*set_bbreg)(struct ieee80211_hw *hw, u32 regaddr, u32 bitmask, +			  u32 data); +	u32 (*get_rfreg)(struct ieee80211_hw *hw, enum radio_path rfpath, +			 u32 regaddr, u32 bitmask); +	void (*set_rfreg)(struct ieee80211_hw *hw, enum radio_path rfpath, +			  u32 regaddr, u32 bitmask, u32 data); +	void (*allow_all_destaddr)(struct ieee80211_hw *hw, +				   bool allow_all_da, bool write_into_reg); +	void (*linked_set_reg)(struct ieee80211_hw *hw); +	void (*check_switch_to_dmdp)(struct ieee80211_hw *hw); +	void (*dualmac_easy_concurrent)(struct ieee80211_hw *hw); +	void (*dualmac_switch_to_dmdp)(struct ieee80211_hw *hw); +	void (*c2h_command_handle)(struct ieee80211_hw *hw); +	void (*bt_wifi_media_status_notify)(struct ieee80211_hw *hw, +					    bool mstate); +	void (*bt_turn_off_bt_coexist_before_enter_lps)(struct ieee80211_hw *w); +	void (*fill_h2c_cmd)(struct ieee80211_hw *hw, u8 element_id, +			     u32 cmd_len, u8 *p_cmdbuffer); +	bool (*get_btc_status)(void); +	u32 (*rx_command_packet)(struct ieee80211_hw *hw, +				 struct rtl_stats status, struct sk_buff *skb); +	void (*add_wowlan_pattern)(struct ieee80211_hw *hw, +				   struct rtl_wow_pattern *rtl_pattern, +				   u8 index); +}; + +struct rtl_intf_ops { +	/*com */ +	void (*read92e_efuse_byte)(struct ieee80211_hw *hw, u16 _offset, +				   u8 *pbuf); +	int (*adapter_start)(struct ieee80211_hw *hw); +	void (*adapter_stop)(struct ieee80211_hw *hw); +	bool (*check_buddy_priv)(struct ieee80211_hw *hw, +				 struct rtl_priv **buddy_priv); + +	int (*adapter_tx)(struct ieee80211_hw *hw, +			  struct ieee80211_sta *sta, +			  struct sk_buff *skb, +			  struct rtl_tcb_desc *ptcb_desc); +	void (*flush)(struct ieee80211_hw *hw, u32 queues, bool drop); +	int (*reset_trx_ring)(struct ieee80211_hw *hw); +	bool (*waitq_insert)(struct ieee80211_hw *hw, +			     struct ieee80211_sta *sta, +			     struct sk_buff *skb); + +	/*pci */ +	void (*disable_aspm)(struct ieee80211_hw *hw); +	void (*enable_aspm)(struct ieee80211_hw *hw); + +	/*usb */ +}; + +struct rtl_mod_params { +	/* default: 0 = using hardware encryption */ +	bool sw_crypto; + +	/* default: 0 = DBG_EMERG (0)*/ +	int debug; + +	/* default: 1 = using no linked power save */ +	bool b_inactiveps; + +	/* default: 1 = using linked sw power save */ +	bool b_swctrl_lps; + +	/* default: 1 = using linked fw power save */ +	bool b_fwctrl_lps; +}; + +struct rtl_hal_cfg { +	u8 bar_id; +	bool write_readback; +	char *name; +	char *fw_name; +	struct rtl_hal_ops *ops; +	struct rtl_mod_params *mod_params; + +	/*this map used for some registers or vars +	   defined int HAL but used in MAIN */ +	u32 maps[RTL_VAR_MAP_MAX]; + +}; + +struct rtl_locks { +	/* mutex */ +	struct mutex conf_mutex; + +	/*spin lock */ +	spinlock_t ips_lock; +	spinlock_t irq_th_lock; +	spinlock_t h2c_lock; +	spinlock_t rf_ps_lock; +	spinlock_t rf_lock; +	spinlock_t lps_lock; +	spinlock_t waitq_lock; +	spinlock_t entry_list_lock; + +	/*FW clock change */ +	spinlock_t fw_ps_lock; + +	/*Dul mac*/ +	spinlock_t cck_and_rw_pagea_lock; + +	/*Easy concurrent*/ +	spinlock_t check_sendpkt_lock; + +	spinlock_t iqk_lock; +}; + +struct rtl_works { +	struct ieee80211_hw *hw; + +	/*timer */ +	struct timer_list watchdog_timer; +	struct timer_list dualmac_easyconcurrent_retrytimer; +	struct timer_list fw_clockoff_timer; +	struct timer_list fast_antenna_trainning_timer; +	/*task */ +	struct tasklet_struct irq_tasklet; +	struct tasklet_struct irq_prepare_bcn_tasklet; + +	/*work queue */ +	struct workqueue_struct *rtl_wq; +	struct delayed_work watchdog_wq; +	struct delayed_work ips_nic_off_wq; + +	/* For SW LPS */ +	struct delayed_work ps_work; +	struct delayed_work ps_rfon_wq; +	struct delayed_work fwevt_wq; +}; + +struct rtl_debug { +	u32 dbgp_type[DBGP_TYPE_MAX]; +	u32 global_debuglevel; +	u64 global_debugcomponents; + +	/* add for proc debug */ +	struct proc_dir_entry *proc_dir; +	char proc_name[20]; +}; + +#define MIMO_PS_STATIC			0 +#define MIMO_PS_DYNAMIC			1 +#define MIMO_PS_NOLIMIT			3 + +struct rtl_dualmac_easy_concurrent_ctl { +	enum band_type currentbandtype_backfordmdp; +	bool bclose_bbandrf_for_dmsp; +	bool bchange_to_dmdp; +	bool bchange_to_dmsp; +	bool bswitch_in_process; +}; + +struct rtl_dmsp_ctl { +	bool bactivescan_for_slaveofdmsp; +	bool bscan_for_anothermac_fordmsp; +	bool bscan_for_itself_fordmsp; +	bool bwritedig_for_anothermacofdmsp; +	u32 curdigvalue_for_anothermacofdmsp; +	bool bchangecckpdstate_for_anothermacofdmsp; +	u8 curcckpdstate_for_anothermacofdmsp; +	bool bchangetxhighpowerlvl_for_anothermacofdmsp; +	u8 curtxhighlvl_for_anothermacofdmsp; +	long rssivalmin_for_anothermacofdmsp; +}; + +struct rtl_global_var { +	/* from this list we can get +	 * other adapter's rtl_priv */ +	struct list_head glb_priv_list; +	spinlock_t glb_list_lock; +}; + +struct rtl_btc_info { +	u8 bt_type; +	u8 btcoexist; +	u8 ant_num; +}; + +struct rtl_btc_ops { +	void (*btc_init_variables)(struct rtl_priv *rtlpriv); +	void (*btc_init_hal_vars)(struct rtl_priv *rtlpriv); +	void (*btc_init_hw_config)(struct rtl_priv *rtlpriv); +	void (*btc_ips_notify)(struct rtl_priv *rtlpriv, u8 type); +	void (*btc_lps_notify)(struct rtl_priv *rtlpriv, u8 type); +	void (*btc_scan_notify)(struct rtl_priv *rtlpriv, u8 scantype); +	void (*btc_connect_notify)(struct rtl_priv *rtlpriv, u8 action); +	void (*btc_mediastatus_notify)(struct rtl_priv *rtlpriv, +				       enum rt_media_status mstatus); +	void (*btc_periodical)(struct rtl_priv *rtlpriv); +	void (*btc_halt_notify)(void); +	void (*btc_btinfo_notify)(struct rtl_priv *rtlpriv, +				  u8 *tmp_buf, u8 length); +	bool (*btc_is_limited_dig)(struct rtl_priv *rtlpriv); +	bool (*btc_is_disable_edca_turbo)(struct rtl_priv *rtlpriv); +	bool (*btc_is_bt_disabled)(struct rtl_priv *rtlpriv); +	void (*btc_special_packet_notify)(struct rtl_priv *rtlpriv, +					  u8 pkt_type); +}; + +struct rtl_bt_coexist { +	struct rtl_btc_ops *btc_ops; +	struct rtl_btc_info btc_info; +}; + + +struct rtl_priv { +	struct list_head list; +	struct rtl_priv *buddy_priv; +	struct rtl_global_var *glb_var; +	struct rtl_dualmac_easy_concurrent_ctl easy_concurrent_ctl; +	struct rtl_dmsp_ctl dmsp_ctl; +	struct rtl_locks locks; +	struct rtl_works works; +	struct rtl_mac mac80211; +	struct rtl_hal rtlhal; +	struct rtl_regulatory regd; +	struct rtl_rfkill rfkill; +	struct rtl_io io; +	struct rtl_phy phy; +	struct rtl_dm dm; +	struct rtl_security sec; +	struct rtl_efuse efuse; + +	struct rtl_ps_ctl psc; +	struct rate_adaptive ra; +	struct dynamic_primary_cca primarycca; +	struct wireless_stats stats; +	struct rt_link_detect link_info; +	struct false_alarm_statistics falsealm_cnt; + +	struct rtl_rate_priv *rate_priv; + +	struct rtl_debug dbg; + +	/* sta entry list for ap adhoc or mesh */ +	struct list_head entry_list; + +	/* +	 *hal_cfg : for diff cards +	 *intf_ops : for diff interrface usb/pcie +	 */ +	struct rtl_hal_cfg *cfg; +	struct rtl_intf_ops *intf_ops; + +	/*this var will be set by set_bit, +	   and was used to indicate status of +	   interface or hardware */ +	unsigned long status; + +	/* intel Proximity, should be alloc mem +	 * in intel Proximity module and can only +	 * be used in intel Proximity mode */ +	struct proxim proximity; + +	/*for bt coexist use*/ +	struct rtl_bt_coexist btcoexist; + +	/* seperate 92ee from other ICs, +	  * 92ee use new trx flow. */ +	bool use_new_trx_flow; + +#ifdef CONFIG_PM +	struct wiphy_wowlan_support wowlan; +#endif +	/*This must be the last item so +	   that it points to the data allocated +	   beyond  this structure like: +	   rtl_pci_priv or rtl_usb_priv */ +	u8 priv[0]; +}; + +#define rtl_priv(hw)		(((struct rtl_priv *)(hw)->priv)) +#define rtl_mac(rtlpriv)	(&((rtlpriv)->mac80211)) +#define rtl_hal(rtlpriv)	(&((rtlpriv)->rtlhal)) +#define rtl_efuse(rtlpriv)	(&((rtlpriv)->efuse)) +#define rtl_psc(rtlpriv)	(&((rtlpriv)->psc)) +#define rtl_sec(rtlpriv)	(&((rtlpriv)->sec)) +#define rtl_dm(rtlpriv)	(&((rtlpriv)->dm)) +/*************************************** +    Bluetooth Co-existance Related +****************************************/ + +enum bt_ant_num { +	ANT_X2 = 0, +	ANT_X1 = 1, +}; + +enum bt_co_type { +	BT_2WIRE = 0, +	BT_ISSC_3WIRE = 1, +	BT_ACCEL = 2, +	BT_CSR_BC4 = 3, +	BT_CSR_BC8 = 4, +	BT_RTL8756 = 5, +	BT_RTL8723A = 6, +	BT_RTL8821A = 7, +	BT_RTL8723B = 8, +	BT_RTL8192E = 9, +	BT_RTL8812A = 11, +}; + +enum bt_total_ant_num { +	ANT_TOTAL_X2 = 0, +	ANT_TOTAL_X1 = 1 +}; + +enum bt_cur_state { +	BT_OFF = 0, +	BT_ON = 1, +}; + +enum bt_service_type { +	BT_SCO = 0, +	BT_A2DP = 1, +	BT_HID = 2, +	BT_HID_IDLE = 3, +	BT_SCAN = 4, +	BT_IDLE = 5, +	BT_OTHER_ACTION = 6, +	BT_BUSY = 7, +	BT_OTHERBUSY = 8, +	BT_PAN = 9, +}; + +enum bt_radio_shared { +	BT_RADIO_SHARED = 0, +	BT_RADIO_INDIVIDUAL = 1, +}; + +struct bt_coexist_info { +	/* EEPROM BT info. */ +	u8 eeprom_bt_coexist; +	u8 eeprom_bt_type; +	u8 eeprom_bt_ant_num; +	u8 eeprom_bt_ant_isolation; +	u8 eeprom_bt_radio_shared; + +	u8 bt_coexistence; +	u8 bt_ant_num; +	u8 bt_coexist_type; +	u8 bt_state; +	u8 bt_cur_state;	/* 0:on, 1:off */ +	u8 bt_ant_isolation;	/* 0:good, 1:bad */ +	u8 bt_pape_ctrl;	/* 0:SW, 1:SW/HW dynamic */ +	u8 bt_service; +	u8 bt_radio_shared_type; +	u8 bt_rfreg_origin_1e; +	u8 bt_rfreg_origin_1f; +	u8 bt_rssi_state; +	u32 ratio_tx; +	u32 ratio_pri; +	u32 bt_edca_ul; +	u32 bt_edca_dl; + +	bool b_init_set; +	bool b_bt_busy_traffic; +	bool b_bt_traffic_mode_set; +	bool b_bt_non_traffic_mode_set; + +	bool b_fw_coexist_all_off; +	bool b_sw_coexist_all_off; +	bool b_hw_coexist_all_off; +	u32 current_state; +	u32 previous_state; +	u32 current_state_h; +	u32 previous_state_h; + +	u8 bt_pre_rssi_state; +	u8 bt_pre_rssi_state1; + +	u8 b_reg_bt_iso; +	u8 b_reg_bt_sco; +	bool b_balance_on; +	u8 bt_active_zero_cnt; +	bool b_cur_bt_disabled; +	bool b_pre_bt_disabled; + +	u8 bt_profile_case; +	u8 bt_profile_action; +	bool b_bt_busy; +	bool b_hold_for_bt_operation; +	u8 lps_counter; +}; + +/**************************************** +	mem access macro define start +	Call endian free function when +	1. Read/write packet content. +	2. Before write integer to IO. +	3. After read integer from IO. +****************************************/ +/* Convert little data endian to host ordering */ +#define EF1BYTE(_val)		\ +	((u8)(_val)) +#define EF2BYTE(_val)		\ +	(le16_to_cpu(_val)) +#define EF4BYTE(_val)		\ +	(le32_to_cpu(_val)) + +/* Read data from memory */ +#define READEF1BYTE(_ptr)	\ +	EF1BYTE(*((u8 *)(_ptr))) +/* Read le16 data from memory and convert to host ordering */ +#define READEF2BYTE(_ptr)	\ +	EF2BYTE(*(_ptr)) +#define READEF4BYTE(_ptr)	\ +	EF4BYTE(*(_ptr)) + +/* Write data to memory */ +#define WRITEEF1BYTE(_ptr, _val)	\ +	(*((u8 *)(_ptr))) = EF1BYTE(_val) +/* Write le16 data to memory in host ordering */ +#define WRITEEF2BYTE(_ptr, _val)	\ +	(*((u16 *)(_ptr))) = EF2BYTE(_val) +#define WRITEEF4BYTE(_ptr, _val)	\ +	(*((u32 *)(_ptr))) = EF2BYTE(_val) + +/* Create a bit mask + * Examples: + * BIT_LEN_MASK_32(0) => 0x00000000 + * BIT_LEN_MASK_32(1) => 0x00000001 + * BIT_LEN_MASK_32(2) => 0x00000003 + * BIT_LEN_MASK_32(32) => 0xFFFFFFFF + */ +#define BIT_LEN_MASK_32(__bitlen)	 \ +	(0xFFFFFFFF >> (32 - (__bitlen))) +#define BIT_LEN_MASK_16(__bitlen)	 \ +	(0xFFFF >> (16 - (__bitlen))) +#define BIT_LEN_MASK_8(__bitlen) \ +	(0xFF >> (8 - (__bitlen))) + +/* Create an offset bit mask + * Examples: + * BIT_OFFSET_LEN_MASK_32(0, 2) => 0x00000003 + * BIT_OFFSET_LEN_MASK_32(16, 2) => 0x00030000 + */ +#define BIT_OFFSET_LEN_MASK_32(__bitoffset, __bitlen) \ +	(BIT_LEN_MASK_32(__bitlen) << (__bitoffset)) +#define BIT_OFFSET_LEN_MASK_16(__bitoffset, __bitlen) \ +	(BIT_LEN_MASK_16(__bitlen) << (__bitoffset)) +#define BIT_OFFSET_LEN_MASK_8(__bitoffset, __bitlen) \ +	(BIT_LEN_MASK_8(__bitlen) << (__bitoffset)) + +/*Description: + * Return 4-byte value in host byte ordering from + * 4-byte pointer in little-endian system. + */ +#define LE_P4BYTE_TO_HOST_4BYTE(__pstart) \ +	(EF4BYTE(*((__le32 *)(__pstart)))) +#define LE_P2BYTE_TO_HOST_2BYTE(__pstart) \ +	(EF2BYTE(*((__le16 *)(__pstart)))) +#define LE_P1BYTE_TO_HOST_1BYTE(__pstart) \ +	(EF1BYTE(*((u8 *)(__pstart)))) + +/*Description: +Translate subfield (continuous bits in little-endian) of 4-byte +value to host byte ordering.*/ +#define LE_BITS_TO_4BYTE(__pstart, __bitoffset, __bitlen) \ +	( \ +		(LE_P4BYTE_TO_HOST_4BYTE(__pstart) >> (__bitoffset))  & \ +		BIT_LEN_MASK_32(__bitlen) \ +	) +#define LE_BITS_TO_2BYTE(__pstart, __bitoffset, __bitlen) \ +	( \ +		(LE_P2BYTE_TO_HOST_2BYTE(__pstart) >> (__bitoffset)) & \ +		BIT_LEN_MASK_16(__bitlen) \ +	) +#define LE_BITS_TO_1BYTE(__pstart, __bitoffset, __bitlen) \ +	( \ +		(LE_P1BYTE_TO_HOST_1BYTE(__pstart) >> (__bitoffset)) & \ +		BIT_LEN_MASK_8(__bitlen) \ +	) + +/* Description: + * Mask subfield (continuous bits in little-endian) of 4-byte value + * and return the result in 4-byte value in host byte ordering. + */ +#define LE_BITS_CLEARED_TO_4BYTE(__pstart, __bitoffset, __bitlen) \ +	( \ +		LE_P4BYTE_TO_HOST_4BYTE(__pstart)  & \ +		(~BIT_OFFSET_LEN_MASK_32(__bitoffset, __bitlen)) \ +	) +#define LE_BITS_CLEARED_TO_2BYTE(__pstart, __bitoffset, __bitlen) \ +	( \ +		LE_P2BYTE_TO_HOST_2BYTE(__pstart) & \ +		(~BIT_OFFSET_LEN_MASK_16(__bitoffset, __bitlen)) \ +	) +#define LE_BITS_CLEARED_TO_1BYTE(__pstart, __bitoffset, __bitlen) \ +	( \ +		LE_P1BYTE_TO_HOST_1BYTE(__pstart) & \ +		(~BIT_OFFSET_LEN_MASK_8(__bitoffset, __bitlen)) \ +	) + +/* Description: + * Set subfield of little-endian 4-byte value to specified value. + */ +#define SET_BITS_TO_LE_4BYTE(__pstart, __bitoffset, __bitlen, __val) \ +	*((u32 *)(__pstart)) = \ +	( \ +		LE_BITS_CLEARED_TO_4BYTE(__pstart, __bitoffset, __bitlen) | \ +		((((u32)__val) & BIT_LEN_MASK_32(__bitlen)) << (__bitoffset)) \ +	); +#define SET_BITS_TO_LE_2BYTE(__pstart, __bitoffset, __bitlen, __val) \ +	*((u16 *)(__pstart)) = \ +	( \ +		LE_BITS_CLEARED_TO_2BYTE(__pstart, __bitoffset, __bitlen) | \ +		((((u16)__val) & BIT_LEN_MASK_16(__bitlen)) << (__bitoffset)) \ +	); +#define SET_BITS_TO_LE_1BYTE(__pstart, __bitoffset, __bitlen, __val) \ +	*((u8 *)(__pstart)) = EF1BYTE \ +	( \ +		LE_BITS_CLEARED_TO_1BYTE(__pstart, __bitoffset, __bitlen) | \ +		((((u8)__val) & BIT_LEN_MASK_8(__bitlen)) << (__bitoffset)) \ +	); + +#define	N_BYTE_ALIGMENT(__value, __aligment) ((__aligment == 1) ? \ +	(__value) : (((__value + __aligment - 1) / __aligment) * __aligment)) + +/**************************************** +	mem access macro define end +****************************************/ + +#define byte(x , n) ((x >> (8 * n)) & 0xff) + +#define packet_get_type(_packet) (EF1BYTE((_packet).octet[0]) & 0xFC) +#define RTL_WATCH_DOG_TIME	2000 +#define MSECS(t)		msecs_to_jiffies(t) +#define WLAN_FC_GET_VERS(fc)	(le16_to_cpu(fc) & IEEE80211_FCTL_VERS) +#define WLAN_FC_GET_TYPE(fc)	(le16_to_cpu(fc) & IEEE80211_FCTL_FTYPE) +#define WLAN_FC_GET_STYPE(fc)	(le16_to_cou(fc) & IEEE80211_FCTL_STYPE) +#define WLAN_FC_MORE_DATA(fc)	(le16_to_cpu(fc) & IEEE80211_FCTL_MOREDATA) +#define SEQ_TO_SN(seq)		(((seq) & IEEE80211_SCTL_SEQ) >> 4) +#define SN_TO_SEQ(ssn)		(((ssn) << 4) & IEEE80211_SCTL_SEQ) +#define MAX_SN			((IEEE80211_SCTL_SEQ) >> 4) + +#define	RT_RF_OFF_LEVL_ASPM		BIT(0)	/*PCI ASPM */ +#define	RT_RF_OFF_LEVL_CLK_REQ		BIT(1)	/*PCI clock request */ +#define	RT_RF_OFF_LEVL_PCI_D3		BIT(2)	/*PCI D3 mode */ +/*NIC halt, re-initialize hw parameters*/ +#define	RT_RF_OFF_LEVL_HALT_NIC		BIT(3) +#define	RT_RF_OFF_LEVL_FREE_FW		BIT(4)	/*FW free, re-download the FW */ +#define	RT_RF_OFF_LEVL_FW_32K		BIT(5)	/*FW in 32k */ +/*Always enable ASPM and Clock Req in initialization.*/ +#define	RT_RF_PS_LEVEL_ALWAYS_ASPM	BIT(6) +/* no matter RFOFF or SLEEP we set PS_ASPM_LEVL*/ +#define	RT_PS_LEVEL_ASPM		BIT(7) +/*When LPS is on, disable 2R if no packet is received or transmittd.*/ +#define	RT_RF_LPS_DISALBE_2R		BIT(30) +#define	RT_RF_LPS_LEVEL_ASPM		BIT(31)	/*LPS with ASPM */ +#define	RT_IN_PS_LEVEL(ppsc, _ps_flg)		\ +	((ppsc->cur_ps_level & _ps_flg) ? true : false) +#define	RT_CLEAR_PS_LEVEL(ppsc, _ps_flg)	\ +	(ppsc->cur_ps_level &= (~(_ps_flg))) +#define	RT_SET_PS_LEVEL(ppsc, _ps_flg)		\ +	(ppsc->cur_ps_level |= _ps_flg) + +#define container_of_dwork_rtl(x , y , z) \ +	container_of(container_of(x, struct delayed_work, work), y, z) + +#define FILL_OCTET_STRING(_os , _octet , _len)	\ +		(_os).octet = (u8 *)(_octet);		\ +		(_os).length = (_len); + +#define CP_MACADDR(des , src)	\ +	((des)[0] = (src)[0] , (des)[1] = (src)[1],\ +	(des)[2] = (src)[2] , (des)[3] = (src)[3],\ +	(des)[4] = (src)[4] , (des)[5] = (src)[5]) + +#define	LDPC_HT_ENABLE_RX			BIT(0) +#define	LDPC_HT_ENABLE_TX			BIT(1) +#define	LDPC_HT_TEST_TX_ENABLE			BIT(2) +#define	LDPC_HT_CAP_TX				BIT(3) + +#define	STBC_HT_ENABLE_RX			BIT(0) +#define	STBC_HT_ENABLE_TX			BIT(1) +#define	STBC_HT_TEST_TX_ENABLE			BIT(2) +#define	STBC_HT_CAP_TX				BIT(3) + + +#define	LDPC_VHT_ENABLE_RX			BIT(0) +#define	LDPC_VHT_ENABLE_TX			BIT(1) +#define	LDPC_VHT_TEST_TX_ENABLE			BIT(2) +#define	LDPC_VHT_CAP_TX				BIT(3) + +#define	STBC_VHT_ENABLE_RX			BIT(0) +#define	STBC_VHT_ENABLE_TX			BIT(1) +#define	STBC_VHT_TEST_TX_ENABLE			BIT(2) +#define	STBC_VHT_CAP_TX				BIT(3) + + +static inline u8 rtl_read_byte(struct rtl_priv *rtlpriv, u32 addr) +{ +	return rtlpriv->io.read8_sync(rtlpriv, addr); +} + +static inline u16 rtl_read_word(struct rtl_priv *rtlpriv, u32 addr) +{ +	return rtlpriv->io.read16_sync(rtlpriv, addr); +} + +static inline u32 rtl_read_dword(struct rtl_priv *rtlpriv, u32 addr) +{ +	return rtlpriv->io.read32_sync(rtlpriv, addr); +} + +static inline void rtl_write_byte(struct rtl_priv *rtlpriv, u32 addr, u8 val8) +{ +	rtlpriv->io.write8_async(rtlpriv, addr, val8); + +	if (rtlpriv->cfg->write_readback) +		rtlpriv->io.read8_sync(rtlpriv, addr); +} + +static inline void rtl_write_word(struct rtl_priv *rtlpriv, u32 addr, u16 val16) +{ +	rtlpriv->io.write16_async(rtlpriv, addr, val16); + +	if (rtlpriv->cfg->write_readback) +		rtlpriv->io.read16_sync(rtlpriv, addr); +} + +static inline void rtl_write_dword(struct rtl_priv *rtlpriv, +				   u32 addr, u32 val32) +{ +	rtlpriv->io.write32_async(rtlpriv, addr, val32); + +	if (rtlpriv->cfg->write_readback) +		rtlpriv->io.read32_sync(rtlpriv, addr); +} + +static inline u32 rtl_get_bbreg(struct ieee80211_hw *hw, +				u32 regaddr, u32 bitmask) +{ +	return ((struct rtl_priv *)(hw)->priv)->cfg->ops->get_bbreg(hw, +								    regaddr, +								    bitmask); +} + +static inline void rtl_set_bbreg(struct ieee80211_hw *hw, u32 regaddr, +				 u32 bitmask, u32 data) +{ +	struct rtl_priv *rtlpriv = hw->priv; + +	rtlpriv->cfg->ops->set_bbreg(hw, regaddr, bitmask, data); +} + +static inline u32 rtl_get_rfreg(struct ieee80211_hw *hw, +				enum radio_path rfpath, u32 regaddr, +				u32 bitmask) +{ +	return ((struct rtl_priv *)(hw)->priv)->cfg->ops->get_rfreg(hw, +								    rfpath, +								    regaddr, +								    bitmask); +} + +static inline void rtl_set_rfreg(struct ieee80211_hw *hw, +				 enum radio_path rfpath, u32 regaddr, +				 u32 bitmask, u32 data) +{ +	((struct rtl_priv *)(hw)->priv)->cfg->ops->set_rfreg(hw, +							     rfpath, regaddr, +							     bitmask, data); +} + +static inline bool is_hal_stop(struct rtl_hal *rtlhal) +{ +	return _HAL_STATE_STOP == rtlhal->state; +} + +static inline void set_hal_start(struct rtl_hal *rtlhal) +{ +	rtlhal->state = _HAL_STATE_START; +} + +static inline void set_hal_stop(struct rtl_hal *rtlhal) +{ +	rtlhal->state = _HAL_STATE_STOP; +} + +static inline u8 get_rf_type(struct rtl_phy *rtlphy) +{ +	return rtlphy->rf_type; +} + +static inline struct ieee80211_hdr *rtl_get_hdr(struct sk_buff *skb) +{ +	return (struct ieee80211_hdr *)(skb->data); +} + +static inline __le16 rtl_get_fc(struct sk_buff *skb) +{ +	return rtl_get_hdr(skb)->frame_control; +} + +static inline u16 rtl_get_tid_h(struct ieee80211_hdr *hdr) +{ +	return (ieee80211_get_qos_ctl(hdr))[0] & IEEE80211_QOS_CTL_TID_MASK; +} + +static inline u16 rtl_get_tid(struct sk_buff *skb) +{ +	return rtl_get_tid_h(rtl_get_hdr(skb)); +} + +static inline struct ieee80211_sta *rtl_find_sta(struct ieee80211_hw *hw, +						 u8 *mac_addr) +{ +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +	return ieee80211_find_sta(mac->vif, mac_addr); +} + +struct ieee80211_hw *rtl_pci_get_hw_pointer(void); +#endif  | 
