diff options
author | Srikant Patnaik | 2015-01-11 12:28:04 +0530 |
---|---|---|
committer | Srikant Patnaik | 2015-01-11 12:28:04 +0530 |
commit | 871480933a1c28f8a9fed4c4d34d06c439a7a422 (patch) | |
tree | 8718f573808810c2a1e8cb8fb6ac469093ca2784 /drivers/net/wireless/rtlwifi | |
parent | 9d40ac5867b9aefe0722bc1f110b965ff294d30d (diff) | |
download | FOSSEE-netbook-kernel-source-871480933a1c28f8a9fed4c4d34d06c439a7a422.tar.gz FOSSEE-netbook-kernel-source-871480933a1c28f8a9fed4c4d34d06c439a7a422.tar.bz2 FOSSEE-netbook-kernel-source-871480933a1c28f8a9fed4c4d34d06c439a7a422.zip |
Moved, renamed, and deleted files
The original directory structure was scattered and unorganized.
Changes are basically to make it look like kernel structure.
Diffstat (limited to 'drivers/net/wireless/rtlwifi')
113 files changed, 62216 insertions, 0 deletions
diff --git a/drivers/net/wireless/rtlwifi/Kconfig b/drivers/net/wireless/rtlwifi/Kconfig new file mode 100644 index 00000000..cefac6a4 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/Kconfig @@ -0,0 +1,60 @@ +config RTL8192CE + tristate "Realtek RTL8192CE/RTL8188CE Wireless Network Adapter" + depends on MAC80211 && PCI && EXPERIMENTAL + select FW_LOADER + select RTLWIFI + select RTL8192C_COMMON + ---help--- + This is the driver for Realtek RTL8192CE/RTL8188CE 802.11n PCIe + wireless network adapters. + + If you choose to build it as a module, it will be called rtl8192ce + +config RTL8192SE + tristate "Realtek RTL8192SE/RTL8191SE PCIe Wireless Network Adapter" + depends on MAC80211 && EXPERIMENTAL && PCI + select FW_LOADER + select RTLWIFI + ---help--- + This is the driver for Realtek RTL8192SE/RTL8191SE 802.11n PCIe + wireless network adapters. + + If you choose to build it as a module, it will be called rtl8192se + +config RTL8192DE + tristate "Realtek RTL8192DE/RTL8188DE PCIe Wireless Network Adapter" + depends on MAC80211 && EXPERIMENTAL && PCI + select FW_LOADER + select RTLWIFI + ---help--- + This is the driver for Realtek RTL8192DE/RTL8188DE 802.11n PCIe + wireless network adapters. + + If you choose to build it as a module, it will be called rtl8192de + +config RTL8192CU + tristate "Realtek RTL8192CU/RTL8188CU USB Wireless Network Adapter" + depends on MAC80211 && USB && EXPERIMENTAL + select FW_LOADER + select RTLWIFI + select RTL8192C_COMMON + ---help--- + This is the driver for Realtek RTL8192CU/RTL8188CU 802.11n USB + wireless network adapters. + + If you choose to build it as a module, it will be called rtl8192cu + +config RTLWIFI + tristate + depends on RTL8192CE || RTL8192CU || RTL8192SE || RTL8192DE + default m + +config RTLWIFI_DEBUG + bool "Additional debugging output" + depends on RTL8192CE || RTL8192CU || RTL8192SE || RTL8192DE + default y + +config RTL8192C_COMMON + tristate + depends on RTL8192CE || RTL8192CU + default m diff --git a/drivers/net/wireless/rtlwifi/Makefile b/drivers/net/wireless/rtlwifi/Makefile new file mode 100644 index 00000000..97935c56 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/Makefile @@ -0,0 +1,28 @@ +obj-$(CONFIG_RTLWIFI) += rtlwifi.o +rtlwifi-objs := \ + base.o \ + cam.o \ + core.o \ + debug.o \ + efuse.o \ + ps.o \ + rc.o \ + regd.o + +rtl8192c_common-objs += \ + +ifneq ($(CONFIG_PCI),) +rtlwifi-objs += pci.o +endif + +ifneq ($(CONFIG_USB),) +rtlwifi-objs += usb.o +endif + +obj-$(CONFIG_RTL8192C_COMMON) += rtl8192c/ +obj-$(CONFIG_RTL8192CE) += rtl8192ce/ +obj-$(CONFIG_RTL8192CU) += rtl8192cu/ +obj-$(CONFIG_RTL8192SE) += rtl8192se/ +obj-$(CONFIG_RTL8192DE) += rtl8192de/ + +ccflags-y += -D__CHECK_ENDIAN__ diff --git a/drivers/net/wireless/rtlwifi/base.c b/drivers/net/wireless/rtlwifi/base.c new file mode 100644 index 00000000..e54488db --- /dev/null +++ b/drivers/net/wireless/rtlwifi/base.c @@ -0,0 +1,1582 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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> + * + *****************************************************************************/ + +#include "wifi.h" +#include "rc.h" +#include "base.h" +#include "efuse.h" +#include "cam.h" +#include "ps.h" +#include "regd.h" + +#include <linux/ip.h> +#include <linux/module.h> + +/* + *NOTICE!!!: This file will be very big, we should + *keep it clear under following roles: + * + *This file include following parts, 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) ... + */ + +/********************************************************* + * + * 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 rtl_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 (get_rf_type(rtlphy) == RF_1T2R || get_rf_type(rtlphy) == RF_2T2R) { + + RT_TRACE(rtlpriv, 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(rtlpriv, 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_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); + + /* <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); + + /* <4> set mac->sband to wiphy->sband */ + hw->wiphy->bands[IEEE80211_BAND_5GHZ] = sband; + } else { + RT_TRACE(rtlpriv, 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_CONNECTION_MONITOR | + /* IEEE80211_HW_SUPPORTS_CQM_RSSI | */ + IEEE80211_HW_REPORTS_TX_ACK_STATUS | 0; + + /* swlps or hwlps has been set in diff chip in init_sw_vars */ + if (rtlpriv->psc.swctrl_lps) + hw->flags |= IEEE80211_HW_SUPPORTS_PS | + IEEE80211_HW_PS_NULLFUNC_STACK | + /* IEEE80211_HW_SUPPORTS_DYNAMIC_PS | */ + 0; + + hw->wiphy->interface_modes = + BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_ADHOC); + + 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; + hw->max_listen_interval = 10; + hw->max_rate_tries = 4; + /* hw->max_rates = 1; */ + hw->sta_data_size = sizeof(struct rtl_sta_info); + + /* <6> mac address */ + if (is_valid_ether_addr(rtlefuse->dev_addr)) { + SET_IEEE80211_PERM_ADDR(hw, rtlefuse->dev_addr); + } else { + u8 rtlmac1[] = { 0x00, 0xe0, 0x4c, 0x81, 0x92, 0x00 }; + get_random_bytes((rtlmac1 + (ETH_ALEN - 1)), 1); + SET_IEEE80211_PERM_ADDR(hw, rtlmac1); + } + +} + +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, + rtl_watch_dog_timer_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 *)rtl_watchdog_wq_callback); + INIT_DELAYED_WORK(&rtlpriv->works.ips_nic_off_wq, + (void *)rtl_ips_nic_off_wq_callback); + INIT_DELAYED_WORK(&rtlpriv->works.ps_work, + (void *)rtl_swlps_wq_callback); + INIT_DELAYED_WORK(&rtlpriv->works.ps_rfon_wq, + (void *)rtl_swlps_rfon_wq_callback); + +} + +void rtl_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); +} + +void rtl_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 = true; + wiphy_rfkill_set_hw_state(hw->wiphy, 0); + + radio_state = rtlpriv->cfg->ops->radio_onoff_checking(hw, &valid); + + if (valid) { + pr_info("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); +} +EXPORT_SYMBOL(rtl_init_rfkill); + +void rtl_deinit_rfkill(struct ieee80211_hw *hw) +{ + wiphy_rfkill_stop_polling(hw->wiphy); +} + +int rtl_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; + + /* <2> rate control register */ + hw->rate_control_algorithm = "rtl_rc"; + + /* + * <3> init CRDA must come after init + * mac80211 hw in _rtl_init_mac80211. + */ + if (rtl_regd_init(hw, rtl_reg_notifier)) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "REGD init failed\n"); + return 1; + } else { + /* CRDA regd hint must after init CRDA */ + if (regulatory_hint(hw->wiphy, rtlpriv->regd.alpha2)) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, + "regulatory_hint fail\n"); + } + } + + /* <4> locks */ + mutex_init(&rtlpriv->locks.conf_mutex); + mutex_init(&rtlpriv->locks.ps_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.waitq_lock); + spin_lock_init(&rtlpriv->locks.cck_and_rw_pagea_lock); + + rtlmac->link_state = MAC80211_NOLINK; + + /* <5> init deferred work */ + _rtl_init_deferred_work(hw); + + return 0; +} + +void rtl_deinit_core(struct ieee80211_hw *hw) +{ +} + +void rtl_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; + 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; + + if (!(sta->ht_cap.ht_supported)) + return; + + if (!sgi_40 && !sgi_20) + return; + + if (mac->opmode == NL80211_IFTYPE_STATION) + bw_40 = mac->bw_40; + else if (mac->opmode == NL80211_IFTYPE_AP || + mac->opmode == NL80211_IFTYPE_ADHOC) + bw_40 = sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40; + + if (bw_40 && sgi_40) + tcb_desc->use_shortgi = true; + else if ((bw_40 == false) && 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->rts_stbc = false; + tcb_desc->cts_enable = false; + tcb_desc->rts_sc = 0; + tcb_desc->rts_bw = false; + tcb_desc->rts_use_shortpreamble = false; + tcb_desc->rts_use_shortgi = false; + + if (rate_flag & IEEE80211_TX_RC_USE_CTS_PROTECT) { + /* Use CTS-to-SELF in protection mode. */ + tcb_desc->rts_enable = true; + tcb_desc->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->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) { + if (tcb_desc->multicast || tcb_desc->broadcast) { + tcb_desc->hw_rate = + rtlpriv->cfg->maps[RTL_RC_CCK_RATE2M]; + tcb_desc->use_driver_rate = 1; + } else { + /* TODO */ + } + tcb_desc->ratr_index = ratr_index; + } else if (mac->opmode == NL80211_IFTYPE_AP) { + tcb_desc->ratr_index = ratr_index; + } + } + + if (rtlpriv->dm.useramask) { + /* TODO we will differentiate adhoc and station futrue */ + if (mac->opmode == NL80211_IFTYPE_STATION) { + tcb_desc->mac_id = 0; + + 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 (NULL != 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 = false; + if (!sta) + return; + if (mac->opmode == NL80211_IFTYPE_AP || + mac->opmode == NL80211_IFTYPE_ADHOC) { + 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->multicast || tcb_desc->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 = true; +} + +static u8 _rtl_get_highest_n_rate(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + u8 hw_rate; + + if (get_rf_type(rtlphy) == RF_2T2R) + hw_rate = rtlpriv->cfg->maps[RTL_RC_HT_RATEMCS15]; + else + hw_rate = rtlpriv->cfg->maps[RTL_RC_HT_RATEMCS7]; + + return hw_rate; +} + +/* 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, + * DESC92_RATE1M-->DESC92_RATE54M ==> idx is 0-->11, + * + * N rate: + * (rx_status->flag & RX_FLAG_HT) = 1, + * DESC92_RATEMCS0-->DESC92_RATEMCS15 ==> idx is 0-->15 + * + * 5G band:rx_status->band == IEEE80211_BAND_5GHZ + * A rate: + * (rx_status->flag & RX_FLAG_HT) = 0, + * DESC92_RATE6M-->DESC92_RATE54M ==> idx is 0-->7, + * + * N rate: + * (rx_status->flag & RX_FLAG_HT) = 1, + * DESC92_RATEMCS0-->DESC92_RATEMCS15 ==> idx is 0-->15 + */ +int rtlwifi_rate_mapping(struct ieee80211_hw *hw, + bool isht, u8 desc_rate, bool first_ampdu) +{ + int rate_idx; + + if (false == isht) { + if (IEEE80211_BAND_2GHZ == hw->conf.channel->band) { + switch (desc_rate) { + case DESC92_RATE1M: + rate_idx = 0; + break; + case DESC92_RATE2M: + rate_idx = 1; + break; + case DESC92_RATE5_5M: + rate_idx = 2; + break; + case DESC92_RATE11M: + rate_idx = 3; + break; + case DESC92_RATE6M: + rate_idx = 4; + break; + case DESC92_RATE9M: + rate_idx = 5; + break; + case DESC92_RATE12M: + rate_idx = 6; + break; + case DESC92_RATE18M: + rate_idx = 7; + break; + case DESC92_RATE24M: + rate_idx = 8; + break; + case DESC92_RATE36M: + rate_idx = 9; + break; + case DESC92_RATE48M: + rate_idx = 10; + break; + case DESC92_RATE54M: + rate_idx = 11; + break; + default: + rate_idx = 0; + break; + } + } else { + switch (desc_rate) { + case DESC92_RATE6M: + rate_idx = 0; + break; + case DESC92_RATE9M: + rate_idx = 1; + break; + case DESC92_RATE12M: + rate_idx = 2; + break; + case DESC92_RATE18M: + rate_idx = 3; + break; + case DESC92_RATE24M: + rate_idx = 4; + break; + case DESC92_RATE36M: + rate_idx = 5; + break; + case DESC92_RATE48M: + rate_idx = 6; + break; + case DESC92_RATE54M: + rate_idx = 7; + break; + default: + rate_idx = 0; + break; + } + } + + } else { + + switch (desc_rate) { + case DESC92_RATEMCS0: + rate_idx = 0; + break; + case DESC92_RATEMCS1: + rate_idx = 1; + break; + case DESC92_RATEMCS2: + rate_idx = 2; + break; + case DESC92_RATEMCS3: + rate_idx = 3; + break; + case DESC92_RATEMCS4: + rate_idx = 4; + break; + case DESC92_RATEMCS5: + rate_idx = 5; + break; + case DESC92_RATEMCS6: + rate_idx = 6; + break; + case DESC92_RATEMCS7: + rate_idx = 7; + break; + case DESC92_RATEMCS8: + rate_idx = 8; + break; + case DESC92_RATEMCS9: + rate_idx = 9; + break; + case DESC92_RATEMCS10: + rate_idx = 10; + break; + case DESC92_RATEMCS11: + rate_idx = 11; + break; + case DESC92_RATEMCS12: + rate_idx = 12; + break; + case DESC92_RATEMCS13: + rate_idx = 13; + break; + case DESC92_RATEMCS14: + rate_idx = 14; + break; + case DESC92_RATEMCS15: + rate_idx = 15; + break; + default: + rate_idx = 0; + break; + } + } + return rate_idx; +} +EXPORT_SYMBOL(rtlwifi_rate_mapping); + +void 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 = hdr->frame_control; + + txrate = ieee80211_get_tx_rate(hw, info); + if (txrate) + tcb_desc->hw_rate = txrate->hw_value; + else + tcb_desc->hw_rate = 0; + + 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 controlled by FW + *when tcb_desc->use_driver_rate = false + */ + if (sta && (sta->ht_cap.ht_supported)) { + tcb_desc->hw_rate = _rtl_get_highest_n_rate(hw); + } 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->multicast = 1; + else if (is_broadcast_ether_addr(ieee80211_get_DA(hdr))) + tcb_desc->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 = false; + } +} +EXPORT_SYMBOL(rtl_get_tcb_desc); + +bool rtl_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 = hdr->frame_control; + 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(rtlpriv, (COMP_SEND | COMP_RECV), DBG_DMESG, + "%s ACT_ADDBAREQ From :%pM\n", + is_tx ? "Tx" : "Rx", hdr->addr2); + break; + case ACT_ADDBARSP: + RT_TRACE(rtlpriv, (COMP_SEND | COMP_RECV), DBG_DMESG, + "%s ACT_ADDBARSP From :%pM\n", + is_tx ? "Tx" : "Rx", hdr->addr2); + break; + case ACT_DELBA: + RT_TRACE(rtlpriv, (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 rtl_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)) + return false; + + + ip = (struct iphdr *)((u8 *) skb->data + mac_hdr_len + + SNAP_SIZE + PROTOC_TYPE_SIZE); + ether_type = *(u16 *) ((u8 *) skb->data + mac_hdr_len + SNAP_SIZE); + /* ether_type = ntohs(ether_type); */ + + 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(rtlpriv, (COMP_SEND | COMP_RECV), + DBG_DMESG, "dhcp %s !!\n", + is_tx ? "Tx" : "Rx"); + + if (is_tx) { + rtl_lps_leave(hw); + ppsc->last_delaylps_stamp_jiffies = + jiffies; + } + + return true; + } + } + } else if (ETH_P_ARP == ether_type) { + if (is_tx) { + rtl_lps_leave(hw); + ppsc->last_delaylps_stamp_jiffies = jiffies; + } + + return true; + } else if (ETH_P_PAE == ether_type) { + RT_TRACE(rtlpriv, (COMP_SEND | COMP_RECV), DBG_DMESG, + "802.1X %s EAPOL pkt!!\n", is_tx ? "Tx" : "Rx"); + + if (is_tx) { + rtl_lps_leave(hw); + ppsc->last_delaylps_stamp_jiffies = jiffies; + } + + return true; + } else if (ETH_P_IPV6 == ether_type) { + /* IPv6 */ + return true; + } + + return false; +} + +/********************************************************* + * + * functions called by core.c + * + *********************************************************/ +int rtl_tx_agg_start(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, u16 tid, u16 *ssn) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_tid_data *tid_data; + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + 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(rtlpriv, 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(mac->vif, sta->addr, tid); + + return 0; +} + +int rtl_tx_agg_stop(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, u16 tid) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_sta_info *sta_entry = NULL; + + if (sta == NULL) + return -EINVAL; + + if (!sta->addr) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "ra = NULL\n"); + return -EINVAL; + } + + RT_TRACE(rtlpriv, 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; + sta_entry->tids[tid].agg.agg_state = RTL_AGG_STOP; + + ieee80211_stop_tx_ba_cb_irqsafe(mac->vif, sta->addr, tid); + + return 0; +} + +int rtl_tx_agg_oper(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, u16 tid) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_sta_info *sta_entry = NULL; + + if (sta == NULL) + return -EINVAL; + + if (!sta->addr) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "ra = NULL\n"); + return -EINVAL; + } + + RT_TRACE(rtlpriv, 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; + sta_entry->tids[tid].agg.agg_state = RTL_AGG_OPERATIONAL; + + return 0; +} + +/********************************************************* + * + * wq & timer callback functions + * + *********************************************************/ +void rtl_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 busytraffic = false; + bool higher_busytraffic = false; + bool 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 enter_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) + busytraffic = true; + + /* Higher Tx/Rx data. */ + if (aver_rx_cnt_inperiod > 4000 || + aver_tx_cnt_inperiod > 4000) { + higher_busytraffic = true; + + /* Extremely high Rx data. */ + if (aver_rx_cnt_inperiod > 5000) + 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)) + enter_ps = false; + else + enter_ps = true; + + /* LeisurePS only work in infra mode. */ + if (enter_ps) + rtl_lps_enter(hw); + else + rtl_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.busytraffic = busytraffic; + rtlpriv->link_info.higher_busytraffic = higher_busytraffic; + rtlpriv->link_info.higher_busyrxtraffic = higher_busyrxtraffic; + + /* <3> DM */ + rtlpriv->cfg->ops->dm_watchdog(hw); +} + +void rtl_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)); +} + +/********************************************************* + * + * frame process functions + * + *********************************************************/ +u8 *rtl_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 *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); + memcpy(action_frame->da, da, ETH_ALEN); + memcpy(action_frame->sa, rtlefuse->dev_addr, ETH_ALEN); + memcpy(action_frame->bssid, bssid, ETH_ALEN); + 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); + 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 rtl_send_smps_action(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, u8 *da, u8 *bssid, + 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 = rtl_make_smps_action(hw, smps, da, bssid); + struct rtl_tcb_desc tcb_desc; + 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; + + /* 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->control.sta = sta; + info->band = hw->conf.channel->band; + rtlpriv->intf_ops->adapter_tx(hw, skb, &tcb_desc); + } +err_free: + return 0; +} + +/********************************************************* + * + * 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 rtl_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 (compare_ether_addr(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(rtlpriv, 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(rtlpriv, COMP_MAC80211, DBG_LOUD, "=>ral find\n"); + vendor = PEER_RAL; + } else if (memcmp(mac->bssid, ap6_1, 3) == 0 || + vendor == PEER_CISCO) { + vendor = PEER_CISCO; + RT_TRACE(rtlpriv, 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(rtlpriv, 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(rtlpriv, COMP_MAC80211, DBG_LOUD, "=>marv find\n"); + } + + mac->vendor = vendor; +} + +/********************************************************* + * + * sysfs functions + * + *********************************************************/ +static ssize_t rtl_show_debug_level(struct device *d, + struct device_attribute *attr, char *buf) +{ + struct ieee80211_hw *hw = dev_get_drvdata(d); + struct rtl_priv *rtlpriv = rtl_priv(hw); + + return sprintf(buf, "0x%08X\n", rtlpriv->dbg.global_debuglevel); +} + +static ssize_t rtl_store_debug_level(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct ieee80211_hw *hw = dev_get_drvdata(d); + struct rtl_priv *rtlpriv = rtl_priv(hw); + unsigned long val; + int ret; + + ret = strict_strtoul(buf, 0, &val); + if (ret) { + printk(KERN_DEBUG "%s is not in hex or decimal form.\n", buf); + } else { + rtlpriv->dbg.global_debuglevel = val; + printk(KERN_DEBUG "debuglevel:%x\n", + rtlpriv->dbg.global_debuglevel); + } + + return strnlen(buf, count); +} + +static DEVICE_ATTR(debug_level, S_IWUSR | S_IRUGO, + rtl_show_debug_level, rtl_store_debug_level); + +static struct attribute *rtl_sysfs_entries[] = { + + &dev_attr_debug_level.attr, + + NULL +}; + +/* + * "name" is folder name witch will be + * put in device directory like : + * sys/devices/pci0000:00/0000:00:1c.4/ + * 0000:06:00.0/rtl_sysfs + */ +struct attribute_group rtl_attribute_group = { + .name = "rtlsysfs", + .attrs = rtl_sysfs_entries, +}; + +MODULE_AUTHOR("lizhaoming <chaoming_li@realsil.com.cn>"); +MODULE_AUTHOR("Realtek WlanFAE <wlanfae@realtek.com>"); +MODULE_AUTHOR("Larry Finger <Larry.FInger@lwfinger.net>"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Realtek 802.11n PCI wireless core"); + +static int __init rtl_core_module_init(void) +{ + if (rtl_rate_control_register()) + pr_err("Unable to register rtl_rc, use default RC !!\n"); + + return 0; +} + +static void __exit rtl_core_module_exit(void) +{ + /*RC*/ + rtl_rate_control_unregister(); +} + +module_init(rtl_core_module_init); +module_exit(rtl_core_module_exit); diff --git a/drivers/net/wireless/rtlwifi/base.h b/drivers/net/wireless/rtlwifi/base.h new file mode 100644 index 00000000..5a23a6d0 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/base.h @@ -0,0 +1,145 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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 __RTL_BASE_H__ +#define __RTL_BASE_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 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) \ + (*(u16 *)((u8 *)(_hdr) + FRAME_OFFSET_DURATION) = le16_to_cpu(_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 rtl_init_core(struct ieee80211_hw *hw); +void rtl_deinit_core(struct ieee80211_hw *hw); +void rtl_init_rx_config(struct ieee80211_hw *hw); +void rtl_init_rfkill(struct ieee80211_hw *hw); +void rtl_deinit_rfkill(struct ieee80211_hw *hw); + +void rtl_watch_dog_timer_callback(unsigned long data); +void rtl_deinit_deferred_work(struct ieee80211_hw *hw); + +bool rtl_action_proc(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx); +u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx); + +void rtl_watch_dog_timer_callback(unsigned long data); +int rtl_tx_agg_start(struct ieee80211_hw *hw, struct ieee80211_sta *sta, + u16 tid, u16 *ssn); +int rtl_tx_agg_stop(struct ieee80211_hw *hw, struct ieee80211_sta *sta, + u16 tid); +int rtl_tx_agg_oper(struct ieee80211_hw *hw, struct ieee80211_sta *sta, + u16 tid); +void rtl_watchdog_wq_callback(void *data); + +void 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 rtl_send_smps_action(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, u8 *da, u8 *bssid, + enum ieee80211_smps_mode smps); +u8 *rtl_find_ie(u8 *data, unsigned int len, u8 ie); +void rtl_recognize_peer(struct ieee80211_hw *hw, u8 *data, unsigned int len); +u8 rtl_tid_to_ac(struct ieee80211_hw *hw, u8 tid); +extern struct attribute_group rtl_attribute_group; +int rtlwifi_rate_mapping(struct ieee80211_hw *hw, + bool isht, u8 desc_rate, bool first_ampdu); +#endif diff --git a/drivers/net/wireless/rtlwifi/cam.c b/drivers/net/wireless/rtlwifi/cam.c new file mode 100644 index 00000000..5c7d5794 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/cam.c @@ -0,0 +1,351 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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> + * + *****************************************************************************/ + +#include <linux/export.h> +#include "wifi.h" +#include "cam.h" + +void rtl_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_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, + "key_cont_128:\n %x:%x:%x:%x:%x:%x\n", + key_cont_128[0], key_cont_128[1], + key_cont_128[2], key_cont_128[3], + key_cont_128[4], key_cont_128[5]); + + 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(rtlpriv, COMP_SEC, DBG_LOUD, "WRITE %x: %x\n", + rtlpriv->cfg->maps[WCAMI], target_content); + RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, + "The Key ID is %d\n", entry_no); + RT_TRACE(rtlpriv, 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(rtlpriv, COMP_SEC, DBG_LOUD, "WRITE A4: %x\n", + target_content); + RT_TRACE(rtlpriv, 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(rtlpriv, COMP_SEC, DBG_LOUD, "WRITE A4: %x\n", + target_content); + RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, "WRITE A0: %x\n", + target_command); + } + } + + RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, "after set key, usconfig:%x\n", + us_config); +} + +u8 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(rtlpriv, 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(rtlpriv, 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(rtlpriv, COMP_SEC, DBG_DMESG, "<===\n"); + + return 1; + +} +EXPORT_SYMBOL(rtl_cam_add_one_entry); + +int 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(rtlpriv, 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(rtlpriv, COMP_SEC, DBG_DMESG, + "rtl_cam_delete_one_entry(): WRITE A4: %x\n", 0); + RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, + "rtl_cam_delete_one_entry(): WRITE A0: %x\n", ul_command); + + return 0; + +} +EXPORT_SYMBOL(rtl_cam_delete_one_entry); + +void 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(rtl_cam_reset_all_entry); + +void 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(rtlpriv, COMP_SEC, DBG_DMESG, + "rtl_cam_mark_invalid(): WRITE A4: %x\n", ul_content); + RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, + "rtl_cam_mark_invalid(): WRITE A0: %x\n", ul_command); +} +EXPORT_SYMBOL(rtl_cam_mark_invalid); + +void 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(rtlpriv, COMP_SEC, DBG_LOUD, + "rtl_cam_empty_entry(): WRITE A4: %x\n", + ul_content); + RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, + "rtl_cam_empty_entry(): WRITE A0: %x\n", + ul_command); + } + +} +EXPORT_SYMBOL(rtl_cam_empty_entry); + +u8 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 (NULL == sta_addr) { + RT_TRACE(rtlpriv, 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(rtlpriv, 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(rtl_cam_get_free_entry); + +void 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(rtlpriv, COMP_SEC, DBG_EMERG, "sta_addr is NULL\n"); + } + + if ((sta_addr[0]|sta_addr[1]|sta_addr[2]|sta_addr[3]|\ + sta_addr[4]|sta_addr[5]) == 0) { + RT_TRACE(rtlpriv, 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(rtl_cam_del_entry); diff --git a/drivers/net/wireless/rtlwifi/cam.h b/drivers/net/wireless/rtlwifi/cam.h new file mode 100644 index 00000000..35e00086 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/cam.h @@ -0,0 +1,56 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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 __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 + +extern void rtl_cam_reset_all_entry(struct ieee80211_hw *hw); +extern u8 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 rtl_cam_delete_one_entry(struct ieee80211_hw *hw, u8 *mac_addr, + u32 ul_key_id); +void rtl_cam_mark_invalid(struct ieee80211_hw *hw, u8 uc_index); +void rtl_cam_empty_entry(struct ieee80211_hw *hw, u8 uc_index); +void rtl_cam_reset_sec_info(struct ieee80211_hw *hw); +u8 rtl_cam_get_free_entry(struct ieee80211_hw *hw, u8 *sta_addr); +void rtl_cam_del_entry(struct ieee80211_hw *hw, u8 *sta_addr); + +#endif diff --git a/drivers/net/wireless/rtlwifi/core.c b/drivers/net/wireless/rtlwifi/core.c new file mode 100644 index 00000000..278e9f95 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/core.c @@ -0,0 +1,1196 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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> + * + *****************************************************************************/ + +#include "wifi.h" +#include "core.h" +#include "cam.h" +#include "base.h" +#include "pci.h" +#include "ps.h" + +#include <linux/export.h> + +void rtl_fw_cb(const struct firmware *firmware, void *context) +{ + struct ieee80211_hw *hw = context; + struct rtl_priv *rtlpriv = rtl_priv(hw); + int err; + + RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD, + "Firmware callback routine entered!\n"); + complete(&rtlpriv->firmware_loading_complete); + if (!firmware) { + pr_err("Firmware %s not available\n", rtlpriv->cfg->fw_name); + rtlpriv->max_fw_size = 0; + return; + } + if (firmware->size > rtlpriv->max_fw_size) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "Firmware is too big!\n"); + release_firmware(firmware); + return; + } + memcpy(rtlpriv->rtlhal.pfirmware, firmware->data, firmware->size); + rtlpriv->rtlhal.fwsize = firmware->size; + release_firmware(firmware); + + err = ieee80211_register_hw(hw); + if (err) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "Can't register mac80211 hw\n"); + return; + } else { + rtlpriv->mac80211.mac80211_registered = 1; + } + set_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status); + + /*init rfkill */ + rtl_init_rfkill(hw); +} +EXPORT_SYMBOL(rtl_fw_cb); + +/*mutex for start & stop is must here. */ +static int rtl_op_start(struct ieee80211_hw *hw) +{ + int err; + 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) + rtl_watch_dog_timer_callback((unsigned long)hw); + 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)); + + if (is_hal_stop(rtlhal)) + return; + + if (unlikely(ppsc->rfpwr_state == ERFOFF)) { + rtl_ips_nic_on(hw); + mdelay(1); + } + + mutex_lock(&rtlpriv->locks.conf_mutex); + + mac->link_state = MAC80211_NOLINK; + memset(mac->bssid, 0, 6); + mac->vendor = PEER_UNKNOWN; + + /*reset sec info */ + rtl_cam_reset_sec_info(hw); + + rtl_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 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, skb)) + rtlpriv->intf_ops->adapter_tx(hw, skb, &tcb_desc); + + return; + +err_free: + dev_kfree_skb_any(skb); +} + +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; + + vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER; + + if (mac->vif) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, + "vif has been set!! mac->vif = 0x%p\n", mac->vif); + return -EOPNOTSUPP; + } + + rtl_ips_nic_on(hw); + + mutex_lock(&rtlpriv->locks.conf_mutex); + switch (vif->type) { + case NL80211_IFTYPE_STATION: + if (mac->beacon_enabled == 1) { + RT_TRACE(rtlpriv, 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(rtlpriv, 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_AP: + RT_TRACE(rtlpriv, 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; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "operation mode %d is not supported!\n", vif->type); + err = -EOPNOTSUPP; + goto out; + } + + mac->vif = vif; + mac->opmode = vif->type; + rtlpriv->cfg->ops->set_network_type(hw, vif->type); + memcpy(mac->mac_addr, vif->addr, ETH_ALEN); + 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 ((mac->opmode == NL80211_IFTYPE_AP) || + (mac->opmode == NL80211_IFTYPE_ADHOC) || + (mac->opmode == 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->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); +} + +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; + + mutex_lock(&rtlpriv->locks.conf_mutex); + if (changed & IEEE80211_CONF_CHANGE_LISTEN_INTERVAL) { /*BIT(2)*/ + RT_TRACE(rtlpriv, 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) + rtl_ips_nic_off(hw); + else + rtl_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)) + rtl_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 { + rtl_swlps_rf_awake(hw); + rtlpriv->psc.sw_ps_enabled = false; + } + } + + if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS) { + RT_TRACE(rtlpriv, 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) { + struct ieee80211_channel *channel = hw->conf.channel; + u8 wide_chan = (u8) channel->hw_value; + + /* + *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 + */ + switch (hw->conf.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; + 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; + + /*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; + + /*wide channel */ + wide_chan += 2; + + break; + default: + mac->bw_40 = false; + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "switch case not processed\n"); + break; + } + + if (wide_chan <= 0) + wide_chan = 1; + + /* In scanning, before we go 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 may have caused AP to put lots of packet to hw tx + * buffer. These packets must be tx'd before we go off channel + * so we must delay more time to let AP flush these packets + * before going offchannel, or dis-association or delete BA will + * happen by AP + */ + if (rtlpriv->mac80211.offchan_delay) { + rtlpriv->mac80211.offchan_delay = 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, + hw->conf.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 (!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(rtlpriv, 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(rtlpriv, 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(rtlpriv, COMP_MAC80211, DBG_LOUD, + "Enable receive FCS error frame\n"); + } else { + mac->rx_conf &= ~rtlpriv->cfg->maps[MAC_RCR_ACRC32]; + RT_TRACE(rtlpriv, 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) { + 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(rtlpriv, COMP_MAC80211, DBG_LOUD, + "Enable receive control frame\n"); + } else { + mac->rx_conf &= ~rtlpriv->cfg->maps[MAC_RCR_ACF]; + RT_TRACE(rtlpriv, 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(rtlpriv, COMP_MAC80211, DBG_LOUD, + "Enable receive other BSS's frame\n"); + } else { + mac->rx_conf &= ~rtlpriv->cfg->maps[MAC_RCR_AAP]; + RT_TRACE(rtlpriv, 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_sta_info *sta_entry; + + if (sta) { + sta_entry = (struct rtl_sta_info *) sta->drv_priv; + 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; + } 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_24G; + } + + /* I found some times mac80211 give wrong supp_rates for adhoc*/ + if (rtlpriv->mac80211.opmode == NL80211_IFTYPE_ADHOC) + sta_entry->wireless_mode = WIRELESS_MODE_G; + + RT_TRACE(rtlpriv, 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(rtlpriv, 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; + } + 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(rtlpriv, 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)); + struct ieee80211_sta *sta = NULL; + + 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(rtlpriv, 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(rtlpriv, 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(rtlpriv, 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) { + if (bss_conf->assoc) { + /* 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 */ + rtl_cam_reset_sec_info(hw); + /* reset cam to fix wep fail issue + * when change from wpa to wep */ + 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); + if (mac->opmode == NL80211_IFTYPE_STATION && sta) + rtlpriv->cfg->ops->update_rate_tbl(hw, sta, 0); + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG, + "BSS_CHANGED_ASSOC\n"); + } else { + if (mac->link_state == MAC80211_LINKED) + rtl_lps_leave(hw); + + mac->link_state = MAC80211_NOLINK; + memset(mac->bssid, 0, 6); + + /* reset sec info */ + rtl_cam_reset_sec_info(hw); + + rtl_cam_reset_all_entry(hw); + mac->vendor = PEER_UNKNOWN; + + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG, + "BSS_CHANGED_UN_ASSOC\n"); + } + } + + if (changed & BSS_CHANGED_ERP_CTS_PROT) { + RT_TRACE(rtlpriv, 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(rtlpriv, 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(rtlpriv, 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) { + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE, "BSS_CHANGED_HT\n"); + rcu_read_lock(); + sta = get_sta(hw, vif, 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; + + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_BSSID, + (u8 *) bss_conf->bssid); + + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG, "%pM\n", + bss_conf->bssid); + + mac->vendor = PEER_UNKNOWN; + memcpy(mac->bssid, bss_conf->bssid, 6); + rtlpriv->cfg->ops->set_network_type(hw, vif->type); + + rcu_read_lock(); + sta = get_sta(hw, vif, 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; + } + + /* just station need it, because ibss & ap mode will + * set in sta_add, and will be NULL here */ + if (mac->opmode == 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 (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(); + } + + /* + * For FW LPS: + * To tell firmware we have connected + * to an AP. For 92SE/CE power save v2. + */ + if (changed & BSS_CHANGED_ASSOC) { + if (bss_conf->assoc) { + if (ppsc->fwctrl_lps) { + u8 mstatus = RT_MEDIA_CONNECT; + rtlpriv->cfg->ops->set_hw_reg(hw, + HW_VAR_H2C_FW_JOINBSSRPT, + (u8 *) (&mstatus)); + ppsc->report_linked = true; + } + } else { + if (ppsc->fwctrl_lps) { + u8 mstatus = RT_MEDIA_DISCONNECT; + rtlpriv->cfg->ops->set_hw_reg(hw, + HW_VAR_H2C_FW_JOINBSSRPT, + (u8 *)(&mstatus)); + ppsc->report_linked = false; + } + } + } + +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(rtlpriv, COMP_MAC80211, DBG_TRACE, + "IEEE80211_AMPDU_TX_START: TID:%d\n", tid); + return rtl_tx_agg_start(hw, sta, tid, ssn); + break; + case IEEE80211_AMPDU_TX_STOP: + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE, + "IEEE80211_AMPDU_TX_STOP: TID:%d\n", tid); + return rtl_tx_agg_stop(hw, sta, tid); + break; + case IEEE80211_AMPDU_TX_OPERATIONAL: + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE, + "IEEE80211_AMPDU_TX_OPERATIONAL:TID:%d\n", tid); + rtl_tx_agg_oper(hw, sta, tid); + break; + case IEEE80211_AMPDU_RX_START: + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE, + "IEEE80211_AMPDU_RX_START:TID:%d\n", tid); + break; + case IEEE80211_AMPDU_RX_STOP: + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE, + "IEEE80211_AMPDU_RX_STOP:TID:%d\n", tid); + break; + default: + RT_TRACE(rtlpriv, 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)); + + mac->act_scanning = true; + + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, "\n"); + + if (mac->link_state == MAC80211_LINKED) { + rtl_lps_leave(hw); + mac->link_state = MAC80211_LINKED_SCANNING; + } else { + rtl_ips_nic_on(hw); + } + + /* Dual mac */ + rtlpriv->rtlhal.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); +} + +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(rtlpriv, COMP_MAC80211, DBG_LOUD, "\n"); + mac->act_scanning = false; + /* Dual mac */ + rtlpriv->rtlhal.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); +} + +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); + struct rtl_mac *mac = rtl_mac(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 }; + u8 zero_addr[ETH_ALEN] = { 0 }; + + if (rtlpriv->cfg->mod_params->sw_crypto || rtlpriv->sec.use_sw_sec) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, + "not open hw encryption\n"); + return -ENOSPC; /*User disabled HW-crypto */ + } + RT_TRACE(rtlpriv, 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; + rtl_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(rtlpriv, COMP_SEC, DBG_DMESG, "alg:WEP40\n"); + break; + case WLAN_CIPHER_SUITE_WEP104: + RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, "alg:WEP104\n"); + key_type = WEP104_ENCRYPTION; + break; + case WLAN_CIPHER_SUITE_TKIP: + key_type = TKIP_ENCRYPTION; + RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, "alg:TKIP\n"); + break; + case WLAN_CIPHER_SUITE_CCMP: + key_type = AESCCMP_ENCRYPTION; + RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, "alg:CCMP\n"); + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "alg_err:%x!!!!\n", + key->cipher); + goto out_unlock; + } + if (key_type == WEP40_ENCRYPTION || + key_type == WEP104_ENCRYPTION || + mac->opmode == 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 (mac->opmode == NL80211_IFTYPE_AP) { + 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) || (mac->opmode == 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(rtlpriv, 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(rtlpriv, 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; + memcpy(mac_addr, zero_addr, ETH_ALEN); + } else if (group_key) { /* group key */ + RT_TRACE(rtlpriv, 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; + memcpy(mac_addr, bcast_addr, ETH_ALEN); + } else { /* pairwise key */ + RT_TRACE(rtlpriv, 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]; + memcpy(mac_addr, sta->addr, ETH_ALEN); + } + 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; + break; + case DISABLE_KEY: + RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, + "disable key delete one entry\n"); + /*set local buf about wep key. */ + if (mac->opmode == NL80211_IFTYPE_AP) { + if (sta) + rtl_cam_del_entry(hw, sta->addr); + } + memset(rtlpriv->sec.key_buf[key_idx], 0, key->keylen); + rtlpriv->sec.key_len[key_idx] = 0; + memcpy(mac_addr, zero_addr, ETH_ALEN); + /* + *mac80211 will delete entrys one by one, + *so don't use rtl_cam_reset_all_entry + *or clear all entry here. + */ + rtl_cam_delete_one_entry(hw, mac_addr, key_idx); + + rtl_cam_reset_sec_info(hw); + + break; + default: + RT_TRACE(rtlpriv, 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(rtlpriv, COMP_RF, DBG_DMESG, + "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, bool drop) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + if (rtlpriv->intf_ops->flush) + rtlpriv->intf_ops->flush(hw, drop); +} + +const struct ieee80211_ops rtl_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, + .config = rtl_op_config, + .configure_filter = rtl_op_configure_filter, + .sta_add = rtl_op_sta_add, + .sta_remove = rtl_op_sta_remove, + .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, + .flush = rtl_op_flush, +}; diff --git a/drivers/net/wireless/rtlwifi/core.h b/drivers/net/wireless/rtlwifi/core.h new file mode 100644 index 00000000..2fe46a1b --- /dev/null +++ b/drivers/net/wireless/rtlwifi/core.h @@ -0,0 +1,45 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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. + * + * You should have received a copy of the GNU General Public License along with + * tmis program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * 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 rtl_ops; +void rtl_fw_cb(const struct firmware *firmware, void *context); + +#endif diff --git a/drivers/net/wireless/rtlwifi/debug.c b/drivers/net/wireless/rtlwifi/debug.c new file mode 100644 index 00000000..bdda9b2f --- /dev/null +++ b/drivers/net/wireless/rtlwifi/debug.c @@ -0,0 +1,50 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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. + * + * You should have received a copy of the GNU General Public License along with + * tmis program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * 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> + *****************************************************************************/ + +#include "wifi.h" + +#include <linux/moduleparam.h> + +void rtl_dbgp_flag_init(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 i; + + 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_EFUSE | COMP_QOS | COMP_MAC80211 | COMP_REGD | COMP_CHAN; + + for (i = 0; i < DBGP_TYPE_MAX; i++) + rtlpriv->dbg.dbgp_type[i] = 0; + + /*Init Debug flag enable condition */ +} diff --git a/drivers/net/wireless/rtlwifi/debug.h b/drivers/net/wireless/rtlwifi/debug.h new file mode 100644 index 00000000..07493d29 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/debug.h @@ -0,0 +1,233 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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. + * + * You should have received a copy of the GNU General Public License along with + * tmis program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * 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 0 + +/* + *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_USB BIT(29) + +/*-------------------------------------------------------------- + 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) + +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 +}; + +#ifdef CONFIG_RTLWIFI_DEBUG + +#define RT_ASSERT(_exp, fmt, ...) \ +do { \ + if (!(_exp)) { \ + printk(KERN_DEBUG KBUILD_MODNAME ":%s(): " fmt, \ + __func__, ##__VA_ARGS__); \ + } \ +} while (0) + +#define RT_TRACE(rtlpriv, comp, level, fmt, ...) \ +do { \ + if (unlikely(((comp) & rtlpriv->dbg.global_debugcomponents) && \ + ((level) <= rtlpriv->dbg.global_debuglevel))) { \ + printk(KERN_DEBUG KBUILD_MODNAME ":%s():<%lx-%x> " fmt, \ + __func__, in_interrupt(), in_atomic(), \ + ##__VA_ARGS__); \ + } \ +} while (0) + +#define RTPRINT(rtlpriv, dbgtype, dbgflag, fmt, ...) \ +do { \ + if (unlikely(rtlpriv->dbg.dbgp_type[dbgtype] & dbgflag)) { \ + printk(KERN_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))) { \ + printk(KERN_DEBUG "%s: In process \"%s\" (pid %i): %s\n", \ + KBUILD_MODNAME, current->comm, current->pid, \ + _titlestring); \ + print_hex_dump_bytes("", DUMP_PREFIX_NONE, \ + _hexdata, _hexdatalen); \ + } \ +} while (0) + +#else + +struct rtl_priv; + +__printf(2, 3) +static inline void RT_ASSERT(int exp, const char *fmt, ...) +{ +} + +__printf(4, 5) +static inline void RT_TRACE(struct rtl_priv *rtlpriv, + int comp, int level, + const char *fmt, ...) +{ +} + +__printf(4, 5) +static inline void RTPRINT(struct rtl_priv *rtlpriv, + int dbgtype, int dbgflag, + const char *fmt, ...) +{ +} + +static inline void RT_PRINT_DATA(struct rtl_priv *rtlpriv, + int comp, int level, + const char *titlestring, + const void *hexdata, size_t hexdatalen) +{ +} + +#endif + +void rtl_dbgp_flag_init(struct ieee80211_hw *hw); +#endif diff --git a/drivers/net/wireless/rtlwifi/efuse.c b/drivers/net/wireless/rtlwifi/efuse.c new file mode 100644 index 00000000..1f143800 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/efuse.c @@ -0,0 +1,1208 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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. + * + * You should have received a copy of the GNU General Public License along with + * tmis program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * 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> + * + *****************************************************************************/ + +#include <linux/export.h> +#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 u8 EFUSE_OOB_PROTECT_BYTES = 15; + +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 efuse_shadow_read_1byte(struct ieee80211_hw *hw, u16 offset, + u8 *value); +static void efuse_shadow_read_2byte(struct ieee80211_hw *hw, u16 offset, + u16 *value); +static void efuse_shadow_read_4byte(struct ieee80211_hw *hw, u16 offset, + u32 *value); +static void efuse_shadow_write_1byte(struct ieee80211_hw *hw, u16 offset, + u8 value); +static void efuse_shadow_write_2byte(struct ieee80211_hw *hw, u16 offset, + u16 value); +static void efuse_shadow_write_4byte(struct ieee80211_hw *hw, u16 offset, + u32 value); +static int efuse_one_byte_read(struct ieee80211_hw *hw, u16 addr, + u8 *data); +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 write, + u8 pwrstate); +static u16 efuse_get_current_size(struct ieee80211_hw *hw); +static u8 efuse_calculate_word_cnts(u8 word_en); + +void efuse_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 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_len = + rtlpriv->cfg->maps[EFUSE_REAL_CONTENT_SIZE]; + + if (address < efuse_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(efuse_read_1byte); + +void efuse_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_len = + rtlpriv->cfg->maps[EFUSE_REAL_CONTENT_SIZE]; + + RT_TRACE(rtlpriv, COMP_EFUSE, DBG_LOUD, "Addr=%x Data =%x\n", + address, value); + + if (address < efuse_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 read_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 read_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; + u16 i; + u16 j; + const u16 efuse_max_section = + rtlpriv->cfg->maps[EFUSE_MAX_SECTION_MAP]; + const u32 efuse_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(rtlpriv, COMP_EFUSE, DBG_LOUD, + "read_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 = kmalloc(EFUSE_MAX_WORD_UNIT * sizeof(u16 *), GFP_ATOMIC); + if (!efuse_word) + goto done; + 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][i] = 0xFFFF; + + read_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_len)) { + offset = ((*rtemp8 >> 4) & 0x0f); + + if (offset < efuse_max_section) { + wren = (*rtemp8 & 0x0f); + 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); + + read_efuse_byte(hw, efuse_addr, rtemp8); + efuse_addr++; + efuse_utilized++; + efuse_word[i][offset] = + (*rtemp8 & 0xff); + + if (efuse_addr >= efuse_len) + break; + + RTPRINT(rtlpriv, FEEPROM, + EFUSE_READ_ALL, + "Addr=%d\n", efuse_addr); + + read_efuse_byte(hw, efuse_addr, rtemp8); + efuse_addr++; + efuse_utilized++; + efuse_word[i][offset] |= + (((u16)*rtemp8 << 8) & 0xff00); + + if (efuse_addr >= efuse_len) + break; + } + + wren >>= 1; + } + } + + RTPRINT(rtlpriv, FEEPROM, EFUSE_READ_ALL, + "Addr=%d\n", efuse_addr); + read_efuse_byte(hw, efuse_addr, rtemp8); + if (*rtemp8 != 0xFF && (efuse_addr < efuse_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_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); + kfree(efuse_tbl); +} + +bool efuse_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 wordchanged, result = true; + + for (section_idx = 0; section_idx < 16; section_idx++) { + Base = section_idx * 8; + wordchanged = 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++; + wordchanged = true; + } + } + + if (wordchanged) + hdr_num++; + } + + totalbytes = hdr_num + words_need * 2; + efuse_used = rtlefuse->efuse_usedbytes; + + if ((totalbytes + efuse_used) >= + (EFUSE_MAX_SIZE - EFUSE_OOB_PROTECT_BYTES)) + result = false; + + RT_TRACE(rtlpriv, COMP_EFUSE, DBG_LOUD, + "efuse_shadow_update_chk(): totalbytes(%#x), hdr_num(%#x), words_need(%#x), efuse_used(%d)\n", + totalbytes, hdr_num, words_need, efuse_used); + + return result; +} + +void efuse_shadow_read(struct ieee80211_hw *hw, u8 type, + u16 offset, u32 *value) +{ + if (type == 1) + efuse_shadow_read_1byte(hw, offset, (u8 *) value); + else if (type == 2) + efuse_shadow_read_2byte(hw, offset, (u16 *) value); + else if (type == 4) + efuse_shadow_read_4byte(hw, offset, (u32 *) value); + +} + +void efuse_shadow_write(struct ieee80211_hw *hw, u8 type, u16 offset, + u32 value) +{ + if (type == 1) + efuse_shadow_write_1byte(hw, offset, (u8) value); + else if (type == 2) + efuse_shadow_write_2byte(hw, offset, (u16) value); + else if (type == 4) + efuse_shadow_write_4byte(hw, offset, value); + +} + +bool efuse_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(rtlpriv, COMP_EFUSE, DBG_LOUD, "--->\n"); + + if (!efuse_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(rtlpriv, 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", tmpdata, 8); + + if (!efuse_pg_packet_write(hw, (u8) offset, word_en, + tmpdata)) { + RT_TRACE(rtlpriv, 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(rtlpriv, COMP_EFUSE, DBG_LOUD, "<---\n"); + return true; +} + +void rtl_efuse_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(rtl_efuse_shadow_map_update); + +void efuse_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 efuse_re_pg_section(struct ieee80211_hw *hw, u8 section_idx) +{ +} + +static void efuse_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 efuse_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 efuse_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 efuse_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 efuse_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 efuse_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); + +} + +static int efuse_one_byte_read(struct ieee80211_hw *hw, u16 addr, u8 *data) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 tmpidx = 0; + int result; + + 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]); + result = true; + } else { + *data = 0xff; + result = false; + } + return result; +} + +static int efuse_one_byte_write(struct ieee80211_hw *hw, u16 addr, u8 data) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 tmpidx = 0; + + RT_TRACE(rtlpriv, 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) + return true; + + return false; +} + +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); + read_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 dataempty = 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 (efuse_one_byte_read(hw, *efuse_addr + 1 + tmpidx, + &efuse_data)) { + tmpdata[tmpidx] = efuse_data; + if (efuse_data != 0xff) + dataempty = true; + } + } + + if (dataempty) { + *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 continual = true; + u8 efuse_data, word_cnts = 0; + u16 efuse_addr = 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 (continual && (efuse_addr < EFUSE_MAX_SIZE)) { + if (readstate & PG_STATE_HEADER) { + if (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 + continual = false; + } else if (readstate & PG_STATE_DATA) { + efuse_word_enable_data_read(0, 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 *continual, + u8 *write_state, struct pgpkt_struct *target_pkt, + int *repeat_times, int *result, u8 word_en) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct pgpkt_struct tmp_pkt; + bool dataempty = 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++) { + u16 address = *efuse_addr + 1 + tmpindex; + if (efuse_one_byte_read(hw, address, + &efuse_data) && (efuse_data != 0xFF)) + dataempty = false; + } + + if (!dataempty) { + *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 { + *continual = false; + } + *write_state = PG_STATE_HEADER; + *repeat_times += 1; + if (*repeat_times > EFUSE_REPEAT_THRESHOLD_) { + *continual = false; + *result = 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 *continual, u8 *write_state, + struct pgpkt_struct target_pkt, + int *repeat_times, int *result) +{ + 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); + 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_) { + *continual = false; + *result = 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_) { + *continual = false; + *result = 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 continual = true, result = 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 - EFUSE_OOB_PROTECT_BYTES)) { + 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 (continual && (efuse_addr < + (EFUSE_MAX_SIZE - EFUSE_OOB_PROTECT_BYTES))) { + + if (write_state == PG_STATE_HEADER) { + badworden = 0x0F; + RTPRINT(rtlpriv, FEEPROM, EFUSE_PG, + "efuse PG_STATE_HEADER\n"); + + if (efuse_one_byte_read(hw, efuse_addr, &efuse_data) && + (efuse_data != 0xFF)) + efuse_write_data_case1(hw, &efuse_addr, + efuse_data, offset, + &continual, + &write_state, &target_pkt, + &repeat_times, &result, + word_en); + else + efuse_write_data_case2(hw, &efuse_addr, + &continual, + &write_state, + target_pkt, + &repeat_times, + &result); + + } else if (write_state == PG_STATE_DATA) { + RTPRINT(rtlpriv, FEEPROM, EFUSE_PG, + "efuse PG_STATE_DATA\n"); + badworden = + efuse_word_enable_data_write(hw, efuse_addr + 1, + target_pkt.word_en, + target_pkt.data); + + if ((badworden & 0x0F) == 0x0F) { + continual = false; + } else { + 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_) { + continual = false; + result = false; + } + RTPRINT(rtlpriv, FEEPROM, EFUSE_PG, + "efuse PG_STATE_HEADER-3\n"); + } + } + } + + if (efuse_addr >= (EFUSE_MAX_SIZE - EFUSE_OOB_PROTECT_BYTES)) { + RT_TRACE(rtlpriv, 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(rtlpriv, 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]); + + efuse_one_byte_read(hw, tmpaddr, &tmpdata[0]); + 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]); + + efuse_one_byte_read(hw, tmpaddr, &tmpdata[2]); + 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]); + + efuse_one_byte_read(hw, tmpaddr, &tmpdata[4]); + 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]); + + efuse_one_byte_read(hw, tmpaddr, &tmpdata[6]); + 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 write, 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)) { + 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 (write) { + tempval = rtl_read_byte(rtlpriv, + rtlpriv->cfg->maps[EFUSE_TEST] + + 3); + + 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 (write) { + 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 continual = true; + u16 efuse_addr = 0; + u8 hworden; + u8 efuse_data, word_cnts; + + while (continual && efuse_one_byte_read(hw, efuse_addr, &efuse_data) + && (efuse_addr < EFUSE_MAX_SIZE)) { + if (efuse_data != 0xFF) { + hworden = efuse_data & 0x0F; + word_cnts = efuse_calculate_word_cnts(hworden); + efuse_addr = efuse_addr + (word_cnts * 2) + 1; + } else { + continual = 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/net/wireless/rtlwifi/efuse.h b/drivers/net/wireless/rtlwifi/efuse.h new file mode 100644 index 00000000..2bdea9a8 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/efuse.h @@ -0,0 +1,124 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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 __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_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]; +}; + +extern void read_efuse_byte(struct ieee80211_hw *hw, u16 _offset, u8 *pbuf); +extern void efuse_initialize(struct ieee80211_hw *hw); +extern u8 efuse_read_1byte(struct ieee80211_hw *hw, u16 address); +extern void efuse_write_1byte(struct ieee80211_hw *hw, u16 address, u8 value); +extern void read_efuse(struct ieee80211_hw *hw, u16 _offset, + u16 _size_byte, u8 *pbuf); +extern void efuse_shadow_read(struct ieee80211_hw *hw, u8 type, + u16 offset, u32 *value); +extern void efuse_shadow_write(struct ieee80211_hw *hw, u8 type, + u16 offset, u32 value); +extern bool efuse_shadow_update(struct ieee80211_hw *hw); +extern bool efuse_shadow_update_chk(struct ieee80211_hw *hw); +extern void rtl_efuse_shadow_map_update(struct ieee80211_hw *hw); +extern void efuse_force_write_vendor_Id(struct ieee80211_hw *hw); +extern void efuse_re_pg_section(struct ieee80211_hw *hw, u8 section_idx); + +#endif diff --git a/drivers/net/wireless/rtlwifi/pci.c b/drivers/net/wireless/rtlwifi/pci.c new file mode 100644 index 00000000..67f9430e --- /dev/null +++ b/drivers/net/wireless/rtlwifi/pci.c @@ -0,0 +1,2025 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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> + * + *****************************************************************************/ + +#include "wifi.h" +#include "core.h" +#include "pci.h" +#include "base.h" +#include "ps.h" +#include "efuse.h" +#include <linux/export.h> + +static const u16 pcibridge_vendors[PCI_BRIDGE_VENDOR_MAX] = { + PCI_VENDOR_ID_INTEL, + PCI_VENDOR_ID_ATI, + PCI_VENDOR_ID_AMD, + PCI_VENDOR_ID_SI +}; + +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)) + 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->support_aspm = false; + + /*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 support_aspm = false; + ppsc->support_aspm = support_aspm; + break; + } + case 1:{ + /*Support ASPM. */ + bool support_aspm = true; + bool support_backdoor = true; + ppsc->support_aspm = support_aspm; + + /*if (priv->oem_id == RT_CID_TOSHIBA && + !priv->ndis_adapter.amd_l1_patch) + support_backdoor = false; */ + + ppsc->support_backdoor = support_backdoor; + + break; + } + case 2: + /*ASPM value set by chipset. */ + if (pcibridge_vendor == PCI_BRIDGE_VENDOR_INTEL) { + bool support_aspm = true; + ppsc->support_aspm = support_aspm; + } + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "switch case not processed\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->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)); + + if (rtlhal->hw_type != HARDWARE_TYPE_RTL8192SE) + value |= 0x40; + + pci_write_config_byte(rtlpci->pdev, 0x80, value); + + return false; +} + +/*When we set 0x01 to enable clk request. Set 0x0 to disable clk req.*/ +static void _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)); + + pci_write_config_byte(rtlpci->pdev, 0x81, value); + + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192SE) + udelay(100); +} + +/*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; + 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; + u8 tmp_u1b = 0; + + if (!ppsc->support_aspm) + return; + + if (pcibridge_vendor == PCI_BRIDGE_VENDOR_UNKNOWN) { + RT_TRACE(rtlpriv, 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); + } + + /*for promising device will in L0 state after an I/O. */ + 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 */ + pci_write_config_byte(rtlpci->pdev, (num4bytes << 2), + 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_busnum = pcipriv->ndis_adapter.pcibridge_busnum; + u8 pcibridge_devnum = pcipriv->ndis_adapter.pcibridge_devnum; + u8 pcibridge_funcnum = pcipriv->ndis_adapter.pcibridge_funcnum; + u8 pcibridge_vendor = pcipriv->ndis_adapter.pcibridge_vendor; + u8 num4bytes = pcipriv->ndis_adapter.num4bytes; + u16 aspmlevel; + u8 u_pcibridge_aspmsetting; + u8 u_device_aspmsetting; + + if (!ppsc->support_aspm) + return; + + if (pcibridge_vendor == PCI_BRIDGE_VENDOR_UNKNOWN) { + RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE, + "PCI(Bridge) UNKNOWN\n"); + return; + } + + /*4 Enable Pci Bridge ASPM */ + + 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); + + pci_write_config_byte(rtlpci->pdev, (num4bytes << 2), + u_pcibridge_aspmsetting); + + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "PlatformEnableASPM():PciBridge busnumber[%x], DevNumbe[%x], funcnumber[%x], Write reg[%x] = %x\n", + pcibridge_busnum, pcibridge_devnum, pcibridge_funcnum, + (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 *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + + bool status = false; + u8 offset_e0; + unsigned offset_e4; + + pci_write_config_byte(rtlpci->pdev, 0xe0, 0xa0); + + pci_read_config_byte(rtlpci->pdev, 0xe0, &offset_e0); + + if (offset_e0 == 0xA0) { + pci_read_config_dword(rtlpci->pdev, 0xe4, &offset_e4); + if (offset_e4 & BIT(23)) + status = true; + } + + return status; +} + +static void rtl_pci_get_linkcontrol_field(struct ieee80211_hw *hw) +{ + struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(pcipriv); + u8 capabilityoffset = pcipriv->ndis_adapter.pcibridge_pciehdr_offset; + u8 linkctrl_reg; + u8 num4bbytes; + + num4bbytes = (capabilityoffset + 0x10) / 4; + + /*Read Link Control Register */ + pci_read_config_byte(rtlpci->pdev, (num4bbytes << 2), &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_pcie_cap(pdev); + pci_read_config_byte(pdev, pos + PCI_EXP_LNKCTL, &linkctrl_reg); + pcipriv->ndis_adapter.linkctrl_reg = linkctrl_reg; + + RT_TRACE(rtlpriv, 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 void _rtl_pci_io_handler_release(struct ieee80211_hw *hw) +{ +} + +static bool _rtl_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); + u8 additionlen = FCS_LEN; + struct sk_buff *next_skb; + + /* 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 >= 5) + 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 sk_buff *skb = NULL; + struct ieee80211_tx_info *info = NULL; + int tid; + + if (!rtlpriv->rtlhal.earlymode_enable) + return; + + /* we juse use em for BE/BK/VI/VO */ + for (tid = 7; tid >= 0; tid--) { + u8 hw_queue = ac_to_hwq[rtl_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) > 5)) { + 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_update_earlymode_info(hw, skb, + &tcb_desc, tid); + + rtlpriv->intf_ops->adapter_tx(hw, 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 rtl_tx_desc *entry = &ring->desc[ring->idx]; + struct sk_buff *skb; + struct ieee80211_tx_info *info; + __le16 fc; + u8 tid; + + u8 own = (u8) rtlpriv->cfg->ops->get_desc((u8 *) entry, true, + HW_DESC_OWN); + + /* + *beacon packet will only use the first + *descriptor defautly,and the own may not + *be cleared by the hardware + */ + if (own) + 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.earlymode_enable) + skb_pull(skb, EM_HDR_LEN); + + RT_TRACE(rtlpriv, (COMP_INTR | COMP_SEND), DBG_TRACE, + "new ring->idx:%d, free: skb_queue_len:%d, free: seq:%x\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 kown we are sleeped, 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_delay = true; + rtlpriv->psc.state_inap = true; + } else { + rtlpriv->psc.state_inap = false; + } + } + + /* 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(rtlpriv, 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)) { + schedule_work(&rtlpriv->works.lps_leave_work); + } +} + +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; + struct sk_buff *uskb = NULL; + u8 *pdata; + + + 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; + } + + rtl_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++; + } + + /* for sw lps */ + rtl_swlps_beacon(hw, (void *)skb->data, skb->len); + rtl_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))) + return; + + if (unlikely(!rtl_action_proc(hw, skb, false))) + return; + + uskb = dev_alloc_skb(skb->len + 128); + if (!uskb) + return; /* exit if allocation failed */ + memcpy(IEEE80211_SKB_RXCB(uskb), &rx_status, sizeof(rx_status)); + pdata = (u8 *)skb_put(uskb, skb->len); + memcpy(pdata, skb->data, skb->len); + + ieee80211_rx_irqsafe(hw, uskb); +} + +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)); + int rx_queue_idx = RTL_PCI_RX_MPDU_QUEUE; + + struct ieee80211_rx_status rx_status = { 0 }; + unsigned int count = rtlpci->rxringcount; + u8 own; + u8 tmp_one; + u32 bufferaddress; + + struct rtl_stats stats = { + .signal = 0, + .noise = -98, + .rate = 0, + }; + int index = rtlpci->rx_ring[rx_queue_idx].idx; + + /*RX NORMAL PKT */ + while (count--) { + /*rx descriptor */ + struct rtl_rx_desc *pdesc = &rtlpci->rx_ring[rx_queue_idx].desc[ + index]; + /*rx pkt */ + struct sk_buff *skb = rtlpci->rx_ring[rx_queue_idx].rx_buf[ + index]; + struct sk_buff *new_skb = NULL; + + own = (u8) rtlpriv->cfg->ops->get_desc((u8 *) pdesc, + false, HW_DESC_OWN); + + /*wait data to be filled by hardware */ + if (own) + break; + + rtlpriv->cfg->ops->query_rx_desc(hw, &stats, + &rx_status, + (u8 *) pdesc, skb); + + if (stats.crc || stats.hwerror) + goto done; + + new_skb = dev_alloc_skb(rtlpci->rxbuffersize); + if (unlikely(!new_skb)) { + RT_TRACE(rtlpriv, (COMP_INTR | COMP_RECV), DBG_DMESG, + "can't alloc skb for rx\n"); + goto done; + } + + pci_unmap_single(rtlpci->pdev, + *((dma_addr_t *) skb->cb), + rtlpci->rxbuffersize, + PCI_DMA_FROMDEVICE); + + skb_put(skb, rtlpriv->cfg->ops->get_desc((u8 *) pdesc, false, + HW_DESC_RXPKT_LEN)); + skb_reserve(skb, stats.rx_drvinfo_size + stats.rx_bufshift); + + /* + * 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); + */ + + _rtl_receive_one(hw, skb, rx_status); + + if (((rtlpriv->link_info.num_rx_inperiod + + rtlpriv->link_info.num_tx_inperiod) > 8) || + (rtlpriv->link_info.num_rx_inperiod > 2)) { + schedule_work(&rtlpriv->works.lps_leave_work); + } + + dev_kfree_skb_any(skb); + skb = new_skb; + + rtlpci->rx_ring[rx_queue_idx].rx_buf[index] = skb; + *((dma_addr_t *) skb->cb) = + pci_map_single(rtlpci->pdev, skb_tail_pointer(skb), + rtlpci->rxbuffersize, + PCI_DMA_FROMDEVICE); + +done: + bufferaddress = (*((dma_addr_t *)skb->cb)); + tmp_one = 1; + rtlpriv->cfg->ops->set_desc((u8 *) pdesc, false, + HW_DESC_RXBUFF_ADDR, + (u8 *)&bufferaddress); + rtlpriv->cfg->ops->set_desc((u8 *)pdesc, false, + HW_DESC_RXPKT_LEN, + (u8 *)&rtlpci->rxbuffersize); + + if (index == rtlpci->rxringcount - 1) + rtlpriv->cfg->ops->set_desc((u8 *)pdesc, false, + HW_DESC_RXERO, + (u8 *)&tmp_one); + + rtlpriv->cfg->ops->set_desc((u8 *)pdesc, false, HW_DESC_RXOWN, + (u8 *)&tmp_one); + + index = (index + 1) % rtlpci->rxringcount; + } + + rtlpci->rx_ring[rx_queue_idx].idx = index; +} + +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_hal *rtlhal = rtl_hal(rtl_priv(hw)); + unsigned long flags; + u32 inta = 0; + u32 intb = 0; + irqreturn_t ret = IRQ_HANDLED; + + spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags); + + /*read ISR: 4/8bytes */ + rtlpriv->cfg->ops->interrupt_recognized(hw, &inta, &intb); + + /*Shared IRQ or HW disappared */ + if (!inta || inta == 0xffff) { + ret = IRQ_NONE; + goto done; + } + + /*<1> beacon related */ + if (inta & rtlpriv->cfg->maps[RTL_IMR_TBDOK]) { + RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE, + "beacon ok interrupt!\n"); + } + + if (unlikely(inta & rtlpriv->cfg->maps[RTL_IMR_TBDER])) { + RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE, + "beacon err interrupt!\n"); + } + + if (inta & rtlpriv->cfg->maps[RTL_IMR_BDOK]) { + RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE, "beacon interrupt!\n"); + } + + if (inta & rtlpriv->cfg->maps[RTL_IMR_BcnInt]) { + RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE, + "prepare beacon for interrupt!\n"); + tasklet_schedule(&rtlpriv->works.irq_prepare_bcn_tasklet); + } + + /*<3> Tx related */ + if (unlikely(inta & rtlpriv->cfg->maps[RTL_IMR_TXFOVW])) + RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, "IMR_TXFOVW!\n"); + + if (inta & rtlpriv->cfg->maps[RTL_IMR_MGNTDOK]) { + RT_TRACE(rtlpriv, 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(rtlpriv, 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(rtlpriv, 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(rtlpriv, 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(rtlpriv, 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(rtlpriv, 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(rtlpriv, COMP_INTR, DBG_TRACE, + "CMD TX OK interrupt!\n"); + _rtl_pci_tx_isr(hw, TXCMD_QUEUE); + } + } + + /*<2> Rx related */ + if (inta & rtlpriv->cfg->maps[RTL_IMR_ROK]) { + RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE, "Rx ok interrupt!\n"); + _rtl_pci_rx_interrupt(hw); + } + + if (unlikely(inta & rtlpriv->cfg->maps[RTL_IMR_RDU])) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, + "rx descriptor unavailable!\n"); + _rtl_pci_rx_interrupt(hw); + } + + if (unlikely(inta & rtlpriv->cfg->maps[RTL_IMR_RXFOVW])) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, "rx overflow !\n"); + _rtl_pci_rx_interrupt(hw); + } + + if (rtlpriv->rtlhal.earlymode_enable) + tasklet_schedule(&rtlpriv->works.irq_tasklet); + +done: + spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags); + return ret; +} + +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; + 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) { + struct rtl_tx_desc *entry = &ring->desc[ring->idx]; + pci_unmap_single(rtlpci->pdev, rtlpriv->cfg->ops->get_desc( + (u8 *) entry, true, HW_DESC_TXBUFF_ADDR), + pskb->len, PCI_DMA_TODEVICE); + 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]; + rtlpriv->cfg->ops->fill_tx_desc(hw, hdr, (u8 *) pdesc, + info, pskb, BEACON_QUEUE, &tcb_desc); + + __skb_queue_tail(&ring->queue, pskb); + + rtlpriv->cfg->ops->set_desc((u8 *) pdesc, true, HW_DESC_OWN, + (u8 *)&temp_one); + + return; +} + +static void rtl_lps_leave_work_callback(struct work_struct *work) +{ + struct rtl_works *rtlworks = + container_of(work, struct rtl_works, lps_leave_work); + struct ieee80211_hw *hw = rtlworks->hw; + + rtl_lps_leave(hw); +} + +static void _rtl_pci_init_trx_var(struct ieee80211_hw *hw) +{ + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + u8 i; + + for (i = 0; i < RTL_PCI_MAX_TX_QUEUE_COUNT; i++) + rtlpci->txringcount[i] = RT_TXDESC_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. + */ + 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)); + + rtlpci->up_first_time = true; + rtlpci->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); + INIT_WORK(&rtlpriv->works.lps_leave_work, rtl_lps_leave_work_callback); +} + +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_desc *ring; + dma_addr_t dma; + u32 nextdescaddress; + int i; + + ring = pci_alloc_consistent(rtlpci->pdev, + sizeof(*ring) * entries, &dma); + + if (!ring || (unsigned long)ring & 0xFF) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "Cannot allocate TX ring (prio = %d)\n", prio); + return -ENOMEM; + } + + memset(ring, 0, sizeof(*ring) * entries); + rtlpci->tx_ring[prio].desc = ring; + rtlpci->tx_ring[prio].dma = dma; + rtlpci->tx_ring[prio].idx = 0; + rtlpci->tx_ring[prio].entries = entries; + skb_queue_head_init(&rtlpci->tx_ring[prio].queue); + + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "queue:%d, ring_addr:%p\n", + prio, ring); + + for (i = 0; i < entries; i++) { + nextdescaddress = (u32) dma + + ((i + 1) % entries) * + sizeof(*ring); + + rtlpriv->cfg->ops->set_desc((u8 *)&(ring[i]), + true, HW_DESC_TX_NEXTDESC_ADDR, + (u8 *)&nextdescaddress); + } + + return 0; +} + +static int _rtl_pci_init_rx_ring(struct ieee80211_hw *hw) +{ + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_rx_desc *entry = NULL; + int i, rx_queue_idx; + u8 tmp_one = 1; + + /* + *rx_queue_idx 0:RX_MPDU_QUEUE + *rx_queue_idx 1:RX_CMD_QUEUE + */ + for (rx_queue_idx = 0; rx_queue_idx < RTL_PCI_MAX_RX_QUEUE; + rx_queue_idx++) { + rtlpci->rx_ring[rx_queue_idx].desc = + pci_alloc_consistent(rtlpci->pdev, + sizeof(*rtlpci->rx_ring[rx_queue_idx]. + desc) * rtlpci->rxringcount, + &rtlpci->rx_ring[rx_queue_idx].dma); + + if (!rtlpci->rx_ring[rx_queue_idx].desc || + (unsigned long)rtlpci->rx_ring[rx_queue_idx].desc & 0xFF) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "Cannot allocate RX ring\n"); + return -ENOMEM; + } + + memset(rtlpci->rx_ring[rx_queue_idx].desc, 0, + sizeof(*rtlpci->rx_ring[rx_queue_idx].desc) * + rtlpci->rxringcount); + + rtlpci->rx_ring[rx_queue_idx].idx = 0; + + /* If amsdu_8k is disabled, set buffersize to 4096. This + * change will reduce memory fragmentation. + */ + if (rtlpci->rxbuffersize > 4096 && + rtlpriv->rtlhal.disable_amsdu_8k) + rtlpci->rxbuffersize = 4096; + + for (i = 0; i < rtlpci->rxringcount; i++) { + struct sk_buff *skb = + dev_alloc_skb(rtlpci->rxbuffersize); + u32 bufferaddress; + if (!skb) + return 0; + entry = &rtlpci->rx_ring[rx_queue_idx].desc[i]; + + /*skb->dev = dev; */ + + rtlpci->rx_ring[rx_queue_idx].rx_buf[i] = 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)); + rtlpriv->cfg->ops->set_desc((u8 *)entry, false, + HW_DESC_RXBUFF_ADDR, + (u8 *)&bufferaddress); + rtlpriv->cfg->ops->set_desc((u8 *)entry, false, + HW_DESC_RXPKT_LEN, + (u8 *)&rtlpci-> + rxbuffersize); + rtlpriv->cfg->ops->set_desc((u8 *) entry, false, + HW_DESC_RXOWN, + (u8 *)&tmp_one); + } + + rtlpriv->cfg->ops->set_desc((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]; + + while (skb_queue_len(&ring->queue)) { + struct rtl_tx_desc *entry = &ring->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; + } + + if (ring->desc) { + pci_free_consistent(rtlpci->pdev, + sizeof(*ring->desc) * ring->entries, + ring->desc, ring->dma); + ring->desc = NULL; + } +} + +static void _rtl_pci_free_rx_ring(struct rtl_pci *rtlpci) +{ + int i, rx_queue_idx; + + /*rx_queue_idx 0:RX_MPDU_QUEUE */ + /*rx_queue_idx 1:RX_CMD_QUEUE */ + for (rx_queue_idx = 0; rx_queue_idx < RTL_PCI_MAX_RX_QUEUE; + rx_queue_idx++) { + for (i = 0; i < rtlpci->rxringcount; i++) { + struct sk_buff *skb = + rtlpci->rx_ring[rx_queue_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); + } + + if (rtlpci->rx_ring[rx_queue_idx].desc) { + pci_free_consistent(rtlpci->pdev, + sizeof(*rtlpci->rx_ring[rx_queue_idx]. + desc) * rtlpci->rxringcount, + rtlpci->rx_ring[rx_queue_idx].desc, + rtlpci->rx_ring[rx_queue_idx].dma); + rtlpci->rx_ring[rx_queue_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; + + ret = _rtl_pci_init_rx_ring(hw); + 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: + _rtl_pci_free_rx_ring(rtlpci); + + for (i = 0; i < RTL_PCI_MAX_TX_QUEUE_COUNT; i++) + if (rtlpci->tx_ring[i].desc) + _rtl_pci_free_tx_ring(hw, i); + + return 1; +} + +static int _rtl_pci_deinit_trx_ring(struct ieee80211_hw *hw) +{ + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + u32 i; + + /*free rx rings */ + _rtl_pci_free_rx_ring(rtlpci); + + /*free tx rings */ + for (i = 0; i < RTL_PCI_MAX_TX_QUEUE_COUNT; i++) + _rtl_pci_free_tx_ring(hw, i); + + return 0; +} + +int rtl_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, rx_queue_idx; + unsigned long flags; + u8 tmp_one = 1; + + /*rx_queue_idx 0:RX_MPDU_QUEUE */ + /*rx_queue_idx 1:RX_CMD_QUEUE */ + for (rx_queue_idx = 0; rx_queue_idx < RTL_PCI_MAX_RX_QUEUE; + rx_queue_idx++) { + /* + *force the rx_ring[RX_MPDU_QUEUE/ + *RX_CMD_QUEUE].idx to the first one + */ + if (rtlpci->rx_ring[rx_queue_idx].desc) { + struct rtl_rx_desc *entry = NULL; + + for (i = 0; i < rtlpci->rxringcount; i++) { + entry = &rtlpci->rx_ring[rx_queue_idx].desc[i]; + rtlpriv->cfg->ops->set_desc((u8 *) entry, + false, + HW_DESC_RXOWN, + (u8 *)&tmp_one); + } + rtlpci->rx_ring[rx_queue_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) { + struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[i]; + + while (skb_queue_len(&ring->queue)) { + struct rtl_tx_desc *entry = + &ring->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; + } + 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 sk_buff *skb) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_sta *sta = info->control.sta; + struct rtl_sta_info *sta_entry = NULL; + u8 tid = rtl_get_tid(skb); + + if (!sta) + return false; + sta_entry = (struct rtl_sta_info *)sta->drv_priv; + + if (!rtlpriv->rtlhal.earlymode_enable) + 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 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 ieee80211_sta *sta = info->control.sta; + struct rtl8192_tx_ring *ring; + struct rtl_tx_desc *pdesc; + u8 idx; + 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; + u8 own; + u8 temp_one = 1; + + if (ieee80211_is_auth(fc)) { + RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG, "MAC80211_LINKING\n"); + rtl_ips_nic_on(hw); + } + + 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); + } + + rtl_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) + idx = (ring->idx + skb_queue_len(&ring->queue)) % + ring->entries; + else + idx = 0; + + pdesc = &ring->desc[idx]; + own = (u8) rtlpriv->cfg->ops->get_desc((u8 *) pdesc, + true, HW_DESC_OWN); + + if ((own == 1) && (hw_queue != BEACON_QUEUE)) { + RT_TRACE(rtlpriv, 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, + info, skb, hw_queue, ptcb_desc); + + __skb_queue_tail(&ring->queue, skb); + + rtlpriv->cfg->ops->set_desc((u8 *)pdesc, true, + HW_DESC_OWN, (u8 *)&temp_one); + + + if ((ring->entries - skb_queue_len(&ring->queue)) < 2 && + hw_queue != BEACON_QUEUE) { + + RT_TRACE(rtlpriv, 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); + + rtlpriv->cfg->ops->tx_polling(hw, hw_queue); + + return 0; +} + +static void rtl_pci_flush(struct ieee80211_hw *hw, bool drop) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u16 i = 0; + int queue_id; + struct rtl8192_tx_ring *ring; + + for (queue_id = RTL_PCI_MAX_TX_QUEUE_COUNT - 1; queue_id >= 0;) { + u32 queue_len; + 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(20); + 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); + cancel_work_sync(&rtlpriv->works.lps_leave_work); + + 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(rtlpriv, COMP_ERR, DBG_EMERG, + "tx ring initialization failed\n"); + return err; + } + + return 0; +} + +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_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + + int err; + + rtl_pci_reset_trx_ring(hw); + + rtlpci->driver_is_goingto_unload = false; + err = rtlpriv->cfg->ops->hw_init(hw); + if (err) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "Failed to config hardware!\n"); + return err; + } + + rtlpriv->cfg->ops->enable_interrupt(hw); + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "enable_interrupt OK\n"); + + rtl_init_rx_config(hw); + + /*should be after adapter start and interrupt enable. */ + set_hal_start(rtlhal); + + RT_CLEAR_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC); + + rtlpci->up_first_time = false; + + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "OK\n"); + return 0; +} + +static void rtl_pci_stop(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + unsigned long flags; + u8 RFInProgressTimeOut = 0; + + /* + *should be before disable interrupt&adapter + *and will do it immediately. + */ + set_hal_stop(rtlhal); + + rtlpriv->cfg->ops->disable_interrupt(hw); + cancel_work_sync(&rtlpriv->works.lps_leave_work); + + spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flags); + while (ppsc->rfchange_inprogress) { + spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flags); + if (RFInProgressTimeOut > 100) { + spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flags); + break; + } + mdelay(1); + RFInProgressTimeOut++; + spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flags); + } + ppsc->rfchange_inprogress = true; + spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flags); + + rtlpci->driver_is_goingto_unload = true; + rtlpriv->cfg->ops->hw_disable(hw); + /* some things are not needed if firmware not available */ + if (!rtlpriv->max_fw_size) + return; + rtlpriv->cfg->ops->led_control(hw, LED_CTL_POWER_OFF); + + spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flags); + ppsc->rfchange_inprogress = false; + spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flags); + + 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; + + pcipriv->ndis_adapter.pcibridge_vendor = PCI_BRIDGE_VENDOR_UNKNOWN; + venderid = pdev->vendor; + deviceid = pdev->device; + pci_read_config_byte(pdev, 0x8, &revisionid); + pci_read_config_word(pdev, 0x3C, &irqline); + + /* PCI ID 0x10ec:0x8192 occurs for both RTL8192E, which uses + * r8192e_pci, and RTL8192SE, which uses this driver. If the + * revision ID is RTL_PCI_REVISION_ID_8192PCIE (0x01), then + * the correct driver is r8192e_pci, thus this routine should + * return false. + */ + if (deviceid == RTL_PCI_8192SE_DID && + revisionid == RTL_PCI_REVISION_ID_8192PCIE) + return false; + + 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(rtlpriv, COMP_INIT, DBG_DMESG, + "8192 PCI-E is found - vid/did=%x/%x\n", + venderid, deviceid); + rtlhal->hw_type = HARDWARE_TYPE_RTL8192E; + break; + case RTL_PCI_REVISION_ID_8192SE: + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "8192SE is found - vid/did=%x/%x\n", + venderid, deviceid); + rtlhal->hw_type = HARDWARE_TYPE_RTL8192SE; + break; + default: + RT_TRACE(rtlpriv, 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_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(rtlpriv, 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(rtlpriv, COMP_INIT, DBG_DMESG, + "8192D PCI-E is found - vid/did=%x/%x\n", + venderid, deviceid); + } else { + RT_TRACE(rtlpriv, 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(rtlpriv, COMP_INIT, DBG_LOUD, + "Find 92DE MAC0\n"); + rtlhal->interfaceindex = 0; + } else if (revisionid == 1) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "Find 92DE MAC1\n"); + rtlhal->interfaceindex = 1; + } + } else { + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "Unknown device - VendorID/DeviceID=%x/%x, Revision=%x\n", + venderid, deviceid, revisionid); + rtlhal->interfaceindex = 0; + } + } + /*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); + + if (bridge_pdev) { + /*find bridge info if available */ + 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(rtlpriv, 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.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(rtlpriv, 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(rtlpriv, 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); + + return true; +} + +int __devinit 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"); + err = -ENOMEM; + goto fail1; + } + } + + pci_set_master(pdev); + + hw = ieee80211_alloc_hw(sizeof(struct rtl_pci_priv) + + sizeof(struct rtl_priv), &rtl_ops); + if (!hw) { + RT_ASSERT(false, + "%s : ieee80211 alloc failed\n", pci_name(pdev)); + err = -ENOMEM; + goto fail1; + } + + SET_IEEE80211_DEV(hw, &pdev->dev); + pci_set_drvdata(pdev, hw); + + rtlpriv = hw->priv; + pcipriv = (void *)rtlpriv->priv; + pcipriv->dev.pdev = pdev; + init_completion(&rtlpriv->firmware_loading_complete); + + /* init cfg & intf_ops */ + rtlpriv->rtlhal.interface = INTF_PCI; + rtlpriv->cfg = (struct rtl_hal_cfg *)(id->driver_data); + rtlpriv->intf_ops = &rtl_pci_ops; + + /* + *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 + */ + rtl_dbgp_flag_init(hw); + + /* MEM map */ + err = pci_request_regions(pdev, KBUILD_MODNAME); + if (err) { + RT_ASSERT(false, "Can't obtain PCI resources\n"); + goto fail1; + } + + 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"); + err = -ENOMEM; + goto fail2; + } + + RT_TRACE(rtlpriv, 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); + + /* find adapter */ + if (!_rtl_pci_find_adapter(pdev, hw)) { + err = -ENODEV; + 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); + + /*aspm */ + rtl_pci_init_aspm(hw); + + /* Init mac80211 sw */ + err = rtl_init_core(hw); + if (err) { + RT_TRACE(rtlpriv, 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(rtlpriv, COMP_ERR, DBG_EMERG, "Failed to init PCI\n"); + goto fail3; + } + + if (rtlpriv->cfg->ops->init_sw_vars(hw)) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Can't init_sw_vars\n"); + err = -ENODEV; + goto fail3; + } + + rtlpriv->cfg->ops->init_sw_leds(hw); + + err = sysfs_create_group(&pdev->dev.kobj, &rtl_attribute_group); + if (err) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "failed to create sysfs device attributes\n"); + goto fail3; + } + + rtlpci = rtl_pcidev(pcipriv); + err = request_irq(rtlpci->pdev->irq, &_rtl_pci_interrupt, + IRQF_SHARED, KBUILD_MODNAME, hw); + if (err) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "%s: failed to register IRQ handler\n", + wiphy_name(hw->wiphy)); + goto fail3; + } + rtlpci->irq_alloc = 1; + + return 0; + +fail3: + rtl_deinit_core(hw); + _rtl_pci_io_handler_release(hw); + + if (rtlpriv->io.pci_mem_start != 0) + pci_iounmap(pdev, (void __iomem *)rtlpriv->io.pci_mem_start); + +fail2: + pci_release_regions(pdev); + complete(&rtlpriv->firmware_loading_complete); + +fail1: + if (hw) + ieee80211_free_hw(hw); + pci_set_drvdata(pdev, NULL); + pci_disable_device(pdev); + + return err; + +} +EXPORT_SYMBOL(rtl_pci_probe); + +void 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); + + /* just in case driver is removed before firmware callback */ + wait_for_completion(&rtlpriv->firmware_loading_complete); + clear_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status); + + sysfs_remove_group(&pdev->dev.kobj, &rtl_attribute_group); + + /*ieee80211_unregister_hw will call ops_stop */ + if (rtlmac->mac80211_registered == 1) { + ieee80211_unregister_hw(hw); + rtlmac->mac80211_registered = 0; + } else { + rtl_deinit_deferred_work(hw); + rtlpriv->intf_ops->adapter_stop(hw); + } + rtlpriv->cfg->ops->disable_interrupt(hw); + + /*deinit rfkill */ + rtl_deinit_rfkill(hw); + + rtl_pci_deinit(hw); + rtl_deinit_core(hw); + _rtl_pci_io_handler_release(hw); + rtlpriv->cfg->ops->deinit_sw_vars(hw); + + if (rtlpci->irq_alloc) { + free_irq(rtlpci->pdev->irq, hw); + rtlpci->irq_alloc = 0; + } + + 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(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 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); + rtl_deinit_rfkill(hw); + + return 0; +} +EXPORT_SYMBOL(rtl_pci_suspend); + +int 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); + rtl_init_rfkill(hw); + return 0; +} +EXPORT_SYMBOL(rtl_pci_resume); + +struct rtl_intf_ops rtl_pci_ops = { + .read_efuse_byte = read_efuse_byte, + .adapter_start = rtl_pci_start, + .adapter_stop = rtl_pci_stop, + .adapter_tx = rtl_pci_tx, + .flush = rtl_pci_flush, + .reset_trx_ring = rtl_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/net/wireless/rtlwifi/pci.h b/drivers/net/wireless/rtlwifi/pci.h new file mode 100644 index 00000000..241448fc --- /dev/null +++ b/drivers/net/wireless/rtlwifi/pci.h @@ -0,0 +1,274 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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 __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 64 +#define RTL_PCI_MAX_TX_QUEUE_COUNT 9 + +#define RT_TXDESC_NUM 128 +#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 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 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_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*/ + +/*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; +}; + +struct rtl_rx_desc { + u32 dword[8]; +} __packed; + +struct rtl_tx_desc { + u32 dword[16]; +} __packed; + +struct rtl_tx_cmd_desc { + u32 dword[16]; +} __packed; + +struct rtl8192_tx_ring { + struct rtl_tx_desc *desc; + dma_addr_t dma; + unsigned int idx; + unsigned int entries; + struct sk_buff_head queue; +}; + +struct rtl8192_rx_ring { + struct rtl_rx_desc *desc; + dma_addr_t dma; + unsigned int idx; + struct sk_buff *rx_buf[RTL_PCI_MAX_RX_COUNT]; +}; + +struct rtl_pci { + struct pci_dev *pdev; + + bool driver_is_goingto_unload; + bool up_first_time; + bool first_init; + bool being_init_adapter; + bool init_ready; + + /*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]; + + /*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 support_aspm; + bool support_backdoor; + + /*QOS & EDCA */ + enum acm_method acm_method; + + u16 shortretry_limit; + u16 longretry_limit; +}; + +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; + + 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 bt_coexist; +}; + +#define rtl_pcipriv(hw) (((struct rtl_pci_priv *)(rtl_priv(hw))->priv)) +#define rtl_pcidev(pcipriv) (&((pcipriv)->dev)) + +int rtl_pci_reset_trx_ring(struct ieee80211_hw *hw); + +extern struct rtl_intf_ops rtl_pci_ops; + +int __devinit rtl_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *id); +void rtl_pci_disconnect(struct pci_dev *pdev); +int rtl_pci_suspend(struct device *dev); +int rtl_pci_resume(struct device *dev); +static inline u8 pci_read8_sync(struct rtl_priv *rtlpriv, u32 addr) +{ + return 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); +} + +#endif diff --git a/drivers/net/wireless/rtlwifi/ps.c b/drivers/net/wireless/rtlwifi/ps.c new file mode 100644 index 00000000..5b9c3b5e --- /dev/null +++ b/drivers/net/wireless/rtlwifi/ps.c @@ -0,0 +1,644 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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> + * + *****************************************************************************/ + +#include <linux/export.h> +#include "wifi.h" +#include "base.h" +#include "ps.h" + +bool 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)); + + /*<1> reset trx ring */ + if (rtlhal->interface == INTF_PCI) + rtlpriv->intf_ops->reset_trx_ring(hw); + + if (is_hal_stop(rtlhal)) + RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, + "Driver is already down!\n"); + + /*<2> Enable Adapter */ + if (rtlpriv->cfg->ops->hw_init(hw)) + return 1; + RT_CLEAR_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC); + + /*<3> Enable Interrupt */ + rtlpriv->cfg->ops->enable_interrupt(hw); + + /*<enable timer> */ + rtl_watch_dog_timer_callback((unsigned long)hw); + + return true; +} +EXPORT_SYMBOL(rtl_ps_enable_nic); + +bool rtl_ps_disable_nic(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + /*<1> Stop all timer */ + rtl_deinit_deferred_work(hw); + + /*<2> Disable Interrupt */ + rtlpriv->cfg->ops->disable_interrupt(hw); + tasklet_kill(&rtlpriv->works.irq_tasklet); + + /*<3> Disable Adapter */ + rtlpriv->cfg->ops->hw_disable(hw); + + return true; +} +EXPORT_SYMBOL(rtl_ps_disable_nic); + +bool rtl_ps_set_rf_state(struct ieee80211_hw *hw, + enum rf_pwrstate state_toset, + u32 changesource) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + bool actionallowed = false; + + switch (state_toset) { + case ERFON: + ppsc->rfoff_reason &= (~changesource); + + if ((changesource == RF_CHANGE_BY_HW) && + (ppsc->hwradiooff)) { + ppsc->hwradiooff = false; + } + + if (!ppsc->rfoff_reason) { + ppsc->rfoff_reason = 0; + actionallowed = true; + } + + break; + + case ERFOFF: + + if ((changesource == RF_CHANGE_BY_HW) && !ppsc->hwradiooff) { + ppsc->hwradiooff = true; + } + + ppsc->rfoff_reason |= changesource; + actionallowed = true; + break; + + case ERFSLEEP: + ppsc->rfoff_reason |= changesource; + actionallowed = true; + break; + + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "switch case not processed\n"); + break; + } + + if (actionallowed) + rtlpriv->cfg->ops->set_rf_power_state(hw, state_toset); + + return actionallowed; +} +EXPORT_SYMBOL(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->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); + } + } + + rtl_ps_set_rf_state(hw, ppsc->inactive_pwrstate, RF_CHANGE_BY_IPS); + + 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->swrf_processing = false; +} + +void rtl_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(rtlpriv, COMP_ERR, DBG_WARNING, + "not station return\n"); + return; + } + + if (mac->link_state > MAC80211_NOLINK) + return; + + if (is_hal_stop(rtlhal)) + return; + + if (rtlpriv->sec.being_setkey) + return; + + if (ppsc->inactiveps) { + rtstate = ppsc->rfpwr_state; + + /* + *Do not enter IPS in the following conditions: + *(1) RF is already OFF or Sleep + *(2) 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->swrf_processing && + (mac->link_state == MAC80211_NOLINK) && + !mac->act_scanning) { + RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, + "IPSEnter(): Turn off RF\n"); + + ppsc->inactive_pwrstate = ERFOFF; + ppsc->in_powersavemode = true; + + /*rtl_pci_reset_trx_ring(hw); */ + _rtl_ps_inactive_ps(hw); + } + } +} + +void rtl_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)); +} + +void rtl_ips_nic_on(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)); + enum rf_pwrstate rtstate; + unsigned long flags; + + if (mac->opmode != NL80211_IFTYPE_STATION) + return; + + spin_lock_irqsave(&rtlpriv->locks.ips_lock, flags); + + if (ppsc->inactiveps) { + rtstate = ppsc->rfpwr_state; + + if (rtstate != ERFON && + !ppsc->swrf_processing && + ppsc->rfoff_reason <= RF_CHANGE_BY_IPS) { + + ppsc->inactive_pwrstate = ERFON; + ppsc->in_powersavemode = false; + + _rtl_ps_inactive_ps(hw); + } + } + + spin_unlock_irqrestore(&rtlpriv->locks.ips_lock, flags); +} + +/*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(rtlpriv, 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.*/ +static 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)); + u8 rpwm_val, fw_pwrmode; + + 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->fwctrl_lps) && ppsc->report_linked) { + bool fw_current_inps; + if (ppsc->dot11_psmode == EACTIVE) { + RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG, + "FW LPS leave ps_mode:%x\n", + FW_PS_ACTIVE_MODE); + + rpwm_val = 0x0C; /* RF on */ + fw_pwrmode = FW_PS_ACTIVE_MODE; + 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)); + fw_current_inps = false; + + rtlpriv->cfg->ops->set_hw_reg(hw, + HW_VAR_FW_PSMODE_STATUS, + (u8 *) (&fw_current_inps)); + + } else { + if (rtl_get_fwlps_doze(hw)) { + RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG, + "FW LPS enter ps_mode:%x\n", + ppsc->fwctrl_psmode); + + rpwm_val = 0x02; /* RF off */ + fw_current_inps = true; + rtlpriv->cfg->ops->set_hw_reg(hw, + HW_VAR_FW_PSMODE_STATUS, + (u8 *) (&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)); + } else { + /* Reset the power save related parameters. */ + ppsc->dot11_psmode = EACTIVE; + } + } + } +} + +/*Enter the leisure power save mode.*/ +void rtl_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); + + if (!ppsc->fwctrl_lps) + return; + + if (rtlpriv->sec.being_setkey) + return; + + if (rtlpriv->link_info.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; + + mutex_lock(&rtlpriv->locks.ps_mutex); + + /* 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(rtlpriv, COMP_POWER, DBG_LOUD, + "Enter 802.11 power save mode...\n"); + + rtl_lps_set_psmode(hw, EAUTOPS); + } + } + + mutex_unlock(&rtlpriv->locks.ps_mutex); +} + +/*Leave the leisure power save mode.*/ +void rtl_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)); + + mutex_lock(&rtlpriv->locks.ps_mutex); + + if (ppsc->fwctrl_lps) { + if (ppsc->dot11_psmode != EACTIVE) { + + /*FIX ME */ + rtlpriv->cfg->ops->enable_interrupt(hw); + + 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(rtlpriv, COMP_POWER, DBG_LOUD, + "Busy Traffic,Leave 802.11 power save..\n"); + + rtl_lps_set_psmode(hw, EACTIVE); + } + } + mutex_unlock(&rtlpriv->locks.ps_mutex); +} + +/* For sw LPS*/ +void rtl_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.swctrl_lps) + return; + + if (rtlpriv->mac80211.link_state != MAC80211_LINKED) + return; + + if (!rtlpriv->psc.sw_ps_enabled) + return; + + if (rtlpriv->psc.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 (compare_ether_addr(hdr->addr3, rtlpriv->mac80211.bssid)) + return; + + rtlpriv->psc.last_beacon = jiffies; + + tim = rtl_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) { + /* 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(rtlpriv, COMP_POWER, DBG_DMESG, + "u_bufferd: %x, m_buffered: %x\n", u_buffed, m_buffed); + } +} + +void rtl_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)); + + if (!rtlpriv->psc.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); + } + + mutex_lock(&rtlpriv->locks.ps_mutex); + rtl_ps_set_rf_state(hw, ERFON, RF_CHANGE_BY_PS); + mutex_unlock(&rtlpriv->locks.ps_mutex); +} + +void rtl_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; + + rtl_swlps_rf_awake(hw); +} + +void rtl_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)); + 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.busytraffic) + return; + + mutex_lock(&rtlpriv->locks.ps_mutex); + rtl_ps_set_rf_state(hw, ERFSLEEP, RF_CHANGE_BY_PS); + mutex_unlock(&rtlpriv->locks.ps_mutex); + + 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(rtlpriv, 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 rtl_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) { + rtl_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; + } +} diff --git a/drivers/net/wireless/rtlwifi/ps.h b/drivers/net/wireless/rtlwifi/ps.h new file mode 100644 index 00000000..13578569 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/ps.h @@ -0,0 +1,51 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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 __REALTEK_RTL_PCI_PS_H__ +#define __REALTEK_RTL_PCI_PS_H__ + +#define MAX_SW_LPS_SLEEP_INTV 5 + +bool rtl_ps_set_rf_state(struct ieee80211_hw *hw, + enum rf_pwrstate state_toset, u32 changesource); +bool rtl_ps_enable_nic(struct ieee80211_hw *hw); +bool rtl_ps_disable_nic(struct ieee80211_hw *hw); +void rtl_ips_nic_off(struct ieee80211_hw *hw); +void rtl_ips_nic_on(struct ieee80211_hw *hw); +void rtl_ips_nic_off_wq_callback(void *data); +void rtl_lps_enter(struct ieee80211_hw *hw); +void rtl_lps_leave(struct ieee80211_hw *hw); + +void rtl_swlps_beacon(struct ieee80211_hw *hw, void *data, unsigned int len); +void rtl_swlps_wq_callback(void *data); +void rtl_swlps_rfon_wq_callback(void *data); +void rtl_swlps_rf_awake(struct ieee80211_hw *hw); +void rtl_swlps_rf_sleep(struct ieee80211_hw *hw); + +#endif diff --git a/drivers/net/wireless/rtlwifi/rc.c b/drivers/net/wireless/rtlwifi/rc.c new file mode 100644 index 00000000..c66f08a0 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rc.c @@ -0,0 +1,291 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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> + * + *****************************************************************************/ + +#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 + *CCK11M or OFDM_54M based on wireless mode. + */ +static u8 _rtl_rc_get_highest_rix(struct rtl_priv *rtlpriv, + struct ieee80211_sta *sta, + struct sk_buff *skb, bool not_data) +{ + struct rtl_mac *rtlmac = rtl_mac(rtlpriv); + 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 rtl_get_tcb_desc when we check rate is + * 1M we will not use FW rate but user rate. + */ + if (rtlmac->opmode == NL80211_IFTYPE_AP || + rtlmac->opmode == NL80211_IFTYPE_ADHOC) { + if (sta) { + sta_entry = (struct rtl_sta_info *) sta->drv_priv; + wireless_mode = sta_entry->wireless_mode; + } else { + return 0; + } + } else { + wireless_mode = rtlmac->mode; + } + + if (rtl_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 (get_rf_type(rtlphy) != RF_2T2R) + return N_MODE_MCS7_RIX; + else + return N_MODE_MCS15_RIX; + } + } else { + if (wireless_mode == WIRELESS_MODE_A) { + return A_MODE_MAX_RIX; + } else { + if (get_rf_type(rtlphy) != RF_2T2R) + return N_MODE_MCS7_RIX; + else + return N_MODE_MCS15_RIX; + } + } + } +} + +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; + + if (sta) { + sgi_20 = sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20; + sgi_40 = sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40; + } + 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; + } else { + if (mac->bw_40) + rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; + } + if (sgi_20 || sgi_40) + rate->flags |= IEEE80211_TX_RC_SHORT_GI; + if (sta && sta->ht_cap.ht_supported) + rate->flags |= IEEE80211_TX_RC_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 (rtl_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 ieee80211_sta *sta, void *priv_sta) +{ +} + +static void rtl_rate_update(void *ppriv, + struct ieee80211_supported_band *sband, + struct ieee80211_sta *sta, void *priv_sta, + u32 changed, + enum nl80211_channel_type oper_chan_type) +{ +} + +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(struct rtl_rate_priv), gfp); + if (!rate_priv) { + RT_TRACE(rtlpriv, 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 = { + .module = NULL, + .name = "rtl_rc", + .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, + .rate_update = rtl_rate_update, + .tx_status = rtl_tx_status, + .get_rate = rtl_get_rate, +}; + +int rtl_rate_control_register(void) +{ + return ieee80211_rate_control_register(&rtl_rate_ops); +} + +void rtl_rate_control_unregister(void) +{ + ieee80211_rate_control_unregister(&rtl_rate_ops); +} diff --git a/drivers/net/wireless/rtlwifi/rc.h b/drivers/net/wireless/rtlwifi/rc.h new file mode 100644 index 00000000..4d617616 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rc.h @@ -0,0 +1,47 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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 __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 + +struct rtl_rate_priv { + u8 ht_cap; +}; + +int rtl_rate_control_register(void); +void rtl_rate_control_unregister(void); +#endif diff --git a/drivers/net/wireless/rtlwifi/regd.c b/drivers/net/wireless/rtlwifi/regd.c new file mode 100644 index 00000000..c1608cdd --- /dev/null +++ b/drivers/net/wireless/rtlwifi/regd.c @@ -0,0 +1,437 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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> + * + *****************************************************************************/ + +#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, 40, 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, 40, 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, 40, 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; + u32 bandwidth = 0; + int r; + + 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) { + r = freq_reg_info(wiphy, ch->center_freq, + bandwidth, ®_rule); + if (r) + 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; + u32 bandwidth = 0; + int r; + + 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 received 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 */ + r = freq_reg_info(wiphy, ch->center_freq, bandwidth, ®_rule); + if (!r) { + 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 */ + r = freq_reg_info(wiphy, ch->center_freq, bandwidth, ®_rule); + if (!r) { + 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 int _rtl_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; + } + + 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 _rtl_regd_init_wiphy(struct rtl_regulatory *reg, + struct wiphy *wiphy, + int (*reg_notifier) (struct wiphy *wiphy, + struct regulatory_request * + request)) +{ + const struct ieee80211_regdomain *regd; + + wiphy->reg_notifier = reg_notifier; + + wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; + wiphy->flags &= ~WIPHY_FLAG_STRICT_REGULATORY; + wiphy->flags &= ~WIPHY_FLAG_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 rtl_regd_init(struct ieee80211_hw *hw, + int (*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(rtlpriv, COMP_REGD, DBG_TRACE, + "rtl: EEPROM regdomain: 0x%0x\n", rtlpriv->regd.country_code); + + if (rtlpriv->regd.country_code >= COUNTRY_CODE_MAX) { + RT_TRACE(rtlpriv, 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(rtlpriv, COMP_REGD, DBG_TRACE, + "rtl: Country alpha2 being used: %c%c\n", + rtlpriv->regd.alpha2[0], rtlpriv->regd.alpha2[1]); + + _rtl_regd_init_wiphy(&rtlpriv->regd, wiphy, reg_notifier); + + return 0; +} + +int rtl_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(rtlpriv, COMP_REGD, DBG_LOUD, "\n"); + + return _rtl_reg_notifier_apply(wiphy, request, &rtlpriv->regd); +} diff --git a/drivers/net/wireless/rtlwifi/regd.h b/drivers/net/wireless/rtlwifi/regd.h new file mode 100644 index 00000000..70ef2f41 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/regd.h @@ -0,0 +1,61 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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 __RTL_REGD_H__ +#define __RTL_REGD_H__ + +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 rtl_regd_init(struct ieee80211_hw *hw, + int (*reg_notifier) (struct wiphy *wiphy, + struct regulatory_request *request)); +int rtl_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request); +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/Makefile b/drivers/net/wireless/rtlwifi/rtl8192c/Makefile new file mode 100644 index 00000000..aee42d7a --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192c/Makefile @@ -0,0 +1,9 @@ +rtl8192c-common-objs := \ + main.o \ + dm_common.o \ + fw_common.o \ + phy_common.o + +obj-$(CONFIG_RTL8192C_COMMON) += rtl8192c-common.o + +ccflags-y += -D__CHECK_ENDIAN__ diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c new file mode 100644 index 00000000..1208b753 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c @@ -0,0 +1,1770 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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> + * + *****************************************************************************/ + +#include <linux/export.h> +#include "dm_common.h" +#include "phy_common.h" +#include "../pci.h" +#include "../base.h" + +struct dig_t dm_digtable; +static struct ps_t dm_pstable; + +#define BT_RSSI_STATE_NORMAL_POWER BIT_OFFSET_LEN_MASK_32(0, 1) +#define BT_RSSI_STATE_AMDPU_OFF BIT_OFFSET_LEN_MASK_32(1, 1) +#define BT_RSSI_STATE_SPECIAL_LOW BIT_OFFSET_LEN_MASK_32(2, 1) +#define BT_RSSI_STATE_BG_EDCA_LOW BIT_OFFSET_LEN_MASK_32(3, 1) +#define BT_RSSI_STATE_TXPOWER_LOW BIT_OFFSET_LEN_MASK_32(4, 1) + +#define RTLPRIV (struct rtl_priv *) +#define GET_UNDECORATED_AVERAGE_RSSI(_priv) \ + ((RTLPRIV(_priv))->mac80211.opmode == \ + NL80211_IFTYPE_ADHOC) ? \ + ((RTLPRIV(_priv))->dm.entry_min_undecoratedsmoothed_pwdb) : \ + ((RTLPRIV(_priv))->dm.undecorated_smoothed_pwdb) + +static const u32 ofdmswing_table[OFDM_TABLE_SIZE] = { + 0x7f8001fe, + 0x788001e2, + 0x71c001c7, + 0x6b8001ae, + 0x65400195, + 0x5fc0017f, + 0x5a400169, + 0x55400155, + 0x50800142, + 0x4c000130, + 0x47c0011f, + 0x43c0010f, + 0x40000100, + 0x3c8000f2, + 0x390000e4, + 0x35c000d7, + 0x32c000cb, + 0x300000c0, + 0x2d4000b5, + 0x2ac000ab, + 0x288000a2, + 0x26000098, + 0x24000090, + 0x22000088, + 0x20000080, + 0x1e400079, + 0x1c800072, + 0x1b00006c, + 0x19800066, + 0x18000060, + 0x16c0005b, + 0x15800056, + 0x14400051, + 0x1300004c, + 0x12000048, + 0x11000044, + 0x10000040, +}; + +static const u8 cckswing_table_ch1ch13[CCK_TABLE_SIZE][8] = { + {0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04}, + {0x33, 0x32, 0x2b, 0x23, 0x1a, 0x11, 0x08, 0x04}, + {0x30, 0x2f, 0x29, 0x21, 0x19, 0x10, 0x08, 0x03}, + {0x2d, 0x2d, 0x27, 0x1f, 0x18, 0x0f, 0x08, 0x03}, + {0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03}, + {0x28, 0x28, 0x22, 0x1c, 0x15, 0x0d, 0x07, 0x03}, + {0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03}, + {0x24, 0x23, 0x1f, 0x19, 0x13, 0x0c, 0x06, 0x03}, + {0x22, 0x21, 0x1d, 0x18, 0x11, 0x0b, 0x06, 0x02}, + {0x20, 0x20, 0x1b, 0x16, 0x11, 0x08, 0x05, 0x02}, + {0x1f, 0x1e, 0x1a, 0x15, 0x10, 0x0a, 0x05, 0x02}, + {0x1d, 0x1c, 0x18, 0x14, 0x0f, 0x0a, 0x05, 0x02}, + {0x1b, 0x1a, 0x17, 0x13, 0x0e, 0x09, 0x04, 0x02}, + {0x1a, 0x19, 0x16, 0x12, 0x0d, 0x09, 0x04, 0x02}, + {0x18, 0x17, 0x15, 0x11, 0x0c, 0x08, 0x04, 0x02}, + {0x17, 0x16, 0x13, 0x10, 0x0c, 0x08, 0x04, 0x02}, + {0x16, 0x15, 0x12, 0x0f, 0x0b, 0x07, 0x04, 0x01}, + {0x14, 0x14, 0x11, 0x0e, 0x0b, 0x07, 0x03, 0x02}, + {0x13, 0x13, 0x10, 0x0d, 0x0a, 0x06, 0x03, 0x01}, + {0x12, 0x12, 0x0f, 0x0c, 0x09, 0x06, 0x03, 0x01}, + {0x11, 0x11, 0x0f, 0x0c, 0x09, 0x06, 0x03, 0x01}, + {0x10, 0x10, 0x0e, 0x0b, 0x08, 0x05, 0x03, 0x01}, + {0x0f, 0x0f, 0x0d, 0x0b, 0x08, 0x05, 0x03, 0x01}, + {0x0e, 0x0e, 0x0c, 0x0a, 0x08, 0x05, 0x02, 0x01}, + {0x0d, 0x0d, 0x0c, 0x0a, 0x07, 0x05, 0x02, 0x01}, + {0x0d, 0x0c, 0x0b, 0x09, 0x07, 0x04, 0x02, 0x01}, + {0x0c, 0x0c, 0x0a, 0x09, 0x06, 0x04, 0x02, 0x01}, + {0x0b, 0x0b, 0x0a, 0x08, 0x06, 0x04, 0x02, 0x01}, + {0x0b, 0x0a, 0x09, 0x08, 0x06, 0x04, 0x02, 0x01}, + {0x0a, 0x0a, 0x09, 0x07, 0x05, 0x03, 0x02, 0x01}, + {0x0a, 0x09, 0x08, 0x07, 0x05, 0x03, 0x02, 0x01}, + {0x09, 0x09, 0x08, 0x06, 0x05, 0x03, 0x01, 0x01}, + {0x09, 0x08, 0x07, 0x06, 0x04, 0x03, 0x01, 0x01} +}; + +static const u8 cckswing_table_ch14[CCK_TABLE_SIZE][8] = { + {0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00}, + {0x33, 0x32, 0x2b, 0x19, 0x00, 0x00, 0x00, 0x00}, + {0x30, 0x2f, 0x29, 0x18, 0x00, 0x00, 0x00, 0x00}, + {0x2d, 0x2d, 0x17, 0x17, 0x00, 0x00, 0x00, 0x00}, + {0x2b, 0x2a, 0x25, 0x15, 0x00, 0x00, 0x00, 0x00}, + {0x28, 0x28, 0x24, 0x14, 0x00, 0x00, 0x00, 0x00}, + {0x26, 0x25, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00}, + {0x24, 0x23, 0x1f, 0x12, 0x00, 0x00, 0x00, 0x00}, + {0x22, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x00, 0x00}, + {0x20, 0x20, 0x1b, 0x10, 0x00, 0x00, 0x00, 0x00}, + {0x1f, 0x1e, 0x1a, 0x0f, 0x00, 0x00, 0x00, 0x00}, + {0x1d, 0x1c, 0x18, 0x0e, 0x00, 0x00, 0x00, 0x00}, + {0x1b, 0x1a, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00}, + {0x1a, 0x19, 0x16, 0x0d, 0x00, 0x00, 0x00, 0x00}, + {0x18, 0x17, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00}, + {0x17, 0x16, 0x13, 0x0b, 0x00, 0x00, 0x00, 0x00}, + {0x16, 0x15, 0x12, 0x0b, 0x00, 0x00, 0x00, 0x00}, + {0x14, 0x14, 0x11, 0x0a, 0x00, 0x00, 0x00, 0x00}, + {0x13, 0x13, 0x10, 0x0a, 0x00, 0x00, 0x00, 0x00}, + {0x12, 0x12, 0x0f, 0x09, 0x00, 0x00, 0x00, 0x00}, + {0x11, 0x11, 0x0f, 0x09, 0x00, 0x00, 0x00, 0x00}, + {0x10, 0x10, 0x0e, 0x08, 0x00, 0x00, 0x00, 0x00}, + {0x0f, 0x0f, 0x0d, 0x08, 0x00, 0x00, 0x00, 0x00}, + {0x0e, 0x0e, 0x0c, 0x07, 0x00, 0x00, 0x00, 0x00}, + {0x0d, 0x0d, 0x0c, 0x07, 0x00, 0x00, 0x00, 0x00}, + {0x0d, 0x0c, 0x0b, 0x06, 0x00, 0x00, 0x00, 0x00}, + {0x0c, 0x0c, 0x0a, 0x06, 0x00, 0x00, 0x00, 0x00}, + {0x0b, 0x0b, 0x0a, 0x06, 0x00, 0x00, 0x00, 0x00}, + {0x0b, 0x0a, 0x09, 0x05, 0x00, 0x00, 0x00, 0x00}, + {0x0a, 0x0a, 0x09, 0x05, 0x00, 0x00, 0x00, 0x00}, + {0x0a, 0x09, 0x08, 0x05, 0x00, 0x00, 0x00, 0x00}, + {0x09, 0x09, 0x08, 0x05, 0x00, 0x00, 0x00, 0x00}, + {0x09, 0x08, 0x07, 0x04, 0x00, 0x00, 0x00, 0x00} +}; + +static void rtl92c_dm_diginit(struct ieee80211_hw *hw) +{ + dm_digtable.dig_enable_flag = true; + dm_digtable.dig_ext_port_stage = DIG_EXT_PORT_STAGE_MAX; + dm_digtable.cur_igvalue = 0x20; + dm_digtable.pre_igvalue = 0x0; + dm_digtable.cursta_connectctate = DIG_STA_DISCONNECT; + dm_digtable.presta_connectstate = DIG_STA_DISCONNECT; + dm_digtable.curmultista_connectstate = DIG_MULTISTA_DISCONNECT; + dm_digtable.rssi_lowthresh = DM_DIG_THRESH_LOW; + dm_digtable.rssi_highthresh = DM_DIG_THRESH_HIGH; + dm_digtable.fa_lowthresh = DM_FALSEALARM_THRESH_LOW; + dm_digtable.fa_highthresh = DM_FALSEALARM_THRESH_HIGH; + dm_digtable.rx_gain_range_max = DM_DIG_MAX; + dm_digtable.rx_gain_range_min = DM_DIG_MIN; + dm_digtable.backoff_val = DM_DIG_BACKOFF_DEFAULT; + dm_digtable.backoff_val_range_max = DM_DIG_BACKOFF_MAX; + dm_digtable.backoff_val_range_min = DM_DIG_BACKOFF_MIN; + dm_digtable.pre_cck_pd_state = CCK_PD_STAGE_MAX; + dm_digtable.cur_cck_pd_state = CCK_PD_STAGE_MAX; +} + +static u8 rtl92c_dm_initial_gain_min_pwdb(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + long rssi_val_min = 0; + + if ((dm_digtable.curmultista_connectstate == DIG_MULTISTA_CONNECT) && + (dm_digtable.cursta_connectctate == DIG_STA_CONNECT)) { + if (rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb != 0) + rssi_val_min = + (rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb > + rtlpriv->dm.undecorated_smoothed_pwdb) ? + rtlpriv->dm.undecorated_smoothed_pwdb : + rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb; + else + rssi_val_min = rtlpriv->dm.undecorated_smoothed_pwdb; + } else if (dm_digtable.cursta_connectctate == DIG_STA_CONNECT || + dm_digtable.cursta_connectctate == DIG_STA_BEFORE_CONNECT) { + rssi_val_min = rtlpriv->dm.undecorated_smoothed_pwdb; + } else if (dm_digtable.curmultista_connectstate == + DIG_MULTISTA_CONNECT) { + rssi_val_min = rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb; + } + + return (u8) rssi_val_min; +} + +static void rtl92c_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); + + ret_value = rtl_get_bbreg(hw, ROFDM_PHYCOUNTER1, MASKDWORD); + falsealm_cnt->cnt_parity_fail = ((ret_value & 0xffff0000) >> 16); + + ret_value = rtl_get_bbreg(hw, ROFDM_PHYCOUNTER2, MASKDWORD); + falsealm_cnt->cnt_rate_illegal = (ret_value & 0xffff); + falsealm_cnt->cnt_crc8_fail = ((ret_value & 0xffff0000) >> 16); + + ret_value = rtl_get_bbreg(hw, ROFDM_PHYCOUNTER3, 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; + + rtl_set_bbreg(hw, RCCK0_FALSEALARMREPORT, BIT(14), 1); + ret_value = rtl_get_bbreg(hw, RCCK0_FACOUNTERLOWER, MASKBYTE0); + falsealm_cnt->cnt_cck_fail = ret_value; + + ret_value = rtl_get_bbreg(hw, RCCK0_FACOUNTERUPPER, MASKBYTE3); + falsealm_cnt->cnt_cck_fail += (ret_value & 0xff) << 8; + falsealm_cnt->cnt_all = (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); + + rtl_set_bbreg(hw, ROFDM1_LSTF, 0x08000000, 1); + rtl_set_bbreg(hw, ROFDM1_LSTF, 0x08000000, 0); + rtl_set_bbreg(hw, RCCK0_FALSEALARMREPORT, 0x0000c000, 0); + rtl_set_bbreg(hw, RCCK0_FALSEALARMREPORT, 0x0000c000, 2); + + RT_TRACE(rtlpriv, 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(rtlpriv, 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 rtl92c_dm_ctrl_initgain_by_fa(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 value_igi = dm_digtable.cur_igvalue; + + if (rtlpriv->falsealm_cnt.cnt_all < DM_DIG_FA_TH0) + value_igi--; + else if (rtlpriv->falsealm_cnt.cnt_all < DM_DIG_FA_TH1) + value_igi += 0; + else if (rtlpriv->falsealm_cnt.cnt_all < DM_DIG_FA_TH2) + value_igi++; + else if (rtlpriv->falsealm_cnt.cnt_all >= DM_DIG_FA_TH2) + value_igi += 2; + if (value_igi > DM_DIG_FA_UPPER) + value_igi = DM_DIG_FA_UPPER; + else if (value_igi < DM_DIG_FA_LOWER) + value_igi = DM_DIG_FA_LOWER; + if (rtlpriv->falsealm_cnt.cnt_all > 10000) + value_igi = 0x32; + + dm_digtable.cur_igvalue = value_igi; + rtl92c_dm_write_dig(hw); +} + +static void rtl92c_dm_ctrl_initgain_by_rssi(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + if (rtlpriv->falsealm_cnt.cnt_all > dm_digtable.fa_highthresh) { + if ((dm_digtable.backoff_val - 2) < + dm_digtable.backoff_val_range_min) + dm_digtable.backoff_val = + dm_digtable.backoff_val_range_min; + else + dm_digtable.backoff_val -= 2; + } else if (rtlpriv->falsealm_cnt.cnt_all < dm_digtable.fa_lowthresh) { + if ((dm_digtable.backoff_val + 2) > + dm_digtable.backoff_val_range_max) + dm_digtable.backoff_val = + dm_digtable.backoff_val_range_max; + else + dm_digtable.backoff_val += 2; + } + + if ((dm_digtable.rssi_val_min + 10 - dm_digtable.backoff_val) > + dm_digtable.rx_gain_range_max) + dm_digtable.cur_igvalue = dm_digtable.rx_gain_range_max; + else if ((dm_digtable.rssi_val_min + 10 - + dm_digtable.backoff_val) < dm_digtable.rx_gain_range_min) + dm_digtable.cur_igvalue = dm_digtable.rx_gain_range_min; + else + dm_digtable.cur_igvalue = dm_digtable.rssi_val_min + 10 - + dm_digtable.backoff_val; + + RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE, + "rssi_val_min = %x backoff_val %x\n", + dm_digtable.rssi_val_min, dm_digtable.backoff_val); + + rtl92c_dm_write_dig(hw); +} + +static void rtl92c_dm_initial_gain_multi_sta(struct ieee80211_hw *hw) +{ + static u8 initialized; /* initialized to false */ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + long rssi_strength = rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb; + bool multi_sta = false; + + if (mac->opmode == NL80211_IFTYPE_ADHOC) + multi_sta = true; + + if (!multi_sta || + dm_digtable.cursta_connectctate != DIG_STA_DISCONNECT) { + initialized = false; + dm_digtable.dig_ext_port_stage = DIG_EXT_PORT_STAGE_MAX; + return; + } else if (initialized == false) { + initialized = true; + dm_digtable.dig_ext_port_stage = DIG_EXT_PORT_STAGE_0; + dm_digtable.cur_igvalue = 0x20; + rtl92c_dm_write_dig(hw); + } + + if (dm_digtable.curmultista_connectstate == DIG_MULTISTA_CONNECT) { + if ((rssi_strength < dm_digtable.rssi_lowthresh) && + (dm_digtable.dig_ext_port_stage != DIG_EXT_PORT_STAGE_1)) { + + if (dm_digtable.dig_ext_port_stage == + DIG_EXT_PORT_STAGE_2) { + dm_digtable.cur_igvalue = 0x20; + rtl92c_dm_write_dig(hw); + } + + dm_digtable.dig_ext_port_stage = DIG_EXT_PORT_STAGE_1; + } else if (rssi_strength > dm_digtable.rssi_highthresh) { + dm_digtable.dig_ext_port_stage = DIG_EXT_PORT_STAGE_2; + rtl92c_dm_ctrl_initgain_by_fa(hw); + } + } else if (dm_digtable.dig_ext_port_stage != DIG_EXT_PORT_STAGE_0) { + dm_digtable.dig_ext_port_stage = DIG_EXT_PORT_STAGE_0; + dm_digtable.cur_igvalue = 0x20; + rtl92c_dm_write_dig(hw); + } + + RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE, + "curmultista_connectstate = %x dig_ext_port_stage %x\n", + dm_digtable.curmultista_connectstate, + dm_digtable.dig_ext_port_stage); +} + +static void rtl92c_dm_initial_gain_sta(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE, + "presta_connectstate = %x, cursta_connectctate = %x\n", + dm_digtable.presta_connectstate, + dm_digtable.cursta_connectctate); + + if (dm_digtable.presta_connectstate == dm_digtable.cursta_connectctate + || dm_digtable.cursta_connectctate == DIG_STA_BEFORE_CONNECT + || dm_digtable.cursta_connectctate == DIG_STA_CONNECT) { + + if (dm_digtable.cursta_connectctate != DIG_STA_DISCONNECT) { + dm_digtable.rssi_val_min = + rtl92c_dm_initial_gain_min_pwdb(hw); + rtl92c_dm_ctrl_initgain_by_rssi(hw); + } + } else { + dm_digtable.rssi_val_min = 0; + dm_digtable.dig_ext_port_stage = DIG_EXT_PORT_STAGE_MAX; + dm_digtable.backoff_val = DM_DIG_BACKOFF_DEFAULT; + dm_digtable.cur_igvalue = 0x20; + dm_digtable.pre_igvalue = 0; + rtl92c_dm_write_dig(hw); + } +} + +static void rtl92c_dm_cck_packet_detection_thresh(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + + if (dm_digtable.cursta_connectctate == DIG_STA_CONNECT) { + dm_digtable.rssi_val_min = rtl92c_dm_initial_gain_min_pwdb(hw); + + if (dm_digtable.pre_cck_pd_state == CCK_PD_STAGE_LowRssi) { + if (dm_digtable.rssi_val_min <= 25) + dm_digtable.cur_cck_pd_state = + CCK_PD_STAGE_LowRssi; + else + dm_digtable.cur_cck_pd_state = + CCK_PD_STAGE_HighRssi; + } else { + if (dm_digtable.rssi_val_min <= 20) + dm_digtable.cur_cck_pd_state = + CCK_PD_STAGE_LowRssi; + else + dm_digtable.cur_cck_pd_state = + CCK_PD_STAGE_HighRssi; + } + } else { + dm_digtable.cur_cck_pd_state = CCK_PD_STAGE_MAX; + } + + if (dm_digtable.pre_cck_pd_state != dm_digtable.cur_cck_pd_state) { + if (dm_digtable.cur_cck_pd_state == CCK_PD_STAGE_LowRssi) { + if (rtlpriv->falsealm_cnt.cnt_cck_fail > 800) + dm_digtable.cur_cck_fa_state = + CCK_FA_STAGE_High; + else + dm_digtable.cur_cck_fa_state = CCK_FA_STAGE_Low; + + if (dm_digtable.pre_cck_fa_state != + dm_digtable.cur_cck_fa_state) { + if (dm_digtable.cur_cck_fa_state == + CCK_FA_STAGE_Low) + rtl_set_bbreg(hw, RCCK0_CCA, MASKBYTE2, + 0x83); + else + rtl_set_bbreg(hw, RCCK0_CCA, MASKBYTE2, + 0xcd); + + dm_digtable.pre_cck_fa_state = + dm_digtable.cur_cck_fa_state; + } + + rtl_set_bbreg(hw, RCCK0_SYSTEM, MASKBYTE1, 0x40); + + if (IS_92C_SERIAL(rtlhal->version)) + rtl_set_bbreg(hw, RCCK0_FALSEALARMREPORT, + MASKBYTE2, 0xd7); + } else { + rtl_set_bbreg(hw, RCCK0_CCA, MASKBYTE2, 0xcd); + rtl_set_bbreg(hw, RCCK0_SYSTEM, MASKBYTE1, 0x47); + + if (IS_92C_SERIAL(rtlhal->version)) + rtl_set_bbreg(hw, RCCK0_FALSEALARMREPORT, + MASKBYTE2, 0xd3); + } + dm_digtable.pre_cck_pd_state = dm_digtable.cur_cck_pd_state; + } + + RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE, "CCKPDStage=%x\n", + dm_digtable.cur_cck_pd_state); + + RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE, "is92C=%x\n", + IS_92C_SERIAL(rtlhal->version)); +} + +static void rtl92c_dm_ctrl_initgain_by_twoport(struct ieee80211_hw *hw) +{ + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + + if (mac->act_scanning) + return; + + if (mac->link_state >= MAC80211_LINKED) + dm_digtable.cursta_connectctate = DIG_STA_CONNECT; + else + dm_digtable.cursta_connectctate = DIG_STA_DISCONNECT; + + rtl92c_dm_initial_gain_sta(hw); + rtl92c_dm_initial_gain_multi_sta(hw); + rtl92c_dm_cck_packet_detection_thresh(hw); + + dm_digtable.presta_connectstate = dm_digtable.cursta_connectctate; + +} + +static void rtl92c_dm_dig(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + if (rtlpriv->dm.dm_initialgain_enable == false) + return; + if (dm_digtable.dig_enable_flag == false) + return; + + rtl92c_dm_ctrl_initgain_by_twoport(hw); + +} + +static void rtl92c_dm_init_dynamic_txpower(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtlpriv->dm.dynamic_txpower_enable = false; + + rtlpriv->dm.last_dtp_lvl = TXHIGHPWRLEVEL_NORMAL; + rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_NORMAL; +} + +void rtl92c_dm_write_dig(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, + "cur_igvalue = 0x%x, pre_igvalue = 0x%x, backoff_val = %d\n", + dm_digtable.cur_igvalue, dm_digtable.pre_igvalue, + dm_digtable.backoff_val); + + dm_digtable.cur_igvalue += 2; + if (dm_digtable.cur_igvalue > 0x3f) + dm_digtable.cur_igvalue = 0x3f; + + if (dm_digtable.pre_igvalue != dm_digtable.cur_igvalue) { + rtl_set_bbreg(hw, ROFDM0_XAAGCCORE1, 0x7f, + dm_digtable.cur_igvalue); + rtl_set_bbreg(hw, ROFDM0_XBAGCCORE1, 0x7f, + dm_digtable.cur_igvalue); + + dm_digtable.pre_igvalue = dm_digtable.cur_igvalue; + } +} +EXPORT_SYMBOL(rtl92c_dm_write_dig); + +static void rtl92c_dm_pwdb_monitor(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + long tmpentry_max_pwdb = 0, tmpentry_min_pwdb = 0xff; + + u8 h2c_parameter[3] = { 0 }; + + return; + + if (tmpentry_max_pwdb != 0) { + rtlpriv->dm.entry_max_undecoratedsmoothed_pwdb = + tmpentry_max_pwdb; + } else { + rtlpriv->dm.entry_max_undecoratedsmoothed_pwdb = 0; + } + + if (tmpentry_min_pwdb != 0xff) { + rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb = + tmpentry_min_pwdb; + } else { + rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb = 0; + } + + h2c_parameter[2] = (u8) (rtlpriv->dm.undecorated_smoothed_pwdb & 0xFF); + h2c_parameter[0] = 0; + + rtl92c_fill_h2c_cmd(hw, H2C_RSSI_REPORT, 3, h2c_parameter); +} + +void rtl92c_dm_init_edca_turbo(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + rtlpriv->dm.current_turbo_edca = false; + rtlpriv->dm.is_any_nonbepkts = false; + rtlpriv->dm.is_cur_rdlstate = false; +} +EXPORT_SYMBOL(rtl92c_dm_init_edca_turbo); + +static void rtl92c_dm_check_edca_turbo(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + + static u64 last_txok_cnt; + static u64 last_rxok_cnt; + static u32 last_bt_edca_ul; + static u32 last_bt_edca_dl; + u64 cur_txok_cnt = 0; + u64 cur_rxok_cnt = 0; + u32 edca_be_ul = 0x5ea42b; + u32 edca_be_dl = 0x5ea42b; + bool bt_change_edca = false; + + if ((last_bt_edca_ul != rtlpcipriv->bt_coexist.bt_edca_ul) || + (last_bt_edca_dl != rtlpcipriv->bt_coexist.bt_edca_dl)) { + rtlpriv->dm.current_turbo_edca = false; + last_bt_edca_ul = rtlpcipriv->bt_coexist.bt_edca_ul; + last_bt_edca_dl = rtlpcipriv->bt_coexist.bt_edca_dl; + } + + if (rtlpcipriv->bt_coexist.bt_edca_ul != 0) { + edca_be_ul = rtlpcipriv->bt_coexist.bt_edca_ul; + bt_change_edca = true; + } + + if (rtlpcipriv->bt_coexist.bt_edca_dl != 0) { + edca_be_ul = rtlpcipriv->bt_coexist.bt_edca_dl; + bt_change_edca = true; + } + + if (mac->link_state != MAC80211_LINKED) { + rtlpriv->dm.current_turbo_edca = false; + return; + } + + if ((!mac->ht_enable) && (!rtlpcipriv->bt_coexist.bt_coexistence)) { + if (!(edca_be_ul & 0xffff0000)) + edca_be_ul |= 0x005e0000; + + if (!(edca_be_dl & 0xffff0000)) + edca_be_dl |= 0x005e0000; + } + + if ((bt_change_edca) || ((!rtlpriv->dm.is_any_nonbepkts) && + (!rtlpriv->dm.disable_framebursting))) { + + cur_txok_cnt = rtlpriv->stats.txbytesunicast - last_txok_cnt; + cur_rxok_cnt = rtlpriv->stats.rxbytesunicast - last_rxok_cnt; + + if (cur_rxok_cnt > 4 * cur_txok_cnt) { + if (!rtlpriv->dm.is_cur_rdlstate || + !rtlpriv->dm.current_turbo_edca) { + rtl_write_dword(rtlpriv, + REG_EDCA_BE_PARAM, + edca_be_dl); + rtlpriv->dm.is_cur_rdlstate = true; + } + } else { + if (rtlpriv->dm.is_cur_rdlstate || + !rtlpriv->dm.current_turbo_edca) { + rtl_write_dword(rtlpriv, + REG_EDCA_BE_PARAM, + edca_be_ul); + rtlpriv->dm.is_cur_rdlstate = false; + } + } + rtlpriv->dm.current_turbo_edca = true; + } else { + if (rtlpriv->dm.current_turbo_edca) { + u8 tmp = AC0_BE; + rtlpriv->cfg->ops->set_hw_reg(hw, + HW_VAR_AC_PARAM, + (u8 *) (&tmp)); + rtlpriv->dm.current_turbo_edca = false; + } + } + + rtlpriv->dm.is_any_nonbepkts = false; + last_txok_cnt = rtlpriv->stats.txbytesunicast; + last_rxok_cnt = rtlpriv->stats.rxbytesunicast; +} + +static void rtl92c_dm_txpower_tracking_callback_thermalmeter(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_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + u8 thermalvalue, delta, delta_lck, delta_iqk; + long ele_a, ele_d, temp_cck, val_x, value32; + long val_y, ele_c = 0; + u8 ofdm_index[2], cck_index = 0, ofdm_index_old[2], cck_index_old = 0; + int i; + bool is2t = IS_92C_SERIAL(rtlhal->version); + s8 txpwr_level[2] = {0, 0}; + u8 ofdm_min_index = 6, rf; + + rtlpriv->dm.txpower_trackinginit = true; + RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, + "rtl92c_dm_txpower_tracking_callback_thermalmeter\n"); + + thermalvalue = (u8) rtl_get_rfreg(hw, RF90_PATH_A, RF_T_METER, 0x1f); + + RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, + "Readback Thermal Meter = 0x%x pre thermal meter 0x%x eeprom_thermalmeter 0x%x\n", + thermalvalue, rtlpriv->dm.thermalvalue, + rtlefuse->eeprom_thermalmeter); + + rtl92c_phy_ap_calibrate(hw, (thermalvalue - + rtlefuse->eeprom_thermalmeter)); + if (is2t) + rf = 2; + else + rf = 1; + + if (thermalvalue) { + ele_d = rtl_get_bbreg(hw, ROFDM0_XATXIQIMBALANCE, + MASKDWORD) & MASKOFDM_D; + + for (i = 0; i < OFDM_TABLE_LENGTH; i++) { + if (ele_d == (ofdmswing_table[i] & MASKOFDM_D)) { + ofdm_index_old[0] = (u8) i; + + RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, + "Initial pathA ele_d reg0x%x = 0x%lx, ofdm_index=0x%x\n", + ROFDM0_XATXIQIMBALANCE, + ele_d, ofdm_index_old[0]); + break; + } + } + + if (is2t) { + ele_d = rtl_get_bbreg(hw, ROFDM0_XBTXIQIMBALANCE, + MASKDWORD) & MASKOFDM_D; + + for (i = 0; i < OFDM_TABLE_LENGTH; i++) { + if (ele_d == (ofdmswing_table[i] & + MASKOFDM_D)) { + + RT_TRACE(rtlpriv, COMP_POWER_TRACKING, + DBG_LOUD, + "Initial pathB ele_d reg0x%x = 0x%lx, ofdm_index=0x%x\n", + ROFDM0_XBTXIQIMBALANCE, ele_d, + ofdm_index_old[1]); + break; + } + } + } + + temp_cck = + rtl_get_bbreg(hw, RCCK0_TXFILTER2, MASKDWORD) & MASKCCK; + + for (i = 0; i < CCK_TABLE_LENGTH; i++) { + if (rtlpriv->dm.cck_inch14) { + if (memcmp((void *)&temp_cck, + (void *)&cckswing_table_ch14[i][2], + 4) == 0) { + cck_index_old = (u8) i; + + RT_TRACE(rtlpriv, COMP_POWER_TRACKING, + DBG_LOUD, + "Initial reg0x%x = 0x%lx, cck_index=0x%x, ch 14 %d\n", + RCCK0_TXFILTER2, temp_cck, + cck_index_old, + rtlpriv->dm.cck_inch14); + break; + } + } else { + if (memcmp((void *)&temp_cck, + (void *) + &cckswing_table_ch1ch13[i][2], + 4) == 0) { + cck_index_old = (u8) i; + + RT_TRACE(rtlpriv, COMP_POWER_TRACKING, + DBG_LOUD, + "Initial reg0x%x = 0x%lx, cck_index=0x%x, ch14 %d\n", + RCCK0_TXFILTER2, temp_cck, + cck_index_old, + rtlpriv->dm.cck_inch14); + break; + } + } + } + + if (!rtlpriv->dm.thermalvalue) { + rtlpriv->dm.thermalvalue = + rtlefuse->eeprom_thermalmeter; + rtlpriv->dm.thermalvalue_lck = thermalvalue; + rtlpriv->dm.thermalvalue_iqk = thermalvalue; + for (i = 0; i < rf; i++) + rtlpriv->dm.ofdm_index[i] = ofdm_index_old[i]; + rtlpriv->dm.cck_index = cck_index_old; + } + + delta = (thermalvalue > rtlpriv->dm.thermalvalue) ? + (thermalvalue - rtlpriv->dm.thermalvalue) : + (rtlpriv->dm.thermalvalue - thermalvalue); + + delta_lck = (thermalvalue > rtlpriv->dm.thermalvalue_lck) ? + (thermalvalue - rtlpriv->dm.thermalvalue_lck) : + (rtlpriv->dm.thermalvalue_lck - thermalvalue); + + delta_iqk = (thermalvalue > rtlpriv->dm.thermalvalue_iqk) ? + (thermalvalue - rtlpriv->dm.thermalvalue_iqk) : + (rtlpriv->dm.thermalvalue_iqk - thermalvalue); + + RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, + "Readback Thermal Meter = 0x%x pre thermal meter 0x%x eeprom_thermalmeter 0x%x delta 0x%x delta_lck 0x%x delta_iqk 0x%x\n", + thermalvalue, rtlpriv->dm.thermalvalue, + rtlefuse->eeprom_thermalmeter, delta, delta_lck, + delta_iqk); + + if (delta_lck > 1) { + rtlpriv->dm.thermalvalue_lck = thermalvalue; + rtl92c_phy_lc_calibrate(hw); + } + + if (delta > 0 && rtlpriv->dm.txpower_track_control) { + if (thermalvalue > rtlpriv->dm.thermalvalue) { + for (i = 0; i < rf; i++) + rtlpriv->dm.ofdm_index[i] -= delta; + rtlpriv->dm.cck_index -= delta; + } else { + for (i = 0; i < rf; i++) + rtlpriv->dm.ofdm_index[i] += delta; + rtlpriv->dm.cck_index += delta; + } + + if (is2t) { + RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, + "temp OFDM_A_index=0x%x, OFDM_B_index=0x%x, cck_index=0x%x\n", + rtlpriv->dm.ofdm_index[0], + rtlpriv->dm.ofdm_index[1], + rtlpriv->dm.cck_index); + } else { + RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, + "temp OFDM_A_index=0x%x, cck_index=0x%x\n", + rtlpriv->dm.ofdm_index[0], + rtlpriv->dm.cck_index); + } + + if (thermalvalue > rtlefuse->eeprom_thermalmeter) { + for (i = 0; i < rf; i++) + ofdm_index[i] = + rtlpriv->dm.ofdm_index[i] + + 1; + cck_index = rtlpriv->dm.cck_index + 1; + } else { + for (i = 0; i < rf; i++) + ofdm_index[i] = + rtlpriv->dm.ofdm_index[i]; + cck_index = rtlpriv->dm.cck_index; + } + + for (i = 0; i < rf; i++) { + if (txpwr_level[i] >= 0 && + txpwr_level[i] <= 26) { + if (thermalvalue > + rtlefuse->eeprom_thermalmeter) { + if (delta < 5) + ofdm_index[i] -= 1; + + else + ofdm_index[i] -= 2; + } else if (delta > 5 && thermalvalue < + rtlefuse-> + eeprom_thermalmeter) { + ofdm_index[i] += 1; + } + } else if (txpwr_level[i] >= 27 && + txpwr_level[i] <= 32 + && thermalvalue > + rtlefuse->eeprom_thermalmeter) { + if (delta < 5) + ofdm_index[i] -= 1; + + else + ofdm_index[i] -= 2; + } else if (txpwr_level[i] >= 32 && + txpwr_level[i] <= 38 && + thermalvalue > + rtlefuse->eeprom_thermalmeter + && delta > 5) { + ofdm_index[i] -= 1; + } + } + + if (txpwr_level[i] >= 0 && txpwr_level[i] <= 26) { + if (thermalvalue > + rtlefuse->eeprom_thermalmeter) { + if (delta < 5) + cck_index -= 1; + + else + cck_index -= 2; + } else if (delta > 5 && thermalvalue < + rtlefuse->eeprom_thermalmeter) { + cck_index += 1; + } + } else if (txpwr_level[i] >= 27 && + txpwr_level[i] <= 32 && + thermalvalue > + rtlefuse->eeprom_thermalmeter) { + if (delta < 5) + cck_index -= 1; + + else + cck_index -= 2; + } else if (txpwr_level[i] >= 32 && + txpwr_level[i] <= 38 && + thermalvalue > rtlefuse->eeprom_thermalmeter + && delta > 5) { + cck_index -= 1; + } + + for (i = 0; i < rf; i++) { + if (ofdm_index[i] > OFDM_TABLE_SIZE - 1) + ofdm_index[i] = OFDM_TABLE_SIZE - 1; + + else if (ofdm_index[i] < ofdm_min_index) + ofdm_index[i] = ofdm_min_index; + } + + if (cck_index > CCK_TABLE_SIZE - 1) + cck_index = CCK_TABLE_SIZE - 1; + else if (cck_index < 0) + cck_index = 0; + + if (is2t) { + RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, + "new OFDM_A_index=0x%x, OFDM_B_index=0x%x, cck_index=0x%x\n", + ofdm_index[0], ofdm_index[1], + cck_index); + } else { + RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, + "new OFDM_A_index=0x%x, cck_index=0x%x\n", + ofdm_index[0], cck_index); + } + } + + if (rtlpriv->dm.txpower_track_control && delta != 0) { + ele_d = + (ofdmswing_table[ofdm_index[0]] & 0xFFC00000) >> 22; + val_x = rtlphy->reg_e94; + val_y = rtlphy->reg_e9c; + + if (val_x != 0) { + if ((val_x & 0x00000200) != 0) + val_x = val_x | 0xFFFFFC00; + ele_a = ((val_x * ele_d) >> 8) & 0x000003FF; + + if ((val_y & 0x00000200) != 0) + val_y = val_y | 0xFFFFFC00; + ele_c = ((val_y * ele_d) >> 8) & 0x000003FF; + + value32 = (ele_d << 22) | + ((ele_c & 0x3F) << 16) | ele_a; + + rtl_set_bbreg(hw, ROFDM0_XATXIQIMBALANCE, + MASKDWORD, value32); + + value32 = (ele_c & 0x000003C0) >> 6; + rtl_set_bbreg(hw, ROFDM0_XCTXAFE, MASKH4BITS, + value32); + + value32 = ((val_x * ele_d) >> 7) & 0x01; + rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD, + BIT(31), value32); + + value32 = ((val_y * ele_d) >> 7) & 0x01; + rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD, + BIT(29), value32); + } else { + rtl_set_bbreg(hw, ROFDM0_XATXIQIMBALANCE, + MASKDWORD, + ofdmswing_table[ofdm_index[0]]); + + rtl_set_bbreg(hw, ROFDM0_XCTXAFE, MASKH4BITS, + 0x00); + rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD, + BIT(31) | BIT(29), 0x00); + } + + if (!rtlpriv->dm.cck_inch14) { + rtl_write_byte(rtlpriv, 0xa22, + cckswing_table_ch1ch13[cck_index] + [0]); + rtl_write_byte(rtlpriv, 0xa23, + cckswing_table_ch1ch13[cck_index] + [1]); + rtl_write_byte(rtlpriv, 0xa24, + cckswing_table_ch1ch13[cck_index] + [2]); + rtl_write_byte(rtlpriv, 0xa25, + cckswing_table_ch1ch13[cck_index] + [3]); + rtl_write_byte(rtlpriv, 0xa26, + cckswing_table_ch1ch13[cck_index] + [4]); + rtl_write_byte(rtlpriv, 0xa27, + cckswing_table_ch1ch13[cck_index] + [5]); + rtl_write_byte(rtlpriv, 0xa28, + cckswing_table_ch1ch13[cck_index] + [6]); + rtl_write_byte(rtlpriv, 0xa29, + cckswing_table_ch1ch13[cck_index] + [7]); + } else { + rtl_write_byte(rtlpriv, 0xa22, + cckswing_table_ch14[cck_index] + [0]); + rtl_write_byte(rtlpriv, 0xa23, + cckswing_table_ch14[cck_index] + [1]); + rtl_write_byte(rtlpriv, 0xa24, + cckswing_table_ch14[cck_index] + [2]); + rtl_write_byte(rtlpriv, 0xa25, + cckswing_table_ch14[cck_index] + [3]); + rtl_write_byte(rtlpriv, 0xa26, + cckswing_table_ch14[cck_index] + [4]); + rtl_write_byte(rtlpriv, 0xa27, + cckswing_table_ch14[cck_index] + [5]); + rtl_write_byte(rtlpriv, 0xa28, + cckswing_table_ch14[cck_index] + [6]); + rtl_write_byte(rtlpriv, 0xa29, + cckswing_table_ch14[cck_index] + [7]); + } + + if (is2t) { + ele_d = (ofdmswing_table[ofdm_index[1]] & + 0xFFC00000) >> 22; + + val_x = rtlphy->reg_eb4; + val_y = rtlphy->reg_ebc; + + if (val_x != 0) { + if ((val_x & 0x00000200) != 0) + val_x = val_x | 0xFFFFFC00; + ele_a = ((val_x * ele_d) >> 8) & + 0x000003FF; + + if ((val_y & 0x00000200) != 0) + val_y = val_y | 0xFFFFFC00; + ele_c = ((val_y * ele_d) >> 8) & + 0x00003FF; + + value32 = (ele_d << 22) | + ((ele_c & 0x3F) << 16) | ele_a; + rtl_set_bbreg(hw, + ROFDM0_XBTXIQIMBALANCE, + MASKDWORD, value32); + + value32 = (ele_c & 0x000003C0) >> 6; + rtl_set_bbreg(hw, ROFDM0_XDTXAFE, + MASKH4BITS, value32); + + value32 = ((val_x * ele_d) >> 7) & 0x01; + rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD, + BIT(27), value32); + + value32 = ((val_y * ele_d) >> 7) & 0x01; + rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD, + BIT(25), value32); + } else { + rtl_set_bbreg(hw, + ROFDM0_XBTXIQIMBALANCE, + MASKDWORD, + ofdmswing_table[ofdm_index + [1]]); + rtl_set_bbreg(hw, ROFDM0_XDTXAFE, + MASKH4BITS, 0x00); + rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD, + BIT(27) | BIT(25), 0x00); + } + + } + } + + if (delta_iqk > 3) { + rtlpriv->dm.thermalvalue_iqk = thermalvalue; + rtl92c_phy_iq_calibrate(hw, false); + } + + if (rtlpriv->dm.txpower_track_control) + rtlpriv->dm.thermalvalue = thermalvalue; + } + + RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, "<===\n"); + +} + +static void rtl92c_dm_initialize_txpower_tracking_thermalmeter( + struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtlpriv->dm.txpower_tracking = true; + rtlpriv->dm.txpower_trackinginit = false; + + RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, + "pMgntInfo->txpower_tracking = %d\n", + rtlpriv->dm.txpower_tracking); +} + +static void rtl92c_dm_initialize_txpower_tracking(struct ieee80211_hw *hw) +{ + rtl92c_dm_initialize_txpower_tracking_thermalmeter(hw); +} + +static void rtl92c_dm_txpower_tracking_directcall(struct ieee80211_hw *hw) +{ + rtl92c_dm_txpower_tracking_callback_thermalmeter(hw); +} + +static void rtl92c_dm_check_txpower_tracking_thermal_meter( + struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + static u8 tm_trigger; + + if (!rtlpriv->dm.txpower_tracking) + return; + + if (!tm_trigger) { + rtl_set_rfreg(hw, RF90_PATH_A, RF_T_METER, RFREG_OFFSET_MASK, + 0x60); + RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, + "Trigger 92S Thermal Meter!!\n"); + tm_trigger = 1; + return; + } else { + RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, + "Schedule TxPowerTracking direct call!!\n"); + rtl92c_dm_txpower_tracking_directcall(hw); + tm_trigger = 0; + } +} + +void rtl92c_dm_check_txpower_tracking(struct ieee80211_hw *hw) +{ + rtl92c_dm_check_txpower_tracking_thermal_meter(hw); +} +EXPORT_SYMBOL(rtl92c_dm_check_txpower_tracking); + +void rtl92c_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.useramask = true; + else + rtlpriv->dm.useramask = false; + +} +EXPORT_SYMBOL(rtl92c_dm_init_rate_adaptive_mask); + +static void rtl92c_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); + u32 low_rssithresh_for_ra, high_rssithresh_for_ra; + struct ieee80211_sta *sta = NULL; + + if (is_hal_stop(rtlhal)) { + RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD, + "<---- driver is going to unload\n"); + return; + } + + if (!rtlpriv->dm.useramask) { + RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD, + "<---- driver does not control rate adaptive mask\n"); + return; + } + + if (mac->link_state == MAC80211_LINKED && + mac->opmode == NL80211_IFTYPE_STATION) { + switch (p_ra->pre_ratr_state) { + case DM_RATR_STA_HIGH: + high_rssithresh_for_ra = 50; + low_rssithresh_for_ra = 20; + break; + case DM_RATR_STA_MIDDLE: + high_rssithresh_for_ra = 55; + low_rssithresh_for_ra = 20; + break; + case DM_RATR_STA_LOW: + high_rssithresh_for_ra = 50; + low_rssithresh_for_ra = 25; + break; + default: + high_rssithresh_for_ra = 50; + low_rssithresh_for_ra = 20; + break; + } + + if (rtlpriv->dm.undecorated_smoothed_pwdb > + (long)high_rssithresh_for_ra) + p_ra->ratr_state = DM_RATR_STA_HIGH; + else if (rtlpriv->dm.undecorated_smoothed_pwdb > + (long)low_rssithresh_for_ra) + p_ra->ratr_state = DM_RATR_STA_MIDDLE; + else + p_ra->ratr_state = DM_RATR_STA_LOW; + + if (p_ra->pre_ratr_state != p_ra->ratr_state) { + RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD, "RSSI = %ld\n", + rtlpriv->dm.undecorated_smoothed_pwdb); + RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD, + "RSSI_LEVEL = %d\n", p_ra->ratr_state); + RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD, + "PreState = %d, CurState = %d\n", + p_ra->pre_ratr_state, p_ra->ratr_state); + + /* Only the PCI card uses sta in the update rate table + * callback routine */ + if (rtlhal->interface == INTF_PCI) { + rcu_read_lock(); + sta = ieee80211_find_sta(mac->vif, mac->bssid); + } + rtlpriv->cfg->ops->update_rate_tbl(hw, sta, + p_ra->ratr_state); + + p_ra->pre_ratr_state = p_ra->ratr_state; + if (rtlhal->interface == INTF_PCI) + rcu_read_unlock(); + } + } +} + +static void rtl92c_dm_init_dynamic_bb_powersaving(struct ieee80211_hw *hw) +{ + dm_pstable.pre_ccastate = CCA_MAX; + dm_pstable.cur_ccasate = CCA_MAX; + dm_pstable.pre_rfstate = RF_MAX; + dm_pstable.cur_rfstate = RF_MAX; + dm_pstable.rssi_val_min = 0; +} + +void rtl92c_dm_rf_saving(struct ieee80211_hw *hw, u8 bforce_in_normal) +{ + static u8 initialize; + static u32 reg_874, reg_c70, reg_85c, reg_a74; + + if (initialize == 0) { + reg_874 = (rtl_get_bbreg(hw, RFPGA0_XCD_RFINTERFACESW, + MASKDWORD) & 0x1CC000) >> 14; + + reg_c70 = (rtl_get_bbreg(hw, ROFDM0_AGCPARAMETER1, + MASKDWORD) & BIT(3)) >> 3; + + reg_85c = (rtl_get_bbreg(hw, RFPGA0_XCD_SWITCHCONTROL, + MASKDWORD) & 0xFF000000) >> 24; + + reg_a74 = (rtl_get_bbreg(hw, 0xa74, MASKDWORD) & 0xF000) >> 12; + + initialize = 1; + } + + if (!bforce_in_normal) { + if (dm_pstable.rssi_val_min != 0) { + if (dm_pstable.pre_rfstate == RF_NORMAL) { + if (dm_pstable.rssi_val_min >= 30) + dm_pstable.cur_rfstate = RF_SAVE; + else + dm_pstable.cur_rfstate = RF_NORMAL; + } else { + if (dm_pstable.rssi_val_min <= 25) + dm_pstable.cur_rfstate = RF_NORMAL; + else + dm_pstable.cur_rfstate = RF_SAVE; + } + } else { + dm_pstable.cur_rfstate = RF_MAX; + } + } else { + dm_pstable.cur_rfstate = RF_NORMAL; + } + + if (dm_pstable.pre_rfstate != dm_pstable.cur_rfstate) { + if (dm_pstable.cur_rfstate == RF_SAVE) { + rtl_set_bbreg(hw, RFPGA0_XCD_RFINTERFACESW, + 0x1C0000, 0x2); + rtl_set_bbreg(hw, ROFDM0_AGCPARAMETER1, BIT(3), 0); + rtl_set_bbreg(hw, RFPGA0_XCD_SWITCHCONTROL, + 0xFF000000, 0x63); + rtl_set_bbreg(hw, RFPGA0_XCD_RFINTERFACESW, + 0xC000, 0x2); + rtl_set_bbreg(hw, 0xa74, 0xF000, 0x3); + rtl_set_bbreg(hw, 0x818, BIT(28), 0x0); + rtl_set_bbreg(hw, 0x818, BIT(28), 0x1); + } else { + rtl_set_bbreg(hw, RFPGA0_XCD_RFINTERFACESW, + 0x1CC000, reg_874); + rtl_set_bbreg(hw, ROFDM0_AGCPARAMETER1, BIT(3), + reg_c70); + rtl_set_bbreg(hw, RFPGA0_XCD_SWITCHCONTROL, 0xFF000000, + reg_85c); + rtl_set_bbreg(hw, 0xa74, 0xF000, reg_a74); + rtl_set_bbreg(hw, 0x818, BIT(28), 0x0); + } + + dm_pstable.pre_rfstate = dm_pstable.cur_rfstate; + } +} +EXPORT_SYMBOL(rtl92c_dm_rf_saving); + +static void rtl92c_dm_dynamic_bb_powersaving(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)); + + if (((mac->link_state == MAC80211_NOLINK)) && + (rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb == 0)) { + dm_pstable.rssi_val_min = 0; + RT_TRACE(rtlpriv, DBG_LOUD, DBG_LOUD, "Not connected to any\n"); + } + + if (mac->link_state == MAC80211_LINKED) { + if (mac->opmode == NL80211_IFTYPE_ADHOC) { + dm_pstable.rssi_val_min = + rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb; + RT_TRACE(rtlpriv, DBG_LOUD, DBG_LOUD, + "AP Client PWDB = 0x%lx\n", + dm_pstable.rssi_val_min); + } else { + dm_pstable.rssi_val_min = + rtlpriv->dm.undecorated_smoothed_pwdb; + RT_TRACE(rtlpriv, DBG_LOUD, DBG_LOUD, + "STA Default Port PWDB = 0x%lx\n", + dm_pstable.rssi_val_min); + } + } else { + dm_pstable.rssi_val_min = + rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb; + + RT_TRACE(rtlpriv, DBG_LOUD, DBG_LOUD, + "AP Ext Port PWDB = 0x%lx\n", + dm_pstable.rssi_val_min); + } + + if (IS_92C_SERIAL(rtlhal->version)) + ;/* rtl92c_dm_1r_cca(hw); */ + else + rtl92c_dm_rf_saving(hw, false); +} + +void rtl92c_dm_init(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtlpriv->dm.dm_type = DM_TYPE_BYDRIVER; + rtl92c_dm_diginit(hw); + rtl92c_dm_init_dynamic_txpower(hw); + rtl92c_dm_init_edca_turbo(hw); + rtl92c_dm_init_rate_adaptive_mask(hw); + rtl92c_dm_initialize_txpower_tracking(hw); + rtl92c_dm_init_dynamic_bb_powersaving(hw); +} +EXPORT_SYMBOL(rtl92c_dm_init); + +void rtl92c_dm_dynamic_txpower(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + long undecorated_smoothed_pwdb; + + if (!rtlpriv->dm.dynamic_txpower_enable) + return; + + if (rtlpriv->dm.dm_flag & HAL_DM_HIPWR_DISABLE) { + rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_NORMAL; + return; + } + + if ((mac->link_state < MAC80211_LINKED) && + (rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb == 0)) { + RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE, + "Not connected to any\n"); + + rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_NORMAL; + + rtlpriv->dm.last_dtp_lvl = TXHIGHPWRLEVEL_NORMAL; + return; + } + + if (mac->link_state >= MAC80211_LINKED) { + if (mac->opmode == NL80211_IFTYPE_ADHOC) { + undecorated_smoothed_pwdb = + rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb; + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + "AP Client PWDB = 0x%lx\n", + undecorated_smoothed_pwdb); + } else { + undecorated_smoothed_pwdb = + rtlpriv->dm.undecorated_smoothed_pwdb; + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + "STA Default Port PWDB = 0x%lx\n", + undecorated_smoothed_pwdb); + } + } else { + undecorated_smoothed_pwdb = + rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb; + + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + "AP Ext Port PWDB = 0x%lx\n", + undecorated_smoothed_pwdb); + } + + if (undecorated_smoothed_pwdb >= TX_POWER_NEAR_FIELD_THRESH_LVL2) { + rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_LEVEL1; + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + "TXHIGHPWRLEVEL_LEVEL1 (TxPwr=0x0)\n"); + } else if ((undecorated_smoothed_pwdb < + (TX_POWER_NEAR_FIELD_THRESH_LVL2 - 3)) && + (undecorated_smoothed_pwdb >= + TX_POWER_NEAR_FIELD_THRESH_LVL1)) { + + rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_LEVEL1; + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + "TXHIGHPWRLEVEL_LEVEL1 (TxPwr=0x10)\n"); + } else if (undecorated_smoothed_pwdb < + (TX_POWER_NEAR_FIELD_THRESH_LVL1 - 5)) { + rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_NORMAL; + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + "TXHIGHPWRLEVEL_NORMAL\n"); + } + + if ((rtlpriv->dm.dynamic_txhighpower_lvl != rtlpriv->dm.last_dtp_lvl)) { + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + "PHY_SetTxPowerLevel8192S() Channel = %d\n", + rtlphy->current_channel); + rtl92c_phy_set_txpower_level(hw, rtlphy->current_channel); + } + + rtlpriv->dm.last_dtp_lvl = rtlpriv->dm.dynamic_txhighpower_lvl; +} + +void rtl92c_dm_watchdog(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + bool fw_current_inpsmode = false; + bool fw_ps_awake = true; + + rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_FW_PSMODE_STATUS, + (u8 *) (&fw_current_inpsmode)); + rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_FWLPS_RF_ON, + (u8 *) (&fw_ps_awake)); + + if ((ppsc->rfpwr_state == ERFON) && ((!fw_current_inpsmode) && + fw_ps_awake) + && (!ppsc->rfchange_inprogress)) { + rtl92c_dm_pwdb_monitor(hw); + rtl92c_dm_dig(hw); + rtl92c_dm_false_alarm_counter_statistics(hw); + rtl92c_dm_dynamic_bb_powersaving(hw); + rtl92c_dm_dynamic_txpower(hw); + rtl92c_dm_check_txpower_tracking(hw); + rtl92c_dm_refresh_rate_adaptive_mask(hw); + rtl92c_dm_bt_coexist(hw); + rtl92c_dm_check_edca_turbo(hw); + } +} +EXPORT_SYMBOL(rtl92c_dm_watchdog); + +u8 rtl92c_bt_rssi_state_change(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + long undecorated_smoothed_pwdb; + u8 curr_bt_rssi_state = 0x00; + + if (rtlpriv->mac80211.link_state == MAC80211_LINKED) { + undecorated_smoothed_pwdb = + GET_UNDECORATED_AVERAGE_RSSI(rtlpriv); + } else { + if (rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb == 0) + undecorated_smoothed_pwdb = 100; + else + undecorated_smoothed_pwdb = + rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb; + } + + /* Check RSSI to determine HighPower/NormalPower state for + * BT coexistence. */ + if (undecorated_smoothed_pwdb >= 67) + curr_bt_rssi_state &= (~BT_RSSI_STATE_NORMAL_POWER); + else if (undecorated_smoothed_pwdb < 62) + curr_bt_rssi_state |= BT_RSSI_STATE_NORMAL_POWER; + + /* Check RSSI to determine AMPDU setting for BT coexistence. */ + if (undecorated_smoothed_pwdb >= 40) + curr_bt_rssi_state &= (~BT_RSSI_STATE_AMDPU_OFF); + else if (undecorated_smoothed_pwdb <= 32) + curr_bt_rssi_state |= BT_RSSI_STATE_AMDPU_OFF; + + /* Marked RSSI state. It will be used to determine BT coexistence + * setting later. */ + if (undecorated_smoothed_pwdb < 35) + curr_bt_rssi_state |= BT_RSSI_STATE_SPECIAL_LOW; + else + curr_bt_rssi_state &= (~BT_RSSI_STATE_SPECIAL_LOW); + + /* Set Tx Power according to BT status. */ + if (undecorated_smoothed_pwdb >= 30) + curr_bt_rssi_state |= BT_RSSI_STATE_TXPOWER_LOW; + else if (undecorated_smoothed_pwdb < 25) + curr_bt_rssi_state &= (~BT_RSSI_STATE_TXPOWER_LOW); + + /* Check BT state related to BT_Idle in B/G mode. */ + if (undecorated_smoothed_pwdb < 15) + curr_bt_rssi_state |= BT_RSSI_STATE_BG_EDCA_LOW; + else + curr_bt_rssi_state &= (~BT_RSSI_STATE_BG_EDCA_LOW); + + if (curr_bt_rssi_state != rtlpcipriv->bt_coexist.bt_rssi_state) { + rtlpcipriv->bt_coexist.bt_rssi_state = curr_bt_rssi_state; + return true; + } else { + return false; + } +} +EXPORT_SYMBOL(rtl92c_bt_rssi_state_change); + +static bool rtl92c_bt_state_change(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + + u32 polling, ratio_tx, ratio_pri; + u32 bt_tx, bt_pri; + u8 bt_state; + u8 cur_service_type; + + if (rtlpriv->mac80211.link_state < MAC80211_LINKED) + return false; + + bt_state = rtl_read_byte(rtlpriv, 0x4fd); + bt_tx = rtl_read_dword(rtlpriv, 0x488); + bt_tx = bt_tx & 0x00ffffff; + bt_pri = rtl_read_dword(rtlpriv, 0x48c); + bt_pri = bt_pri & 0x00ffffff; + polling = rtl_read_dword(rtlpriv, 0x490); + + if (bt_tx == 0xffffffff && bt_pri == 0xffffffff && + polling == 0xffffffff && bt_state == 0xff) + return false; + + bt_state &= BIT_OFFSET_LEN_MASK_32(0, 1); + if (bt_state != rtlpcipriv->bt_coexist.bt_cur_state) { + rtlpcipriv->bt_coexist.bt_cur_state = bt_state; + + if (rtlpcipriv->bt_coexist.reg_bt_sco == 3) { + rtlpcipriv->bt_coexist.bt_service = BT_IDLE; + + bt_state = bt_state | + ((rtlpcipriv->bt_coexist.bt_ant_isolation == 1) ? + 0 : BIT_OFFSET_LEN_MASK_32(1, 1)) | + BIT_OFFSET_LEN_MASK_32(2, 1); + rtl_write_byte(rtlpriv, 0x4fd, bt_state); + } + return true; + } + + ratio_tx = bt_tx * 1000 / polling; + ratio_pri = bt_pri * 1000 / polling; + rtlpcipriv->bt_coexist.ratio_tx = ratio_tx; + rtlpcipriv->bt_coexist.ratio_pri = ratio_pri; + + if (bt_state && rtlpcipriv->bt_coexist.reg_bt_sco == 3) { + + if ((ratio_tx < 30) && (ratio_pri < 30)) + cur_service_type = BT_IDLE; + else if ((ratio_pri > 110) && (ratio_pri < 250)) + cur_service_type = BT_SCO; + else if ((ratio_tx >= 200) && (ratio_pri >= 200)) + cur_service_type = BT_BUSY; + else if ((ratio_tx >= 350) && (ratio_tx < 500)) + cur_service_type = BT_OTHERBUSY; + else if (ratio_tx >= 500) + cur_service_type = BT_PAN; + else + cur_service_type = BT_OTHER_ACTION; + + if (cur_service_type != rtlpcipriv->bt_coexist.bt_service) { + rtlpcipriv->bt_coexist.bt_service = cur_service_type; + bt_state = bt_state | + ((rtlpcipriv->bt_coexist.bt_ant_isolation == 1) ? + 0 : BIT_OFFSET_LEN_MASK_32(1, 1)) | + ((rtlpcipriv->bt_coexist.bt_service != BT_IDLE) ? + 0 : BIT_OFFSET_LEN_MASK_32(2, 1)); + + /* Add interrupt migration when bt is not ini + * idle state (no traffic). */ + if (rtlpcipriv->bt_coexist.bt_service != BT_IDLE) { + rtl_write_word(rtlpriv, 0x504, 0x0ccc); + rtl_write_byte(rtlpriv, 0x506, 0x54); + rtl_write_byte(rtlpriv, 0x507, 0x54); + } else { + rtl_write_byte(rtlpriv, 0x506, 0x00); + rtl_write_byte(rtlpriv, 0x507, 0x00); + } + + rtl_write_byte(rtlpriv, 0x4fd, bt_state); + return true; + } + } + + return false; + +} + +static bool rtl92c_bt_wifi_connect_change(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + static bool media_connect; + + if (rtlpriv->mac80211.link_state < MAC80211_LINKED) { + media_connect = false; + } else { + if (!media_connect) { + media_connect = true; + return true; + } + media_connect = true; + } + + return false; +} + +static void rtl92c_bt_set_normal(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + + + if (rtlpcipriv->bt_coexist.bt_service == BT_OTHERBUSY) { + rtlpcipriv->bt_coexist.bt_edca_ul = 0x5ea72b; + rtlpcipriv->bt_coexist.bt_edca_dl = 0x5ea72b; + } else if (rtlpcipriv->bt_coexist.bt_service == BT_BUSY) { + rtlpcipriv->bt_coexist.bt_edca_ul = 0x5eb82f; + rtlpcipriv->bt_coexist.bt_edca_dl = 0x5eb82f; + } else if (rtlpcipriv->bt_coexist.bt_service == BT_SCO) { + if (rtlpcipriv->bt_coexist.ratio_tx > 160) { + rtlpcipriv->bt_coexist.bt_edca_ul = 0x5ea72f; + rtlpcipriv->bt_coexist.bt_edca_dl = 0x5ea72f; + } else { + rtlpcipriv->bt_coexist.bt_edca_ul = 0x5ea32b; + rtlpcipriv->bt_coexist.bt_edca_dl = 0x5ea42b; + } + } else { + rtlpcipriv->bt_coexist.bt_edca_ul = 0; + rtlpcipriv->bt_coexist.bt_edca_dl = 0; + } + + if ((rtlpcipriv->bt_coexist.bt_service != BT_IDLE) && + (rtlpriv->mac80211.mode == WIRELESS_MODE_G || + (rtlpriv->mac80211.mode == (WIRELESS_MODE_G | WIRELESS_MODE_B))) && + (rtlpcipriv->bt_coexist.bt_rssi_state & + BT_RSSI_STATE_BG_EDCA_LOW)) { + rtlpcipriv->bt_coexist.bt_edca_ul = 0x5eb82b; + rtlpcipriv->bt_coexist.bt_edca_dl = 0x5eb82b; + } +} + +static void rtl92c_bt_ant_isolation(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + + + /* Only enable HW BT coexist when BT in "Busy" state. */ + if (rtlpriv->mac80211.vendor == PEER_CISCO && + rtlpcipriv->bt_coexist.bt_service == BT_OTHER_ACTION) { + rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG, 0xa0); + } else { + if ((rtlpcipriv->bt_coexist.bt_service == BT_BUSY) && + (rtlpcipriv->bt_coexist.bt_rssi_state & + BT_RSSI_STATE_NORMAL_POWER)) { + rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG, 0xa0); + } else if ((rtlpcipriv->bt_coexist.bt_service == + BT_OTHER_ACTION) && (rtlpriv->mac80211.mode < + WIRELESS_MODE_N_24G) && + (rtlpcipriv->bt_coexist.bt_rssi_state & + BT_RSSI_STATE_SPECIAL_LOW)) { + rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG, 0xa0); + } else if (rtlpcipriv->bt_coexist.bt_service == BT_PAN) { + rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG, 0x00); + } else { + rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG, 0x00); + } + } + + if (rtlpcipriv->bt_coexist.bt_service == BT_PAN) + rtl_write_dword(rtlpriv, REG_GPIO_PIN_CTRL, 0x10100); + else + rtl_write_dword(rtlpriv, REG_GPIO_PIN_CTRL, 0x0); + + if (rtlpcipriv->bt_coexist.bt_rssi_state & + BT_RSSI_STATE_NORMAL_POWER) { + rtl92c_bt_set_normal(hw); + } else { + rtlpcipriv->bt_coexist.bt_edca_ul = 0; + rtlpcipriv->bt_coexist.bt_edca_dl = 0; + } + + if (rtlpcipriv->bt_coexist.bt_service != BT_IDLE) { + rtlpriv->cfg->ops->set_rfreg(hw, + RF90_PATH_A, + 0x1e, + 0xf0, 0xf); + } else { + rtlpriv->cfg->ops->set_rfreg(hw, + RF90_PATH_A, 0x1e, 0xf0, + rtlpcipriv->bt_coexist.bt_rfreg_origin_1e); + } + + if (!rtlpriv->dm.dynamic_txpower_enable) { + if (rtlpcipriv->bt_coexist.bt_service != BT_IDLE) { + if (rtlpcipriv->bt_coexist.bt_rssi_state & + BT_RSSI_STATE_TXPOWER_LOW) { + rtlpriv->dm.dynamic_txhighpower_lvl = + TXHIGHPWRLEVEL_BT2; + } else { + rtlpriv->dm.dynamic_txhighpower_lvl = + TXHIGHPWRLEVEL_BT1; + } + } else { + rtlpriv->dm.dynamic_txhighpower_lvl = + TXHIGHPWRLEVEL_NORMAL; + } + rtl92c_phy_set_txpower_level(hw, + rtlpriv->phy.current_channel); + } +} + +static void rtl92c_check_bt_change(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + + if (rtlpcipriv->bt_coexist.bt_cur_state) { + if (rtlpcipriv->bt_coexist.bt_ant_isolation) + rtl92c_bt_ant_isolation(hw); + } else { + rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG, 0x00); + rtlpriv->cfg->ops->set_rfreg(hw, RF90_PATH_A, 0x1e, 0xf0, + rtlpcipriv->bt_coexist.bt_rfreg_origin_1e); + + rtlpcipriv->bt_coexist.bt_edca_ul = 0; + rtlpcipriv->bt_coexist.bt_edca_dl = 0; + } +} + +void rtl92c_dm_bt_coexist(struct ieee80211_hw *hw) +{ + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + + bool wifi_connect_change; + bool bt_state_change; + bool rssi_state_change; + + if ((rtlpcipriv->bt_coexist.bt_coexistence) && + (rtlpcipriv->bt_coexist.bt_coexist_type == BT_CSR_BC4)) { + + wifi_connect_change = rtl92c_bt_wifi_connect_change(hw); + bt_state_change = rtl92c_bt_state_change(hw); + rssi_state_change = rtl92c_bt_rssi_state_change(hw); + + if (wifi_connect_change || bt_state_change || rssi_state_change) + rtl92c_check_bt_change(hw); + } +} +EXPORT_SYMBOL(rtl92c_dm_bt_coexist); diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.h b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.h new file mode 100644 index 00000000..2178e376 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.h @@ -0,0 +1,206 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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 __RTL92COMMON_DM_H__ +#define __RTL92COMMON_DM_H__ + +#include "../wifi.h" +#include "../rtl8192ce/def.h" +#include "../rtl8192ce/reg.h" +#include "fw_common.h" + +#define HAL_DM_DIG_DISABLE BIT(0) +#define HAL_DM_HIPWR_DISABLE BIT(1) + +#define OFDM_TABLE_LENGTH 37 +#define CCK_TABLE_LENGTH 33 + +#define OFDM_TABLE_SIZE 37 +#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_FA_UPPER 0x32 +#define DM_DIG_FA_LOWER 0x20 +#define DM_DIG_FA_TH0 0x20 +#define DM_DIG_FA_TH1 0x100 +#define DM_DIG_FA_TH2 0x200 + +#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 + +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; + 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_pd_state; + u8 cur_cck_pd_state; + u8 pre_cck_fa_state; + u8 cur_cck_fa_state; + u8 pre_ccastate; + u8 cur_ccasate; +}; + +struct swat_t { + u8 failure_cnt; + u8 try_flag; + u8 stop_trying; + long pre_rssi; + long trying_threshold; + u8 cur_antenna; + u8 pre_antenna; +}; + +enum tag_dynamic_init_gain_operation_type_definition { + DIG_TYPE_THRESH_HIGH = 0, + DIG_TYPE_THRESH_LOW = 1, + DIG_TYPE_BACKOFF = 2, + DIG_TYPE_RX_GAIN_MIN = 3, + DIG_TYPE_RX_GAIN_MAX = 4, + DIG_TYPE_ENABLE = 5, + DIG_TYPE_DISABLE = 6, + DIG_OP_TYPE_MAX +}; + +enum tag_cck_packet_detection_threshold_type_definition { + CCK_PD_STAGE_LowRssi = 0, + CCK_PD_STAGE_HighRssi = 1, + CCK_FA_STAGE_Low = 2, + CCK_FA_STAGE_High = 3, + CCK_PD_STAGE_MAX = 4, +}; + +enum dm_1r_cca_e { + CCA_1R = 0, + CCA_2R = 1, + CCA_MAX = 2, +}; + +enum dm_rf_e { + RF_SAVE = 0, + RF_NORMAL = 1, + RF_MAX = 2, +}; + +enum dm_sw_ant_switch_e { + ANS_ANTENNA_B = 1, + ANS_ANTENNA_A = 2, + ANS_ANTENNA_MAX = 3, +}; + +enum dm_dig_ext_port_alg_e { + DIG_EXT_PORT_STAGE_0 = 0, + DIG_EXT_PORT_STAGE_1 = 1, + DIG_EXT_PORT_STAGE_2 = 2, + DIG_EXT_PORT_STAGE_3 = 3, + DIG_EXT_PORT_STAGE_MAX = 4, +}; + +enum dm_dig_connect_e { + DIG_STA_DISCONNECT = 0, + DIG_STA_CONNECT = 1, + DIG_STA_BEFORE_CONNECT = 2, + DIG_MULTISTA_DISCONNECT = 3, + DIG_MULTISTA_CONNECT = 4, + DIG_CONNECT_MAX +}; + +extern struct dig_t dm_digtable; +void rtl92c_dm_init(struct ieee80211_hw *hw); +void rtl92c_dm_watchdog(struct ieee80211_hw *hw); +void rtl92c_dm_write_dig(struct ieee80211_hw *hw); +void rtl92c_dm_init_edca_turbo(struct ieee80211_hw *hw); +void rtl92c_dm_check_txpower_tracking(struct ieee80211_hw *hw); +void rtl92c_dm_init_rate_adaptive_mask(struct ieee80211_hw *hw); +void rtl92c_dm_rf_saving(struct ieee80211_hw *hw, u8 bforce_in_normal); +void rtl92c_phy_ap_calibrate(struct ieee80211_hw *hw, char delta); +void rtl92c_phy_lc_calibrate(struct ieee80211_hw *hw); +void rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw, bool recovery); +void rtl92c_dm_dynamic_txpower(struct ieee80211_hw *hw); +void rtl92c_dm_bt_coexist(struct ieee80211_hw *hw); + +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c new file mode 100644 index 00000000..c20b3c30 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c @@ -0,0 +1,808 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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> + * + *****************************************************************************/ + +#include "../wifi.h" +#include "../pci.h" +#include "../base.h" +#include "../rtl8192ce/reg.h" +#include "../rtl8192ce/def.h" +#include "fw_common.h" +#include <linux/export.h> + +static void _rtl92c_enable_fw_download(struct ieee80211_hw *hw, bool enable) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192CU) { + u32 value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL); + if (enable) + value32 |= MCUFWDL_EN; + else + value32 &= ~MCUFWDL_EN; + rtl_write_dword(rtlpriv, REG_MCUFWDL, value32); + } else if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192CE) { + u8 tmp; + if (enable) { + + tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1); + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, + tmp | 0x04); + + tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL); + rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp | 0x01); + + 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); + + rtl_write_byte(rtlpriv, REG_MCUFWDL + 1, 0x00); + } + } +} + +static void rtl_block_fw_writeN(struct ieee80211_hw *hw, const u8 *buffer, + u32 size) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 blockSize = REALTEK_USB_VENQT_MAX_BUF_SIZE - 20; + u8 *bufferPtr = (u8 *) buffer; + u32 i, offset, blockCount, remainSize; + + blockCount = size / blockSize; + remainSize = size % blockSize; + + for (i = 0; i < blockCount; i++) { + offset = i * blockSize; + rtlpriv->io.writeN_sync(rtlpriv, + (FW_8192C_START_ADDRESS + offset), + (void *)(bufferPtr + offset), + blockSize); + } + + if (remainSize) { + offset = blockCount * blockSize; + rtlpriv->io.writeN_sync(rtlpriv, + (FW_8192C_START_ADDRESS + offset), + (void *)(bufferPtr + offset), + remainSize); + } +} + +static void _rtl92c_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; + u32 data; + + if (rtlpriv->io.writeN_sync) { + rtl_block_fw_writeN(hw, buffer, size); + return; + } + blockCount = size / blockSize; + remainSize = size % blockSize; + if (remainSize) { + /* the last word is < 4 bytes - pad it with zeros */ + for (i = 0; i < 4 - remainSize; i++) + *(bufferPtr + size + i) = 0; + blockCount++; + } + + for (i = 0; i < blockCount; i++) { + offset = i * blockSize; + /* for big-endian platforms, the firmware data need to be byte + * swapped as it was read as a byte string and will be written + * as 32-bit dwords and byte swapped when written + */ + data = le32_to_cpu(*(__le32 *)(pu4BytePtr + i)); + rtl_write_dword(rtlpriv, (FW_8192C_START_ADDRESS + offset), + data); + } +} + +static void _rtl92c_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); + _rtl92c_fw_block_write(hw, buffer, size); +} + +static void _rtl92c_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 _rtl92c_write_fw(struct ieee80211_hw *hw, + enum version_8192c version, u8 *buffer, u32 size) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u8 *bufferPtr = (u8 *) buffer; + + RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, "FW size is %d bytes\n", size); + + if (IS_CHIP_VER_B(version)) { + u32 pageNums, remainSize; + u32 page, offset; + + if (IS_HARDWARE_TYPE_8192CE(rtlhal)) + _rtl92c_fill_dummy(bufferPtr, &size); + + pageNums = size / FW_8192C_PAGE_SIZE; + remainSize = size % FW_8192C_PAGE_SIZE; + + if (pageNums > 4) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "Page numbers should not greater then 4\n"); + } + + for (page = 0; page < pageNums; page++) { + offset = page * FW_8192C_PAGE_SIZE; + _rtl92c_fw_page_write(hw, page, (bufferPtr + offset), + FW_8192C_PAGE_SIZE); + } + + if (remainSize) { + offset = pageNums * FW_8192C_PAGE_SIZE; + page = pageNums; + _rtl92c_fw_page_write(hw, page, (bufferPtr + offset), + remainSize); + } + } else { + _rtl92c_fw_block_write(hw, buffer, size); + } +} + +static int _rtl92c_fw_free_to_go(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + 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(rtlpriv, COMP_ERR, DBG_EMERG, + "chksum report faill ! REG_MCUFWDL:0x%08x\n", value32); + return -EIO; + } + + RT_TRACE(rtlpriv, 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); + + counter = 0; + + do { + value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL); + if (value32 & WINTINI_RDY) { + RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, + "Polling FW ready success!! REG_MCUFWDL:0x%08x\n", + value32); + return 0; + } + + mdelay(FW_8192C_POLLING_DELAY); + + } while (counter++ < FW_8192C_POLLING_TIMEOUT_COUNT); + + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "Polling FW ready fail!! REG_MCUFWDL:0x%08x\n", value32); + return -EIO; +} + +int rtl92c_download_fw(struct ieee80211_hw *hw) +{ + 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; + enum version_8192c version = rtlhal->version; + + if (rtlpriv->max_fw_size == 0 || !rtlhal->pfirmware) + return 1; + + pfwheader = (struct rtl92c_firmware_header *)rtlhal->pfirmware; + pfwdata = (u8 *) rtlhal->pfirmware; + fwsize = rtlhal->fwsize; + + if (IS_FW_HEADER_EXIST(pfwheader)) { + RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG, + "Firmware Version(%d), Signature(%#x),Size(%d)\n", + le16_to_cpu(pfwheader->version), + le16_to_cpu(pfwheader->signature), + (uint)sizeof(struct rtl92c_firmware_header)); + + pfwdata = pfwdata + sizeof(struct rtl92c_firmware_header); + fwsize = fwsize - sizeof(struct rtl92c_firmware_header); + } + + _rtl92c_enable_fw_download(hw, true); + _rtl92c_write_fw(hw, version, pfwdata, fwsize); + _rtl92c_enable_fw_download(hw, false); + + if (_rtl92c_fw_free_to_go(hw)) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "Firmware is not ready to run!\n"); + } else { + RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, + "Firmware is ready to run!\n"); + } + + return 0; +} +EXPORT_SYMBOL(rtl92c_download_fw); + +static bool _rtl92c_check_fw_read_last_h2c(struct ieee80211_hw *hw, u8 boxnum) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 val_hmetfr, val_mcutst_1; + bool result = false; + + val_hmetfr = rtl_read_byte(rtlpriv, REG_HMETFR); + val_mcutst_1 = rtl_read_byte(rtlpriv, (REG_MCUTST_1 + boxnum)); + + if (((val_hmetfr >> boxnum) & BIT(0)) == 0 && val_mcutst_1 == 0) + result = true; + return result; +} + +static void _rtl92c_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)); + u8 boxnum; + u16 box_reg = 0, box_extreg = 0; + u8 u1b_tmp; + bool isfw_read = false; + bool bwrite_sucess = false; + u8 wait_h2c_limmit = 100; + u8 wait_writeh2c_limmit = 100; + u8 boxcontent[4], boxextcontent[2]; + u32 h2c_waitcounter = 0; + unsigned long flag; + u8 idx; + + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "come in\n"); + + while (true) { + spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag); + if (rtlhal->h2c_setinprogress) { + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, + "H2C set in progress! Wait to set..element_id(%d)\n", + element_id); + + while (rtlhal->h2c_setinprogress) { + spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, + flag); + h2c_waitcounter++; + RT_TRACE(rtlpriv, 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->h2c_setinprogress = true; + spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag); + break; + } + } + + while (!bwrite_sucess) { + wait_writeh2c_limmit--; + if (wait_writeh2c_limmit == 0) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "Write H2C fail because no trigger for FW INT!\n"); + break; + } + + 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(rtlpriv, COMP_ERR, DBG_EMERG, + "switch case not processed\n"); + break; + } + + isfw_read = _rtl92c_check_fw_read_last_h2c(hw, boxnum); + while (!isfw_read) { + + wait_h2c_limmit--; + if (wait_h2c_limmit == 0) { + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, + "Waiting too long for FW read clear HMEBox(%d)!\n", + boxnum); + break; + } + + udelay(10); + + isfw_read = _rtl92c_check_fw_read_last_h2c(hw, boxnum); + u1b_tmp = rtl_read_byte(rtlpriv, 0x1BF); + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, + "Waiting for FW read clear HMEBox(%d)!!! 0x1BF = %2x\n", + boxnum, u1b_tmp); + } + + if (!isfw_read) { + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, + "Write H2C register BOX[%d] fail!!!!! Fw do not read\n", + boxnum); + break; + } + + memset(boxcontent, 0, sizeof(boxcontent)); + memset(boxextcontent, 0, sizeof(boxextcontent)); + boxcontent[0] = element_id; + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, + "Write element_id box_reg(%4x) = %2x\n", + box_reg, element_id); + + switch (cmd_len) { + case 1: + boxcontent[0] &= ~(BIT(7)); + memcpy((u8 *) (boxcontent) + 1, + p_cmdbuffer, 1); + + for (idx = 0; idx < 4; idx++) { + rtl_write_byte(rtlpriv, box_reg + idx, + boxcontent[idx]); + } + break; + case 2: + boxcontent[0] &= ~(BIT(7)); + memcpy((u8 *) (boxcontent) + 1, + p_cmdbuffer, 2); + + for (idx = 0; idx < 4; idx++) { + rtl_write_byte(rtlpriv, box_reg + idx, + boxcontent[idx]); + } + break; + case 3: + boxcontent[0] &= ~(BIT(7)); + memcpy((u8 *) (boxcontent) + 1, + p_cmdbuffer, 3); + + for (idx = 0; idx < 4; idx++) { + rtl_write_byte(rtlpriv, box_reg + idx, + boxcontent[idx]); + } + break; + case 4: + boxcontent[0] |= (BIT(7)); + memcpy((u8 *) (boxextcontent), + p_cmdbuffer, 2); + memcpy((u8 *) (boxcontent) + 1, + p_cmdbuffer + 2, 2); + + for (idx = 0; idx < 2; 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; + case 5: + boxcontent[0] |= (BIT(7)); + memcpy((u8 *) (boxextcontent), + p_cmdbuffer, 2); + memcpy((u8 *) (boxcontent) + 1, + p_cmdbuffer + 2, 3); + + for (idx = 0; idx < 2; 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(rtlpriv, COMP_ERR, DBG_EMERG, + "switch case not processed\n"); + break; + } + + bwrite_sucess = true; + + rtlhal->last_hmeboxnum = boxnum + 1; + if (rtlhal->last_hmeboxnum == 4) + rtlhal->last_hmeboxnum = 0; + + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, + "pHalData->last_hmeboxnum = %d\n", + rtlhal->last_hmeboxnum); + } + + spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag); + rtlhal->h2c_setinprogress = false; + spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag); + + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "go out\n"); +} + +void rtl92c_fill_h2c_cmd(struct ieee80211_hw *hw, + u8 element_id, u32 cmd_len, u8 *p_cmdbuffer) +{ + u32 tmp_cmdbuf[2]; + + memset(tmp_cmdbuf, 0, 8); + memcpy(tmp_cmdbuf, p_cmdbuffer, cmd_len); + _rtl92c_fill_h2c_command(hw, element_id, cmd_len, (u8 *)&tmp_cmdbuf); + + return; +} +EXPORT_SYMBOL(rtl92c_fill_h2c_cmd); + +void rtl92c_firmware_selfreset(struct ieee80211_hw *hw) +{ + u8 u1b_tmp; + u8 delay = 100; + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtl_write_byte(rtlpriv, REG_HMETFR + 3, 0x20); + u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1); + + while (u1b_tmp & BIT(2)) { + delay--; + if (delay == 0) { + RT_ASSERT(false, "8051 reset fail\n"); + break; + } + udelay(50); + u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1); + } +} +EXPORT_SYMBOL(rtl92c_firmware_selfreset); + +void rtl92c_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 u1_h2c_set_pwrmode[3] = {0}; + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, "FW LPS mode = %d\n", mode); + + SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, mode); + SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode, 1); + SET_H2CCMD_PWRMODE_PARM_BCN_PASS_TIME(u1_h2c_set_pwrmode, + ppsc->reg_max_lps_awakeintvl); + + RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG, + "rtl92c_set_fw_rsvdpagepkt(): u1_h2c_set_pwrmode", + u1_h2c_set_pwrmode, 3); + rtl92c_fill_h2c_cmd(hw, H2C_SETPWRMODE, 3, u1_h2c_set_pwrmode); + +} +EXPORT_SYMBOL(rtl92c_set_fw_pwrmode_cmd); + +static bool _rtl92c_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); + + 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); + + rtlpriv->cfg->ops->tx_polling(hw, BEACON_QUEUE); + + 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, 0x76, 0x00, 0x42, + 0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x50, 0x08, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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 1 beacon */ + 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, + 0x10, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* page 2 ps-poll */ + 0xA4, 0x10, 0x01, 0xC0, 0x00, 0x40, 0x10, 0x10, + 0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42, + 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, + 0x18, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* page 3 null */ + 0x48, 0x01, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10, + 0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42, + 0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 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, + 0x72, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 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 rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool 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[3] = {0}; + bool dlok = false; + + u8 *beacon; + u8 *pspoll; + u8 *nullfunc; + u8 *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 + --------------------------------------------------------*/ + pspoll = &reserved_page_packet[PSPOLL_PG * 128]; + SET_80211_PS_POLL_AID(pspoll, (mac->assoc_id | 0xc000)); + SET_80211_PS_POLL_BSSID(pspoll, mac->bssid); + SET_80211_PS_POLL_TA(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 + ----------------------------------------------------------*/ + probersp = &reserved_page_packet[PROBERSP_PG * 128]; + SET_80211_HDR_ADDRESS1(probersp, mac->bssid); + SET_80211_HDR_ADDRESS2(probersp, mac->mac_addr); + SET_80211_HDR_ADDRESS3(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, + "rtl92c_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL", + &reserved_page_packet[0], totalpacketlen); + RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG, + "rtl92c_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL", + u1RsvdPageLoc, 3); + + + skb = dev_alloc_skb(totalpacketlen); + if (!skb) + return; + memcpy((u8 *) skb_put(skb, totalpacketlen), + &reserved_page_packet, totalpacketlen); + + rtstatus = _rtl92c_cmd_send_packet(hw, skb); + + if (rtstatus) + dlok = true; + + if (dlok) { + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + "Set RSVD page location to Fw\n"); + RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG, + "H2C_RSVDPAGE", u1RsvdPageLoc, 3); + rtl92c_fill_h2c_cmd(hw, H2C_RSVDPAGE, + sizeof(u1RsvdPageLoc), u1RsvdPageLoc); + } else + RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, + "Set RSVD page location to Fw FAIL!!!!!!\n"); +} +EXPORT_SYMBOL(rtl92c_set_fw_rsvdpagepkt); + +void rtl92c_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus) +{ + u8 u1_joinbssrpt_parm[1] = {0}; + + SET_H2CCMD_JOINBSSRPT_PARM_OPMODE(u1_joinbssrpt_parm, mstatus); + + rtl92c_fill_h2c_cmd(hw, H2C_JOINBSSRPT, 1, u1_joinbssrpt_parm); +} +EXPORT_SYMBOL(rtl92c_set_fw_joinbss_report_cmd); diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.h b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.h new file mode 100644 index 00000000..780ea5b1 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.h @@ -0,0 +1,99 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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 __RTL92C__FW__COMMON__H__ +#define __RTL92C__FW__COMMON__H__ + +#define FW_8192C_SIZE 0x3000 +#define FW_8192C_START_ADDRESS 0x1000 +#define FW_8192C_END_ADDRESS 0x1FFF +#define FW_8192C_PAGE_SIZE 4096 +#define FW_8192C_POLLING_DELAY 5 +#define FW_8192C_POLLING_TIMEOUT_COUNT 100 + +#define IS_FW_HEADER_EXIST(_pfwhdr) \ + ((le16_to_cpu(_pfwhdr->signature)&0xFFF0) == 0x92C0 ||\ + (le16_to_cpu(_pfwhdr->signature)&0xFFF0) == 0x88C0) + +struct rtl92c_firmware_header { + __le16 signature; + u8 category; + u8 function; + __le16 version; + u8 subversion; + u8 rsvd1; + u8 month; + u8 date; + u8 hour; + u8 minute; + __le16 ramcodeSize; + __le16 rsvd2; + __le32 svnindex; + __le32 rsvd3; + __le32 rsvd4; + __le32 rsvd5; +}; + +enum rtl8192c_h2c_cmd { + H2C_AP_OFFLOAD = 0, + H2C_SETPWRMODE = 1, + H2C_JOINBSSRPT = 2, + H2C_RSVDPAGE = 3, + H2C_RSSI_REPORT = 5, + H2C_RA_MASK = 6, + MAX_H2CCMD +}; + +#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_SMART_PS(__ph2ccmd, __val) \ + SET_BITS_TO_LE_1BYTE((__ph2ccmd)+1, 0, 8, __val) +#define SET_H2CCMD_PWRMODE_PARM_BCN_PASS_TIME(__ph2ccmd, __val) \ + SET_BITS_TO_LE_1BYTE((__ph2ccmd)+2, 0, 8, __val) +#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) + +int rtl92c_download_fw(struct ieee80211_hw *hw); +void rtl92c_fill_h2c_cmd(struct ieee80211_hw *hw, u8 element_id, + u32 cmd_len, u8 *p_cmdbuffer); +void rtl92c_firmware_selfreset(struct ieee80211_hw *hw); +void rtl92c_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode); +void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished); +void rtl92c_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus); +void usb_writeN_async(struct rtl_priv *rtlpriv, u32 addr, void *data, u16 len); + +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/main.c b/drivers/net/wireless/rtlwifi/rtl8192c/main.c new file mode 100644 index 00000000..918b1d12 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192c/main.c @@ -0,0 +1,40 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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> + * + *****************************************************************************/ + +#include "../wifi.h" +#include <linux/module.h> + + +MODULE_AUTHOR("lizhaoming <chaoming_li@realsil.com.cn>"); +MODULE_AUTHOR("Realtek WlanFAE <wlanfae@realtek.com>"); +MODULE_AUTHOR("Georgia <georgia@realtek.com>"); +MODULE_AUTHOR("Ziv Huang <ziv_huang@realtek.com>"); +MODULE_AUTHOR("Larry Finger <Larry.Finger@lwfinger.net>"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Realtek 8192C/8188C 802.11n PCI wireless"); diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c b/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c new file mode 100644 index 00000000..4c016241 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c @@ -0,0 +1,1952 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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> + * + *****************************************************************************/ + +#include <linux/export.h> +#include "../wifi.h" +#include "../rtl8192ce/reg.h" +#include "../rtl8192ce/def.h" +#include "dm_common.h" +#include "phy_common.h" + +/* Define macro to shorten lines */ +#define MCS_TXPWR mcs_txpwrlevel_origoffset + +u32 rtl92c_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(rtlpriv, COMP_RF, DBG_TRACE, "regaddr(%#x), bitmask(%#x)\n", + regaddr, bitmask); + originalvalue = rtl_read_dword(rtlpriv, regaddr); + bitshift = _rtl92c_phy_calculate_bit_shift(bitmask); + returnvalue = (originalvalue & bitmask) >> bitshift; + + RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, + "BBR MASK=0x%x Addr[0x%x]=0x%x\n", + bitmask, regaddr, originalvalue); + + return returnvalue; + +} +EXPORT_SYMBOL(rtl92c_phy_query_bb_reg); + +void rtl92c_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(rtlpriv, COMP_RF, DBG_TRACE, + "regaddr(%#x), bitmask(%#x), data(%#x)\n", + regaddr, bitmask, data); + + if (bitmask != MASKDWORD) { + originalvalue = rtl_read_dword(rtlpriv, regaddr); + bitshift = _rtl92c_phy_calculate_bit_shift(bitmask); + data = ((originalvalue & (~bitmask)) | (data << bitshift)); + } + + rtl_write_dword(rtlpriv, regaddr, data); + + RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, + "regaddr(%#x), bitmask(%#x), data(%#x)\n", + regaddr, bitmask, data); + +} +EXPORT_SYMBOL(rtl92c_phy_set_bb_reg); + +u32 _rtl92c_phy_fw_rf_serial_read(struct ieee80211_hw *hw, + enum radio_path rfpath, u32 offset) +{ + RT_ASSERT(false, "deprecated!\n"); + return 0; + +} +EXPORT_SYMBOL(_rtl92c_phy_fw_rf_serial_read); + +void _rtl92c_phy_fw_rf_serial_write(struct ieee80211_hw *hw, + enum radio_path rfpath, u32 offset, + u32 data) +{ + RT_ASSERT(false, "deprecated!\n"); +} +EXPORT_SYMBOL(_rtl92c_phy_fw_rf_serial_write); + +u32 _rtl92c_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 &= 0x3f; + newoffset = offset; + if (RT_CANNOT_IO(hw)) { + RT_TRACE(rtlpriv, 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); + rtl_set_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, MASKDWORD, + tmplong | BLSSIREADEDGE); + 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(rtlpriv, COMP_RF, DBG_TRACE, "RFR-%d Addr[0x%x]=0x%x\n", + rfpath, pphyreg->rflssi_readback, retvalue); + return retvalue; +} +EXPORT_SYMBOL(_rtl92c_phy_rf_serial_read); + +void _rtl92c_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(rtlpriv, COMP_ERR, DBG_EMERG, "stop\n"); + return; + } + offset &= 0x3f; + newoffset = offset; + data_and_addr = ((newoffset << 20) | (data & 0x000fffff)) & 0x0fffffff; + rtl_set_bbreg(hw, pphyreg->rf3wire_offset, MASKDWORD, data_and_addr); + RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, "RFW-%d Addr[0x%x]=0x%x\n", + rfpath, pphyreg->rf3wire_offset, data_and_addr); +} +EXPORT_SYMBOL(_rtl92c_phy_rf_serial_write); + +u32 _rtl92c_phy_calculate_bit_shift(u32 bitmask) +{ + u32 i; + + for (i = 0; i <= 31; i++) { + if ((bitmask >> i) & 0x1) + break; + } + return i; +} +EXPORT_SYMBOL(_rtl92c_phy_calculate_bit_shift); + +static void _rtl92c_phy_bb_config_1t(struct ieee80211_hw *hw) +{ + rtl_set_bbreg(hw, RFPGA0_TXINFO, 0x3, 0x2); + rtl_set_bbreg(hw, RFPGA1_TXINFO, 0x300033, 0x200022); + rtl_set_bbreg(hw, RCCK0_AFESETTING, MASKBYTE3, 0x45); + rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, MASKBYTE0, 0x23); + rtl_set_bbreg(hw, ROFDM0_AGCPARAMETER1, 0x30, 0x1); + rtl_set_bbreg(hw, 0xe74, 0x0c000000, 0x2); + rtl_set_bbreg(hw, 0xe78, 0x0c000000, 0x2); + rtl_set_bbreg(hw, 0xe7c, 0x0c000000, 0x2); + rtl_set_bbreg(hw, 0xe80, 0x0c000000, 0x2); + rtl_set_bbreg(hw, 0xe88, 0x0c000000, 0x2); +} + +bool rtl92c_phy_rf_config(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + return rtlpriv->cfg->ops->phy_rf6052_config(hw); +} +EXPORT_SYMBOL(rtl92c_phy_rf_config); + +bool _rtl92c_phy_bb8192c_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; + + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "==>\n"); + rtstatus = rtlpriv->cfg->ops->config_bb_with_headerfile(hw, + BASEBAND_CONFIG_PHY_REG); + if (!rtstatus) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Write BB Reg Fail!!\n"); + return false; + } + if (rtlphy->rf_type == RF_1T2R) { + _rtl92c_phy_bb_config_1t(hw); + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "Config to 1T!!\n"); + } + if (rtlefuse->autoload_failflag == false) { + rtlphy->pwrgroup_cnt = 0; + rtstatus = rtlpriv->cfg->ops->config_bb_with_pgheaderfile(hw, + BASEBAND_CONFIG_PHY_REG); + } + if (!rtstatus) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "BB_PG Reg Fail!!\n"); + return false; + } + rtstatus = rtlpriv->cfg->ops->config_bb_with_headerfile(hw, + BASEBAND_CONFIG_AGC_TAB); + if (!rtstatus) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "AGC Table Fail\n"); + return false; + } + rtlphy->cck_high_power = (bool) (rtl_get_bbreg(hw, + RFPGA0_XA_HSSIPARAMETER2, + 0x200)); + + return true; +} +EXPORT_SYMBOL(_rtl92c_phy_bb8192c_config_parafile); + +void _rtl92c_store_pwrIndex_diffrate_offset(struct ieee80211_hw *hw, + u32 regaddr, u32 bitmask, + u32 data) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + int index; + + if (regaddr == RTXAGC_A_RATE18_06) + index = 0; + else if (regaddr == RTXAGC_A_RATE54_24) + index = 1; + else if (regaddr == RTXAGC_A_CCK1_MCS32) + index = 6; + else if (regaddr == RTXAGC_B_CCK11_A_CCK2_11 && bitmask == 0xffffff00) + index = 7; + else if (regaddr == RTXAGC_A_MCS03_MCS00) + index = 2; + else if (regaddr == RTXAGC_A_MCS07_MCS04) + index = 3; + else if (regaddr == RTXAGC_A_MCS11_MCS08) + index = 4; + else if (regaddr == RTXAGC_A_MCS15_MCS12) + index = 5; + else if (regaddr == RTXAGC_B_RATE18_06) + index = 8; + else if (regaddr == RTXAGC_B_RATE54_24) + index = 9; + else if (regaddr == RTXAGC_B_CCK1_55_MCS32) + index = 14; + else if (regaddr == RTXAGC_B_CCK11_A_CCK2_11 && bitmask == 0x000000ff) + index = 15; + else if (regaddr == RTXAGC_B_MCS03_MCS00) + index = 10; + else if (regaddr == RTXAGC_B_MCS07_MCS04) + index = 11; + else if (regaddr == RTXAGC_B_MCS11_MCS08) + index = 12; + else if (regaddr == RTXAGC_B_MCS15_MCS12) + index = 13; + else + return; + + rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][index] = data; + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + "MCSTxPowerLevelOriginalOffset[%d][%d] = 0x%x\n", + rtlphy->pwrgroup_cnt, index, + rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][index]); + + if (index == 13) + rtlphy->pwrgroup_cnt++; +} +EXPORT_SYMBOL(_rtl92c_store_pwrIndex_diffrate_offset); + +void rtl92c_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(rtlpriv, 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(rtlpriv, COMP_INIT, DBG_TRACE, + "Default framesync (0x%x) = 0x%x\n", + ROFDM0_RXDETECTOR3, rtlphy->framesync); +} + +void _rtl92c_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_C].rfintfs = RFPGA0_XCD_RFINTERFACESW; + rtlphy->phyreg_def[RF90_PATH_D].rfintfs = RFPGA0_XCD_RFINTERFACESW; + + rtlphy->phyreg_def[RF90_PATH_A].rfintfi = RFPGA0_XAB_RFINTERFACERB; + rtlphy->phyreg_def[RF90_PATH_B].rfintfi = RFPGA0_XAB_RFINTERFACERB; + rtlphy->phyreg_def[RF90_PATH_C].rfintfi = RFPGA0_XCD_RFINTERFACERB; + rtlphy->phyreg_def[RF90_PATH_D].rfintfi = RFPGA0_XCD_RFINTERFACERB; + + 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].rflssi_select = rFPGA0_XAB_RFPARAMETER; + rtlphy->phyreg_def[RF90_PATH_B].rflssi_select = rFPGA0_XAB_RFPARAMETER; + rtlphy->phyreg_def[RF90_PATH_C].rflssi_select = rFPGA0_XCD_RFPARAMETER; + rtlphy->phyreg_def[RF90_PATH_D].rflssi_select = rFPGA0_XCD_RFPARAMETER; + + rtlphy->phyreg_def[RF90_PATH_A].rftxgain_stage = RFPGA0_TXGAINSTAGE; + rtlphy->phyreg_def[RF90_PATH_B].rftxgain_stage = RFPGA0_TXGAINSTAGE; + rtlphy->phyreg_def[RF90_PATH_C].rftxgain_stage = RFPGA0_TXGAINSTAGE; + rtlphy->phyreg_def[RF90_PATH_D].rftxgain_stage = RFPGA0_TXGAINSTAGE; + + rtlphy->phyreg_def[RF90_PATH_A].rfhssi_para1 = RFPGA0_XA_HSSIPARAMETER1; + rtlphy->phyreg_def[RF90_PATH_B].rfhssi_para1 = RFPGA0_XB_HSSIPARAMETER1; + + 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].rfswitch_control = + RFPGA0_XAB_SWITCHCONTROL; + rtlphy->phyreg_def[RF90_PATH_B].rfswitch_control = + RFPGA0_XAB_SWITCHCONTROL; + rtlphy->phyreg_def[RF90_PATH_C].rfswitch_control = + RFPGA0_XCD_SWITCHCONTROL; + rtlphy->phyreg_def[RF90_PATH_D].rfswitch_control = + RFPGA0_XCD_SWITCHCONTROL; + + rtlphy->phyreg_def[RF90_PATH_A].rfagc_control1 = ROFDM0_XAAGCCORE1; + rtlphy->phyreg_def[RF90_PATH_B].rfagc_control1 = ROFDM0_XBAGCCORE1; + rtlphy->phyreg_def[RF90_PATH_C].rfagc_control1 = ROFDM0_XCAGCCORE1; + rtlphy->phyreg_def[RF90_PATH_D].rfagc_control1 = ROFDM0_XDAGCCORE1; + + rtlphy->phyreg_def[RF90_PATH_A].rfagc_control2 = ROFDM0_XAAGCCORE2; + rtlphy->phyreg_def[RF90_PATH_B].rfagc_control2 = ROFDM0_XBAGCCORE2; + rtlphy->phyreg_def[RF90_PATH_C].rfagc_control2 = ROFDM0_XCAGCCORE2; + rtlphy->phyreg_def[RF90_PATH_D].rfagc_control2 = ROFDM0_XDAGCCORE2; + + rtlphy->phyreg_def[RF90_PATH_A].rfrxiq_imbalance = + ROFDM0_XARXIQIMBALANCE; + rtlphy->phyreg_def[RF90_PATH_B].rfrxiq_imbalance = + ROFDM0_XBRXIQIMBALANCE; + rtlphy->phyreg_def[RF90_PATH_C].rfrxiq_imbalance = + ROFDM0_XCRXIQIMBANLANCE; + rtlphy->phyreg_def[RF90_PATH_D].rfrxiq_imbalance = + ROFDM0_XDRXIQIMBALANCE; + + rtlphy->phyreg_def[RF90_PATH_A].rfrx_afe = ROFDM0_XARXAFE; + rtlphy->phyreg_def[RF90_PATH_B].rfrx_afe = ROFDM0_XBRXAFE; + rtlphy->phyreg_def[RF90_PATH_C].rfrx_afe = ROFDM0_XCRXAFE; + rtlphy->phyreg_def[RF90_PATH_D].rfrx_afe = ROFDM0_XDRXAFE; + + rtlphy->phyreg_def[RF90_PATH_A].rftxiq_imbalance = + ROFDM0_XATXIQIMBALANCE; + rtlphy->phyreg_def[RF90_PATH_B].rftxiq_imbalance = + ROFDM0_XBTXIQIMBALANCE; + rtlphy->phyreg_def[RF90_PATH_C].rftxiq_imbalance = + ROFDM0_XCTXIQIMBALANCE; + rtlphy->phyreg_def[RF90_PATH_D].rftxiq_imbalance = + ROFDM0_XDTXIQIMBALANCE; + + rtlphy->phyreg_def[RF90_PATH_A].rftx_afe = ROFDM0_XATXAFE; + rtlphy->phyreg_def[RF90_PATH_B].rftx_afe = ROFDM0_XBTXAFE; + rtlphy->phyreg_def[RF90_PATH_C].rftx_afe = ROFDM0_XCTXAFE; + rtlphy->phyreg_def[RF90_PATH_D].rftx_afe = ROFDM0_XDTXAFE; + + 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_C].rflssi_readback = + RFPGA0_XC_LSSIREADBACK; + rtlphy->phyreg_def[RF90_PATH_D].rflssi_readback = + RFPGA0_XD_LSSIREADBACK; + + rtlphy->phyreg_def[RF90_PATH_A].rflssi_readbackpi = + TRANSCEIVEA_HSPI_READBACK; + rtlphy->phyreg_def[RF90_PATH_B].rflssi_readbackpi = + TRANSCEIVEB_HSPI_READBACK; + +} +EXPORT_SYMBOL(_rtl92c_phy_init_bb_rf_register_definition); + +void rtl92c_phy_get_txpower_level(struct ieee80211_hw *hw, long *powerlevel) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + u8 txpwr_level; + long txpwr_dbm; + + txpwr_level = rtlphy->cur_cck_txpwridx; + txpwr_dbm = _rtl92c_phy_txpwr_idx_to_dbm(hw, + WIRELESS_MODE_B, txpwr_level); + txpwr_level = rtlphy->cur_ofdm24g_txpwridx + + rtlefuse->legacy_ht_txpowerdiff; + if (_rtl92c_phy_txpwr_idx_to_dbm(hw, + WIRELESS_MODE_G, + txpwr_level) > txpwr_dbm) + txpwr_dbm = + _rtl92c_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_G, + txpwr_level); + txpwr_level = rtlphy->cur_ofdm24g_txpwridx; + if (_rtl92c_phy_txpwr_idx_to_dbm(hw, + WIRELESS_MODE_N_24G, + txpwr_level) > txpwr_dbm) + txpwr_dbm = + _rtl92c_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_N_24G, + txpwr_level); + *powerlevel = txpwr_dbm; +} + +static void _rtl92c_get_txpower_index(struct ieee80211_hw *hw, u8 channel, + u8 *cckpowerlevel, u8 *ofdmpowerlevel) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + u8 index = (channel - 1); + + cckpowerlevel[RF90_PATH_A] = + rtlefuse->txpwrlevel_cck[RF90_PATH_A][index]; + cckpowerlevel[RF90_PATH_B] = + rtlefuse->txpwrlevel_cck[RF90_PATH_B][index]; + if (get_rf_type(rtlphy) == RF_1T2R || get_rf_type(rtlphy) == RF_1T1R) { + ofdmpowerlevel[RF90_PATH_A] = + rtlefuse->txpwrlevel_ht40_1s[RF90_PATH_A][index]; + ofdmpowerlevel[RF90_PATH_B] = + rtlefuse->txpwrlevel_ht40_1s[RF90_PATH_B][index]; + } else if (get_rf_type(rtlphy) == RF_2T2R) { + ofdmpowerlevel[RF90_PATH_A] = + rtlefuse->txpwrlevel_ht40_2s[RF90_PATH_A][index]; + ofdmpowerlevel[RF90_PATH_B] = + rtlefuse->txpwrlevel_ht40_2s[RF90_PATH_B][index]; + } +} + +static void _rtl92c_ccxpower_index_check(struct ieee80211_hw *hw, + u8 channel, u8 *cckpowerlevel, + u8 *ofdmpowerlevel) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + + rtlphy->cur_cck_txpwridx = cckpowerlevel[0]; + rtlphy->cur_ofdm24g_txpwridx = ofdmpowerlevel[0]; + +} + +void rtl92c_phy_set_txpower_level(struct ieee80211_hw *hw, u8 channel) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_efuse *rtlefuse = rtl_efuse(rtlpriv); + u8 cckpowerlevel[2], ofdmpowerlevel[2]; + + if (!rtlefuse->txpwr_fromeprom) + return; + _rtl92c_get_txpower_index(hw, channel, + &cckpowerlevel[0], &ofdmpowerlevel[0]); + _rtl92c_ccxpower_index_check(hw, + channel, &cckpowerlevel[0], + &ofdmpowerlevel[0]); + rtlpriv->cfg->ops->phy_rf6052_set_cck_txpower(hw, &cckpowerlevel[0]); + rtlpriv->cfg->ops->phy_rf6052_set_ofdm_txpower(hw, &ofdmpowerlevel[0], + channel); +} +EXPORT_SYMBOL(rtl92c_phy_set_txpower_level); + +bool rtl92c_phy_update_txpower_dbm(struct ieee80211_hw *hw, long power_indbm) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + u8 idx; + u8 rf_path; + u8 ccktxpwridx = _rtl92c_phy_dbm_to_txpwr_Idx(hw, + WIRELESS_MODE_B, + power_indbm); + u8 ofdmtxpwridx = _rtl92c_phy_dbm_to_txpwr_Idx(hw, + WIRELESS_MODE_N_24G, + power_indbm); + if (ofdmtxpwridx - rtlefuse->legacy_ht_txpowerdiff > 0) + ofdmtxpwridx -= rtlefuse->legacy_ht_txpowerdiff; + else + ofdmtxpwridx = 0; + RT_TRACE(rtlpriv, COMP_TXAGC, DBG_TRACE, + "%lx dBm, ccktxpwridx = %d, ofdmtxpwridx = %d\n", + power_indbm, ccktxpwridx, ofdmtxpwridx); + for (idx = 0; idx < 14; idx++) { + for (rf_path = 0; rf_path < 2; rf_path++) { + rtlefuse->txpwrlevel_cck[rf_path][idx] = ccktxpwridx; + rtlefuse->txpwrlevel_ht40_1s[rf_path][idx] = + ofdmtxpwridx; + rtlefuse->txpwrlevel_ht40_2s[rf_path][idx] = + ofdmtxpwridx; + } + } + rtl92c_phy_set_txpower_level(hw, rtlphy->current_channel); + return true; +} +EXPORT_SYMBOL(rtl92c_phy_update_txpower_dbm); + +u8 _rtl92c_phy_dbm_to_txpwr_Idx(struct ieee80211_hw *hw, + enum wireless_mode wirelessmode, + long power_indbm) +{ + u8 txpwridx; + long offset; + + 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; + } + + if ((power_indbm - offset) > 0) + txpwridx = (u8) ((power_indbm - offset) * 2); + else + txpwridx = 0; + + if (txpwridx > MAX_TXPWR_IDX_NMODE_92S) + txpwridx = MAX_TXPWR_IDX_NMODE_92S; + + return txpwridx; +} +EXPORT_SYMBOL(_rtl92c_phy_dbm_to_txpwr_Idx); + +long _rtl92c_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; +} +EXPORT_SYMBOL(_rtl92c_phy_txpwr_idx_to_dbm); + +void rtl92c_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: + iotype = IO_CMD_PAUSE_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(rtlpriv, COMP_ERR, DBG_EMERG, + "Unknown Scan Backup operation\n"); + break; + } + } +} +EXPORT_SYMBOL(rtl92c_phy_scan_operation_backup); + +void rtl92c_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))) { + rtlpriv->cfg->ops->phy_set_bw_mode_callback(hw); + } else { + RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, + "FALSE driver sleep or unload\n"); + rtlphy->set_bwmode_inprogress = false; + rtlphy->current_chan_bw = tmp_bw; + } +} +EXPORT_SYMBOL(rtl92c_phy_set_bw_mode); + +void rtl92c_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(rtlpriv, 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 (!_rtl92c_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(rtlpriv, COMP_SCAN, DBG_TRACE, "<==\n"); +} +EXPORT_SYMBOL(rtl92c_phy_sw_chnl_callback); + +u8 rtl92c_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\n"); + rtlphy->sw_chnl_inprogress = true; + rtlphy->sw_chnl_stage = 0; + rtlphy->sw_chnl_step = 0; + if (!(is_hal_stop(rtlhal)) && !(RT_CANNOT_IO(hw))) { + rtl92c_phy_sw_chnl_callback(hw); + RT_TRACE(rtlpriv, COMP_CHAN, DBG_LOUD, + "sw_chnl_inprogress false schdule workitem\n"); + rtlphy->sw_chnl_inprogress = false; + } else { + RT_TRACE(rtlpriv, COMP_CHAN, DBG_LOUD, + "sw_chnl_inprogress false driver sleep or unload\n"); + rtlphy->sw_chnl_inprogress = false; + } + return 1; +} +EXPORT_SYMBOL(rtl92c_phy_sw_chnl); + +static bool _rtl92c_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; +} + +bool _rtl92c_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; + _rtl92c_phy_set_sw_chnl_cmdarray(precommoncmd, precommoncmdcnt++, + MAX_PRECMD_CNT, + CMDID_SET_TXPOWEROWER_LEVEL, 0, 0, 0); + _rtl92c_phy_set_sw_chnl_cmdarray(precommoncmd, precommoncmdcnt++, + MAX_PRECMD_CNT, CMDID_END, 0, 0, 0); + + postcommoncmdcnt = 0; + + _rtl92c_phy_set_sw_chnl_cmdarray(postcommoncmd, postcommoncmdcnt++, + MAX_POSTCMD_CNT, CMDID_END, 0, 0, 0); + + rfdependcmdcnt = 0; + + RT_ASSERT((channel >= 1 && channel <= 14), + "invalid channel for Zebra: %d\n", channel); + + _rtl92c_phy_set_sw_chnl_cmdarray(rfdependcmd, rfdependcmdcnt++, + MAX_RFDEPENDCMD_CNT, CMDID_RF_WRITEREG, + RF_CHNLBW, channel, 10); + + _rtl92c_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; + } + + if (currentcmd->cmdid == CMDID_END) { + if ((*stage) == 2) { + return true; + } else { + (*stage)++; + (*step) = 0; + continue; + } + } + + switch (currentcmd->cmdid) { + case CMDID_SET_TXPOWEROWER_LEVEL: + rtl92c_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] & + 0xfffffc00) | currentcmd->para2); + + rtl_set_rfreg(hw, (enum radio_path)rfpath, + currentcmd->para1, + RFREG_OFFSET_MASK, + rtlphy->rfreg_chnlval[rfpath]); + } + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "switch case not processed\n"); + break; + } + + break; + } while (true); + + (*delay) = currentcmd->msdelay; + (*step)++; + return false; +} + +bool rtl8192_phy_check_is_legal_rfpath(struct ieee80211_hw *hw, u32 rfpath) +{ + return true; +} +EXPORT_SYMBOL(rtl8192_phy_check_is_legal_rfpath); + +static u8 _rtl92c_phy_path_a_iqk(struct ieee80211_hw *hw, bool config_pathb) +{ + u32 reg_eac, reg_e94, reg_e9c, reg_ea4; + u8 result = 0x00; + + rtl_set_bbreg(hw, 0xe30, MASKDWORD, 0x10008c1f); + rtl_set_bbreg(hw, 0xe34, MASKDWORD, 0x10008c1f); + rtl_set_bbreg(hw, 0xe38, MASKDWORD, 0x82140102); + rtl_set_bbreg(hw, 0xe3c, MASKDWORD, + config_pathb ? 0x28160202 : 0x28160502); + + if (config_pathb) { + rtl_set_bbreg(hw, 0xe50, MASKDWORD, 0x10008c22); + rtl_set_bbreg(hw, 0xe54, MASKDWORD, 0x10008c22); + rtl_set_bbreg(hw, 0xe58, MASKDWORD, 0x82140102); + rtl_set_bbreg(hw, 0xe5c, MASKDWORD, 0x28160202); + } + + rtl_set_bbreg(hw, 0xe4c, MASKDWORD, 0x001028d1); + rtl_set_bbreg(hw, 0xe48, MASKDWORD, 0xf9000000); + rtl_set_bbreg(hw, 0xe48, 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); + reg_ea4 = rtl_get_bbreg(hw, 0xea4, MASKDWORD); + + if (!(reg_eac & BIT(28)) && + (((reg_e94 & 0x03FF0000) >> 16) != 0x142) && + (((reg_e9c & 0x03FF0000) >> 16) != 0x42)) + result |= 0x01; + else + return result; + + if (!(reg_eac & BIT(27)) && + (((reg_ea4 & 0x03FF0000) >> 16) != 0x132) && + (((reg_eac & 0x03FF0000) >> 16) != 0x36)) + result |= 0x02; + return result; +} + +static u8 _rtl92c_phy_path_b_iqk(struct ieee80211_hw *hw) +{ + u32 reg_eac, reg_eb4, reg_ebc, reg_ec4, reg_ecc; + u8 result = 0x00; + + rtl_set_bbreg(hw, 0xe60, MASKDWORD, 0x00000002); + rtl_set_bbreg(hw, 0xe60, MASKDWORD, 0x00000000); + 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); + reg_ec4 = rtl_get_bbreg(hw, 0xec4, MASKDWORD); + reg_ecc = rtl_get_bbreg(hw, 0xecc, MASKDWORD); + + if (!(reg_eac & BIT(31)) && + (((reg_eb4 & 0x03FF0000) >> 16) != 0x142) && + (((reg_ebc & 0x03FF0000) >> 16) != 0x42)) + result |= 0x01; + else + return result; + if (!(reg_eac & BIT(30)) && + (((reg_ec4 & 0x03FF0000) >> 16) != 0x132) && + (((reg_ecc & 0x03FF0000) >> 16) != 0x36)) + result |= 0x02; + return result; +} + +static void _rtl92c_phy_path_a_fill_iqk_matrix(struct ieee80211_hw *hw, + bool 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 (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, 0xca0, 0xF0000000, reg); + } +} + +static void _rtl92c_phy_path_b_fill_iqk_matrix(struct ieee80211_hw *hw, + bool 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 (iqk_ok) { + oldval_1 = (rtl_get_bbreg(hw, ROFDM0_XBTXIQIMBALANCE, + 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_XBTXIQIMBALANCE, 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, 0x0000F000, reg); + } +} + +static void _rtl92c_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 _rtl92c_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 _rtl92c_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 _rtl92c_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 _rtl92c_phy_path_adda_on(struct ieee80211_hw *hw, + u32 *addareg, bool is_patha_on, bool is2t) +{ + u32 pathOn; + u32 i; + + pathOn = is_patha_on ? 0x04db25a4 : 0x0b1b25a4; + if (false == is2t) { + pathOn = 0x0bdb25a0; + rtl_set_bbreg(hw, addareg[0], MASKDWORD, 0x0b1b25a0); + } 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 _rtl92c_phy_mac_setting_calibration(struct ieee80211_hw *hw, + u32 *macreg, u32 *macbackup) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 i; + + rtl_write_byte(rtlpriv, macreg[0], 0x3F); + + for (i = 1; i < (IQK_MAC_REG_NUM - 1); i++) + rtl_write_byte(rtlpriv, macreg[i], + (u8) (macbackup[i] & (~BIT(3)))); + rtl_write_byte(rtlpriv, macreg[i], (u8) (macbackup[i] & (~BIT(5)))); +} + +static void _rtl92c_phy_path_a_standby(struct ieee80211_hw *hw) +{ + rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0x0); + rtl_set_bbreg(hw, 0x840, MASKDWORD, 0x00010000); + rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0x80800000); +} + +static void _rtl92c_phy_pi_mode_switch(struct ieee80211_hw *hw, bool pi_mode) +{ + u32 mode; + + mode = pi_mode ? 0x01000100 : 0x01000000; + rtl_set_bbreg(hw, 0x820, MASKDWORD, mode); + rtl_set_bbreg(hw, 0x828, MASKDWORD, mode); +} + +static bool _rtl92c_phy_simularity_compare(struct ieee80211_hw *hw, + long result[][8], u8 c1, u8 c2) +{ + u32 i, j, diff, simularity_bitmap, bound; + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + + u8 final_candidate[2] = { 0xFF, 0xFF }; + bool bresult = true, is2t = IS_92C_SERIAL(rtlhal->version); + + if (is2t) + bound = 8; + else + bound = 4; + + simularity_bitmap = 0; + + for (i = 0; i < bound; i++) { + diff = (result[c1][i] > result[c2][i]) ? + (result[c1][i] - result[c2][i]) : + (result[c2][i] - result[c1][i]); + + 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 = simularity_bitmap | + (1 << i); + } else + simularity_bitmap = + 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 & 0x0F)) { + for (i = 0; i < 4; i++) + result[3][i] = result[c1][i]; + return false; + } else if (!(simularity_bitmap & 0xF0) && is2t) { + for (i = 4; i < 8; i++) + result[3][i] = result[c1][i]; + return false; + } else { + return false; + } + +} + +static void _rtl92c_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; + 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 + }; + + const u32 retrycount = 2; + + if (t == 0) { + /* dummy read */ + rtl_get_bbreg(hw, 0x800, MASKDWORD); + + _rtl92c_phy_save_adda_registers(hw, adda_reg, + rtlphy->adda_backup, 16); + _rtl92c_phy_save_mac_registers(hw, iqk_mac_reg, + rtlphy->iqk_mac_backup); + } + _rtl92c_phy_path_adda_on(hw, adda_reg, true, is2t); + if (t == 0) { + rtlphy->rfpi_enable = (u8) rtl_get_bbreg(hw, + RFPGA0_XA_HSSIPARAMETER1, + BIT(8)); + } + + if (!rtlphy->rfpi_enable) + _rtl92c_phy_pi_mode_switch(hw, true); + if (t == 0) { + rtlphy->reg_c04 = rtl_get_bbreg(hw, 0xc04, MASKDWORD); + rtlphy->reg_c08 = rtl_get_bbreg(hw, 0xc08, MASKDWORD); + rtlphy->reg_874 = rtl_get_bbreg(hw, 0x874, MASKDWORD); + } + rtl_set_bbreg(hw, 0xc04, MASKDWORD, 0x03a05600); + rtl_set_bbreg(hw, 0xc08, MASKDWORD, 0x000800e4); + rtl_set_bbreg(hw, 0x874, MASKDWORD, 0x22204000); + if (is2t) { + rtl_set_bbreg(hw, 0x840, MASKDWORD, 0x00010000); + rtl_set_bbreg(hw, 0x844, MASKDWORD, 0x00010000); + } + _rtl92c_phy_mac_setting_calibration(hw, iqk_mac_reg, + rtlphy->iqk_mac_backup); + rtl_set_bbreg(hw, 0xb68, MASKDWORD, 0x00080000); + if (is2t) + rtl_set_bbreg(hw, 0xb6c, MASKDWORD, 0x00080000); + rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0x80800000); + rtl_set_bbreg(hw, 0xe40, MASKDWORD, 0x01007c00); + rtl_set_bbreg(hw, 0xe44, MASKDWORD, 0x01004800); + for (i = 0; i < retrycount; i++) { + patha_ok = _rtl92c_phy_path_a_iqk(hw, is2t); + if (patha_ok == 0x03) { + result[t][0] = (rtl_get_bbreg(hw, 0xe94, MASKDWORD) & + 0x3FF0000) >> 16; + result[t][1] = (rtl_get_bbreg(hw, 0xe9c, MASKDWORD) & + 0x3FF0000) >> 16; + result[t][2] = (rtl_get_bbreg(hw, 0xea4, MASKDWORD) & + 0x3FF0000) >> 16; + result[t][3] = (rtl_get_bbreg(hw, 0xeac, MASKDWORD) & + 0x3FF0000) >> 16; + break; + } else if (i == (retrycount - 1) && patha_ok == 0x01) + + result[t][0] = (rtl_get_bbreg(hw, 0xe94, + MASKDWORD) & 0x3FF0000) >> + 16; + result[t][1] = + (rtl_get_bbreg(hw, 0xe9c, MASKDWORD) & 0x3FF0000) >> 16; + + } + + if (is2t) { + _rtl92c_phy_path_a_standby(hw); + _rtl92c_phy_path_adda_on(hw, adda_reg, false, is2t); + for (i = 0; i < retrycount; i++) { + pathb_ok = _rtl92c_phy_path_b_iqk(hw); + if (pathb_ok == 0x03) { + result[t][4] = (rtl_get_bbreg(hw, + 0xeb4, + MASKDWORD) & + 0x3FF0000) >> 16; + result[t][5] = + (rtl_get_bbreg(hw, 0xebc, MASKDWORD) & + 0x3FF0000) >> 16; + result[t][6] = + (rtl_get_bbreg(hw, 0xec4, MASKDWORD) & + 0x3FF0000) >> 16; + result[t][7] = + (rtl_get_bbreg(hw, 0xecc, MASKDWORD) & + 0x3FF0000) >> 16; + break; + } else if (i == (retrycount - 1) && pathb_ok == 0x01) { + result[t][4] = (rtl_get_bbreg(hw, + 0xeb4, + MASKDWORD) & + 0x3FF0000) >> 16; + } + result[t][5] = (rtl_get_bbreg(hw, 0xebc, MASKDWORD) & + 0x3FF0000) >> 16; + } + } + rtl_set_bbreg(hw, 0xc04, MASKDWORD, rtlphy->reg_c04); + rtl_set_bbreg(hw, 0x874, MASKDWORD, rtlphy->reg_874); + rtl_set_bbreg(hw, 0xc08, MASKDWORD, rtlphy->reg_c08); + rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0); + rtl_set_bbreg(hw, 0x840, MASKDWORD, 0x00032ed3); + if (is2t) + rtl_set_bbreg(hw, 0x844, MASKDWORD, 0x00032ed3); + if (t != 0) { + if (!rtlphy->rfpi_enable) + _rtl92c_phy_pi_mode_switch(hw, false); + _rtl92c_phy_reload_adda_registers(hw, adda_reg, + rtlphy->adda_backup, 16); + _rtl92c_phy_reload_mac_registers(hw, iqk_mac_reg, + rtlphy->iqk_mac_backup); + } +} + +static void _rtl92c_phy_ap_calibrate(struct ieee80211_hw *hw, + char delta, bool is2t) +{ +#if 0 /* This routine is deliberately dummied out for later fixes */ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + + u32 reg_d[PATH_NUM]; + u32 tmpreg, index, offset, path, i, pathbound = PATH_NUM, apkbound; + + u32 bb_backup[APK_BB_REG_NUM]; + u32 bb_reg[APK_BB_REG_NUM] = { + 0x904, 0xc04, 0x800, 0xc08, 0x874 + }; + u32 bb_ap_mode[APK_BB_REG_NUM] = { + 0x00000020, 0x00a05430, 0x02040000, + 0x000800e4, 0x00204000 + }; + u32 bb_normal_ap_mode[APK_BB_REG_NUM] = { + 0x00000020, 0x00a05430, 0x02040000, + 0x000800e4, 0x22204000 + }; + + u32 afe_backup[APK_AFE_REG_NUM]; + u32 afe_reg[APK_AFE_REG_NUM] = { + 0x85c, 0xe6c, 0xe70, 0xe74, 0xe78, + 0xe7c, 0xe80, 0xe84, 0xe88, 0xe8c, + 0xed0, 0xed4, 0xed8, 0xedc, 0xee0, + 0xeec + }; + + u32 mac_backup[IQK_MAC_REG_NUM]; + u32 mac_reg[IQK_MAC_REG_NUM] = { + 0x522, 0x550, 0x551, 0x040 + }; + + u32 apk_rf_init_value[PATH_NUM][APK_BB_REG_NUM] = { + {0x0852c, 0x1852c, 0x5852c, 0x1852c, 0x5852c}, + {0x2852e, 0x0852e, 0x3852e, 0x0852e, 0x0852e} + }; + + u32 apk_normal_rf_init_value[PATH_NUM][APK_BB_REG_NUM] = { + {0x0852c, 0x0a52c, 0x3a52c, 0x5a52c, 0x5a52c}, + {0x0852c, 0x0a52c, 0x5a52c, 0x5a52c, 0x5a52c} + }; + + u32 apk_rf_value_0[PATH_NUM][APK_BB_REG_NUM] = { + {0x52019, 0x52014, 0x52013, 0x5200f, 0x5208d}, + {0x5201a, 0x52019, 0x52016, 0x52033, 0x52050} + }; + + u32 apk_normal_rf_value_0[PATH_NUM][APK_BB_REG_NUM] = { + {0x52019, 0x52017, 0x52010, 0x5200d, 0x5206a}, + {0x52019, 0x52017, 0x52010, 0x5200d, 0x5206a} + }; + + u32 afe_on_off[PATH_NUM] = { + 0x04db25a4, 0x0b1b25a4 + }; + + const u32 apk_offset[PATH_NUM] = { 0xb68, 0xb6c }; + + u32 apk_normal_offset[PATH_NUM] = { 0xb28, 0xb98 }; + + u32 apk_value[PATH_NUM] = { 0x92fc0000, 0x12fc0000 }; + + u32 apk_normal_value[PATH_NUM] = { 0x92680000, 0x12680000 }; + + const char apk_delta_mapping[APK_BB_REG_NUM][13] = { + {-4, -3, -2, -2, -1, -1, 0, 1, 2, 3, 4, 5, 6}, + {-4, -3, -2, -2, -1, -1, 0, 1, 2, 3, 4, 5, 6}, + {-6, -4, -2, -2, -1, -1, 0, 1, 2, 3, 4, 5, 6}, + {-1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6}, + {-11, -9, -7, -5, -3, -1, 0, 0, 0, 0, 0, 0, 0} + }; + + const u32 apk_normal_setting_value_1[13] = { + 0x01017018, 0xf7ed8f84, 0x1b1a1816, 0x2522201e, 0x322e2b28, + 0x433f3a36, 0x5b544e49, 0x7b726a62, 0xa69a8f84, 0xdfcfc0b3, + 0x12680000, 0x00880000, 0x00880000 + }; + + const u32 apk_normal_setting_value_2[16] = { + 0x01c7021d, 0x01670183, 0x01000123, 0x00bf00e2, 0x008d00a3, + 0x0068007b, 0x004d0059, 0x003a0042, 0x002b0031, 0x001f0025, + 0x0017001b, 0x00110014, 0x000c000f, 0x0009000b, 0x00070008, + 0x00050006 + }; + + u32 apk_result[PATH_NUM][APK_BB_REG_NUM]; + + long bb_offset, delta_v, delta_offset; + + if (!is2t) + pathbound = 1; + + return; + + for (index = 0; index < PATH_NUM; index++) { + apk_offset[index] = apk_normal_offset[index]; + apk_value[index] = apk_normal_value[index]; + afe_on_off[index] = 0x6fdb25a4; + } + + for (index = 0; index < APK_BB_REG_NUM; index++) { + for (path = 0; path < pathbound; path++) { + apk_rf_init_value[path][index] = + apk_normal_rf_init_value[path][index]; + apk_rf_value_0[path][index] = + apk_normal_rf_value_0[path][index]; + } + bb_ap_mode[index] = bb_normal_ap_mode[index]; + + apkbound = 6; + } + + for (index = 0; index < APK_BB_REG_NUM; index++) { + if (index == 0) + continue; + bb_backup[index] = rtl_get_bbreg(hw, bb_reg[index], MASKDWORD); + } + + _rtl92c_phy_save_mac_registers(hw, mac_reg, mac_backup); + + _rtl92c_phy_save_adda_registers(hw, afe_reg, afe_backup, 16); + + for (path = 0; path < pathbound; path++) { + if (path == RF90_PATH_A) { + offset = 0xb00; + for (index = 0; index < 11; index++) { + rtl_set_bbreg(hw, offset, MASKDWORD, + apk_normal_setting_value_1 + [index]); + + offset += 0x04; + } + + rtl_set_bbreg(hw, 0xb98, MASKDWORD, 0x12680000); + + offset = 0xb68; + for (; index < 13; index++) { + rtl_set_bbreg(hw, offset, MASKDWORD, + apk_normal_setting_value_1 + [index]); + + offset += 0x04; + } + + rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0x40000000); + + offset = 0xb00; + for (index = 0; index < 16; index++) { + rtl_set_bbreg(hw, offset, MASKDWORD, + apk_normal_setting_value_2 + [index]); + + offset += 0x04; + } + rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0x00000000); + } else if (path == RF90_PATH_B) { + offset = 0xb70; + for (index = 0; index < 10; index++) { + rtl_set_bbreg(hw, offset, MASKDWORD, + apk_normal_setting_value_1 + [index]); + + offset += 0x04; + } + rtl_set_bbreg(hw, 0xb28, MASKDWORD, 0x12680000); + rtl_set_bbreg(hw, 0xb98, MASKDWORD, 0x12680000); + + offset = 0xb68; + index = 11; + for (; index < 13; index++) { + rtl_set_bbreg(hw, offset, MASKDWORD, + apk_normal_setting_value_1 + [index]); + + offset += 0x04; + } + + rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0x40000000); + + offset = 0xb60; + for (index = 0; index < 16; index++) { + rtl_set_bbreg(hw, offset, MASKDWORD, + apk_normal_setting_value_2 + [index]); + + offset += 0x04; + } + rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0x00000000); + } + + reg_d[path] = rtl_get_rfreg(hw, (enum radio_path)path, + 0xd, MASKDWORD); + + for (index = 0; index < APK_AFE_REG_NUM; index++) + rtl_set_bbreg(hw, afe_reg[index], MASKDWORD, + afe_on_off[path]); + + if (path == RF90_PATH_A) { + for (index = 0; index < APK_BB_REG_NUM; index++) { + if (index == 0) + continue; + rtl_set_bbreg(hw, bb_reg[index], MASKDWORD, + bb_ap_mode[index]); + } + } + + _rtl92c_phy_mac_setting_calibration(hw, mac_reg, mac_backup); + + if (path == 0) { + rtl_set_rfreg(hw, RF90_PATH_B, 0x0, MASKDWORD, 0x10000); + } else { + rtl_set_rfreg(hw, RF90_PATH_A, 0x00, MASKDWORD, + 0x10000); + rtl_set_rfreg(hw, RF90_PATH_A, 0x10, MASKDWORD, + 0x1000f); + rtl_set_rfreg(hw, RF90_PATH_A, 0x11, MASKDWORD, + 0x20103); + } + + delta_offset = ((delta + 14) / 2); + if (delta_offset < 0) + delta_offset = 0; + else if (delta_offset > 12) + delta_offset = 12; + + for (index = 0; index < APK_BB_REG_NUM; index++) { + if (index != 1) + continue; + + tmpreg = apk_rf_init_value[path][index]; + + if (!rtlefuse->apk_thermalmeterignore) { + bb_offset = (tmpreg & 0xF0000) >> 16; + + if (!(tmpreg & BIT(15))) + bb_offset = -bb_offset; + + delta_v = + apk_delta_mapping[index][delta_offset]; + + bb_offset += delta_v; + + if (bb_offset < 0) { + tmpreg = tmpreg & (~BIT(15)); + bb_offset = -bb_offset; + } else { + tmpreg = tmpreg | BIT(15); + } + + tmpreg = + (tmpreg & 0xFFF0FFFF) | (bb_offset << 16); + } + + rtl_set_rfreg(hw, (enum radio_path)path, 0xc, + MASKDWORD, 0x8992e); + rtl_set_rfreg(hw, (enum radio_path)path, 0x0, + MASKDWORD, apk_rf_value_0[path][index]); + rtl_set_rfreg(hw, (enum radio_path)path, 0xd, + MASKDWORD, tmpreg); + + i = 0; + do { + rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0x80000000); + rtl_set_bbreg(hw, apk_offset[path], + MASKDWORD, apk_value[0]); + RTPRINT(rtlpriv, FINIT, INIT_IQK, + ("PHY_APCalibrate() offset 0x%x " + "value 0x%x\n", + apk_offset[path], + rtl_get_bbreg(hw, apk_offset[path], + MASKDWORD))); + + mdelay(3); + + rtl_set_bbreg(hw, apk_offset[path], + MASKDWORD, apk_value[1]); + RTPRINT(rtlpriv, FINIT, INIT_IQK, + ("PHY_APCalibrate() offset 0x%x " + "value 0x%x\n", + apk_offset[path], + rtl_get_bbreg(hw, apk_offset[path], + MASKDWORD))); + + mdelay(20); + + rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0x00000000); + + if (path == RF90_PATH_A) + tmpreg = rtl_get_bbreg(hw, 0xbd8, + 0x03E00000); + else + tmpreg = rtl_get_bbreg(hw, 0xbd8, + 0xF8000000); + + RTPRINT(rtlpriv, FINIT, INIT_IQK, + ("PHY_APCalibrate() offset " + "0xbd8[25:21] %x\n", tmpreg)); + + i++; + + } while (tmpreg > apkbound && i < 4); + + apk_result[path][index] = tmpreg; + } + } + + _rtl92c_phy_reload_mac_registers(hw, mac_reg, mac_backup); + + for (index = 0; index < APK_BB_REG_NUM; index++) { + if (index == 0) + continue; + rtl_set_bbreg(hw, bb_reg[index], MASKDWORD, bb_backup[index]); + } + + _rtl92c_phy_reload_adda_registers(hw, afe_reg, afe_backup, 16); + + for (path = 0; path < pathbound; path++) { + rtl_set_rfreg(hw, (enum radio_path)path, 0xd, + MASKDWORD, reg_d[path]); + + if (path == RF90_PATH_B) { + rtl_set_rfreg(hw, RF90_PATH_A, 0x10, MASKDWORD, + 0x1000f); + rtl_set_rfreg(hw, RF90_PATH_A, 0x11, MASKDWORD, + 0x20101); + } + + if (apk_result[path][1] > 6) + apk_result[path][1] = 6; + } + + for (path = 0; path < pathbound; path++) { + rtl_set_rfreg(hw, (enum radio_path)path, 0x3, MASKDWORD, + ((apk_result[path][1] << 15) | + (apk_result[path][1] << 10) | + (apk_result[path][1] << 5) | + apk_result[path][1])); + + if (path == RF90_PATH_A) + rtl_set_rfreg(hw, (enum radio_path)path, 0x4, MASKDWORD, + ((apk_result[path][1] << 15) | + (apk_result[path][1] << 10) | + (0x00 << 5) | 0x05)); + else + rtl_set_rfreg(hw, (enum radio_path)path, 0x4, MASKDWORD, + ((apk_result[path][1] << 15) | + (apk_result[path][1] << 10) | + (0x02 << 5) | 0x05)); + + rtl_set_rfreg(hw, (enum radio_path)path, 0xe, MASKDWORD, + ((0x08 << 15) | (0x08 << 10) | (0x08 << 5) | + 0x08)); + + } + rtlphy->b_apk_done = true; +#endif +} + +static void _rtl92c_phy_set_rfpath_switch(struct ieee80211_hw *hw, + bool bmain, bool is2t) +{ + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + + if (is_hal_stop(rtlhal)) { + rtl_set_bbreg(hw, REG_LEDCFG0, BIT(23), 0x01); + 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 { + if (bmain) + rtl_set_bbreg(hw, RFPGA0_XA_RFINTERFACEOE, 0x300, 0x2); + else + rtl_set_bbreg(hw, RFPGA0_XA_RFINTERFACEOE, 0x300, 0x1); + + } + +} + +#undef IQK_ADDA_REG_NUM +#undef IQK_DELAY_TIME + +void rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw, bool recovery) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + + long result[4][8]; + u8 i, final_candidate; + bool patha_ok, pathb_ok; + long reg_e94, reg_e9c, reg_ea4, reg_eb4, reg_ebc, reg_ec4, reg_tmp = 0; + bool is12simular, is13simular, is23simular; + bool start_conttx = false, singletone = false; + u32 iqk_bb_reg[10] = { + ROFDM0_XARXIQIMBALANCE, + ROFDM0_XBRXIQIMBALANCE, + ROFDM0_ECCATHRESHOLD, + ROFDM0_AGCRSSITABLE, + ROFDM0_XATXIQIMBALANCE, + ROFDM0_XBTXIQIMBALANCE, + ROFDM0_XCTXIQIMBALANCE, + ROFDM0_XCTXAFE, + ROFDM0_XDTXAFE, + ROFDM0_RXIQEXTANTA + }; + + if (recovery) { + _rtl92c_phy_reload_adda_registers(hw, + iqk_bb_reg, + rtlphy->iqk_bb_backup, 10); + return; + } + if (start_conttx || singletone) + return; + for (i = 0; i < 8; i++) { + result[0][i] = 0; + result[1][i] = 0; + result[2][i] = 0; + result[3][i] = 0; + } + final_candidate = 0xff; + patha_ok = false; + pathb_ok = false; + is12simular = false; + is23simular = false; + is13simular = false; + for (i = 0; i < 3; i++) { + if (IS_92C_SERIAL(rtlhal->version)) + _rtl92c_phy_iq_calibrate(hw, result, i, true); + else + _rtl92c_phy_iq_calibrate(hw, result, i, false); + if (i == 1) { + is12simular = _rtl92c_phy_simularity_compare(hw, + result, 0, + 1); + if (is12simular) { + final_candidate = 0; + break; + } + } + if (i == 2) { + is13simular = _rtl92c_phy_simularity_compare(hw, + result, 0, + 2); + if (is13simular) { + final_candidate = 0; + break; + } + is23simular = _rtl92c_phy_simularity_compare(hw, + result, 1, + 2); + if (is23simular) + final_candidate = 1; + else { + for (i = 0; i < 8; i++) + reg_tmp += result[3][i]; + + if (reg_tmp != 0) + final_candidate = 3; + else + final_candidate = 0xFF; + } + } + } + for (i = 0; i < 4; i++) { + reg_e94 = result[i][0]; + reg_e9c = result[i][1]; + reg_ea4 = result[i][2]; + reg_eb4 = result[i][4]; + reg_ebc = result[i][5]; + reg_ec4 = result[i][6]; + } + if (final_candidate != 0xff) { + rtlphy->reg_e94 = reg_e94 = result[final_candidate][0]; + rtlphy->reg_e9c = reg_e9c = result[final_candidate][1]; + reg_ea4 = result[final_candidate][2]; + rtlphy->reg_eb4 = reg_eb4 = result[final_candidate][4]; + rtlphy->reg_ebc = reg_ebc = result[final_candidate][5]; + reg_ec4 = result[final_candidate][6]; + patha_ok = pathb_ok = true; + } else { + rtlphy->reg_e94 = rtlphy->reg_eb4 = 0x100; + rtlphy->reg_e9c = rtlphy->reg_ebc = 0x0; + } + if (reg_e94 != 0) /*&&(reg_ea4 != 0) */ + _rtl92c_phy_path_a_fill_iqk_matrix(hw, patha_ok, result, + final_candidate, + (reg_ea4 == 0)); + if (IS_92C_SERIAL(rtlhal->version)) { + if (reg_eb4 != 0) /*&&(reg_ec4 != 0) */ + _rtl92c_phy_path_b_fill_iqk_matrix(hw, pathb_ok, + result, + final_candidate, + (reg_ec4 == 0)); + } + _rtl92c_phy_save_adda_registers(hw, iqk_bb_reg, + rtlphy->iqk_bb_backup, 10); +} +EXPORT_SYMBOL(rtl92c_phy_iq_calibrate); + +void rtl92c_phy_lc_calibrate(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + bool start_conttx = false, singletone = false; + + if (start_conttx || singletone) + return; + if (IS_92C_SERIAL(rtlhal->version)) + rtlpriv->cfg->ops->phy_lc_calibrate(hw, true); + else + rtlpriv->cfg->ops->phy_lc_calibrate(hw, false); +} +EXPORT_SYMBOL(rtl92c_phy_lc_calibrate); + +void rtl92c_phy_ap_calibrate(struct ieee80211_hw *hw, char delta) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + + if (rtlphy->apk_done) + return; + if (IS_92C_SERIAL(rtlhal->version)) + _rtl92c_phy_ap_calibrate(hw, delta, true); + else + _rtl92c_phy_ap_calibrate(hw, delta, false); +} +EXPORT_SYMBOL(rtl92c_phy_ap_calibrate); + +void rtl92c_phy_set_rfpath_switch(struct ieee80211_hw *hw, bool bmain) +{ + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + + if (IS_92C_SERIAL(rtlhal->version)) + _rtl92c_phy_set_rfpath_switch(hw, bmain, true); + else + _rtl92c_phy_set_rfpath_switch(hw, bmain, false); +} +EXPORT_SYMBOL(rtl92c_phy_set_rfpath_switch); + +bool rtl92c_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 postprocessing = false; + + RT_TRACE(rtlpriv, 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(rtlpriv, COMP_CMD, DBG_TRACE, + "[IO CMD] Resume DM after scan\n"); + postprocessing = true; + break; + case IO_CMD_PAUSE_DM_BY_SCAN: + RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE, + "[IO CMD] Pause DM before scan\n"); + postprocessing = true; + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "switch case not processed\n"); + break; + } + } while (false); + if (postprocessing && !rtlphy->set_io_inprogress) { + rtlphy->set_io_inprogress = true; + rtlphy->current_io_type = iotype; + } else { + return false; + } + rtl92c_phy_set_io(hw); + RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE, "<--IO Type(%#x)\n", iotype); + return true; +} +EXPORT_SYMBOL(rtl92c_phy_set_io_cmd); + +void rtl92c_phy_set_io(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + + RT_TRACE(rtlpriv, 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: + dm_digtable.cur_igvalue = rtlphy->initgain_backup.xaagccore1; + rtl92c_dm_write_dig(hw); + rtl92c_phy_set_txpower_level(hw, rtlphy->current_channel); + break; + case IO_CMD_PAUSE_DM_BY_SCAN: + rtlphy->initgain_backup.xaagccore1 = dm_digtable.cur_igvalue; + dm_digtable.cur_igvalue = 0x37; + rtl92c_dm_write_dig(hw); + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "switch case not processed\n"); + break; + } + rtlphy->set_io_inprogress = false; + RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE, "<---(%#x)\n", + rtlphy->current_io_type); +} +EXPORT_SYMBOL(rtl92c_phy_set_io); + +void rtl92ce_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); +} +EXPORT_SYMBOL(rtl92ce_phy_set_rf_on); + +void _rtl92c_phy_set_rf_sleep(struct ieee80211_hw *hw) +{ + u32 u4b_tmp; + u8 delay = 5; + 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_APSD_CTRL, 0x40); + u4b_tmp = rtl_get_rfreg(hw, RF90_PATH_A, 0, RFREG_OFFSET_MASK); + while (u4b_tmp != 0 && delay > 0) { + rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x0); + rtl_set_rfreg(hw, RF90_PATH_A, 0x00, RFREG_OFFSET_MASK, 0x00); + rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x40); + u4b_tmp = rtl_get_rfreg(hw, RF90_PATH_A, 0, RFREG_OFFSET_MASK); + delay--; + } + if (delay == 0) { + 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); + RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE, + "Switch RF timeout !!!\n"); + return; + } + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE2); + rtl_write_byte(rtlpriv, REG_SPS0_CTRL, 0x22); +} +EXPORT_SYMBOL(_rtl92c_phy_set_rf_sleep); diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.h b/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.h new file mode 100644 index 00000000..cec10d69 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.h @@ -0,0 +1,258 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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 __RTL92C_PHY_COMMON_H__ +#define __RTL92C_PHY_COMMON_H__ + +#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 MAX_TOLERANCE 5 +#define IQK_DELAY_TIME 1 + +#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 IQK_ADDA_REG_NUM 16 +#define IQK_MAC_REG_NUM 4 + +#define IQK_DELAY_TIME 1 +#define RF90_PATH_MAX 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_DIF 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 +#define LLT_LAST_ENTRY_OF_TX_PKT_BUFFER 255 + +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 hw90_block_e { + HW90_BLOCK_MAC = 0, + HW90_BLOCK_PHY0 = 1, + HW90_BLOCK_PHY1 = 2, + HW90_BLOCK_RF = 3, + HW90_BLOCK_MAXIMUM = 4, +}; + +enum baseband_config_type { + BASEBAND_CONFIG_PHY_REG = 0, + BASEBAND_CONFIG_AGC_TAB = 1, +}; + +enum ra_offset_area { + RA_OFFSET_LEGACY_OFDM1, + RA_OFFSET_LEGACY_OFDM2, + RA_OFFSET_HT_OFDM1, + RA_OFFSET_HT_OFDM2, + RA_OFFSET_HT_OFDM3, + RA_OFFSET_HT_OFDM4, + RA_OFFSET_HT_CCK, +}; + +enum antenna_path { + ANTENNA_NONE, + ANTENNA_D, + ANTENNA_C, + ANTENNA_CD, + ANTENNA_B, + ANTENNA_BD, + ANTENNA_BC, + ANTENNA_BCD, + ANTENNA_A, + ANTENNA_AD, + ANTENNA_AC, + ANTENNA_ACD, + ANTENNA_AB, + ANTENNA_ABD, + ANTENNA_ABC, + ANTENNA_ABCD +}; + +struct r_antenna_select_ofdm { + u32 r_tx_antenna:4; + u32 r_ant_l:4; + u32 r_ant_non_ht:4; + u32 r_ant_ht1:4; + u32 r_ant_ht2:4; + u32 r_ant_ht_s1:4; + u32 r_ant_non_ht_s1:4; + u32 ofdm_txsc:2; + u32 reserved:2; +}; + +struct r_antenna_select_cck { + u8 r_cckrx_enable_2:2; + u8 r_cckrx_enable:2; + u8 r_ccktx_enable:4; +}; + +struct efuse_contents { + u8 mac_addr[ETH_ALEN]; + u8 cck_tx_power_idx[6]; + u8 ht40_1s_tx_power_idx[6]; + u8 ht40_2s_tx_power_idx_diff[3]; + u8 ht20_tx_power_idx_diff[3]; + u8 ofdm_tx_power_idx_diff[3]; + u8 ht40_max_power_offset[3]; + u8 ht20_max_power_offset[3]; + u8 channel_plan; + u8 thermal_meter; + u8 rf_option[5]; + u8 version; + u8 oem_id; + u8 regulatory; +}; + +struct tx_power_struct { + u8 cck[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER]; + u8 ht40_1s[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER]; + u8 ht40_2s[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER]; + u8 ht20_diff[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER]; + u8 legacy_ht_diff[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER]; + u8 legacy_ht_txpowerdiff; + u8 groupht20[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER]; + u8 groupht40[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER]; + u8 pwrgroup_cnt; + u32 mcs_original_offset[4][16]; +}; + +u32 rtl92c_phy_query_bb_reg(struct ieee80211_hw *hw, + u32 regaddr, u32 bitmask); +void rtl92c_phy_set_bb_reg(struct ieee80211_hw *hw, + u32 regaddr, u32 bitmask, u32 data); +u32 rtl92c_phy_query_rf_reg(struct ieee80211_hw *hw, + enum radio_path rfpath, u32 regaddr, + u32 bitmask); +bool rtl92c_phy_mac_config(struct ieee80211_hw *hw); +bool rtl92c_phy_bb_config(struct ieee80211_hw *hw); +bool rtl92c_phy_rf_config(struct ieee80211_hw *hw); +bool rtl92c_phy_config_rf_with_feaderfile(struct ieee80211_hw *hw, + enum radio_path rfpath); +void rtl92c_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw); +void rtl92c_phy_get_txpower_level(struct ieee80211_hw *hw, + long *powerlevel); +void rtl92c_phy_set_txpower_level(struct ieee80211_hw *hw, u8 channel); +bool rtl92c_phy_update_txpower_dbm(struct ieee80211_hw *hw, + long power_indbm); +void rtl92c_phy_scan_operation_backup(struct ieee80211_hw *hw, + u8 operation); +void rtl92c_phy_set_bw_mode(struct ieee80211_hw *hw, + enum nl80211_channel_type ch_type); +void rtl92c_phy_sw_chnl_callback(struct ieee80211_hw *hw); +u8 rtl92c_phy_sw_chnl(struct ieee80211_hw *hw); +void rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery); +void rtl92c_phy_set_beacon_hw_reg(struct ieee80211_hw *hw, + u16 beaconinterval); +void rtl92c_phy_ap_calibrate(struct ieee80211_hw *hw, char delta); +void rtl92c_phy_lc_calibrate(struct ieee80211_hw *hw); +void rtl92c_phy_set_rfpath_switch(struct ieee80211_hw *hw, bool bmain); +bool rtl92c_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, + enum radio_path rfpath); +bool rtl8192_phy_check_is_legal_rfpath(struct ieee80211_hw *hw, + u32 rfpath); +bool rtl92c_phy_set_rf_power_state(struct ieee80211_hw *hw, + enum rf_pwrstate rfpwr_state); +void rtl92ce_phy_set_rf_on(struct ieee80211_hw *hw); +void rtl92c_phy_set_io(struct ieee80211_hw *hw); +void rtl92c_bb_block_on(struct ieee80211_hw *hw); +u32 _rtl92c_phy_calculate_bit_shift(u32 bitmask); +long _rtl92c_phy_txpwr_idx_to_dbm(struct ieee80211_hw *hw, + enum wireless_mode wirelessmode, + u8 txpwridx); +u8 _rtl92c_phy_dbm_to_txpwr_Idx(struct ieee80211_hw *hw, + enum wireless_mode wirelessmode, + long power_indbm); +void _rtl92c_phy_init_bb_rf_register_definition(struct ieee80211_hw *hw); +void _rtl92c_phy_set_rf_sleep(struct ieee80211_hw *hw); +bool _rtl92c_phy_sw_chnl_step_by_step(struct ieee80211_hw *hw, + u8 channel, u8 *stage, u8 *step, + u32 *delay); +u8 rtl92c_bt_rssi_state_change(struct ieee80211_hw *hw); +u32 _rtl92c_phy_fw_rf_serial_read(struct ieee80211_hw *hw, + enum radio_path rfpath, u32 offset); +void _rtl92c_phy_fw_rf_serial_write(struct ieee80211_hw *hw, + enum radio_path rfpath, u32 offset, + u32 data); +u32 _rtl92c_phy_rf_serial_read(struct ieee80211_hw *hw, + enum radio_path rfpath, u32 offset); +void _rtl92c_phy_rf_serial_write(struct ieee80211_hw *hw, + enum radio_path rfpath, u32 offset, + u32 data); +bool _rtl92c_phy_bb8192c_config_parafile(struct ieee80211_hw *hw); +void _rtl92c_store_pwrIndex_diffrate_offset(struct ieee80211_hw *hw, + u32 regaddr, u32 bitmask, + u32 data); +bool rtl92c_phy_set_io_cmd(struct ieee80211_hw *hw, enum io_type iotype); + +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/Makefile b/drivers/net/wireless/rtlwifi/rtl8192ce/Makefile new file mode 100644 index 00000000..c0cb0cfe --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/Makefile @@ -0,0 +1,13 @@ +rtl8192ce-objs := \ + dm.o \ + hw.o \ + led.o \ + phy.o \ + rf.o \ + sw.o \ + table.o \ + trx.o + +obj-$(CONFIG_RTL8192CE) += rtl8192ce.o + +ccflags-y += -D__CHECK_ENDIAN__ diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/def.h b/drivers/net/wireless/rtlwifi/rtl8192ce/def.h new file mode 100644 index 00000000..04c3aef8 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/def.h @@ -0,0 +1,249 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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 __RTL92C_DEF_H__ +#define __RTL92C_DEF_H__ + +#define HAL_RETRY_LIMIT_INFRA 48 +#define HAL_RETRY_LIMIT_AP_ADHOC 7 + +#define PHY_RSSI_SLID_WIN_MAX 100 +#define PHY_LINKQUALITY_SLID_WIN_MAX 20 +#define PHY_BEACON_RSSI_SLID_WIN_MAX 10 + +#define RESET_DELAY_8185 20 + +#define RT_IBSS_INT_MASKS (IMR_BCNINT | IMR_TBDOK | IMR_TBDER) +#define RT_AC_INT_MASKS (IMR_VIDOK | IMR_VODOK | IMR_BEDOK|IMR_BKDOK) + +#define NUM_OF_FIRMWARE_QUEUE 10 +#define NUM_OF_PAGES_IN_FW 0x100 +#define NUM_OF_PAGE_IN_FW_QUEUE_BK 0x07 +#define NUM_OF_PAGE_IN_FW_QUEUE_BE 0x07 +#define NUM_OF_PAGE_IN_FW_QUEUE_VI 0x07 +#define NUM_OF_PAGE_IN_FW_QUEUE_VO 0x07 +#define NUM_OF_PAGE_IN_FW_QUEUE_HCCA 0x0 +#define NUM_OF_PAGE_IN_FW_QUEUE_CMD 0x0 +#define NUM_OF_PAGE_IN_FW_QUEUE_MGNT 0x02 +#define NUM_OF_PAGE_IN_FW_QUEUE_HIGH 0x02 +#define NUM_OF_PAGE_IN_FW_QUEUE_BCN 0x2 +#define NUM_OF_PAGE_IN_FW_QUEUE_PUB 0xA1 + +#define NUM_OF_PAGE_IN_FW_QUEUE_BK_DTM 0x026 +#define NUM_OF_PAGE_IN_FW_QUEUE_BE_DTM 0x048 +#define NUM_OF_PAGE_IN_FW_QUEUE_VI_DTM 0x048 +#define NUM_OF_PAGE_IN_FW_QUEUE_VO_DTM 0x026 +#define NUM_OF_PAGE_IN_FW_QUEUE_PUB_DTM 0x00 + +#define MAX_LINES_HWCONFIG_TXT 1000 +#define MAX_BYTES_LINE_HWCONFIG_TXT 256 + +#define SW_THREE_WIRE 0 +#define HW_THREE_WIRE 2 + +#define BT_DEMO_BOARD 0 +#define BT_QA_BOARD 1 +#define BT_FPGA 2 + +#define RX_SMOOTH_FACTOR 20 + +#define HAL_PRIME_CHNL_OFFSET_DONT_CARE 0 +#define HAL_PRIME_CHNL_OFFSET_LOWER 1 +#define HAL_PRIME_CHNL_OFFSET_UPPER 2 + +#define MAX_H2C_QUEUE_NUM 10 + +#define RX_MPDU_QUEUE 0 +#define RX_CMD_QUEUE 1 +#define RX_MAX_QUEUE 2 +#define AC2QUEUEID(_AC) (_AC) + +#define C2H_RX_CMD_HDR_LEN 8 +#define GET_C2H_CMD_CMD_LEN(__prxhdr) \ + LE_BITS_TO_4BYTE((__prxhdr), 0, 16) +#define GET_C2H_CMD_ELEMENT_ID(__prxhdr) \ + LE_BITS_TO_4BYTE((__prxhdr), 16, 8) +#define GET_C2H_CMD_CMD_SEQ(__prxhdr) \ + LE_BITS_TO_4BYTE((__prxhdr), 24, 7) +#define GET_C2H_CMD_CONTINUE(__prxhdr) \ + LE_BITS_TO_4BYTE((__prxhdr), 31, 1) +#define GET_C2H_CMD_CONTENT(__prxhdr) \ + ((u8 *)(__prxhdr) + C2H_RX_CMD_HDR_LEN) + +#define GET_C2H_CMD_FEEDBACK_ELEMENT_ID(__pcmdfbhdr) \ + LE_BITS_TO_4BYTE((__pcmdfbhdr), 0, 8) +#define GET_C2H_CMD_FEEDBACK_CCX_LEN(__pcmdfbhdr) \ + LE_BITS_TO_4BYTE((__pcmdfbhdr), 8, 8) +#define GET_C2H_CMD_FEEDBACK_CCX_CMD_CNT(__pcmdfbhdr) \ + LE_BITS_TO_4BYTE((__pcmdfbhdr), 16, 16) +#define GET_C2H_CMD_FEEDBACK_CCX_MAC_ID(__pcmdfbhdr) \ + LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 0, 5) +#define GET_C2H_CMD_FEEDBACK_CCX_VALID(__pcmdfbhdr) \ + LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 7, 1) +#define GET_C2H_CMD_FEEDBACK_CCX_RETRY_CNT(__pcmdfbhdr) \ + LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 8, 5) +#define GET_C2H_CMD_FEEDBACK_CCX_TOK(__pcmdfbhdr) \ + LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 15, 1) +#define GET_C2H_CMD_FEEDBACK_CCX_QSEL(__pcmdfbhdr) \ + LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 16, 4) +#define GET_C2H_CMD_FEEDBACK_CCX_SEQ(__pcmdfbhdr) \ + LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 20, 12) + +#define CHIP_VER_B BIT(4) +#define CHIP_92C_BITMASK BIT(0) +#define CHIP_92C_1T2R 0x03 +#define CHIP_92C 0x01 +#define CHIP_88C 0x00 + +enum version_8192c { + VERSION_A_CHIP_92C = 0x01, + VERSION_A_CHIP_88C = 0x00, + VERSION_B_CHIP_92C = 0x11, + VERSION_B_CHIP_88C = 0x10, + VERSION_TEST_CHIP_88C = 0x00, + VERSION_TEST_CHIP_92C = 0x01, + VERSION_NORMAL_TSMC_CHIP_88C = 0x10, + VERSION_NORMAL_TSMC_CHIP_92C = 0x11, + VERSION_NORMAL_TSMC_CHIP_92C_1T2R = 0x13, + VERSION_NORMAL_UMC_CHIP_88C_A_CUT = 0x30, + VERSION_NORMAL_UMC_CHIP_92C_A_CUT = 0x31, + VERSION_NORMAL_UMC_CHIP_92C_1T2R_A_CUT = 0x33, + VERSION_NORMA_UMC_CHIP_8723_1T1R_A_CUT = 0x34, + VERSION_NORMA_UMC_CHIP_8723_1T1R_B_CUT = 0x3c, + VERSION_NORMAL_UMC_CHIP_88C_B_CUT = 0x70, + VERSION_NORMAL_UMC_CHIP_92C_B_CUT = 0x71, + VERSION_NORMAL_UMC_CHIP_92C_1T2R_B_CUT = 0x73, + VERSION_UNKNOWN = 0x88, +}; + +#define CUT_VERSION_MASK (BIT(6)|BIT(7)) +#define CHIP_VENDOR_UMC BIT(5) +#define CHIP_VENDOR_UMC_B_CUT BIT(6) /* Chip version for ECO */ +#define IS_VENDOR_UMC_A_CUT(version) ((IS_CHIP_VENDOR_UMC(version)) ? \ + ((GET_CVID_CUT_VERSION(version)) ? false : true) : false) +#define IS_CHIP_VER_B(version) ((version & CHIP_VER_B) ? true : false) +#define IS_VENDOR_UMC_A_CUT(version) ((IS_CHIP_VENDOR_UMC(version)) ? \ + ((GET_CVID_CUT_VERSION(version)) ? false : true) : false) +#define IS_92C_SERIAL(version) ((version & CHIP_92C_BITMASK) ? true : false) +#define IS_CHIP_VENDOR_UMC(version) \ + ((version & CHIP_VENDOR_UMC) ? true : false) +#define GET_CVID_CUT_VERSION(version) ((version) & CUT_VERSION_MASK) +#define IS_81xxC_VENDOR_UMC_B_CUT(version) \ + ((IS_CHIP_VENDOR_UMC(version)) ? \ + ((GET_CVID_CUT_VERSION(version) == CHIP_VENDOR_UMC_B_CUT) ? \ + true : false) : false) + +enum rtl819x_loopback_e { + RTL819X_NO_LOOPBACK = 0, + RTL819X_MAC_LOOPBACK = 1, + RTL819X_DMA_LOOPBACK = 2, + RTL819X_CCK_LOOPBACK = 3, +}; + +enum rf_optype { + RF_OP_BY_SW_3WIRE = 0, + RF_OP_BY_FW, + RF_OP_MAX +}; + +enum rf_power_state { + RF_ON, + RF_OFF, + RF_SLEEP, + RF_SHUT_DOWN, +}; + +enum power_save_mode { + POWER_SAVE_MODE_ACTIVE, + POWER_SAVE_MODE_SAVE, +}; + +enum power_polocy_config { + POWERCFG_MAX_POWER_SAVINGS, + POWERCFG_GLOBAL_POWER_SAVINGS, + POWERCFG_LOCAL_POWER_SAVINGS, + POWERCFG_LENOVO, +}; + +enum interface_select_pci { + INTF_SEL1_MINICARD = 0, + INTF_SEL0_PCIE = 1, + INTF_SEL2_RSV = 2, + INTF_SEL3_RSV = 3, +}; + +enum hal_fw_c2h_cmd_id { + HAL_FW_C2H_CMD_Read_MACREG = 0, + HAL_FW_C2H_CMD_Read_BBREG = 1, + HAL_FW_C2H_CMD_Read_RFREG = 2, + HAL_FW_C2H_CMD_Read_EEPROM = 3, + HAL_FW_C2H_CMD_Read_EFUSE = 4, + HAL_FW_C2H_CMD_Read_CAM = 5, + HAL_FW_C2H_CMD_Get_BasicRate = 6, + HAL_FW_C2H_CMD_Get_DataRate = 7, + HAL_FW_C2H_CMD_Survey = 8, + HAL_FW_C2H_CMD_SurveyDone = 9, + HAL_FW_C2H_CMD_JoinBss = 10, + HAL_FW_C2H_CMD_AddSTA = 11, + HAL_FW_C2H_CMD_DelSTA = 12, + HAL_FW_C2H_CMD_AtimDone = 13, + HAL_FW_C2H_CMD_TX_Report = 14, + HAL_FW_C2H_CMD_CCX_Report = 15, + HAL_FW_C2H_CMD_DTM_Report = 16, + HAL_FW_C2H_CMD_TX_Rate_Statistics = 17, + HAL_FW_C2H_CMD_C2HLBK = 18, + HAL_FW_C2H_CMD_C2HDBG = 19, + HAL_FW_C2H_CMD_C2HFEEDBACK = 20, + HAL_FW_C2H_CMD_MAX +}; + +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, +}; + +struct phy_sts_cck_8192s_t { + u8 adc_pwdb_X[4]; + u8 sq_rpt; + u8 cck_agc_rpt; +}; + +struct h2c_cmd_8192c { + u8 element_id; + u32 cmd_len; + u8 *p_cmdbuffer; +}; + +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/dm.c b/drivers/net/wireless/rtlwifi/rtl8192ce/dm.c new file mode 100644 index 00000000..27b3af88 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/dm.c @@ -0,0 +1,115 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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> + * + *****************************************************************************/ + +#include "../wifi.h" +#include "../base.h" +#include "../pci.h" +#include "reg.h" +#include "def.h" +#include "phy.h" +#include "dm.h" +#include "../rtl8192c/fw_common.h" + +void rtl92ce_dm_dynamic_txpower(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + long undecorated_smoothed_pwdb; + + if (!rtlpriv->dm.dynamic_txpower_enable) + return; + + if (rtlpriv->dm.dm_flag & HAL_DM_HIPWR_DISABLE) { + rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_NORMAL; + return; + } + + if ((mac->link_state < MAC80211_LINKED) && + (rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb == 0)) { + RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE, + "Not connected to any\n"); + + rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_NORMAL; + + rtlpriv->dm.last_dtp_lvl = TXHIGHPWRLEVEL_NORMAL; + return; + } + + if (mac->link_state >= MAC80211_LINKED) { + if (mac->opmode == NL80211_IFTYPE_ADHOC) { + undecorated_smoothed_pwdb = + rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb; + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + "AP Client PWDB = 0x%lx\n", + undecorated_smoothed_pwdb); + } else { + undecorated_smoothed_pwdb = + rtlpriv->dm.undecorated_smoothed_pwdb; + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + "STA Default Port PWDB = 0x%lx\n", + undecorated_smoothed_pwdb); + } + } else { + undecorated_smoothed_pwdb = + rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb; + + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + "AP Ext Port PWDB = 0x%lx\n", + undecorated_smoothed_pwdb); + } + + if (undecorated_smoothed_pwdb >= TX_POWER_NEAR_FIELD_THRESH_LVL2) { + rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_LEVEL1; + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + "TXHIGHPWRLEVEL_LEVEL1 (TxPwr=0x0)\n"); + } else if ((undecorated_smoothed_pwdb < + (TX_POWER_NEAR_FIELD_THRESH_LVL2 - 3)) && + (undecorated_smoothed_pwdb >= + TX_POWER_NEAR_FIELD_THRESH_LVL1)) { + + rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_LEVEL1; + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + "TXHIGHPWRLEVEL_LEVEL1 (TxPwr=0x10)\n"); + } else if (undecorated_smoothed_pwdb < + (TX_POWER_NEAR_FIELD_THRESH_LVL1 - 5)) { + rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_NORMAL; + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + "TXHIGHPWRLEVEL_NORMAL\n"); + } + + if ((rtlpriv->dm.dynamic_txhighpower_lvl != rtlpriv->dm.last_dtp_lvl)) { + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + "PHY_SetTxPowerLevel8192S() Channel = %d\n", + rtlphy->current_channel); + rtl92c_phy_set_txpower_level(hw, rtlphy->current_channel); + } + + rtlpriv->dm.last_dtp_lvl = rtlpriv->dm.dynamic_txhighpower_lvl; +} diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/dm.h b/drivers/net/wireless/rtlwifi/rtl8192ce/dm.h new file mode 100644 index 00000000..26747fa8 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/dm.h @@ -0,0 +1,198 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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 __RTL92C_DM_H__ +#define __RTL92C_DM_H__ + +#define HAL_DM_DIG_DISABLE BIT(0) +#define HAL_DM_HIPWR_DISABLE BIT(1) + +#define OFDM_TABLE_LENGTH 37 +#define CCK_TABLE_LENGTH 33 + +#define OFDM_TABLE_SIZE 37 +#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_FA_UPPER 0x32 +#define DM_DIG_FA_LOWER 0x20 +#define DM_DIG_FA_TH0 0x20 +#define DM_DIG_FA_TH1 0x100 +#define DM_DIG_FA_TH2 0x200 + +#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 + +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; + 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_pd_state; + u8 cur_cck_pd_state; + u8 pre_cck_fa_state; + u8 cur_cck_fa_state; + u8 pre_ccastate; + u8 cur_ccasate; +}; + +struct swat_t { + u8 failure_cnt; + u8 try_flag; + u8 stop_trying; + long pre_rssi; + long trying_threshold; + u8 cur_antenna; + u8 pre_antenna; +}; + +enum tag_dynamic_init_gain_operation_type_definition { + DIG_TYPE_THRESH_HIGH = 0, + DIG_TYPE_THRESH_LOW = 1, + DIG_TYPE_BACKOFF = 2, + DIG_TYPE_RX_GAIN_MIN = 3, + DIG_TYPE_RX_GAIN_MAX = 4, + DIG_TYPE_ENABLE = 5, + DIG_TYPE_DISABLE = 6, + DIG_OP_TYPE_MAX +}; + +enum tag_cck_packet_detection_threshold_type_definition { + CCK_PD_STAGE_LowRssi = 0, + CCK_PD_STAGE_HighRssi = 1, + CCK_FA_STAGE_Low = 2, + CCK_FA_STAGE_High = 3, + CCK_PD_STAGE_MAX = 4, +}; + +enum dm_1r_cca_e { + CCA_1R = 0, + CCA_2R = 1, + CCA_MAX = 2, +}; + +enum dm_rf_e { + RF_SAVE = 0, + RF_NORMAL = 1, + RF_MAX = 2, +}; + +enum dm_sw_ant_switch_e { + ANS_ANTENNA_B = 1, + ANS_ANTENNA_A = 2, + ANS_ANTENNA_MAX = 3, +}; + +enum dm_dig_ext_port_alg_e { + DIG_EXT_PORT_STAGE_0 = 0, + DIG_EXT_PORT_STAGE_1 = 1, + DIG_EXT_PORT_STAGE_2 = 2, + DIG_EXT_PORT_STAGE_3 = 3, + DIG_EXT_PORT_STAGE_MAX = 4, +}; + +enum dm_dig_connect_e { + DIG_STA_DISCONNECT = 0, + DIG_STA_CONNECT = 1, + DIG_STA_BEFORE_CONNECT = 2, + DIG_MULTISTA_DISCONNECT = 3, + DIG_MULTISTA_CONNECT = 4, + DIG_CONNECT_MAX +}; + +extern struct dig_t dm_digtable; +void rtl92c_dm_init(struct ieee80211_hw *hw); +void rtl92c_dm_watchdog(struct ieee80211_hw *hw); +void rtl92c_dm_write_dig(struct ieee80211_hw *hw); +void rtl92c_dm_init_edca_turbo(struct ieee80211_hw *hw); +void rtl92c_dm_check_txpower_tracking(struct ieee80211_hw *hw); +void rtl92c_dm_init_rate_adaptive_mask(struct ieee80211_hw *hw); +void rtl92c_dm_rf_saving(struct ieee80211_hw *hw, u8 bforce_in_normal); +void rtl92c_dm_bt_coexist(struct ieee80211_hw *hw); +void rtl92ce_dm_dynamic_txpower(struct ieee80211_hw *hw); + +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c new file mode 100644 index 00000000..5c4d9bc0 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c @@ -0,0 +1,2286 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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> + * + *****************************************************************************/ + +#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 "../rtl8192c/fw_common.h" +#include "dm.h" +#include "led.h" +#include "hw.h" + +#define LLT_CONFIG 5 + +static void _rtl92ce_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 _rtl92ce_stop_tx_beacon(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 tmp1byte; + + tmp1byte = rtl_read_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2); + rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2, tmp1byte & (~BIT(6))); + rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 1, 0x64); + tmp1byte = rtl_read_byte(rtlpriv, REG_TBTT_PROHIBIT + 2); + tmp1byte &= ~(BIT(0)); + rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 2, tmp1byte); +} + +static void _rtl92ce_resume_tx_beacon(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 tmp1byte; + + tmp1byte = rtl_read_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2); + rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2, tmp1byte | BIT(6)); + rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 1, 0xff); + tmp1byte = rtl_read_byte(rtlpriv, REG_TBTT_PROHIBIT + 2); + tmp1byte |= BIT(0); + rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 2, tmp1byte); +} + +static void _rtl92ce_enable_bcn_sub_func(struct ieee80211_hw *hw) +{ + _rtl92ce_set_bcn_ctrl_reg(hw, 0, BIT(1)); +} + +static void _rtl92ce_disable_bcn_sub_func(struct ieee80211_hw *hw) +{ + _rtl92ce_set_bcn_ctrl_reg(hw, BIT(1), 0); +} + +void rtl92ce_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->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(rtlpriv, COMP_ERR, DBG_EMERG, + "switch case not processed\n"); + break; + } +} + +void rtl92ce_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_efuse *rtlefuse = 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 rate_cfg = ((u16 *) val)[0]; + u8 rate_index = 0; + rate_cfg &= 0x15f; + rate_cfg |= 0x01; + rtl_write_byte(rtlpriv, REG_RRSR, rate_cfg & 0xff); + rtl_write_byte(rtlpriv, REG_RRSR + 1, + (rate_cfg >> 8) & 0xff); + while (rate_cfg > 0x1) { + rate_cfg = (rate_cfg >> 1); + rate_index++; + } + rtl_write_byte(rtlpriv, REG_INIRTS_RATE_SEL, + rate_index); + 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(rtlpriv, COMP_MLME, DBG_LOUD, + "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 = (mac->cur_40_prime_sc) << 5; + if (short_preamble) + reg_tmp |= 0x80; + + rtl_write_byte(rtlpriv, REG_RRSR + 2, reg_tmp); + break; + } + case HW_VAR_AMPDU_MIN_SPACE:{ + u8 min_spacing_to_set; + u8 sec_min_space; + + min_spacing_to_set = *((u8 *) val); + if (min_spacing_to_set <= 7) { + sec_min_space = 0; + + if (min_spacing_to_set < sec_min_space) + min_spacing_to_set = sec_min_space; + + mac->min_space_cfg = ((mac->min_space_cfg & + 0xf8) | + min_spacing_to_set); + + *val = min_spacing_to_set; + + RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD, + "Set HW_VAR_AMPDU_MIN_SPACE: %#x\n", + mac->min_space_cfg); + + rtl_write_byte(rtlpriv, REG_AMPDU_MIN_SPACE, + mac->min_space_cfg); + } + break; + } + case HW_VAR_SHORTGI_DENSITY:{ + u8 density_to_set; + + density_to_set = *((u8 *) val); + mac->min_space_cfg |= (density_to_set << 3); + + RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD, + "Set HW_VAR_SHORTGI_DENSITY: %#x\n", + mac->min_space_cfg); + + rtl_write_byte(rtlpriv, REG_AMPDU_MIN_SPACE, + mac->min_space_cfg); + + break; + } + case HW_VAR_AMPDU_FACTOR:{ + u8 regtoset_normal[4] = {0x41, 0xa8, 0x72, 0xb9}; + u8 regtoset_bt[4] = {0x31, 0x74, 0x42, 0x97}; + + u8 factor_toset; + u8 *p_regtoset = NULL; + u8 index = 0; + + if ((rtlpcipriv->bt_coexist.bt_coexistence) && + (rtlpcipriv->bt_coexist.bt_coexist_type == + BT_CSR_BC4)) + p_regtoset = regtoset_bt; + else + p_regtoset = regtoset_normal; + + factor_toset = *((u8 *) val); + if (factor_toset <= 3) { + factor_toset = (1 << (factor_toset + 2)); + if (factor_toset > 0xf) + factor_toset = 0xf; + + for (index = 0; index < 4; index++) { + if ((p_regtoset[index] & 0xf0) > + (factor_toset << 4)) + p_regtoset[index] = + (p_regtoset[index] & 0x0f) | + (factor_toset << 4); + + if ((p_regtoset[index] & 0x0f) > + factor_toset) + p_regtoset[index] = + (p_regtoset[index] & 0xf0) | + (factor_toset); + + rtl_write_byte(rtlpriv, + (REG_AGGLEN_LMT + index), + p_regtoset[index]); + + } + + RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD, + "Set HW_VAR_AMPDU_FACTOR: %#x\n", + factor_toset); + } + break; + } + case HW_VAR_AC_PARAM:{ + u8 e_aci = *((u8 *) val); + rtl92c_dm_init_edca_turbo(hw); + + 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 *p_aci_aifsn = + (union aci_aifsn *)(&(mac->ac[0].aifs)); + u8 acm = p_aci_aifsn->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(rtlpriv, 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(rtlpriv, COMP_ERR, DBG_EMERG, + "switch case not processed\n"); + break; + } + } + + RT_TRACE(rtlpriv, 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_RL, + 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: + rtlefuse->efuse_usedbytes = *((u16 *) val); + break; + case HW_VAR_EFUSE_USAGE: + rtlefuse->efuse_usedpercentage = *((u8 *) val); + break; + case HW_VAR_IO_CMD: + rtl92c_phy_set_io_cmd(hw, (*(enum io_type *)val)); + break; + case HW_VAR_WPA_CONFIG: + rtl_write_byte(rtlpriv, REG_SECCFG, *((u8 *) 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:{ + u8 psmode = (*(u8 *) val); + + if ((psmode != FW_PS_ACTIVE_MODE) && + (!IS_92C_SERIAL(rtlhal->version))) { + rtl92c_dm_rf_saving(hw, true); + } + + rtl92c_set_fw_pwrmode_cmd(hw, (*(u8 *) val)); + break; + } + case HW_VAR_FW_PSMODE_STATUS: + ppsc->fw_current_inpsmode = *((bool *) val); + break; + case HW_VAR_H2C_FW_JOINBSSRPT:{ + u8 mstatus = (*(u8 *) val); + u8 tmp_regcr, tmp_reg422; + bool recover = false; + + if (mstatus == RT_MEDIA_CONNECT) { + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_AID, + NULL); + + tmp_regcr = rtl_read_byte(rtlpriv, REG_CR + 1); + rtl_write_byte(rtlpriv, REG_CR + 1, + (tmp_regcr | BIT(0))); + + _rtl92ce_set_bcn_ctrl_reg(hw, 0, BIT(3)); + _rtl92ce_set_bcn_ctrl_reg(hw, BIT(4), 0); + + tmp_reg422 = + rtl_read_byte(rtlpriv, + REG_FWHW_TXQ_CTRL + 2); + if (tmp_reg422 & BIT(6)) + recover = true; + rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2, + tmp_reg422 & (~BIT(6))); + + rtl92c_set_fw_rsvdpagepkt(hw, 0); + + _rtl92ce_set_bcn_ctrl_reg(hw, BIT(3), 0); + _rtl92ce_set_bcn_ctrl_reg(hw, 0, BIT(4)); + + if (recover) { + rtl_write_byte(rtlpriv, + REG_FWHW_TXQ_CTRL + 2, + tmp_reg422); + } + + rtl_write_byte(rtlpriv, REG_CR + 1, + (tmp_regcr & ~(BIT(0)))); + } + rtl92c_set_fw_joinbss_report_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) + _rtl92ce_stop_tx_beacon(hw); + + _rtl92ce_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)); + + _rtl92ce_set_bcn_ctrl_reg(hw, BIT(3), 0); + + if (btype_ibss) + _rtl92ce_resume_tx_beacon(hw); + + break; + + } + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "switch case not processed\n"); + break; + } +} + +static bool _rtl92ce_llt_write(struct ieee80211_hw *hw, u32 address, u32 data) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + bool status = true; + long count = 0; + u32 value = _LLT_INIT_ADDR(address) | + _LLT_INIT_DATA(data) | _LLT_OP(_LLT_WRITE_ACCESS); + + rtl_write_dword(rtlpriv, REG_LLT_INIT, value); + + do { + value = rtl_read_dword(rtlpriv, REG_LLT_INIT); + if (_LLT_NO_ACTIVE == _LLT_OP_VALUE(value)) + break; + + if (count > POLLING_LLT_THRESHOLD) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "Failed to polling write LLT done at address %d!\n", + address); + status = false; + break; + } + } while (++count); + + return status; +} + +static bool _rtl92ce_llt_table_init(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + unsigned short i; + u8 txpktbuf_bndy; + u8 maxPage; + bool status; + +#if LLT_CONFIG == 1 + maxPage = 255; + txpktbuf_bndy = 252; +#elif LLT_CONFIG == 2 + maxPage = 127; + txpktbuf_bndy = 124; +#elif LLT_CONFIG == 3 + maxPage = 255; + txpktbuf_bndy = 174; +#elif LLT_CONFIG == 4 + maxPage = 255; + txpktbuf_bndy = 246; +#elif LLT_CONFIG == 5 + maxPage = 255; + txpktbuf_bndy = 246; +#endif + +#if LLT_CONFIG == 1 + rtl_write_byte(rtlpriv, REG_RQPN_NPQ, 0x1c); + rtl_write_dword(rtlpriv, REG_RQPN, 0x80a71c1c); +#elif LLT_CONFIG == 2 + rtl_write_dword(rtlpriv, REG_RQPN, 0x845B1010); +#elif LLT_CONFIG == 3 + rtl_write_dword(rtlpriv, REG_RQPN, 0x84838484); +#elif LLT_CONFIG == 4 + rtl_write_dword(rtlpriv, REG_RQPN, 0x80bd1c1c); +#elif LLT_CONFIG == 5 + rtl_write_word(rtlpriv, REG_RQPN_NPQ, 0x0000); + + rtl_write_dword(rtlpriv, REG_RQPN, 0x80b01c29); +#endif + + rtl_write_dword(rtlpriv, REG_TRXFF_BNDY, (0x27FF0000 | txpktbuf_bndy)); + rtl_write_byte(rtlpriv, REG_TDECTRL + 1, txpktbuf_bndy); + + rtl_write_byte(rtlpriv, REG_TXPKTBUF_BCNQ_BDNY, txpktbuf_bndy); + rtl_write_byte(rtlpriv, REG_TXPKTBUF_MGQ_BDNY, txpktbuf_bndy); + + rtl_write_byte(rtlpriv, 0x45D, txpktbuf_bndy); + rtl_write_byte(rtlpriv, REG_PBP, 0x11); + rtl_write_byte(rtlpriv, REG_RX_DRVINFO_SZ, 0x4); + + for (i = 0; i < (txpktbuf_bndy - 1); i++) { + status = _rtl92ce_llt_write(hw, i, i + 1); + if (true != status) + return status; + } + + status = _rtl92ce_llt_write(hw, (txpktbuf_bndy - 1), 0xFF); + if (true != status) + return status; + + for (i = txpktbuf_bndy; i < maxPage; i++) { + status = _rtl92ce_llt_write(hw, i, (i + 1)); + if (true != status) + return status; + } + + status = _rtl92ce_llt_write(hw, maxPage, txpktbuf_bndy); + if (true != status) + return status; + + return true; +} + +static void _rtl92ce_gen_refresh_led_state(struct ieee80211_hw *hw) +{ + struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + struct rtl_led *pLed0 = &(pcipriv->ledctl.sw_led0); + + if (rtlpci->up_first_time) + return; + + if (ppsc->rfoff_reason == RF_CHANGE_BY_IPS) + rtl92ce_sw_led_on(hw, pLed0); + else if (ppsc->rfoff_reason == RF_CHANGE_BY_INIT) + rtl92ce_sw_led_on(hw, pLed0); + else + rtl92ce_sw_led_off(hw, pLed0); +} + +static bool _rtl92ce_init_mac(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + + unsigned char bytetmp; + unsigned short wordtmp; + u16 retry; + + rtl_write_byte(rtlpriv, REG_RSV_CTRL, 0x00); + if (rtlpcipriv->bt_coexist.bt_coexistence) { + u32 value32; + value32 = rtl_read_dword(rtlpriv, REG_APS_FSMCO); + value32 |= (SOP_ABG | SOP_AMB | XOP_BTCK); + rtl_write_dword(rtlpriv, REG_APS_FSMCO, value32); + } + rtl_write_byte(rtlpriv, REG_SPS0_CTRL, 0x2b); + rtl_write_byte(rtlpriv, REG_AFE_XTAL_CTRL, 0x0F); + + if (rtlpcipriv->bt_coexist.bt_coexistence) { + u32 u4b_tmp = rtl_read_dword(rtlpriv, REG_AFE_XTAL_CTRL); + + u4b_tmp &= (~0x00024800); + rtl_write_dword(rtlpriv, REG_AFE_XTAL_CTRL, u4b_tmp); + } + + bytetmp = rtl_read_byte(rtlpriv, REG_APS_FSMCO + 1) | BIT(0); + udelay(2); + + rtl_write_byte(rtlpriv, REG_APS_FSMCO + 1, bytetmp); + udelay(2); + + bytetmp = rtl_read_byte(rtlpriv, REG_APS_FSMCO + 1); + udelay(2); + + retry = 0; + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "reg0xec:%x:%x\n", + rtl_read_dword(rtlpriv, 0xEC), bytetmp); + + while ((bytetmp & BIT(0)) && retry < 1000) { + retry++; + udelay(50); + bytetmp = rtl_read_byte(rtlpriv, REG_APS_FSMCO + 1); + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "reg0xec:%x:%x\n", + rtl_read_dword(rtlpriv, 0xEC), bytetmp); + udelay(50); + } + + rtl_write_word(rtlpriv, REG_APS_FSMCO, 0x1012); + + rtl_write_byte(rtlpriv, REG_SYS_ISO_CTRL + 1, 0x82); + udelay(2); + + if (rtlpcipriv->bt_coexist.bt_coexistence) { + bytetmp = rtl_read_byte(rtlpriv, REG_AFE_XTAL_CTRL+2) & 0xfd; + rtl_write_byte(rtlpriv, REG_AFE_XTAL_CTRL+2, bytetmp); + } + + rtl_write_word(rtlpriv, REG_CR, 0x2ff); + + if (!_rtl92ce_llt_table_init(hw)) + return false; + + rtl_write_dword(rtlpriv, REG_HISR, 0xffffffff); + rtl_write_byte(rtlpriv, REG_HISRE, 0xff); + + rtl_write_word(rtlpriv, REG_TRXFF_BNDY + 2, 0x27ff); + + wordtmp = rtl_read_word(rtlpriv, REG_TRXDMA_CTRL); + wordtmp &= 0xf; + wordtmp |= 0xF771; + rtl_write_word(rtlpriv, REG_TRXDMA_CTRL, wordtmp); + + rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 1, 0x1F); + rtl_write_dword(rtlpriv, REG_RCR, rtlpci->receive_config); + rtl_write_dword(rtlpriv, REG_TCR, rtlpci->transmit_config); + + rtl_write_byte(rtlpriv, 0x4d0, 0x0); + + rtl_write_dword(rtlpriv, REG_BCNQ_DESA, + ((u64) rtlpci->tx_ring[BEACON_QUEUE].dma) & + DMA_BIT_MASK(32)); + rtl_write_dword(rtlpriv, REG_MGQ_DESA, + (u64) rtlpci->tx_ring[MGNT_QUEUE].dma & + DMA_BIT_MASK(32)); + rtl_write_dword(rtlpriv, REG_VOQ_DESA, + (u64) rtlpci->tx_ring[VO_QUEUE].dma & DMA_BIT_MASK(32)); + rtl_write_dword(rtlpriv, REG_VIQ_DESA, + (u64) rtlpci->tx_ring[VI_QUEUE].dma & DMA_BIT_MASK(32)); + rtl_write_dword(rtlpriv, REG_BEQ_DESA, + (u64) rtlpci->tx_ring[BE_QUEUE].dma & DMA_BIT_MASK(32)); + rtl_write_dword(rtlpriv, REG_BKQ_DESA, + (u64) rtlpci->tx_ring[BK_QUEUE].dma & DMA_BIT_MASK(32)); + rtl_write_dword(rtlpriv, REG_HQ_DESA, + (u64) rtlpci->tx_ring[HIGH_QUEUE].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 (IS_92C_SERIAL(rtlhal->version)) + rtl_write_byte(rtlpriv, REG_PCIE_CTRL_REG + 3, 0x77); + else + rtl_write_byte(rtlpriv, REG_PCIE_CTRL_REG + 3, 0x22); + + rtl_write_dword(rtlpriv, REG_INT_MIG, 0); + + bytetmp = rtl_read_byte(rtlpriv, REG_APSD_CTRL); + rtl_write_byte(rtlpriv, REG_APSD_CTRL, bytetmp & ~BIT(6)); + do { + retry++; + bytetmp = rtl_read_byte(rtlpriv, REG_APSD_CTRL); + } while ((retry < 200) && (bytetmp & BIT(7))); + + _rtl92ce_gen_refresh_led_state(hw); + + rtl_write_dword(rtlpriv, REG_MCUTST_1, 0x0); + + return true; +} + +static void _rtl92ce_hw_configure(struct ieee80211_hw *hw) +{ + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + u8 reg_bw_opmode; + u32 reg_prsr; + + reg_bw_opmode = BW_OPMODE_20MHZ; + reg_prsr = RATE_ALL_CCK | RATE_ALL_OFDM_AG; + + rtl_write_byte(rtlpriv, REG_INIRTS_RATE_SEL, 0x8); + + rtl_write_byte(rtlpriv, REG_BWOPMODE, reg_bw_opmode); + + rtl_write_dword(rtlpriv, REG_RRSR, reg_prsr); + + rtl_write_byte(rtlpriv, REG_SLOT, 0x09); + + rtl_write_byte(rtlpriv, REG_AMPDU_MIN_SPACE, 0x0); + + rtl_write_word(rtlpriv, REG_FWHW_TXQ_CTRL, 0x1F80); + + rtl_write_word(rtlpriv, REG_RL, 0x0707); + + rtl_write_dword(rtlpriv, REG_BAR_MODE_CTRL, 0x02012802); + + rtl_write_byte(rtlpriv, REG_HWSEQ_CTRL, 0xFF); + + 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); + + if ((rtlpcipriv->bt_coexist.bt_coexistence) && + (rtlpcipriv->bt_coexist.bt_coexist_type == BT_CSR_BC4)) + rtl_write_dword(rtlpriv, REG_AGGLEN_LMT, 0x97427431); + else + rtl_write_dword(rtlpriv, REG_AGGLEN_LMT, 0xb972a841); + + rtl_write_byte(rtlpriv, REG_ATIMWND, 0x2); + + rtl_write_byte(rtlpriv, REG_BCN_MAX_ERR, 0xff); + + rtlpci->reg_bcn_ctrl_val = 0x1f; + rtl_write_byte(rtlpriv, REG_BCN_CTRL, rtlpci->reg_bcn_ctrl_val); + + rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 1, 0xff); + + rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 1, 0xff); + + rtl_write_byte(rtlpriv, REG_PIFS, 0x1C); + rtl_write_byte(rtlpriv, REG_AGGR_BREAK_TIME, 0x16); + + if ((rtlpcipriv->bt_coexist.bt_coexistence) && + (rtlpcipriv->bt_coexist.bt_coexist_type == BT_CSR_BC4)) { + rtl_write_word(rtlpriv, REG_NAV_PROT_LEN, 0x0020); + rtl_write_word(rtlpriv, REG_PROT_MODE_CTRL, 0x0402); + } else { + rtl_write_word(rtlpriv, REG_NAV_PROT_LEN, 0x0020); + rtl_write_word(rtlpriv, REG_NAV_PROT_LEN, 0x0020); + } + + if ((rtlpcipriv->bt_coexist.bt_coexistence) && + (rtlpcipriv->bt_coexist.bt_coexist_type == BT_CSR_BC4)) + rtl_write_dword(rtlpriv, REG_FAST_EDCA_CTRL, 0x03086666); + else + rtl_write_dword(rtlpriv, REG_FAST_EDCA_CTRL, 0x086666); + + rtl_write_byte(rtlpriv, REG_ACKTO, 0x40); + + rtl_write_word(rtlpriv, REG_SPEC_SIFS, 0x1010); + rtl_write_word(rtlpriv, REG_MAC_SPEC_SIFS, 0x1010); + + rtl_write_word(rtlpriv, REG_SIFS_CTX, 0x1010); + + rtl_write_word(rtlpriv, REG_SIFS_TRX, 0x1010); + + rtl_write_dword(rtlpriv, REG_MAR, 0xffffffff); + rtl_write_dword(rtlpriv, REG_MAR + 4, 0xffffffff); + +} + +static void _rtl92ce_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)); + + rtl_write_byte(rtlpriv, 0x34b, 0x93); + rtl_write_word(rtlpriv, 0x350, 0x870c); + rtl_write_byte(rtlpriv, 0x352, 0x1); + + if (ppsc->support_backdoor) + rtl_write_byte(rtlpriv, 0x349, 0x1b); + else + rtl_write_byte(rtlpriv, 0x349, 0x03); + + rtl_write_word(rtlpriv, 0x350, 0x2718); + rtl_write_byte(rtlpriv, 0x352, 0x1); +} + +void rtl92ce_enable_hw_security_config(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 sec_reg_value; + + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "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(rtlpriv, 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); + + rtl_write_byte(rtlpriv, REG_CR + 1, 0x02); + + RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, + "The SECR-value %x\n", sec_reg_value); + + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_WPA_CONFIG, &sec_reg_value); + +} + +int rtl92ce_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_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + static bool iqk_initialized; /* initialized to false */ + bool rtstatus = true; + bool is92c; + int err; + u8 tmp_u1b; + + rtlpci->being_init_adapter = true; + rtlpriv->intf_ops->disable_aspm(hw); + rtstatus = _rtl92ce_init_mac(hw); + if (!rtstatus) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Init MAC failed\n"); + err = 1; + return err; + } + + err = rtl92c_download_fw(hw); + if (err) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, + "Failed to download FW. Init HW without FW now..\n"); + err = 1; + return err; + } + + rtlhal->last_hmeboxnum = 0; + rtl92c_phy_mac_config(hw); + rtl92c_phy_bb_config(hw); + rtlphy->rf_mode = RF_OP_BY_SW_3WIRE; + rtl92c_phy_rf_config(hw); + rtlphy->rfreg_chnlval[0] = rtl_get_rfreg(hw, (enum radio_path)0, + RF_CHNLBW, RFREG_OFFSET_MASK); + rtlphy->rfreg_chnlval[1] = rtl_get_rfreg(hw, (enum radio_path)1, + RF_CHNLBW, RFREG_OFFSET_MASK); + rtl_set_bbreg(hw, RFPGA0_RFMOD, BCCKEN, 0x1); + rtl_set_bbreg(hw, RFPGA0_RFMOD, BOFDMEN, 0x1); + rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER2, BIT(10), 1); + _rtl92ce_hw_configure(hw); + rtl_cam_reset_all_entry(hw); + rtl92ce_enable_hw_security_config(hw); + + ppsc->rfpwr_state = ERFON; + + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_ETHER_ADDR, mac->mac_addr); + _rtl92ce_enable_aspm_back_door(hw); + rtlpriv->intf_ops->enable_aspm(hw); + + rtl8192ce_bt_hw_init(hw); + + if (ppsc->rfpwr_state == ERFON) { + rtl92c_phy_set_rfpath_switch(hw, 1); + if (iqk_initialized) { + rtl92c_phy_iq_calibrate(hw, true); + } else { + rtl92c_phy_iq_calibrate(hw, false); + iqk_initialized = true; + } + + rtl92c_dm_check_txpower_tracking(hw); + rtl92c_phy_lc_calibrate(hw); + } + + is92c = IS_92C_SERIAL(rtlhal->version); + tmp_u1b = efuse_read_1byte(hw, 0x1FA); + if (!(tmp_u1b & BIT(0))) { + rtl_set_rfreg(hw, RF90_PATH_A, 0x15, 0x0F, 0x05); + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "PA BIAS path A\n"); + } + + if (!(tmp_u1b & BIT(1)) && is92c) { + rtl_set_rfreg(hw, RF90_PATH_B, 0x15, 0x0F, 0x05); + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "PA BIAS path B\n"); + } + + if (!(tmp_u1b & BIT(4))) { + tmp_u1b = rtl_read_byte(rtlpriv, 0x16); + tmp_u1b &= 0x0F; + rtl_write_byte(rtlpriv, 0x16, tmp_u1b | 0x80); + udelay(10); + rtl_write_byte(rtlpriv, 0x16, tmp_u1b | 0x90); + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "under 1.5V\n"); + } + rtl92c_dm_init(hw); + rtlpci->being_init_adapter = false; + return err; +} + +static enum version_8192c _rtl92ce_read_chip_version(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + enum version_8192c version = VERSION_UNKNOWN; + u32 value32; + const char *versionid; + + value32 = rtl_read_dword(rtlpriv, REG_SYS_CFG); + if (value32 & TRP_VAUX_EN) { + version = (value32 & TYPE_ID) ? VERSION_A_CHIP_92C : + VERSION_A_CHIP_88C; + } else { + version = (value32 & TYPE_ID) ? VERSION_B_CHIP_92C : + VERSION_B_CHIP_88C; + } + + switch (version) { + case VERSION_B_CHIP_92C: + versionid = "B_CHIP_92C"; + break; + case VERSION_B_CHIP_88C: + versionid = "B_CHIP_88C"; + break; + case VERSION_A_CHIP_92C: + versionid = "A_CHIP_92C"; + break; + case VERSION_A_CHIP_88C: + versionid = "A_CHIP_88C"; + break; + default: + versionid = "Unknown. Bug?"; + break; + } + + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + "Chip Version ID: %s\n", versionid); + + switch (version & 0x3) { + case CHIP_88C: + rtlphy->rf_type = RF_1T1R; + break; + case CHIP_92C: + rtlphy->rf_type = RF_2T2R; + break; + case CHIP_92C_1T2R: + rtlphy->rf_type = RF_1T2R; + break; + default: + rtlphy->rf_type = RF_1T1R; + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "ERROR RF_Type is set!!\n"); + break; + } + + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "Chip RF Type: %s\n", + rtlphy->rf_type == RF_2T2R ? "RF_2T2R" : "RF_1T1R"); + + return version; +} + +static int _rtl92ce_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; + bt_msr &= 0xfc; + + if (type == NL80211_IFTYPE_UNSPECIFIED || + type == NL80211_IFTYPE_STATION) { + _rtl92ce_stop_tx_beacon(hw); + _rtl92ce_enable_bcn_sub_func(hw); + } else if (type == NL80211_IFTYPE_ADHOC || type == NL80211_IFTYPE_AP) { + _rtl92ce_resume_tx_beacon(hw); + _rtl92ce_disable_bcn_sub_func(hw); + } else { + RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, + "Set HW_VAR_MEDIA_STATUS: No such media status(%x)\n", + type); + } + + switch (type) { + case NL80211_IFTYPE_UNSPECIFIED: + bt_msr |= MSR_NOLINK; + ledaction = LED_CTL_LINK; + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + "Set Network type to NO LINK!\n"); + break; + case NL80211_IFTYPE_ADHOC: + bt_msr |= MSR_ADHOC; + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + "Set Network type to Ad Hoc!\n"); + break; + case NL80211_IFTYPE_STATION: + bt_msr |= MSR_INFRA; + ledaction = LED_CTL_LINK; + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + "Set Network type to STA!\n"); + break; + case NL80211_IFTYPE_AP: + bt_msr |= MSR_AP; + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + "Set Network type to AP!\n"); + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "Network type %d not supported!\n", type); + return 1; + break; + + } + + rtl_write_byte(rtlpriv, (MSR), bt_msr); + rtlpriv->cfg->ops->led_control(hw, ledaction); + if ((bt_msr & 0xfc) == MSR_AP) + rtl_write_byte(rtlpriv, REG_BCNTCFG + 1, 0x00); + else + rtl_write_byte(rtlpriv, REG_BCNTCFG + 1, 0x66); + return 0; +} + +void rtl92ce_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 reg_rcr = rtl_read_dword(rtlpriv, REG_RCR); + + if (rtlpriv->psc.rfpwr_state != ERFON) + return; + + if (check_bssid) { + reg_rcr |= (RCR_CBSSID_DATA | RCR_CBSSID_BCN); + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR, + (u8 *) (®_rcr)); + _rtl92ce_set_bcn_ctrl_reg(hw, 0, BIT(4)); + } else if (!check_bssid) { + reg_rcr &= (~(RCR_CBSSID_DATA | RCR_CBSSID_BCN)); + _rtl92ce_set_bcn_ctrl_reg(hw, BIT(4), 0); + rtlpriv->cfg->ops->set_hw_reg(hw, + HW_VAR_RCR, (u8 *) (®_rcr)); + } + +} + +int rtl92ce_set_network_type(struct ieee80211_hw *hw, enum nl80211_iftype type) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + if (_rtl92ce_set_media_status(hw, type)) + return -EOPNOTSUPP; + + if (rtlpriv->mac80211.link_state == MAC80211_LINKED) { + if (type != NL80211_IFTYPE_AP) + rtl92ce_set_check_bssid(hw, true); + } else { + rtl92ce_set_check_bssid(hw, false); + } + + return 0; +} + +/* don't set REG_EDCA_BE_PARAM here because mac80211 will send pkt when scan */ +void rtl92ce_set_qos(struct ieee80211_hw *hw, int aci) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + rtl92c_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; + } +} + +void rtl92ce_enable_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, rtlpci->irq_mask[0] & 0xFFFFFFFF); + rtl_write_dword(rtlpriv, REG_HIMRE, rtlpci->irq_mask[1] & 0xFFFFFFFF); +} + +void rtl92ce_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, IMR8190_DISABLED); + rtl_write_dword(rtlpriv, REG_HIMRE, IMR8190_DISABLED); + synchronize_irq(rtlpci->pdev->irq); +} + +static void _rtl92ce_poweroff_adapter(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + u8 u1b_tmp; + u32 u4b_tmp; + + rtlpriv->intf_ops->enable_aspm(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_RF_CTRL, 0x00); + rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x40); + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE2); + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE0); + if (rtl_read_byte(rtlpriv, REG_MCUFWDL) & BIT(7)) + rtl92c_firmware_selfreset(hw); + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, 0x51); + rtl_write_byte(rtlpriv, REG_MCUFWDL, 0x00); + rtl_write_dword(rtlpriv, REG_GPIO_PIN_CTRL, 0x00000000); + u1b_tmp = rtl_read_byte(rtlpriv, REG_GPIO_PIN_CTRL); + if ((rtlpcipriv->bt_coexist.bt_coexistence) && + ((rtlpcipriv->bt_coexist.bt_coexist_type == BT_CSR_BC4) || + (rtlpcipriv->bt_coexist.bt_coexist_type == BT_CSR_BC8))) { + rtl_write_dword(rtlpriv, REG_GPIO_PIN_CTRL, 0x00F30000 | + (u1b_tmp << 8)); + } else { + rtl_write_dword(rtlpriv, REG_GPIO_PIN_CTRL, 0x00FF0000 | + (u1b_tmp << 8)); + } + rtl_write_word(rtlpriv, REG_GPIO_IO_SEL, 0x0790); + rtl_write_word(rtlpriv, REG_LEDCFG0, 0x8080); + rtl_write_byte(rtlpriv, REG_AFE_PLL_CTRL, 0x80); + rtl_write_byte(rtlpriv, REG_SPS0_CTRL, 0x23); + if (rtlpcipriv->bt_coexist.bt_coexistence) { + u4b_tmp = rtl_read_dword(rtlpriv, REG_AFE_XTAL_CTRL); + u4b_tmp |= 0x03824800; + rtl_write_dword(rtlpriv, REG_AFE_XTAL_CTRL, u4b_tmp); + } else { + rtl_write_dword(rtlpriv, REG_AFE_XTAL_CTRL, 0x0e); + } + + rtl_write_byte(rtlpriv, REG_RSV_CTRL, 0x0e); + rtl_write_byte(rtlpriv, REG_APS_FSMCO + 1, 0x10); +} + +void rtl92ce_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_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + enum nl80211_iftype opmode; + + mac->link_state = MAC80211_NOLINK; + opmode = NL80211_IFTYPE_UNSPECIFIED; + _rtl92ce_set_media_status(hw, opmode); + if (rtlpci->driver_is_goingto_unload || + ppsc->rfoff_reason > RF_CHANGE_BY_PS) + rtlpriv->cfg->ops->led_control(hw, LED_CTL_POWER_OFF); + RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC); + _rtl92ce_poweroff_adapter(hw); +} + +void rtl92ce_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, ISR + 4, *p_intb); + */ +} + +void rtl92ce_set_beacon_related_registers(struct ieee80211_hw *hw) +{ + + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + u16 bcn_interval, atim_window; + + bcn_interval = mac->beacon_interval; + atim_window = 2; /*FIX MERGE */ + rtl92ce_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); + rtl92ce_enable_interrupt(hw); +} + +void rtl92ce_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(rtlpriv, COMP_BEACON, DBG_DMESG, + "beacon_interval:%d\n", bcn_interval); + rtl92ce_disable_interrupt(hw); + rtl_write_word(rtlpriv, REG_BCN_INTERVAL, bcn_interval); + rtl92ce_enable_interrupt(hw); +} + +void rtl92ce_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(rtlpriv, 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); + rtl92ce_disable_interrupt(hw); + rtl92ce_enable_interrupt(hw); +} + +static void _rtl92ce_read_txpower_info_from_hwpg(struct ieee80211_hw *hw, + bool autoload_fail, + u8 *hwinfo) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + u8 rf_path, index, tempval; + u16 i; + + for (rf_path = 0; rf_path < 2; rf_path++) { + for (i = 0; i < 3; i++) { + if (!autoload_fail) { + rtlefuse-> + eeprom_chnlarea_txpwr_cck[rf_path][i] = + hwinfo[EEPROM_TXPOWERCCK + rf_path * 3 + i]; + rtlefuse-> + eeprom_chnlarea_txpwr_ht40_1s[rf_path][i] = + hwinfo[EEPROM_TXPOWERHT40_1S + rf_path * 3 + + i]; + } else { + rtlefuse-> + eeprom_chnlarea_txpwr_cck[rf_path][i] = + EEPROM_DEFAULT_TXPOWERLEVEL; + rtlefuse-> + eeprom_chnlarea_txpwr_ht40_1s[rf_path][i] = + EEPROM_DEFAULT_TXPOWERLEVEL; + } + } + } + + for (i = 0; i < 3; i++) { + if (!autoload_fail) + tempval = hwinfo[EEPROM_TXPOWERHT40_2SDIFF + i]; + else + tempval = EEPROM_DEFAULT_HT40_2SDIFF; + rtlefuse->eeprom_chnlarea_txpwr_ht40_2sdiif[RF90_PATH_A][i] = + (tempval & 0xf); + rtlefuse->eeprom_chnlarea_txpwr_ht40_2sdiif[RF90_PATH_B][i] = + ((tempval & 0xf0) >> 4); + } + + for (rf_path = 0; rf_path < 2; rf_path++) + for (i = 0; i < 3; i++) + RTPRINT(rtlpriv, FINIT, INIT_EEPROM, + "RF(%d) EEPROM CCK Area(%d) = 0x%x\n", + rf_path, i, + rtlefuse-> + eeprom_chnlarea_txpwr_cck[rf_path][i]); + for (rf_path = 0; rf_path < 2; rf_path++) + for (i = 0; i < 3; i++) + RTPRINT(rtlpriv, FINIT, INIT_EEPROM, + "RF(%d) EEPROM HT40 1S Area(%d) = 0x%x\n", + rf_path, i, + rtlefuse-> + eeprom_chnlarea_txpwr_ht40_1s[rf_path][i]); + for (rf_path = 0; rf_path < 2; rf_path++) + for (i = 0; i < 3; i++) + RTPRINT(rtlpriv, FINIT, INIT_EEPROM, + "RF(%d) EEPROM HT40 2S Diff Area(%d) = 0x%x\n", + rf_path, i, + rtlefuse-> + eeprom_chnlarea_txpwr_ht40_2sdiif[rf_path][i]); + + for (rf_path = 0; rf_path < 2; rf_path++) { + for (i = 0; i < 14; i++) { + index = _rtl92c_get_chnl_group((u8) i); + + rtlefuse->txpwrlevel_cck[rf_path][i] = + rtlefuse->eeprom_chnlarea_txpwr_cck[rf_path][index]; + rtlefuse->txpwrlevel_ht40_1s[rf_path][i] = + rtlefuse-> + eeprom_chnlarea_txpwr_ht40_1s[rf_path][index]; + + if ((rtlefuse-> + eeprom_chnlarea_txpwr_ht40_1s[rf_path][index] - + rtlefuse-> + eeprom_chnlarea_txpwr_ht40_2sdiif[rf_path][index]) + > 0) { + rtlefuse->txpwrlevel_ht40_2s[rf_path][i] = + rtlefuse-> + eeprom_chnlarea_txpwr_ht40_1s[rf_path] + [index] - + rtlefuse-> + eeprom_chnlarea_txpwr_ht40_2sdiif[rf_path] + [index]; + } else { + rtlefuse->txpwrlevel_ht40_2s[rf_path][i] = 0; + } + } + + for (i = 0; i < 14; i++) { + RTPRINT(rtlpriv, FINIT, INIT_TxPower, + "RF(%d)-Ch(%d) [CCK / HT40_1S / HT40_2S] = [0x%x / 0x%x / 0x%x]\n", + rf_path, i, + rtlefuse->txpwrlevel_cck[rf_path][i], + rtlefuse->txpwrlevel_ht40_1s[rf_path][i], + rtlefuse->txpwrlevel_ht40_2s[rf_path][i]); + } + } + + for (i = 0; i < 3; i++) { + if (!autoload_fail) { + rtlefuse->eeprom_pwrlimit_ht40[i] = + hwinfo[EEPROM_TXPWR_GROUP + i]; + rtlefuse->eeprom_pwrlimit_ht20[i] = + hwinfo[EEPROM_TXPWR_GROUP + 3 + i]; + } else { + rtlefuse->eeprom_pwrlimit_ht40[i] = 0; + rtlefuse->eeprom_pwrlimit_ht20[i] = 0; + } + } + + for (rf_path = 0; rf_path < 2; rf_path++) { + for (i = 0; i < 14; i++) { + index = _rtl92c_get_chnl_group((u8) i); + + if (rf_path == RF90_PATH_A) { + rtlefuse->pwrgroup_ht20[rf_path][i] = + (rtlefuse->eeprom_pwrlimit_ht20[index] + & 0xf); + rtlefuse->pwrgroup_ht40[rf_path][i] = + (rtlefuse->eeprom_pwrlimit_ht40[index] + & 0xf); + } else if (rf_path == RF90_PATH_B) { + rtlefuse->pwrgroup_ht20[rf_path][i] = + ((rtlefuse->eeprom_pwrlimit_ht20[index] + & 0xf0) >> 4); + rtlefuse->pwrgroup_ht40[rf_path][i] = + ((rtlefuse->eeprom_pwrlimit_ht40[index] + & 0xf0) >> 4); + } + + RTPRINT(rtlpriv, FINIT, INIT_TxPower, + "RF-%d pwrgroup_ht20[%d] = 0x%x\n", + rf_path, i, + rtlefuse->pwrgroup_ht20[rf_path][i]); + RTPRINT(rtlpriv, FINIT, INIT_TxPower, + "RF-%d pwrgroup_ht40[%d] = 0x%x\n", + rf_path, i, + rtlefuse->pwrgroup_ht40[rf_path][i]); + } + } + + for (i = 0; i < 14; i++) { + index = _rtl92c_get_chnl_group((u8) i); + + if (!autoload_fail) + tempval = hwinfo[EEPROM_TXPOWERHT20DIFF + index]; + else + tempval = EEPROM_DEFAULT_HT20_DIFF; + + rtlefuse->txpwr_ht20diff[RF90_PATH_A][i] = (tempval & 0xF); + rtlefuse->txpwr_ht20diff[RF90_PATH_B][i] = + ((tempval >> 4) & 0xF); + + if (rtlefuse->txpwr_ht20diff[RF90_PATH_A][i] & BIT(3)) + rtlefuse->txpwr_ht20diff[RF90_PATH_A][i] |= 0xF0; + + if (rtlefuse->txpwr_ht20diff[RF90_PATH_B][i] & BIT(3)) + rtlefuse->txpwr_ht20diff[RF90_PATH_B][i] |= 0xF0; + + index = _rtl92c_get_chnl_group((u8) i); + + if (!autoload_fail) + tempval = hwinfo[EEPROM_TXPOWER_OFDMDIFF + index]; + else + tempval = EEPROM_DEFAULT_LEGACYHTTXPOWERDIFF; + + rtlefuse->txpwr_legacyhtdiff[RF90_PATH_A][i] = (tempval & 0xF); + rtlefuse->txpwr_legacyhtdiff[RF90_PATH_B][i] = + ((tempval >> 4) & 0xF); + } + + rtlefuse->legacy_ht_txpowerdiff = + rtlefuse->txpwr_legacyhtdiff[RF90_PATH_A][7]; + + for (i = 0; i < 14; i++) + RTPRINT(rtlpriv, FINIT, INIT_TxPower, + "RF-A Ht20 to HT40 Diff[%d] = 0x%x\n", + i, rtlefuse->txpwr_ht20diff[RF90_PATH_A][i]); + for (i = 0; i < 14; i++) + RTPRINT(rtlpriv, FINIT, INIT_TxPower, + "RF-A Legacy to Ht40 Diff[%d] = 0x%x\n", + i, rtlefuse->txpwr_legacyhtdiff[RF90_PATH_A][i]); + for (i = 0; i < 14; i++) + RTPRINT(rtlpriv, FINIT, INIT_TxPower, + "RF-B Ht20 to HT40 Diff[%d] = 0x%x\n", + i, rtlefuse->txpwr_ht20diff[RF90_PATH_B][i]); + for (i = 0; i < 14; i++) + RTPRINT(rtlpriv, FINIT, INIT_TxPower, + "RF-B Legacy to HT40 Diff[%d] = 0x%x\n", + i, rtlefuse->txpwr_legacyhtdiff[RF90_PATH_B][i]); + + if (!autoload_fail) + rtlefuse->eeprom_regulatory = (hwinfo[RF_OPTION1] & 0x7); + else + rtlefuse->eeprom_regulatory = 0; + RTPRINT(rtlpriv, FINIT, INIT_TxPower, + "eeprom_regulatory = 0x%x\n", rtlefuse->eeprom_regulatory); + + if (!autoload_fail) { + rtlefuse->eeprom_tssi[RF90_PATH_A] = hwinfo[EEPROM_TSSI_A]; + rtlefuse->eeprom_tssi[RF90_PATH_B] = hwinfo[EEPROM_TSSI_B]; + } else { + rtlefuse->eeprom_tssi[RF90_PATH_A] = EEPROM_DEFAULT_TSSI; + rtlefuse->eeprom_tssi[RF90_PATH_B] = EEPROM_DEFAULT_TSSI; + } + RTPRINT(rtlpriv, FINIT, INIT_TxPower, "TSSI_A = 0x%x, TSSI_B = 0x%x\n", + rtlefuse->eeprom_tssi[RF90_PATH_A], + rtlefuse->eeprom_tssi[RF90_PATH_B]); + + if (!autoload_fail) + tempval = hwinfo[EEPROM_THERMAL_METER]; + else + tempval = EEPROM_DEFAULT_THERMALMETER; + rtlefuse->eeprom_thermalmeter = (tempval & 0x1f); + + if (rtlefuse->eeprom_thermalmeter == 0x1f || autoload_fail) + rtlefuse->apk_thermalmeterignore = true; + + rtlefuse->thermalmeter[0] = rtlefuse->eeprom_thermalmeter; + RTPRINT(rtlpriv, FINIT, INIT_TxPower, + "thermalmeter = 0x%x\n", rtlefuse->eeprom_thermalmeter); +} + +static void _rtl92ce_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) { + rtl_efuse_shadow_map_update(hw); + + memcpy((void *)hwinfo, + (void *)&rtlefuse->efuse_map[EFUSE_INIT_MAP][0], + HWSET_MAX_SIZE); + } else if (rtlefuse->epromtype == EEPROM_93C46) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "RTL819X Not boot from eeprom, check it !!"); + } + + RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_DMESG, "MAP", + hwinfo, HWSET_MAX_SIZE); + + eeprom_id = *((u16 *)&hwinfo[0]); + if (eeprom_id != RTL8190_EEPROM_ID) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, + "EEPROM ID(%#x) is invalid!!\n", eeprom_id); + rtlefuse->autoload_failflag = true; + } else { + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "Autoload OK\n"); + rtlefuse->autoload_failflag = false; + } + + if (rtlefuse->autoload_failflag) + return; + + for (i = 0; i < 6; i += 2) { + usvalue = *(u16 *)&hwinfo[EEPROM_MAC_ADDR + i]; + *((u16 *) (&rtlefuse->dev_addr[i])) = usvalue; + } + + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "%pM\n", rtlefuse->dev_addr); + + _rtl92ce_read_txpower_info_from_hwpg(hw, + rtlefuse->autoload_failflag, + hwinfo); + + rtl8192ce_read_bt_coexist_info_from_hwpg(hw, + rtlefuse->autoload_failflag, + hwinfo); + + rtlefuse->eeprom_channelplan = *(u8 *)&hwinfo[EEPROM_CHANNELPLAN]; + rtlefuse->eeprom_version = *(u16 *)&hwinfo[EEPROM_VERSION]; + rtlefuse->txpwr_fromeprom = true; + rtlefuse->eeprom_oemid = *(u8 *)&hwinfo[EEPROM_CUSTOMER_ID]; + + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "EEPROM Customer ID: 0x%2x\n", rtlefuse->eeprom_oemid); + + /* set channel paln to world wide 13 */ + rtlefuse->channel_plan = COUNTRY_CODE_WORLD_WIDE_13; + + if (rtlhal->oem_id == RT_CID_DEFAULT) { + switch (rtlefuse->eeprom_oemid) { + case EEPROM_CID_DEFAULT: + if (rtlefuse->eeprom_did == 0x8176) { + if ((rtlefuse->eeprom_svid == 0x103C && + rtlefuse->eeprom_smid == 0x1629)) + rtlhal->oem_id = RT_CID_819x_HP; + else + rtlhal->oem_id = RT_CID_DEFAULT; + } else { + rtlhal->oem_id = RT_CID_DEFAULT; + } + break; + case EEPROM_CID_TOSHIBA: + rtlhal->oem_id = RT_CID_TOSHIBA; + break; + case EEPROM_CID_QMI: + rtlhal->oem_id = RT_CID_819x_QMI; + break; + case EEPROM_CID_WHQL: + default: + rtlhal->oem_id = RT_CID_DEFAULT; + break; + + } + } + +} + +static void _rtl92ce_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)); + + switch (rtlhal->oem_id) { + case RT_CID_819x_HP: + pcipriv->ledctl.led_opendrain = true; + break; + case RT_CID_819x_Lenovo: + case RT_CID_DEFAULT: + case RT_CID_TOSHIBA: + case RT_CID_CCX: + case RT_CID_819x_Acer: + case RT_CID_WHQL: + default: + break; + } + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "RT Customized ID: 0x%02X\n", rtlhal->oem_id); +} + +void rtl92ce_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 = _rtl92ce_read_chip_version(hw); + if (get_rf_type(rtlphy) == RF_1T1R) + rtlpriv->dm.rfpath_rxenable[0] = true; + else + rtlpriv->dm.rfpath_rxenable[0] = + rtlpriv->dm.rfpath_rxenable[1] = true; + RT_TRACE(rtlpriv, 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(rtlpriv, COMP_INIT, DBG_DMESG, "Boot from EEPROM\n"); + rtlefuse->epromtype = EEPROM_93C46; + } else { + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "Boot from EFUSE\n"); + rtlefuse->epromtype = EEPROM_BOOT_EFUSE; + } + if (tmp_u1b & BIT(5)) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "Autoload OK\n"); + rtlefuse->autoload_failflag = false; + _rtl92ce_read_adapter_info(hw); + } else { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Autoload ERR!!\n"); + } + _rtl92ce_hal_customized_behavior(hw); +} + +static void rtl92ce_update_hal_rate_table(struct ieee80211_hw *hw, + struct ieee80211_sta *sta) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u32 ratr_value; + u8 ratr_index = 0; + u8 nmode = mac->ht_enable; + u8 mimo_ps = IEEE80211_SMPS_OFF; + u16 shortgi_rate; + u32 tmp_ratr_value; + u8 curtxbw_40mhz = mac->bw_40; + u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ? + 1 : 0; + u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ? + 1 : 0; + enum wireless_mode wirelessmode = mac->mode; + + if (rtlhal->current_bandtype == BAND_ON_5G) + ratr_value = sta->supp_rates[1] << 4; + else + ratr_value = sta->supp_rates[0]; + ratr_value |= (sta->ht_cap.mcs.rx_mask[1] << 20 | + sta->ht_cap.mcs.rx_mask[0] << 12); + switch (wirelessmode) { + case WIRELESS_MODE_B: + if (ratr_value & 0x0000000c) + ratr_value &= 0x0000000d; + else + ratr_value &= 0x0000000f; + break; + case WIRELESS_MODE_G: + ratr_value &= 0x00000FF5; + break; + case WIRELESS_MODE_N_24G: + case WIRELESS_MODE_N_5G: + nmode = 1; + if (mimo_ps == IEEE80211_SMPS_STATIC) { + ratr_value &= 0x0007F005; + } else { + u32 ratr_mask; + + if (get_rf_type(rtlphy) == RF_1T2R || + get_rf_type(rtlphy) == RF_1T1R) + ratr_mask = 0x000ff005; + else + ratr_mask = 0x0f0ff005; + + ratr_value &= ratr_mask; + } + break; + default: + if (rtlphy->rf_type == RF_1T2R) + ratr_value &= 0x000ff0ff; + else + ratr_value &= 0x0f0ff0ff; + + break; + } + + if ((rtlpcipriv->bt_coexist.bt_coexistence) && + (rtlpcipriv->bt_coexist.bt_coexist_type == BT_CSR_BC4) && + (rtlpcipriv->bt_coexist.bt_cur_state) && + (rtlpcipriv->bt_coexist.bt_ant_isolation) && + ((rtlpcipriv->bt_coexist.bt_service == BT_SCO) || + (rtlpcipriv->bt_coexist.bt_service == BT_BUSY))) + ratr_value &= 0x0fffcfc0; + else + ratr_value &= 0x0FFFFFFF; + + if (nmode && ((curtxbw_40mhz && + curshortgi_40mhz) || (!curtxbw_40mhz && + curshortgi_20mhz))) { + + ratr_value |= 0x10000000; + tmp_ratr_value = (ratr_value >> 12); + + for (shortgi_rate = 15; shortgi_rate > 0; shortgi_rate--) { + if ((1 << shortgi_rate) & tmp_ratr_value) + break; + } + + shortgi_rate = (shortgi_rate << 12) | (shortgi_rate << 8) | + (shortgi_rate << 4) | (shortgi_rate); + } + + rtl_write_dword(rtlpriv, REG_ARFR0 + ratr_index * 4, ratr_value); + + RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG, "%x\n", + rtl_read_dword(rtlpriv, REG_ARFR0)); +} + +static void rtl92ce_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_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_sta_info *sta_entry = NULL; + u32 ratr_bitmap; + u8 ratr_index; + u8 curtxbw_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) + ? 1 : 0; + u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ? + 1 : 0; + u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ? + 1 : 0; + enum wireless_mode wirelessmode = 0; + bool shortgi = false; + u8 rate_mask[5]; + 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) + curtxbw_40mhz = mac->bw_40; + else if (mac->opmode == NL80211_IFTYPE_AP || + mac->opmode == NL80211_IFTYPE_ADHOC) + macid = sta->aid + 1; + + if (rtlhal->current_bandtype == BAND_ON_5G) + ratr_bitmap = sta->supp_rates[1] << 4; + else + ratr_bitmap = sta->supp_rates[0]; + 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_A: + ratr_index = RATR_INX_WIRELESS_A; + ratr_bitmap &= 0x00000ff0; + break; + case WIRELESS_MODE_N_24G: + case WIRELESS_MODE_N_5G: + ratr_index = RATR_INX_WIRELESS_NGB; + + if (mimo_ps == IEEE80211_SMPS_STATIC) { + if (rssi_level == 1) + ratr_bitmap &= 0x00070000; + else if (rssi_level == 2) + ratr_bitmap &= 0x0007f000; + else + ratr_bitmap &= 0x0007f005; + } else { + if (rtlphy->rf_type == RF_1T2R || + rtlphy->rf_type == RF_1T1R) { + if (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 (curtxbw_40mhz) { + if (rssi_level == 1) + ratr_bitmap &= 0x0f0f0000; + else if (rssi_level == 2) + ratr_bitmap &= 0x0f0ff000; + else + ratr_bitmap &= 0x0f0ff015; + } else { + if (rssi_level == 1) + ratr_bitmap &= 0x0f0f0000; + else if (rssi_level == 2) + ratr_bitmap &= 0x0f0ff000; + else + ratr_bitmap &= 0x0f0ff005; + } + } + } + + if ((curtxbw_40mhz && curshortgi_40mhz) || + (!curtxbw_40mhz && curshortgi_20mhz)) { + + if (macid == 0) + shortgi = true; + else if (macid == 1) + shortgi = false; + } + break; + default: + ratr_index = RATR_INX_WIRELESS_NGB; + + if (rtlphy->rf_type == RF_1T2R) + ratr_bitmap &= 0x000ff0ff; + else + ratr_bitmap &= 0x0f0ff0ff; + break; + } + RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG, + "ratr_bitmap :%x\n", ratr_bitmap); + *(u32 *)&rate_mask = EF4BYTE((ratr_bitmap & 0x0fffffff) | + (ratr_index << 28)); + rate_mask[4] = macid | (shortgi ? 0x20 : 0x00) | 0x80; + RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG, + "Rate_index:%x, ratr_val:%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]); + rtl92c_fill_h2c_cmd(hw, H2C_RA_MASK, 5, rate_mask); + + if (macid != 0) + sta_entry->ratr_index = ratr_index; +} + +void rtl92ce_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.useramask) + rtl92ce_update_hal_rate_mask(hw, sta, rssi_level); + else + rtl92ce_update_hal_rate_table(hw, sta); +} + +void rtl92ce_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 = 0x1010; + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SIFS, (u8 *)&sifs_timer); +} + +bool rtl92ce_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 *valid) +{ + 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)); + enum rf_pwrstate e_rfpowerstate_toset; + u8 u1tmp; + bool actuallyset = false; + unsigned long flag; + + if (rtlpci->being_init_adapter) + return false; + + if (ppsc->swrf_processing) + return false; + + spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flag); + if (ppsc->rfchange_inprogress) { + spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag); + return false; + } else { + ppsc->rfchange_inprogress = true; + spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag); + } + + rtl_write_byte(rtlpriv, REG_MAC_PINMUX_CFG, rtl_read_byte(rtlpriv, + REG_MAC_PINMUX_CFG)&~(BIT(3))); + + u1tmp = rtl_read_byte(rtlpriv, REG_GPIO_IO_SEL); + e_rfpowerstate_toset = (u1tmp & BIT(3)) ? ERFON : ERFOFF; + + if ((ppsc->hwradiooff) && (e_rfpowerstate_toset == ERFON)) { + RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG, + "GPIOChangeRF - HW Radio ON, RF ON\n"); + + e_rfpowerstate_toset = ERFON; + ppsc->hwradiooff = false; + actuallyset = true; + } else if (!ppsc->hwradiooff && (e_rfpowerstate_toset == ERFOFF)) { + RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG, + "GPIOChangeRF - HW Radio OFF, RF OFF\n"); + + e_rfpowerstate_toset = ERFOFF; + ppsc->hwradiooff = true; + actuallyset = true; + } + + if (actuallyset) { + spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flag); + ppsc->rfchange_inprogress = false; + spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag); + } else { + if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_HALT_NIC) + RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC); + + spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flag); + ppsc->rfchange_inprogress = false; + spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag); + } + + *valid = 1; + return !ppsc->hwradiooff; + +} + +void rtl92ce_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(rtlpriv, COMP_SEC, DBG_DMESG, "clear_all\n"); + + for (idx = 0; idx < clear_number; idx++) { + rtl_cam_mark_invalid(hw, cam_offset + idx); + 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(rtlpriv, COMP_ERR, DBG_EMERG, + "switch case not processed\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) { + entry_id = rtl_cam_get_free_entry(hw, + p_macaddr); + if (entry_id >= TOTAL_CAM_ENTRY) { + RT_TRACE(rtlpriv, 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(rtlpriv, COMP_SEC, DBG_DMESG, + "delete one entry, entry_id is %d\n", + entry_id); + if (mac->opmode == NL80211_IFTYPE_AP) + rtl_cam_del_entry(hw, p_macaddr); + rtl_cam_delete_one_entry(hw, p_macaddr, entry_id); + } else { + RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, + "The insert KEY length is %d\n", + rtlpriv->sec.key_len[PAIRWISE_KEYIDX]); + RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, + "The insert KEY is %x %x\n", + rtlpriv->sec.key_buf[0][0], + rtlpriv->sec.key_buf[0][1]); + + RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, + "add one entry\n"); + if (is_pairwise) { + RT_PRINT_DATA(rtlpriv, COMP_SEC, DBG_LOUD, + "Pairwise Key content", + rtlpriv->sec.pairwise_key, + rtlpriv->sec. + key_len[PAIRWISE_KEYIDX]); + + RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, + "set Pairwise key\n"); + + 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(rtlpriv, COMP_SEC, DBG_DMESG, + "set group key\n"); + + if (mac->opmode == NL80211_IFTYPE_ADHOC) { + 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]); + } + + rtl_cam_add_one_entry(hw, macaddr, key_index, + entry_id, enc_algo, + CAM_CONFIG_NO_USEDK, + rtlpriv->sec.key_buf[entry_id]); + } + + } + } +} + +static void rtl8192ce_bt_var_init(struct ieee80211_hw *hw) +{ + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + + rtlpcipriv->bt_coexist.bt_coexistence = + rtlpcipriv->bt_coexist.eeprom_bt_coexist; + rtlpcipriv->bt_coexist.bt_ant_num = + rtlpcipriv->bt_coexist.eeprom_bt_ant_num; + rtlpcipriv->bt_coexist.bt_coexist_type = + rtlpcipriv->bt_coexist.eeprom_bt_type; + + if (rtlpcipriv->bt_coexist.reg_bt_iso == 2) + rtlpcipriv->bt_coexist.bt_ant_isolation = + rtlpcipriv->bt_coexist.eeprom_bt_ant_isolation; + else + rtlpcipriv->bt_coexist.bt_ant_isolation = + rtlpcipriv->bt_coexist.reg_bt_iso; + + rtlpcipriv->bt_coexist.bt_radio_shared_type = + rtlpcipriv->bt_coexist.eeprom_bt_radio_shared; + + if (rtlpcipriv->bt_coexist.bt_coexistence) { + + if (rtlpcipriv->bt_coexist.reg_bt_sco == 1) + rtlpcipriv->bt_coexist.bt_service = BT_OTHER_ACTION; + else if (rtlpcipriv->bt_coexist.reg_bt_sco == 2) + rtlpcipriv->bt_coexist.bt_service = BT_SCO; + else if (rtlpcipriv->bt_coexist.reg_bt_sco == 4) + rtlpcipriv->bt_coexist.bt_service = BT_BUSY; + else if (rtlpcipriv->bt_coexist.reg_bt_sco == 5) + rtlpcipriv->bt_coexist.bt_service = BT_OTHERBUSY; + else + rtlpcipriv->bt_coexist.bt_service = BT_IDLE; + + rtlpcipriv->bt_coexist.bt_edca_ul = 0; + rtlpcipriv->bt_coexist.bt_edca_dl = 0; + rtlpcipriv->bt_coexist.bt_rssi_state = 0xff; + } +} + +void rtl8192ce_read_bt_coexist_info_from_hwpg(struct ieee80211_hw *hw, + bool auto_load_fail, u8 *hwinfo) +{ + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + u8 value; + + if (!auto_load_fail) { + rtlpcipriv->bt_coexist.eeprom_bt_coexist = + ((hwinfo[RF_OPTION1] & 0xe0) >> 5); + value = hwinfo[RF_OPTION4]; + rtlpcipriv->bt_coexist.eeprom_bt_type = ((value & 0xe) >> 1); + rtlpcipriv->bt_coexist.eeprom_bt_ant_num = (value & 0x1); + rtlpcipriv->bt_coexist.eeprom_bt_ant_isolation = + ((value & 0x10) >> 4); + rtlpcipriv->bt_coexist.eeprom_bt_radio_shared = + ((value & 0x20) >> 5); + } else { + rtlpcipriv->bt_coexist.eeprom_bt_coexist = 0; + rtlpcipriv->bt_coexist.eeprom_bt_type = BT_2WIRE; + rtlpcipriv->bt_coexist.eeprom_bt_ant_num = ANT_X2; + rtlpcipriv->bt_coexist.eeprom_bt_ant_isolation = 0; + rtlpcipriv->bt_coexist.eeprom_bt_radio_shared = BT_RADIO_SHARED; + } + + rtl8192ce_bt_var_init(hw); +} + +void rtl8192ce_bt_reg_init(struct ieee80211_hw *hw) +{ + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + + /* 0:Low, 1:High, 2:From Efuse. */ + rtlpcipriv->bt_coexist.reg_bt_iso = 2; + /* 0:Idle, 1:None-SCO, 2:SCO, 3:From Counter. */ + rtlpcipriv->bt_coexist.reg_bt_sco = 3; + /* 0:Disable BT control A-MPDU, 1:Enable BT control A-MPDU. */ + rtlpcipriv->bt_coexist.reg_bt_sco = 0; +} + + +void rtl8192ce_bt_hw_init(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + + u8 u1_tmp; + + if (rtlpcipriv->bt_coexist.bt_coexistence && + ((rtlpcipriv->bt_coexist.bt_coexist_type == BT_CSR_BC4) || + rtlpcipriv->bt_coexist.bt_coexist_type == BT_CSR_BC8)) { + + if (rtlpcipriv->bt_coexist.bt_ant_isolation) + rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG, 0xa0); + + u1_tmp = rtl_read_byte(rtlpriv, 0x4fd) & + BIT_OFFSET_LEN_MASK_32(0, 1); + u1_tmp = u1_tmp | + ((rtlpcipriv->bt_coexist.bt_ant_isolation == 1) ? + 0 : BIT_OFFSET_LEN_MASK_32(1, 1)) | + ((rtlpcipriv->bt_coexist.bt_service == BT_SCO) ? + 0 : BIT_OFFSET_LEN_MASK_32(2, 1)); + rtl_write_byte(rtlpriv, 0x4fd, u1_tmp); + + rtl_write_dword(rtlpriv, REG_BT_COEX_TABLE+4, 0xaaaa9aaa); + rtl_write_dword(rtlpriv, REG_BT_COEX_TABLE+8, 0xffbd0040); + rtl_write_dword(rtlpriv, REG_BT_COEX_TABLE+0xc, 0x40000010); + + /* Config to 1T1R. */ + if (rtlphy->rf_type == RF_1T1R) { + u1_tmp = rtl_read_byte(rtlpriv, ROFDM0_TRXPATHENABLE); + u1_tmp &= ~(BIT_OFFSET_LEN_MASK_32(1, 1)); + rtl_write_byte(rtlpriv, ROFDM0_TRXPATHENABLE, u1_tmp); + + u1_tmp = rtl_read_byte(rtlpriv, ROFDM1_TRXPATHENABLE); + u1_tmp &= ~(BIT_OFFSET_LEN_MASK_32(1, 1)); + rtl_write_byte(rtlpriv, ROFDM1_TRXPATHENABLE, u1_tmp); + } + } +} + +void rtl92ce_suspend(struct ieee80211_hw *hw) +{ +} + +void rtl92ce_resume(struct ieee80211_hw *hw) +{ +} diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.h b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.h new file mode 100644 index 00000000..52a3aea9 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.h @@ -0,0 +1,78 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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 __RTL92CE_HW_H__ +#define __RTL92CE_HW_H__ + +static inline u8 _rtl92c_get_chnl_group(u8 chnl) +{ + u8 group; + + if (chnl < 3) + group = 0; + else if (chnl < 9) + group = 1; + else + group = 2; + return group; +} + +void rtl92ce_get_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val); +void rtl92ce_read_eeprom_info(struct ieee80211_hw *hw); +void rtl92ce_interrupt_recognized(struct ieee80211_hw *hw, + u32 *p_inta, u32 *p_intb); +int rtl92ce_hw_init(struct ieee80211_hw *hw); +void rtl92ce_card_disable(struct ieee80211_hw *hw); +void rtl92ce_enable_interrupt(struct ieee80211_hw *hw); +void rtl92ce_disable_interrupt(struct ieee80211_hw *hw); +int rtl92ce_set_network_type(struct ieee80211_hw *hw, enum nl80211_iftype type); +void rtl92ce_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid); +void rtl92ce_set_qos(struct ieee80211_hw *hw, int aci); +void rtl92ce_set_beacon_related_registers(struct ieee80211_hw *hw); +void rtl92ce_set_beacon_interval(struct ieee80211_hw *hw); +void rtl92ce_update_interrupt_mask(struct ieee80211_hw *hw, + u32 add_msr, u32 rm_msr); +void rtl92ce_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val); +void rtl92ce_update_hal_rate_tbl(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, u8 rssi_level); +void rtl92ce_update_channel_access_setting(struct ieee80211_hw *hw); +bool rtl92ce_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 *valid); +void rtl92ce_enable_hw_security_config(struct ieee80211_hw *hw); +void rtl92ce_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 rtl8192ce_read_bt_coexist_info_from_hwpg(struct ieee80211_hw *hw, + bool autoload_fail, u8 *hwinfo); +void rtl8192ce_bt_reg_init(struct ieee80211_hw *hw); +void rtl8192ce_bt_hw_init(struct ieee80211_hw *hw); +void rtl92ce_suspend(struct ieee80211_hw *hw); +void rtl92ce_resume(struct ieee80211_hw *hw); + +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/led.c b/drivers/net/wireless/rtlwifi/rtl8192ce/led.c new file mode 100644 index 00000000..8283e9b2 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/led.c @@ -0,0 +1,151 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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> + * + *****************************************************************************/ + +#include "../wifi.h" +#include "../pci.h" +#include "reg.h" +#include "led.h" + +static void _rtl92ce_init_led(struct ieee80211_hw *hw, + struct rtl_led *pled, enum rtl_led_pin ledpin) +{ + pled->hw = hw; + pled->ledpin = ledpin; + pled->ledon = false; +} + +void rtl92ce_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled) +{ + u8 ledcfg; + struct rtl_priv *rtlpriv = rtl_priv(hw); + + RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD, "LedAddr:%X ledpin=%d\n", + REG_LEDCFG2, pled->ledpin); + + ledcfg = rtl_read_byte(rtlpriv, REG_LEDCFG2); + + switch (pled->ledpin) { + case LED_PIN_GPIO0: + break; + case LED_PIN_LED0: + rtl_write_byte(rtlpriv, + REG_LEDCFG2, (ledcfg & 0xf0) | BIT(5) | BIT(6)); + break; + case LED_PIN_LED1: + rtl_write_byte(rtlpriv, REG_LEDCFG2, (ledcfg & 0x0f) | BIT(5)); + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "switch case not processed\n"); + break; + } + pled->ledon = true; +} + +void rtl92ce_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); + u8 ledcfg; + + RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD, "LedAddr:%X ledpin=%d\n", + REG_LEDCFG2, pled->ledpin); + + ledcfg = rtl_read_byte(rtlpriv, REG_LEDCFG2); + + switch (pled->ledpin) { + case LED_PIN_GPIO0: + break; + case LED_PIN_LED0: + ledcfg &= 0xf0; + if (pcipriv->ledctl.led_opendrain) + rtl_write_byte(rtlpriv, REG_LEDCFG2, + (ledcfg | BIT(1) | BIT(5) | BIT(6))); + else + rtl_write_byte(rtlpriv, REG_LEDCFG2, + (ledcfg | BIT(3) | BIT(5) | BIT(6))); + break; + case LED_PIN_LED1: + ledcfg &= 0x0f; + rtl_write_byte(rtlpriv, REG_LEDCFG2, (ledcfg | BIT(3))); + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "switch case not processed\n"); + break; + } + pled->ledon = false; +} + +void rtl92ce_init_sw_leds(struct ieee80211_hw *hw) +{ + struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); + _rtl92ce_init_led(hw, &(pcipriv->ledctl.sw_led0), LED_PIN_LED0); + _rtl92ce_init_led(hw, &(pcipriv->ledctl.sw_led1), LED_PIN_LED1); +} + +static void _rtl92ce_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: + rtl92ce_sw_led_on(hw, pLed0); + break; + case LED_CTL_POWER_OFF: + rtl92ce_sw_led_off(hw, pLed0); + break; + default: + break; + } +} + +void rtl92ce_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(rtlpriv, COMP_LED, DBG_LOUD, "ledaction %d\n", + ledaction); + _rtl92ce_sw_led_control(hw, ledaction); +} diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/led.h b/drivers/net/wireless/rtlwifi/rtl8192ce/led.h new file mode 100644 index 00000000..c5761066 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/led.h @@ -0,0 +1,38 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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 __RTL92CE_LED_H__ +#define __RTL92CE_LED_H__ + +void rtl92ce_init_sw_leds(struct ieee80211_hw *hw); +void rtl92ce_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled); +void rtl92ce_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled); +void rtl92ce_led_control(struct ieee80211_hw *hw, enum led_ctl_mode ledaction); + +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/phy.c b/drivers/net/wireless/rtlwifi/rtl8192ce/phy.c new file mode 100644 index 00000000..88deae67 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/phy.c @@ -0,0 +1,620 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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> + * + *****************************************************************************/ + +#include "../wifi.h" +#include "../pci.h" +#include "../ps.h" +#include "reg.h" +#include "def.h" +#include "hw.h" +#include "phy.h" +#include "rf.h" +#include "dm.h" +#include "table.h" + +static bool _rtl92c_phy_config_mac_with_headerfile(struct ieee80211_hw *hw); + +u32 rtl92c_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; + struct rtl_phy *rtlphy = &(rtlpriv->phy); + + RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, + "regaddr(%#x), rfpath(%#x), bitmask(%#x)\n", + regaddr, rfpath, bitmask); + + spin_lock(&rtlpriv->locks.rf_lock); + + if (rtlphy->rf_mode != RF_OP_BY_FW) { + original_value = _rtl92c_phy_rf_serial_read(hw, + rfpath, regaddr); + } else { + original_value = _rtl92c_phy_fw_rf_serial_read(hw, + rfpath, regaddr); + } + + bitshift = _rtl92c_phy_calculate_bit_shift(bitmask); + readback_value = (original_value & bitmask) >> bitshift; + + spin_unlock(&rtlpriv->locks.rf_lock); + + RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, + "regaddr(%#x), rfpath(%#x), bitmask(%#x), original_value(%#x)\n", + regaddr, rfpath, bitmask, original_value); + + return readback_value; +} + +bool rtl92c_phy_mac_config(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + bool is92c = IS_92C_SERIAL(rtlhal->version); + bool rtstatus = _rtl92c_phy_config_mac_with_headerfile(hw); + + if (is92c) + rtl_write_byte(rtlpriv, 0x14, 0x71); + return rtstatus; +} + +bool rtl92c_phy_bb_config(struct ieee80211_hw *hw) +{ + bool rtstatus = true; + struct rtl_priv *rtlpriv = rtl_priv(hw); + u16 regval; + u32 regvaldw; + u8 reg_hwparafile = 1; + + _rtl92c_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_AFE_PLL_CTRL, 0x83); + rtl_write_byte(rtlpriv, REG_AFE_PLL_CTRL + 1, 0xdb); + 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); + regvaldw = rtl_read_dword(rtlpriv, REG_LEDCFG0); + rtl_write_dword(rtlpriv, REG_LEDCFG0, regvaldw | BIT(23)); + if (reg_hwparafile == 1) + rtstatus = _rtl92c_phy_bb8192c_config_parafile(hw); + return rtstatus; +} + +void rtl92ce_phy_set_rf_reg(struct ieee80211_hw *hw, + enum radio_path rfpath, + u32 regaddr, u32 bitmask, u32 data) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + u32 original_value, bitshift; + + RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, + "regaddr(%#x), bitmask(%#x), data(%#x), rfpath(%#x)\n", + regaddr, bitmask, data, rfpath); + + spin_lock(&rtlpriv->locks.rf_lock); + + if (rtlphy->rf_mode != RF_OP_BY_FW) { + if (bitmask != RFREG_OFFSET_MASK) { + original_value = _rtl92c_phy_rf_serial_read(hw, + rfpath, + regaddr); + bitshift = _rtl92c_phy_calculate_bit_shift(bitmask); + data = + ((original_value & (~bitmask)) | + (data << bitshift)); + } + + _rtl92c_phy_rf_serial_write(hw, rfpath, regaddr, data); + } else { + if (bitmask != RFREG_OFFSET_MASK) { + original_value = _rtl92c_phy_fw_rf_serial_read(hw, + rfpath, + regaddr); + bitshift = _rtl92c_phy_calculate_bit_shift(bitmask); + data = + ((original_value & (~bitmask)) | + (data << bitshift)); + } + _rtl92c_phy_fw_rf_serial_write(hw, rfpath, regaddr, data); + } + + spin_unlock(&rtlpriv->locks.rf_lock); + + RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, + "regaddr(%#x), bitmask(%#x), data(%#x), rfpath(%#x)\n", + regaddr, bitmask, data, rfpath); +} + +static bool _rtl92c_phy_config_mac_with_headerfile(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 i; + u32 arraylength; + u32 *ptrarray; + + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "Read Rtl819XMACPHY_Array\n"); + arraylength = MAC_2T_ARRAYLENGTH; + ptrarray = RTL8192CEMAC_2T_ARRAY; + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "Img:RTL8192CEMAC_2T_ARRAY\n"); + for (i = 0; i < arraylength; i = i + 2) + rtl_write_byte(rtlpriv, ptrarray[i], (u8) ptrarray[i + 1]); + return true; +} + +bool _rtl92ce_phy_config_bb_with_headerfile(struct ieee80211_hw *hw, + u8 configtype) +{ + int i; + u32 *phy_regarray_table; + u32 *agctab_array_table; + u16 phy_reg_arraylen, agctab_arraylen; + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + + if (IS_92C_SERIAL(rtlhal->version)) { + agctab_arraylen = AGCTAB_2TARRAYLENGTH; + agctab_array_table = RTL8192CEAGCTAB_2TARRAY; + phy_reg_arraylen = PHY_REG_2TARRAY_LENGTH; + phy_regarray_table = RTL8192CEPHY_REG_2TARRAY; + } else { + agctab_arraylen = AGCTAB_1TARRAYLENGTH; + agctab_array_table = RTL8192CEAGCTAB_1TARRAY; + phy_reg_arraylen = PHY_REG_1TARRAY_LENGTH; + phy_regarray_table = RTL8192CEPHY_REG_1TARRAY; + } + if (configtype == BASEBAND_CONFIG_PHY_REG) { + for (i = 0; i < phy_reg_arraylen; i = i + 2) { + if (phy_regarray_table[i] == 0xfe) + mdelay(50); + else if (phy_regarray_table[i] == 0xfd) + mdelay(5); + else if (phy_regarray_table[i] == 0xfc) + mdelay(1); + else if (phy_regarray_table[i] == 0xfb) + udelay(50); + else if (phy_regarray_table[i] == 0xfa) + udelay(5); + else if (phy_regarray_table[i] == 0xf9) + udelay(1); + rtl_set_bbreg(hw, phy_regarray_table[i], MASKDWORD, + phy_regarray_table[i + 1]); + udelay(1); + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + "The phy_regarray_table[0] is %x Rtl819XPHY_REGArray[1] is %x\n", + phy_regarray_table[i], + phy_regarray_table[i + 1]); + } + } else if (configtype == BASEBAND_CONFIG_AGC_TAB) { + for (i = 0; i < agctab_arraylen; i = i + 2) { + rtl_set_bbreg(hw, agctab_array_table[i], MASKDWORD, + agctab_array_table[i + 1]); + udelay(1); + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + "The agctab_array_table[0] is %x Rtl819XPHY_REGArray[1] is %x\n", + agctab_array_table[i], + agctab_array_table[i + 1]); + } + } + return true; +} + +bool _rtl92ce_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; + + phy_regarray_pg_len = PHY_REG_ARRAY_PGLENGTH; + phy_regarray_table_pg = RTL8192CEPHY_REG_ARRAY_PG; + + if (configtype == BASEBAND_CONFIG_PHY_REG) { + for (i = 0; i < phy_regarray_pg_len; i = i + 3) { + if (phy_regarray_table_pg[i] == 0xfe) + mdelay(50); + else if (phy_regarray_table_pg[i] == 0xfd) + mdelay(5); + else if (phy_regarray_table_pg[i] == 0xfc) + mdelay(1); + else if (phy_regarray_table_pg[i] == 0xfb) + udelay(50); + else if (phy_regarray_table_pg[i] == 0xfa) + udelay(5); + else if (phy_regarray_table_pg[i] == 0xf9) + udelay(1); + + _rtl92c_store_pwrIndex_diffrate_offset(hw, + phy_regarray_table_pg[i], + phy_regarray_table_pg[i + 1], + phy_regarray_table_pg[i + 2]); + } + } else { + + RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE, + "configtype != BaseBand_Config_PHY_REG\n"); + } + return true; +} + +bool rtl92c_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, + enum radio_path rfpath) +{ + + int i; + u32 *radioa_array_table; + u32 *radiob_array_table; + u16 radioa_arraylen, radiob_arraylen; + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + + if (IS_92C_SERIAL(rtlhal->version)) { + radioa_arraylen = RADIOA_2TARRAYLENGTH; + radioa_array_table = RTL8192CERADIOA_2TARRAY; + radiob_arraylen = RADIOB_2TARRAYLENGTH; + radiob_array_table = RTL8192CE_RADIOB_2TARRAY; + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + "Radio_A:RTL8192CERADIOA_2TARRAY\n"); + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + "Radio_B:RTL8192CE_RADIOB_2TARRAY\n"); + } else { + radioa_arraylen = RADIOA_1TARRAYLENGTH; + radioa_array_table = RTL8192CE_RADIOA_1TARRAY; + radiob_arraylen = RADIOB_1TARRAYLENGTH; + radiob_array_table = RTL8192CE_RADIOB_1TARRAY; + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + "Radio_A:RTL8192CE_RADIOA_1TARRAY\n"); + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + "Radio_B:RTL8192CE_RADIOB_1TARRAY\n"); + } + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "Radio No %x\n", rfpath); + switch (rfpath) { + case RF90_PATH_A: + for (i = 0; i < radioa_arraylen; i = i + 2) { + if (radioa_array_table[i] == 0xfe) + mdelay(50); + else if (radioa_array_table[i] == 0xfd) + mdelay(5); + else if (radioa_array_table[i] == 0xfc) + mdelay(1); + else if (radioa_array_table[i] == 0xfb) + udelay(50); + else if (radioa_array_table[i] == 0xfa) + udelay(5); + else if (radioa_array_table[i] == 0xf9) + udelay(1); + else { + rtl_set_rfreg(hw, rfpath, radioa_array_table[i], + RFREG_OFFSET_MASK, + radioa_array_table[i + 1]); + udelay(1); + } + } + break; + case RF90_PATH_B: + for (i = 0; i < radiob_arraylen; i = i + 2) { + if (radiob_array_table[i] == 0xfe) { + mdelay(50); + } else if (radiob_array_table[i] == 0xfd) + mdelay(5); + else if (radiob_array_table[i] == 0xfc) + mdelay(1); + else if (radiob_array_table[i] == 0xfb) + udelay(50); + else if (radiob_array_table[i] == 0xfa) + udelay(5); + else if (radiob_array_table[i] == 0xf9) + udelay(1); + else { + rtl_set_rfreg(hw, rfpath, radiob_array_table[i], + RFREG_OFFSET_MASK, + radiob_array_table[i + 1]); + udelay(1); + } + } + break; + case RF90_PATH_C: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "switch case not processed\n"); + break; + case RF90_PATH_D: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "switch case not processed\n"); + break; + } + return true; +} + +void rtl92ce_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(rtlpriv, 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(rtlpriv, 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, RFPGA0_ANALOGPARAMETER2, BIT(10), 1); + 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, RFPGA0_ANALOGPARAMETER2, BIT(10), 0); + + 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(rtlpriv, COMP_ERR, DBG_EMERG, + "unknown bandwidth: %#X\n", rtlphy->current_chan_bw); + break; + } + rtl92ce_phy_rf6052_set_bandwidth(hw, rtlphy->current_chan_bw); + rtlphy->set_bwmode_inprogress = false; + RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE, "<==\n"); +} + +void _rtl92ce_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); + } +} + +static void _rtl92ce_phy_set_rf_sleep(struct ieee80211_hw *hw) +{ + u32 u4b_tmp; + u8 delay = 5; + 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_APSD_CTRL, 0x40); + u4b_tmp = rtl_get_rfreg(hw, RF90_PATH_A, 0, RFREG_OFFSET_MASK); + while (u4b_tmp != 0 && delay > 0) { + rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x0); + rtl_set_rfreg(hw, RF90_PATH_A, 0x00, RFREG_OFFSET_MASK, 0x00); + rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x40); + u4b_tmp = rtl_get_rfreg(hw, RF90_PATH_A, 0, RFREG_OFFSET_MASK); + delay--; + } + if (delay == 0) { + 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); + RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE, + "Switch RF timeout !!!\n"); + return; + } + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE2); + rtl_write_byte(rtlpriv, REG_SPS0_CTRL, 0x22); +} + +static bool _rtl92ce_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 InitializeCount = 0; + do { + InitializeCount++; + RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG, + "IPS Set eRf nic enable\n"); + rtstatus = rtl_ps_enable_nic(hw); + } while (!rtstatus && (InitializeCount < 10)); + RT_CLEAR_PS_LEVEL(ppsc, + RT_RF_OFF_LEVL_HALT_NIC); + } else { + RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG, + "Set ERFON sleeped:%d ms\n", + jiffies_to_msecs(jiffies - + ppsc-> + last_sleep_jiffies)); + ppsc->last_awake_jiffies = jiffies; + rtl92ce_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:{ + if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_HALT_NIC) { + RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG, + "IPS Set eRf nic disable\n"); + 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) + return false; + 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(rtlpriv, 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(rtlpriv, COMP_ERR, DBG_WARNING, + "ERFSLEEP: %d times TcbBusyQueue[%d] = %d !\n", + MAX_DOZE_WAITING_TIMES_9x, + queue_id, + skb_queue_len(&ring->queue)); + break; + } + } + RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG, + "Set ERFSLEEP awaked:%d ms\n", + jiffies_to_msecs(jiffies - + ppsc->last_awake_jiffies)); + ppsc->last_sleep_jiffies = jiffies; + _rtl92ce_phy_set_rf_sleep(hw); + break; + } + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "switch case not processed\n"); + bresult = false; + break; + } + if (bresult) + ppsc->rfpwr_state = rfpwr_state; + return bresult; +} + +bool rtl92c_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 = _rtl92ce_phy_set_rf_power_state(hw, rfpwr_state); + return bresult; +} diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/phy.h b/drivers/net/wireless/rtlwifi/rtl8192ce/phy.h new file mode 100644 index 00000000..d5e3b704 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/phy.h @@ -0,0 +1,262 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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 __RTL92C_PHY_H__ +#define __RTL92C_PHY_H__ + +#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 MAX_TOLERANCE 5 +#define IQK_DELAY_TIME 1 + +#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 IQK_ADDA_REG_NUM 16 +#define IQK_MAC_REG_NUM 4 + +#define IQK_DELAY_TIME 1 + +#define RF90_PATH_MAX 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_DIF 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 hw90_block_e { + HW90_BLOCK_MAC = 0, + HW90_BLOCK_PHY0 = 1, + HW90_BLOCK_PHY1 = 2, + HW90_BLOCK_RF = 3, + HW90_BLOCK_MAXIMUM = 4, +}; + +enum baseband_config_type { + BASEBAND_CONFIG_PHY_REG = 0, + BASEBAND_CONFIG_AGC_TAB = 1, +}; + +enum ra_offset_area { + RA_OFFSET_LEGACY_OFDM1, + RA_OFFSET_LEGACY_OFDM2, + RA_OFFSET_HT_OFDM1, + RA_OFFSET_HT_OFDM2, + RA_OFFSET_HT_OFDM3, + RA_OFFSET_HT_OFDM4, + RA_OFFSET_HT_CCK, +}; + +enum antenna_path { + ANTENNA_NONE, + ANTENNA_D, + ANTENNA_C, + ANTENNA_CD, + ANTENNA_B, + ANTENNA_BD, + ANTENNA_BC, + ANTENNA_BCD, + ANTENNA_A, + ANTENNA_AD, + ANTENNA_AC, + ANTENNA_ACD, + ANTENNA_AB, + ANTENNA_ABD, + ANTENNA_ABC, + ANTENNA_ABCD +}; + +struct r_antenna_select_ofdm { + u32 r_tx_antenna:4; + u32 r_ant_l:4; + u32 r_ant_non_ht:4; + u32 r_ant_ht1:4; + u32 r_ant_ht2:4; + u32 r_ant_ht_s1:4; + u32 r_ant_non_ht_s1:4; + u32 ofdm_txsc:2; + u32 reserved:2; +}; + +struct r_antenna_select_cck { + u8 r_cckrx_enable_2:2; + u8 r_cckrx_enable:2; + u8 r_ccktx_enable:4; +}; + +struct efuse_contents { + u8 mac_addr[ETH_ALEN]; + u8 cck_tx_power_idx[6]; + u8 ht40_1s_tx_power_idx[6]; + u8 ht40_2s_tx_power_idx_diff[3]; + u8 ht20_tx_power_idx_diff[3]; + u8 ofdm_tx_power_idx_diff[3]; + u8 ht40_max_power_offset[3]; + u8 ht20_max_power_offset[3]; + u8 channel_plan; + u8 thermal_meter; + u8 rf_option[5]; + u8 version; + u8 oem_id; + u8 regulatory; +}; + +struct tx_power_struct { + u8 cck[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER]; + u8 ht40_1s[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER]; + u8 ht40_2s[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER]; + u8 ht20_diff[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER]; + u8 legacy_ht_diff[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER]; + u8 legacy_ht_txpowerdiff; + u8 groupht20[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER]; + u8 groupht40[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER]; + u8 pwrgroup_cnt; + u32 mcs_original_offset[4][16]; +}; + +bool rtl92c_phy_bb_config(struct ieee80211_hw *hw); +u32 rtl92c_phy_query_bb_reg(struct ieee80211_hw *hw, + u32 regaddr, u32 bitmask); +void rtl92c_phy_set_bb_reg(struct ieee80211_hw *hw, + u32 regaddr, u32 bitmask, u32 data); +u32 rtl92c_phy_query_rf_reg(struct ieee80211_hw *hw, + enum radio_path rfpath, u32 regaddr, + u32 bitmask); +extern void rtl92ce_phy_set_rf_reg(struct ieee80211_hw *hw, + enum radio_path rfpath, u32 regaddr, + u32 bitmask, u32 data); +bool rtl92c_phy_mac_config(struct ieee80211_hw *hw); +bool rtl92ce_phy_bb_config(struct ieee80211_hw *hw); +bool rtl92c_phy_rf_config(struct ieee80211_hw *hw); +bool rtl92c_phy_config_rf_with_feaderfile(struct ieee80211_hw *hw, + enum radio_path rfpath); +void rtl92c_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw); +void rtl92c_phy_get_txpower_level(struct ieee80211_hw *hw, + long *powerlevel); +void rtl92c_phy_set_txpower_level(struct ieee80211_hw *hw, u8 channel); +bool rtl92c_phy_update_txpower_dbm(struct ieee80211_hw *hw, + long power_indbm); +void rtl92c_phy_scan_operation_backup(struct ieee80211_hw *hw, + u8 operation); +void rtl92c_phy_set_bw_mode(struct ieee80211_hw *hw, + enum nl80211_channel_type ch_type); +void rtl92c_phy_sw_chnl_callback(struct ieee80211_hw *hw); +u8 rtl92c_phy_sw_chnl(struct ieee80211_hw *hw); +void rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery); +void rtl92c_phy_set_beacon_hw_reg(struct ieee80211_hw *hw, + u16 beaconinterval); +void rtl92c_phy_ap_calibrate(struct ieee80211_hw *hw, char delta); +void rtl92c_phy_lc_calibrate(struct ieee80211_hw *hw); +void _rtl92ce_phy_lc_calibrate(struct ieee80211_hw *hw, bool is2t); +void rtl92c_phy_set_rfpath_switch(struct ieee80211_hw *hw, bool bmain); +bool rtl92c_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, + enum radio_path rfpath); +bool rtl8192_phy_check_is_legal_rfpath(struct ieee80211_hw *hw, + u32 rfpath); +bool rtl92c_phy_set_io_cmd(struct ieee80211_hw *hw, enum io_type iotype); +bool rtl92ce_phy_set_rf_power_state(struct ieee80211_hw *hw, + enum rf_pwrstate rfpwr_state); +void rtl92ce_phy_set_rf_on(struct ieee80211_hw *hw); +bool rtl92c_phy_set_io_cmd(struct ieee80211_hw *hw, enum io_type iotype); +void rtl92c_phy_set_io(struct ieee80211_hw *hw); +void rtl92c_bb_block_on(struct ieee80211_hw *hw); +u32 _rtl92c_phy_rf_serial_read(struct ieee80211_hw *hw, + enum radio_path rfpath, u32 offset); +u32 _rtl92c_phy_fw_rf_serial_read(struct ieee80211_hw *hw, + enum radio_path rfpath, u32 offset); +u32 _rtl92c_phy_calculate_bit_shift(u32 bitmask); +void _rtl92c_phy_rf_serial_write(struct ieee80211_hw *hw, + enum radio_path rfpath, u32 offset, + u32 data); +void _rtl92c_phy_fw_rf_serial_write(struct ieee80211_hw *hw, + enum radio_path rfpath, u32 offset, + u32 data); +void _rtl92c_store_pwrIndex_diffrate_offset(struct ieee80211_hw *hw, + u32 regaddr, u32 bitmask, + u32 data); +bool _rtl92ce_phy_config_mac_with_headerfile(struct ieee80211_hw *hw); +void _rtl92c_phy_init_bb_rf_register_definition(struct ieee80211_hw *hw); +bool _rtl92c_phy_bb8192c_config_parafile(struct ieee80211_hw *hw); +void _rtl92c_phy_set_rf_sleep(struct ieee80211_hw *hw); +bool rtl92c_phy_set_rf_power_state(struct ieee80211_hw *hw, + enum rf_pwrstate rfpwr_state); +bool _rtl92ce_phy_config_bb_with_headerfile(struct ieee80211_hw *hw, + u8 configtype); +bool _rtl92ce_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw, + u8 configtype); +void rtl92ce_phy_set_bw_mode_callback(struct ieee80211_hw *hw); + +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/reg.h b/drivers/net/wireless/rtlwifi/rtl8192ce/reg.h new file mode 100644 index 00000000..e4d738f6 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/reg.h @@ -0,0 +1,2091 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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 __RTL92C_REG_H__ +#define __RTL92C_REG_H__ + +#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_AFE_MISC 0x0010 +#define REG_SPS0_CTRL 0x0011 +#define REG_SPS_OCP_CFG 0x0018 +#define REG_RSV_CTRL 0x001C +#define REG_RF_CTRL 0x001F +#define REG_LDOA15_CTRL 0x0020 +#define REG_LDOV12D_CTRL 0x0021 +#define REG_LDOHCI12_CTRL 0x0022 +#define REG_LPLDO_CTRL 0x0023 +#define REG_AFE_XTAL_CTRL 0x0024 +#define REG_AFE_PLL_CTRL 0x0028 +#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 + +/* RTL8723 WIFI/BT/GPS Multi-Function GPIO Pin Control. */ +#define REG_GPIO_PIN_CTRL_2 0x0060 +/* RTL8723 WIFI/BT/GPS Multi-Function GPIO Select. */ +#define REG_GPIO_IO_SEL_2 0x0062 +/* RTL8723 WIFI/BT/GPS Multi-Function control source. */ +#define REG_MULTI_FUNC_CTRL 0x0068 + +#define REG_MCUFWDL 0x0080 + +#define REG_HMEBOX_EXT_0 0x0088 +#define REG_HMEBOX_EXT_1 0x008A +#define REG_HMEBOX_EXT_2 0x008C +#define REG_HMEBOX_EXT_3 0x008E + +#define REG_BIST_SCAN 0x00D0 +#define REG_BIST_RPT 0x00D4 +#define REG_BIST_ROM_RPT 0x00D8 +#define REG_USB_SIE_INTF 0x00E0 +#define REG_PCIE_MIO_INTF 0x00E4 +#define REG_PCIE_MIO_INTD 0x00E8 +#define REG_HPON_FSM 0x00EC +#define REG_SYS_CFG 0x00F0 +#define REG_GPIO_OUTSTS 0x00F4 /* For RTL8723 only.*/ + +#define REG_CR 0x0100 +#define REG_PBP 0x0104 +#define REG_TRXDMA_CTRL 0x010C +#define REG_TRXFF_BNDY 0x0114 +#define REG_TRXFF_STATUS 0x0118 +#define REG_RXFF_PTR 0x011C +#define REG_HIMR 0x0120 +#define REG_HISR 0x0124 +#define REG_HIMRE 0x0128 +#define REG_HISRE 0x012C +#define REG_CPWM 0x012F +#define REG_FWIMR 0x0130 +#define REG_FWISR 0x0134 +#define REG_PKTBUF_DBG_CTRL 0x0140 +#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_MBIST_START 0x0174 +#define REG_MBIST_DONE 0x0178 +#define REG_MBIST_FAIL 0x017C +#define REG_C2HEVT_MSG_NORMAL 0x01A0 +#define REG_C2HEVT_MSG_TEST 0x01B8 +#define REG_C2HEVT_CLEAR 0x01BF +#define REG_MCUTST_1 0x01c0 +#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_BB_ACCEESS_CTRL 0x01E8 +#define REG_BB_ACCESS_DATA 0x01EC + +#define REG_RQPN 0x0200 +#define REG_FIFOPAGE 0x0204 +#define REG_TDECTRL 0x0208 +#define REG_TXDMA_OFFSET_CHK 0x020C +#define REG_TXDMA_STATUS 0x0210 +#define REG_RQPN_NPQ 0x0214 + +#define REG_RXDMA_AGG_PG_TH 0x0280 +#define REG_RXPKT_NUM 0x0284 +#define REG_RXDMA_STATUS 0x0288 + +#define REG_PCIE_CTRL_REG 0x0300 +#define REG_INT_MIG 0x0304 +#define REG_BCNQ_DESA 0x0308 +#define REG_HQ_DESA 0x0310 +#define REG_MGQ_DESA 0x0318 +#define REG_VOQ_DESA 0x0320 +#define REG_VIQ_DESA 0x0328 +#define REG_BEQ_DESA 0x0330 +#define REG_BKQ_DESA 0x0338 +#define REG_RX_DESA 0x0340 +#define REG_DBI 0x0348 +#define REG_MDIO 0x0354 +#define REG_DBG_SEL 0x0360 +#define REG_PCIE_HRPWM 0x0361 +#define REG_PCIE_HCPWM 0x0363 +#define REG_UART_CTRL 0x0364 +#define REG_UART_TX_DESA 0x0370 +#define REG_UART_RX_DESA 0x0378 + +#define REG_HDAQ_DESA_NODEF 0x0000 +#define REG_CMDQ_DESA_NODEF 0x0000 + +#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_CPU_MGQ_INFORMATION 0x041C +#define REG_FWHW_TXQ_CTRL 0x0420 +#define REG_HWSEQ_CTRL 0x0423 +#define REG_TXPKTBUF_BCNQ_BDNY 0x0424 +#define REG_TXPKTBUF_MGQ_BDNY 0x0425 +#define REG_MULTI_BCNQ_EN 0x0426 +#define REG_MULTI_BCNQ_OFFSET 0x0427 +#define REG_SPEC_SIFS 0x0428 +#define REG_RL 0x042A +#define REG_DARFRC 0x0430 +#define REG_RARFRC 0x0438 +#define REG_RRSR 0x0440 +#define REG_ARFR0 0x0444 +#define REG_ARFR1 0x0448 +#define REG_ARFR2 0x044C +#define REG_ARFR3 0x0450 +#define REG_AGGLEN_LMT 0x0458 +#define REG_AMPDU_MIN_SPACE 0x045C +#define REG_TXPKTBUF_WMAC_LBK_BF_HD 0x045D +#define REG_FAST_EDCA_CTRL 0x0460 +#define REG_RD_RESP_PKT_TH 0x0463 +#define REG_INIRTS_RATE_SEL 0x0480 +#define REG_INIDATA_RATE_SEL 0x0484 +#define REG_POWER_STATUS 0x04A4 +#define REG_POWER_STAGE1 0x04B4 +#define REG_POWER_STAGE2 0x04B8 +#define REG_PKT_LIFE_TIME 0x04C0 +#define REG_STBC_SETTING 0x04C4 +#define REG_PROT_MODE_CTRL 0x04C8 +#define REG_BAR_MODE_CTRL 0x04CC +#define REG_RA_TRY_RATE_AGG_LMT 0x04CF +#define REG_NQOS_SEQ 0x04DC +#define REG_QOS_SEQ 0x04DE +#define REG_NEED_CPU_HANDLE 0x04E0 +#define REG_PKT_LOSE_RPT 0x04E1 +#define REG_PTCL_ERR_STATUS 0x04E2 +#define REG_DUMMY 0x04FC + +#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_SIFS_CCK 0x0514 +#define REG_SIFS_OFDM 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_USTIME_TSF 0x0551 +#define REG_MBID_NUM 0x0552 +#define REG_DUAL_TSF_RST 0x0553 +#define REG_BCN_INTERVAL 0x0554 +#define REG_MBSSID_BCN_SPACE 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_INIT_TSFTR 0x0564 +#define REG_PSTIMER 0x0580 +#define REG_TIMER0 0x0584 +#define REG_TIMER1 0x0588 +#define REG_ACMHWCTRL 0x05C0 +#define REG_ACMRSTCTRL 0x05C1 +#define REG_ACMAVG 0x05C2 +#define REG_VO_ADMTIME 0x05C4 +#define REG_VI_ADMTIME 0x05C6 +#define REG_BE_ADMTIME 0x05C8 +#define REG_EDCA_RANDOM_GEN 0x05CC +#define REG_SCH_TXCMD 0x05D0 + +#define REG_APSD_CTRL 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 +/* [15:8]SIFS_R2T_OFDM, [7:0]SIFS_R2T_CCK */ +#define REG_R2T_SIFS 0x063C +/* [15:8]SIFS_T2T_OFDM, [7:0]SIFS_T2T_CCK */ +#define REG_T2T_SIFS 0x063E +#define REG_ACKTO 0x0640 +#define REG_CTS2TO 0x0641 +#define REG_EIFS 0x0642 + +#define REG_NAV_CTRL 0x0650 +#define REG_BACAMCMD 0x0654 +#define REG_BACAMCONTENT 0x0658 +#define REG_LBDLY 0x0660 +#define REG_FWDLY 0x0661 +#define REG_RXERR_RPT 0x0664 +#define REG_WMAC_TRXPTCL_CTL 0x0668 + +#define REG_CAMCMD 0x0670 +#define REG_CAMWRITE 0x0674 +#define REG_CAMREAD 0x0678 +#define REG_CAMDBG 0x067C +#define REG_SECCFG 0x0680 + +#define REG_WOW_CTRL 0x0690 +#define REG_PSSTATUS 0x0691 +#define REG_PS_RX_INFO 0x0692 +#define REG_LPNAV_CTRL 0x0694 +#define REG_WKFMCAM_CMD 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_CALB32K_CTRL 0x06AC +#define REG_PKT_MON_CTRL 0x06B4 +#define REG_BT_COEX_TABLE 0x06C0 +#define REG_WMAC_RESP_TXINFO 0x06D8 + +#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_TEST_USB_TXQS 0xFE48 +#define REG_TEST_SIE_VID 0xFE60 +#define REG_TEST_SIE_PID 0xFE62 +#define REG_TEST_SIE_OPTIONAL 0xFE64 +#define REG_TEST_SIE_CHIRP_K 0xFE65 +#define REG_TEST_SIE_PHY 0xFE66 +#define REG_TEST_SIE_MAC_ADDR 0xFE70 +#define REG_TEST_SIE_STRING 0xFE80 + +#define REG_NORMAL_SIE_VID 0xFE60 +#define REG_NORMAL_SIE_PID 0xFE62 +#define REG_NORMAL_SIE_OPTIONAL 0xFE64 +#define REG_NORMAL_SIE_EP 0xFE65 +#define REG_NORMAL_SIE_PHY 0xFE68 +#define REG_NORMAL_SIE_MAC_ADDR 0xFE70 +#define REG_NORMAL_SIE_STRING 0xFE80 + +#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 BW_OPMODE_11J BIT(0) + +#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 + +#define WOW_PMEN BIT(0) +#define WOW_WOMEN BIT(1) +#define WOW_MAGIC BIT(2) +#define WOW_UWF BIT(3) + +#define IMR8190_DISABLED 0x0 +#define IMR_BCNDMAINT6 BIT(31) +#define IMR_BCNDMAINT5 BIT(30) +#define IMR_BCNDMAINT4 BIT(29) +#define IMR_BCNDMAINT3 BIT(28) +#define IMR_BCNDMAINT2 BIT(27) +#define IMR_BCNDMAINT1 BIT(26) +#define IMR_BCNDOK8 BIT(25) +#define IMR_BCNDOK7 BIT(24) +#define IMR_BCNDOK6 BIT(23) +#define IMR_BCNDOK5 BIT(22) +#define IMR_BCNDOK4 BIT(21) +#define IMR_BCNDOK3 BIT(20) +#define IMR_BCNDOK2 BIT(19) +#define IMR_BCNDOK1 BIT(18) +#define IMR_TIMEOUT2 BIT(17) +#define IMR_TIMEOUT1 BIT(16) +#define IMR_TXFOVW BIT(15) +#define IMR_PSTIMEOUT BIT(14) +#define IMR_BCNINT BIT(13) +#define IMR_RXFOVW BIT(12) +#define IMR_RDU BIT(11) +#define IMR_ATIMEND BIT(10) +#define IMR_BDOK BIT(9) +#define IMR_HIGHDOK BIT(8) +#define IMR_TBDOK BIT(7) +#define IMR_MGNTDOK BIT(6) +#define IMR_TBDER BIT(5) +#define IMR_BKDOK BIT(4) +#define IMR_BEDOK BIT(3) +#define IMR_VIDOK BIT(2) +#define IMR_VODOK BIT(1) +#define IMR_ROK BIT(0) + +#define IMR_TXERR BIT(11) +#define IMR_RXERR BIT(10) +#define IMR_C2HCMD BIT(9) +#define IMR_CPWM BIT(8) +#define IMR_OCPINT BIT(1) +#define IMR_WLANOFF BIT(0) + +#define EFUSE_REAL_CONTENT_LEN 512 + +#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 0x12 +#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 RTL8192_EEPROM_ID 0x8129 + +#define RTL8190_EEPROM_ID 0x8129 +#define EEPROM_HPON 0x02 +#define EEPROM_CLK 0x06 +#define EEPROM_TESTR 0x08 + +#define EEPROM_VID 0x0A +#define EEPROM_DID 0x0C +#define EEPROM_SVID 0x0E +#define EEPROM_SMID 0x10 + +#define EEPROM_MAC_ADDR 0x16 + +#define EEPROM_CCK_TX_PWR_INX 0x5A +#define EEPROM_HT40_1S_TX_PWR_INX 0x60 +#define EEPROM_HT40_2S_TX_PWR_INX_DIFF 0x66 +#define EEPROM_HT20_TX_PWR_INX_DIFF 0x69 +#define EEPROM_OFDM_TX_PWR_INX_DIFF 0x6C +#define EEPROM_HT40_MAX_PWR_OFFSET 0x6F +#define EEPROM_HT20_MAX_PWR_OFFSET 0x72 + +#define EEPROM_TSSI_A 0x76 +#define EEPROM_TSSI_B 0x77 +#define EEPROM_THERMAL_METER 0x78 +#define EEPROM_XTAL_K 0x78 +#define EEPROM_RF_OPT1 0x79 +#define EEPROM_RF_OPT2 0x7A +#define EEPROM_RF_OPT3 0x7B +#define EEPROM_RF_OPT4 0x7C +#define EEPROM_CHANNEL_PLAN 0x7D +#define EEPROM_VERSION 0x7E +#define EEPROM_CUSTOMER_ID 0x7F + +#define EEPROM_PWRDIFF 0x54 + +#define EEPROM_TXPOWERCCK 0x5A +#define EEPROM_TXPOWERHT40_1S 0x60 +#define EEPROM_TXPOWERHT40_2SDIFF 0x66 +#define EEPROM_TXPOWERHT20DIFF 0x69 +#define EEPROM_TXPOWER_OFDMDIFF 0x6C + +#define EEPROM_TXPWR_GROUP 0x6F + +#define EEPROM_TSSI_A 0x76 +#define EEPROM_TSSI_B 0x77 +#define EEPROM_THERMAL_METER 0x78 + +#define EEPROM_CHANNELPLAN 0x75 + +#define RF_OPTION1 0x79 +#define RF_OPTION2 0x7A +#define RF_OPTION3 0x7B +#define RF_OPTION4 0x7C + +#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_FCS BIT(31) +#define RCR_APP_MIC BIT(30) +#define RCR_APP_ICV BIT(29) +#define RCR_APP_PHYSTS BIT(28) +#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 BT_FUNC BIT(16) +#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 RF_RL_ID (BIT(31) | BIT(30) | BIT(29) | BIT(28)) + +#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_OFFSET 16 +#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 LAST_ENTRY_OF_TX_PKT_BUFFER 255 + +#define POLLING_LLT_THRESHOLD 20 +#define POLLING_READY_TIMEOUT_COUNT 1000 + +#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 128 +#define HWSET_MAX_SIZE_92S HWSET_MAX_SIZE +#define EFUSE_MAX_SECTION 16 + +#define WL_HWPDN_EN BIT(0) + +#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 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 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_RXHPPARAMETER 0xce0 +#define ROFDM0_TXPSEUDONOISEWGT 0xce4 +#define ROFDM0_FRAMESYNC 0xcf0 +#define ROFDM0_DFSREPORT 0xcf4 +#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 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 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 0x24 + +#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 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 + +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/rf.c b/drivers/net/wireless/rtlwifi/rtl8192ce/rf.c new file mode 100644 index 00000000..54c76149 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/rf.c @@ -0,0 +1,516 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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> + * + *****************************************************************************/ + +#include "../wifi.h" +#include "reg.h" +#include "def.h" +#include "phy.h" +#include "rf.h" +#include "dm.h" + +static bool _rtl92ce_phy_rf6052_config_parafile(struct ieee80211_hw *hw); + +void rtl92ce_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) | 0x0400); + rtl_set_rfreg(hw, RF90_PATH_A, 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)); + rtl_set_rfreg(hw, RF90_PATH_A, RF_CHNLBW, RFREG_OFFSET_MASK, + rtlphy->rfreg_chnlval[0]); + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "unknown bandwidth: %#X\n", bandwidth); + break; + } +} + +void rtl92ce_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw, + u8 *ppowerlevel) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + u32 tx_agc[2] = {0, 0}, tmpval; + bool turbo_scanoff = false; + u8 idx1, idx2; + u8 *ptr; + + if (rtlefuse->eeprom_regulatory != 0) + turbo_scanoff = true; + + if (mac->act_scanning) { + tx_agc[RF90_PATH_A] = 0x3f3f3f3f; + tx_agc[RF90_PATH_B] = 0x3f3f3f3f; + + if (turbo_scanoff) { + for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B; idx1++) { + tx_agc[idx1] = ppowerlevel[idx1] | + (ppowerlevel[idx1] << 8) | + (ppowerlevel[idx1] << 16) | + (ppowerlevel[idx1] << 24); + } + } + } else { + for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B; idx1++) { + tx_agc[idx1] = ppowerlevel[idx1] | + (ppowerlevel[idx1] << 8) | + (ppowerlevel[idx1] << 16) | + (ppowerlevel[idx1] << 24); + } + + if (rtlefuse->eeprom_regulatory == 0) { + tmpval = + (rtlphy->mcs_txpwrlevel_origoffset[0][6]) + + (rtlphy->mcs_txpwrlevel_origoffset[0][7] << + 8); + tx_agc[RF90_PATH_A] += tmpval; + + tmpval = (rtlphy->mcs_txpwrlevel_origoffset[0][14]) + + (rtlphy->mcs_txpwrlevel_origoffset[0][15] << + 24); + tx_agc[RF90_PATH_B] += tmpval; + } + } + + for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B; idx1++) { + ptr = (u8 *) (&(tx_agc[idx1])); + for (idx2 = 0; idx2 < 4; idx2++) { + if (*ptr > RF6052_MAX_TX_PWR) + *ptr = RF6052_MAX_TX_PWR; + ptr++; + } + } + + tmpval = tx_agc[RF90_PATH_A] & 0xff; + rtl_set_bbreg(hw, RTXAGC_A_CCK1_MCS32, MASKBYTE1, tmpval); + + RTPRINT(rtlpriv, FPHY, PHY_TXPWR, + "CCK PWR 1M (rf-A) = 0x%x (reg 0x%x)\n", + tmpval, RTXAGC_A_CCK1_MCS32); + + tmpval = tx_agc[RF90_PATH_A] >> 8; + + tmpval = tmpval & 0xff00ffff; + + rtl_set_bbreg(hw, RTXAGC_B_CCK11_A_CCK2_11, 0xffffff00, tmpval); + + RTPRINT(rtlpriv, FPHY, PHY_TXPWR, + "CCK PWR 2~11M (rf-A) = 0x%x (reg 0x%x)\n", + tmpval, RTXAGC_B_CCK11_A_CCK2_11); + + tmpval = tx_agc[RF90_PATH_B] >> 24; + rtl_set_bbreg(hw, RTXAGC_B_CCK11_A_CCK2_11, MASKBYTE0, tmpval); + + RTPRINT(rtlpriv, FPHY, PHY_TXPWR, + "CCK PWR 11M (rf-B) = 0x%x (reg 0x%x)\n", + tmpval, RTXAGC_B_CCK11_A_CCK2_11); + + tmpval = tx_agc[RF90_PATH_B] & 0x00ffffff; + rtl_set_bbreg(hw, RTXAGC_B_CCK1_55_MCS32, 0xffffff00, tmpval); + + RTPRINT(rtlpriv, FPHY, PHY_TXPWR, + "CCK PWR 1~5.5M (rf-B) = 0x%x (reg 0x%x)\n", + tmpval, RTXAGC_B_CCK1_55_MCS32); +} + +static void rtl92c_phy_get_power_base(struct ieee80211_hw *hw, + u8 *ppowerlevel, u8 channel, + u32 *ofdmbase, u32 *mcsbase) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + u32 powerBase0, powerBase1; + u8 legacy_pwrdiff, ht20_pwrdiff; + u8 i, powerlevel[2]; + + for (i = 0; i < 2; i++) { + powerlevel[i] = ppowerlevel[i]; + legacy_pwrdiff = rtlefuse->txpwr_legacyhtdiff[i][channel - 1]; + powerBase0 = powerlevel[i] + legacy_pwrdiff; + + powerBase0 = (powerBase0 << 24) | (powerBase0 << 16) | + (powerBase0 << 8) | powerBase0; + *(ofdmbase + i) = powerBase0; + RTPRINT(rtlpriv, FPHY, PHY_TXPWR, + " [OFDM power base index rf(%c) = 0x%x]\n", + i == 0 ? 'A' : 'B', *(ofdmbase + i)); + } + + for (i = 0; i < 2; i++) { + if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20) { + ht20_pwrdiff = rtlefuse->txpwr_ht20diff[i][channel - 1]; + powerlevel[i] += ht20_pwrdiff; + } + powerBase1 = powerlevel[i]; + powerBase1 = (powerBase1 << 24) | + (powerBase1 << 16) | (powerBase1 << 8) | powerBase1; + + *(mcsbase + i) = powerBase1; + + RTPRINT(rtlpriv, FPHY, PHY_TXPWR, + " [MCS power base index rf(%c) = 0x%x]\n", + i == 0 ? 'A' : 'B', *(mcsbase + i)); + } +} + +static void _rtl92c_get_txpower_writeval_by_regulatory(struct ieee80211_hw *hw, + u8 channel, u8 index, + u32 *powerBase0, + u32 *powerBase1, + u32 *p_outwriteval) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + u8 i, chnlgroup = 0, pwr_diff_limit[4]; + u32 writeVal, customer_limit, rf; + + for (rf = 0; rf < 2; rf++) { + switch (rtlefuse->eeprom_regulatory) { + case 0: + chnlgroup = 0; + + writeVal = + rtlphy->mcs_txpwrlevel_origoffset[chnlgroup][index + + (rf ? 8 : 0)] + + ((index < 2) ? powerBase0[rf] : powerBase1[rf]); + + RTPRINT(rtlpriv, FPHY, PHY_TXPWR, + "RTK better performance, writeVal(%c) = 0x%x\n", + rf == 0 ? 'A' : 'B', writeVal); + break; + case 1: + if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) { + writeVal = ((index < 2) ? powerBase0[rf] : + powerBase1[rf]); + + RTPRINT(rtlpriv, FPHY, PHY_TXPWR, + "Realtek regulatory, 40MHz, writeVal(%c) = 0x%x\n", + rf == 0 ? 'A' : 'B', writeVal); + } else { + if (rtlphy->pwrgroup_cnt == 1) + chnlgroup = 0; + if (rtlphy->pwrgroup_cnt >= 3) { + if (channel <= 3) + chnlgroup = 0; + else if (channel >= 4 && channel <= 9) + chnlgroup = 1; + else if (channel > 9) + chnlgroup = 2; + if (rtlphy->pwrgroup_cnt == 4) + chnlgroup++; + } + + writeVal = + rtlphy->mcs_txpwrlevel_origoffset[chnlgroup] + [index + (rf ? 8 : 0)] + ((index < 2) ? + powerBase0[rf] : + powerBase1[rf]); + + RTPRINT(rtlpriv, FPHY, PHY_TXPWR, + "Realtek regulatory, 20MHz, writeVal(%c) = 0x%x\n", + rf == 0 ? 'A' : 'B', writeVal); + } + break; + case 2: + writeVal = + ((index < 2) ? powerBase0[rf] : powerBase1[rf]); + + RTPRINT(rtlpriv, FPHY, PHY_TXPWR, + "Better regulatory, writeVal(%c) = 0x%x\n", + rf == 0 ? 'A' : 'B', writeVal); + break; + case 3: + chnlgroup = 0; + + if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) { + RTPRINT(rtlpriv, FPHY, PHY_TXPWR, + "customer's limit, 40MHz rf(%c) = 0x%x\n", + rf == 0 ? 'A' : 'B', + rtlefuse->pwrgroup_ht40[rf][channel - + 1]); + } else { + RTPRINT(rtlpriv, FPHY, PHY_TXPWR, + "customer's limit, 20MHz rf(%c) = 0x%x\n", + rf == 0 ? 'A' : 'B', + rtlefuse->pwrgroup_ht20[rf][channel - + 1]); + } + for (i = 0; i < 4; i++) { + pwr_diff_limit[i] = + (u8) ((rtlphy->mcs_txpwrlevel_origoffset + [chnlgroup][index + + (rf ? 8 : 0)] & (0x7f << (i * 8))) >> + (i * 8)); + + if (rtlphy->current_chan_bw == + HT_CHANNEL_WIDTH_20_40) { + if (pwr_diff_limit[i] > + rtlefuse-> + pwrgroup_ht40[rf][channel - 1]) + pwr_diff_limit[i] = + rtlefuse->pwrgroup_ht40[rf] + [channel - 1]; + } else { + if (pwr_diff_limit[i] > + rtlefuse-> + pwrgroup_ht20[rf][channel - 1]) + pwr_diff_limit[i] = + rtlefuse->pwrgroup_ht20[rf] + [channel - 1]; + } + } + + customer_limit = (pwr_diff_limit[3] << 24) | + (pwr_diff_limit[2] << 16) | + (pwr_diff_limit[1] << 8) | (pwr_diff_limit[0]); + + RTPRINT(rtlpriv, FPHY, PHY_TXPWR, + "Customer's limit rf(%c) = 0x%x\n", + rf == 0 ? 'A' : 'B', customer_limit); + + writeVal = customer_limit + + ((index < 2) ? powerBase0[rf] : powerBase1[rf]); + + RTPRINT(rtlpriv, FPHY, PHY_TXPWR, + "Customer, writeVal rf(%c)= 0x%x\n", + rf == 0 ? 'A' : 'B', writeVal); + break; + default: + chnlgroup = 0; + writeVal = + rtlphy->mcs_txpwrlevel_origoffset[chnlgroup] + [index + (rf ? 8 : 0)] + + ((index < 2) ? powerBase0[rf] : powerBase1[rf]); + + RTPRINT(rtlpriv, FPHY, PHY_TXPWR, + "RTK better performance, writeVal rf(%c) = 0x%x\n", + rf == 0 ? 'A' : 'B', writeVal); + break; + } + + if (rtlpriv->dm.dynamic_txhighpower_lvl == TXHIGHPWRLEVEL_BT1) + writeVal = writeVal - 0x06060606; + else if (rtlpriv->dm.dynamic_txhighpower_lvl == + TXHIGHPWRLEVEL_BT2) + writeVal = writeVal - 0x0c0c0c0c; + *(p_outwriteval + rf) = writeVal; + } +} + +static void _rtl92c_write_ofdm_power_reg(struct ieee80211_hw *hw, + u8 index, u32 *pValue) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + + u16 regoffset_a[6] = { + RTXAGC_A_RATE18_06, RTXAGC_A_RATE54_24, + RTXAGC_A_MCS03_MCS00, RTXAGC_A_MCS07_MCS04, + RTXAGC_A_MCS11_MCS08, RTXAGC_A_MCS15_MCS12 + }; + u16 regoffset_b[6] = { + RTXAGC_B_RATE18_06, RTXAGC_B_RATE54_24, + RTXAGC_B_MCS03_MCS00, RTXAGC_B_MCS07_MCS04, + RTXAGC_B_MCS11_MCS08, RTXAGC_B_MCS15_MCS12 + }; + u8 i, rf, pwr_val[4]; + u32 writeVal; + u16 regoffset; + + for (rf = 0; rf < 2; rf++) { + writeVal = pValue[rf]; + for (i = 0; i < 4; i++) { + pwr_val[i] = (u8) ((writeVal & (0x7f << + (i * 8))) >> (i * 8)); + + if (pwr_val[i] > RF6052_MAX_TX_PWR) + pwr_val[i] = RF6052_MAX_TX_PWR; + } + writeVal = (pwr_val[3] << 24) | (pwr_val[2] << 16) | + (pwr_val[1] << 8) | pwr_val[0]; + + if (rf == 0) + regoffset = regoffset_a[index]; + else + regoffset = regoffset_b[index]; + rtl_set_bbreg(hw, regoffset, MASKDWORD, writeVal); + + RTPRINT(rtlpriv, FPHY, PHY_TXPWR, + "Set 0x%x = %08x\n", regoffset, writeVal); + + if (((get_rf_type(rtlphy) == RF_2T2R) && + (regoffset == RTXAGC_A_MCS15_MCS12 || + regoffset == RTXAGC_B_MCS15_MCS12)) || + ((get_rf_type(rtlphy) != RF_2T2R) && + (regoffset == RTXAGC_A_MCS07_MCS04 || + regoffset == RTXAGC_B_MCS07_MCS04))) { + + writeVal = pwr_val[3]; + if (regoffset == RTXAGC_A_MCS15_MCS12 || + regoffset == RTXAGC_A_MCS07_MCS04) + regoffset = 0xc90; + if (regoffset == RTXAGC_B_MCS15_MCS12 || + regoffset == RTXAGC_B_MCS07_MCS04) + regoffset = 0xc98; + + for (i = 0; i < 3; i++) { + writeVal = (writeVal > 6) ? (writeVal - 6) : 0; + rtl_write_byte(rtlpriv, (u32) (regoffset + i), + (u8) writeVal); + } + } + } +} + +void rtl92ce_phy_rf6052_set_ofdm_txpower(struct ieee80211_hw *hw, + u8 *ppowerlevel, u8 channel) +{ + u32 writeVal[2], powerBase0[2], powerBase1[2]; + u8 index; + + rtl92c_phy_get_power_base(hw, ppowerlevel, + channel, &powerBase0[0], &powerBase1[0]); + + for (index = 0; index < 6; index++) { + _rtl92c_get_txpower_writeval_by_regulatory(hw, + channel, index, + &powerBase0[0], + &powerBase1[0], + &writeVal[0]); + + _rtl92c_write_ofdm_power_reg(hw, index, &writeVal[0]); + } +} + +bool rtl92ce_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 _rtl92ce_phy_rf6052_config_parafile(hw); + +} + +static bool _rtl92ce_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 = rtl92c_phy_config_rf_with_headerfile(hw, + (enum radio_path)rfpath); + break; + case RF90_PATH_B: + rtstatus = rtl92c_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(rtlpriv, COMP_INIT, DBG_TRACE, + "Radio[%d] Fail!!\n", rfpath); + return false; + } + + } + + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "<---\n"); + return rtstatus; +} diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/rf.h b/drivers/net/wireless/rtlwifi/rtl8192ce/rf.h new file mode 100644 index 00000000..6c8d56ef --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/rf.h @@ -0,0 +1,44 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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 __RTL92C_RF_H__ +#define __RTL92C_RF_H__ + +#define RF6052_MAX_TX_PWR 0x3F +#define RF6052_MAX_REG 0x3F +#define RF6052_MAX_PATH 2 + +extern void rtl92ce_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw, + u8 bandwidth); +extern void rtl92ce_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw, + u8 *ppowerlevel); +extern void rtl92ce_phy_rf6052_set_ofdm_txpower(struct ieee80211_hw *hw, + u8 *ppowerlevel, u8 channel); +extern bool rtl92ce_phy_rf6052_config(struct ieee80211_hw *hw); +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c b/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c new file mode 100644 index 00000000..2c3b7336 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c @@ -0,0 +1,409 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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> + * + *****************************************************************************/ + +#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 "rf.h" +#include "sw.h" +#include "trx.h" +#include "led.h" + +#include <linux/module.h> + +static void rtl92c_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 rtl92c_init_sw_vars(struct ieee80211_hw *hw) +{ + int err; + 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)); + + rtl8192ce_bt_reg_init(hw); + + rtlpriv->dm.dm_initialgain_enable = true; + rtlpriv->dm.dm_flag = 0; + rtlpriv->dm.disable_framebursting = false; + rtlpriv->dm.thermalvalue = 0; + rtlpci->transmit_config = CFENDFORM | BIT(12) | BIT(13); + + /* compatible 5G band 88ce just 2.4G band & smsp */ + 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_AMF | + RCR_ADF | + RCR_APP_MIC | + RCR_APP_ICV | + RCR_AICV | + RCR_ACRC32 | + RCR_AB | + RCR_AM | + RCR_APM | + RCR_APP_PHYST_RXFF | RCR_HTC_LOC_CTRL | 0); + + rtlpci->irq_mask[0] = + (u32) (IMR_ROK | + IMR_VODOK | + IMR_VIDOK | + IMR_BEDOK | + IMR_BKDOK | + IMR_MGNTDOK | + IMR_HIGHDOK | IMR_BDOK | IMR_RDU | IMR_RXFOVW | 0); + + rtlpci->irq_mask[1] = (u32) (IMR_CPWM | IMR_C2HCMD | 0); + + /* for debug level */ + rtlpriv->dbg.global_debuglevel = rtlpriv->cfg->mod_params->debug; + /* for LPS & IPS */ + rtlpriv->psc.inactiveps = rtlpriv->cfg->mod_params->inactiveps; + rtlpriv->psc.swctrl_lps = rtlpriv->cfg->mod_params->swctrl_lps; + rtlpriv->psc.fwctrl_lps = rtlpriv->cfg->mod_params->fwctrl_lps; + if (!rtlpriv->psc.inactiveps) + pr_info("rtl8192ce: Power Save off (module option)\n"); + if (!rtlpriv->psc.fwctrl_lps) + pr_info("rtl8192ce: FW Power Save off (module option)\n"); + rtlpriv->psc.reg_fwctrl_lps = 3; + rtlpriv->psc.reg_max_lps_awakeintvl = 5; + /* for ASPM, you can close aspm through + * set const_support_pciaspm = 0 */ + rtl92c_init_aspm_vars(hw); + + if (rtlpriv->psc.reg_fwctrl_lps == 1) + rtlpriv->psc.fwctrl_psmode = FW_PS_MIN_MODE; + else if (rtlpriv->psc.reg_fwctrl_lps == 2) + rtlpriv->psc.fwctrl_psmode = FW_PS_MAX_MODE; + else if (rtlpriv->psc.reg_fwctrl_lps == 3) + rtlpriv->psc.fwctrl_psmode = FW_PS_DTIM_MODE; + + /* for firmware buf */ + rtlpriv->rtlhal.pfirmware = vzalloc(0x4000); + if (!rtlpriv->rtlhal.pfirmware) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "Can't alloc buffer for fw\n"); + return 1; + } + + /* request fw */ + if (IS_VENDOR_UMC_A_CUT(rtlhal->version) && + !IS_92C_SERIAL(rtlhal->version)) + rtlpriv->cfg->fw_name = "rtlwifi/rtl8192cfwU.bin"; + else if (IS_81xxC_VENDOR_UMC_B_CUT(rtlhal->version)) + rtlpriv->cfg->fw_name = "rtlwifi/rtl8192cfwU_B.bin"; + + rtlpriv->max_fw_size = 0x4000; + pr_info("Using firmware %s\n", rtlpriv->cfg->fw_name); + err = request_firmware_nowait(THIS_MODULE, 1, rtlpriv->cfg->fw_name, + rtlpriv->io.dev, GFP_KERNEL, hw, + rtl_fw_cb); + if (err) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "Failed to request firmware!\n"); + return 1; + } + + return 0; +} + +void rtl92c_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; + } +} + +static struct rtl_hal_ops rtl8192ce_hal_ops = { + .init_sw_vars = rtl92c_init_sw_vars, + .deinit_sw_vars = rtl92c_deinit_sw_vars, + .read_eeprom_info = rtl92ce_read_eeprom_info, + .interrupt_recognized = rtl92ce_interrupt_recognized, + .hw_init = rtl92ce_hw_init, + .hw_disable = rtl92ce_card_disable, + .hw_suspend = rtl92ce_suspend, + .hw_resume = rtl92ce_resume, + .enable_interrupt = rtl92ce_enable_interrupt, + .disable_interrupt = rtl92ce_disable_interrupt, + .set_network_type = rtl92ce_set_network_type, + .set_chk_bssid = rtl92ce_set_check_bssid, + .set_qos = rtl92ce_set_qos, + .set_bcn_reg = rtl92ce_set_beacon_related_registers, + .set_bcn_intv = rtl92ce_set_beacon_interval, + .update_interrupt_mask = rtl92ce_update_interrupt_mask, + .get_hw_reg = rtl92ce_get_hw_reg, + .set_hw_reg = rtl92ce_set_hw_reg, + .update_rate_tbl = rtl92ce_update_hal_rate_tbl, + .fill_tx_desc = rtl92ce_tx_fill_desc, + .fill_tx_cmddesc = rtl92ce_tx_fill_cmddesc, + .query_rx_desc = rtl92ce_rx_query_desc, + .set_channel_access = rtl92ce_update_channel_access_setting, + .radio_onoff_checking = rtl92ce_gpio_radio_on_off_checking, + .set_bw_mode = rtl92c_phy_set_bw_mode, + .switch_channel = rtl92c_phy_sw_chnl, + .dm_watchdog = rtl92c_dm_watchdog, + .scan_operation_backup = rtl92c_phy_scan_operation_backup, + .set_rf_power_state = rtl92c_phy_set_rf_power_state, + .led_control = rtl92ce_led_control, + .set_desc = rtl92ce_set_desc, + .get_desc = rtl92ce_get_desc, + .tx_polling = rtl92ce_tx_polling, + .enable_hw_sec = rtl92ce_enable_hw_security_config, + .set_key = rtl92ce_set_key, + .init_sw_leds = rtl92ce_init_sw_leds, + .get_bbreg = rtl92c_phy_query_bb_reg, + .set_bbreg = rtl92c_phy_set_bb_reg, + .set_rfreg = rtl92ce_phy_set_rf_reg, + .get_rfreg = rtl92c_phy_query_rf_reg, + .phy_rf6052_config = rtl92ce_phy_rf6052_config, + .phy_rf6052_set_cck_txpower = rtl92ce_phy_rf6052_set_cck_txpower, + .phy_rf6052_set_ofdm_txpower = rtl92ce_phy_rf6052_set_ofdm_txpower, + .config_bb_with_headerfile = _rtl92ce_phy_config_bb_with_headerfile, + .config_bb_with_pgheaderfile = _rtl92ce_phy_config_bb_with_pgheaderfile, + .phy_lc_calibrate = _rtl92ce_phy_lc_calibrate, + .phy_set_bw_mode_callback = rtl92ce_phy_set_bw_mode_callback, + .dm_dynamic_txpower = rtl92ce_dm_dynamic_txpower, +}; + +static struct rtl_mod_params rtl92ce_mod_params = { + .sw_crypto = false, + .inactiveps = true, + .swctrl_lps = false, + .fwctrl_lps = true, + .debug = DBG_EMERG, +}; + +static struct rtl_hal_cfg rtl92ce_hal_cfg = { + .bar_id = 2, + .write_readback = true, + .name = "rtl92c_pci", + .fw_name = "rtlwifi/rtl8192cfw.bin", + .ops = &rtl8192ce_hal_ops, + .mod_params = &rtl92ce_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[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] = EFUSE_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[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, + .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_BCNINT, + .maps[RTL_IMR_RXFOVW] = IMR_RXFOVW, + .maps[RTL_IMR_RDU] = IMR_RDU, + .maps[RTL_IMR_ATIMEND] = IMR_ATIMEND, + .maps[RTL_IMR_BDOK] = IMR_BDOK, + .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_BCNINT | IMR_TBDOK | IMR_TBDER), + + .maps[RTL_RC_CCK_RATE1M] = DESC92_RATE1M, + .maps[RTL_RC_CCK_RATE2M] = DESC92_RATE2M, + .maps[RTL_RC_CCK_RATE5_5M] = DESC92_RATE5_5M, + .maps[RTL_RC_CCK_RATE11M] = DESC92_RATE11M, + .maps[RTL_RC_OFDM_RATE6M] = DESC92_RATE6M, + .maps[RTL_RC_OFDM_RATE9M] = DESC92_RATE9M, + .maps[RTL_RC_OFDM_RATE12M] = DESC92_RATE12M, + .maps[RTL_RC_OFDM_RATE18M] = DESC92_RATE18M, + .maps[RTL_RC_OFDM_RATE24M] = DESC92_RATE24M, + .maps[RTL_RC_OFDM_RATE36M] = DESC92_RATE36M, + .maps[RTL_RC_OFDM_RATE48M] = DESC92_RATE48M, + .maps[RTL_RC_OFDM_RATE54M] = DESC92_RATE54M, + + .maps[RTL_RC_HT_RATEMCS7] = DESC92_RATEMCS7, + .maps[RTL_RC_HT_RATEMCS15] = DESC92_RATEMCS15, +}; + +DEFINE_PCI_DEVICE_TABLE(rtl92ce_pci_ids) = { + {RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8191, rtl92ce_hal_cfg)}, + {RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8178, rtl92ce_hal_cfg)}, + {RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8177, rtl92ce_hal_cfg)}, + {RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8176, rtl92ce_hal_cfg)}, + {}, +}; + +MODULE_DEVICE_TABLE(pci, rtl92ce_pci_ids); + +MODULE_AUTHOR("lizhaoming <chaoming_li@realsil.com.cn>"); +MODULE_AUTHOR("Realtek WlanFAE <wlanfae@realtek.com>"); +MODULE_AUTHOR("Larry Finger <Larry.Finger@lwfinger.net>"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Realtek 8192C/8188C 802.11n PCI wireless"); +MODULE_FIRMWARE("rtlwifi/rtl8192cfw.bin"); +MODULE_FIRMWARE("rtlwifi/rtl8192cfwU.bin"); +MODULE_FIRMWARE("rtlwifi/rtl8192cfwU_B.bin"); + +module_param_named(swenc, rtl92ce_mod_params.sw_crypto, bool, 0444); +module_param_named(debug, rtl92ce_mod_params.debug, int, 0444); +module_param_named(ips, rtl92ce_mod_params.inactiveps, bool, 0444); +module_param_named(swlps, rtl92ce_mod_params.swctrl_lps, bool, 0444); +module_param_named(fwlps, rtl92ce_mod_params.fwctrl_lps, bool, 0444); +MODULE_PARM_DESC(swenc, "Set to 1 for software crypto (default 0)\n"); +MODULE_PARM_DESC(ips, "Set to 0 to not use link power save (default 1)\n"); +MODULE_PARM_DESC(swlps, "Set to 1 to use SW control power save (default 0)\n"); +MODULE_PARM_DESC(fwlps, "Set to 1 to use FW control power save (default 1)\n"); +MODULE_PARM_DESC(debug, "Set debug level (0-5) (default 0)"); + +static const struct dev_pm_ops rtlwifi_pm_ops = { + .suspend = rtl_pci_suspend, + .resume = rtl_pci_resume, + .freeze = rtl_pci_suspend, + .thaw = rtl_pci_resume, + .poweroff = rtl_pci_suspend, + .restore = rtl_pci_resume, +}; + +static struct pci_driver rtl92ce_driver = { + .name = KBUILD_MODNAME, + .id_table = rtl92ce_pci_ids, + .probe = rtl_pci_probe, + .remove = rtl_pci_disconnect, + .driver.pm = &rtlwifi_pm_ops, +}; + +static int __init rtl92ce_module_init(void) +{ + int ret; + + ret = pci_register_driver(&rtl92ce_driver); + if (ret) + RT_ASSERT(false, "No device found\n"); + + return ret; +} + +static void __exit rtl92ce_module_exit(void) +{ + pci_unregister_driver(&rtl92ce_driver); +} + +module_init(rtl92ce_module_init); +module_exit(rtl92ce_module_exit); diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/sw.h b/drivers/net/wireless/rtlwifi/rtl8192ce/sw.h new file mode 100644 index 00000000..d2367a5d --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/sw.h @@ -0,0 +1,41 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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 __RTL92CE_SW_H__ +#define __RTL92CE_SW_H__ + +int rtl92c_init_sw_vars(struct ieee80211_hw *hw); +void rtl92c_deinit_sw_vars(struct ieee80211_hw *hw); +void rtl92c_init_var_map(struct ieee80211_hw *hw); +bool _rtl92ce_phy_config_bb_with_headerfile(struct ieee80211_hw *hw, + u8 configtype); +bool _rtl92ce_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw, + u8 configtype); + +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/table.c b/drivers/net/wireless/rtlwifi/rtl8192ce/table.c new file mode 100644 index 00000000..752f943a --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/table.c @@ -0,0 +1,1224 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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> + * + *****************************************************************************/ + +#include "table.h" + + +u32 RTL8192CEPHY_REG_2TARRAY[PHY_REG_2TARRAY_LENGTH] = { + 0x024, 0x0011800f, + 0x028, 0x00ffdb83, + 0x800, 0x80040002, + 0x804, 0x00000003, + 0x808, 0x0000fc00, + 0x80c, 0x0000000a, + 0x810, 0x10005388, + 0x814, 0x020c3d10, + 0x818, 0x02200385, + 0x81c, 0x00000000, + 0x820, 0x01000100, + 0x824, 0x00390004, + 0x828, 0x01000100, + 0x82c, 0x00390004, + 0x830, 0x27272727, + 0x834, 0x27272727, + 0x838, 0x27272727, + 0x83c, 0x27272727, + 0x840, 0x00010000, + 0x844, 0x00010000, + 0x848, 0x27272727, + 0x84c, 0x27272727, + 0x850, 0x00000000, + 0x854, 0x00000000, + 0x858, 0x569a569a, + 0x85c, 0x0c1b25a4, + 0x860, 0x66e60230, + 0x864, 0x061f0130, + 0x868, 0x27272727, + 0x86c, 0x2b2b2b27, + 0x870, 0x07000700, + 0x874, 0x22184000, + 0x878, 0x08080808, + 0x87c, 0x00000000, + 0x880, 0xc0083070, + 0x884, 0x000004d5, + 0x888, 0x00000000, + 0x88c, 0xcc0000c0, + 0x890, 0x00000800, + 0x894, 0xfffffffe, + 0x898, 0x40302010, + 0x89c, 0x00706050, + 0x900, 0x00000000, + 0x904, 0x00000023, + 0x908, 0x00000000, + 0x90c, 0x81121313, + 0xa00, 0x00d047c8, + 0xa04, 0x80ff000c, + 0xa08, 0x8c838300, + 0xa0c, 0x2e68120f, + 0xa10, 0x9500bb78, + 0xa14, 0x11144028, + 0xa18, 0x00881117, + 0xa1c, 0x89140f00, + 0xa20, 0x1a1b0000, + 0xa24, 0x090e1317, + 0xa28, 0x00000204, + 0xa2c, 0x00d30000, + 0xa70, 0x101fbf00, + 0xa74, 0x00000007, + 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, 0x69e9ac44, + 0xc34, 0x469652cf, + 0xc38, 0x49795994, + 0xc3c, 0x0a97971c, + 0xc40, 0x1f7c403f, + 0xc44, 0x000100b7, + 0xc48, 0xec020107, + 0xc4c, 0x007f037f, + 0xc50, 0x69543420, + 0xc54, 0x43bc0094, + 0xc58, 0x69543420, + 0xc5c, 0x433c0094, + 0xc60, 0x00000000, + 0xc64, 0x5116848b, + 0xc68, 0x47c00bff, + 0xc6c, 0x00000036, + 0xc70, 0x2c7f000d, + 0xc74, 0x018610db, + 0xc78, 0x0000001f, + 0xc7c, 0x00b91612, + 0xc80, 0x40000100, + 0xc84, 0x20f60000, + 0xc88, 0x40000100, + 0xc8c, 0x20200000, + 0xc90, 0x00121820, + 0xc94, 0x00000000, + 0xc98, 0x00121820, + 0xc9c, 0x00007f7f, + 0xca0, 0x00000000, + 0xca4, 0x00000080, + 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, 0x00000000, + 0xce8, 0x37644302, + 0xcec, 0x2f97d40c, + 0xd00, 0x00080740, + 0xd04, 0x00020403, + 0xd08, 0x0000907f, + 0xd0c, 0x20010201, + 0xd10, 0xa0633333, + 0xd14, 0x3333bc43, + 0xd18, 0x7a8f5b6b, + 0xd2c, 0xcc979975, + 0xd30, 0x00000000, + 0xd34, 0x80608000, + 0xd38, 0x00000000, + 0xd3c, 0x00027293, + 0xd40, 0x00000000, + 0xd44, 0x00000000, + 0xd48, 0x00000000, + 0xd4c, 0x00000000, + 0xd50, 0x6437140a, + 0xd54, 0x00000000, + 0xd58, 0x00000000, + 0xd5c, 0x30032064, + 0xd60, 0x4653de68, + 0xd64, 0x04518a3c, + 0xd68, 0x00002101, + 0xd6c, 0x2a201c16, + 0xd70, 0x1812362e, + 0xd74, 0x322c2220, + 0xd78, 0x000e3c24, + 0xe00, 0x2a2a2a2a, + 0xe04, 0x2a2a2a2a, + 0xe08, 0x03902a2a, + 0xe10, 0x2a2a2a2a, + 0xe14, 0x2a2a2a2a, + 0xe18, 0x2a2a2a2a, + 0xe1c, 0x2a2a2a2a, + 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, 0x00000010, + 0xe68, 0x001b25a4, + 0xe6c, 0x63db25a4, + 0xe70, 0x63db25a4, + 0xe74, 0x0c1b25a4, + 0xe78, 0x0c1b25a4, + 0xe7c, 0x0c1b25a4, + 0xe80, 0x0c1b25a4, + 0xe84, 0x63db25a4, + 0xe88, 0x0c1b25a4, + 0xe8c, 0x63db25a4, + 0xed0, 0x63db25a4, + 0xed4, 0x63db25a4, + 0xed8, 0x63db25a4, + 0xedc, 0x001b25a4, + 0xee0, 0x001b25a4, + 0xeec, 0x6fdb25a4, + 0xf14, 0x00000003, + 0xf4c, 0x00000000, + 0xf00, 0x00000300, +}; + +u32 RTL8192CEPHY_REG_1TARRAY[PHY_REG_1TARRAY_LENGTH] = { + 0x024, 0x0011800f, + 0x028, 0x00ffdb83, + 0x800, 0x80040000, + 0x804, 0x00000001, + 0x808, 0x0000fc00, + 0x80c, 0x0000000a, + 0x810, 0x10005388, + 0x814, 0x020c3d10, + 0x818, 0x02200385, + 0x81c, 0x00000000, + 0x820, 0x01000100, + 0x824, 0x00390004, + 0x828, 0x00000000, + 0x82c, 0x00000000, + 0x830, 0x00000000, + 0x834, 0x00000000, + 0x838, 0x00000000, + 0x83c, 0x00000000, + 0x840, 0x00010000, + 0x844, 0x00000000, + 0x848, 0x00000000, + 0x84c, 0x00000000, + 0x850, 0x00000000, + 0x854, 0x00000000, + 0x858, 0x569a569a, + 0x85c, 0x001b25a4, + 0x860, 0x66e60230, + 0x864, 0x061f0130, + 0x868, 0x00000000, + 0x86c, 0x32323200, + 0x870, 0x07000700, + 0x874, 0x22004000, + 0x878, 0x00000808, + 0x87c, 0x00000000, + 0x880, 0xc0083070, + 0x884, 0x000004d5, + 0x888, 0x00000000, + 0x88c, 0xccc000c0, + 0x890, 0x00000800, + 0x894, 0xfffffffe, + 0x898, 0x40302010, + 0x89c, 0x00706050, + 0x900, 0x00000000, + 0x904, 0x00000023, + 0x908, 0x00000000, + 0x90c, 0x81121111, + 0xa00, 0x00d047c8, + 0xa04, 0x80ff000c, + 0xa08, 0x8c838300, + 0xa0c, 0x2e68120f, + 0xa10, 0x9500bb78, + 0xa14, 0x11144028, + 0xa18, 0x00881117, + 0xa1c, 0x89140f00, + 0xa20, 0x1a1b0000, + 0xa24, 0x090e1317, + 0xa28, 0x00000204, + 0xa2c, 0x00d30000, + 0xa70, 0x101fbf00, + 0xa74, 0x00000007, + 0xc00, 0x48071d40, + 0xc04, 0x03a05611, + 0xc08, 0x000000e4, + 0xc0c, 0x6c6c6c6c, + 0xc10, 0x08800000, + 0xc14, 0x40000100, + 0xc18, 0x08800000, + 0xc1c, 0x40000100, + 0xc20, 0x00000000, + 0xc24, 0x00000000, + 0xc28, 0x00000000, + 0xc2c, 0x00000000, + 0xc30, 0x69e9ac44, + 0xc34, 0x469652cf, + 0xc38, 0x49795994, + 0xc3c, 0x0a97971c, + 0xc40, 0x1f7c403f, + 0xc44, 0x000100b7, + 0xc48, 0xec020107, + 0xc4c, 0x007f037f, + 0xc50, 0x69543420, + 0xc54, 0x43bc0094, + 0xc58, 0x69543420, + 0xc5c, 0x433c0094, + 0xc60, 0x00000000, + 0xc64, 0x5116848b, + 0xc68, 0x47c00bff, + 0xc6c, 0x00000036, + 0xc70, 0x2c7f000d, + 0xc74, 0x018610db, + 0xc78, 0x0000001f, + 0xc7c, 0x00b91612, + 0xc80, 0x40000100, + 0xc84, 0x20f60000, + 0xc88, 0x40000100, + 0xc8c, 0x20200000, + 0xc90, 0x00121820, + 0xc94, 0x00000000, + 0xc98, 0x00121820, + 0xc9c, 0x00007f7f, + 0xca0, 0x00000000, + 0xca4, 0x00000080, + 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, 0x00000000, + 0xce8, 0x37644302, + 0xcec, 0x2f97d40c, + 0xd00, 0x00080740, + 0xd04, 0x00020401, + 0xd08, 0x0000907f, + 0xd0c, 0x20010201, + 0xd10, 0xa0633333, + 0xd14, 0x3333bc43, + 0xd18, 0x7a8f5b6b, + 0xd2c, 0xcc979975, + 0xd30, 0x00000000, + 0xd34, 0x80608000, + 0xd38, 0x00000000, + 0xd3c, 0x00027293, + 0xd40, 0x00000000, + 0xd44, 0x00000000, + 0xd48, 0x00000000, + 0xd4c, 0x00000000, + 0xd50, 0x6437140a, + 0xd54, 0x00000000, + 0xd58, 0x00000000, + 0xd5c, 0x30032064, + 0xd60, 0x4653de68, + 0xd64, 0x04518a3c, + 0xd68, 0x00002101, + 0xd6c, 0x2a201c16, + 0xd70, 0x1812362e, + 0xd74, 0x322c2220, + 0xd78, 0x000e3c24, + 0xe00, 0x2a2a2a2a, + 0xe04, 0x2a2a2a2a, + 0xe08, 0x03902a2a, + 0xe10, 0x2a2a2a2a, + 0xe14, 0x2a2a2a2a, + 0xe18, 0x2a2a2a2a, + 0xe1c, 0x2a2a2a2a, + 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, 0x00000010, + 0xe68, 0x001b25a4, + 0xe6c, 0x631b25a0, + 0xe70, 0x631b25a0, + 0xe74, 0x081b25a0, + 0xe78, 0x081b25a0, + 0xe7c, 0x081b25a0, + 0xe80, 0x081b25a0, + 0xe84, 0x631b25a0, + 0xe88, 0x081b25a0, + 0xe8c, 0x631b25a0, + 0xed0, 0x631b25a0, + 0xed4, 0x631b25a0, + 0xed8, 0x631b25a0, + 0xedc, 0x001b25a0, + 0xee0, 0x001b25a0, + 0xeec, 0x6b1b25a0, + 0xf14, 0x00000003, + 0xf4c, 0x00000000, + 0xf00, 0x00000300, +}; + +u32 RTL8192CEPHY_REG_ARRAY_PG[PHY_REG_ARRAY_PGLENGTH] = { + 0xe00, 0xffffffff, 0x0a0c0c0c, + 0xe04, 0xffffffff, 0x02040608, + 0xe08, 0x0000ff00, 0x00000000, + 0x86c, 0xffffff00, 0x00000000, + 0xe10, 0xffffffff, 0x0a0c0d0e, + 0xe14, 0xffffffff, 0x02040608, + 0xe18, 0xffffffff, 0x0a0c0d0e, + 0xe1c, 0xffffffff, 0x02040608, + 0x830, 0xffffffff, 0x0a0c0c0c, + 0x834, 0xffffffff, 0x02040608, + 0x838, 0xffffff00, 0x00000000, + 0x86c, 0x000000ff, 0x00000000, + 0x83c, 0xffffffff, 0x0a0c0d0e, + 0x848, 0xffffffff, 0x02040608, + 0x84c, 0xffffffff, 0x0a0c0d0e, + 0x868, 0xffffffff, 0x02040608, + 0xe00, 0xffffffff, 0x00000000, + 0xe04, 0xffffffff, 0x00000000, + 0xe08, 0x0000ff00, 0x00000000, + 0x86c, 0xffffff00, 0x00000000, + 0xe10, 0xffffffff, 0x00000000, + 0xe14, 0xffffffff, 0x00000000, + 0xe18, 0xffffffff, 0x00000000, + 0xe1c, 0xffffffff, 0x00000000, + 0x830, 0xffffffff, 0x00000000, + 0x834, 0xffffffff, 0x00000000, + 0x838, 0xffffff00, 0x00000000, + 0x86c, 0x000000ff, 0x00000000, + 0x83c, 0xffffffff, 0x00000000, + 0x848, 0xffffffff, 0x00000000, + 0x84c, 0xffffffff, 0x00000000, + 0x868, 0xffffffff, 0x00000000, + 0xe00, 0xffffffff, 0x04040404, + 0xe04, 0xffffffff, 0x00020204, + 0xe08, 0x0000ff00, 0x00000000, + 0x86c, 0xffffff00, 0x00000000, + 0xe10, 0xffffffff, 0x06060606, + 0xe14, 0xffffffff, 0x00020406, + 0xe18, 0xffffffff, 0x06060606, + 0xe1c, 0xffffffff, 0x00020406, + 0x830, 0xffffffff, 0x04040404, + 0x834, 0xffffffff, 0x00020204, + 0x838, 0xffffff00, 0x00000000, + 0x86c, 0x000000ff, 0x00000000, + 0x83c, 0xffffffff, 0x06060606, + 0x848, 0xffffffff, 0x00020406, + 0x84c, 0xffffffff, 0x06060606, + 0x868, 0xffffffff, 0x00020406, + 0xe00, 0xffffffff, 0x00000000, + 0xe04, 0xffffffff, 0x00000000, + 0xe08, 0x0000ff00, 0x00000000, + 0x86c, 0xffffff00, 0x00000000, + 0xe10, 0xffffffff, 0x00000000, + 0xe14, 0xffffffff, 0x00000000, + 0xe18, 0xffffffff, 0x00000000, + 0xe1c, 0xffffffff, 0x00000000, + 0x830, 0xffffffff, 0x00000000, + 0x834, 0xffffffff, 0x00000000, + 0x838, 0xffffff00, 0x00000000, + 0x86c, 0x000000ff, 0x00000000, + 0x83c, 0xffffffff, 0x00000000, + 0x848, 0xffffffff, 0x00000000, + 0x84c, 0xffffffff, 0x00000000, + 0x868, 0xffffffff, 0x00000000, +}; + +u32 RTL8192CERADIOA_2TARRAY[RADIOA_2TARRAYLENGTH] = { + 0x000, 0x00030159, + 0x001, 0x00031284, + 0x002, 0x00098000, + 0x003, 0x00018c63, + 0x004, 0x000210e7, + 0x009, 0x0002044f, + 0x00a, 0x0001adb0, + 0x00b, 0x00054867, + 0x00c, 0x0008992e, + 0x00d, 0x0000e52c, + 0x00e, 0x00039ce7, + 0x00f, 0x00000451, + 0x019, 0x00000000, + 0x01a, 0x00010255, + 0x01b, 0x00060a00, + 0x01c, 0x000fc378, + 0x01d, 0x000a1250, + 0x01e, 0x0004445f, + 0x01f, 0x00080001, + 0x020, 0x0000b614, + 0x021, 0x0006c000, + 0x022, 0x00000000, + 0x023, 0x00001558, + 0x024, 0x00000060, + 0x025, 0x00000483, + 0x026, 0x0004f000, + 0x027, 0x000ec7d9, + 0x028, 0x000977c0, + 0x029, 0x00004783, + 0x02a, 0x00000001, + 0x02b, 0x00021334, + 0x02a, 0x00000000, + 0x02b, 0x00000054, + 0x02a, 0x00000001, + 0x02b, 0x00000808, + 0x02b, 0x00053333, + 0x02c, 0x0000000c, + 0x02a, 0x00000002, + 0x02b, 0x00000808, + 0x02b, 0x0005b333, + 0x02c, 0x0000000d, + 0x02a, 0x00000003, + 0x02b, 0x00000808, + 0x02b, 0x00063333, + 0x02c, 0x0000000d, + 0x02a, 0x00000004, + 0x02b, 0x00000808, + 0x02b, 0x0006b333, + 0x02c, 0x0000000d, + 0x02a, 0x00000005, + 0x02b, 0x00000808, + 0x02b, 0x00073333, + 0x02c, 0x0000000d, + 0x02a, 0x00000006, + 0x02b, 0x00000709, + 0x02b, 0x0005b333, + 0x02c, 0x0000000d, + 0x02a, 0x00000007, + 0x02b, 0x00000709, + 0x02b, 0x00063333, + 0x02c, 0x0000000d, + 0x02a, 0x00000008, + 0x02b, 0x0000060a, + 0x02b, 0x0004b333, + 0x02c, 0x0000000d, + 0x02a, 0x00000009, + 0x02b, 0x0000060a, + 0x02b, 0x00053333, + 0x02c, 0x0000000d, + 0x02a, 0x0000000a, + 0x02b, 0x0000060a, + 0x02b, 0x0005b333, + 0x02c, 0x0000000d, + 0x02a, 0x0000000b, + 0x02b, 0x0000060a, + 0x02b, 0x00063333, + 0x02c, 0x0000000d, + 0x02a, 0x0000000c, + 0x02b, 0x0000060a, + 0x02b, 0x0006b333, + 0x02c, 0x0000000d, + 0x02a, 0x0000000d, + 0x02b, 0x0000060a, + 0x02b, 0x00073333, + 0x02c, 0x0000000d, + 0x02a, 0x0000000e, + 0x02b, 0x0000050b, + 0x02b, 0x00066666, + 0x02c, 0x0000001a, + 0x02a, 0x000e0000, + 0x010, 0x0004000f, + 0x011, 0x000e31fc, + 0x010, 0x0006000f, + 0x011, 0x000ff9f8, + 0x010, 0x0002000f, + 0x011, 0x000203f9, + 0x010, 0x0003000f, + 0x011, 0x000ff500, + 0x010, 0x00000000, + 0x011, 0x00000000, + 0x010, 0x0008000f, + 0x011, 0x0003f100, + 0x010, 0x0009000f, + 0x011, 0x00023100, + 0x012, 0x00032000, + 0x012, 0x00071000, + 0x012, 0x000b0000, + 0x012, 0x000fc000, + 0x013, 0x000287af, + 0x013, 0x000244b7, + 0x013, 0x000204ab, + 0x013, 0x0001c49f, + 0x013, 0x00018493, + 0x013, 0x00014297, + 0x013, 0x00010295, + 0x013, 0x0000c298, + 0x013, 0x0000819c, + 0x013, 0x000040a8, + 0x013, 0x0000001c, + 0x014, 0x0001944c, + 0x014, 0x00059444, + 0x014, 0x0009944c, + 0x014, 0x000d9444, + 0x015, 0x0000f424, + 0x015, 0x0004f424, + 0x015, 0x0008f424, + 0x015, 0x000cf424, + 0x016, 0x000e0330, + 0x016, 0x000a0330, + 0x016, 0x00060330, + 0x016, 0x00020330, + 0x000, 0x00010159, + 0x018, 0x0000f401, + 0x0fe, 0x00000000, + 0x0fe, 0x00000000, + 0x01f, 0x00080003, + 0x0fe, 0x00000000, + 0x0fe, 0x00000000, + 0x01e, 0x00044457, + 0x01f, 0x00080000, + 0x000, 0x00030159, +}; + +u32 RTL8192CE_RADIOB_2TARRAY[RADIOB_2TARRAYLENGTH] = { + 0x000, 0x00030159, + 0x001, 0x00031284, + 0x002, 0x00098000, + 0x003, 0x00018c63, + 0x004, 0x000210e7, + 0x009, 0x0002044f, + 0x00a, 0x0001adb0, + 0x00b, 0x00054867, + 0x00c, 0x0008992e, + 0x00d, 0x0000e52c, + 0x00e, 0x00039ce7, + 0x00f, 0x00000451, + 0x012, 0x00032000, + 0x012, 0x00071000, + 0x012, 0x000b0000, + 0x012, 0x000fc000, + 0x013, 0x000287af, + 0x013, 0x000244b7, + 0x013, 0x000204ab, + 0x013, 0x0001c49f, + 0x013, 0x00018493, + 0x013, 0x00014297, + 0x013, 0x00010295, + 0x013, 0x0000c298, + 0x013, 0x0000819c, + 0x013, 0x000040a8, + 0x013, 0x0000001c, + 0x014, 0x0001944c, + 0x014, 0x00059444, + 0x014, 0x0009944c, + 0x014, 0x000d9444, + 0x015, 0x0000f424, + 0x015, 0x0004f424, + 0x015, 0x0008f424, + 0x015, 0x000cf424, + 0x016, 0x000e0330, + 0x016, 0x000a0330, + 0x016, 0x00060330, + 0x016, 0x00020330, +}; + +u32 RTL8192CE_RADIOA_1TARRAY[RADIOA_1TARRAYLENGTH] = { + 0x000, 0x00030159, + 0x001, 0x00031284, + 0x002, 0x00098000, + 0x003, 0x00018c63, + 0x004, 0x000210e7, + 0x009, 0x0002044f, + 0x00a, 0x0001adb0, + 0x00b, 0x00054867, + 0x00c, 0x0008992e, + 0x00d, 0x0000e52c, + 0x00e, 0x00039ce7, + 0x00f, 0x00000451, + 0x019, 0x00000000, + 0x01a, 0x00010255, + 0x01b, 0x00060a00, + 0x01c, 0x000fc378, + 0x01d, 0x000a1250, + 0x01e, 0x0004445f, + 0x01f, 0x00080001, + 0x020, 0x0000b614, + 0x021, 0x0006c000, + 0x022, 0x00000000, + 0x023, 0x00001558, + 0x024, 0x00000060, + 0x025, 0x00000483, + 0x026, 0x0004f000, + 0x027, 0x000ec7d9, + 0x028, 0x000977c0, + 0x029, 0x00004783, + 0x02a, 0x00000001, + 0x02b, 0x00021334, + 0x02a, 0x00000000, + 0x02b, 0x00000054, + 0x02a, 0x00000001, + 0x02b, 0x00000808, + 0x02b, 0x00053333, + 0x02c, 0x0000000c, + 0x02a, 0x00000002, + 0x02b, 0x00000808, + 0x02b, 0x0005b333, + 0x02c, 0x0000000d, + 0x02a, 0x00000003, + 0x02b, 0x00000808, + 0x02b, 0x00063333, + 0x02c, 0x0000000d, + 0x02a, 0x00000004, + 0x02b, 0x00000808, + 0x02b, 0x0006b333, + 0x02c, 0x0000000d, + 0x02a, 0x00000005, + 0x02b, 0x00000808, + 0x02b, 0x00073333, + 0x02c, 0x0000000d, + 0x02a, 0x00000006, + 0x02b, 0x00000709, + 0x02b, 0x0005b333, + 0x02c, 0x0000000d, + 0x02a, 0x00000007, + 0x02b, 0x00000709, + 0x02b, 0x00063333, + 0x02c, 0x0000000d, + 0x02a, 0x00000008, + 0x02b, 0x0000060a, + 0x02b, 0x0004b333, + 0x02c, 0x0000000d, + 0x02a, 0x00000009, + 0x02b, 0x0000060a, + 0x02b, 0x00053333, + 0x02c, 0x0000000d, + 0x02a, 0x0000000a, + 0x02b, 0x0000060a, + 0x02b, 0x0005b333, + 0x02c, 0x0000000d, + 0x02a, 0x0000000b, + 0x02b, 0x0000060a, + 0x02b, 0x00063333, + 0x02c, 0x0000000d, + 0x02a, 0x0000000c, + 0x02b, 0x0000060a, + 0x02b, 0x0006b333, + 0x02c, 0x0000000d, + 0x02a, 0x0000000d, + 0x02b, 0x0000060a, + 0x02b, 0x00073333, + 0x02c, 0x0000000d, + 0x02a, 0x0000000e, + 0x02b, 0x0000050b, + 0x02b, 0x00066666, + 0x02c, 0x0000001a, + 0x02a, 0x000e0000, + 0x010, 0x0004000f, + 0x011, 0x000e31fc, + 0x010, 0x0006000f, + 0x011, 0x000ff9f8, + 0x010, 0x0002000f, + 0x011, 0x000203f9, + 0x010, 0x0003000f, + 0x011, 0x000ff500, + 0x010, 0x00000000, + 0x011, 0x00000000, + 0x010, 0x0008000f, + 0x011, 0x0003f100, + 0x010, 0x0009000f, + 0x011, 0x00023100, + 0x012, 0x00032000, + 0x012, 0x00071000, + 0x012, 0x000b0000, + 0x012, 0x000fc000, + 0x013, 0x000287af, + 0x013, 0x000244b7, + 0x013, 0x000204ab, + 0x013, 0x0001c49f, + 0x013, 0x00018493, + 0x013, 0x00014297, + 0x013, 0x00010295, + 0x013, 0x0000c298, + 0x013, 0x0000819c, + 0x013, 0x000040a8, + 0x013, 0x0000001c, + 0x014, 0x0001944c, + 0x014, 0x00059444, + 0x014, 0x0009944c, + 0x014, 0x000d9444, + 0x015, 0x0000f424, + 0x015, 0x0004f424, + 0x015, 0x0008f424, + 0x015, 0x000cf424, + 0x016, 0x000e0330, + 0x016, 0x000a0330, + 0x016, 0x00060330, + 0x016, 0x00020330, + 0x000, 0x00010159, + 0x018, 0x0000f401, + 0x0fe, 0x00000000, + 0x0fe, 0x00000000, + 0x01f, 0x00080003, + 0x0fe, 0x00000000, + 0x0fe, 0x00000000, + 0x01e, 0x00044457, + 0x01f, 0x00080000, + 0x000, 0x00030159, +}; + +u32 RTL8192CE_RADIOB_1TARRAY[RADIOB_1TARRAYLENGTH] = { + 0x0, +}; + +u32 RTL8192CEMAC_2T_ARRAY[MAC_2T_ARRAYLENGTH] = { + 0x420, 0x00000080, + 0x423, 0x00000000, + 0x430, 0x00000000, + 0x431, 0x00000000, + 0x432, 0x00000000, + 0x433, 0x00000001, + 0x434, 0x00000004, + 0x435, 0x00000005, + 0x436, 0x00000006, + 0x437, 0x00000007, + 0x438, 0x00000000, + 0x439, 0x00000000, + 0x43a, 0x00000000, + 0x43b, 0x00000001, + 0x43c, 0x00000004, + 0x43d, 0x00000005, + 0x43e, 0x00000006, + 0x43f, 0x00000007, + 0x440, 0x0000005d, + 0x441, 0x00000001, + 0x442, 0x00000000, + 0x444, 0x00000015, + 0x445, 0x000000f0, + 0x446, 0x0000000f, + 0x447, 0x00000000, + 0x458, 0x00000041, + 0x459, 0x000000a8, + 0x45a, 0x00000072, + 0x45b, 0x000000b9, + 0x460, 0x00000088, + 0x461, 0x00000088, + 0x462, 0x00000006, + 0x463, 0x00000003, + 0x4c8, 0x00000004, + 0x4c9, 0x00000008, + 0x4cc, 0x00000002, + 0x4cd, 0x00000028, + 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, + 0x515, 0x00000010, + 0x516, 0x0000000a, + 0x517, 0x00000010, + 0x51a, 0x00000016, + 0x524, 0x0000000f, + 0x525, 0x0000004f, + 0x546, 0x00000020, + 0x547, 0x00000000, + 0x559, 0x00000002, + 0x55a, 0x00000002, + 0x55d, 0x000000ff, + 0x605, 0x00000030, + 0x608, 0x0000000e, + 0x609, 0x0000002a, + 0x652, 0x00000020, + 0x63c, 0x0000000a, + 0x63d, 0x0000000a, + 0x700, 0x00000021, + 0x701, 0x00000043, + 0x702, 0x00000065, + 0x703, 0x00000087, + 0x708, 0x00000021, + 0x709, 0x00000043, + 0x70a, 0x00000065, + 0x70b, 0x00000087, +}; + +u32 RTL8192CEAGCTAB_2TARRAY[AGCTAB_2TARRAYLENGTH] = { + 0xc78, 0x7b000001, + 0xc78, 0x7b010001, + 0xc78, 0x7b020001, + 0xc78, 0x7b030001, + 0xc78, 0x7b040001, + 0xc78, 0x7b050001, + 0xc78, 0x7a060001, + 0xc78, 0x79070001, + 0xc78, 0x78080001, + 0xc78, 0x77090001, + 0xc78, 0x760a0001, + 0xc78, 0x750b0001, + 0xc78, 0x740c0001, + 0xc78, 0x730d0001, + 0xc78, 0x720e0001, + 0xc78, 0x710f0001, + 0xc78, 0x70100001, + 0xc78, 0x6f110001, + 0xc78, 0x6e120001, + 0xc78, 0x6d130001, + 0xc78, 0x6c140001, + 0xc78, 0x6b150001, + 0xc78, 0x6a160001, + 0xc78, 0x69170001, + 0xc78, 0x68180001, + 0xc78, 0x67190001, + 0xc78, 0x661a0001, + 0xc78, 0x651b0001, + 0xc78, 0x641c0001, + 0xc78, 0x631d0001, + 0xc78, 0x621e0001, + 0xc78, 0x611f0001, + 0xc78, 0x60200001, + 0xc78, 0x49210001, + 0xc78, 0x48220001, + 0xc78, 0x47230001, + 0xc78, 0x46240001, + 0xc78, 0x45250001, + 0xc78, 0x44260001, + 0xc78, 0x43270001, + 0xc78, 0x42280001, + 0xc78, 0x41290001, + 0xc78, 0x402a0001, + 0xc78, 0x262b0001, + 0xc78, 0x252c0001, + 0xc78, 0x242d0001, + 0xc78, 0x232e0001, + 0xc78, 0x222f0001, + 0xc78, 0x21300001, + 0xc78, 0x20310001, + 0xc78, 0x06320001, + 0xc78, 0x05330001, + 0xc78, 0x04340001, + 0xc78, 0x03350001, + 0xc78, 0x02360001, + 0xc78, 0x01370001, + 0xc78, 0x00380001, + 0xc78, 0x00390001, + 0xc78, 0x003a0001, + 0xc78, 0x003b0001, + 0xc78, 0x003c0001, + 0xc78, 0x003d0001, + 0xc78, 0x003e0001, + 0xc78, 0x003f0001, + 0xc78, 0x7b400001, + 0xc78, 0x7b410001, + 0xc78, 0x7b420001, + 0xc78, 0x7b430001, + 0xc78, 0x7b440001, + 0xc78, 0x7b450001, + 0xc78, 0x7a460001, + 0xc78, 0x79470001, + 0xc78, 0x78480001, + 0xc78, 0x77490001, + 0xc78, 0x764a0001, + 0xc78, 0x754b0001, + 0xc78, 0x744c0001, + 0xc78, 0x734d0001, + 0xc78, 0x724e0001, + 0xc78, 0x714f0001, + 0xc78, 0x70500001, + 0xc78, 0x6f510001, + 0xc78, 0x6e520001, + 0xc78, 0x6d530001, + 0xc78, 0x6c540001, + 0xc78, 0x6b550001, + 0xc78, 0x6a560001, + 0xc78, 0x69570001, + 0xc78, 0x68580001, + 0xc78, 0x67590001, + 0xc78, 0x665a0001, + 0xc78, 0x655b0001, + 0xc78, 0x645c0001, + 0xc78, 0x635d0001, + 0xc78, 0x625e0001, + 0xc78, 0x615f0001, + 0xc78, 0x60600001, + 0xc78, 0x49610001, + 0xc78, 0x48620001, + 0xc78, 0x47630001, + 0xc78, 0x46640001, + 0xc78, 0x45650001, + 0xc78, 0x44660001, + 0xc78, 0x43670001, + 0xc78, 0x42680001, + 0xc78, 0x41690001, + 0xc78, 0x406a0001, + 0xc78, 0x266b0001, + 0xc78, 0x256c0001, + 0xc78, 0x246d0001, + 0xc78, 0x236e0001, + 0xc78, 0x226f0001, + 0xc78, 0x21700001, + 0xc78, 0x20710001, + 0xc78, 0x06720001, + 0xc78, 0x05730001, + 0xc78, 0x04740001, + 0xc78, 0x03750001, + 0xc78, 0x02760001, + 0xc78, 0x01770001, + 0xc78, 0x00780001, + 0xc78, 0x00790001, + 0xc78, 0x007a0001, + 0xc78, 0x007b0001, + 0xc78, 0x007c0001, + 0xc78, 0x007d0001, + 0xc78, 0x007e0001, + 0xc78, 0x007f0001, + 0xc78, 0x3800001e, + 0xc78, 0x3801001e, + 0xc78, 0x3802001e, + 0xc78, 0x3803001e, + 0xc78, 0x3804001e, + 0xc78, 0x3805001e, + 0xc78, 0x3806001e, + 0xc78, 0x3807001e, + 0xc78, 0x3808001e, + 0xc78, 0x3c09001e, + 0xc78, 0x3e0a001e, + 0xc78, 0x400b001e, + 0xc78, 0x440c001e, + 0xc78, 0x480d001e, + 0xc78, 0x4c0e001e, + 0xc78, 0x500f001e, + 0xc78, 0x5210001e, + 0xc78, 0x5611001e, + 0xc78, 0x5a12001e, + 0xc78, 0x5e13001e, + 0xc78, 0x6014001e, + 0xc78, 0x6015001e, + 0xc78, 0x6016001e, + 0xc78, 0x6217001e, + 0xc78, 0x6218001e, + 0xc78, 0x6219001e, + 0xc78, 0x621a001e, + 0xc78, 0x621b001e, + 0xc78, 0x621c001e, + 0xc78, 0x621d001e, + 0xc78, 0x621e001e, + 0xc78, 0x621f001e, +}; + +u32 RTL8192CEAGCTAB_1TARRAY[AGCTAB_1TARRAYLENGTH] = { + 0xc78, 0x7b000001, + 0xc78, 0x7b010001, + 0xc78, 0x7b020001, + 0xc78, 0x7b030001, + 0xc78, 0x7b040001, + 0xc78, 0x7b050001, + 0xc78, 0x7a060001, + 0xc78, 0x79070001, + 0xc78, 0x78080001, + 0xc78, 0x77090001, + 0xc78, 0x760a0001, + 0xc78, 0x750b0001, + 0xc78, 0x740c0001, + 0xc78, 0x730d0001, + 0xc78, 0x720e0001, + 0xc78, 0x710f0001, + 0xc78, 0x70100001, + 0xc78, 0x6f110001, + 0xc78, 0x6e120001, + 0xc78, 0x6d130001, + 0xc78, 0x6c140001, + 0xc78, 0x6b150001, + 0xc78, 0x6a160001, + 0xc78, 0x69170001, + 0xc78, 0x68180001, + 0xc78, 0x67190001, + 0xc78, 0x661a0001, + 0xc78, 0x651b0001, + 0xc78, 0x641c0001, + 0xc78, 0x631d0001, + 0xc78, 0x621e0001, + 0xc78, 0x611f0001, + 0xc78, 0x60200001, + 0xc78, 0x49210001, + 0xc78, 0x48220001, + 0xc78, 0x47230001, + 0xc78, 0x46240001, + 0xc78, 0x45250001, + 0xc78, 0x44260001, + 0xc78, 0x43270001, + 0xc78, 0x42280001, + 0xc78, 0x41290001, + 0xc78, 0x402a0001, + 0xc78, 0x262b0001, + 0xc78, 0x252c0001, + 0xc78, 0x242d0001, + 0xc78, 0x232e0001, + 0xc78, 0x222f0001, + 0xc78, 0x21300001, + 0xc78, 0x20310001, + 0xc78, 0x06320001, + 0xc78, 0x05330001, + 0xc78, 0x04340001, + 0xc78, 0x03350001, + 0xc78, 0x02360001, + 0xc78, 0x01370001, + 0xc78, 0x00380001, + 0xc78, 0x00390001, + 0xc78, 0x003a0001, + 0xc78, 0x003b0001, + 0xc78, 0x003c0001, + 0xc78, 0x003d0001, + 0xc78, 0x003e0001, + 0xc78, 0x003f0001, + 0xc78, 0x7b400001, + 0xc78, 0x7b410001, + 0xc78, 0x7b420001, + 0xc78, 0x7b430001, + 0xc78, 0x7b440001, + 0xc78, 0x7b450001, + 0xc78, 0x7a460001, + 0xc78, 0x79470001, + 0xc78, 0x78480001, + 0xc78, 0x77490001, + 0xc78, 0x764a0001, + 0xc78, 0x754b0001, + 0xc78, 0x744c0001, + 0xc78, 0x734d0001, + 0xc78, 0x724e0001, + 0xc78, 0x714f0001, + 0xc78, 0x70500001, + 0xc78, 0x6f510001, + 0xc78, 0x6e520001, + 0xc78, 0x6d530001, + 0xc78, 0x6c540001, + 0xc78, 0x6b550001, + 0xc78, 0x6a560001, + 0xc78, 0x69570001, + 0xc78, 0x68580001, + 0xc78, 0x67590001, + 0xc78, 0x665a0001, + 0xc78, 0x655b0001, + 0xc78, 0x645c0001, + 0xc78, 0x635d0001, + 0xc78, 0x625e0001, + 0xc78, 0x615f0001, + 0xc78, 0x60600001, + 0xc78, 0x49610001, + 0xc78, 0x48620001, + 0xc78, 0x47630001, + 0xc78, 0x46640001, + 0xc78, 0x45650001, + 0xc78, 0x44660001, + 0xc78, 0x43670001, + 0xc78, 0x42680001, + 0xc78, 0x41690001, + 0xc78, 0x406a0001, + 0xc78, 0x266b0001, + 0xc78, 0x256c0001, + 0xc78, 0x246d0001, + 0xc78, 0x236e0001, + 0xc78, 0x226f0001, + 0xc78, 0x21700001, + 0xc78, 0x20710001, + 0xc78, 0x06720001, + 0xc78, 0x05730001, + 0xc78, 0x04740001, + 0xc78, 0x03750001, + 0xc78, 0x02760001, + 0xc78, 0x01770001, + 0xc78, 0x00780001, + 0xc78, 0x00790001, + 0xc78, 0x007a0001, + 0xc78, 0x007b0001, + 0xc78, 0x007c0001, + 0xc78, 0x007d0001, + 0xc78, 0x007e0001, + 0xc78, 0x007f0001, + 0xc78, 0x3800001e, + 0xc78, 0x3801001e, + 0xc78, 0x3802001e, + 0xc78, 0x3803001e, + 0xc78, 0x3804001e, + 0xc78, 0x3805001e, + 0xc78, 0x3806001e, + 0xc78, 0x3807001e, + 0xc78, 0x3808001e, + 0xc78, 0x3c09001e, + 0xc78, 0x3e0a001e, + 0xc78, 0x400b001e, + 0xc78, 0x440c001e, + 0xc78, 0x480d001e, + 0xc78, 0x4c0e001e, + 0xc78, 0x500f001e, + 0xc78, 0x5210001e, + 0xc78, 0x5611001e, + 0xc78, 0x5a12001e, + 0xc78, 0x5e13001e, + 0xc78, 0x6014001e, + 0xc78, 0x6015001e, + 0xc78, 0x6016001e, + 0xc78, 0x6217001e, + 0xc78, 0x6218001e, + 0xc78, 0x6219001e, + 0xc78, 0x621a001e, + 0xc78, 0x621b001e, + 0xc78, 0x621c001e, + 0xc78, 0x621d001e, + 0xc78, 0x621e001e, + 0xc78, 0x621f001e, +}; diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/table.h b/drivers/net/wireless/rtlwifi/rtl8192ce/table.h new file mode 100644 index 00000000..8b79161f --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/table.h @@ -0,0 +1,58 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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 __RTL92CE_TABLE__H_ +#define __RTL92CE_TABLE__H_ + +#include <linux/types.h> + +#define PHY_REG_2TARRAY_LENGTH 374 +extern u32 RTL8192CEPHY_REG_2TARRAY[PHY_REG_2TARRAY_LENGTH]; +#define PHY_REG_1TARRAY_LENGTH 374 +extern u32 RTL8192CEPHY_REG_1TARRAY[PHY_REG_1TARRAY_LENGTH]; +#define PHY_REG_ARRAY_PGLENGTH 192 +extern u32 RTL8192CEPHY_REG_ARRAY_PG[PHY_REG_ARRAY_PGLENGTH]; +#define RADIOA_2TARRAYLENGTH 282 +extern u32 RTL8192CERADIOA_2TARRAY[RADIOA_2TARRAYLENGTH]; +#define RADIOB_2TARRAYLENGTH 78 +extern u32 RTL8192CE_RADIOB_2TARRAY[RADIOB_2TARRAYLENGTH]; +#define RADIOA_1TARRAYLENGTH 282 +extern u32 RTL8192CE_RADIOA_1TARRAY[RADIOA_1TARRAYLENGTH]; +#define RADIOB_1TARRAYLENGTH 1 +extern u32 RTL8192CE_RADIOB_1TARRAY[RADIOB_1TARRAYLENGTH]; +#define MAC_2T_ARRAYLENGTH 162 +extern u32 RTL8192CEMAC_2T_ARRAY[MAC_2T_ARRAYLENGTH]; +#define AGCTAB_2TARRAYLENGTH 320 +extern u32 RTL8192CEAGCTAB_2TARRAY[AGCTAB_2TARRAYLENGTH]; +#define AGCTAB_1TARRAYLENGTH 320 +extern u32 RTL8192CEAGCTAB_1TARRAY[AGCTAB_1TARRAYLENGTH]; + +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c new file mode 100644 index 00000000..37b13636 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c @@ -0,0 +1,911 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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> + * + *****************************************************************************/ + +#include "../wifi.h" +#include "../pci.h" +#include "../base.h" +#include "reg.h" +#include "def.h" +#include "phy.h" +#include "trx.h" +#include "led.h" + +static u8 _rtl92ce_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)) + return QSLT_MGNT; + + return skb->priority; +} + +static u8 _rtl92c_query_rxpwrpercentage(char antpower) +{ + if ((antpower <= -100) || (antpower >= 20)) + return 0; + else if (antpower >= 0) + return 100; + else + return 100 + antpower; +} + +static u8 _rtl92c_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; +} + +static long _rtl92ce_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; +} + +static long _rtl92ce_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; +} + +static void _rtl92ce_query_rxphystatus(struct ieee80211_hw *hw, + struct rtl_stats *pstats, + struct rx_desc_92c *pdesc, + struct rx_fwinfo_92c *p_drvinfo, + bool packet_match_bssid, + bool packet_toself, + bool packet_beacon) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct phy_sts_cck_8192s_t *cck_buf; + s8 rx_pwr_all = 0, rx_pwr[4]; + u8 evm, pwdb_all, rf_rx_num = 0; + u8 i, max_spatial_stream; + u32 rssi, total_rssi = 0; + bool in_powersavemode = false; + bool is_cck_rate; + + is_cck_rate = RX_HAL_IS_CCK_RATE(pdesc); + pstats->packet_matchbssid = packet_match_bssid; + pstats->packet_toself = packet_toself; + pstats->is_cck = is_cck_rate; + pstats->packet_beacon = packet_beacon; + pstats->is_cck = is_cck_rate; + pstats->rx_mimo_signalquality[0] = -1; + pstats->rx_mimo_signalquality[1] = -1; + + if (is_cck_rate) { + u8 report, cck_highpwr; + cck_buf = (struct phy_sts_cck_8192s_t *)p_drvinfo; + + if (!in_powersavemode) + cck_highpwr = (u8) rtl_get_bbreg(hw, + RFPGA0_XA_HSSIPARAMETER2, + BIT(9)); + else + cck_highpwr = false; + + if (!cck_highpwr) { + u8 cck_agc_rpt = cck_buf->cck_agc_rpt; + report = cck_buf->cck_agc_rpt & 0xc0; + report = report >> 6; + switch (report) { + case 0x3: + rx_pwr_all = -46 - (cck_agc_rpt & 0x3e); + break; + case 0x2: + rx_pwr_all = -26 - (cck_agc_rpt & 0x3e); + break; + case 0x1: + rx_pwr_all = -12 - (cck_agc_rpt & 0x3e); + break; + case 0x0: + rx_pwr_all = 16 - (cck_agc_rpt & 0x3e); + break; + } + } else { + u8 cck_agc_rpt = cck_buf->cck_agc_rpt; + report = p_drvinfo->cfosho[0] & 0x60; + report = report >> 5; + switch (report) { + case 0x3: + rx_pwr_all = -46 - ((cck_agc_rpt & 0x1f) << 1); + break; + case 0x2: + rx_pwr_all = -26 - ((cck_agc_rpt & 0x1f) << 1); + break; + case 0x1: + rx_pwr_all = -12 - ((cck_agc_rpt & 0x1f) << 1); + break; + case 0x0: + rx_pwr_all = 16 - ((cck_agc_rpt & 0x1f) << 1); + break; + } + } + + pwdb_all = _rtl92c_query_rxpwrpercentage(rx_pwr_all); + pstats->rx_pwdb_all = pwdb_all; + pstats->recvsignalpower = rx_pwr_all; + + if (packet_match_bssid) { + u8 sq; + if (pstats->rx_pwdb_all > 40) + sq = 100; + else { + sq = cck_buf->sq_rpt; + if (sq > 64) + sq = 0; + else if (sq < 20) + sq = 100; + else + sq = ((64 - sq) * 100) / 44; + } + + pstats->signalquality = sq; + pstats->rx_mimo_signalquality[0] = sq; + pstats->rx_mimo_signalquality[1] = -1; + } + } else { + rtlpriv->dm.rfpath_rxenable[0] = + rtlpriv->dm.rfpath_rxenable[1] = true; + for (i = RF90_PATH_A; i < RF90_PATH_MAX; i++) { + if (rtlpriv->dm.rfpath_rxenable[i]) + rf_rx_num++; + + rx_pwr[i] = + ((p_drvinfo->gain_trsw[i] & 0x3f) * 2) - 110; + rssi = _rtl92c_query_rxpwrpercentage(rx_pwr[i]); + total_rssi += rssi; + rtlpriv->stats.rx_snr_db[i] = + (long)(p_drvinfo->rxsnr[i] / 2); + + if (packet_match_bssid) + pstats->rx_mimo_signalstrength[i] = (u8) rssi; + } + + rx_pwr_all = ((p_drvinfo->pwdb_all >> 1) & 0x7f) - 110; + pwdb_all = _rtl92c_query_rxpwrpercentage(rx_pwr_all); + pstats->rx_pwdb_all = pwdb_all; + pstats->rxpower = rx_pwr_all; + pstats->recvsignalpower = rx_pwr_all; + + if (pdesc->rxht && pdesc->rxmcs >= DESC92_RATEMCS8 && + pdesc->rxmcs <= DESC92_RATEMCS15) + max_spatial_stream = 2; + else + max_spatial_stream = 1; + + for (i = 0; i < max_spatial_stream; i++) { + evm = _rtl92c_evm_db_to_percentage(p_drvinfo->rxevm[i]); + + if (packet_match_bssid) { + if (i == 0) + pstats->signalquality = + (u8) (evm & 0xff); + pstats->rx_mimo_signalquality[i] = + (u8) (evm & 0xff); + } + } + } + + if (is_cck_rate) + pstats->signalstrength = + (u8) (_rtl92ce_signal_scale_mapping(hw, pwdb_all)); + else if (rf_rx_num != 0) + pstats->signalstrength = + (u8) (_rtl92ce_signal_scale_mapping + (hw, total_rssi /= rf_rx_num)); +} + +static void _rtl92ce_process_ui_rssi(struct ieee80211_hw *hw, + struct rtl_stats *pstats) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + u8 rfpath; + u32 last_rssi, tmpval; + + if (pstats->packet_toself || pstats->packet_beacon) { + 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 += pstats->signalstrength; + rtlpriv->stats.ui_rssi.elements[rtlpriv->stats.ui_rssi. + index++] = + pstats->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 = + _rtl92ce_translate_todbm(hw, (u8) tmpval); + pstats->rssi = rtlpriv->stats.signal_strength; + } + + if (!pstats->is_cck && pstats->packet_toself) { + 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] = + pstats->rx_mimo_signalstrength[rfpath]; + + } + + if (pstats->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)) + + (pstats->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)) + + (pstats->rx_mimo_signalstrength[rfpath])) / + (RX_SMOOTH_FACTOR); + } + + } + } +} + +static void _rtl92ce_update_rxsignalstatistics(struct ieee80211_hw *hw, + struct rtl_stats *pstats) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + int weighting = 0; + + if (rtlpriv->stats.recv_signal_power == 0) + rtlpriv->stats.recv_signal_power = pstats->recvsignalpower; + + if (pstats->recvsignalpower > rtlpriv->stats.recv_signal_power) + weighting = 5; + + else if (pstats->recvsignalpower < rtlpriv->stats.recv_signal_power) + weighting = (-5); + + rtlpriv->stats.recv_signal_power = + (rtlpriv->stats.recv_signal_power * 5 + + pstats->recvsignalpower + weighting) / 6; +} + +static void _rtl92ce_process_pwdb(struct ieee80211_hw *hw, + struct rtl_stats *pstats) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + long undecorated_smoothed_pwdb; + + if (mac->opmode == NL80211_IFTYPE_ADHOC) { + return; + } else { + undecorated_smoothed_pwdb = + rtlpriv->dm.undecorated_smoothed_pwdb; + } + + if (pstats->packet_toself || pstats->packet_beacon) { + if (undecorated_smoothed_pwdb < 0) + undecorated_smoothed_pwdb = pstats->rx_pwdb_all; + + if (pstats->rx_pwdb_all > (u32) undecorated_smoothed_pwdb) { + undecorated_smoothed_pwdb = + (((undecorated_smoothed_pwdb) * + (RX_SMOOTH_FACTOR - 1)) + + (pstats->rx_pwdb_all)) / (RX_SMOOTH_FACTOR); + + undecorated_smoothed_pwdb = undecorated_smoothed_pwdb + + 1; + } else { + undecorated_smoothed_pwdb = + (((undecorated_smoothed_pwdb) * + (RX_SMOOTH_FACTOR - 1)) + + (pstats->rx_pwdb_all)) / (RX_SMOOTH_FACTOR); + } + + rtlpriv->dm.undecorated_smoothed_pwdb = + undecorated_smoothed_pwdb; + _rtl92ce_update_rxsignalstatistics(hw, pstats); + } +} + +static void _rtl92ce_process_ui_link_quality(struct ieee80211_hw *hw, + struct rtl_stats *pstats) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 last_evm, n_spatialstream, tmpval; + + if (pstats->signalquality != 0) { + if (pstats->packet_toself || pstats->packet_beacon) { + + 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 += + pstats->signalquality; + rtlpriv->stats.ui_link_quality.elements[rtlpriv->stats. + ui_link_quality. + index++] = + pstats->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_spatialstream = 0; n_spatialstream < 2; + n_spatialstream++) { + if (pstats-> + rx_mimo_signalquality[n_spatialstream] != + -1) { + if (rtlpriv->stats. + rx_evm_percentage[n_spatialstream] + == 0) { + rtlpriv->stats. + rx_evm_percentage + [n_spatialstream] = + pstats->rx_mimo_signalquality + [n_spatialstream]; + } + + rtlpriv->stats. + rx_evm_percentage[n_spatialstream] = + ((rtlpriv-> + stats.rx_evm_percentage + [n_spatialstream] * + (RX_SMOOTH_FACTOR - 1)) + + (pstats-> + rx_mimo_signalquality + [n_spatialstream] * 1)) / + (RX_SMOOTH_FACTOR); + } + } + } + } else { + ; + } +} + +static void _rtl92ce_process_phyinfo(struct ieee80211_hw *hw, + u8 *buffer, + struct rtl_stats *pcurrent_stats) +{ + + if (!pcurrent_stats->packet_matchbssid && + !pcurrent_stats->packet_beacon) + return; + + _rtl92ce_process_ui_rssi(hw, pcurrent_stats); + _rtl92ce_process_pwdb(hw, pcurrent_stats); + _rtl92ce_process_ui_link_quality(hw, pcurrent_stats); +} + +static void _rtl92ce_translate_rx_signal_stuff(struct ieee80211_hw *hw, + struct sk_buff *skb, + struct rtl_stats *pstats, + struct rx_desc_92c *pdesc, + struct rx_fwinfo_92c *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; + __le16 fc; + u16 type, c_fc; + bool packet_matchbssid, packet_toself, packet_beacon; + + tmp_buf = skb->data + pstats->rx_drvinfo_size + pstats->rx_bufshift; + + hdr = (struct ieee80211_hdr *)tmp_buf; + fc = hdr->frame_control; + c_fc = le16_to_cpu(fc); + type = WLAN_FC_GET_TYPE(fc); + praddr = hdr->addr1; + + packet_matchbssid = + ((IEEE80211_FTYPE_CTL != type) && + (!compare_ether_addr(mac->bssid, + (c_fc & IEEE80211_FCTL_TODS) ? + hdr->addr1 : (c_fc & IEEE80211_FCTL_FROMDS) ? + hdr->addr2 : hdr->addr3)) && + (!pstats->hwerror) && (!pstats->crc) && (!pstats->icv)); + + packet_toself = packet_matchbssid && + (!compare_ether_addr(praddr, rtlefuse->dev_addr)); + + if (ieee80211_is_beacon(fc)) + packet_beacon = true; + + _rtl92ce_query_rxphystatus(hw, pstats, pdesc, p_drvinfo, + packet_matchbssid, packet_toself, + packet_beacon); + + _rtl92ce_process_phyinfo(hw, tmp_buf, pstats); +} + +bool rtl92ce_rx_query_desc(struct ieee80211_hw *hw, + struct rtl_stats *stats, + struct ieee80211_rx_status *rx_status, + u8 *p_desc, struct sk_buff *skb) +{ + struct rx_fwinfo_92c *p_drvinfo; + struct rx_desc_92c *pdesc = (struct rx_desc_92c *)p_desc; + + u32 phystatus = GET_RX_DESC_PHYST(pdesc); + stats->length = (u16) GET_RX_DESC_PKT_LEN(pdesc); + stats->rx_drvinfo_size = (u8) GET_RX_DESC_DRV_INFO_SIZE(pdesc) * + RX_DRV_INFO_SIZE_UNIT; + stats->rx_bufshift = (u8) (GET_RX_DESC_SHIFT(pdesc) & 0x03); + stats->icv = (u16) GET_RX_DESC_ICV(pdesc); + stats->crc = (u16) GET_RX_DESC_CRC32(pdesc); + stats->hwerror = (stats->crc | stats->icv); + stats->decrypted = !GET_RX_DESC_SWDEC(pdesc); + stats->rate = (u8) GET_RX_DESC_RXMCS(pdesc); + stats->shortpreamble = (u16) GET_RX_DESC_SPLCP(pdesc); + stats->isampdu = (bool) (GET_RX_DESC_PAGGR(pdesc) == 1); + stats->isampdu = (bool) ((GET_RX_DESC_PAGGR(pdesc) == 1) + && (GET_RX_DESC_FAGGR(pdesc) == 1)); + stats->timestamp_low = GET_RX_DESC_TSFL(pdesc); + stats->rx_is40Mhzpacket = (bool) GET_RX_DESC_BW(pdesc); + + rx_status->freq = hw->conf.channel->center_freq; + rx_status->band = hw->conf.channel->band; + + if (GET_RX_DESC_CRC32(pdesc)) + rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; + + if (!GET_RX_DESC_SWDEC(pdesc)) + rx_status->flag |= RX_FLAG_DECRYPTED; + + if (GET_RX_DESC_BW(pdesc)) + rx_status->flag |= RX_FLAG_40MHZ; + + if (GET_RX_DESC_RXHT(pdesc)) + rx_status->flag |= RX_FLAG_HT; + + rx_status->flag |= RX_FLAG_MACTIME_MPDU; + + if (stats->decrypted) + rx_status->flag |= RX_FLAG_DECRYPTED; + + rx_status->rate_idx = rtlwifi_rate_mapping(hw, + (bool)GET_RX_DESC_RXHT(pdesc), + (u8)GET_RX_DESC_RXMCS(pdesc), + (bool)GET_RX_DESC_PAGGR(pdesc)); + + rx_status->mactime = GET_RX_DESC_TSFL(pdesc); + if (phystatus) { + p_drvinfo = (struct rx_fwinfo_92c *)(skb->data + + stats->rx_bufshift); + + _rtl92ce_translate_rx_signal_stuff(hw, + skb, stats, pdesc, + p_drvinfo); + } + + /*rx_status->qual = stats->signal; */ + rx_status->signal = stats->rssi + 10; + /*rx_status->noise = -stats->noise; */ + + return true; +} + +void rtl92ce_tx_fill_desc(struct ieee80211_hw *hw, + struct ieee80211_hdr *hdr, u8 *pdesc_tx, + struct ieee80211_tx_info *info, struct sk_buff *skb, + u8 hw_queue, struct rtl_tcb_desc *tcb_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_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + bool defaultadapter = true; + struct ieee80211_sta *sta; + u8 *pdesc = (u8 *) pdesc_tx; + u16 seq_number; + __le16 fc = hdr->frame_control; + u8 fw_qsel = _rtl92ce_map_hwqueue_to_fwqueue(skb, hw_queue); + bool firstseg = ((hdr->seq_ctrl & + cpu_to_le16(IEEE80211_SCTL_FRAG)) == 0); + + bool lastseg = ((hdr->frame_control & + cpu_to_le16(IEEE80211_FCTL_MOREFRAGS)) == 0); + + dma_addr_t mapping = pci_map_single(rtlpci->pdev, + skb->data, skb->len, + PCI_DMA_TODEVICE); + u8 bw_40 = 0; + + rcu_read_lock(); + sta = get_sta(hw, mac->vif, mac->bssid); + 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; + + rtl_get_tcb_desc(hw, info, sta, skb, tcb_desc); + + CLEAR_PCI_TX_DESC_CONTENT(pdesc, sizeof(struct tx_desc_92c)); + + if (ieee80211_is_nullfunc(fc) || ieee80211_is_ctl(fc)) { + firstseg = true; + lastseg = true; + } + if (firstseg) { + SET_TX_DESC_OFFSET(pdesc, USB_HWDESC_HEADER_LEN); + + SET_TX_DESC_TX_RATE(pdesc, tcb_desc->hw_rate); + + if (tcb_desc->use_shortgi || tcb_desc->use_shortpreamble) + SET_TX_DESC_DATA_SHORTGI(pdesc, 1); + + if (info->flags & IEEE80211_TX_CTL_AMPDU) { + SET_TX_DESC_AGG_BREAK(pdesc, 1); + SET_TX_DESC_MAX_AGG_NUM(pdesc, 0x14); + } + SET_TX_DESC_SEQ(pdesc, seq_number); + + SET_TX_DESC_RTS_ENABLE(pdesc, ((tcb_desc->rts_enable && + !tcb_desc-> + cts_enable) ? 1 : 0)); + SET_TX_DESC_HW_RTS_ENABLE(pdesc, + ((tcb_desc->rts_enable + || tcb_desc->cts_enable) ? 1 : 0)); + SET_TX_DESC_CTS2SELF(pdesc, ((tcb_desc->cts_enable) ? 1 : 0)); + SET_TX_DESC_RTS_STBC(pdesc, ((tcb_desc->rts_stbc) ? 1 : 0)); + + SET_TX_DESC_RTS_RATE(pdesc, tcb_desc->rts_rate); + SET_TX_DESC_RTS_BW(pdesc, 0); + SET_TX_DESC_RTS_SC(pdesc, tcb_desc->rts_sc); + SET_TX_DESC_RTS_SHORT(pdesc, + ((tcb_desc->rts_rate <= DESC92_RATE54M) ? + (tcb_desc->rts_use_shortpreamble ? 1 : 0) + : (tcb_desc->rts_use_shortgi ? 1 : 0))); + + if (bw_40) { + if (tcb_desc->packet_bw) { + 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); + SET_TX_DESC_PKT_SIZE(pdesc, (u16) skb->len); + + 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 *keyconf = + info->control.hw_key; + + switch (keyconf->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_PKT_ID(pdesc, 0); + 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, 0); + SET_TX_DESC_USE_RATE(pdesc, tcb_desc->use_driver_rate ? 1 : 0); + + if (ieee80211_is_data_qos(fc)) { + if (mac->rdg_en) { + RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE, + "Enable RDG function\n"); + SET_TX_DESC_RDG_ENABLE(pdesc, 1); + SET_TX_DESC_HTC(pdesc, 1); + } + } + } + rcu_read_unlock(); + + SET_TX_DESC_FIRST_SEG(pdesc, (firstseg ? 1 : 0)); + SET_TX_DESC_LAST_SEG(pdesc, (lastseg ? 1 : 0)); + + SET_TX_DESC_TX_BUFFER_SIZE(pdesc, (u16) skb->len); + + SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, mapping); + + if (rtlpriv->dm.useramask) { + SET_TX_DESC_RATE_ID(pdesc, tcb_desc->ratr_index); + SET_TX_DESC_MACID(pdesc, tcb_desc->mac_id); + } else { + SET_TX_DESC_RATE_ID(pdesc, 0xC + tcb_desc->ratr_index); + SET_TX_DESC_MACID(pdesc, tcb_desc->ratr_index); + } + + if ((!ieee80211_is_data_qos(fc)) && ppsc->fwctrl_lps) { + SET_TX_DESC_HWSEQ_EN(pdesc, 1); + SET_TX_DESC_PKT_ID(pdesc, 8); + + if (!defaultadapter) + SET_TX_DESC_QOS(pdesc, 1); + } + + SET_TX_DESC_MORE_FRAG(pdesc, (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(rtlpriv, COMP_SEND, DBG_TRACE, "\n"); +} + +void rtl92ce_tx_fill_cmddesc(struct ieee80211_hw *hw, + u8 *pdesc, bool firstseg, + bool 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); + + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data); + __le16 fc = hdr->frame_control; + + CLEAR_PCI_TX_DESC_CONTENT(pdesc, TX_DESC_SIZE); + + if (firstseg) + SET_TX_DESC_OFFSET(pdesc, USB_HWDESC_HEADER_LEN); + + SET_TX_DESC_TX_RATE(pdesc, DESC92_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, 0x20); + + SET_TX_DESC_USE_RATE(pdesc, 1); + + if (!ieee80211_is_data_qos(fc)) { + SET_TX_DESC_HWSEQ_EN(pdesc, 1); + SET_TX_DESC_PKT_ID(pdesc, 8); + } + + RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD, + "H2C Tx Cmd Content", pdesc, TX_DESC_SIZE); +} + +void rtl92ce_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val) +{ + if (istx) { + switch (desc_name) { + case HW_DESC_OWN: + wmb(); + SET_TX_DESC_OWN(pdesc, 1); + break; + case HW_DESC_TX_NEXTDESC_ADDR: + SET_TX_DESC_NEXT_DESC_ADDRESS(pdesc, *(u32 *) val); + break; + default: + RT_ASSERT(false, "ERR txdesc :%d not process\n", + desc_name); + break; + } + } else { + switch (desc_name) { + case HW_DESC_RXOWN: + wmb(); + SET_RX_DESC_OWN(pdesc, 1); + break; + case HW_DESC_RXBUFF_ADDR: + SET_RX_DESC_BUFF_ADDR(pdesc, *(u32 *) val); + break; + case HW_DESC_RXPKT_LEN: + SET_RX_DESC_PKT_LEN(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 rtl92ce_get_desc(u8 *p_desc, bool istx, u8 desc_name) +{ + u32 ret = 0; + + if (istx) { + switch (desc_name) { + case HW_DESC_OWN: + ret = GET_TX_DESC_OWN(p_desc); + break; + case HW_DESC_TXBUFF_ADDR: + ret = GET_TX_DESC_TX_BUFFER_ADDRESS(p_desc); + break; + default: + RT_ASSERT(false, "ERR txdesc :%d not process\n", + desc_name); + break; + } + } else { + struct rx_desc_92c *pdesc = (struct rx_desc_92c *)p_desc; + 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; + default: + RT_ASSERT(false, "ERR rxdesc :%d not process\n", + desc_name); + break; + } + } + return ret; +} + +void rtl92ce_tx_polling(struct ieee80211_hw *hw, u8 hw_queue) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + if (hw_queue == BEACON_QUEUE) { + rtl_write_word(rtlpriv, REG_PCIE_CTRL_REG, BIT(4)); + } else { + rtl_write_word(rtlpriv, REG_PCIE_CTRL_REG, + BIT(0) << (hw_queue)); + } +} + diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.h b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.h new file mode 100644 index 00000000..efb9ab27 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.h @@ -0,0 +1,733 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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 __RTL92CE_TRX_H__ +#define __RTL92CE_TRX_H__ + +#define TX_DESC_SIZE 64 +#define TX_DESC_AGGR_SUBFRAME_SIZE 32 + +#define RX_DESC_SIZE 32 +#define RX_DRV_INFO_SIZE_UNIT 8 + +#define TX_DESC_NEXT_DESC_OFFSET 40 +#define USB_HWDESC_HEADER_LEN 32 +#define CRCLENGTH 4 + +/* Define a macro that takes a le32 word, converts it to host ordering, + * right shifts by a specified count, creates a mask of the specified + * bit count, and extracts that number of bits. + */ + +#define SHIFT_AND_MASK_LE(__pdesc, __shift, __mask) \ + ((le32_to_cpu(*(((__le32 *)(__pdesc)))) >> (__shift)) & \ + BIT_LEN_MASK_32(__mask)) + +/* Define a macro that clears a bit field in an le32 word and + * sets the specified value into that bit field. The resulting + * value remains in le32 ordering; however, it is properly converted + * to host ordering for the clear and set operations before conversion + * back to le32. + */ + +#define SET_BITS_OFFSET_LE(__pdesc, __shift, __len, __val) \ + (*(__le32 *)(__pdesc) = \ + (cpu_to_le32((le32_to_cpu(*((__le32 *)(__pdesc))) & \ + (~(BIT_OFFSET_LEN_MASK_32((__shift), __len)))) | \ + (((u32)(__val) & BIT_LEN_MASK_32(__len)) << (__shift))))); + +/* macros to read/write various fields in RX or TX descriptors */ + +#define SET_TX_DESC_PKT_SIZE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 0, 16, __val) +#define SET_TX_DESC_OFFSET(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 16, 8, __val) +#define SET_TX_DESC_BMC(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 24, 1, __val) +#define SET_TX_DESC_HTC(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 25, 1, __val) +#define SET_TX_DESC_LAST_SEG(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 26, 1, __val) +#define SET_TX_DESC_FIRST_SEG(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 27, 1, __val) +#define SET_TX_DESC_LINIP(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 28, 1, __val) +#define SET_TX_DESC_NO_ACM(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 29, 1, __val) +#define SET_TX_DESC_GF(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 30, 1, __val) +#define SET_TX_DESC_OWN(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 31, 1, __val) + +#define GET_TX_DESC_PKT_SIZE(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 0, 16) +#define GET_TX_DESC_OFFSET(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 16, 8) +#define GET_TX_DESC_BMC(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 24, 1) +#define GET_TX_DESC_HTC(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 25, 1) +#define GET_TX_DESC_LAST_SEG(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 26, 1) +#define GET_TX_DESC_FIRST_SEG(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 27, 1) +#define GET_TX_DESC_LINIP(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 28, 1) +#define GET_TX_DESC_NO_ACM(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 29, 1) +#define GET_TX_DESC_GF(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 30, 1) +#define GET_TX_DESC_OWN(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 31, 1) + +#define SET_TX_DESC_MACID(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+4, 0, 5, __val) +#define SET_TX_DESC_AGG_BREAK(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+4, 5, 1, __val) +#define SET_TX_DESC_BK(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+4, 6, 1, __val) +#define SET_TX_DESC_RDG_ENABLE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+4, 7, 1, __val) +#define SET_TX_DESC_QUEUE_SEL(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+4, 8, 5, __val) +#define SET_TX_DESC_RDG_NAV_EXT(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+4, 13, 1, __val) +#define SET_TX_DESC_LSIG_TXOP_EN(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+4, 14, 1, __val) +#define SET_TX_DESC_PIFS(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+4, 15, 1, __val) +#define SET_TX_DESC_RATE_ID(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+4, 16, 4, __val) +#define SET_TX_DESC_NAV_USE_HDR(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+4, 20, 1, __val) +#define SET_TX_DESC_EN_DESC_ID(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+4, 21, 1, __val) +#define SET_TX_DESC_SEC_TYPE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+4, 22, 2, __val) +#define SET_TX_DESC_PKT_OFFSET(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+4, 24, 8, __val) + +#define GET_TX_DESC_MACID(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+4, 0, 5) +#define GET_TX_DESC_AGG_ENABLE(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+4, 5, 1) +#define GET_TX_DESC_AGG_BREAK(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+4, 6, 1) +#define GET_TX_DESC_RDG_ENABLE(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+4, 7, 1) +#define GET_TX_DESC_QUEUE_SEL(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+4, 8, 5) +#define GET_TX_DESC_RDG_NAV_EXT(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+4, 13, 1) +#define GET_TX_DESC_LSIG_TXOP_EN(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+4, 14, 1) +#define GET_TX_DESC_PIFS(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+4, 15, 1) +#define GET_TX_DESC_RATE_ID(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+4, 16, 4) +#define GET_TX_DESC_NAV_USE_HDR(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+4, 20, 1) +#define GET_TX_DESC_EN_DESC_ID(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+4, 21, 1) +#define GET_TX_DESC_SEC_TYPE(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+4, 22, 2) +#define GET_TX_DESC_PKT_OFFSET(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+4, 24, 8) + +#define SET_TX_DESC_RTS_RC(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+8, 0, 6, __val) +#define SET_TX_DESC_DATA_RC(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+8, 6, 6, __val) +#define SET_TX_DESC_BAR_RTY_TH(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+8, 14, 2, __val) +#define SET_TX_DESC_MORE_FRAG(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+8, 17, 1, __val) +#define SET_TX_DESC_RAW(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+8, 18, 1, __val) +#define SET_TX_DESC_CCX(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+8, 19, 1, __val) +#define SET_TX_DESC_AMPDU_DENSITY(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+8, 20, 3, __val) +#define SET_TX_DESC_ANTSEL_A(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+8, 24, 1, __val) +#define SET_TX_DESC_ANTSEL_B(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+8, 25, 1, __val) +#define SET_TX_DESC_TX_ANT_CCK(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+8, 26, 2, __val) +#define SET_TX_DESC_TX_ANTL(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+8, 28, 2, __val) +#define SET_TX_DESC_TX_ANT_HT(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+8, 30, 2, __val) + +#define GET_TX_DESC_RTS_RC(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+8, 0, 6) +#define GET_TX_DESC_DATA_RC(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+8, 6, 6) +#define GET_TX_DESC_BAR_RTY_TH(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+8, 14, 2) +#define GET_TX_DESC_MORE_FRAG(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+8, 17, 1) +#define GET_TX_DESC_RAW(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+8, 18, 1) +#define GET_TX_DESC_CCX(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+8, 19, 1) +#define GET_TX_DESC_AMPDU_DENSITY(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+8, 20, 3) +#define GET_TX_DESC_ANTSEL_A(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+8, 24, 1) +#define GET_TX_DESC_ANTSEL_B(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+8, 25, 1) +#define GET_TX_DESC_TX_ANT_CCK(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+8, 26, 2) +#define GET_TX_DESC_TX_ANTL(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+8, 28, 2) +#define GET_TX_DESC_TX_ANT_HT(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+8, 30, 2) + +#define SET_TX_DESC_NEXT_HEAP_PAGE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+12, 0, 8, __val) +#define SET_TX_DESC_TAIL_PAGE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+12, 8, 8, __val) +#define SET_TX_DESC_SEQ(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+12, 16, 12, __val) +#define SET_TX_DESC_PKT_ID(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+12, 28, 4, __val) + +#define GET_TX_DESC_NEXT_HEAP_PAGE(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+12, 0, 8) +#define GET_TX_DESC_TAIL_PAGE(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+12, 8, 8) +#define GET_TX_DESC_SEQ(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+12, 16, 12) +#define GET_TX_DESC_PKT_ID(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+12, 28, 4) + +#define SET_TX_DESC_RTS_RATE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+16, 0, 5, __val) +#define SET_TX_DESC_AP_DCFE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+16, 5, 1, __val) +#define SET_TX_DESC_QOS(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+16, 6, 1, __val) +#define SET_TX_DESC_HWSEQ_EN(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+16, 7, 1, __val) +#define SET_TX_DESC_USE_RATE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+16, 8, 1, __val) +#define SET_TX_DESC_DISABLE_RTS_FB(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+16, 9, 1, __val) +#define SET_TX_DESC_DISABLE_FB(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+16, 10, 1, __val) +#define SET_TX_DESC_CTS2SELF(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+16, 11, 1, __val) +#define SET_TX_DESC_RTS_ENABLE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+16, 12, 1, __val) +#define SET_TX_DESC_HW_RTS_ENABLE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+16, 13, 1, __val) +#define SET_TX_DESC_PORT_ID(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+16, 14, 1, __val) +#define SET_TX_DESC_WAIT_DCTS(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+16, 18, 1, __val) +#define SET_TX_DESC_CTS2AP_EN(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+16, 19, 1, __val) +#define SET_TX_DESC_TX_SUB_CARRIER(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+16, 20, 2, __val) +#define SET_TX_DESC_TX_STBC(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+16, 22, 2, __val) +#define SET_TX_DESC_DATA_SHORT(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+16, 24, 1, __val) +#define SET_TX_DESC_DATA_BW(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+16, 25, 1, __val) +#define SET_TX_DESC_RTS_SHORT(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+16, 26, 1, __val) +#define SET_TX_DESC_RTS_BW(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+16, 27, 1, __val) +#define SET_TX_DESC_RTS_SC(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+16, 28, 2, __val) +#define SET_TX_DESC_RTS_STBC(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+16, 30, 2, __val) + +#define GET_TX_DESC_RTS_RATE(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+16, 0, 5) +#define GET_TX_DESC_AP_DCFE(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+16, 5, 1) +#define GET_TX_DESC_QOS(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+16, 6, 1) +#define GET_TX_DESC_HWSEQ_EN(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+16, 7, 1) +#define GET_TX_DESC_USE_RATE(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+16, 8, 1) +#define GET_TX_DESC_DISABLE_RTS_FB(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+16, 9, 1) +#define GET_TX_DESC_DISABLE_FB(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+16, 10, 1) +#define GET_TX_DESC_CTS2SELF(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+16, 11, 1) +#define GET_TX_DESC_RTS_ENABLE(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+16, 12, 1) +#define GET_TX_DESC_HW_RTS_ENABLE(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+16, 13, 1) +#define GET_TX_DESC_PORT_ID(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+16, 14, 1) +#define GET_TX_DESC_WAIT_DCTS(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+16, 18, 1) +#define GET_TX_DESC_CTS2AP_EN(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+16, 19, 1) +#define GET_TX_DESC_TX_SUB_CARRIER(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+16, 20, 2) +#define GET_TX_DESC_TX_STBC(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+16, 22, 2) +#define GET_TX_DESC_DATA_SHORT(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+16, 24, 1) +#define GET_TX_DESC_DATA_BW(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+16, 25, 1) +#define GET_TX_DESC_RTS_SHORT(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+16, 26, 1) +#define GET_TX_DESC_RTS_BW(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+16, 27, 1) +#define GET_TX_DESC_RTS_SC(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+16, 28, 2) +#define GET_TX_DESC_RTS_STBC(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+16, 30, 2) + +#define SET_TX_DESC_TX_RATE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+20, 0, 6, __val) +#define SET_TX_DESC_DATA_SHORTGI(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+20, 6, 1, __val) +#define SET_TX_DESC_CCX_TAG(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+20, 7, 1, __val) +#define SET_TX_DESC_DATA_RATE_FB_LIMIT(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+20, 8, 5, __val) +#define SET_TX_DESC_RTS_RATE_FB_LIMIT(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+20, 13, 4, __val) +#define SET_TX_DESC_RETRY_LIMIT_ENABLE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+20, 17, 1, __val) +#define SET_TX_DESC_DATA_RETRY_LIMIT(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+20, 18, 6, __val) +#define SET_TX_DESC_USB_TXAGG_NUM(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+20, 24, 8, __val) + +#define GET_TX_DESC_TX_RATE(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+20, 0, 6) +#define GET_TX_DESC_DATA_SHORTGI(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+20, 6, 1) +#define GET_TX_DESC_CCX_TAG(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+20, 7, 1) +#define GET_TX_DESC_DATA_RATE_FB_LIMIT(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+20, 8, 5) +#define GET_TX_DESC_RTS_RATE_FB_LIMIT(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+20, 13, 4) +#define GET_TX_DESC_RETRY_LIMIT_ENABLE(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+20, 17, 1) +#define GET_TX_DESC_DATA_RETRY_LIMIT(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+20, 18, 6) +#define GET_TX_DESC_USB_TXAGG_NUM(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+20, 24, 8) + +#define SET_TX_DESC_TXAGC_A(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+24, 0, 5, __val) +#define SET_TX_DESC_TXAGC_B(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+24, 5, 5, __val) +#define SET_TX_DESC_USE_MAX_LEN(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+24, 10, 1, __val) +#define SET_TX_DESC_MAX_AGG_NUM(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+24, 11, 5, __val) +#define SET_TX_DESC_MCSG1_MAX_LEN(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+24, 16, 4, __val) +#define SET_TX_DESC_MCSG2_MAX_LEN(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+24, 20, 4, __val) +#define SET_TX_DESC_MCSG3_MAX_LEN(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+24, 24, 4, __val) +#define SET_TX_DESC_MCS7_SGI_MAX_LEN(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+24, 28, 4, __val) + +#define GET_TX_DESC_TXAGC_A(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+24, 0, 5) +#define GET_TX_DESC_TXAGC_B(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+24, 5, 5) +#define GET_TX_DESC_USE_MAX_LEN(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+24, 10, 1) +#define GET_TX_DESC_MAX_AGG_NUM(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+24, 11, 5) +#define GET_TX_DESC_MCSG1_MAX_LEN(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+24, 16, 4) +#define GET_TX_DESC_MCSG2_MAX_LEN(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+24, 20, 4) +#define GET_TX_DESC_MCSG3_MAX_LEN(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+24, 24, 4) +#define GET_TX_DESC_MCS7_SGI_MAX_LEN(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+24, 28, 4) + +#define SET_TX_DESC_TX_BUFFER_SIZE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+28, 0, 16, __val) +#define SET_TX_DESC_MCSG4_MAX_LEN(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+28, 16, 4, __val) +#define SET_TX_DESC_MCSG5_MAX_LEN(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+28, 20, 4, __val) +#define SET_TX_DESC_MCSG6_MAX_LEN(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+28, 24, 4, __val) +#define SET_TX_DESC_MCS15_SGI_MAX_LEN(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+28, 28, 4, __val) + +#define GET_TX_DESC_TX_BUFFER_SIZE(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+28, 0, 16) +#define GET_TX_DESC_MCSG4_MAX_LEN(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+28, 16, 4) +#define GET_TX_DESC_MCSG5_MAX_LEN(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+28, 20, 4) +#define GET_TX_DESC_MCSG6_MAX_LEN(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+28, 24, 4) +#define GET_TX_DESC_MCS15_SGI_MAX_LEN(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+28, 28, 4) + +#define SET_TX_DESC_TX_BUFFER_ADDRESS(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+32, 0, 32, __val) +#define SET_TX_DESC_TX_BUFFER_ADDRESS64(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+36, 0, 32, __val) + +#define GET_TX_DESC_TX_BUFFER_ADDRESS(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+32, 0, 32) +#define GET_TX_DESC_TX_BUFFER_ADDRESS64(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+36, 0, 32) + +#define SET_TX_DESC_NEXT_DESC_ADDRESS(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+40, 0, 32, __val) +#define SET_TX_DESC_NEXT_DESC_ADDRESS64(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+44, 0, 32, __val) + +#define GET_TX_DESC_NEXT_DESC_ADDRESS(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+40, 0, 32) +#define GET_TX_DESC_NEXT_DESC_ADDRESS64(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+44, 0, 32) + +#define GET_RX_DESC_PKT_LEN(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 0, 14) +#define GET_RX_DESC_CRC32(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 14, 1) +#define GET_RX_DESC_ICV(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 15, 1) +#define GET_RX_DESC_DRV_INFO_SIZE(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 16, 4) +#define GET_RX_DESC_SECURITY(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 20, 3) +#define GET_RX_DESC_QOS(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 23, 1) +#define GET_RX_DESC_SHIFT(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 24, 2) +#define GET_RX_DESC_PHYST(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 26, 1) +#define GET_RX_DESC_SWDEC(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 27, 1) +#define GET_RX_DESC_LS(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 28, 1) +#define GET_RX_DESC_FS(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 29, 1) +#define GET_RX_DESC_EOR(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 30, 1) +#define GET_RX_DESC_OWN(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 31, 1) + +#define SET_RX_DESC_PKT_LEN(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 0, 14, __val) +#define SET_RX_DESC_EOR(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 30, 1, __val) +#define SET_RX_DESC_OWN(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 31, 1, __val) + +#define GET_RX_DESC_MACID(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+4, 0, 5) +#define GET_RX_DESC_TID(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+4, 5, 4) +#define GET_RX_DESC_HWRSVD(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+4, 9, 5) +#define GET_RX_DESC_PAGGR(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+4, 14, 1) +#define GET_RX_DESC_FAGGR(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+4, 15, 1) +#define GET_RX_DESC_A1_FIT(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+4, 16, 4) +#define GET_RX_DESC_A2_FIT(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+4, 20, 4) +#define GET_RX_DESC_PAM(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+4, 24, 1) +#define GET_RX_DESC_PWR(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+4, 25, 1) +#define GET_RX_DESC_MD(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+4, 26, 1) +#define GET_RX_DESC_MF(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+4, 27, 1) +#define GET_RX_DESC_TYPE(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+4, 28, 2) +#define GET_RX_DESC_MC(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+4, 30, 1) +#define GET_RX_DESC_BC(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+4, 31, 1) +#define GET_RX_DESC_SEQ(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+8, 0, 12) +#define GET_RX_DESC_FRAG(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+8, 12, 4) +#define GET_RX_DESC_NEXT_PKT_LEN(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+8, 16, 14) +#define GET_RX_DESC_NEXT_IND(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+8, 30, 1) +#define GET_RX_DESC_RSVD(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+8, 31, 1) + +#define GET_RX_DESC_RXMCS(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+12, 0, 6) +#define GET_RX_DESC_RXHT(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+12, 6, 1) +#define GET_RX_DESC_SPLCP(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+12, 8, 1) +#define GET_RX_DESC_BW(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+12, 9, 1) +#define GET_RX_DESC_HTC(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+12, 10, 1) +#define GET_RX_DESC_HWPC_ERR(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+12, 14, 1) +#define GET_RX_DESC_HWPC_IND(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+12, 15, 1) +#define GET_RX_DESC_IV0(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+12, 16, 16) + +#define GET_RX_DESC_IV1(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+16, 0, 32) +#define GET_RX_DESC_TSFL(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+20, 0, 32) + +#define GET_RX_DESC_BUFF_ADDR(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+24, 0, 32) +#define GET_RX_DESC_BUFF_ADDR64(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+28, 0, 32) + +#define SET_RX_DESC_BUFF_ADDR(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+24, 0, 32, __val) +#define SET_RX_DESC_BUFF_ADDR64(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+28, 0, 32, __val) + +#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); + +struct rx_fwinfo_92c { + 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_92c { + 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:5; + u32 agg_en:1; + u32 bk:1; + u32 rdg_en:1; + 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 rsvd0:2; + u32 bar_retryht:2; + u32 rsvd1:1; + u32 morefrag:1; + u32 raw:1; + u32 ccx:1; + u32 ampdudensity:3; + u32 rsvd2: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 pktid:4; + + u32 rtsrate:5; + u32 apdcfe:1; + u32 qos:1; + u32 hwseq_enable: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 rsvd3: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 mcsg4maxlen:4; + u32 mcsg5maxlen:4; + u32 mcsg6maxlen:4; + u32 mcsg15sgimaxlen:4; + + u32 txbuffaddr; + u32 txbufferaddr64; + u32 nextdescaddress; + u32 nextdescaddress64; + + u32 reserve_pass_pcie_mm_limit[4]; +} __packed; + +struct rx_desc_92c { + 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:5; + 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 rtl92ce_tx_fill_desc(struct ieee80211_hw *hw, + struct ieee80211_hdr *hdr, + u8 *pdesc, struct ieee80211_tx_info *info, + struct sk_buff *skb, u8 hw_queue, + struct rtl_tcb_desc *ptcb_desc); +bool rtl92ce_rx_query_desc(struct ieee80211_hw *hw, + struct rtl_stats *stats, + struct ieee80211_rx_status *rx_status, + u8 *pdesc, struct sk_buff *skb); +void rtl92ce_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val); +u32 rtl92ce_get_desc(u8 *pdesc, bool istx, u8 desc_name); +void rtl92ce_tx_polling(struct ieee80211_hw *hw, u8 hw_queue); +void rtl92ce_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc, + bool b_firstseg, bool b_lastseg, + struct sk_buff *skb); +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/Makefile b/drivers/net/wireless/rtlwifi/rtl8192cu/Makefile new file mode 100644 index 00000000..ad2de6b8 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/Makefile @@ -0,0 +1,14 @@ +rtl8192cu-objs := \ + dm.o \ + hw.o \ + led.o \ + mac.o \ + phy.o \ + rf.o \ + sw.o \ + table.o \ + trx.o + +obj-$(CONFIG_RTL8192CU) += rtl8192cu.o + +ccflags-y += -D__CHECK_ENDIAN__ diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/def.h b/drivers/net/wireless/rtlwifi/rtl8192cu/def.h new file mode 100644 index 00000000..f916555e --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/def.h @@ -0,0 +1,58 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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> + * + *****************************************************************************/ + +#include "../rtl8192ce/def.h" + +/*------------------------------------------------------------------------- + * Chip specific + *-------------------------------------------------------------------------*/ +#define CHIP_8723 BIT(2) /* RTL8723 With BT feature */ +#define CHIP_8723_DRV_REV BIT(3) /* RTL8723 Driver Revised */ +#define NORMAL_CHIP BIT(4) +#define CHIP_VENDOR_UMC BIT(5) +#define CHIP_VENDOR_UMC_B_CUT BIT(6) + +#define IS_NORMAL_CHIP(version) \ + (((version) & NORMAL_CHIP) ? true : false) + +#define IS_8723_SERIES(version) \ + (((version) & CHIP_8723) ? true : false) + +#define IS_92C_1T2R(version) \ + (((version) & CHIP_92C) && ((version) & CHIP_92C_1T2R)) + +#define IS_VENDOR_UMC(version) \ + (((version) & CHIP_VENDOR_UMC) ? true : false) + +#define IS_VENDOR_8723_A_CUT(version) \ + (((version) & CHIP_VENDOR_UMC) ? (((version) & (BIT(6))) ? \ + false : true) : false) + +#define CHIP_BONDING_92C_1T2R 0x1 +#define CHIP_BONDING_IDENTIFIER(_value) (((_value) >> 22) & 0x3) diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/dm.c b/drivers/net/wireless/rtlwifi/rtl8192cu/dm.c new file mode 100644 index 00000000..6fd39eaf --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/dm.c @@ -0,0 +1,113 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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> + * + *****************************************************************************/ + +#include "../wifi.h" +#include "../base.h" +#include "reg.h" +#include "def.h" +#include "phy.h" +#include "dm.h" + +void rtl92cu_dm_dynamic_txpower(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + long undecorated_smoothed_pwdb; + + if (!rtlpriv->dm.dynamic_txpower_enable) + return; + + if (rtlpriv->dm.dm_flag & HAL_DM_HIPWR_DISABLE) { + rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_NORMAL; + return; + } + + if ((mac->link_state < MAC80211_LINKED) && + (rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb == 0)) { + RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE, + "Not connected to any\n"); + + rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_NORMAL; + + rtlpriv->dm.last_dtp_lvl = TXHIGHPWRLEVEL_NORMAL; + return; + } + + if (mac->link_state >= MAC80211_LINKED) { + if (mac->opmode == NL80211_IFTYPE_ADHOC) { + undecorated_smoothed_pwdb = + rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb; + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + "AP Client PWDB = 0x%lx\n", + undecorated_smoothed_pwdb); + } else { + undecorated_smoothed_pwdb = + rtlpriv->dm.undecorated_smoothed_pwdb; + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + "STA Default Port PWDB = 0x%lx\n", + undecorated_smoothed_pwdb); + } + } else { + undecorated_smoothed_pwdb = + rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb; + + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + "AP Ext Port PWDB = 0x%lx\n", + undecorated_smoothed_pwdb); + } + + if (undecorated_smoothed_pwdb >= TX_POWER_NEAR_FIELD_THRESH_LVL2) { + rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_LEVEL1; + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + "TXHIGHPWRLEVEL_LEVEL1 (TxPwr=0x0)\n"); + } else if ((undecorated_smoothed_pwdb < + (TX_POWER_NEAR_FIELD_THRESH_LVL2 - 3)) && + (undecorated_smoothed_pwdb >= + TX_POWER_NEAR_FIELD_THRESH_LVL1)) { + + rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_LEVEL1; + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + "TXHIGHPWRLEVEL_LEVEL1 (TxPwr=0x10)\n"); + } else if (undecorated_smoothed_pwdb < + (TX_POWER_NEAR_FIELD_THRESH_LVL1 - 5)) { + rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_NORMAL; + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + "TXHIGHPWRLEVEL_NORMAL\n"); + } + + if ((rtlpriv->dm.dynamic_txhighpower_lvl != rtlpriv->dm.last_dtp_lvl)) { + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + "PHY_SetTxPowerLevel8192S() Channel = %d\n", + rtlphy->current_channel); + rtl92c_phy_set_txpower_level(hw, rtlphy->current_channel); + } + + rtlpriv->dm.last_dtp_lvl = rtlpriv->dm.dynamic_txhighpower_lvl; +} diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/dm.h b/drivers/net/wireless/rtlwifi/rtl8192cu/dm.h new file mode 100644 index 00000000..d947e7d3 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/dm.h @@ -0,0 +1,32 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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> + * + *****************************************************************************/ + +#include "../rtl8192ce/dm.h" + +void rtl92cu_dm_dynamic_txpower(struct ieee80211_hw *hw); diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c new file mode 100644 index 00000000..0c74d4f2 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c @@ -0,0 +1,2313 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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. + * + * 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> + * + *****************************************************************************/ + +#include "../wifi.h" +#include "../efuse.h" +#include "../base.h" +#include "../cam.h" +#include "../ps.h" +#include "../usb.h" +#include "reg.h" +#include "def.h" +#include "phy.h" +#include "mac.h" +#include "dm.h" +#include "hw.h" +#include "../rtl8192ce/hw.h" +#include "trx.h" +#include "led.h" +#include "table.h" + +static void _rtl92cu_phy_param_tab_init(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_efuse *rtlefuse = rtl_efuse(rtlpriv); + + rtlphy->hwparam_tables[MAC_REG].length = RTL8192CUMAC_2T_ARRAYLENGTH; + rtlphy->hwparam_tables[MAC_REG].pdata = RTL8192CUMAC_2T_ARRAY; + if (IS_HIGHT_PA(rtlefuse->board_type)) { + rtlphy->hwparam_tables[PHY_REG_PG].length = + RTL8192CUPHY_REG_Array_PG_HPLength; + rtlphy->hwparam_tables[PHY_REG_PG].pdata = + RTL8192CUPHY_REG_Array_PG_HP; + } else { + rtlphy->hwparam_tables[PHY_REG_PG].length = + RTL8192CUPHY_REG_ARRAY_PGLENGTH; + rtlphy->hwparam_tables[PHY_REG_PG].pdata = + RTL8192CUPHY_REG_ARRAY_PG; + } + /* 2T */ + rtlphy->hwparam_tables[PHY_REG_2T].length = + RTL8192CUPHY_REG_2TARRAY_LENGTH; + rtlphy->hwparam_tables[PHY_REG_2T].pdata = + RTL8192CUPHY_REG_2TARRAY; + rtlphy->hwparam_tables[RADIOA_2T].length = + RTL8192CURADIOA_2TARRAYLENGTH; + rtlphy->hwparam_tables[RADIOA_2T].pdata = + RTL8192CURADIOA_2TARRAY; + rtlphy->hwparam_tables[RADIOB_2T].length = + RTL8192CURADIOB_2TARRAYLENGTH; + rtlphy->hwparam_tables[RADIOB_2T].pdata = + RTL8192CU_RADIOB_2TARRAY; + rtlphy->hwparam_tables[AGCTAB_2T].length = + RTL8192CUAGCTAB_2TARRAYLENGTH; + rtlphy->hwparam_tables[AGCTAB_2T].pdata = + RTL8192CUAGCTAB_2TARRAY; + /* 1T */ + if (IS_HIGHT_PA(rtlefuse->board_type)) { + rtlphy->hwparam_tables[PHY_REG_1T].length = + RTL8192CUPHY_REG_1T_HPArrayLength; + rtlphy->hwparam_tables[PHY_REG_1T].pdata = + RTL8192CUPHY_REG_1T_HPArray; + rtlphy->hwparam_tables[RADIOA_1T].length = + RTL8192CURadioA_1T_HPArrayLength; + rtlphy->hwparam_tables[RADIOA_1T].pdata = + RTL8192CURadioA_1T_HPArray; + rtlphy->hwparam_tables[RADIOB_1T].length = + RTL8192CURADIOB_1TARRAYLENGTH; + rtlphy->hwparam_tables[RADIOB_1T].pdata = + RTL8192CU_RADIOB_1TARRAY; + rtlphy->hwparam_tables[AGCTAB_1T].length = + RTL8192CUAGCTAB_1T_HPArrayLength; + rtlphy->hwparam_tables[AGCTAB_1T].pdata = + Rtl8192CUAGCTAB_1T_HPArray; + } else { + rtlphy->hwparam_tables[PHY_REG_1T].length = + RTL8192CUPHY_REG_1TARRAY_LENGTH; + rtlphy->hwparam_tables[PHY_REG_1T].pdata = + RTL8192CUPHY_REG_1TARRAY; + rtlphy->hwparam_tables[RADIOA_1T].length = + RTL8192CURADIOA_1TARRAYLENGTH; + rtlphy->hwparam_tables[RADIOA_1T].pdata = + RTL8192CU_RADIOA_1TARRAY; + rtlphy->hwparam_tables[RADIOB_1T].length = + RTL8192CURADIOB_1TARRAYLENGTH; + rtlphy->hwparam_tables[RADIOB_1T].pdata = + RTL8192CU_RADIOB_1TARRAY; + rtlphy->hwparam_tables[AGCTAB_1T].length = + RTL8192CUAGCTAB_1TARRAYLENGTH; + rtlphy->hwparam_tables[AGCTAB_1T].pdata = + RTL8192CUAGCTAB_1TARRAY; + } +} + +static void _rtl92cu_read_txpower_info_from_hwpg(struct ieee80211_hw *hw, + bool autoload_fail, + u8 *hwinfo) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + u8 rf_path, index, tempval; + u16 i; + + for (rf_path = 0; rf_path < 2; rf_path++) { + for (i = 0; i < 3; i++) { + if (!autoload_fail) { + rtlefuse-> + eeprom_chnlarea_txpwr_cck[rf_path][i] = + hwinfo[EEPROM_TXPOWERCCK + rf_path * 3 + i]; + rtlefuse-> + eeprom_chnlarea_txpwr_ht40_1s[rf_path][i] = + hwinfo[EEPROM_TXPOWERHT40_1S + rf_path * 3 + + i]; + } else { + rtlefuse-> + eeprom_chnlarea_txpwr_cck[rf_path][i] = + EEPROM_DEFAULT_TXPOWERLEVEL; + rtlefuse-> + eeprom_chnlarea_txpwr_ht40_1s[rf_path][i] = + EEPROM_DEFAULT_TXPOWERLEVEL; + } + } + } + for (i = 0; i < 3; i++) { + if (!autoload_fail) + tempval = hwinfo[EEPROM_TXPOWERHT40_2SDIFF + i]; + else + tempval = EEPROM_DEFAULT_HT40_2SDIFF; + rtlefuse->eeprom_chnlarea_txpwr_ht40_2sdiif[RF90_PATH_A][i] = + (tempval & 0xf); + rtlefuse->eeprom_chnlarea_txpwr_ht40_2sdiif[RF90_PATH_B][i] = + ((tempval & 0xf0) >> 4); + } + for (rf_path = 0; rf_path < 2; rf_path++) + for (i = 0; i < 3; i++) + RTPRINT(rtlpriv, FINIT, INIT_EEPROM, + "RF(%d) EEPROM CCK Area(%d) = 0x%x\n", + rf_path, i, + rtlefuse-> + eeprom_chnlarea_txpwr_cck[rf_path][i]); + for (rf_path = 0; rf_path < 2; rf_path++) + for (i = 0; i < 3; i++) + RTPRINT(rtlpriv, FINIT, INIT_EEPROM, + "RF(%d) EEPROM HT40 1S Area(%d) = 0x%x\n", + rf_path, i, + rtlefuse-> + eeprom_chnlarea_txpwr_ht40_1s[rf_path][i]); + for (rf_path = 0; rf_path < 2; rf_path++) + for (i = 0; i < 3; i++) + RTPRINT(rtlpriv, FINIT, INIT_EEPROM, + "RF(%d) EEPROM HT40 2S Diff Area(%d) = 0x%x\n", + rf_path, i, + rtlefuse-> + eeprom_chnlarea_txpwr_ht40_2sdiif[rf_path][i]); + for (rf_path = 0; rf_path < 2; rf_path++) { + for (i = 0; i < 14; i++) { + index = _rtl92c_get_chnl_group((u8) i); + rtlefuse->txpwrlevel_cck[rf_path][i] = + rtlefuse->eeprom_chnlarea_txpwr_cck[rf_path][index]; + rtlefuse->txpwrlevel_ht40_1s[rf_path][i] = + rtlefuse-> + eeprom_chnlarea_txpwr_ht40_1s[rf_path][index]; + if ((rtlefuse-> + eeprom_chnlarea_txpwr_ht40_1s[rf_path][index] - + rtlefuse-> + eeprom_chnlarea_txpwr_ht40_2sdiif[rf_path][index]) + > 0) { + rtlefuse->txpwrlevel_ht40_2s[rf_path][i] = + rtlefuse-> + eeprom_chnlarea_txpwr_ht40_1s[rf_path] + [index] - rtlefuse-> + eeprom_chnlarea_txpwr_ht40_2sdiif[rf_path] + [index]; + } else { + rtlefuse->txpwrlevel_ht40_2s[rf_path][i] = 0; + } + } + for (i = 0; i < 14; i++) { + RTPRINT(rtlpriv, FINIT, INIT_TxPower, + "RF(%d)-Ch(%d) [CCK / HT40_1S / HT40_2S] = [0x%x / 0x%x / 0x%x]\n", rf_path, i, + rtlefuse->txpwrlevel_cck[rf_path][i], + rtlefuse->txpwrlevel_ht40_1s[rf_path][i], + rtlefuse->txpwrlevel_ht40_2s[rf_path][i]); + } + } + for (i = 0; i < 3; i++) { + if (!autoload_fail) { + rtlefuse->eeprom_pwrlimit_ht40[i] = + hwinfo[EEPROM_TXPWR_GROUP + i]; + rtlefuse->eeprom_pwrlimit_ht20[i] = + hwinfo[EEPROM_TXPWR_GROUP + 3 + i]; + } else { + rtlefuse->eeprom_pwrlimit_ht40[i] = 0; + rtlefuse->eeprom_pwrlimit_ht20[i] = 0; + } + } + for (rf_path = 0; rf_path < 2; rf_path++) { + for (i = 0; i < 14; i++) { + index = _rtl92c_get_chnl_group((u8) i); + if (rf_path == RF90_PATH_A) { + rtlefuse->pwrgroup_ht20[rf_path][i] = + (rtlefuse->eeprom_pwrlimit_ht20[index] + & 0xf); + rtlefuse->pwrgroup_ht40[rf_path][i] = + (rtlefuse->eeprom_pwrlimit_ht40[index] + & 0xf); + } else if (rf_path == RF90_PATH_B) { + rtlefuse->pwrgroup_ht20[rf_path][i] = + ((rtlefuse->eeprom_pwrlimit_ht20[index] + & 0xf0) >> 4); + rtlefuse->pwrgroup_ht40[rf_path][i] = + ((rtlefuse->eeprom_pwrlimit_ht40[index] + & 0xf0) >> 4); + } + RTPRINT(rtlpriv, FINIT, INIT_TxPower, + "RF-%d pwrgroup_ht20[%d] = 0x%x\n", + rf_path, i, + rtlefuse->pwrgroup_ht20[rf_path][i]); + RTPRINT(rtlpriv, FINIT, INIT_TxPower, + "RF-%d pwrgroup_ht40[%d] = 0x%x\n", + rf_path, i, + rtlefuse->pwrgroup_ht40[rf_path][i]); + } + } + for (i = 0; i < 14; i++) { + index = _rtl92c_get_chnl_group((u8) i); + if (!autoload_fail) + tempval = hwinfo[EEPROM_TXPOWERHT20DIFF + index]; + else + tempval = EEPROM_DEFAULT_HT20_DIFF; + rtlefuse->txpwr_ht20diff[RF90_PATH_A][i] = (tempval & 0xF); + rtlefuse->txpwr_ht20diff[RF90_PATH_B][i] = + ((tempval >> 4) & 0xF); + if (rtlefuse->txpwr_ht20diff[RF90_PATH_A][i] & BIT(3)) + rtlefuse->txpwr_ht20diff[RF90_PATH_A][i] |= 0xF0; + if (rtlefuse->txpwr_ht20diff[RF90_PATH_B][i] & BIT(3)) + rtlefuse->txpwr_ht20diff[RF90_PATH_B][i] |= 0xF0; + index = _rtl92c_get_chnl_group((u8) i); + if (!autoload_fail) + tempval = hwinfo[EEPROM_TXPOWER_OFDMDIFF + index]; + else + tempval = EEPROM_DEFAULT_LEGACYHTTXPOWERDIFF; + rtlefuse->txpwr_legacyhtdiff[RF90_PATH_A][i] = (tempval & 0xF); + rtlefuse->txpwr_legacyhtdiff[RF90_PATH_B][i] = + ((tempval >> 4) & 0xF); + } + rtlefuse->legacy_ht_txpowerdiff = + rtlefuse->txpwr_legacyhtdiff[RF90_PATH_A][7]; + for (i = 0; i < 14; i++) + RTPRINT(rtlpriv, FINIT, INIT_TxPower, + "RF-A Ht20 to HT40 Diff[%d] = 0x%x\n", + i, rtlefuse->txpwr_ht20diff[RF90_PATH_A][i]); + for (i = 0; i < 14; i++) + RTPRINT(rtlpriv, FINIT, INIT_TxPower, + "RF-A Legacy to Ht40 Diff[%d] = 0x%x\n", + i, rtlefuse->txpwr_legacyhtdiff[RF90_PATH_A][i]); + for (i = 0; i < 14; i++) + RTPRINT(rtlpriv, FINIT, INIT_TxPower, + "RF-B Ht20 to HT40 Diff[%d] = 0x%x\n", + i, rtlefuse->txpwr_ht20diff[RF90_PATH_B][i]); + for (i = 0; i < 14; i++) + RTPRINT(rtlpriv, FINIT, INIT_TxPower, + "RF-B Legacy to HT40 Diff[%d] = 0x%x\n", + i, rtlefuse->txpwr_legacyhtdiff[RF90_PATH_B][i]); + if (!autoload_fail) + rtlefuse->eeprom_regulatory = (hwinfo[RF_OPTION1] & 0x7); + else + rtlefuse->eeprom_regulatory = 0; + RTPRINT(rtlpriv, FINIT, INIT_TxPower, + "eeprom_regulatory = 0x%x\n", rtlefuse->eeprom_regulatory); + if (!autoload_fail) { + rtlefuse->eeprom_tssi[RF90_PATH_A] = hwinfo[EEPROM_TSSI_A]; + rtlefuse->eeprom_tssi[RF90_PATH_B] = hwinfo[EEPROM_TSSI_B]; + } else { + rtlefuse->eeprom_tssi[RF90_PATH_A] = EEPROM_DEFAULT_TSSI; + rtlefuse->eeprom_tssi[RF90_PATH_B] = EEPROM_DEFAULT_TSSI; + } + RTPRINT(rtlpriv, FINIT, INIT_TxPower, + "TSSI_A = 0x%x, TSSI_B = 0x%x\n", + rtlefuse->eeprom_tssi[RF90_PATH_A], + rtlefuse->eeprom_tssi[RF90_PATH_B]); + if (!autoload_fail) + tempval = hwinfo[EEPROM_THERMAL_METER]; + else + tempval = EEPROM_DEFAULT_THERMALMETER; + rtlefuse->eeprom_thermalmeter = (tempval & 0x1f); + if (rtlefuse->eeprom_thermalmeter < 0x06 || + rtlefuse->eeprom_thermalmeter > 0x1c) + rtlefuse->eeprom_thermalmeter = 0x12; + if (rtlefuse->eeprom_thermalmeter == 0x1f || autoload_fail) + rtlefuse->apk_thermalmeterignore = true; + rtlefuse->thermalmeter[0] = rtlefuse->eeprom_thermalmeter; + RTPRINT(rtlpriv, FINIT, INIT_TxPower, + "thermalmeter = 0x%x\n", rtlefuse->eeprom_thermalmeter); +} + +static void _rtl92cu_read_board_type(struct ieee80211_hw *hw, u8 *contents) +{ + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u8 boardType; + + if (IS_NORMAL_CHIP(rtlhal->version)) { + boardType = ((contents[EEPROM_RF_OPT1]) & + BOARD_TYPE_NORMAL_MASK) >> 5; /*bit[7:5]*/ + } else { + boardType = contents[EEPROM_RF_OPT4]; + boardType &= BOARD_TYPE_TEST_MASK; + } + rtlefuse->board_type = boardType; + if (IS_HIGHT_PA(rtlefuse->board_type)) + rtlefuse->external_pa = 1; + pr_info("Board Type %x\n", rtlefuse->board_type); +} + +static void _rtl92cu_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] = {0}; + u16 eeprom_id; + + if (rtlefuse->epromtype == EEPROM_BOOT_EFUSE) { + rtl_efuse_shadow_map_update(hw); + memcpy((void *)hwinfo, + (void *)&rtlefuse->efuse_map[EFUSE_INIT_MAP][0], + HWSET_MAX_SIZE); + } else if (rtlefuse->epromtype == EEPROM_93C46) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "RTL819X Not boot from eeprom, check it !!\n"); + } + RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_LOUD, "MAP", + hwinfo, HWSET_MAX_SIZE); + eeprom_id = le16_to_cpu(*((__le16 *)&hwinfo[0])); + if (eeprom_id != RTL8190_EEPROM_ID) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "EEPROM ID(%#x) is invalid!!\n", eeprom_id); + rtlefuse->autoload_failflag = true; + } else { + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "Autoload OK\n"); + rtlefuse->autoload_failflag = false; + } + if (rtlefuse->autoload_failflag) + return; + for (i = 0; i < 6; i += 2) { + usvalue = *(u16 *)&hwinfo[EEPROM_MAC_ADDR + i]; + *((u16 *) (&rtlefuse->dev_addr[i])) = usvalue; + } + pr_info("MAC address: %pM\n", rtlefuse->dev_addr); + _rtl92cu_read_txpower_info_from_hwpg(hw, + rtlefuse->autoload_failflag, hwinfo); + rtlefuse->eeprom_vid = le16_to_cpu(*(__le16 *)&hwinfo[EEPROM_VID]); + rtlefuse->eeprom_did = le16_to_cpu(*(__le16 *)&hwinfo[EEPROM_DID]); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, " VID = 0x%02x PID = 0x%02x\n", + rtlefuse->eeprom_vid, rtlefuse->eeprom_did); + rtlefuse->eeprom_channelplan = *(u8 *)&hwinfo[EEPROM_CHANNELPLAN]; + rtlefuse->eeprom_version = + le16_to_cpu(*(__le16 *)&hwinfo[EEPROM_VERSION]); + rtlefuse->txpwr_fromeprom = true; + rtlefuse->eeprom_oemid = *(u8 *)&hwinfo[EEPROM_CUSTOMER_ID]; + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "EEPROM Customer ID: 0x%2x\n", + rtlefuse->eeprom_oemid); + if (rtlhal->oem_id == RT_CID_DEFAULT) { + switch (rtlefuse->eeprom_oemid) { + case EEPROM_CID_DEFAULT: + if (rtlefuse->eeprom_did == 0x8176) { + if ((rtlefuse->eeprom_svid == 0x103C && + rtlefuse->eeprom_smid == 0x1629)) + rtlhal->oem_id = RT_CID_819x_HP; + else + rtlhal->oem_id = RT_CID_DEFAULT; + } else { + rtlhal->oem_id = RT_CID_DEFAULT; + } + break; + case EEPROM_CID_TOSHIBA: + rtlhal->oem_id = RT_CID_TOSHIBA; + break; + case EEPROM_CID_QMI: + rtlhal->oem_id = RT_CID_819x_QMI; + break; + case EEPROM_CID_WHQL: + default: + rtlhal->oem_id = RT_CID_DEFAULT; + break; + } + } + _rtl92cu_read_board_type(hw, hwinfo); +} + +static void _rtl92cu_hal_customized_behavior(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_usb_priv *usb_priv = rtl_usbpriv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + + switch (rtlhal->oem_id) { + case RT_CID_819x_HP: + usb_priv->ledctl.led_opendrain = true; + break; + case RT_CID_819x_Lenovo: + case RT_CID_DEFAULT: + case RT_CID_TOSHIBA: + case RT_CID_CCX: + case RT_CID_819x_Acer: + case RT_CID_WHQL: + default: + break; + } + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "RT Customized ID: 0x%02X\n", + rtlhal->oem_id); +} + +void rtl92cu_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_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u8 tmp_u1b; + + if (!IS_NORMAL_CHIP(rtlhal->version)) + return; + tmp_u1b = rtl_read_byte(rtlpriv, REG_9346CR); + rtlefuse->epromtype = (tmp_u1b & BOOT_FROM_EEPROM) ? + EEPROM_93C46 : EEPROM_BOOT_EFUSE; + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "Boot from %s\n", + tmp_u1b & BOOT_FROM_EEPROM ? "EERROM" : "EFUSE"); + rtlefuse->autoload_failflag = (tmp_u1b & EEPROM_EN) ? false : true; + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "Autoload %s\n", + tmp_u1b & EEPROM_EN ? "OK!!" : "ERR!!"); + _rtl92cu_read_adapter_info(hw); + _rtl92cu_hal_customized_behavior(hw); + return; +} + +static int _rtl92cu_init_power_on(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + int status = 0; + u16 value16; + u8 value8; + /* polling autoload done. */ + u32 pollingCount = 0; + + do { + if (rtl_read_byte(rtlpriv, REG_APS_FSMCO) & PFM_ALDN) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "Autoload Done!\n"); + break; + } + if (pollingCount++ > 100) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG, + "Failed to polling REG_APS_FSMCO[PFM_ALDN] done!\n"); + return -ENODEV; + } + } while (true); + /* 0. RSV_CTRL 0x1C[7:0] = 0 unlock ISO/CLK/Power control register */ + rtl_write_byte(rtlpriv, REG_RSV_CTRL, 0x0); + /* Power on when re-enter from IPS/Radio off/card disable */ + /* enable SPS into PWM mode */ + rtl_write_byte(rtlpriv, REG_SPS0_CTRL, 0x2b); + udelay(100); + value8 = rtl_read_byte(rtlpriv, REG_LDOV12D_CTRL); + if (0 == (value8 & LDV12_EN)) { + value8 |= LDV12_EN; + rtl_write_byte(rtlpriv, REG_LDOV12D_CTRL, value8); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + " power-on :REG_LDOV12D_CTRL Reg0x21:0x%02x\n", + value8); + udelay(100); + value8 = rtl_read_byte(rtlpriv, REG_SYS_ISO_CTRL); + value8 &= ~ISO_MD2PP; + rtl_write_byte(rtlpriv, REG_SYS_ISO_CTRL, value8); + } + /* auto enable WLAN */ + pollingCount = 0; + value16 = rtl_read_word(rtlpriv, REG_APS_FSMCO); + value16 |= APFM_ONMAC; + rtl_write_word(rtlpriv, REG_APS_FSMCO, value16); + do { + if (!(rtl_read_word(rtlpriv, REG_APS_FSMCO) & APFM_ONMAC)) { + pr_info("MAC auto ON okay!\n"); + break; + } + if (pollingCount++ > 100) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG, + "Failed to polling REG_APS_FSMCO[APFM_ONMAC] done!\n"); + return -ENODEV; + } + } while (true); + /* Enable Radio ,GPIO ,and LED function */ + rtl_write_word(rtlpriv, REG_APS_FSMCO, 0x0812); + /* release RF digital isolation */ + value16 = rtl_read_word(rtlpriv, REG_SYS_ISO_CTRL); + value16 &= ~ISO_DIOR; + rtl_write_word(rtlpriv, REG_SYS_ISO_CTRL, value16); + /* Reconsider when to do this operation after asking HWSD. */ + pollingCount = 0; + rtl_write_byte(rtlpriv, REG_APSD_CTRL, (rtl_read_byte(rtlpriv, + REG_APSD_CTRL) & ~BIT(6))); + do { + pollingCount++; + } while ((pollingCount < 200) && + (rtl_read_byte(rtlpriv, REG_APSD_CTRL) & BIT(7))); + /* Enable MAC DMA/WMAC/SCHEDULE/SEC block */ + value16 = rtl_read_word(rtlpriv, REG_CR); + value16 |= (HCI_TXDMA_EN | HCI_RXDMA_EN | TXDMA_EN | RXDMA_EN | + PROTOCOL_EN | SCHEDULE_EN | MACTXEN | MACRXEN | ENSEC); + rtl_write_word(rtlpriv, REG_CR, value16); + return status; +} + +static void _rtl92cu_init_queue_reserved_page(struct ieee80211_hw *hw, + bool wmm_enable, + u8 out_ep_num, + u8 queue_sel) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + bool isChipN = IS_NORMAL_CHIP(rtlhal->version); + u32 outEPNum = (u32)out_ep_num; + u32 numHQ = 0; + u32 numLQ = 0; + u32 numNQ = 0; + u32 numPubQ; + u32 value32; + u8 value8; + u32 txQPageNum, txQPageUnit, txQRemainPage; + + if (!wmm_enable) { + numPubQ = (isChipN) ? CHIP_B_PAGE_NUM_PUBQ : + CHIP_A_PAGE_NUM_PUBQ; + txQPageNum = TX_TOTAL_PAGE_NUMBER - numPubQ; + + txQPageUnit = txQPageNum/outEPNum; + txQRemainPage = txQPageNum % outEPNum; + if (queue_sel & TX_SELE_HQ) + numHQ = txQPageUnit; + if (queue_sel & TX_SELE_LQ) + numLQ = txQPageUnit; + /* HIGH priority queue always present in the configuration of + * 2 out-ep. Remainder pages have assigned to High queue */ + if ((outEPNum > 1) && (txQRemainPage)) + numHQ += txQRemainPage; + /* NOTE: This step done before writting REG_RQPN. */ + if (isChipN) { + if (queue_sel & TX_SELE_NQ) + numNQ = txQPageUnit; + value8 = (u8)_NPQ(numNQ); + rtl_write_byte(rtlpriv, REG_RQPN_NPQ, value8); + } + } else { + /* for WMM ,number of out-ep must more than or equal to 2! */ + numPubQ = isChipN ? WMM_CHIP_B_PAGE_NUM_PUBQ : + WMM_CHIP_A_PAGE_NUM_PUBQ; + if (queue_sel & TX_SELE_HQ) { + numHQ = isChipN ? WMM_CHIP_B_PAGE_NUM_HPQ : + WMM_CHIP_A_PAGE_NUM_HPQ; + } + if (queue_sel & TX_SELE_LQ) { + numLQ = isChipN ? WMM_CHIP_B_PAGE_NUM_LPQ : + WMM_CHIP_A_PAGE_NUM_LPQ; + } + /* NOTE: This step done before writting REG_RQPN. */ + if (isChipN) { + if (queue_sel & TX_SELE_NQ) + numNQ = WMM_CHIP_B_PAGE_NUM_NPQ; + value8 = (u8)_NPQ(numNQ); + rtl_write_byte(rtlpriv, REG_RQPN_NPQ, value8); + } + } + /* TX DMA */ + value32 = _HPQ(numHQ) | _LPQ(numLQ) | _PUBQ(numPubQ) | LD_RQPN; + rtl_write_dword(rtlpriv, REG_RQPN, value32); +} + +static void _rtl92c_init_trx_buffer(struct ieee80211_hw *hw, bool wmm_enable) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u8 txpktbuf_bndy; + u8 value8; + + if (!wmm_enable) + txpktbuf_bndy = TX_PAGE_BOUNDARY; + else /* for WMM */ + txpktbuf_bndy = (IS_NORMAL_CHIP(rtlhal->version)) + ? WMM_CHIP_B_TX_PAGE_BOUNDARY + : WMM_CHIP_A_TX_PAGE_BOUNDARY; + rtl_write_byte(rtlpriv, REG_TXPKTBUF_BCNQ_BDNY, txpktbuf_bndy); + rtl_write_byte(rtlpriv, REG_TXPKTBUF_MGQ_BDNY, txpktbuf_bndy); + rtl_write_byte(rtlpriv, REG_TXPKTBUF_WMAC_LBK_BF_HD, txpktbuf_bndy); + rtl_write_byte(rtlpriv, REG_TRXFF_BNDY, txpktbuf_bndy); + rtl_write_byte(rtlpriv, REG_TDECTRL+1, txpktbuf_bndy); + rtl_write_word(rtlpriv, (REG_TRXFF_BNDY + 2), 0x27FF); + value8 = _PSRX(RX_PAGE_SIZE_REG_VALUE) | _PSTX(PBP_128); + rtl_write_byte(rtlpriv, REG_PBP, value8); +} + +static void _rtl92c_init_chipN_reg_priority(struct ieee80211_hw *hw, u16 beQ, + u16 bkQ, u16 viQ, u16 voQ, + u16 mgtQ, u16 hiQ) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u16 value16 = (rtl_read_word(rtlpriv, REG_TRXDMA_CTRL) & 0x7); + + value16 |= _TXDMA_BEQ_MAP(beQ) | _TXDMA_BKQ_MAP(bkQ) | + _TXDMA_VIQ_MAP(viQ) | _TXDMA_VOQ_MAP(voQ) | + _TXDMA_MGQ_MAP(mgtQ) | _TXDMA_HIQ_MAP(hiQ); + rtl_write_word(rtlpriv, REG_TRXDMA_CTRL, value16); +} + +static void _rtl92cu_init_chipN_one_out_ep_priority(struct ieee80211_hw *hw, + bool wmm_enable, + u8 queue_sel) +{ + u16 uninitialized_var(value); + + switch (queue_sel) { + case TX_SELE_HQ: + value = QUEUE_HIGH; + break; + case TX_SELE_LQ: + value = QUEUE_LOW; + break; + case TX_SELE_NQ: + value = QUEUE_NORMAL; + break; + default: + WARN_ON(1); /* Shall not reach here! */ + break; + } + _rtl92c_init_chipN_reg_priority(hw, value, value, value, value, + value, value); + pr_info("Tx queue select: 0x%02x\n", queue_sel); +} + +static void _rtl92cu_init_chipN_two_out_ep_priority(struct ieee80211_hw *hw, + bool wmm_enable, + u8 queue_sel) +{ + u16 beQ, bkQ, viQ, voQ, mgtQ, hiQ; + u16 uninitialized_var(valueHi); + u16 uninitialized_var(valueLow); + + switch (queue_sel) { + case (TX_SELE_HQ | TX_SELE_LQ): + valueHi = QUEUE_HIGH; + valueLow = QUEUE_LOW; + break; + case (TX_SELE_NQ | TX_SELE_LQ): + valueHi = QUEUE_NORMAL; + valueLow = QUEUE_LOW; + break; + case (TX_SELE_HQ | TX_SELE_NQ): + valueHi = QUEUE_HIGH; + valueLow = QUEUE_NORMAL; + break; + default: + WARN_ON(1); + break; + } + if (!wmm_enable) { + beQ = valueLow; + bkQ = valueLow; + viQ = valueHi; + voQ = valueHi; + mgtQ = valueHi; + hiQ = valueHi; + } else {/* for WMM ,CONFIG_OUT_EP_WIFI_MODE */ + beQ = valueHi; + bkQ = valueLow; + viQ = valueLow; + voQ = valueHi; + mgtQ = valueHi; + hiQ = valueHi; + } + _rtl92c_init_chipN_reg_priority(hw, beQ, bkQ, viQ, voQ, mgtQ, hiQ); + pr_info("Tx queue select: 0x%02x\n", queue_sel); +} + +static void _rtl92cu_init_chipN_three_out_ep_priority(struct ieee80211_hw *hw, + bool wmm_enable, + u8 queue_sel) +{ + u16 beQ, bkQ, viQ, voQ, mgtQ, hiQ; + struct rtl_priv *rtlpriv = rtl_priv(hw); + + if (!wmm_enable) { /* typical setting */ + beQ = QUEUE_LOW; + bkQ = QUEUE_LOW; + viQ = QUEUE_NORMAL; + voQ = QUEUE_HIGH; + mgtQ = QUEUE_HIGH; + hiQ = QUEUE_HIGH; + } else { /* for WMM */ + beQ = QUEUE_LOW; + bkQ = QUEUE_NORMAL; + viQ = QUEUE_NORMAL; + voQ = QUEUE_HIGH; + mgtQ = QUEUE_HIGH; + hiQ = QUEUE_HIGH; + } + _rtl92c_init_chipN_reg_priority(hw, beQ, bkQ, viQ, voQ, mgtQ, hiQ); + RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG, "Tx queue select :0x%02x..\n", + queue_sel); +} + +static void _rtl92cu_init_chipN_queue_priority(struct ieee80211_hw *hw, + bool wmm_enable, + u8 out_ep_num, + u8 queue_sel) +{ + switch (out_ep_num) { + case 1: + _rtl92cu_init_chipN_one_out_ep_priority(hw, wmm_enable, + queue_sel); + break; + case 2: + _rtl92cu_init_chipN_two_out_ep_priority(hw, wmm_enable, + queue_sel); + break; + case 3: + _rtl92cu_init_chipN_three_out_ep_priority(hw, wmm_enable, + queue_sel); + break; + default: + WARN_ON(1); /* Shall not reach here! */ + break; + } +} + +static void _rtl92cu_init_chipT_queue_priority(struct ieee80211_hw *hw, + bool wmm_enable, + u8 out_ep_num, + u8 queue_sel) +{ + u8 hq_sele = 0; + struct rtl_priv *rtlpriv = rtl_priv(hw); + + switch (out_ep_num) { + case 2: /* (TX_SELE_HQ|TX_SELE_LQ) */ + if (!wmm_enable) /* typical setting */ + hq_sele = HQSEL_VOQ | HQSEL_VIQ | HQSEL_MGTQ | + HQSEL_HIQ; + else /* for WMM */ + hq_sele = HQSEL_VOQ | HQSEL_BEQ | HQSEL_MGTQ | + HQSEL_HIQ; + break; + case 1: + if (TX_SELE_LQ == queue_sel) { + /* map all endpoint to Low queue */ + hq_sele = 0; + } else if (TX_SELE_HQ == queue_sel) { + /* map all endpoint to High queue */ + hq_sele = HQSEL_VOQ | HQSEL_VIQ | HQSEL_BEQ | + HQSEL_BKQ | HQSEL_MGTQ | HQSEL_HIQ; + } + break; + default: + WARN_ON(1); /* Shall not reach here! */ + break; + } + rtl_write_byte(rtlpriv, (REG_TRXDMA_CTRL+1), hq_sele); + RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG, "Tx queue select :0x%02x..\n", + hq_sele); +} + +static void _rtl92cu_init_queue_priority(struct ieee80211_hw *hw, + bool wmm_enable, + u8 out_ep_num, + u8 queue_sel) +{ + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + if (IS_NORMAL_CHIP(rtlhal->version)) + _rtl92cu_init_chipN_queue_priority(hw, wmm_enable, out_ep_num, + queue_sel); + else + _rtl92cu_init_chipT_queue_priority(hw, wmm_enable, out_ep_num, + queue_sel); +} + +static void _rtl92cu_init_usb_aggregation(struct ieee80211_hw *hw) +{ +} + +static void _rtl92cu_init_wmac_setting(struct ieee80211_hw *hw) +{ + u16 value16; + + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + + mac->rx_conf = (RCR_APM | RCR_AM | RCR_ADF | RCR_AB | RCR_APPFCS | + RCR_APP_ICV | RCR_AMF | RCR_HTC_LOC_CTRL | + RCR_APP_MIC | RCR_APP_PHYSTS | RCR_ACRC32); + rtl_write_dword(rtlpriv, REG_RCR, mac->rx_conf); + /* Accept all multicast address */ + rtl_write_dword(rtlpriv, REG_MAR, 0xFFFFFFFF); + rtl_write_dword(rtlpriv, REG_MAR + 4, 0xFFFFFFFF); + /* Accept all management frames */ + value16 = 0xFFFF; + rtl92c_set_mgt_filter(hw, value16); + /* Reject all control frame - default value is 0 */ + rtl92c_set_ctrl_filter(hw, 0x0); + /* Accept all data frames */ + value16 = 0xFFFF; + rtl92c_set_data_filter(hw, value16); +} + +static int _rtl92cu_init_mac(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_usb_priv *usb_priv = rtl_usbpriv(hw); + struct rtl_usb *rtlusb = rtl_usbdev(usb_priv); + int err = 0; + u32 boundary = 0; + u8 wmm_enable = false; /* TODO */ + u8 out_ep_nums = rtlusb->out_ep_nums; + u8 queue_sel = rtlusb->out_queue_sel; + err = _rtl92cu_init_power_on(hw); + + if (err) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "Failed to init power on!\n"); + return err; + } + if (!wmm_enable) { + boundary = TX_PAGE_BOUNDARY; + } else { /* for WMM */ + boundary = (IS_NORMAL_CHIP(rtlhal->version)) + ? WMM_CHIP_B_TX_PAGE_BOUNDARY + : WMM_CHIP_A_TX_PAGE_BOUNDARY; + } + if (false == rtl92c_init_llt_table(hw, boundary)) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "Failed to init LLT Table!\n"); + return -EINVAL; + } + _rtl92cu_init_queue_reserved_page(hw, wmm_enable, out_ep_nums, + queue_sel); + _rtl92c_init_trx_buffer(hw, wmm_enable); + _rtl92cu_init_queue_priority(hw, wmm_enable, out_ep_nums, + queue_sel); + /* Get Rx PHY status in order to report RSSI and others. */ + rtl92c_init_driver_info_size(hw, RTL92C_DRIVER_INFO_SIZE); + rtl92c_init_interrupt(hw); + rtl92c_init_network_type(hw); + _rtl92cu_init_wmac_setting(hw); + rtl92c_init_adaptive_ctrl(hw); + rtl92c_init_edca(hw); + rtl92c_init_rate_fallback(hw); + rtl92c_init_retry_function(hw); + _rtl92cu_init_usb_aggregation(hw); + rtlpriv->cfg->ops->set_bw_mode(hw, NL80211_CHAN_HT20); + rtl92c_set_min_space(hw, IS_92C_SERIAL(rtlhal->version)); + rtl92c_init_beacon_parameters(hw, rtlhal->version); + rtl92c_init_ampdu_aggregation(hw); + rtl92c_init_beacon_max_error(hw, true); + return err; +} + +void rtl92cu_enable_hw_security_config(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 sec_reg_value = 0x0; + struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "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(rtlpriv, COMP_SEC, DBG_DMESG, + "not open sw 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; + } + if (IS_NORMAL_CHIP(rtlhal->version)) + sec_reg_value |= (SCR_RXBCUSEDK | SCR_TXBCUSEDK); + rtl_write_byte(rtlpriv, REG_CR + 1, 0x02); + RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, "The SECR-value %x\n", + sec_reg_value); + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_WPA_CONFIG, &sec_reg_value); +} + +static void _rtl92cu_hw_configure(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw)); + + /* To Fix MAC loopback mode fail. */ + rtl_write_byte(rtlpriv, REG_LDOHCI12_CTRL, 0x0f); + rtl_write_byte(rtlpriv, 0x15, 0xe9); + /* HW SEQ CTRL */ + /* set 0x0 to 0xFF by tynli. Default enable HW SEQ NUM. */ + rtl_write_byte(rtlpriv, REG_HWSEQ_CTRL, 0xFF); + /* fixed USB interface interference issue */ + rtl_write_byte(rtlpriv, 0xfe40, 0xe0); + rtl_write_byte(rtlpriv, 0xfe41, 0x8d); + rtl_write_byte(rtlpriv, 0xfe42, 0x80); + rtlusb->reg_bcn_ctrl_val = 0x18; + rtl_write_byte(rtlpriv, REG_BCN_CTRL, (u8)rtlusb->reg_bcn_ctrl_val); +} + +static void _InitPABias(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u8 pa_setting; + + /* FIXED PA current issue */ + pa_setting = efuse_read_1byte(hw, 0x1FA); + if (!(pa_setting & BIT(0))) { + rtl_set_rfreg(hw, RF90_PATH_A, 0x15, 0x0FFFFF, 0x0F406); + rtl_set_rfreg(hw, RF90_PATH_A, 0x15, 0x0FFFFF, 0x4F406); + rtl_set_rfreg(hw, RF90_PATH_A, 0x15, 0x0FFFFF, 0x8F406); + rtl_set_rfreg(hw, RF90_PATH_A, 0x15, 0x0FFFFF, 0xCF406); + } + if (!(pa_setting & BIT(1)) && IS_NORMAL_CHIP(rtlhal->version) && + IS_92C_SERIAL(rtlhal->version)) { + rtl_set_rfreg(hw, RF90_PATH_B, 0x15, 0x0FFFFF, 0x0F406); + rtl_set_rfreg(hw, RF90_PATH_B, 0x15, 0x0FFFFF, 0x4F406); + rtl_set_rfreg(hw, RF90_PATH_B, 0x15, 0x0FFFFF, 0x8F406); + rtl_set_rfreg(hw, RF90_PATH_B, 0x15, 0x0FFFFF, 0xCF406); + } + if (!(pa_setting & BIT(4))) { + pa_setting = rtl_read_byte(rtlpriv, 0x16); + pa_setting &= 0x0F; + rtl_write_byte(rtlpriv, 0x16, pa_setting | 0x90); + } +} + +static void _update_mac_setting(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + + mac->rx_conf = rtl_read_dword(rtlpriv, REG_RCR); + mac->rx_mgt_filter = rtl_read_word(rtlpriv, REG_RXFLTMAP0); + mac->rx_ctrl_filter = rtl_read_word(rtlpriv, REG_RXFLTMAP1); + mac->rx_data_filter = rtl_read_word(rtlpriv, REG_RXFLTMAP2); +} + +int rtl92cu_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)); + int err = 0; + static bool iqk_initialized; + + rtlhal->hw_type = HARDWARE_TYPE_RTL8192CU; + err = _rtl92cu_init_mac(hw); + if (err) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "init mac failed!\n"); + return err; + } + err = rtl92c_download_fw(hw); + if (err) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, + "Failed to download FW. Init HW without FW now..\n"); + err = 1; + return err; + } + rtlhal->last_hmeboxnum = 0; /* h2c */ + _rtl92cu_phy_param_tab_init(hw); + rtl92cu_phy_mac_config(hw); + rtl92cu_phy_bb_config(hw); + rtlphy->rf_mode = RF_OP_BY_SW_3WIRE; + rtl92c_phy_rf_config(hw); + if (IS_VENDOR_UMC_A_CUT(rtlhal->version) && + !IS_92C_SERIAL(rtlhal->version)) { + rtl_set_rfreg(hw, RF90_PATH_A, RF_RX_G1, MASKDWORD, 0x30255); + rtl_set_rfreg(hw, RF90_PATH_A, RF_RX_G2, MASKDWORD, 0x50a00); + } + rtlphy->rfreg_chnlval[0] = rtl_get_rfreg(hw, (enum radio_path)0, + RF_CHNLBW, RFREG_OFFSET_MASK); + rtlphy->rfreg_chnlval[1] = rtl_get_rfreg(hw, (enum radio_path)1, + RF_CHNLBW, RFREG_OFFSET_MASK); + rtl92cu_bb_block_on(hw); + rtl_cam_reset_all_entry(hw); + rtl92cu_enable_hw_security_config(hw); + ppsc->rfpwr_state = ERFON; + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_ETHER_ADDR, mac->mac_addr); + if (ppsc->rfpwr_state == ERFON) { + rtl92c_phy_set_rfpath_switch(hw, 1); + if (iqk_initialized) { + rtl92c_phy_iq_calibrate(hw, false); + } else { + rtl92c_phy_iq_calibrate(hw, false); + iqk_initialized = true; + } + rtl92c_dm_check_txpower_tracking(hw); + rtl92c_phy_lc_calibrate(hw); + } + _rtl92cu_hw_configure(hw); + _InitPABias(hw); + _update_mac_setting(hw); + rtl92c_dm_init(hw); + return err; +} + +static void _DisableRFAFEAndResetBB(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); +/************************************** +a. TXPAUSE 0x522[7:0] = 0xFF Pause MAC TX queue +b. RF path 0 offset 0x00 = 0x00 disable RF +c. APSD_CTRL 0x600[7:0] = 0x40 +d. SYS_FUNC_EN 0x02[7:0] = 0x16 reset BB state machine +e. SYS_FUNC_EN 0x02[7:0] = 0x14 reset BB state machine +***************************************/ + u8 eRFPath = 0, value8 = 0; + rtl_write_byte(rtlpriv, REG_TXPAUSE, 0xFF); + rtl_set_rfreg(hw, (enum radio_path)eRFPath, 0x0, MASKBYTE0, 0x0); + + value8 |= APSDOFF; + rtl_write_byte(rtlpriv, REG_APSD_CTRL, value8); /*0x40*/ + value8 = 0; + value8 |= (FEN_USBD | FEN_USBA | FEN_BB_GLB_RSTn); + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, value8);/*0x16*/ + value8 &= (~FEN_BB_GLB_RSTn); + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, value8); /*0x14*/ +} + +static void _ResetDigitalProcedure1(struct ieee80211_hw *hw, bool bWithoutHWSM) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + + if (rtlhal->fw_version <= 0x20) { + /***************************** + f. MCUFWDL 0x80[7:0]=0 reset MCU ready status + g. SYS_FUNC_EN 0x02[10]= 0 reset MCU reg, (8051 reset) + h. SYS_FUNC_EN 0x02[15-12]= 5 reset MAC reg, DCORE + i. SYS_FUNC_EN 0x02[10]= 1 enable MCU reg, (8051 enable) + ******************************/ + u16 valu16 = 0; + + rtl_write_byte(rtlpriv, REG_MCUFWDL, 0); + valu16 = rtl_read_word(rtlpriv, REG_SYS_FUNC_EN); + rtl_write_word(rtlpriv, REG_SYS_FUNC_EN, (valu16 & + (~FEN_CPUEN))); /* reset MCU ,8051 */ + valu16 = rtl_read_word(rtlpriv, REG_SYS_FUNC_EN)&0x0FFF; + rtl_write_word(rtlpriv, REG_SYS_FUNC_EN, (valu16 | + (FEN_HWPDN|FEN_ELDR))); /* reset MAC */ + valu16 = rtl_read_word(rtlpriv, REG_SYS_FUNC_EN); + rtl_write_word(rtlpriv, REG_SYS_FUNC_EN, (valu16 | + FEN_CPUEN)); /* enable MCU ,8051 */ + } else { + u8 retry_cnts = 0; + + /* IF fw in RAM code, do reset */ + if (rtl_read_byte(rtlpriv, REG_MCUFWDL) & BIT(1)) { + /* reset MCU ready status */ + rtl_write_byte(rtlpriv, REG_MCUFWDL, 0); + /* 8051 reset by self */ + rtl_write_byte(rtlpriv, REG_HMETFR+3, 0x20); + while ((retry_cnts++ < 100) && + (FEN_CPUEN & rtl_read_word(rtlpriv, + REG_SYS_FUNC_EN))) { + udelay(50); + } + if (retry_cnts >= 100) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "#####=> 8051 reset failed!.........................\n"); + /* if 8051 reset fail, reset MAC. */ + rtl_write_byte(rtlpriv, + REG_SYS_FUNC_EN + 1, + 0x50); + udelay(100); + } + } + /* Reset MAC and Enable 8051 */ + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, 0x54); + rtl_write_byte(rtlpriv, REG_MCUFWDL, 0); + } + if (bWithoutHWSM) { + /***************************** + Without HW auto state machine + g.SYS_CLKR 0x08[15:0] = 0x30A3 disable MAC clock + h.AFE_PLL_CTRL 0x28[7:0] = 0x80 disable AFE PLL + i.AFE_XTAL_CTRL 0x24[15:0] = 0x880F gated AFE DIG_CLOCK + j.SYS_ISu_CTRL 0x00[7:0] = 0xF9 isolated digital to PON + ******************************/ + rtl_write_word(rtlpriv, REG_SYS_CLKR, 0x70A3); + rtl_write_byte(rtlpriv, REG_AFE_PLL_CTRL, 0x80); + rtl_write_word(rtlpriv, REG_AFE_XTAL_CTRL, 0x880F); + rtl_write_byte(rtlpriv, REG_SYS_ISO_CTRL, 0xF9); + } +} + +static void _ResetDigitalProcedure2(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); +/***************************** +k. SYS_FUNC_EN 0x03[7:0] = 0x44 disable ELDR runction +l. SYS_CLKR 0x08[15:0] = 0x3083 disable ELDR clock +m. SYS_ISO_CTRL 0x01[7:0] = 0x83 isolated ELDR to PON +******************************/ + rtl_write_word(rtlpriv, REG_SYS_CLKR, 0x70A3); + rtl_write_byte(rtlpriv, REG_SYS_ISO_CTRL+1, 0x82); +} + +static void _DisableGPIO(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); +/*************************************** +j. GPIO_PIN_CTRL 0x44[31:0]=0x000 +k. Value = GPIO_PIN_CTRL[7:0] +l. GPIO_PIN_CTRL 0x44[31:0] = 0x00FF0000 | (value <<8); write ext PIN level +m. GPIO_MUXCFG 0x42 [15:0] = 0x0780 +n. LEDCFG 0x4C[15:0] = 0x8080 +***************************************/ + u8 value8; + u16 value16; + u32 value32; + + /* 1. Disable GPIO[7:0] */ + rtl_write_word(rtlpriv, REG_GPIO_PIN_CTRL+2, 0x0000); + value32 = rtl_read_dword(rtlpriv, REG_GPIO_PIN_CTRL) & 0xFFFF00FF; + value8 = (u8) (value32&0x000000FF); + value32 |= ((value8<<8) | 0x00FF0000); + rtl_write_dword(rtlpriv, REG_GPIO_PIN_CTRL, value32); + /* 2. Disable GPIO[10:8] */ + rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG+3, 0x00); + value16 = rtl_read_word(rtlpriv, REG_GPIO_MUXCFG+2) & 0xFF0F; + value8 = (u8) (value16&0x000F); + value16 |= ((value8<<4) | 0x0780); + rtl_write_word(rtlpriv, REG_GPIO_PIN_CTRL+2, value16); + /* 3. Disable LED0 & 1 */ + rtl_write_word(rtlpriv, REG_LEDCFG0, 0x8080); +} + +static void _DisableAnalog(struct ieee80211_hw *hw, bool bWithoutHWSM) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u16 value16 = 0; + u8 value8 = 0; + + if (bWithoutHWSM) { + /***************************** + n. LDOA15_CTRL 0x20[7:0] = 0x04 disable A15 power + o. LDOV12D_CTRL 0x21[7:0] = 0x54 disable digital core power + r. When driver call disable, the ASIC will turn off remaining + clock automatically + ******************************/ + rtl_write_byte(rtlpriv, REG_LDOA15_CTRL, 0x04); + value8 = rtl_read_byte(rtlpriv, REG_LDOV12D_CTRL); + value8 &= (~LDV12_EN); + rtl_write_byte(rtlpriv, REG_LDOV12D_CTRL, value8); + } + +/***************************** +h. SPS0_CTRL 0x11[7:0] = 0x23 enter PFM mode +i. APS_FSMCO 0x04[15:0] = 0x4802 set USB suspend +******************************/ + rtl_write_byte(rtlpriv, REG_SPS0_CTRL, 0x23); + value16 |= (APDM_HOST | AFSM_HSUS | PFM_ALDN); + rtl_write_word(rtlpriv, REG_APS_FSMCO, (u16)value16); + rtl_write_byte(rtlpriv, REG_RSV_CTRL, 0x0E); +} + +static void _CardDisableHWSM(struct ieee80211_hw *hw) +{ + /* ==== RF Off Sequence ==== */ + _DisableRFAFEAndResetBB(hw); + /* ==== Reset digital sequence ====== */ + _ResetDigitalProcedure1(hw, false); + /* ==== Pull GPIO PIN to balance level and LED control ====== */ + _DisableGPIO(hw); + /* ==== Disable analog sequence === */ + _DisableAnalog(hw, false); +} + +static void _CardDisableWithoutHWSM(struct ieee80211_hw *hw) +{ + /*==== RF Off Sequence ==== */ + _DisableRFAFEAndResetBB(hw); + /* ==== Reset digital sequence ====== */ + _ResetDigitalProcedure1(hw, true); + /* ==== Pull GPIO PIN to balance level and LED control ====== */ + _DisableGPIO(hw); + /* ==== Reset digital sequence ====== */ + _ResetDigitalProcedure2(hw); + /* ==== Disable analog sequence === */ + _DisableAnalog(hw, true); +} + +static void _rtl92cu_set_bcn_ctrl_reg(struct ieee80211_hw *hw, + u8 set_bits, u8 clear_bits) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw)); + + rtlusb->reg_bcn_ctrl_val |= set_bits; + rtlusb->reg_bcn_ctrl_val &= ~clear_bits; + rtl_write_byte(rtlpriv, REG_BCN_CTRL, (u8) rtlusb->reg_bcn_ctrl_val); +} + +static void _rtl92cu_stop_tx_beacon(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + u8 tmp1byte = 0; + if (IS_NORMAL_CHIP(rtlhal->version)) { + tmp1byte = rtl_read_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2); + rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2, + tmp1byte & (~BIT(6))); + rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 1, 0x64); + tmp1byte = rtl_read_byte(rtlpriv, REG_TBTT_PROHIBIT + 2); + tmp1byte &= ~(BIT(0)); + rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 2, tmp1byte); + } else { + rtl_write_byte(rtlpriv, REG_TXPAUSE, + rtl_read_byte(rtlpriv, REG_TXPAUSE) | BIT(6)); + } +} + +static void _rtl92cu_resume_tx_beacon(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + u8 tmp1byte = 0; + + if (IS_NORMAL_CHIP(rtlhal->version)) { + tmp1byte = rtl_read_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2); + rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2, + tmp1byte | BIT(6)); + rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 1, 0xff); + tmp1byte = rtl_read_byte(rtlpriv, REG_TBTT_PROHIBIT + 2); + tmp1byte |= BIT(0); + rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 2, tmp1byte); + } else { + rtl_write_byte(rtlpriv, REG_TXPAUSE, + rtl_read_byte(rtlpriv, REG_TXPAUSE) & (~BIT(6))); + } +} + +static void _rtl92cu_enable_bcn_sub_func(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + + if (IS_NORMAL_CHIP(rtlhal->version)) + _rtl92cu_set_bcn_ctrl_reg(hw, 0, BIT(1)); + else + _rtl92cu_set_bcn_ctrl_reg(hw, 0, BIT(4)); +} + +static void _rtl92cu_disable_bcn_sub_func(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + + if (IS_NORMAL_CHIP(rtlhal->version)) + _rtl92cu_set_bcn_ctrl_reg(hw, BIT(1), 0); + else + _rtl92cu_set_bcn_ctrl_reg(hw, BIT(4), 0); +} + +static int _rtl92cu_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; + + bt_msr &= 0xfc; + rtl_write_byte(rtlpriv, REG_BCN_MAX_ERR, 0xFF); + if (type == NL80211_IFTYPE_UNSPECIFIED || type == + NL80211_IFTYPE_STATION) { + _rtl92cu_stop_tx_beacon(hw); + _rtl92cu_enable_bcn_sub_func(hw); + } else if (type == NL80211_IFTYPE_ADHOC || type == NL80211_IFTYPE_AP) { + _rtl92cu_resume_tx_beacon(hw); + _rtl92cu_disable_bcn_sub_func(hw); + } else { + RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, + "Set HW_VAR_MEDIA_STATUS:No such media status(%x)\n", + type); + } + switch (type) { + case NL80211_IFTYPE_UNSPECIFIED: + bt_msr |= MSR_NOLINK; + ledaction = LED_CTL_LINK; + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + "Set Network type to NO LINK!\n"); + break; + case NL80211_IFTYPE_ADHOC: + bt_msr |= MSR_ADHOC; + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + "Set Network type to Ad Hoc!\n"); + break; + case NL80211_IFTYPE_STATION: + bt_msr |= MSR_INFRA; + ledaction = LED_CTL_LINK; + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + "Set Network type to STA!\n"); + break; + case NL80211_IFTYPE_AP: + bt_msr |= MSR_AP; + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + "Set Network type to AP!\n"); + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "Network type %d not supported!\n", type); + goto error_out; + } + rtl_write_byte(rtlpriv, (MSR), bt_msr); + rtlpriv->cfg->ops->led_control(hw, ledaction); + if ((bt_msr & 0xfc) == MSR_AP) + rtl_write_byte(rtlpriv, REG_BCNTCFG + 1, 0x00); + else + rtl_write_byte(rtlpriv, REG_BCNTCFG + 1, 0x66); + return 0; +error_out: + return 1; +} + +void rtl92cu_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_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw)); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + enum nl80211_iftype opmode; + + mac->link_state = MAC80211_NOLINK; + opmode = NL80211_IFTYPE_UNSPECIFIED; + _rtl92cu_set_media_status(hw, opmode); + rtlpriv->cfg->ops->led_control(hw, LED_CTL_POWER_OFF); + RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC); + if (rtlusb->disableHWSM) + _CardDisableHWSM(hw); + else + _CardDisableWithoutHWSM(hw); +} + +void rtl92cu_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid) +{ + /* dummy routine needed for callback from rtl_op_configure_filter() */ +} + +/*========================================================================== */ + +static void _rtl92cu_set_check_bssid(struct ieee80211_hw *hw, + enum nl80211_iftype type) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 reg_rcr = rtl_read_dword(rtlpriv, REG_RCR); + struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + u8 filterout_non_associated_bssid = false; + + switch (type) { + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_STATION: + filterout_non_associated_bssid = true; + break; + case NL80211_IFTYPE_UNSPECIFIED: + case NL80211_IFTYPE_AP: + default: + break; + } + if (filterout_non_associated_bssid) { + if (IS_NORMAL_CHIP(rtlhal->version)) { + switch (rtlphy->current_io_type) { + case IO_CMD_RESUME_DM_BY_SCAN: + reg_rcr |= (RCR_CBSSID_DATA | RCR_CBSSID_BCN); + rtlpriv->cfg->ops->set_hw_reg(hw, + HW_VAR_RCR, (u8 *)(®_rcr)); + /* enable update TSF */ + _rtl92cu_set_bcn_ctrl_reg(hw, 0, BIT(4)); + break; + case IO_CMD_PAUSE_DM_BY_SCAN: + reg_rcr &= ~(RCR_CBSSID_DATA | RCR_CBSSID_BCN); + rtlpriv->cfg->ops->set_hw_reg(hw, + HW_VAR_RCR, (u8 *)(®_rcr)); + /* disable update TSF */ + _rtl92cu_set_bcn_ctrl_reg(hw, BIT(4), 0); + break; + } + } else { + reg_rcr |= (RCR_CBSSID); + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR, + (u8 *)(®_rcr)); + _rtl92cu_set_bcn_ctrl_reg(hw, 0, (BIT(4)|BIT(5))); + } + } else if (filterout_non_associated_bssid == false) { + if (IS_NORMAL_CHIP(rtlhal->version)) { + reg_rcr &= (~(RCR_CBSSID_DATA | RCR_CBSSID_BCN)); + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR, + (u8 *)(®_rcr)); + _rtl92cu_set_bcn_ctrl_reg(hw, BIT(4), 0); + } else { + reg_rcr &= (~RCR_CBSSID); + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR, + (u8 *)(®_rcr)); + _rtl92cu_set_bcn_ctrl_reg(hw, (BIT(4)|BIT(5)), 0); + } + } +} + +int rtl92cu_set_network_type(struct ieee80211_hw *hw, enum nl80211_iftype type) +{ + if (_rtl92cu_set_media_status(hw, type)) + return -EOPNOTSUPP; + _rtl92cu_set_check_bssid(hw, type); + return 0; +} + +static void _InitBeaconParameters(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + + rtl_write_word(rtlpriv, REG_BCN_CTRL, 0x1010); + + /* TODO: Remove these magic number */ + rtl_write_word(rtlpriv, REG_TBTT_PROHIBIT, 0x6404); + rtl_write_byte(rtlpriv, REG_DRVERLYINT, DRIVER_EARLY_INT_TIME); + rtl_write_byte(rtlpriv, REG_BCNDMATIM, BCN_DMA_ATIME_INT_TIME); + /* Change beacon AIFS to the largest number + * beacause test chip does not contension before sending beacon. */ + if (IS_NORMAL_CHIP(rtlhal->version)) + rtl_write_word(rtlpriv, REG_BCNTCFG, 0x660F); + else + rtl_write_word(rtlpriv, REG_BCNTCFG, 0x66FF); +} + +static void _beacon_function_enable(struct ieee80211_hw *hw, bool Enable, + bool Linked) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + _rtl92cu_set_bcn_ctrl_reg(hw, (BIT(4) | BIT(3) | BIT(1)), 0x00); + rtl_write_byte(rtlpriv, REG_RD_CTRL+1, 0x6F); +} + +void rtl92cu_set_beacon_related_registers(struct ieee80211_hw *hw) +{ + + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + u16 bcn_interval, atim_window; + u32 value32; + + bcn_interval = mac->beacon_interval; + atim_window = 2; /*FIX MERGE */ + rtl_write_word(rtlpriv, REG_ATIMWND, atim_window); + rtl_write_word(rtlpriv, REG_BCN_INTERVAL, bcn_interval); + _InitBeaconParameters(hw); + rtl_write_byte(rtlpriv, REG_SLOT, 0x09); + /* + * Force beacon frame transmission even after receiving beacon frame + * from other ad hoc STA + * + * + * Reset TSF Timer to zero, added by Roger. 2008.06.24 + */ + value32 = rtl_read_dword(rtlpriv, REG_TCR); + value32 &= ~TSFRST; + rtl_write_dword(rtlpriv, REG_TCR, value32); + value32 |= TSFRST; + rtl_write_dword(rtlpriv, REG_TCR, value32); + RT_TRACE(rtlpriv, COMP_INIT|COMP_BEACON, DBG_LOUD, + "SetBeaconRelatedRegisters8192CUsb(): Set TCR(%x)\n", + value32); + /* TODO: Modify later (Find the right parameters) + * NOTE: Fix test chip's bug (about contention windows's randomness) */ + if ((mac->opmode == NL80211_IFTYPE_ADHOC) || + (mac->opmode == NL80211_IFTYPE_AP)) { + rtl_write_byte(rtlpriv, REG_RXTSF_OFFSET_CCK, 0x50); + rtl_write_byte(rtlpriv, REG_RXTSF_OFFSET_OFDM, 0x50); + } + _beacon_function_enable(hw, true, true); +} + +void rtl92cu_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(rtlpriv, COMP_BEACON, DBG_DMESG, "beacon_interval:%d\n", + bcn_interval); + rtl_write_word(rtlpriv, REG_BCN_INTERVAL, bcn_interval); +} + +void rtl92cu_update_interrupt_mask(struct ieee80211_hw *hw, + u32 add_msr, u32 rm_msr) +{ +} + +void rtl92cu_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_mac *mac = rtl_mac(rtl_priv(hw)); + + switch (variable) { + case HW_VAR_RCR: + *((u32 *)(val)) = mac->rx_conf; + 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->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; + } + case HW_VAR_MGT_FILTER: + *((u16 *) (val)) = rtl_read_word(rtlpriv, REG_RXFLTMAP0); + break; + case HW_VAR_CTRL_FILTER: + *((u16 *) (val)) = rtl_read_word(rtlpriv, REG_RXFLTMAP1); + break; + case HW_VAR_DATA_FILTER: + *((u16 *) (val)) = rtl_read_word(rtlpriv, REG_RXFLTMAP2); + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "switch case not processed\n"); + break; + } +} + +void rtl92cu_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val) +{ + 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_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + struct rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw)); + enum wireless_mode wirelessmode = mac->mode; + u8 idx = 0; + + 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 rate_cfg = ((u16 *) val)[0]; + u8 rate_index = 0; + + rate_cfg &= 0x15f; + /* TODO */ + /* if (mac->current_network.vender == HT_IOT_PEER_CISCO + * && ((rate_cfg & 0x150) == 0)) { + * rate_cfg |= 0x010; + * } */ + rate_cfg |= 0x01; + rtl_write_byte(rtlpriv, REG_RRSR, rate_cfg & 0xff); + rtl_write_byte(rtlpriv, REG_RRSR + 1, + (rate_cfg >> 8) & 0xff); + while (rate_cfg > 0x1) { + rate_cfg >>= 1; + rate_index++; + } + rtl_write_byte(rtlpriv, REG_INIRTS_RATE_SEL, + rate_index); + 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_CCK + 1, val[0]); + rtl_write_byte(rtlpriv, REG_SIFS_OFDM + 1, val[1]); + rtl_write_byte(rtlpriv, REG_SPEC_SIFS + 1, val[0]); + rtl_write_byte(rtlpriv, REG_MAC_SPEC_SIFS + 1, val[0]); + rtl_write_byte(rtlpriv, REG_R2T_SIFS+1, val[0]); + rtl_write_byte(rtlpriv, REG_T2T_SIFS+1, val[0]); + RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD, "HW_VAR_SIFS\n"); + break; + } + case HW_VAR_SLOT_TIME:{ + u8 e_aci; + u8 QOS_MODE = 1; + + rtl_write_byte(rtlpriv, REG_SLOT, val[0]); + RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD, + "HW_VAR_SLOT_TIME %x\n", val[0]); + if (QOS_MODE) { + for (e_aci = 0; e_aci < AC_MAX; e_aci++) + rtlpriv->cfg->ops->set_hw_reg(hw, + HW_VAR_AC_PARAM, + (u8 *)(&e_aci)); + } else { + u8 sifstime = 0; + u8 u1bAIFS; + + if (IS_WIRELESS_MODE_A(wirelessmode) || + IS_WIRELESS_MODE_N_24G(wirelessmode) || + IS_WIRELESS_MODE_N_5G(wirelessmode)) + sifstime = 16; + else + sifstime = 10; + u1bAIFS = sifstime + (2 * val[0]); + rtl_write_byte(rtlpriv, REG_EDCA_VO_PARAM, + u1bAIFS); + rtl_write_byte(rtlpriv, REG_EDCA_VI_PARAM, + u1bAIFS); + rtl_write_byte(rtlpriv, REG_EDCA_BE_PARAM, + u1bAIFS); + rtl_write_byte(rtlpriv, REG_EDCA_BK_PARAM, + u1bAIFS); + } + break; + } + case HW_VAR_ACK_PREAMBLE:{ + u8 reg_tmp; + u8 short_preamble = (bool) (*(u8 *) val); + reg_tmp = 0; + if (short_preamble) + reg_tmp |= 0x80; + rtl_write_byte(rtlpriv, REG_RRSR + 2, reg_tmp); + break; + } + case HW_VAR_AMPDU_MIN_SPACE:{ + u8 min_spacing_to_set; + u8 sec_min_space; + + min_spacing_to_set = *((u8 *) val); + if (min_spacing_to_set <= 7) { + switch (rtlpriv->sec.pairwise_enc_algorithm) { + case NO_ENCRYPTION: + case AESCCMP_ENCRYPTION: + sec_min_space = 0; + break; + case WEP40_ENCRYPTION: + case WEP104_ENCRYPTION: + case TKIP_ENCRYPTION: + sec_min_space = 6; + break; + default: + sec_min_space = 7; + break; + } + if (min_spacing_to_set < sec_min_space) + min_spacing_to_set = sec_min_space; + mac->min_space_cfg = ((mac->min_space_cfg & + 0xf8) | + min_spacing_to_set); + *val = min_spacing_to_set; + RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD, + "Set HW_VAR_AMPDU_MIN_SPACE: %#x\n", + mac->min_space_cfg); + rtl_write_byte(rtlpriv, REG_AMPDU_MIN_SPACE, + mac->min_space_cfg); + } + break; + } + case HW_VAR_SHORTGI_DENSITY:{ + u8 density_to_set; + + density_to_set = *((u8 *) val); + density_to_set &= 0x1f; + mac->min_space_cfg &= 0x07; + mac->min_space_cfg |= (density_to_set << 3); + RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD, + "Set HW_VAR_SHORTGI_DENSITY: %#x\n", + mac->min_space_cfg); + rtl_write_byte(rtlpriv, REG_AMPDU_MIN_SPACE, + mac->min_space_cfg); + break; + } + case HW_VAR_AMPDU_FACTOR:{ + u8 regtoset_normal[4] = {0x41, 0xa8, 0x72, 0xb9}; + u8 factor_toset; + u8 *p_regtoset = NULL; + u8 index = 0; + + p_regtoset = regtoset_normal; + factor_toset = *((u8 *) val); + if (factor_toset <= 3) { + factor_toset = (1 << (factor_toset + 2)); + if (factor_toset > 0xf) + factor_toset = 0xf; + for (index = 0; index < 4; index++) { + if ((p_regtoset[index] & 0xf0) > + (factor_toset << 4)) + p_regtoset[index] = + (p_regtoset[index] & 0x0f) + | (factor_toset << 4); + if ((p_regtoset[index] & 0x0f) > + factor_toset) + p_regtoset[index] = + (p_regtoset[index] & 0xf0) + | (factor_toset); + rtl_write_byte(rtlpriv, + (REG_AGGLEN_LMT + index), + p_regtoset[index]); + } + RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD, + "Set HW_VAR_AMPDU_FACTOR: %#x\n", + factor_toset); + } + break; + } + case HW_VAR_AC_PARAM:{ + u8 e_aci = *((u8 *) val); + u32 u4b_ac_param; + u16 cw_min = le16_to_cpu(mac->ac[e_aci].cw_min); + u16 cw_max = le16_to_cpu(mac->ac[e_aci].cw_max); + u16 tx_op = le16_to_cpu(mac->ac[e_aci].tx_op); + + u4b_ac_param = (u32) mac->ac[e_aci].aifs; + u4b_ac_param |= (u32) ((cw_min & 0xF) << + AC_PARAM_ECW_MIN_OFFSET); + u4b_ac_param |= (u32) ((cw_max & 0xF) << + AC_PARAM_ECW_MAX_OFFSET); + u4b_ac_param |= (u32) tx_op << AC_PARAM_TXOP_OFFSET; + RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD, + "queue:%x, ac_param:%x\n", + e_aci, u4b_ac_param); + switch (e_aci) { + case AC1_BK: + rtl_write_dword(rtlpriv, REG_EDCA_BK_PARAM, + u4b_ac_param); + 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, + u4b_ac_param); + break; + case AC3_VO: + rtl_write_dword(rtlpriv, REG_EDCA_VO_PARAM, + u4b_ac_param); + break; + default: + RT_ASSERT(false, + "SetHwReg8185(): invalid aci: %d !\n", + e_aci); + break; + } + if (rtlusb->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 *p_aci_aifsn = (union aci_aifsn *) + (&(mac->ac[0].aifs)); + u8 acm = p_aci_aifsn->f.acm; + u8 acm_ctrl = rtl_read_byte(rtlpriv, REG_ACMHWCTRL); + + acm_ctrl = + acm_ctrl | ((rtlusb->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(rtlpriv, 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(rtlpriv, COMP_ERR, DBG_EMERG, + "switch case not processed\n"); + break; + } + } + RT_TRACE(rtlpriv, 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]); + mac->rx_conf = ((u32 *) (val))[0]; + RT_TRACE(rtlpriv, COMP_RECV, DBG_DMESG, + "### Set RCR(0x%08x) ###\n", mac->rx_conf); + break; + } + case HW_VAR_RETRY_LIMIT:{ + u8 retry_limit = ((u8 *) (val))[0]; + + rtl_write_word(rtlpriv, REG_RL, + retry_limit << RETRY_LIMIT_SHORT_SHIFT | + retry_limit << RETRY_LIMIT_LONG_SHIFT); + RT_TRACE(rtlpriv, COMP_MLME, DBG_DMESG, + "Set HW_VAR_RETRY_LIMIT(0x%08x)\n", + retry_limit); + 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: + rtlefuse->efuse_usedbytes = *((u16 *) val); + break; + case HW_VAR_EFUSE_USAGE: + rtlefuse->efuse_usedpercentage = *((u8 *) val); + break; + case HW_VAR_IO_CMD: + rtl92c_phy_set_io_cmd(hw, (*(enum io_type *)val)); + break; + case HW_VAR_WPA_CONFIG: + rtl_write_byte(rtlpriv, REG_SECCFG, *((u8 *) val)); + break; + case HW_VAR_SET_RPWM:{ + u8 rpwm_val = rtl_read_byte(rtlpriv, REG_USB_HRPWM); + + if (rpwm_val & BIT(7)) + rtl_write_byte(rtlpriv, REG_USB_HRPWM, + (*(u8 *)val)); + else + rtl_write_byte(rtlpriv, REG_USB_HRPWM, + ((*(u8 *)val) | BIT(7))); + break; + } + case HW_VAR_H2C_FW_PWRMODE:{ + u8 psmode = (*(u8 *) val); + + if ((psmode != FW_PS_ACTIVE_MODE) && + (!IS_92C_SERIAL(rtlhal->version))) + rtl92c_dm_rf_saving(hw, true); + rtl92c_set_fw_pwrmode_cmd(hw, (*(u8 *) val)); + break; + } + case HW_VAR_FW_PSMODE_STATUS: + ppsc->fw_current_inpsmode = *((bool *) val); + break; + case HW_VAR_H2C_FW_JOINBSSRPT:{ + u8 mstatus = (*(u8 *) val); + u8 tmp_reg422; + bool recover = false; + + if (mstatus == RT_MEDIA_CONNECT) { + rtlpriv->cfg->ops->set_hw_reg(hw, + HW_VAR_AID, NULL); + rtl_write_byte(rtlpriv, REG_CR + 1, 0x03); + _rtl92cu_set_bcn_ctrl_reg(hw, 0, BIT(3)); + _rtl92cu_set_bcn_ctrl_reg(hw, BIT(4), 0); + tmp_reg422 = rtl_read_byte(rtlpriv, + REG_FWHW_TXQ_CTRL + 2); + if (tmp_reg422 & BIT(6)) + recover = true; + rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2, + tmp_reg422 & (~BIT(6))); + rtl92c_set_fw_rsvdpagepkt(hw, 0); + _rtl92cu_set_bcn_ctrl_reg(hw, BIT(3), 0); + _rtl92cu_set_bcn_ctrl_reg(hw, 0, BIT(4)); + if (recover) + rtl_write_byte(rtlpriv, + REG_FWHW_TXQ_CTRL + 2, + tmp_reg422 | BIT(6)); + rtl_write_byte(rtlpriv, REG_CR + 1, 0x02); + } + rtl92c_set_fw_joinbss_report_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) + _rtl92cu_stop_tx_beacon(hw); + _rtl92cu_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)); + _rtl92cu_set_bcn_ctrl_reg(hw, BIT(3), 0); + if (btype_ibss) + _rtl92cu_resume_tx_beacon(hw); + break; + } + case HW_VAR_MGT_FILTER: + rtl_write_word(rtlpriv, REG_RXFLTMAP0, *(u16 *)val); + break; + case HW_VAR_CTRL_FILTER: + rtl_write_word(rtlpriv, REG_RXFLTMAP1, *(u16 *)val); + break; + case HW_VAR_DATA_FILTER: + rtl_write_word(rtlpriv, REG_RXFLTMAP2, *(u16 *)val); + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "switch case not processed\n"); + break; + } +} + +void rtl92cu_update_hal_rate_table(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)); + u32 ratr_value = (u32) mac->basic_rates; + u8 *mcsrate = mac->mcs; + u8 ratr_index = 0; + u8 nmode = mac->ht_enable; + u8 mimo_ps = 1; + u16 shortgi_rate = 0; + u32 tmp_ratr_value = 0; + u8 curtxbw_40mhz = mac->bw_40; + u8 curshortgi_40mhz = mac->sgi_40; + u8 curshortgi_20mhz = mac->sgi_20; + enum wireless_mode wirelessmode = mac->mode; + + ratr_value |= ((*(u16 *) (mcsrate))) << 12; + switch (wirelessmode) { + case WIRELESS_MODE_B: + if (ratr_value & 0x0000000c) + ratr_value &= 0x0000000d; + else + ratr_value &= 0x0000000f; + break; + case WIRELESS_MODE_G: + ratr_value &= 0x00000FF5; + break; + case WIRELESS_MODE_N_24G: + case WIRELESS_MODE_N_5G: + nmode = 1; + if (mimo_ps == 0) { + ratr_value &= 0x0007F005; + } else { + u32 ratr_mask; + + if (get_rf_type(rtlphy) == RF_1T2R || + get_rf_type(rtlphy) == RF_1T1R) + ratr_mask = 0x000ff005; + else + ratr_mask = 0x0f0ff005; + if (curtxbw_40mhz) + ratr_mask |= 0x00000010; + ratr_value &= ratr_mask; + } + break; + default: + if (rtlphy->rf_type == RF_1T2R) + ratr_value &= 0x000ff0ff; + else + ratr_value &= 0x0f0ff0ff; + break; + } + ratr_value &= 0x0FFFFFFF; + if (nmode && ((curtxbw_40mhz && curshortgi_40mhz) || + (!curtxbw_40mhz && curshortgi_20mhz))) { + ratr_value |= 0x10000000; + tmp_ratr_value = (ratr_value >> 12); + for (shortgi_rate = 15; shortgi_rate > 0; shortgi_rate--) { + if ((1 << shortgi_rate) & tmp_ratr_value) + break; + } + shortgi_rate = (shortgi_rate << 12) | (shortgi_rate << 8) | + (shortgi_rate << 4) | (shortgi_rate); + } + rtl_write_dword(rtlpriv, REG_ARFR0 + ratr_index * 4, ratr_value); + RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG, "%x\n", + rtl_read_dword(rtlpriv, REG_ARFR0)); +} + +void rtl92cu_update_hal_rate_mask(struct ieee80211_hw *hw, 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)); + u32 ratr_bitmap = (u32) mac->basic_rates; + u8 *p_mcsrate = mac->mcs; + u8 ratr_index = 0; + u8 curtxbw_40mhz = mac->bw_40; + u8 curshortgi_40mhz = mac->sgi_40; + u8 curshortgi_20mhz = mac->sgi_20; + enum wireless_mode wirelessmode = mac->mode; + bool shortgi = false; + u8 rate_mask[5]; + u8 macid = 0; + u8 mimops = 1; + + ratr_bitmap |= (p_mcsrate[1] << 20) | (p_mcsrate[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_A: + ratr_index = RATR_INX_WIRELESS_A; + ratr_bitmap &= 0x00000ff0; + break; + case WIRELESS_MODE_N_24G: + case WIRELESS_MODE_N_5G: + ratr_index = RATR_INX_WIRELESS_NGB; + if (mimops == 0) { + if (rssi_level == 1) + ratr_bitmap &= 0x00070000; + else if (rssi_level == 2) + ratr_bitmap &= 0x0007f000; + else + ratr_bitmap &= 0x0007f005; + } else { + if (rtlphy->rf_type == RF_1T2R || + rtlphy->rf_type == RF_1T1R) { + if (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 (curtxbw_40mhz) { + if (rssi_level == 1) + ratr_bitmap &= 0x0f0f0000; + else if (rssi_level == 2) + ratr_bitmap &= 0x0f0ff000; + else + ratr_bitmap &= 0x0f0ff015; + } else { + if (rssi_level == 1) + ratr_bitmap &= 0x0f0f0000; + else if (rssi_level == 2) + ratr_bitmap &= 0x0f0ff000; + else + ratr_bitmap &= 0x0f0ff005; + } + } + } + if ((curtxbw_40mhz && curshortgi_40mhz) || + (!curtxbw_40mhz && curshortgi_20mhz)) { + if (macid == 0) + shortgi = true; + else if (macid == 1) + shortgi = false; + } + break; + default: + ratr_index = RATR_INX_WIRELESS_NGB; + if (rtlphy->rf_type == RF_1T2R) + ratr_bitmap &= 0x000ff0ff; + else + ratr_bitmap &= 0x0f0ff0ff; + break; + } + RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG, "ratr_bitmap :%x\n", + ratr_bitmap); + *(u32 *)&rate_mask = ((ratr_bitmap & 0x0fffffff) | + ratr_index << 28); + rate_mask[4] = macid | (shortgi ? 0x20 : 0x00) | 0x80; + RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG, + "Rate_index:%x, ratr_val:%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]); + rtl92c_fill_h2c_cmd(hw, H2C_RA_MASK, 5, rate_mask); +} + +void rtl92cu_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 rtl92cu_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 * valid) +{ + 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)); + enum rf_pwrstate e_rfpowerstate_toset, cur_rfstate; + u8 u1tmp = 0; + bool actuallyset = false; + unsigned long flag = 0; + /* to do - usb autosuspend */ + u8 usb_autosuspend = 0; + + if (ppsc->swrf_processing) + return false; + spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flag); + if (ppsc->rfchange_inprogress) { + spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag); + return false; + } else { + ppsc->rfchange_inprogress = true; + spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag); + } + cur_rfstate = ppsc->rfpwr_state; + if (usb_autosuspend) { + /* to do................... */ + } else { + if (ppsc->pwrdown_mode) { + u1tmp = rtl_read_byte(rtlpriv, REG_HSISR); + e_rfpowerstate_toset = (u1tmp & BIT(7)) ? + ERFOFF : ERFON; + RT_TRACE(rtlpriv, COMP_POWER, DBG_DMESG, + "pwrdown, 0x5c(BIT7)=%02x\n", u1tmp); + } else { + rtl_write_byte(rtlpriv, REG_MAC_PINMUX_CFG, + rtl_read_byte(rtlpriv, + REG_MAC_PINMUX_CFG) & ~(BIT(3))); + u1tmp = rtl_read_byte(rtlpriv, REG_GPIO_IO_SEL); + e_rfpowerstate_toset = (u1tmp & BIT(3)) ? + ERFON : ERFOFF; + RT_TRACE(rtlpriv, COMP_POWER, DBG_DMESG, + "GPIO_IN=%02x\n", u1tmp); + } + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, "N-SS RF =%x\n", + e_rfpowerstate_toset); + } + if ((ppsc->hwradiooff) && (e_rfpowerstate_toset == ERFON)) { + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + "GPIOChangeRF - HW Radio ON, RF ON\n"); + ppsc->hwradiooff = false; + actuallyset = true; + } else if ((!ppsc->hwradiooff) && (e_rfpowerstate_toset == + ERFOFF)) { + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + "GPIOChangeRF - HW Radio OFF\n"); + ppsc->hwradiooff = true; + actuallyset = true; + } else { + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + "pHalData->bHwRadioOff and eRfPowerStateToSet do not match: pHalData->bHwRadioOff %x, eRfPowerStateToSet %x\n", + ppsc->hwradiooff, e_rfpowerstate_toset); + } + if (actuallyset) { + ppsc->hwradiooff = true; + if (e_rfpowerstate_toset == ERFON) { + if ((ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM) && + RT_IN_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_ASPM)) + RT_CLEAR_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_ASPM); + else if ((ppsc->reg_rfps_level & RT_RF_OFF_LEVL_PCI_D3) + && RT_IN_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_PCI_D3)) + RT_CLEAR_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_PCI_D3); + } + spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flag); + ppsc->rfchange_inprogress = false; + spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag); + /* For power down module, we need to enable register block + * contrl reg at 0x1c. Then enable power down control bit + * of register 0x04 BIT4 and BIT15 as 1. + */ + if (ppsc->pwrdown_mode && e_rfpowerstate_toset == ERFOFF) { + /* Enable register area 0x0-0xc. */ + rtl_write_byte(rtlpriv, REG_RSV_CTRL, 0x0); + if (IS_HARDWARE_TYPE_8723U(rtlhal)) { + /* + * We should configure HW PDn source for WiFi + * ONLY, and then our HW will be set in + * power-down mode if PDn source from all + * functions are configured. + */ + u1tmp = rtl_read_byte(rtlpriv, + REG_MULTI_FUNC_CTRL); + rtl_write_byte(rtlpriv, REG_MULTI_FUNC_CTRL, + (u1tmp|WL_HWPDN_EN)); + } else { + rtl_write_word(rtlpriv, REG_APS_FSMCO, 0x8812); + } + } + if (e_rfpowerstate_toset == ERFOFF) { + if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM) + RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_ASPM); + else if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_PCI_D3) + RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_PCI_D3); + } + } else if (e_rfpowerstate_toset == ERFOFF || cur_rfstate == ERFOFF) { + /* Enter D3 or ASPM after GPIO had been done. */ + if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM) + RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_ASPM); + else if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_PCI_D3) + RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_PCI_D3); + spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flag); + ppsc->rfchange_inprogress = false; + spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag); + } else { + spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flag); + ppsc->rfchange_inprogress = false; + spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag); + } + *valid = 1; + return !ppsc->hwradiooff; +} diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.h b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.h new file mode 100644 index 00000000..f41a3aa4 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.h @@ -0,0 +1,117 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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 __RTL92CU_HW_H__ +#define __RTL92CU_HW_H__ + +#define H2C_RA_MASK 6 + +#define LLT_POLLING_LLT_THRESHOLD 20 +#define LLT_POLLING_READY_TIMEOUT_COUNT 100 +#define LLT_LAST_ENTRY_OF_TX_PKT_BUFFER 255 + +#define RX_PAGE_SIZE_REG_VALUE PBP_128 +/* Note: We will divide number of page equally for each queue + * other than public queue! */ +#define TX_TOTAL_PAGE_NUMBER 0xF8 +#define TX_PAGE_BOUNDARY (TX_TOTAL_PAGE_NUMBER + 1) + + +#define CHIP_B_PAGE_NUM_PUBQ 0xE7 + +/* For Test Chip Setting + * (HPQ + LPQ + PUBQ) shall be TX_TOTAL_PAGE_NUMBER */ +#define CHIP_A_PAGE_NUM_PUBQ 0x7E + + +/* For Chip A Setting */ +#define WMM_CHIP_A_TX_TOTAL_PAGE_NUMBER 0xF5 +#define WMM_CHIP_A_TX_PAGE_BOUNDARY \ + (WMM_CHIP_A_TX_TOTAL_PAGE_NUMBER + 1) /* F6 */ + +#define WMM_CHIP_A_PAGE_NUM_PUBQ 0xA3 +#define WMM_CHIP_A_PAGE_NUM_HPQ 0x29 +#define WMM_CHIP_A_PAGE_NUM_LPQ 0x29 + + + +/* Note: For Chip B Setting ,modify later */ +#define WMM_CHIP_B_TX_TOTAL_PAGE_NUMBER 0xF5 +#define WMM_CHIP_B_TX_PAGE_BOUNDARY \ + (WMM_CHIP_B_TX_TOTAL_PAGE_NUMBER + 1) /* F6 */ + +#define WMM_CHIP_B_PAGE_NUM_PUBQ 0xB0 +#define WMM_CHIP_B_PAGE_NUM_HPQ 0x29 +#define WMM_CHIP_B_PAGE_NUM_LPQ 0x1C +#define WMM_CHIP_B_PAGE_NUM_NPQ 0x1C + +#define BOARD_TYPE_NORMAL_MASK 0xE0 +#define BOARD_TYPE_TEST_MASK 0x0F + +/* should be renamed and moved to another file */ +enum _BOARD_TYPE_8192CUSB { + BOARD_USB_DONGLE = 0, /* USB dongle */ + BOARD_USB_High_PA = 1, /* USB dongle - high power PA */ + BOARD_MINICARD = 2, /* Minicard */ + BOARD_USB_SOLO = 3, /* USB solo-Slim module */ + BOARD_USB_COMBO = 4, /* USB Combo-Slim module */ +}; + +#define IS_HIGHT_PA(boardtype) \ + ((boardtype == BOARD_USB_High_PA) ? true : false) + +#define RTL92C_DRIVER_INFO_SIZE 4 +void rtl92cu_read_eeprom_info(struct ieee80211_hw *hw); +void rtl92cu_enable_hw_security_config(struct ieee80211_hw *hw); +int rtl92cu_hw_init(struct ieee80211_hw *hw); +void rtl92cu_card_disable(struct ieee80211_hw *hw); +int rtl92cu_set_network_type(struct ieee80211_hw *hw, enum nl80211_iftype type); +void rtl92cu_set_beacon_related_registers(struct ieee80211_hw *hw); +void rtl92cu_set_beacon_interval(struct ieee80211_hw *hw); +void rtl92cu_update_interrupt_mask(struct ieee80211_hw *hw, + u32 add_msr, u32 rm_msr); +void rtl92cu_get_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val); +void rtl92cu_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val); +void rtl92cu_update_hal_rate_table(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, + u8 rssi_level); +void rtl92cu_update_hal_rate_mask(struct ieee80211_hw *hw, u8 rssi_level); + +void rtl92cu_update_channel_access_setting(struct ieee80211_hw *hw); +bool rtl92cu_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 * valid); +void rtl92cu_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid); +int rtl92c_download_fw(struct ieee80211_hw *hw); +void rtl92c_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode); +void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool dl_finished); +void rtl92c_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus); +void rtl92c_fill_h2c_cmd(struct ieee80211_hw *hw, + u8 element_id, u32 cmd_len, u8 *p_cmdbuffer); +bool rtl92cu_phy_mac_config(struct ieee80211_hw *hw); + +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/led.c b/drivers/net/wireless/rtlwifi/rtl8192cu/led.c new file mode 100644 index 00000000..75a2deb2 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/led.c @@ -0,0 +1,141 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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. + * + * 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. + * + *****************************************************************************/ + +#include "../wifi.h" +#include "../usb.h" +#include "reg.h" +#include "led.h" + +static void _rtl92cu_init_led(struct ieee80211_hw *hw, + struct rtl_led *pled, enum rtl_led_pin ledpin) +{ + pled->hw = hw; + pled->ledpin = ledpin; + pled->ledon = false; +} + +static void _rtl92cu_deInit_led(struct rtl_led *pled) +{ +} + +void rtl92cu_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled) +{ + u8 ledcfg; + struct rtl_priv *rtlpriv = rtl_priv(hw); + + RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD, "LedAddr:%X ledpin=%d\n", + REG_LEDCFG2, pled->ledpin); + ledcfg = rtl_read_byte(rtlpriv, REG_LEDCFG2); + switch (pled->ledpin) { + case LED_PIN_GPIO0: + break; + case LED_PIN_LED0: + rtl_write_byte(rtlpriv, + REG_LEDCFG2, (ledcfg & 0xf0) | BIT(5) | BIT(6)); + break; + case LED_PIN_LED1: + rtl_write_byte(rtlpriv, REG_LEDCFG2, (ledcfg & 0x0f) | BIT(5)); + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "switch case not processed\n"); + break; + } + pled->ledon = true; +} + +void rtl92cu_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_usb_priv *usbpriv = rtl_usbpriv(hw); + u8 ledcfg; + + RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD, "LedAddr:%X ledpin=%d\n", + REG_LEDCFG2, pled->ledpin); + ledcfg = rtl_read_byte(rtlpriv, REG_LEDCFG2); + switch (pled->ledpin) { + case LED_PIN_GPIO0: + break; + case LED_PIN_LED0: + ledcfg &= 0xf0; + if (usbpriv->ledctl.led_opendrain) + rtl_write_byte(rtlpriv, REG_LEDCFG2, + (ledcfg | BIT(1) | BIT(5) | BIT(6))); + else + rtl_write_byte(rtlpriv, REG_LEDCFG2, + (ledcfg | BIT(3) | BIT(5) | BIT(6))); + break; + case LED_PIN_LED1: + ledcfg &= 0x0f; + rtl_write_byte(rtlpriv, REG_LEDCFG2, (ledcfg | BIT(3))); + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "switch case not processed\n"); + break; + } + pled->ledon = false; +} + +void rtl92cu_init_sw_leds(struct ieee80211_hw *hw) +{ + struct rtl_usb_priv *usbpriv = rtl_usbpriv(hw); + _rtl92cu_init_led(hw, &(usbpriv->ledctl.sw_led0), LED_PIN_LED0); + _rtl92cu_init_led(hw, &(usbpriv->ledctl.sw_led1), LED_PIN_LED1); +} + +void rtl92cu_deinit_sw_leds(struct ieee80211_hw *hw) +{ + struct rtl_usb_priv *usbpriv = rtl_usbpriv(hw); + _rtl92cu_deInit_led(&(usbpriv->ledctl.sw_led0)); + _rtl92cu_deInit_led(&(usbpriv->ledctl.sw_led1)); +} + +static void _rtl92cu_sw_led_control(struct ieee80211_hw *hw, + enum led_ctl_mode ledaction) +{ +} + +void rtl92cu_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(rtlpriv, COMP_LED, DBG_LOUD, "ledaction %d\n", ledaction); + _rtl92cu_sw_led_control(hw, ledaction); +} diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/led.h b/drivers/net/wireless/rtlwifi/rtl8192cu/led.h new file mode 100644 index 00000000..0f372278 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/led.h @@ -0,0 +1,37 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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. + * + * 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. + * + *****************************************************************************/ + +#ifndef __RTL92CU_LED_H__ +#define __RTL92CU_LED_H__ + +void rtl92cu_init_sw_leds(struct ieee80211_hw *hw); +void rtl92cu_deinit_sw_leds(struct ieee80211_hw *hw); +void rtl92cu_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled); +void rtl92cu_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled); +void rtl92cu_led_control(struct ieee80211_hw *hw, enum led_ctl_mode ledaction); + +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c b/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c new file mode 100644 index 00000000..025bdc2e --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c @@ -0,0 +1,1116 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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. + * + * 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> + * +****************************************************************************/ + +#include "../wifi.h" +#include "../pci.h" +#include "../usb.h" +#include "../ps.h" +#include "../cam.h" +#include "reg.h" +#include "def.h" +#include "phy.h" +#include "rf.h" +#include "dm.h" +#include "mac.h" +#include "trx.h" + +#include <linux/module.h> + +/* macro to shorten lines */ + +#define LINK_Q ui_link_quality +#define RX_EVM rx_evm_percentage +#define RX_SIGQ rx_mimo_signalquality + + +void rtl92c_read_chip_version(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + enum version_8192c chip_version = VERSION_UNKNOWN; + const char *versionid; + u32 value32; + + value32 = rtl_read_dword(rtlpriv, REG_SYS_CFG); + if (value32 & TRP_VAUX_EN) { + chip_version = (value32 & TYPE_ID) ? VERSION_TEST_CHIP_92C : + VERSION_TEST_CHIP_88C; + } else { + /* Normal mass production chip. */ + chip_version = NORMAL_CHIP; + chip_version |= ((value32 & TYPE_ID) ? CHIP_92C : 0); + chip_version |= ((value32 & VENDOR_ID) ? CHIP_VENDOR_UMC : 0); + /* RTL8723 with BT function. */ + chip_version |= ((value32 & BT_FUNC) ? CHIP_8723 : 0); + if (IS_VENDOR_UMC(chip_version)) + chip_version |= ((value32 & CHIP_VER_RTL_MASK) ? + CHIP_VENDOR_UMC_B_CUT : 0); + if (IS_92C_SERIAL(chip_version)) { + value32 = rtl_read_dword(rtlpriv, REG_HPON_FSM); + chip_version |= ((CHIP_BONDING_IDENTIFIER(value32) == + CHIP_BONDING_92C_1T2R) ? CHIP_92C_1T2R : 0); + } else if (IS_8723_SERIES(chip_version)) { + value32 = rtl_read_dword(rtlpriv, REG_GPIO_OUTSTS); + chip_version |= ((value32 & RF_RL_ID) ? + CHIP_8723_DRV_REV : 0); + } + } + rtlhal->version = (enum version_8192c)chip_version; + pr_info("Chip version 0x%x\n", chip_version); + switch (rtlhal->version) { + case VERSION_NORMAL_TSMC_CHIP_92C_1T2R: + versionid = "NORMAL_B_CHIP_92C"; + break; + case VERSION_NORMAL_TSMC_CHIP_92C: + versionid = "NORMAL_TSMC_CHIP_92C"; + break; + case VERSION_NORMAL_TSMC_CHIP_88C: + versionid = "NORMAL_TSMC_CHIP_88C"; + break; + case VERSION_NORMAL_UMC_CHIP_92C_1T2R_A_CUT: + versionid = "NORMAL_UMC_CHIP_i92C_1T2R_A_CUT"; + break; + case VERSION_NORMAL_UMC_CHIP_92C_A_CUT: + versionid = "NORMAL_UMC_CHIP_92C_A_CUT"; + break; + case VERSION_NORMAL_UMC_CHIP_88C_A_CUT: + versionid = "NORMAL_UMC_CHIP_88C_A_CUT"; + break; + case VERSION_NORMAL_UMC_CHIP_92C_1T2R_B_CUT: + versionid = "NORMAL_UMC_CHIP_92C_1T2R_B_CUT"; + break; + case VERSION_NORMAL_UMC_CHIP_92C_B_CUT: + versionid = "NORMAL_UMC_CHIP_92C_B_CUT"; + break; + case VERSION_NORMAL_UMC_CHIP_88C_B_CUT: + versionid = "NORMAL_UMC_CHIP_88C_B_CUT"; + break; + case VERSION_NORMA_UMC_CHIP_8723_1T1R_A_CUT: + versionid = "NORMAL_UMC_CHIP_8723_1T1R_A_CUT"; + break; + case VERSION_NORMA_UMC_CHIP_8723_1T1R_B_CUT: + versionid = "NORMAL_UMC_CHIP_8723_1T1R_B_CUT"; + break; + case VERSION_TEST_CHIP_92C: + versionid = "TEST_CHIP_92C"; + break; + case VERSION_TEST_CHIP_88C: + versionid = "TEST_CHIP_88C"; + break; + default: + versionid = "UNKNOWN"; + break; + } + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + "Chip Version ID: %s\n", versionid); + + if (IS_92C_SERIAL(rtlhal->version)) + rtlphy->rf_type = + (IS_92C_1T2R(rtlhal->version)) ? RF_1T2R : RF_2T2R; + else + rtlphy->rf_type = RF_1T1R; + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "Chip RF Type: %s\n", + rtlphy->rf_type == RF_2T2R ? "RF_2T2R" : "RF_1T1R"); + if (get_rf_type(rtlphy) == RF_1T1R) + rtlpriv->dm.rfpath_rxenable[0] = true; + else + rtlpriv->dm.rfpath_rxenable[0] = + rtlpriv->dm.rfpath_rxenable[1] = true; + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "VersionID = 0x%4x\n", + rtlhal->version); +} + +/** + * writeLLT - LLT table write access + * @io: io callback + * @address: LLT logical address. + * @data: LLT data content + * + * Realtek hardware access function. + * + */ +bool rtl92c_llt_write(struct ieee80211_hw *hw, u32 address, u32 data) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + bool status = true; + long count = 0; + u32 value = _LLT_INIT_ADDR(address) | + _LLT_INIT_DATA(data) | _LLT_OP(_LLT_WRITE_ACCESS); + + rtl_write_dword(rtlpriv, REG_LLT_INIT, value); + do { + value = rtl_read_dword(rtlpriv, REG_LLT_INIT); + if (_LLT_NO_ACTIVE == _LLT_OP_VALUE(value)) + break; + if (count > POLLING_LLT_THRESHOLD) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "Failed to polling write LLT done at address %d! _LLT_OP_VALUE(%x)\n", + address, _LLT_OP_VALUE(value)); + status = false; + break; + } + } while (++count); + return status; +} +/** + * rtl92c_init_LLT_table - Init LLT table + * @io: io callback + * @boundary: + * + * Realtek hardware access function. + * + */ +bool rtl92c_init_llt_table(struct ieee80211_hw *hw, u32 boundary) +{ + bool rst = true; + u32 i; + + for (i = 0; i < (boundary - 1); i++) { + rst = rtl92c_llt_write(hw, i , i + 1); + if (true != rst) { + pr_err("===> %s #1 fail\n", __func__); + return rst; + } + } + /* end of list */ + rst = rtl92c_llt_write(hw, (boundary - 1), 0xFF); + if (true != rst) { + pr_err("===> %s #2 fail\n", __func__); + return rst; + } + /* Make the other pages as ring buffer + * This ring buffer is used as beacon buffer if we config this MAC + * as two MAC transfer. + * Otherwise used as local loopback buffer. + */ + for (i = boundary; i < LLT_LAST_ENTRY_OF_TX_PKT_BUFFER; i++) { + rst = rtl92c_llt_write(hw, i, (i + 1)); + if (true != rst) { + pr_err("===> %s #3 fail\n", __func__); + return rst; + } + } + /* Let last entry point to the start entry of ring buffer */ + rst = rtl92c_llt_write(hw, LLT_LAST_ENTRY_OF_TX_PKT_BUFFER, boundary); + if (true != rst) { + pr_err("===> %s #4 fail\n", __func__); + return rst; + } + return rst; +} +void rtl92c_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(rtlpriv, COMP_SEC, DBG_DMESG, "clear_all\n"); + for (idx = 0; idx < clear_number; idx++) { + rtl_cam_mark_invalid(hw, cam_offset + idx); + 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(rtlpriv, COMP_ERR, DBG_EMERG, + "illegal switch case\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 { + key_index = PAIRWISE_KEYIDX; + entry_id = CAM_PAIRWISE_KEY_POSITION; + is_pairwise = true; + } + } + if (rtlpriv->sec.key_len[key_index] == 0) { + RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, + "delete one entry\n"); + rtl_cam_delete_one_entry(hw, p_macaddr, entry_id); + } else { + RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, + "The insert KEY length is %d\n", + rtlpriv->sec.key_len[PAIRWISE_KEYIDX]); + RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, + "The insert KEY is %x %x\n", + rtlpriv->sec.key_buf[0][0], + rtlpriv->sec.key_buf[0][1]); + RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, + "add one entry\n"); + if (is_pairwise) { + RT_PRINT_DATA(rtlpriv, COMP_SEC, DBG_LOUD, + "Pairwise Key content", + rtlpriv->sec.pairwise_key, + rtlpriv->sec. + key_len[PAIRWISE_KEYIDX]); + RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, + "set Pairwise key\n"); + + 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(rtlpriv, COMP_SEC, DBG_DMESG, + "set group key\n"); + if (mac->opmode == NL80211_IFTYPE_ADHOC) { + 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]); + } + rtl_cam_add_one_entry(hw, macaddr, key_index, + entry_id, enc_algo, + CAM_CONFIG_NO_USEDK, + rtlpriv->sec.key_buf[entry_id]); + } + } + } +} + +u32 rtl92c_get_txdma_status(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + return rtl_read_dword(rtlpriv, REG_TXDMA_STATUS); +} + +void rtl92c_enable_interrupt(struct ieee80211_hw *hw) +{ + 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 rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw)); + + if (IS_HARDWARE_TYPE_8192CE(rtlhal)) { + rtl_write_dword(rtlpriv, REG_HIMR, rtlpci->irq_mask[0] & + 0xFFFFFFFF); + rtl_write_dword(rtlpriv, REG_HIMRE, rtlpci->irq_mask[1] & + 0xFFFFFFFF); + } else { + rtl_write_dword(rtlpriv, REG_HIMR, rtlusb->irq_mask[0] & + 0xFFFFFFFF); + rtl_write_dword(rtlpriv, REG_HIMRE, rtlusb->irq_mask[1] & + 0xFFFFFFFF); + } +} + +void rtl92c_init_interrupt(struct ieee80211_hw *hw) +{ + rtl92c_enable_interrupt(hw); +} + +void rtl92c_disable_interrupt(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtl_write_dword(rtlpriv, REG_HIMR, IMR8190_DISABLED); + rtl_write_dword(rtlpriv, REG_HIMRE, IMR8190_DISABLED); +} + +void rtl92c_set_qos(struct ieee80211_hw *hw, int aci) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + u32 u4b_ac_param; + + rtl92c_dm_init_edca_turbo(hw); + u4b_ac_param = (u32) mac->ac[aci].aifs; + u4b_ac_param |= + ((u32) le16_to_cpu(mac->ac[aci].cw_min) & 0xF) << + AC_PARAM_ECW_MIN_OFFSET; + u4b_ac_param |= + ((u32) le16_to_cpu(mac->ac[aci].cw_max) & 0xF) << + AC_PARAM_ECW_MAX_OFFSET; + u4b_ac_param |= (u32) le16_to_cpu(mac->ac[aci].tx_op) << + AC_PARAM_TXOP_OFFSET; + RT_TRACE(rtlpriv, COMP_QOS, DBG_LOUD, "queue:%x, ac_param:%x\n", + aci, u4b_ac_param); + switch (aci) { + case AC1_BK: + rtl_write_dword(rtlpriv, REG_EDCA_BK_PARAM, u4b_ac_param); + 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, u4b_ac_param); + break; + case AC3_VO: + rtl_write_dword(rtlpriv, REG_EDCA_VO_PARAM, u4b_ac_param); + break; + default: + RT_ASSERT(false, "invalid aci: %d !\n", aci); + break; + } +} + +/*------------------------------------------------------------------------- + * HW MAC Address + *-------------------------------------------------------------------------*/ +void rtl92c_set_mac_addr(struct ieee80211_hw *hw, const u8 *addr) +{ + u32 i; + struct rtl_priv *rtlpriv = rtl_priv(hw); + + for (i = 0 ; i < ETH_ALEN ; i++) + rtl_write_byte(rtlpriv, (REG_MACID + i), *(addr+i)); + + RT_TRACE(rtlpriv, COMP_CMD, DBG_DMESG, + "MAC Address: %02X-%02X-%02X-%02X-%02X-%02X\n", + rtl_read_byte(rtlpriv, REG_MACID), + rtl_read_byte(rtlpriv, REG_MACID+1), + rtl_read_byte(rtlpriv, REG_MACID+2), + rtl_read_byte(rtlpriv, REG_MACID+3), + rtl_read_byte(rtlpriv, REG_MACID+4), + rtl_read_byte(rtlpriv, REG_MACID+5)); +} + +void rtl92c_init_driver_info_size(struct ieee80211_hw *hw, u8 size) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + rtl_write_byte(rtlpriv, REG_RX_DRVINFO_SZ, size); +} + +int rtl92c_set_network_type(struct ieee80211_hw *hw, enum nl80211_iftype type) +{ + u8 value; + struct rtl_priv *rtlpriv = rtl_priv(hw); + + switch (type) { + case NL80211_IFTYPE_UNSPECIFIED: + value = NT_NO_LINK; + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "Set Network type to NO LINK!\n"); + break; + case NL80211_IFTYPE_ADHOC: + value = NT_LINK_AD_HOC; + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "Set Network type to Ad Hoc!\n"); + break; + case NL80211_IFTYPE_STATION: + value = NT_LINK_AP; + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "Set Network type to STA!\n"); + break; + case NL80211_IFTYPE_AP: + value = NT_AS_AP; + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "Set Network type to AP!\n"); + break; + default: + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "Network type %d not supported!\n", type); + return -EOPNOTSUPP; + } + rtl_write_byte(rtlpriv, (REG_CR + 2), value); + return 0; +} + +void rtl92c_init_network_type(struct ieee80211_hw *hw) +{ + rtl92c_set_network_type(hw, NL80211_IFTYPE_UNSPECIFIED); +} + +void rtl92c_init_adaptive_ctrl(struct ieee80211_hw *hw) +{ + u16 value16; + u32 value32; + struct rtl_priv *rtlpriv = rtl_priv(hw); + + /* Response Rate Set */ + value32 = rtl_read_dword(rtlpriv, REG_RRSR); + value32 &= ~RATE_BITMAP_ALL; + value32 |= RATE_RRSR_CCK_ONLY_1M; + rtl_write_dword(rtlpriv, REG_RRSR, value32); + /* SIFS (used in NAV) */ + value16 = _SPEC_SIFS_CCK(0x10) | _SPEC_SIFS_OFDM(0x10); + rtl_write_word(rtlpriv, REG_SPEC_SIFS, value16); + /* Retry Limit */ + value16 = _LRL(0x30) | _SRL(0x30); + rtl_write_dword(rtlpriv, REG_RL, value16); +} + +void rtl92c_init_rate_fallback(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + /* Set Data Auto Rate Fallback Retry Count register. */ + rtl_write_dword(rtlpriv, REG_DARFRC, 0x00000000); + rtl_write_dword(rtlpriv, REG_DARFRC+4, 0x10080404); + rtl_write_dword(rtlpriv, REG_RARFRC, 0x04030201); + rtl_write_dword(rtlpriv, REG_RARFRC+4, 0x08070605); +} + +static void rtl92c_set_cck_sifs(struct ieee80211_hw *hw, u8 trx_sifs, + u8 ctx_sifs) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtl_write_byte(rtlpriv, REG_SIFS_CCK, trx_sifs); + rtl_write_byte(rtlpriv, (REG_SIFS_CCK + 1), ctx_sifs); +} + +static void rtl92c_set_ofdm_sifs(struct ieee80211_hw *hw, u8 trx_sifs, + u8 ctx_sifs) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtl_write_byte(rtlpriv, REG_SIFS_OFDM, trx_sifs); + rtl_write_byte(rtlpriv, (REG_SIFS_OFDM + 1), ctx_sifs); +} + +void rtl92c_init_edca_param(struct ieee80211_hw *hw, + u16 queue, u16 txop, u8 cw_min, u8 cw_max, u8 aifs) +{ + /* sequence: VO, VI, BE, BK ==> the same as 92C hardware design. + * referenc : enum nl80211_txq_q or ieee80211_set_wmm_default function. + */ + u32 value; + struct rtl_priv *rtlpriv = rtl_priv(hw); + + value = (u32)aifs; + value |= ((u32)cw_min & 0xF) << 8; + value |= ((u32)cw_max & 0xF) << 12; + value |= (u32)txop << 16; + /* 92C hardware register sequence is the same as queue number. */ + rtl_write_dword(rtlpriv, (REG_EDCA_VO_PARAM + (queue * 4)), value); +} + +void rtl92c_init_edca(struct ieee80211_hw *hw) +{ + u16 value16; + struct rtl_priv *rtlpriv = rtl_priv(hw); + + /* disable EDCCA count down, to reduce collison and retry */ + value16 = rtl_read_word(rtlpriv, REG_RD_CTRL); + value16 |= DIS_EDCA_CNT_DWN; + rtl_write_word(rtlpriv, REG_RD_CTRL, value16); + /* Update SIFS timing. ?????????? + * pHalData->SifsTime = 0x0e0e0a0a; */ + rtl92c_set_cck_sifs(hw, 0xa, 0xa); + rtl92c_set_ofdm_sifs(hw, 0xe, 0xe); + /* Set CCK/OFDM SIFS to be 10us. */ + rtl_write_word(rtlpriv, REG_SIFS_CCK, 0x0a0a); + rtl_write_word(rtlpriv, REG_SIFS_OFDM, 0x1010); + rtl_write_word(rtlpriv, REG_PROT_MODE_CTRL, 0x0204); + rtl_write_dword(rtlpriv, REG_BAR_MODE_CTRL, 0x014004); + /* TXOP */ + rtl_write_dword(rtlpriv, REG_EDCA_BE_PARAM, 0x005EA42B); + rtl_write_dword(rtlpriv, REG_EDCA_BK_PARAM, 0x0000A44F); + rtl_write_dword(rtlpriv, REG_EDCA_VI_PARAM, 0x005EA324); + rtl_write_dword(rtlpriv, REG_EDCA_VO_PARAM, 0x002FA226); + /* PIFS */ + rtl_write_byte(rtlpriv, REG_PIFS, 0x1C); + /* AGGR BREAK TIME Register */ + rtl_write_byte(rtlpriv, REG_AGGR_BREAK_TIME, 0x16); + rtl_write_word(rtlpriv, REG_NAV_PROT_LEN, 0x0040); + rtl_write_byte(rtlpriv, REG_BCNDMATIM, 0x02); + rtl_write_byte(rtlpriv, REG_ATIMWND, 0x02); +} + +void rtl92c_init_ampdu_aggregation(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtl_write_dword(rtlpriv, REG_AGGLEN_LMT, 0x99997631); + rtl_write_byte(rtlpriv, REG_AGGR_BREAK_TIME, 0x16); + /* init AMPDU aggregation number, tuning for Tx's TP, */ + rtl_write_word(rtlpriv, 0x4CA, 0x0708); +} + +void rtl92c_init_beacon_max_error(struct ieee80211_hw *hw, bool infra_mode) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtl_write_byte(rtlpriv, REG_BCN_MAX_ERR, 0xFF); +} + +void rtl92c_init_rdg_setting(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtl_write_byte(rtlpriv, REG_RD_CTRL, 0xFF); + rtl_write_word(rtlpriv, REG_RD_NAV_NXT, 0x200); + rtl_write_byte(rtlpriv, REG_RD_RESP_PKT_TH, 0x05); +} + +void rtl92c_init_retry_function(struct ieee80211_hw *hw) +{ + u8 value8; + struct rtl_priv *rtlpriv = rtl_priv(hw); + + value8 = rtl_read_byte(rtlpriv, REG_FWHW_TXQ_CTRL); + value8 |= EN_AMPDU_RTY_NEW; + rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL, value8); + /* Set ACK timeout */ + rtl_write_byte(rtlpriv, REG_ACKTO, 0x40); +} + +void rtl92c_init_beacon_parameters(struct ieee80211_hw *hw, + enum version_8192c version) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + + rtl_write_word(rtlpriv, REG_TBTT_PROHIBIT, 0x6404);/* ms */ + rtl_write_byte(rtlpriv, REG_DRVERLYINT, DRIVER_EARLY_INT_TIME);/*ms*/ + rtl_write_byte(rtlpriv, REG_BCNDMATIM, BCN_DMA_ATIME_INT_TIME); + if (IS_NORMAL_CHIP(rtlhal->version)) + rtl_write_word(rtlpriv, REG_BCNTCFG, 0x660F); + else + rtl_write_word(rtlpriv, REG_BCNTCFG, 0x66FF); +} + +void rtl92c_disable_fast_edca(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtl_write_word(rtlpriv, REG_FAST_EDCA_CTRL, 0); +} + +void rtl92c_set_min_space(struct ieee80211_hw *hw, bool is2T) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 value = is2T ? MAX_MSS_DENSITY_2T : MAX_MSS_DENSITY_1T; + + rtl_write_byte(rtlpriv, REG_AMPDU_MIN_SPACE, value); +} + +u16 rtl92c_get_mgt_filter(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + return rtl_read_word(rtlpriv, REG_RXFLTMAP0); +} + +void rtl92c_set_mgt_filter(struct ieee80211_hw *hw, u16 filter) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtl_write_word(rtlpriv, REG_RXFLTMAP0, filter); +} + +u16 rtl92c_get_ctrl_filter(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + return rtl_read_word(rtlpriv, REG_RXFLTMAP1); +} + +void rtl92c_set_ctrl_filter(struct ieee80211_hw *hw, u16 filter) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtl_write_word(rtlpriv, REG_RXFLTMAP1, filter); +} + +u16 rtl92c_get_data_filter(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + return rtl_read_word(rtlpriv, REG_RXFLTMAP2); +} + +void rtl92c_set_data_filter(struct ieee80211_hw *hw, u16 filter) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtl_write_word(rtlpriv, REG_RXFLTMAP2, filter); +} +/*==============================================================*/ + +static u8 _rtl92c_query_rxpwrpercentage(char antpower) +{ + if ((antpower <= -100) || (antpower >= 20)) + return 0; + else if (antpower >= 0) + return 100; + else + return 100 + antpower; +} + +static u8 _rtl92c_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; +} + +static long _rtl92c_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; +} + +static long _rtl92c_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; +} + +static void _rtl92c_query_rxphystatus(struct ieee80211_hw *hw, + struct rtl_stats *pstats, + struct rx_desc_92c *pdesc, + struct rx_fwinfo_92c *p_drvinfo, + bool packet_match_bssid, + bool packet_toself, + bool packet_beacon) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct phy_sts_cck_8192s_t *cck_buf; + s8 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 in_powersavemode = false; + bool is_cck_rate; + + is_cck_rate = RX_HAL_IS_CCK_RATE(pdesc); + pstats->packet_matchbssid = packet_match_bssid; + pstats->packet_toself = packet_toself; + pstats->is_cck = is_cck_rate; + pstats->packet_beacon = packet_beacon; + pstats->is_cck = is_cck_rate; + pstats->RX_SIGQ[0] = -1; + pstats->RX_SIGQ[1] = -1; + if (is_cck_rate) { + u8 report, cck_highpwr; + cck_buf = (struct phy_sts_cck_8192s_t *)p_drvinfo; + if (!in_powersavemode) + cck_highpwr = rtlphy->cck_high_power; + else + cck_highpwr = false; + if (!cck_highpwr) { + u8 cck_agc_rpt = cck_buf->cck_agc_rpt; + report = cck_buf->cck_agc_rpt & 0xc0; + report = report >> 6; + switch (report) { + case 0x3: + rx_pwr_all = -46 - (cck_agc_rpt & 0x3e); + break; + case 0x2: + rx_pwr_all = -26 - (cck_agc_rpt & 0x3e); + break; + case 0x1: + rx_pwr_all = -12 - (cck_agc_rpt & 0x3e); + break; + case 0x0: + rx_pwr_all = 16 - (cck_agc_rpt & 0x3e); + break; + } + } else { + u8 cck_agc_rpt = cck_buf->cck_agc_rpt; + report = p_drvinfo->cfosho[0] & 0x60; + report = report >> 5; + switch (report) { + case 0x3: + rx_pwr_all = -46 - ((cck_agc_rpt & 0x1f) << 1); + break; + case 0x2: + rx_pwr_all = -26 - ((cck_agc_rpt & 0x1f) << 1); + break; + case 0x1: + rx_pwr_all = -12 - ((cck_agc_rpt & 0x1f) << 1); + break; + case 0x0: + rx_pwr_all = 16 - ((cck_agc_rpt & 0x1f) << 1); + break; + } + } + pwdb_all = _rtl92c_query_rxpwrpercentage(rx_pwr_all); + pstats->rx_pwdb_all = pwdb_all; + pstats->recvsignalpower = rx_pwr_all; + if (packet_match_bssid) { + u8 sq; + if (pstats->rx_pwdb_all > 40) + sq = 100; + else { + sq = cck_buf->sq_rpt; + if (sq > 64) + sq = 0; + else if (sq < 20) + sq = 100; + else + sq = ((64 - sq) * 100) / 44; + } + pstats->signalquality = sq; + pstats->RX_SIGQ[0] = sq; + pstats->RX_SIGQ[1] = -1; + } + } else { + rtlpriv->dm.rfpath_rxenable[0] = + rtlpriv->dm.rfpath_rxenable[1] = true; + for (i = RF90_PATH_A; i < RF90_PATH_MAX; i++) { + if (rtlpriv->dm.rfpath_rxenable[i]) + rf_rx_num++; + rx_pwr[i] = + ((p_drvinfo->gain_trsw[i] & 0x3f) * 2) - 110; + rssi = _rtl92c_query_rxpwrpercentage(rx_pwr[i]); + total_rssi += rssi; + rtlpriv->stats.rx_snr_db[i] = + (long)(p_drvinfo->rxsnr[i] / 2); + + if (packet_match_bssid) + pstats->rx_mimo_signalstrength[i] = (u8) rssi; + } + rx_pwr_all = ((p_drvinfo->pwdb_all >> 1) & 0x7f) - 110; + pwdb_all = _rtl92c_query_rxpwrpercentage(rx_pwr_all); + pstats->rx_pwdb_all = pwdb_all; + pstats->rxpower = rx_pwr_all; + pstats->recvsignalpower = rx_pwr_all; + if (GET_RX_DESC_RX_MCS(pdesc) && + GET_RX_DESC_RX_MCS(pdesc) >= DESC92_RATEMCS8 && + GET_RX_DESC_RX_MCS(pdesc) <= DESC92_RATEMCS15) + max_spatial_stream = 2; + else + max_spatial_stream = 1; + for (i = 0; i < max_spatial_stream; i++) { + evm = _rtl92c_evm_db_to_percentage(p_drvinfo->rxevm[i]); + if (packet_match_bssid) { + if (i == 0) + pstats->signalquality = + (u8) (evm & 0xff); + pstats->RX_SIGQ[i] = + (u8) (evm & 0xff); + } + } + } + if (is_cck_rate) + pstats->signalstrength = + (u8) (_rtl92c_signal_scale_mapping(hw, pwdb_all)); + else if (rf_rx_num != 0) + pstats->signalstrength = + (u8) (_rtl92c_signal_scale_mapping + (hw, total_rssi /= rf_rx_num)); +} + +static void _rtl92c_process_ui_rssi(struct ieee80211_hw *hw, + struct rtl_stats *pstats) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + u8 rfpath; + u32 last_rssi, tmpval; + + if (pstats->packet_toself || pstats->packet_beacon) { + 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 += pstats->signalstrength; + rtlpriv->stats.ui_rssi.elements[rtlpriv->stats.ui_rssi. + index++] = pstats->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 = + _rtl92c_translate_todbm(hw, (u8) tmpval); + pstats->rssi = rtlpriv->stats.signal_strength; + } + if (!pstats->is_cck && pstats->packet_toself) { + for (rfpath = RF90_PATH_A; rfpath < rtlphy->num_total_rfpath; + rfpath++) { + if (!rtl8192_phy_check_is_legal_rfpath(hw, rfpath)) + continue; + if (rtlpriv->stats.rx_rssi_percentage[rfpath] == 0) { + rtlpriv->stats.rx_rssi_percentage[rfpath] = + pstats->rx_mimo_signalstrength[rfpath]; + } + if (pstats->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)) + + (pstats->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)) + + (pstats->rx_mimo_signalstrength[rfpath])) / + (RX_SMOOTH_FACTOR); + } + } + } +} + +static void _rtl92c_update_rxsignalstatistics(struct ieee80211_hw *hw, + struct rtl_stats *pstats) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + int weighting = 0; + + if (rtlpriv->stats.recv_signal_power == 0) + rtlpriv->stats.recv_signal_power = pstats->recvsignalpower; + if (pstats->recvsignalpower > rtlpriv->stats.recv_signal_power) + weighting = 5; + else if (pstats->recvsignalpower < rtlpriv->stats.recv_signal_power) + weighting = (-5); + rtlpriv->stats.recv_signal_power = + (rtlpriv->stats.recv_signal_power * 5 + + pstats->recvsignalpower + weighting) / 6; +} + +static void _rtl92c_process_pwdb(struct ieee80211_hw *hw, + struct rtl_stats *pstats) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + long undecorated_smoothed_pwdb = 0; + + if (mac->opmode == NL80211_IFTYPE_ADHOC) { + return; + } else { + undecorated_smoothed_pwdb = + rtlpriv->dm.undecorated_smoothed_pwdb; + } + if (pstats->packet_toself || pstats->packet_beacon) { + if (undecorated_smoothed_pwdb < 0) + undecorated_smoothed_pwdb = pstats->rx_pwdb_all; + if (pstats->rx_pwdb_all > (u32) undecorated_smoothed_pwdb) { + undecorated_smoothed_pwdb = + (((undecorated_smoothed_pwdb) * + (RX_SMOOTH_FACTOR - 1)) + + (pstats->rx_pwdb_all)) / (RX_SMOOTH_FACTOR); + undecorated_smoothed_pwdb = undecorated_smoothed_pwdb + + 1; + } else { + undecorated_smoothed_pwdb = + (((undecorated_smoothed_pwdb) * + (RX_SMOOTH_FACTOR - 1)) + + (pstats->rx_pwdb_all)) / (RX_SMOOTH_FACTOR); + } + rtlpriv->dm.undecorated_smoothed_pwdb = + undecorated_smoothed_pwdb; + _rtl92c_update_rxsignalstatistics(hw, pstats); + } +} + +static void _rtl92c_process_LINK_Q(struct ieee80211_hw *hw, + struct rtl_stats *pstats) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 last_evm = 0, n_stream, tmpval; + + if (pstats->signalquality != 0) { + if (pstats->packet_toself || pstats->packet_beacon) { + if (rtlpriv->stats.LINK_Q.total_num++ >= + PHY_LINKQUALITY_SLID_WIN_MAX) { + rtlpriv->stats.LINK_Q.total_num = + PHY_LINKQUALITY_SLID_WIN_MAX; + last_evm = + rtlpriv->stats.LINK_Q.elements + [rtlpriv->stats.LINK_Q.index]; + rtlpriv->stats.LINK_Q.total_val -= + last_evm; + } + rtlpriv->stats.LINK_Q.total_val += + pstats->signalquality; + rtlpriv->stats.LINK_Q.elements + [rtlpriv->stats.LINK_Q.index++] = + pstats->signalquality; + if (rtlpriv->stats.LINK_Q.index >= + PHY_LINKQUALITY_SLID_WIN_MAX) + rtlpriv->stats.LINK_Q.index = 0; + tmpval = rtlpriv->stats.LINK_Q.total_val / + rtlpriv->stats.LINK_Q.total_num; + rtlpriv->stats.signal_quality = tmpval; + rtlpriv->stats.last_sigstrength_inpercent = tmpval; + for (n_stream = 0; n_stream < 2; + n_stream++) { + if (pstats->RX_SIGQ[n_stream] != -1) { + if (!rtlpriv->stats.RX_EVM[n_stream]) { + rtlpriv->stats.RX_EVM[n_stream] + = pstats->RX_SIGQ[n_stream]; + } + rtlpriv->stats.RX_EVM[n_stream] = + ((rtlpriv->stats.RX_EVM + [n_stream] * + (RX_SMOOTH_FACTOR - 1)) + + (pstats->RX_SIGQ + [n_stream] * 1)) / + (RX_SMOOTH_FACTOR); + } + } + } + } else { + ; + } +} + +static void _rtl92c_process_phyinfo(struct ieee80211_hw *hw, + u8 *buffer, + struct rtl_stats *pcurrent_stats) +{ + if (!pcurrent_stats->packet_matchbssid && + !pcurrent_stats->packet_beacon) + return; + _rtl92c_process_ui_rssi(hw, pcurrent_stats); + _rtl92c_process_pwdb(hw, pcurrent_stats); + _rtl92c_process_LINK_Q(hw, pcurrent_stats); +} + +void rtl92c_translate_rx_signal_stuff(struct ieee80211_hw *hw, + struct sk_buff *skb, + struct rtl_stats *pstats, + struct rx_desc_92c *pdesc, + struct rx_fwinfo_92c *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; + __le16 fc; + u16 type, cpu_fc; + bool packet_matchbssid, packet_toself, packet_beacon; + + tmp_buf = skb->data + pstats->rx_drvinfo_size + pstats->rx_bufshift; + 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; + packet_matchbssid = + ((IEEE80211_FTYPE_CTL != type) && + (!compare_ether_addr(mac->bssid, + (cpu_fc & IEEE80211_FCTL_TODS) ? + hdr->addr1 : (cpu_fc & IEEE80211_FCTL_FROMDS) ? + hdr->addr2 : hdr->addr3)) && + (!pstats->hwerror) && (!pstats->crc) && (!pstats->icv)); + + packet_toself = packet_matchbssid && + (!compare_ether_addr(praddr, rtlefuse->dev_addr)); + if (ieee80211_is_beacon(fc)) + packet_beacon = true; + _rtl92c_query_rxphystatus(hw, pstats, pdesc, p_drvinfo, + packet_matchbssid, packet_toself, + packet_beacon); + _rtl92c_process_phyinfo(hw, tmp_buf, pstats); +} diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/mac.h b/drivers/net/wireless/rtlwifi/rtl8192cu/mac.h new file mode 100644 index 00000000..bf53652e --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/mac.h @@ -0,0 +1,174 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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. + * + * 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 __RTL92C_MAC_H__ +#define __RTL92C_MAC_H__ + +#define LLT_LAST_ENTRY_OF_TX_PKT_BUFFER 255 +#define DRIVER_EARLY_INT_TIME 0x05 +#define BCN_DMA_ATIME_INT_TIME 0x02 + +void rtl92c_read_chip_version(struct ieee80211_hw *hw); +bool rtl92c_llt_write(struct ieee80211_hw *hw, u32 address, u32 data); +bool rtl92c_init_llt_table(struct ieee80211_hw *hw, u32 boundary); +void rtl92c_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 rtl92c_enable_interrupt(struct ieee80211_hw *hw); +void rtl92c_disable_interrupt(struct ieee80211_hw *hw); +void rtl92c_set_qos(struct ieee80211_hw *hw, int aci); + + +/*--------------------------------------------------------------- + * Hardware init functions + *---------------------------------------------------------------*/ +void rtl92c_set_mac_addr(struct ieee80211_hw *hw, const u8 *addr); +void rtl92c_init_interrupt(struct ieee80211_hw *hw); +void rtl92c_init_driver_info_size(struct ieee80211_hw *hw, u8 size); + +int rtl92c_set_network_type(struct ieee80211_hw *hw, enum nl80211_iftype type); +void rtl92c_init_network_type(struct ieee80211_hw *hw); +void rtl92c_init_adaptive_ctrl(struct ieee80211_hw *hw); +void rtl92c_init_rate_fallback(struct ieee80211_hw *hw); + +void rtl92c_init_edca_param(struct ieee80211_hw *hw, + u16 queue, + u16 txop, + u8 ecwmax, + u8 ecwmin, + u8 aifs); + +void rtl92c_init_edca(struct ieee80211_hw *hw); +void rtl92c_init_ampdu_aggregation(struct ieee80211_hw *hw); +void rtl92c_init_beacon_max_error(struct ieee80211_hw *hw, bool infra_mode); +void rtl92c_init_rdg_setting(struct ieee80211_hw *hw); +void rtl92c_init_retry_function(struct ieee80211_hw *hw); + +void rtl92c_init_beacon_parameters(struct ieee80211_hw *hw, + enum version_8192c version); + +void rtl92c_disable_fast_edca(struct ieee80211_hw *hw); +void rtl92c_set_min_space(struct ieee80211_hw *hw, bool is2T); + +/* For filter */ +u16 rtl92c_get_mgt_filter(struct ieee80211_hw *hw); +void rtl92c_set_mgt_filter(struct ieee80211_hw *hw, u16 filter); +u16 rtl92c_get_ctrl_filter(struct ieee80211_hw *hw); +void rtl92c_set_ctrl_filter(struct ieee80211_hw *hw, u16 filter); +u16 rtl92c_get_data_filter(struct ieee80211_hw *hw); +void rtl92c_set_data_filter(struct ieee80211_hw *hw, u16 filter); + + +u32 rtl92c_get_txdma_status(struct ieee80211_hw *hw); + +struct rx_fwinfo_92c { + 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 rx_desc_92c { + 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:5; /* word 1 */ + 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; /* word 2 */ + u32 frag:4; + u32 nextpktlen:14; + u32 nextind:1; + u32 rsvd:1; + u32 rxmcs:6; /* word 3 */ + 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; /* word 4 */ + u32 tsfl; /* word 5 */ + u32 bufferaddress; /* word 6 */ + u32 bufferaddress64; /* word 7 */ +} __packed; + +enum rtl_desc_qsel rtl92c_map_hwqueue_to_fwqueue(u16 fc, + unsigned int + skb_queue); +void rtl92c_translate_rx_signal_stuff(struct ieee80211_hw *hw, + struct sk_buff *skb, + struct rtl_stats *pstats, + struct rx_desc_92c *pdesc, + struct rx_fwinfo_92c *p_drvinfo); + +/*--------------------------------------------------------------- + * Card disable functions + *---------------------------------------------------------------*/ + + + +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/phy.c b/drivers/net/wireless/rtlwifi/rtl8192cu/phy.c new file mode 100644 index 00000000..34e56308 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/phy.c @@ -0,0 +1,593 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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> + * + *****************************************************************************/ + +#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" + +u32 rtl92cu_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; + struct rtl_phy *rtlphy = &(rtlpriv->phy); + + RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, + "regaddr(%#x), rfpath(%#x), bitmask(%#x)\n", + regaddr, rfpath, bitmask); + if (rtlphy->rf_mode != RF_OP_BY_FW) { + original_value = _rtl92c_phy_rf_serial_read(hw, + rfpath, regaddr); + } else { + original_value = _rtl92c_phy_fw_rf_serial_read(hw, + rfpath, regaddr); + } + bitshift = _rtl92c_phy_calculate_bit_shift(bitmask); + readback_value = (original_value & bitmask) >> bitshift; + RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, + "regaddr(%#x), rfpath(%#x), bitmask(%#x), original_value(%#x)\n", + regaddr, rfpath, bitmask, original_value); + return readback_value; +} + +void rtl92cu_phy_set_rf_reg(struct ieee80211_hw *hw, + enum radio_path rfpath, + u32 regaddr, u32 bitmask, u32 data) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + u32 original_value, bitshift; + + RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, + "regaddr(%#x), bitmask(%#x), data(%#x), rfpath(%#x)\n", + regaddr, bitmask, data, rfpath); + if (rtlphy->rf_mode != RF_OP_BY_FW) { + if (bitmask != RFREG_OFFSET_MASK) { + original_value = _rtl92c_phy_rf_serial_read(hw, + rfpath, + regaddr); + bitshift = _rtl92c_phy_calculate_bit_shift(bitmask); + data = + ((original_value & (~bitmask)) | + (data << bitshift)); + } + _rtl92c_phy_rf_serial_write(hw, rfpath, regaddr, data); + } else { + if (bitmask != RFREG_OFFSET_MASK) { + original_value = _rtl92c_phy_fw_rf_serial_read(hw, + rfpath, + regaddr); + bitshift = _rtl92c_phy_calculate_bit_shift(bitmask); + data = + ((original_value & (~bitmask)) | + (data << bitshift)); + } + _rtl92c_phy_fw_rf_serial_write(hw, rfpath, regaddr, data); + } + RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, + "regaddr(%#x), bitmask(%#x), data(%#x), rfpath(%#x)\n", + regaddr, bitmask, data, rfpath); +} + +bool rtl92cu_phy_mac_config(struct ieee80211_hw *hw) +{ + bool rtstatus; + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + bool is92c = IS_92C_SERIAL(rtlhal->version); + + rtstatus = _rtl92cu_phy_config_mac_with_headerfile(hw); + if (is92c && IS_HARDWARE_TYPE_8192CE(rtlhal)) + rtl_write_byte(rtlpriv, 0x14, 0x71); + return rtstatus; +} + +bool rtl92cu_phy_bb_config(struct ieee80211_hw *hw) +{ + bool rtstatus = true; + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u16 regval; + u8 b_reg_hwparafile = 1; + + _rtl92c_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_AFE_PLL_CTRL, 0x83); + rtl_write_byte(rtlpriv, REG_AFE_PLL_CTRL + 1, 0xdb); + rtl_write_byte(rtlpriv, REG_RF_CTRL, RF_EN | RF_RSTB | RF_SDMRSTB); + if (IS_HARDWARE_TYPE_8192CE(rtlhal)) { + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, FEN_PPLL | FEN_PCIEA | + FEN_DIO_PCIE | FEN_BB_GLB_RSTn | FEN_BBRSTB); + } else if (IS_HARDWARE_TYPE_8192CU(rtlhal)) { + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, FEN_USBA | FEN_USBD | + FEN_BB_GLB_RSTn | FEN_BBRSTB); + rtl_write_byte(rtlpriv, REG_LDOHCI12_CTRL, 0x0f); + } + rtl_write_byte(rtlpriv, REG_AFE_XTAL_CTRL + 1, 0x80); + if (b_reg_hwparafile == 1) + rtstatus = _rtl92c_phy_bb8192c_config_parafile(hw); + return rtstatus; +} + +bool _rtl92cu_phy_config_mac_with_headerfile(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + u32 i; + u32 arraylength; + u32 *ptrarray; + + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "Read Rtl819XMACPHY_Array\n"); + arraylength = rtlphy->hwparam_tables[MAC_REG].length ; + ptrarray = rtlphy->hwparam_tables[MAC_REG].pdata; + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "Img:RTL8192CEMAC_2T_ARRAY\n"); + for (i = 0; i < arraylength; i = i + 2) + rtl_write_byte(rtlpriv, ptrarray[i], (u8) ptrarray[i + 1]); + return true; +} + +bool _rtl92cu_phy_config_bb_with_headerfile(struct ieee80211_hw *hw, + u8 configtype) +{ + int i; + u32 *phy_regarray_table; + u32 *agctab_array_table; + u16 phy_reg_arraylen, agctab_arraylen; + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + + if (IS_92C_SERIAL(rtlhal->version)) { + agctab_arraylen = rtlphy->hwparam_tables[AGCTAB_2T].length; + agctab_array_table = rtlphy->hwparam_tables[AGCTAB_2T].pdata; + phy_reg_arraylen = rtlphy->hwparam_tables[PHY_REG_2T].length; + phy_regarray_table = rtlphy->hwparam_tables[PHY_REG_2T].pdata; + } else { + agctab_arraylen = rtlphy->hwparam_tables[AGCTAB_1T].length; + agctab_array_table = rtlphy->hwparam_tables[AGCTAB_1T].pdata; + phy_reg_arraylen = rtlphy->hwparam_tables[PHY_REG_1T].length; + phy_regarray_table = rtlphy->hwparam_tables[PHY_REG_1T].pdata; + } + if (configtype == BASEBAND_CONFIG_PHY_REG) { + for (i = 0; i < phy_reg_arraylen; i = i + 2) { + if (phy_regarray_table[i] == 0xfe) + mdelay(50); + else if (phy_regarray_table[i] == 0xfd) + mdelay(5); + else if (phy_regarray_table[i] == 0xfc) + mdelay(1); + else if (phy_regarray_table[i] == 0xfb) + udelay(50); + else if (phy_regarray_table[i] == 0xfa) + udelay(5); + else if (phy_regarray_table[i] == 0xf9) + udelay(1); + rtl_set_bbreg(hw, phy_regarray_table[i], MASKDWORD, + phy_regarray_table[i + 1]); + udelay(1); + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + "The phy_regarray_table[0] is %x Rtl819XPHY_REGArray[1] is %x\n", + phy_regarray_table[i], + phy_regarray_table[i + 1]); + } + } else if (configtype == BASEBAND_CONFIG_AGC_TAB) { + for (i = 0; i < agctab_arraylen; i = i + 2) { + rtl_set_bbreg(hw, agctab_array_table[i], MASKDWORD, + agctab_array_table[i + 1]); + udelay(1); + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + "The agctab_array_table[0] is %x Rtl819XPHY_REGArray[1] is %x\n", + agctab_array_table[i], + agctab_array_table[i + 1]); + } + } + return true; +} + +bool _rtl92cu_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw, + u8 configtype) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + int i; + u32 *phy_regarray_table_pg; + u16 phy_regarray_pg_len; + + rtlphy->pwrgroup_cnt = 0; + phy_regarray_pg_len = rtlphy->hwparam_tables[PHY_REG_PG].length; + phy_regarray_table_pg = rtlphy->hwparam_tables[PHY_REG_PG].pdata; + if (configtype == BASEBAND_CONFIG_PHY_REG) { + for (i = 0; i < phy_regarray_pg_len; i = i + 3) { + if (phy_regarray_table_pg[i] == 0xfe) + mdelay(50); + else if (phy_regarray_table_pg[i] == 0xfd) + mdelay(5); + else if (phy_regarray_table_pg[i] == 0xfc) + mdelay(1); + else if (phy_regarray_table_pg[i] == 0xfb) + udelay(50); + else if (phy_regarray_table_pg[i] == 0xfa) + udelay(5); + else if (phy_regarray_table_pg[i] == 0xf9) + udelay(1); + _rtl92c_store_pwrIndex_diffrate_offset(hw, + phy_regarray_table_pg[i], + phy_regarray_table_pg[i + 1], + phy_regarray_table_pg[i + 2]); + } + } else { + RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE, + "configtype != BaseBand_Config_PHY_REG\n"); + } + return true; +} + +bool rtl92cu_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, + enum radio_path rfpath) +{ + int i; + u32 *radioa_array_table; + u32 *radiob_array_table; + u16 radioa_arraylen, radiob_arraylen; + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + + if (IS_92C_SERIAL(rtlhal->version)) { + radioa_arraylen = rtlphy->hwparam_tables[RADIOA_2T].length; + radioa_array_table = rtlphy->hwparam_tables[RADIOA_2T].pdata; + radiob_arraylen = rtlphy->hwparam_tables[RADIOB_2T].length; + radiob_array_table = rtlphy->hwparam_tables[RADIOB_2T].pdata; + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + "Radio_A:RTL8192CERADIOA_2TARRAY\n"); + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + "Radio_B:RTL8192CE_RADIOB_2TARRAY\n"); + } else { + radioa_arraylen = rtlphy->hwparam_tables[RADIOA_1T].length; + radioa_array_table = rtlphy->hwparam_tables[RADIOA_1T].pdata; + radiob_arraylen = rtlphy->hwparam_tables[RADIOB_1T].length; + radiob_array_table = rtlphy->hwparam_tables[RADIOB_1T].pdata; + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + "Radio_A:RTL8192CE_RADIOA_1TARRAY\n"); + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + "Radio_B:RTL8192CE_RADIOB_1TARRAY\n"); + } + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "Radio No %x\n", rfpath); + switch (rfpath) { + case RF90_PATH_A: + for (i = 0; i < radioa_arraylen; i = i + 2) { + if (radioa_array_table[i] == 0xfe) + mdelay(50); + else if (radioa_array_table[i] == 0xfd) + mdelay(5); + else if (radioa_array_table[i] == 0xfc) + mdelay(1); + else if (radioa_array_table[i] == 0xfb) + udelay(50); + else if (radioa_array_table[i] == 0xfa) + udelay(5); + else if (radioa_array_table[i] == 0xf9) + udelay(1); + else { + rtl_set_rfreg(hw, rfpath, radioa_array_table[i], + RFREG_OFFSET_MASK, + radioa_array_table[i + 1]); + udelay(1); + } + } + break; + case RF90_PATH_B: + for (i = 0; i < radiob_arraylen; i = i + 2) { + if (radiob_array_table[i] == 0xfe) { + mdelay(50); + } else if (radiob_array_table[i] == 0xfd) + mdelay(5); + else if (radiob_array_table[i] == 0xfc) + mdelay(1); + else if (radiob_array_table[i] == 0xfb) + udelay(50); + else if (radiob_array_table[i] == 0xfa) + udelay(5); + else if (radiob_array_table[i] == 0xf9) + udelay(1); + else { + rtl_set_rfreg(hw, rfpath, radiob_array_table[i], + RFREG_OFFSET_MASK, + radiob_array_table[i + 1]); + udelay(1); + } + } + break; + case RF90_PATH_C: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "switch case not processed\n"); + break; + case RF90_PATH_D: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "switch case not processed\n"); + break; + } + return true; +} + +void rtl92cu_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(rtlpriv, 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(rtlpriv, 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, RFPGA0_ANALOGPARAMETER2, BIT(10), 1); + 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, RFPGA0_ANALOGPARAMETER2, BIT(10), 0); + 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(rtlpriv, COMP_ERR, DBG_EMERG, + "unknown bandwidth: %#X\n", rtlphy->current_chan_bw); + break; + } + rtl92cu_phy_rf6052_set_bandwidth(hw, rtlphy->current_chan_bw); + rtlphy->set_bwmode_inprogress = false; + RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE, "<==\n"); +} + +void rtl92cu_bb_block_on(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + mutex_lock(&rtlpriv->io.bb_mutex); + rtl_set_bbreg(hw, RFPGA0_RFMOD, BCCKEN, 0x1); + rtl_set_bbreg(hw, RFPGA0_RFMOD, BOFDMEN, 0x1); + mutex_unlock(&rtlpriv->io.bb_mutex); +} + +void _rtl92cu_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); + } +} + +static bool _rtl92cu_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 InitializeCount = 0; + + do { + InitializeCount++; + RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG, + "IPS Set eRf nic enable\n"); + rtstatus = rtl_ps_enable_nic(hw); + } while (!rtstatus && (InitializeCount < 10)); + RT_CLEAR_PS_LEVEL(ppsc, + RT_RF_OFF_LEVL_HALT_NIC); + } else { + RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG, + "Set ERFON sleeped:%d ms\n", + jiffies_to_msecs(jiffies - + ppsc->last_sleep_jiffies)); + ppsc->last_awake_jiffies = jiffies; + rtl92ce_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 == BEACON_QUEUE) { + queue_id++; + continue; + } else { + RT_TRACE(rtlpriv, 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(rtlpriv, COMP_ERR, DBG_WARNING, + "ERFOFF: %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(rtlpriv, COMP_RF, DBG_DMESG, + "IPS Set eRf nic disable\n"); + 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) + return false; + 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(rtlpriv, 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(rtlpriv, COMP_ERR, DBG_WARNING, + "ERFSLEEP: %d times TcbBusyQueue[%d] = %d !\n", + MAX_DOZE_WAITING_TIMES_9x, + queue_id, + skb_queue_len(&ring->queue)); + break; + } + } + RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG, + "Set ERFSLEEP awaked:%d ms\n", + jiffies_to_msecs(jiffies - ppsc->last_awake_jiffies)); + ppsc->last_sleep_jiffies = jiffies; + _rtl92c_phy_set_rf_sleep(hw); + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "switch case not processed\n"); + bresult = false; + break; + } + if (bresult) + ppsc->rfpwr_state = rfpwr_state; + return bresult; +} + +bool rtl92cu_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 = _rtl92cu_phy_set_rf_power_state(hw, rfpwr_state); + return bresult; +} diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/phy.h b/drivers/net/wireless/rtlwifi/rtl8192cu/phy.h new file mode 100644 index 00000000..42b06866 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/phy.h @@ -0,0 +1,50 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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> + * + *****************************************************************************/ + +#include "../rtl8192ce/phy.h" + +void rtl92cu_bb_block_on(struct ieee80211_hw *hw); +bool rtl8192_phy_check_is_legal_rfpath(struct ieee80211_hw *hw, u32 rfpath); +void rtl92c_phy_set_io(struct ieee80211_hw *hw); +bool _rtl92cu_phy_config_mac_with_headerfile(struct ieee80211_hw *hw); +bool rtl92cu_phy_bb_config(struct ieee80211_hw *hw); +u32 rtl92cu_phy_query_rf_reg(struct ieee80211_hw *hw, + enum radio_path rfpath, u32 regaddr, u32 bitmask); +void rtl92cu_phy_set_rf_reg(struct ieee80211_hw *hw, + enum radio_path rfpath, + u32 regaddr, u32 bitmask, u32 data); +bool rtl92cu_phy_mac_config(struct ieee80211_hw *hw); +bool _rtl92cu_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw, + u8 configtype); +void _rtl92cu_phy_lc_calibrate(struct ieee80211_hw *hw, bool is2t); +bool _rtl92cu_phy_config_bb_with_headerfile(struct ieee80211_hw *hw, + u8 configtype); +void rtl92cu_phy_set_bw_mode_callback(struct ieee80211_hw *hw); +bool rtl92cu_phy_set_rf_power_state(struct ieee80211_hw *hw, + enum rf_pwrstate rfpwr_state); diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/reg.h b/drivers/net/wireless/rtlwifi/rtl8192cu/reg.h new file mode 100644 index 00000000..8b81465c --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/reg.h @@ -0,0 +1,30 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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> + * + *****************************************************************************/ + +#include "../rtl8192ce/reg.h" diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/rf.c b/drivers/net/wireless/rtlwifi/rtl8192cu/rf.c new file mode 100644 index 00000000..506b9a07 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/rf.c @@ -0,0 +1,492 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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> + * + *****************************************************************************/ + +#include "../wifi.h" +#include "reg.h" +#include "def.h" +#include "phy.h" +#include "rf.h" +#include "dm.h" + +static bool _rtl92c_phy_rf6052_config_parafile(struct ieee80211_hw *hw); + +void rtl92cu_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) | 0x0400); + rtl_set_rfreg(hw, RF90_PATH_A, 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)); + rtl_set_rfreg(hw, RF90_PATH_A, RF_CHNLBW, RFREG_OFFSET_MASK, + rtlphy->rfreg_chnlval[0]); + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "unknown bandwidth: %#X\n", bandwidth); + break; + } +} + +void rtl92cu_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw, + u8 *ppowerlevel) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + u32 tx_agc[2] = { 0, 0 }, tmpval = 0; + bool turbo_scanoff = false; + u8 idx1, idx2; + u8 *ptr; + + if (rtlhal->interface == INTF_PCI) { + if (rtlefuse->eeprom_regulatory != 0) + turbo_scanoff = true; + } else { + if ((rtlefuse->eeprom_regulatory != 0) || + (rtlefuse->external_pa)) + turbo_scanoff = true; + } + if (mac->act_scanning) { + tx_agc[RF90_PATH_A] = 0x3f3f3f3f; + tx_agc[RF90_PATH_B] = 0x3f3f3f3f; + if (turbo_scanoff) { + for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B; idx1++) { + tx_agc[idx1] = ppowerlevel[idx1] | + (ppowerlevel[idx1] << 8) | + (ppowerlevel[idx1] << 16) | + (ppowerlevel[idx1] << 24); + if (rtlhal->interface == INTF_USB) { + if (tx_agc[idx1] > 0x20 && + rtlefuse->external_pa) + tx_agc[idx1] = 0x20; + } + } + } + } else { + if (rtlpriv->dm.dynamic_txhighpower_lvl == + TXHIGHPWRLEVEL_LEVEL1) { + tx_agc[RF90_PATH_A] = 0x10101010; + tx_agc[RF90_PATH_B] = 0x10101010; + } else if (rtlpriv->dm.dynamic_txhighpower_lvl == + TXHIGHPWRLEVEL_LEVEL1) { + tx_agc[RF90_PATH_A] = 0x00000000; + tx_agc[RF90_PATH_B] = 0x00000000; + } else{ + for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B; idx1++) { + tx_agc[idx1] = ppowerlevel[idx1] | + (ppowerlevel[idx1] << 8) | + (ppowerlevel[idx1] << 16) | + (ppowerlevel[idx1] << 24); + } + if (rtlefuse->eeprom_regulatory == 0) { + tmpval = (rtlphy->mcs_txpwrlevel_origoffset + [0][6]) + + (rtlphy->mcs_txpwrlevel_origoffset + [0][7] << 8); + tx_agc[RF90_PATH_A] += tmpval; + tmpval = (rtlphy->mcs_txpwrlevel_origoffset + [0][14]) + + (rtlphy->mcs_txpwrlevel_origoffset + [0][15] << 24); + tx_agc[RF90_PATH_B] += tmpval; + } + } + } + for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B; idx1++) { + ptr = (u8 *) (&(tx_agc[idx1])); + for (idx2 = 0; idx2 < 4; idx2++) { + if (*ptr > RF6052_MAX_TX_PWR) + *ptr = RF6052_MAX_TX_PWR; + ptr++; + } + } + tmpval = tx_agc[RF90_PATH_A] & 0xff; + rtl_set_bbreg(hw, RTXAGC_A_CCK1_MCS32, MASKBYTE1, tmpval); + + RTPRINT(rtlpriv, FPHY, PHY_TXPWR, + "CCK PWR 1M (rf-A) = 0x%x (reg 0x%x)\n", + tmpval, RTXAGC_A_CCK1_MCS32); + + tmpval = tx_agc[RF90_PATH_A] >> 8; + if (mac->mode == WIRELESS_MODE_B) + tmpval = tmpval & 0xff00ffff; + rtl_set_bbreg(hw, RTXAGC_B_CCK11_A_CCK2_11, 0xffffff00, tmpval); + RTPRINT(rtlpriv, FPHY, PHY_TXPWR, + "CCK PWR 2~11M (rf-A) = 0x%x (reg 0x%x)\n", + tmpval, RTXAGC_B_CCK11_A_CCK2_11); + tmpval = tx_agc[RF90_PATH_B] >> 24; + rtl_set_bbreg(hw, RTXAGC_B_CCK11_A_CCK2_11, MASKBYTE0, tmpval); + RTPRINT(rtlpriv, FPHY, PHY_TXPWR, + "CCK PWR 11M (rf-B) = 0x%x (reg 0x%x)\n", + tmpval, RTXAGC_B_CCK11_A_CCK2_11); + tmpval = tx_agc[RF90_PATH_B] & 0x00ffffff; + rtl_set_bbreg(hw, RTXAGC_B_CCK1_55_MCS32, 0xffffff00, tmpval); + RTPRINT(rtlpriv, FPHY, PHY_TXPWR, + "CCK PWR 1~5.5M (rf-B) = 0x%x (reg 0x%x)\n", + tmpval, RTXAGC_B_CCK1_55_MCS32); +} + +static void rtl92c_phy_get_power_base(struct ieee80211_hw *hw, + u8 *ppowerlevel, u8 channel, + u32 *ofdmbase, u32 *mcsbase) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + u32 powerBase0, powerBase1; + u8 legacy_pwrdiff = 0, ht20_pwrdiff = 0; + u8 i, powerlevel[2]; + + for (i = 0; i < 2; i++) { + powerlevel[i] = ppowerlevel[i]; + legacy_pwrdiff = rtlefuse->txpwr_legacyhtdiff[i][channel - 1]; + powerBase0 = powerlevel[i] + legacy_pwrdiff; + powerBase0 = (powerBase0 << 24) | (powerBase0 << 16) | + (powerBase0 << 8) | powerBase0; + *(ofdmbase + i) = powerBase0; + RTPRINT(rtlpriv, FPHY, PHY_TXPWR, + " [OFDM power base index rf(%c) = 0x%x]\n", + i == 0 ? 'A' : 'B', *(ofdmbase + i)); + } + for (i = 0; i < 2; i++) { + if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20) { + ht20_pwrdiff = rtlefuse->txpwr_ht20diff[i][channel - 1]; + powerlevel[i] += ht20_pwrdiff; + } + powerBase1 = powerlevel[i]; + powerBase1 = (powerBase1 << 24) | + (powerBase1 << 16) | (powerBase1 << 8) | powerBase1; + *(mcsbase + i) = powerBase1; + RTPRINT(rtlpriv, FPHY, PHY_TXPWR, + " [MCS power base index rf(%c) = 0x%x]\n", + i == 0 ? 'A' : 'B', *(mcsbase + i)); + } +} + +static void _rtl92c_get_txpower_writeval_by_regulatory(struct ieee80211_hw *hw, + u8 channel, u8 index, + u32 *powerBase0, + u32 *powerBase1, + u32 *p_outwriteval) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + u8 i, chnlgroup = 0, pwr_diff_limit[4]; + u32 writeVal, customer_limit, rf; + + for (rf = 0; rf < 2; rf++) { + switch (rtlefuse->eeprom_regulatory) { + case 0: + chnlgroup = 0; + writeVal = rtlphy->mcs_txpwrlevel_origoffset + [chnlgroup][index + (rf ? 8 : 0)] + + ((index < 2) ? powerBase0[rf] : powerBase1[rf]); + RTPRINT(rtlpriv, FPHY, PHY_TXPWR, + "RTK better performance,writeVal(%c) = 0x%x\n", + rf == 0 ? 'A' : 'B', writeVal); + break; + case 1: + if (rtlphy->pwrgroup_cnt == 1) + chnlgroup = 0; + if (rtlphy->pwrgroup_cnt >= 3) { + if (channel <= 3) + chnlgroup = 0; + else if (channel >= 4 && channel <= 9) + chnlgroup = 1; + else if (channel > 9) + chnlgroup = 2; + if (rtlphy->current_chan_bw == + HT_CHANNEL_WIDTH_20) + chnlgroup++; + else + chnlgroup += 4; + } + writeVal = rtlphy->mcs_txpwrlevel_origoffset + [chnlgroup][index + + (rf ? 8 : 0)] + + ((index < 2) ? powerBase0[rf] : + powerBase1[rf]); + RTPRINT(rtlpriv, FPHY, PHY_TXPWR, + "Realtek regulatory, 20MHz, writeVal(%c) = 0x%x\n", + rf == 0 ? 'A' : 'B', writeVal); + break; + case 2: + writeVal = ((index < 2) ? powerBase0[rf] : + powerBase1[rf]); + RTPRINT(rtlpriv, FPHY, PHY_TXPWR, + "Better regulatory,writeVal(%c) = 0x%x\n", + rf == 0 ? 'A' : 'B', writeVal); + break; + case 3: + chnlgroup = 0; + if (rtlphy->current_chan_bw == + HT_CHANNEL_WIDTH_20_40) { + RTPRINT(rtlpriv, FPHY, PHY_TXPWR, + "customer's limit, 40MHzrf(%c) = 0x%x\n", + rf == 0 ? 'A' : 'B', + rtlefuse->pwrgroup_ht40[rf] + [channel - 1]); + } else { + RTPRINT(rtlpriv, FPHY, PHY_TXPWR, + "customer's limit, 20MHz rf(%c) = 0x%x\n", + rf == 0 ? 'A' : 'B', + rtlefuse->pwrgroup_ht20[rf] + [channel - 1]); + } + for (i = 0; i < 4; i++) { + pwr_diff_limit[i] = + (u8) ((rtlphy->mcs_txpwrlevel_origoffset + [chnlgroup][index + (rf ? 8 : 0)] + & (0x7f << (i * 8))) >> (i * 8)); + if (rtlphy->current_chan_bw == + HT_CHANNEL_WIDTH_20_40) { + if (pwr_diff_limit[i] > + rtlefuse->pwrgroup_ht40[rf] + [channel - 1]) + pwr_diff_limit[i] = rtlefuse-> + pwrgroup_ht40[rf] + [channel - 1]; + } else { + if (pwr_diff_limit[i] > + rtlefuse->pwrgroup_ht20[rf] + [channel - 1]) + pwr_diff_limit[i] = + rtlefuse->pwrgroup_ht20[rf] + [channel - 1]; + } + } + customer_limit = (pwr_diff_limit[3] << 24) | + (pwr_diff_limit[2] << 16) | + (pwr_diff_limit[1] << 8) | (pwr_diff_limit[0]); + RTPRINT(rtlpriv, FPHY, PHY_TXPWR, + "Customer's limit rf(%c) = 0x%x\n", + rf == 0 ? 'A' : 'B', customer_limit); + writeVal = customer_limit + ((index < 2) ? + powerBase0[rf] : powerBase1[rf]); + RTPRINT(rtlpriv, FPHY, PHY_TXPWR, + "Customer, writeVal rf(%c)= 0x%x\n", + rf == 0 ? 'A' : 'B', writeVal); + break; + default: + chnlgroup = 0; + writeVal = rtlphy->mcs_txpwrlevel_origoffset[chnlgroup] + [index + (rf ? 8 : 0)] + ((index < 2) ? + powerBase0[rf] : powerBase1[rf]); + RTPRINT(rtlpriv, FPHY, PHY_TXPWR, + "RTK better performance, writeValrf(%c) = 0x%x\n", + rf == 0 ? 'A' : 'B', writeVal); + break; + } + if (rtlpriv->dm.dynamic_txhighpower_lvl == + TXHIGHPWRLEVEL_LEVEL1) + writeVal = 0x14141414; + else if (rtlpriv->dm.dynamic_txhighpower_lvl == + TXHIGHPWRLEVEL_LEVEL2) + writeVal = 0x00000000; + if (rtlpriv->dm.dynamic_txhighpower_lvl == TXHIGHPWRLEVEL_BT1) + writeVal = writeVal - 0x06060606; + else if (rtlpriv->dm.dynamic_txhighpower_lvl == + TXHIGHPWRLEVEL_BT2) + writeVal = writeVal; + *(p_outwriteval + rf) = writeVal; + } +} + +static void _rtl92c_write_ofdm_power_reg(struct ieee80211_hw *hw, + u8 index, u32 *pValue) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + u16 regoffset_a[6] = { + RTXAGC_A_RATE18_06, RTXAGC_A_RATE54_24, + RTXAGC_A_MCS03_MCS00, RTXAGC_A_MCS07_MCS04, + RTXAGC_A_MCS11_MCS08, RTXAGC_A_MCS15_MCS12 + }; + u16 regoffset_b[6] = { + RTXAGC_B_RATE18_06, RTXAGC_B_RATE54_24, + RTXAGC_B_MCS03_MCS00, RTXAGC_B_MCS07_MCS04, + RTXAGC_B_MCS11_MCS08, RTXAGC_B_MCS15_MCS12 + }; + u8 i, rf, pwr_val[4]; + u32 writeVal; + u16 regoffset; + + for (rf = 0; rf < 2; rf++) { + writeVal = pValue[rf]; + for (i = 0; i < 4; i++) { + pwr_val[i] = (u8)((writeVal & (0x7f << (i * 8))) >> + (i * 8)); + if (pwr_val[i] > RF6052_MAX_TX_PWR) + pwr_val[i] = RF6052_MAX_TX_PWR; + } + writeVal = (pwr_val[3] << 24) | (pwr_val[2] << 16) | + (pwr_val[1] << 8) | pwr_val[0]; + if (rf == 0) + regoffset = regoffset_a[index]; + else + regoffset = regoffset_b[index]; + rtl_set_bbreg(hw, regoffset, MASKDWORD, writeVal); + RTPRINT(rtlpriv, FPHY, PHY_TXPWR, + "Set 0x%x = %08x\n", regoffset, writeVal); + if (((get_rf_type(rtlphy) == RF_2T2R) && + (regoffset == RTXAGC_A_MCS15_MCS12 || + regoffset == RTXAGC_B_MCS15_MCS12)) || + ((get_rf_type(rtlphy) != RF_2T2R) && + (regoffset == RTXAGC_A_MCS07_MCS04 || + regoffset == RTXAGC_B_MCS07_MCS04))) { + writeVal = pwr_val[3]; + if (regoffset == RTXAGC_A_MCS15_MCS12 || + regoffset == RTXAGC_A_MCS07_MCS04) + regoffset = 0xc90; + if (regoffset == RTXAGC_B_MCS15_MCS12 || + regoffset == RTXAGC_B_MCS07_MCS04) + regoffset = 0xc98; + for (i = 0; i < 3; i++) { + writeVal = (writeVal > 6) ? (writeVal - 6) : 0; + rtl_write_byte(rtlpriv, (u32)(regoffset + i), + (u8)writeVal); + } + } + } +} + +void rtl92cu_phy_rf6052_set_ofdm_txpower(struct ieee80211_hw *hw, + u8 *ppowerlevel, u8 channel) +{ + u32 writeVal[2], powerBase0[2], powerBase1[2]; + u8 index = 0; + + rtl92c_phy_get_power_base(hw, ppowerlevel, + channel, &powerBase0[0], &powerBase1[0]); + for (index = 0; index < 6; index++) { + _rtl92c_get_txpower_writeval_by_regulatory(hw, + channel, index, + &powerBase0[0], + &powerBase1[0], + &writeVal[0]); + _rtl92c_write_ofdm_power_reg(hw, index, &writeVal[0]); + } +} + +bool rtl92cu_phy_rf6052_config(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + bool rtstatus = true; + u8 b_reg_hwparafile = 1; + + if (rtlphy->rf_type == RF_1T1R) + rtlphy->num_total_rfpath = 1; + else + rtlphy->num_total_rfpath = 2; + if (b_reg_hwparafile == 1) + rtstatus = _rtl92c_phy_rf6052_config_parafile(hw); + return rtstatus; +} + +static bool _rtl92c_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 = rtl92cu_phy_config_rf_with_headerfile(hw, + (enum radio_path) rfpath); + break; + case RF90_PATH_B: + rtstatus = rtl92cu_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(rtlpriv, COMP_INIT, DBG_TRACE, + "Radio[%d] Fail!!", rfpath); + goto phy_rf_cfg_fail; + } + } + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "<---\n"); + return rtstatus; +phy_rf_cfg_fail: + return rtstatus; +} diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/rf.h b/drivers/net/wireless/rtlwifi/rtl8192cu/rf.h new file mode 100644 index 00000000..090fd33a --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/rf.h @@ -0,0 +1,51 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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 __RTL92CU_RF_H__ +#define __RTL92CU_RF_H__ + +#define RF6052_MAX_TX_PWR 0x3F +#define RF6052_MAX_REG 0x3F +#define RF6052_MAX_PATH 2 + +extern void rtl92cu_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw, + u8 bandwidth); +extern void rtl92c_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw, + u8 *ppowerlevel); +extern void rtl92c_phy_rf6052_set_ofdm_txpower(struct ieee80211_hw *hw, + u8 *ppowerlevel, u8 channel); +bool rtl92cu_phy_rf6052_config(struct ieee80211_hw *hw); +bool rtl92cu_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, + enum radio_path rfpath); +void rtl92cu_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw, + u8 *ppowerlevel); +void rtl92cu_phy_rf6052_set_ofdm_txpower(struct ieee80211_hw *hw, + u8 *ppowerlevel, u8 channel); + +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c new file mode 100644 index 00000000..5bd40856 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c @@ -0,0 +1,380 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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. + * + * 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> + * + *****************************************************************************/ + +#include "../wifi.h" +#include "../core.h" +#include "../usb.h" +#include "../efuse.h" +#include "reg.h" +#include "def.h" +#include "phy.h" +#include "mac.h" +#include "dm.h" +#include "rf.h" +#include "sw.h" +#include "trx.h" +#include "led.h" +#include "hw.h" +#include <linux/module.h> + +MODULE_AUTHOR("Georgia <georgia@realtek.com>"); +MODULE_AUTHOR("Ziv Huang <ziv_huang@realtek.com>"); +MODULE_AUTHOR("Larry Finger <Larry.Finger@lwfinger.net>"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Realtek 8192C/8188C 802.11n USB wireless"); +MODULE_FIRMWARE("rtlwifi/rtl8192cufw.bin"); + +static int rtl92cu_init_sw_vars(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + int err; + + rtlpriv->dm.dm_initialgain_enable = true; + rtlpriv->dm.dm_flag = 0; + rtlpriv->dm.disable_framebursting = false; + rtlpriv->dm.thermalvalue = 0; + rtlpriv->dbg.global_debuglevel = rtlpriv->cfg->mod_params->debug; + + /* for firmware buf */ + rtlpriv->rtlhal.pfirmware = vzalloc(0x4000); + if (!rtlpriv->rtlhal.pfirmware) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "Can't alloc buffer for fw\n"); + return 1; + } + + pr_info("Loading firmware %s\n", rtlpriv->cfg->fw_name); + rtlpriv->max_fw_size = 0x4000; + err = request_firmware_nowait(THIS_MODULE, 1, + rtlpriv->cfg->fw_name, rtlpriv->io.dev, + GFP_KERNEL, hw, rtl_fw_cb); + + + return 0; +} + +static void rtl92cu_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; + } +} + +static struct rtl_hal_ops rtl8192cu_hal_ops = { + .init_sw_vars = rtl92cu_init_sw_vars, + .deinit_sw_vars = rtl92cu_deinit_sw_vars, + .read_chip_version = rtl92c_read_chip_version, + .read_eeprom_info = rtl92cu_read_eeprom_info, + .enable_interrupt = rtl92c_enable_interrupt, + .disable_interrupt = rtl92c_disable_interrupt, + .hw_init = rtl92cu_hw_init, + .hw_disable = rtl92cu_card_disable, + .set_network_type = rtl92cu_set_network_type, + .set_chk_bssid = rtl92cu_set_check_bssid, + .set_qos = rtl92c_set_qos, + .set_bcn_reg = rtl92cu_set_beacon_related_registers, + .set_bcn_intv = rtl92cu_set_beacon_interval, + .update_interrupt_mask = rtl92cu_update_interrupt_mask, + .get_hw_reg = rtl92cu_get_hw_reg, + .set_hw_reg = rtl92cu_set_hw_reg, + .update_rate_tbl = rtl92cu_update_hal_rate_table, + .update_rate_mask = rtl92cu_update_hal_rate_mask, + .fill_tx_desc = rtl92cu_tx_fill_desc, + .fill_fake_txdesc = rtl92cu_fill_fake_txdesc, + .fill_tx_cmddesc = rtl92cu_tx_fill_cmddesc, + .cmd_send_packet = rtl92cu_cmd_send_packet, + .query_rx_desc = rtl92cu_rx_query_desc, + .set_channel_access = rtl92cu_update_channel_access_setting, + .radio_onoff_checking = rtl92cu_gpio_radio_on_off_checking, + .set_bw_mode = rtl92c_phy_set_bw_mode, + .switch_channel = rtl92c_phy_sw_chnl, + .dm_watchdog = rtl92c_dm_watchdog, + .scan_operation_backup = rtl92c_phy_scan_operation_backup, + .set_rf_power_state = rtl92cu_phy_set_rf_power_state, + .led_control = rtl92cu_led_control, + .enable_hw_sec = rtl92cu_enable_hw_security_config, + .set_key = rtl92c_set_key, + .init_sw_leds = rtl92cu_init_sw_leds, + .deinit_sw_leds = rtl92cu_deinit_sw_leds, + .get_bbreg = rtl92c_phy_query_bb_reg, + .set_bbreg = rtl92c_phy_set_bb_reg, + .get_rfreg = rtl92cu_phy_query_rf_reg, + .set_rfreg = rtl92cu_phy_set_rf_reg, + .phy_rf6052_config = rtl92cu_phy_rf6052_config, + .phy_rf6052_set_cck_txpower = rtl92cu_phy_rf6052_set_cck_txpower, + .phy_rf6052_set_ofdm_txpower = rtl92cu_phy_rf6052_set_ofdm_txpower, + .config_bb_with_headerfile = _rtl92cu_phy_config_bb_with_headerfile, + .config_bb_with_pgheaderfile = _rtl92cu_phy_config_bb_with_pgheaderfile, + .phy_lc_calibrate = _rtl92cu_phy_lc_calibrate, + .phy_set_bw_mode_callback = rtl92cu_phy_set_bw_mode_callback, + .dm_dynamic_txpower = rtl92cu_dm_dynamic_txpower, +}; + +static struct rtl_mod_params rtl92cu_mod_params = { + .sw_crypto = 0, + .debug = DBG_EMERG, +}; + +module_param_named(swenc, rtl92cu_mod_params.sw_crypto, bool, 0444); +module_param_named(debug, rtl92cu_mod_params.debug, int, 0444); +MODULE_PARM_DESC(swenc, "Set to 1 for software crypto (default 0)\n"); +MODULE_PARM_DESC(debug, "Set debug level (0-5) (default 0)"); + +static struct rtl_hal_usbint_cfg rtl92cu_interface_cfg = { + /* rx */ + .in_ep_num = RTL92C_USB_BULK_IN_NUM, + .rx_urb_num = RTL92C_NUM_RX_URBS, + .rx_max_size = RTL92C_SIZE_MAX_RX_BUFFER, + .usb_rx_hdl = rtl8192cu_rx_hdl, + .usb_rx_segregate_hdl = NULL, /* rtl8192c_rx_segregate_hdl; */ + /* tx */ + .usb_tx_cleanup = rtl8192c_tx_cleanup, + .usb_tx_post_hdl = rtl8192c_tx_post_hdl, + .usb_tx_aggregate_hdl = rtl8192c_tx_aggregate_hdl, + /* endpoint mapping */ + .usb_endpoint_mapping = rtl8192cu_endpoint_mapping, + .usb_mq_to_hwq = rtl8192cu_mq_to_hwq, +}; + +static struct rtl_hal_cfg rtl92cu_hal_cfg = { + .name = "rtl92c_usb", + .fw_name = "rtlwifi/rtl8192cufw.bin", + .ops = &rtl8192cu_hal_ops, + .mod_params = &rtl92cu_mod_params, + .usb_interface_cfg = &rtl92cu_interface_cfg, + + .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[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] = EFUSE_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[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, + .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_BCNINT, + .maps[RTL_IMR_RXFOVW] = IMR_RXFOVW, + .maps[RTL_IMR_RDU] = IMR_RDU, + .maps[RTL_IMR_ATIMEND] = IMR_ATIMEND, + .maps[RTL_IMR_BDOK] = IMR_BDOK, + .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_BCNINT | IMR_TBDOK | IMR_TBDER), + + .maps[RTL_RC_CCK_RATE1M] = DESC92_RATE1M, + .maps[RTL_RC_CCK_RATE2M] = DESC92_RATE2M, + .maps[RTL_RC_CCK_RATE5_5M] = DESC92_RATE5_5M, + .maps[RTL_RC_CCK_RATE11M] = DESC92_RATE11M, + .maps[RTL_RC_OFDM_RATE6M] = DESC92_RATE6M, + .maps[RTL_RC_OFDM_RATE9M] = DESC92_RATE9M, + .maps[RTL_RC_OFDM_RATE12M] = DESC92_RATE12M, + .maps[RTL_RC_OFDM_RATE18M] = DESC92_RATE18M, + .maps[RTL_RC_OFDM_RATE24M] = DESC92_RATE24M, + .maps[RTL_RC_OFDM_RATE36M] = DESC92_RATE36M, + .maps[RTL_RC_OFDM_RATE48M] = DESC92_RATE48M, + .maps[RTL_RC_OFDM_RATE54M] = DESC92_RATE54M, + .maps[RTL_RC_HT_RATEMCS7] = DESC92_RATEMCS7, + .maps[RTL_RC_HT_RATEMCS15] = DESC92_RATEMCS15, +}; + +#define USB_VENDER_ID_REALTEK 0x0bda + +/* 2010-10-19 DID_USB_V3.4 */ +static struct usb_device_id rtl8192c_usb_ids[] = { + + /*=== Realtek demoboard ===*/ + /* Default ID */ + {RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x8191, rtl92cu_hal_cfg)}, + + /****** 8188CU ********/ + /* RTL8188CTV */ + {RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x018a, rtl92cu_hal_cfg)}, + /* 8188CE-VAU USB minCard */ + {RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x8170, rtl92cu_hal_cfg)}, + /* 8188cu 1*1 dongle */ + {RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x8176, rtl92cu_hal_cfg)}, + /* 8188cu 1*1 dongle, (b/g mode only) */ + {RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x8177, rtl92cu_hal_cfg)}, + /* 8188cu Slim Solo */ + {RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x817a, rtl92cu_hal_cfg)}, + /* 8188cu Slim Combo */ + {RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x817b, rtl92cu_hal_cfg)}, + /* 8188RU High-power USB Dongle */ + {RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x817d, rtl92cu_hal_cfg)}, + /* 8188CE-VAU USB minCard (b/g mode only) */ + {RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x817e, rtl92cu_hal_cfg)}, + /* 8188RU in Alfa AWUS036NHR */ + {RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x817f, rtl92cu_hal_cfg)}, + /* RTL8188CUS-VL */ + {RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x818a, rtl92cu_hal_cfg)}, + /* 8188 Combo for BC4 */ + {RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x8754, rtl92cu_hal_cfg)}, + + /****** 8192CU ********/ + /* 8192cu 2*2 */ + {RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x8178, rtl92cu_hal_cfg)}, + /* 8192CE-VAU USB minCard */ + {RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x817c, rtl92cu_hal_cfg)}, + + /*=== Customer ID ===*/ + /****** 8188CU ********/ + {RTL_USB_DEVICE(0x050d, 0x1102, rtl92cu_hal_cfg)}, /*Belkin - Edimax*/ + {RTL_USB_DEVICE(0x06f8, 0xe033, rtl92cu_hal_cfg)}, /*Hercules - Edimax*/ + {RTL_USB_DEVICE(0x07b8, 0x8188, rtl92cu_hal_cfg)}, /*Abocom - Abocom*/ + {RTL_USB_DEVICE(0x07b8, 0x8189, rtl92cu_hal_cfg)}, /*Funai - Abocom*/ + {RTL_USB_DEVICE(0x0846, 0x9041, rtl92cu_hal_cfg)}, /*NetGear WNA1000M*/ + {RTL_USB_DEVICE(0x0bda, 0x5088, rtl92cu_hal_cfg)}, /*Thinkware-CC&C*/ + {RTL_USB_DEVICE(0x0df6, 0x0052, rtl92cu_hal_cfg)}, /*Sitecom - Edimax*/ + {RTL_USB_DEVICE(0x0df6, 0x005c, rtl92cu_hal_cfg)}, /*Sitecom - Edimax*/ + {RTL_USB_DEVICE(0x0eb0, 0x9071, rtl92cu_hal_cfg)}, /*NO Brand - Etop*/ + {RTL_USB_DEVICE(0x4856, 0x0091, rtl92cu_hal_cfg)}, /*NetweeN - Feixun*/ + /* HP - Lite-On ,8188CUS Slim Combo */ + {RTL_USB_DEVICE(0x103c, 0x1629, rtl92cu_hal_cfg)}, + {RTL_USB_DEVICE(0x13d3, 0x3357, rtl92cu_hal_cfg)}, /* AzureWave */ + {RTL_USB_DEVICE(0x2001, 0x3308, rtl92cu_hal_cfg)}, /*D-Link - Alpha*/ + {RTL_USB_DEVICE(0x2019, 0x4902, rtl92cu_hal_cfg)}, /*Planex - Etop*/ + {RTL_USB_DEVICE(0x2019, 0xab2a, rtl92cu_hal_cfg)}, /*Planex - Abocom*/ + /*SW-WF02-AD15 -Abocom*/ + {RTL_USB_DEVICE(0x2019, 0xab2e, rtl92cu_hal_cfg)}, + {RTL_USB_DEVICE(0x2019, 0xed17, rtl92cu_hal_cfg)}, /*PCI - Edimax*/ + {RTL_USB_DEVICE(0x20f4, 0x648b, rtl92cu_hal_cfg)}, /*TRENDnet - Cameo*/ + {RTL_USB_DEVICE(0x7392, 0x7811, rtl92cu_hal_cfg)}, /*Edimax - Edimax*/ + {RTL_USB_DEVICE(0x13d3, 0x3358, rtl92cu_hal_cfg)}, /*Azwave 8188CE-VAU*/ + /* Russian customer -Azwave (8188CE-VAU b/g mode only) */ + {RTL_USB_DEVICE(0x13d3, 0x3359, rtl92cu_hal_cfg)}, + {RTL_USB_DEVICE(0x4855, 0x0090, rtl92cu_hal_cfg)}, /* Feixun */ + {RTL_USB_DEVICE(0x4855, 0x0091, rtl92cu_hal_cfg)}, /* NetweeN-Feixun */ + {RTL_USB_DEVICE(0x9846, 0x9041, rtl92cu_hal_cfg)}, /* Netgear Cameo */ + + /****** 8188 RU ********/ + /* Netcore */ + {RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x317f, rtl92cu_hal_cfg)}, + + /****** 8188CUS Slim Solo********/ + {RTL_USB_DEVICE(0x04f2, 0xaff7, rtl92cu_hal_cfg)}, /*Xavi*/ + {RTL_USB_DEVICE(0x04f2, 0xaff9, rtl92cu_hal_cfg)}, /*Xavi*/ + {RTL_USB_DEVICE(0x04f2, 0xaffa, rtl92cu_hal_cfg)}, /*Xavi*/ + + /****** 8188CUS Slim Combo ********/ + {RTL_USB_DEVICE(0x04f2, 0xaff8, rtl92cu_hal_cfg)}, /*Xavi*/ + {RTL_USB_DEVICE(0x04f2, 0xaffb, rtl92cu_hal_cfg)}, /*Xavi*/ + {RTL_USB_DEVICE(0x04f2, 0xaffc, rtl92cu_hal_cfg)}, /*Xavi*/ + {RTL_USB_DEVICE(0x2019, 0x1201, rtl92cu_hal_cfg)}, /*Planex-Vencer*/ + + /****** 8192CU ********/ + {RTL_USB_DEVICE(0x050d, 0x2102, rtl92cu_hal_cfg)}, /*Belcom-Sercomm*/ + {RTL_USB_DEVICE(0x050d, 0x2103, rtl92cu_hal_cfg)}, /*Belcom-Edimax*/ + {RTL_USB_DEVICE(0x0586, 0x341f, rtl92cu_hal_cfg)}, /*Zyxel -Abocom*/ + {RTL_USB_DEVICE(0x07aa, 0x0056, rtl92cu_hal_cfg)}, /*ATKK-Gemtek*/ + {RTL_USB_DEVICE(0x07b8, 0x8178, rtl92cu_hal_cfg)}, /*Funai -Abocom*/ + {RTL_USB_DEVICE(0x0846, 0x9021, rtl92cu_hal_cfg)}, /*Netgear-Sercomm*/ + {RTL_USB_DEVICE(0x0b05, 0x17ab, rtl92cu_hal_cfg)}, /*ASUS-Edimax*/ + {RTL_USB_DEVICE(0x0bda, 0x8186, rtl92cu_hal_cfg)}, /*Realtek 92CE-VAU*/ + {RTL_USB_DEVICE(0x0df6, 0x0061, rtl92cu_hal_cfg)}, /*Sitecom-Edimax*/ + {RTL_USB_DEVICE(0x0e66, 0x0019, rtl92cu_hal_cfg)}, /*Hawking-Edimax*/ + {RTL_USB_DEVICE(0x2001, 0x3307, rtl92cu_hal_cfg)}, /*D-Link-Cameo*/ + {RTL_USB_DEVICE(0x2001, 0x3309, rtl92cu_hal_cfg)}, /*D-Link-Alpha*/ + {RTL_USB_DEVICE(0x2001, 0x330a, rtl92cu_hal_cfg)}, /*D-Link-Alpha*/ + {RTL_USB_DEVICE(0x2019, 0xab2b, rtl92cu_hal_cfg)}, /*Planex -Abocom*/ + {RTL_USB_DEVICE(0x20f4, 0x624d, rtl92cu_hal_cfg)}, /*TRENDNet*/ + {RTL_USB_DEVICE(0x7392, 0x7822, rtl92cu_hal_cfg)}, /*Edimax -Edimax*/ + {} +}; + +MODULE_DEVICE_TABLE(usb, rtl8192c_usb_ids); + +static struct usb_driver rtl8192cu_driver = { + .name = "rtl8192cu", + .probe = rtl_usb_probe, + .disconnect = rtl_usb_disconnect, + .id_table = rtl8192c_usb_ids, + +#ifdef CONFIG_PM + /* .suspend = rtl_usb_suspend, */ + /* .resume = rtl_usb_resume, */ + /* .reset_resume = rtl8192c_resume, */ +#endif /* CONFIG_PM */ +#ifdef CONFIG_AUTOSUSPEND + .supports_autosuspend = 1, +#endif +}; + +module_usb_driver(rtl8192cu_driver); diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.h b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.h new file mode 100644 index 00000000..a1310abd --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.h @@ -0,0 +1,53 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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. + * + * 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 __RTL92CU_SW_H__ +#define __RTL92CU_SW_H__ + +#define EFUSE_MAX_SECTION 16 + +void rtl92cu_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw, + u8 *powerlevel); +void rtl92cu_phy_rf6052_set_ofdm_txpower(struct ieee80211_hw *hw, + u8 *ppowerlevel, u8 channel); +bool _rtl92cu_phy_config_bb_with_headerfile(struct ieee80211_hw *hw, + u8 configtype); +bool _rtl92cu_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw, + u8 configtype); +void _rtl92cu_phy_lc_calibrate(struct ieee80211_hw *hw, bool is2t); +void rtl92cu_phy_set_rf_reg(struct ieee80211_hw *hw, + enum radio_path rfpath, + u32 regaddr, u32 bitmask, u32 data); +bool rtl92cu_phy_set_rf_power_state(struct ieee80211_hw *hw, + enum rf_pwrstate rfpwr_state); +u32 rtl92cu_phy_query_rf_reg(struct ieee80211_hw *hw, + enum radio_path rfpath, u32 regaddr, u32 bitmask); +void rtl92cu_phy_set_bw_mode_callback(struct ieee80211_hw *hw); + +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/table.c b/drivers/net/wireless/rtlwifi/rtl8192cu/table.c new file mode 100644 index 00000000..966be519 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/table.c @@ -0,0 +1,1888 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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> + * + *****************************************************************************/ + +#include "table.h" + +u32 RTL8192CUPHY_REG_2TARRAY[RTL8192CUPHY_REG_2TARRAY_LENGTH] = { + 0x024, 0x0011800f, + 0x028, 0x00ffdb83, + 0x800, 0x80040002, + 0x804, 0x00000003, + 0x808, 0x0000fc00, + 0x80c, 0x0000000a, + 0x810, 0x10005388, + 0x814, 0x020c3d10, + 0x818, 0x02200385, + 0x81c, 0x00000000, + 0x820, 0x01000100, + 0x824, 0x00390004, + 0x828, 0x01000100, + 0x82c, 0x00390004, + 0x830, 0x27272727, + 0x834, 0x27272727, + 0x838, 0x27272727, + 0x83c, 0x27272727, + 0x840, 0x00010000, + 0x844, 0x00010000, + 0x848, 0x27272727, + 0x84c, 0x27272727, + 0x850, 0x00000000, + 0x854, 0x00000000, + 0x858, 0x569a569a, + 0x85c, 0x0c1b25a4, + 0x860, 0x66e60230, + 0x864, 0x061f0130, + 0x868, 0x27272727, + 0x86c, 0x2b2b2b27, + 0x870, 0x07000700, + 0x874, 0x22184000, + 0x878, 0x08080808, + 0x87c, 0x00000000, + 0x880, 0xc0083070, + 0x884, 0x000004d5, + 0x888, 0x00000000, + 0x88c, 0xcc0000c0, + 0x890, 0x00000800, + 0x894, 0xfffffffe, + 0x898, 0x40302010, + 0x89c, 0x00706050, + 0x900, 0x00000000, + 0x904, 0x00000023, + 0x908, 0x00000000, + 0x90c, 0x81121313, + 0xa00, 0x00d047c8, + 0xa04, 0x80ff000c, + 0xa08, 0x8c838300, + 0xa0c, 0x2e68120f, + 0xa10, 0x9500bb78, + 0xa14, 0x11144028, + 0xa18, 0x00881117, + 0xa1c, 0x89140f00, + 0xa20, 0x1a1b0000, + 0xa24, 0x090e1317, + 0xa28, 0x00000204, + 0xa2c, 0x00d30000, + 0xa70, 0x101fbf00, + 0xa74, 0x00000007, + 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, 0x69e9ac44, + 0xc34, 0x469652cf, + 0xc38, 0x49795994, + 0xc3c, 0x0a97971c, + 0xc40, 0x1f7c403f, + 0xc44, 0x000100b7, + 0xc48, 0xec020107, + 0xc4c, 0x007f037f, + 0xc50, 0x6954341e, + 0xc54, 0x43bc0094, + 0xc58, 0x6954341e, + 0xc5c, 0x433c0094, + 0xc60, 0x00000000, + 0xc64, 0x5116848b, + 0xc68, 0x47c00bff, + 0xc6c, 0x00000036, + 0xc70, 0x2c7f000d, + 0xc74, 0x0186115b, + 0xc78, 0x0000001f, + 0xc7c, 0x00b99612, + 0xc80, 0x40000100, + 0xc84, 0x20f60000, + 0xc88, 0x40000100, + 0xc8c, 0x20200000, + 0xc90, 0x00121820, + 0xc94, 0x00000000, + 0xc98, 0x00121820, + 0xc9c, 0x00007f7f, + 0xca0, 0x00000000, + 0xca4, 0x00000080, + 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, 0x00000000, + 0xce8, 0x37644302, + 0xcec, 0x2f97d40c, + 0xd00, 0x00080740, + 0xd04, 0x00020403, + 0xd08, 0x0000907f, + 0xd0c, 0x20010201, + 0xd10, 0xa0633333, + 0xd14, 0x3333bc43, + 0xd18, 0x7a8f5b6b, + 0xd2c, 0xcc979975, + 0xd30, 0x00000000, + 0xd34, 0x80608000, + 0xd38, 0x00000000, + 0xd3c, 0x00027293, + 0xd40, 0x00000000, + 0xd44, 0x00000000, + 0xd48, 0x00000000, + 0xd4c, 0x00000000, + 0xd50, 0x6437140a, + 0xd54, 0x00000000, + 0xd58, 0x00000000, + 0xd5c, 0x30032064, + 0xd60, 0x4653de68, + 0xd64, 0x04518a3c, + 0xd68, 0x00002101, + 0xd6c, 0x2a201c16, + 0xd70, 0x1812362e, + 0xd74, 0x322c2220, + 0xd78, 0x000e3c24, + 0xe00, 0x2a2a2a2a, + 0xe04, 0x2a2a2a2a, + 0xe08, 0x03902a2a, + 0xe10, 0x2a2a2a2a, + 0xe14, 0x2a2a2a2a, + 0xe18, 0x2a2a2a2a, + 0xe1c, 0x2a2a2a2a, + 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, 0x00000010, + 0xe68, 0x001b25a4, + 0xe6c, 0x63db25a4, + 0xe70, 0x63db25a4, + 0xe74, 0x0c1b25a4, + 0xe78, 0x0c1b25a4, + 0xe7c, 0x0c1b25a4, + 0xe80, 0x0c1b25a4, + 0xe84, 0x63db25a4, + 0xe88, 0x0c1b25a4, + 0xe8c, 0x63db25a4, + 0xed0, 0x63db25a4, + 0xed4, 0x63db25a4, + 0xed8, 0x63db25a4, + 0xedc, 0x001b25a4, + 0xee0, 0x001b25a4, + 0xeec, 0x6fdb25a4, + 0xf14, 0x00000003, + 0xf4c, 0x00000000, + 0xf00, 0x00000300, +}; + +u32 RTL8192CUPHY_REG_1TARRAY[RTL8192CUPHY_REG_1TARRAY_LENGTH] = { + 0x024, 0x0011800f, + 0x028, 0x00ffdb83, + 0x800, 0x80040000, + 0x804, 0x00000001, + 0x808, 0x0000fc00, + 0x80c, 0x0000000a, + 0x810, 0x10005388, + 0x814, 0x020c3d10, + 0x818, 0x02200385, + 0x81c, 0x00000000, + 0x820, 0x01000100, + 0x824, 0x00390004, + 0x828, 0x00000000, + 0x82c, 0x00000000, + 0x830, 0x00000000, + 0x834, 0x00000000, + 0x838, 0x00000000, + 0x83c, 0x00000000, + 0x840, 0x00010000, + 0x844, 0x00000000, + 0x848, 0x00000000, + 0x84c, 0x00000000, + 0x850, 0x00000000, + 0x854, 0x00000000, + 0x858, 0x569a569a, + 0x85c, 0x001b25a4, + 0x860, 0x66e60230, + 0x864, 0x061f0130, + 0x868, 0x00000000, + 0x86c, 0x32323200, + 0x870, 0x07000700, + 0x874, 0x22004000, + 0x878, 0x00000808, + 0x87c, 0x00000000, + 0x880, 0xc0083070, + 0x884, 0x000004d5, + 0x888, 0x00000000, + 0x88c, 0xccc000c0, + 0x890, 0x00000800, + 0x894, 0xfffffffe, + 0x898, 0x40302010, + 0x89c, 0x00706050, + 0x900, 0x00000000, + 0x904, 0x00000023, + 0x908, 0x00000000, + 0x90c, 0x81121111, + 0xa00, 0x00d047c8, + 0xa04, 0x80ff000c, + 0xa08, 0x8c838300, + 0xa0c, 0x2e68120f, + 0xa10, 0x9500bb78, + 0xa14, 0x11144028, + 0xa18, 0x00881117, + 0xa1c, 0x89140f00, + 0xa20, 0x1a1b0000, + 0xa24, 0x090e1317, + 0xa28, 0x00000204, + 0xa2c, 0x00d30000, + 0xa70, 0x101fbf00, + 0xa74, 0x00000007, + 0xc00, 0x48071d40, + 0xc04, 0x03a05611, + 0xc08, 0x000000e4, + 0xc0c, 0x6c6c6c6c, + 0xc10, 0x08800000, + 0xc14, 0x40000100, + 0xc18, 0x08800000, + 0xc1c, 0x40000100, + 0xc20, 0x00000000, + 0xc24, 0x00000000, + 0xc28, 0x00000000, + 0xc2c, 0x00000000, + 0xc30, 0x69e9ac44, + 0xc34, 0x469652cf, + 0xc38, 0x49795994, + 0xc3c, 0x0a97971c, + 0xc40, 0x1f7c403f, + 0xc44, 0x000100b7, + 0xc48, 0xec020107, + 0xc4c, 0x007f037f, + 0xc50, 0x6954341e, + 0xc54, 0x43bc0094, + 0xc58, 0x6954341e, + 0xc5c, 0x433c0094, + 0xc60, 0x00000000, + 0xc64, 0x5116848b, + 0xc68, 0x47c00bff, + 0xc6c, 0x00000036, + 0xc70, 0x2c7f000d, + 0xc74, 0x018610db, + 0xc78, 0x0000001f, + 0xc7c, 0x00b91612, + 0xc80, 0x40000100, + 0xc84, 0x20f60000, + 0xc88, 0x40000100, + 0xc8c, 0x20200000, + 0xc90, 0x00121820, + 0xc94, 0x00000000, + 0xc98, 0x00121820, + 0xc9c, 0x00007f7f, + 0xca0, 0x00000000, + 0xca4, 0x00000080, + 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, 0x00000000, + 0xce8, 0x37644302, + 0xcec, 0x2f97d40c, + 0xd00, 0x00080740, + 0xd04, 0x00020401, + 0xd08, 0x0000907f, + 0xd0c, 0x20010201, + 0xd10, 0xa0633333, + 0xd14, 0x3333bc43, + 0xd18, 0x7a8f5b6b, + 0xd2c, 0xcc979975, + 0xd30, 0x00000000, + 0xd34, 0x80608000, + 0xd38, 0x00000000, + 0xd3c, 0x00027293, + 0xd40, 0x00000000, + 0xd44, 0x00000000, + 0xd48, 0x00000000, + 0xd4c, 0x00000000, + 0xd50, 0x6437140a, + 0xd54, 0x00000000, + 0xd58, 0x00000000, + 0xd5c, 0x30032064, + 0xd60, 0x4653de68, + 0xd64, 0x04518a3c, + 0xd68, 0x00002101, + 0xd6c, 0x2a201c16, + 0xd70, 0x1812362e, + 0xd74, 0x322c2220, + 0xd78, 0x000e3c24, + 0xe00, 0x2a2a2a2a, + 0xe04, 0x2a2a2a2a, + 0xe08, 0x03902a2a, + 0xe10, 0x2a2a2a2a, + 0xe14, 0x2a2a2a2a, + 0xe18, 0x2a2a2a2a, + 0xe1c, 0x2a2a2a2a, + 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, 0x001b25a4, + 0xe6c, 0x631b25a0, + 0xe70, 0x631b25a0, + 0xe74, 0x081b25a0, + 0xe78, 0x081b25a0, + 0xe7c, 0x081b25a0, + 0xe80, 0x081b25a0, + 0xe84, 0x631b25a0, + 0xe88, 0x081b25a0, + 0xe8c, 0x631b25a0, + 0xed0, 0x631b25a0, + 0xed4, 0x631b25a0, + 0xed8, 0x631b25a0, + 0xedc, 0x001b25a0, + 0xee0, 0x001b25a0, + 0xeec, 0x6b1b25a0, + 0xf14, 0x00000003, + 0xf4c, 0x00000000, + 0xf00, 0x00000300, +}; + +u32 RTL8192CUPHY_REG_ARRAY_PG[RTL8192CUPHY_REG_ARRAY_PGLENGTH] = { + 0xe00, 0xffffffff, 0x07090c0c, + 0xe04, 0xffffffff, 0x01020405, + 0xe08, 0x0000ff00, 0x00000000, + 0x86c, 0xffffff00, 0x00000000, + 0xe10, 0xffffffff, 0x0b0c0c0e, + 0xe14, 0xffffffff, 0x01030506, + 0xe18, 0xffffffff, 0x0b0c0d0e, + 0xe1c, 0xffffffff, 0x01030509, + 0x830, 0xffffffff, 0x07090c0c, + 0x834, 0xffffffff, 0x01020405, + 0x838, 0xffffff00, 0x00000000, + 0x86c, 0x000000ff, 0x00000000, + 0x83c, 0xffffffff, 0x0b0c0d0e, + 0x848, 0xffffffff, 0x01030509, + 0x84c, 0xffffffff, 0x0b0c0d0e, + 0x868, 0xffffffff, 0x01030509, + 0xe00, 0xffffffff, 0x00000000, + 0xe04, 0xffffffff, 0x00000000, + 0xe08, 0x0000ff00, 0x00000000, + 0x86c, 0xffffff00, 0x00000000, + 0xe10, 0xffffffff, 0x00000000, + 0xe14, 0xffffffff, 0x00000000, + 0xe18, 0xffffffff, 0x00000000, + 0xe1c, 0xffffffff, 0x00000000, + 0x830, 0xffffffff, 0x00000000, + 0x834, 0xffffffff, 0x00000000, + 0x838, 0xffffff00, 0x00000000, + 0x86c, 0x000000ff, 0x00000000, + 0x83c, 0xffffffff, 0x00000000, + 0x848, 0xffffffff, 0x00000000, + 0x84c, 0xffffffff, 0x00000000, + 0x868, 0xffffffff, 0x00000000, + 0xe00, 0xffffffff, 0x04040404, + 0xe04, 0xffffffff, 0x00020204, + 0xe08, 0x0000ff00, 0x00000000, + 0x86c, 0xffffff00, 0x00000000, + 0xe10, 0xffffffff, 0x06060606, + 0xe14, 0xffffffff, 0x00020406, + 0xe18, 0xffffffff, 0x00000000, + 0xe1c, 0xffffffff, 0x00000000, + 0x830, 0xffffffff, 0x04040404, + 0x834, 0xffffffff, 0x00020204, + 0x838, 0xffffff00, 0x00000000, + 0x86c, 0x000000ff, 0x00000000, + 0x83c, 0xffffffff, 0x06060606, + 0x848, 0xffffffff, 0x00020406, + 0x84c, 0xffffffff, 0x00000000, + 0x868, 0xffffffff, 0x00000000, + 0xe00, 0xffffffff, 0x00000000, + 0xe04, 0xffffffff, 0x00000000, + 0xe08, 0x0000ff00, 0x00000000, + 0x86c, 0xffffff00, 0x00000000, + 0xe10, 0xffffffff, 0x00000000, + 0xe14, 0xffffffff, 0x00000000, + 0xe18, 0xffffffff, 0x00000000, + 0xe1c, 0xffffffff, 0x00000000, + 0x830, 0xffffffff, 0x00000000, + 0x834, 0xffffffff, 0x00000000, + 0x838, 0xffffff00, 0x00000000, + 0x86c, 0x000000ff, 0x00000000, + 0x83c, 0xffffffff, 0x00000000, + 0x848, 0xffffffff, 0x00000000, + 0x84c, 0xffffffff, 0x00000000, + 0x868, 0xffffffff, 0x00000000, + 0xe00, 0xffffffff, 0x00000000, + 0xe04, 0xffffffff, 0x00000000, + 0xe08, 0x0000ff00, 0x00000000, + 0x86c, 0xffffff00, 0x00000000, + 0xe10, 0xffffffff, 0x00000000, + 0xe14, 0xffffffff, 0x00000000, + 0xe18, 0xffffffff, 0x00000000, + 0xe1c, 0xffffffff, 0x00000000, + 0x830, 0xffffffff, 0x00000000, + 0x834, 0xffffffff, 0x00000000, + 0x838, 0xffffff00, 0x00000000, + 0x86c, 0x000000ff, 0x00000000, + 0x83c, 0xffffffff, 0x00000000, + 0x848, 0xffffffff, 0x00000000, + 0x84c, 0xffffffff, 0x00000000, + 0x868, 0xffffffff, 0x00000000, + 0xe00, 0xffffffff, 0x04040404, + 0xe04, 0xffffffff, 0x00020204, + 0xe08, 0x0000ff00, 0x00000000, + 0x86c, 0xffffff00, 0x00000000, + 0xe10, 0xffffffff, 0x00000000, + 0xe14, 0xffffffff, 0x00000000, + 0xe18, 0xffffffff, 0x00000000, + 0xe1c, 0xffffffff, 0x00000000, + 0x830, 0xffffffff, 0x04040404, + 0x834, 0xffffffff, 0x00020204, + 0x838, 0xffffff00, 0x00000000, + 0x86c, 0x000000ff, 0x00000000, + 0x83c, 0xffffffff, 0x00000000, + 0x848, 0xffffffff, 0x00000000, + 0x84c, 0xffffffff, 0x00000000, + 0x868, 0xffffffff, 0x00000000, + 0xe00, 0xffffffff, 0x00000000, + 0xe04, 0xffffffff, 0x00000000, + 0xe08, 0x0000ff00, 0x00000000, + 0x86c, 0xffffff00, 0x00000000, + 0xe10, 0xffffffff, 0x00000000, + 0xe14, 0xffffffff, 0x00000000, + 0xe18, 0xffffffff, 0x00000000, + 0xe1c, 0xffffffff, 0x00000000, + 0x830, 0xffffffff, 0x00000000, + 0x834, 0xffffffff, 0x00000000, + 0x838, 0xffffff00, 0x00000000, + 0x86c, 0x000000ff, 0x00000000, + 0x83c, 0xffffffff, 0x00000000, + 0x848, 0xffffffff, 0x00000000, + 0x84c, 0xffffffff, 0x00000000, + 0x868, 0xffffffff, 0x00000000, +}; + +u32 RTL8192CURADIOA_2TARRAY[RTL8192CURADIOA_2TARRAYLENGTH] = { + 0x000, 0x00030159, + 0x001, 0x00031284, + 0x002, 0x00098000, + 0x003, 0x00018c63, + 0x004, 0x000210e7, + 0x009, 0x0002044f, + 0x00a, 0x0001adb1, + 0x00b, 0x00054867, + 0x00c, 0x0008992e, + 0x00d, 0x0000e52c, + 0x00e, 0x00039ce7, + 0x00f, 0x00000451, + 0x019, 0x00000000, + 0x01a, 0x00010255, + 0x01b, 0x00060a00, + 0x01c, 0x000fc378, + 0x01d, 0x000a1250, + 0x01e, 0x0004445f, + 0x01f, 0x00080001, + 0x020, 0x0000b614, + 0x021, 0x0006c000, + 0x022, 0x00000000, + 0x023, 0x00001558, + 0x024, 0x00000060, + 0x025, 0x00000483, + 0x026, 0x0004f000, + 0x027, 0x000ec7d9, + 0x028, 0x000577c0, + 0x029, 0x00004783, + 0x02a, 0x00000001, + 0x02b, 0x00021334, + 0x02a, 0x00000000, + 0x02b, 0x00000054, + 0x02a, 0x00000001, + 0x02b, 0x00000808, + 0x02b, 0x00053333, + 0x02c, 0x0000000c, + 0x02a, 0x00000002, + 0x02b, 0x00000808, + 0x02b, 0x0005b333, + 0x02c, 0x0000000d, + 0x02a, 0x00000003, + 0x02b, 0x00000808, + 0x02b, 0x00063333, + 0x02c, 0x0000000d, + 0x02a, 0x00000004, + 0x02b, 0x00000808, + 0x02b, 0x0006b333, + 0x02c, 0x0000000d, + 0x02a, 0x00000005, + 0x02b, 0x00000808, + 0x02b, 0x00073333, + 0x02c, 0x0000000d, + 0x02a, 0x00000006, + 0x02b, 0x00000709, + 0x02b, 0x0005b333, + 0x02c, 0x0000000d, + 0x02a, 0x00000007, + 0x02b, 0x00000709, + 0x02b, 0x00063333, + 0x02c, 0x0000000d, + 0x02a, 0x00000008, + 0x02b, 0x0000060a, + 0x02b, 0x0004b333, + 0x02c, 0x0000000d, + 0x02a, 0x00000009, + 0x02b, 0x0000060a, + 0x02b, 0x00053333, + 0x02c, 0x0000000d, + 0x02a, 0x0000000a, + 0x02b, 0x0000060a, + 0x02b, 0x0005b333, + 0x02c, 0x0000000d, + 0x02a, 0x0000000b, + 0x02b, 0x0000060a, + 0x02b, 0x00063333, + 0x02c, 0x0000000d, + 0x02a, 0x0000000c, + 0x02b, 0x0000060a, + 0x02b, 0x0006b333, + 0x02c, 0x0000000d, + 0x02a, 0x0000000d, + 0x02b, 0x0000060a, + 0x02b, 0x00073333, + 0x02c, 0x0000000d, + 0x02a, 0x0000000e, + 0x02b, 0x0000050b, + 0x02b, 0x00066666, + 0x02c, 0x0000001a, + 0x02a, 0x000e0000, + 0x010, 0x0004000f, + 0x011, 0x000e31fc, + 0x010, 0x0006000f, + 0x011, 0x000ff9f8, + 0x010, 0x0002000f, + 0x011, 0x000203f9, + 0x010, 0x0003000f, + 0x011, 0x000ff500, + 0x010, 0x00000000, + 0x011, 0x00000000, + 0x010, 0x0008000f, + 0x011, 0x0003f100, + 0x010, 0x0009000f, + 0x011, 0x00023100, + 0x012, 0x00032000, + 0x012, 0x00071000, + 0x012, 0x000b0000, + 0x012, 0x000fc000, + 0x013, 0x000287af, + 0x013, 0x000244b7, + 0x013, 0x000204ab, + 0x013, 0x0001c49f, + 0x013, 0x00018493, + 0x013, 0x00014297, + 0x013, 0x00010295, + 0x013, 0x0000c298, + 0x013, 0x0000819c, + 0x013, 0x000040a8, + 0x013, 0x0000001c, + 0x014, 0x0001944c, + 0x014, 0x00059444, + 0x014, 0x0009944c, + 0x014, 0x000d9444, + 0x015, 0x0000f424, + 0x015, 0x0004f424, + 0x015, 0x0008f424, + 0x015, 0x000cf424, + 0x016, 0x000e0330, + 0x016, 0x000a0330, + 0x016, 0x00060330, + 0x016, 0x00020330, + 0x000, 0x00010159, + 0x018, 0x0000f401, + 0x0fe, 0x00000000, + 0x0fe, 0x00000000, + 0x01f, 0x00080003, + 0x0fe, 0x00000000, + 0x0fe, 0x00000000, + 0x01e, 0x00044457, + 0x01f, 0x00080000, + 0x000, 0x00030159, +}; + +u32 RTL8192CU_RADIOB_2TARRAY[RTL8192CURADIOB_2TARRAYLENGTH] = { + 0x000, 0x00030159, + 0x001, 0x00031284, + 0x002, 0x00098000, + 0x003, 0x00018c63, + 0x004, 0x000210e7, + 0x009, 0x0002044f, + 0x00a, 0x0001adb1, + 0x00b, 0x00054867, + 0x00c, 0x0008992e, + 0x00d, 0x0000e52c, + 0x00e, 0x00039ce7, + 0x00f, 0x00000451, + 0x012, 0x00032000, + 0x012, 0x00071000, + 0x012, 0x000b0000, + 0x012, 0x000fc000, + 0x013, 0x000287af, + 0x013, 0x000244b7, + 0x013, 0x000204ab, + 0x013, 0x0001c49f, + 0x013, 0x00018493, + 0x013, 0x00014297, + 0x013, 0x00010295, + 0x013, 0x0000c298, + 0x013, 0x0000819c, + 0x013, 0x000040a8, + 0x013, 0x0000001c, + 0x014, 0x0001944c, + 0x014, 0x00059444, + 0x014, 0x0009944c, + 0x014, 0x000d9444, + 0x015, 0x0000f424, + 0x015, 0x0004f424, + 0x015, 0x0008f424, + 0x015, 0x000cf424, + 0x016, 0x000e0330, + 0x016, 0x000a0330, + 0x016, 0x00060330, + 0x016, 0x00020330, +}; + +u32 RTL8192CU_RADIOA_1TARRAY[RTL8192CURADIOA_1TARRAYLENGTH] = { + 0x000, 0x00030159, + 0x001, 0x00031284, + 0x002, 0x00098000, + 0x003, 0x00018c63, + 0x004, 0x000210e7, + 0x009, 0x0002044f, + 0x00a, 0x0001adb1, + 0x00b, 0x00054867, + 0x00c, 0x0008992e, + 0x00d, 0x0000e52c, + 0x00e, 0x00039ce7, + 0x00f, 0x00000451, + 0x019, 0x00000000, + 0x01a, 0x00010255, + 0x01b, 0x00060a00, + 0x01c, 0x000fc378, + 0x01d, 0x000a1250, + 0x01e, 0x0004445f, + 0x01f, 0x00080001, + 0x020, 0x0000b614, + 0x021, 0x0006c000, + 0x022, 0x00000000, + 0x023, 0x00001558, + 0x024, 0x00000060, + 0x025, 0x00000483, + 0x026, 0x0004f000, + 0x027, 0x000ec7d9, + 0x028, 0x000577c0, + 0x029, 0x00004783, + 0x02a, 0x00000001, + 0x02b, 0x00021334, + 0x02a, 0x00000000, + 0x02b, 0x00000054, + 0x02a, 0x00000001, + 0x02b, 0x00000808, + 0x02b, 0x00053333, + 0x02c, 0x0000000c, + 0x02a, 0x00000002, + 0x02b, 0x00000808, + 0x02b, 0x0005b333, + 0x02c, 0x0000000d, + 0x02a, 0x00000003, + 0x02b, 0x00000808, + 0x02b, 0x00063333, + 0x02c, 0x0000000d, + 0x02a, 0x00000004, + 0x02b, 0x00000808, + 0x02b, 0x0006b333, + 0x02c, 0x0000000d, + 0x02a, 0x00000005, + 0x02b, 0x00000808, + 0x02b, 0x00073333, + 0x02c, 0x0000000d, + 0x02a, 0x00000006, + 0x02b, 0x00000709, + 0x02b, 0x0005b333, + 0x02c, 0x0000000d, + 0x02a, 0x00000007, + 0x02b, 0x00000709, + 0x02b, 0x00063333, + 0x02c, 0x0000000d, + 0x02a, 0x00000008, + 0x02b, 0x0000060a, + 0x02b, 0x0004b333, + 0x02c, 0x0000000d, + 0x02a, 0x00000009, + 0x02b, 0x0000060a, + 0x02b, 0x00053333, + 0x02c, 0x0000000d, + 0x02a, 0x0000000a, + 0x02b, 0x0000060a, + 0x02b, 0x0005b333, + 0x02c, 0x0000000d, + 0x02a, 0x0000000b, + 0x02b, 0x0000060a, + 0x02b, 0x00063333, + 0x02c, 0x0000000d, + 0x02a, 0x0000000c, + 0x02b, 0x0000060a, + 0x02b, 0x0006b333, + 0x02c, 0x0000000d, + 0x02a, 0x0000000d, + 0x02b, 0x0000060a, + 0x02b, 0x00073333, + 0x02c, 0x0000000d, + 0x02a, 0x0000000e, + 0x02b, 0x0000050b, + 0x02b, 0x00066666, + 0x02c, 0x0000001a, + 0x02a, 0x000e0000, + 0x010, 0x0004000f, + 0x011, 0x000e31fc, + 0x010, 0x0006000f, + 0x011, 0x000ff9f8, + 0x010, 0x0002000f, + 0x011, 0x000203f9, + 0x010, 0x0003000f, + 0x011, 0x000ff500, + 0x010, 0x00000000, + 0x011, 0x00000000, + 0x010, 0x0008000f, + 0x011, 0x0003f100, + 0x010, 0x0009000f, + 0x011, 0x00023100, + 0x012, 0x00032000, + 0x012, 0x00071000, + 0x012, 0x000b0000, + 0x012, 0x000fc000, + 0x013, 0x000287b3, + 0x013, 0x000244b7, + 0x013, 0x000204ab, + 0x013, 0x0001c49f, + 0x013, 0x00018493, + 0x013, 0x0001429b, + 0x013, 0x00010299, + 0x013, 0x0000c29c, + 0x013, 0x000081a0, + 0x013, 0x000040ac, + 0x013, 0x00000020, + 0x014, 0x0001944c, + 0x014, 0x00059444, + 0x014, 0x0009944c, + 0x014, 0x000d9444, + 0x015, 0x0000f405, + 0x015, 0x0004f405, + 0x015, 0x0008f405, + 0x015, 0x000cf405, + 0x016, 0x000e0330, + 0x016, 0x000a0330, + 0x016, 0x00060330, + 0x016, 0x00020330, + 0x000, 0x00010159, + 0x018, 0x0000f401, + 0x0fe, 0x00000000, + 0x0fe, 0x00000000, + 0x01f, 0x00080003, + 0x0fe, 0x00000000, + 0x0fe, 0x00000000, + 0x01e, 0x00044457, + 0x01f, 0x00080000, + 0x000, 0x00030159, +}; + +u32 RTL8192CU_RADIOB_1TARRAY[RTL8192CURADIOB_1TARRAYLENGTH] = { + 0x0, +}; + +u32 RTL8192CUMAC_2T_ARRAY[RTL8192CUMAC_2T_ARRAYLENGTH] = { + 0x420, 0x00000080, + 0x423, 0x00000000, + 0x430, 0x00000000, + 0x431, 0x00000000, + 0x432, 0x00000000, + 0x433, 0x00000001, + 0x434, 0x00000004, + 0x435, 0x00000005, + 0x436, 0x00000006, + 0x437, 0x00000007, + 0x438, 0x00000000, + 0x439, 0x00000000, + 0x43a, 0x00000000, + 0x43b, 0x00000001, + 0x43c, 0x00000004, + 0x43d, 0x00000005, + 0x43e, 0x00000006, + 0x43f, 0x00000007, + 0x440, 0x0000005d, + 0x441, 0x00000001, + 0x442, 0x00000000, + 0x444, 0x00000015, + 0x445, 0x000000f0, + 0x446, 0x0000000f, + 0x447, 0x00000000, + 0x458, 0x00000041, + 0x459, 0x000000a8, + 0x45a, 0x00000072, + 0x45b, 0x000000b9, + 0x460, 0x00000066, + 0x461, 0x00000066, + 0x462, 0x00000008, + 0x463, 0x00000003, + 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, + 0x515, 0x00000010, + 0x516, 0x0000000a, + 0x517, 0x00000010, + 0x51a, 0x00000016, + 0x524, 0x0000000f, + 0x525, 0x0000004f, + 0x546, 0x00000040, + 0x547, 0x00000000, + 0x550, 0x00000010, + 0x551, 0x00000010, + 0x559, 0x00000002, + 0x55a, 0x00000002, + 0x55d, 0x000000ff, + 0x605, 0x00000030, + 0x608, 0x0000000e, + 0x609, 0x0000002a, + 0x652, 0x00000020, + 0x63c, 0x0000000a, + 0x63d, 0x0000000e, + 0x63e, 0x0000000a, + 0x63f, 0x0000000e, + 0x66e, 0x00000005, + 0x700, 0x00000021, + 0x701, 0x00000043, + 0x702, 0x00000065, + 0x703, 0x00000087, + 0x708, 0x00000021, + 0x709, 0x00000043, + 0x70a, 0x00000065, + 0x70b, 0x00000087, +}; + +u32 RTL8192CUAGCTAB_2TARRAY[RTL8192CUAGCTAB_2TARRAYLENGTH] = { + 0xc78, 0x7b000001, + 0xc78, 0x7b010001, + 0xc78, 0x7b020001, + 0xc78, 0x7b030001, + 0xc78, 0x7b040001, + 0xc78, 0x7b050001, + 0xc78, 0x7a060001, + 0xc78, 0x79070001, + 0xc78, 0x78080001, + 0xc78, 0x77090001, + 0xc78, 0x760a0001, + 0xc78, 0x750b0001, + 0xc78, 0x740c0001, + 0xc78, 0x730d0001, + 0xc78, 0x720e0001, + 0xc78, 0x710f0001, + 0xc78, 0x70100001, + 0xc78, 0x6f110001, + 0xc78, 0x6e120001, + 0xc78, 0x6d130001, + 0xc78, 0x6c140001, + 0xc78, 0x6b150001, + 0xc78, 0x6a160001, + 0xc78, 0x69170001, + 0xc78, 0x68180001, + 0xc78, 0x67190001, + 0xc78, 0x661a0001, + 0xc78, 0x651b0001, + 0xc78, 0x641c0001, + 0xc78, 0x631d0001, + 0xc78, 0x621e0001, + 0xc78, 0x611f0001, + 0xc78, 0x60200001, + 0xc78, 0x49210001, + 0xc78, 0x48220001, + 0xc78, 0x47230001, + 0xc78, 0x46240001, + 0xc78, 0x45250001, + 0xc78, 0x44260001, + 0xc78, 0x43270001, + 0xc78, 0x42280001, + 0xc78, 0x41290001, + 0xc78, 0x402a0001, + 0xc78, 0x262b0001, + 0xc78, 0x252c0001, + 0xc78, 0x242d0001, + 0xc78, 0x232e0001, + 0xc78, 0x222f0001, + 0xc78, 0x21300001, + 0xc78, 0x20310001, + 0xc78, 0x06320001, + 0xc78, 0x05330001, + 0xc78, 0x04340001, + 0xc78, 0x03350001, + 0xc78, 0x02360001, + 0xc78, 0x01370001, + 0xc78, 0x00380001, + 0xc78, 0x00390001, + 0xc78, 0x003a0001, + 0xc78, 0x003b0001, + 0xc78, 0x003c0001, + 0xc78, 0x003d0001, + 0xc78, 0x003e0001, + 0xc78, 0x003f0001, + 0xc78, 0x7b400001, + 0xc78, 0x7b410001, + 0xc78, 0x7b420001, + 0xc78, 0x7b430001, + 0xc78, 0x7b440001, + 0xc78, 0x7b450001, + 0xc78, 0x7a460001, + 0xc78, 0x79470001, + 0xc78, 0x78480001, + 0xc78, 0x77490001, + 0xc78, 0x764a0001, + 0xc78, 0x754b0001, + 0xc78, 0x744c0001, + 0xc78, 0x734d0001, + 0xc78, 0x724e0001, + 0xc78, 0x714f0001, + 0xc78, 0x70500001, + 0xc78, 0x6f510001, + 0xc78, 0x6e520001, + 0xc78, 0x6d530001, + 0xc78, 0x6c540001, + 0xc78, 0x6b550001, + 0xc78, 0x6a560001, + 0xc78, 0x69570001, + 0xc78, 0x68580001, + 0xc78, 0x67590001, + 0xc78, 0x665a0001, + 0xc78, 0x655b0001, + 0xc78, 0x645c0001, + 0xc78, 0x635d0001, + 0xc78, 0x625e0001, + 0xc78, 0x615f0001, + 0xc78, 0x60600001, + 0xc78, 0x49610001, + 0xc78, 0x48620001, + 0xc78, 0x47630001, + 0xc78, 0x46640001, + 0xc78, 0x45650001, + 0xc78, 0x44660001, + 0xc78, 0x43670001, + 0xc78, 0x42680001, + 0xc78, 0x41690001, + 0xc78, 0x406a0001, + 0xc78, 0x266b0001, + 0xc78, 0x256c0001, + 0xc78, 0x246d0001, + 0xc78, 0x236e0001, + 0xc78, 0x226f0001, + 0xc78, 0x21700001, + 0xc78, 0x20710001, + 0xc78, 0x06720001, + 0xc78, 0x05730001, + 0xc78, 0x04740001, + 0xc78, 0x03750001, + 0xc78, 0x02760001, + 0xc78, 0x01770001, + 0xc78, 0x00780001, + 0xc78, 0x00790001, + 0xc78, 0x007a0001, + 0xc78, 0x007b0001, + 0xc78, 0x007c0001, + 0xc78, 0x007d0001, + 0xc78, 0x007e0001, + 0xc78, 0x007f0001, + 0xc78, 0x3800001e, + 0xc78, 0x3801001e, + 0xc78, 0x3802001e, + 0xc78, 0x3803001e, + 0xc78, 0x3804001e, + 0xc78, 0x3805001e, + 0xc78, 0x3806001e, + 0xc78, 0x3807001e, + 0xc78, 0x3808001e, + 0xc78, 0x3c09001e, + 0xc78, 0x3e0a001e, + 0xc78, 0x400b001e, + 0xc78, 0x440c001e, + 0xc78, 0x480d001e, + 0xc78, 0x4c0e001e, + 0xc78, 0x500f001e, + 0xc78, 0x5210001e, + 0xc78, 0x5611001e, + 0xc78, 0x5a12001e, + 0xc78, 0x5e13001e, + 0xc78, 0x6014001e, + 0xc78, 0x6015001e, + 0xc78, 0x6016001e, + 0xc78, 0x6217001e, + 0xc78, 0x6218001e, + 0xc78, 0x6219001e, + 0xc78, 0x621a001e, + 0xc78, 0x621b001e, + 0xc78, 0x621c001e, + 0xc78, 0x621d001e, + 0xc78, 0x621e001e, + 0xc78, 0x621f001e, +}; + +u32 RTL8192CUAGCTAB_1TARRAY[RTL8192CUAGCTAB_1TARRAYLENGTH] = { + 0xc78, 0x7b000001, + 0xc78, 0x7b010001, + 0xc78, 0x7b020001, + 0xc78, 0x7b030001, + 0xc78, 0x7b040001, + 0xc78, 0x7b050001, + 0xc78, 0x7a060001, + 0xc78, 0x79070001, + 0xc78, 0x78080001, + 0xc78, 0x77090001, + 0xc78, 0x760a0001, + 0xc78, 0x750b0001, + 0xc78, 0x740c0001, + 0xc78, 0x730d0001, + 0xc78, 0x720e0001, + 0xc78, 0x710f0001, + 0xc78, 0x70100001, + 0xc78, 0x6f110001, + 0xc78, 0x6e120001, + 0xc78, 0x6d130001, + 0xc78, 0x6c140001, + 0xc78, 0x6b150001, + 0xc78, 0x6a160001, + 0xc78, 0x69170001, + 0xc78, 0x68180001, + 0xc78, 0x67190001, + 0xc78, 0x661a0001, + 0xc78, 0x651b0001, + 0xc78, 0x641c0001, + 0xc78, 0x631d0001, + 0xc78, 0x621e0001, + 0xc78, 0x611f0001, + 0xc78, 0x60200001, + 0xc78, 0x49210001, + 0xc78, 0x48220001, + 0xc78, 0x47230001, + 0xc78, 0x46240001, + 0xc78, 0x45250001, + 0xc78, 0x44260001, + 0xc78, 0x43270001, + 0xc78, 0x42280001, + 0xc78, 0x41290001, + 0xc78, 0x402a0001, + 0xc78, 0x262b0001, + 0xc78, 0x252c0001, + 0xc78, 0x242d0001, + 0xc78, 0x232e0001, + 0xc78, 0x222f0001, + 0xc78, 0x21300001, + 0xc78, 0x20310001, + 0xc78, 0x06320001, + 0xc78, 0x05330001, + 0xc78, 0x04340001, + 0xc78, 0x03350001, + 0xc78, 0x02360001, + 0xc78, 0x01370001, + 0xc78, 0x00380001, + 0xc78, 0x00390001, + 0xc78, 0x003a0001, + 0xc78, 0x003b0001, + 0xc78, 0x003c0001, + 0xc78, 0x003d0001, + 0xc78, 0x003e0001, + 0xc78, 0x003f0001, + 0xc78, 0x7b400001, + 0xc78, 0x7b410001, + 0xc78, 0x7b420001, + 0xc78, 0x7b430001, + 0xc78, 0x7b440001, + 0xc78, 0x7b450001, + 0xc78, 0x7a460001, + 0xc78, 0x79470001, + 0xc78, 0x78480001, + 0xc78, 0x77490001, + 0xc78, 0x764a0001, + 0xc78, 0x754b0001, + 0xc78, 0x744c0001, + 0xc78, 0x734d0001, + 0xc78, 0x724e0001, + 0xc78, 0x714f0001, + 0xc78, 0x70500001, + 0xc78, 0x6f510001, + 0xc78, 0x6e520001, + 0xc78, 0x6d530001, + 0xc78, 0x6c540001, + 0xc78, 0x6b550001, + 0xc78, 0x6a560001, + 0xc78, 0x69570001, + 0xc78, 0x68580001, + 0xc78, 0x67590001, + 0xc78, 0x665a0001, + 0xc78, 0x655b0001, + 0xc78, 0x645c0001, + 0xc78, 0x635d0001, + 0xc78, 0x625e0001, + 0xc78, 0x615f0001, + 0xc78, 0x60600001, + 0xc78, 0x49610001, + 0xc78, 0x48620001, + 0xc78, 0x47630001, + 0xc78, 0x46640001, + 0xc78, 0x45650001, + 0xc78, 0x44660001, + 0xc78, 0x43670001, + 0xc78, 0x42680001, + 0xc78, 0x41690001, + 0xc78, 0x406a0001, + 0xc78, 0x266b0001, + 0xc78, 0x256c0001, + 0xc78, 0x246d0001, + 0xc78, 0x236e0001, + 0xc78, 0x226f0001, + 0xc78, 0x21700001, + 0xc78, 0x20710001, + 0xc78, 0x06720001, + 0xc78, 0x05730001, + 0xc78, 0x04740001, + 0xc78, 0x03750001, + 0xc78, 0x02760001, + 0xc78, 0x01770001, + 0xc78, 0x00780001, + 0xc78, 0x00790001, + 0xc78, 0x007a0001, + 0xc78, 0x007b0001, + 0xc78, 0x007c0001, + 0xc78, 0x007d0001, + 0xc78, 0x007e0001, + 0xc78, 0x007f0001, + 0xc78, 0x3800001e, + 0xc78, 0x3801001e, + 0xc78, 0x3802001e, + 0xc78, 0x3803001e, + 0xc78, 0x3804001e, + 0xc78, 0x3805001e, + 0xc78, 0x3806001e, + 0xc78, 0x3807001e, + 0xc78, 0x3808001e, + 0xc78, 0x3c09001e, + 0xc78, 0x3e0a001e, + 0xc78, 0x400b001e, + 0xc78, 0x440c001e, + 0xc78, 0x480d001e, + 0xc78, 0x4c0e001e, + 0xc78, 0x500f001e, + 0xc78, 0x5210001e, + 0xc78, 0x5611001e, + 0xc78, 0x5a12001e, + 0xc78, 0x5e13001e, + 0xc78, 0x6014001e, + 0xc78, 0x6015001e, + 0xc78, 0x6016001e, + 0xc78, 0x6217001e, + 0xc78, 0x6218001e, + 0xc78, 0x6219001e, + 0xc78, 0x621a001e, + 0xc78, 0x621b001e, + 0xc78, 0x621c001e, + 0xc78, 0x621d001e, + 0xc78, 0x621e001e, + 0xc78, 0x621f001e, +}; + +u32 RTL8192CUPHY_REG_1T_HPArray[RTL8192CUPHY_REG_1T_HPArrayLength] = { + 0x024, 0x0011800f, + 0x028, 0x00ffdb83, + 0x040, 0x000c0004, + 0x800, 0x80040000, + 0x804, 0x00000001, + 0x808, 0x0000fc00, + 0x80c, 0x0000000a, + 0x810, 0x10005388, + 0x814, 0x020c3d10, + 0x818, 0x02200385, + 0x81c, 0x00000000, + 0x820, 0x01000100, + 0x824, 0x00390204, + 0x828, 0x00000000, + 0x82c, 0x00000000, + 0x830, 0x00000000, + 0x834, 0x00000000, + 0x838, 0x00000000, + 0x83c, 0x00000000, + 0x840, 0x00010000, + 0x844, 0x00000000, + 0x848, 0x00000000, + 0x84c, 0x00000000, + 0x850, 0x00000000, + 0x854, 0x00000000, + 0x858, 0x569a569a, + 0x85c, 0x001b25a4, + 0x860, 0x66e60230, + 0x864, 0x061f0130, + 0x868, 0x00000000, + 0x86c, 0x20202000, + 0x870, 0x03000300, + 0x874, 0x22004000, + 0x878, 0x00000808, + 0x87c, 0x00ffc3f1, + 0x880, 0xc0083070, + 0x884, 0x000004d5, + 0x888, 0x00000000, + 0x88c, 0xccc000c0, + 0x890, 0x00000800, + 0x894, 0xfffffffe, + 0x898, 0x40302010, + 0x89c, 0x00706050, + 0x900, 0x00000000, + 0x904, 0x00000023, + 0x908, 0x00000000, + 0x90c, 0x81121111, + 0xa00, 0x00d047c8, + 0xa04, 0x80ff000c, + 0xa08, 0x8c838300, + 0xa0c, 0x2e68120f, + 0xa10, 0x9500bb78, + 0xa14, 0x11144028, + 0xa18, 0x00881117, + 0xa1c, 0x89140f00, + 0xa20, 0x15160000, + 0xa24, 0x070b0f12, + 0xa28, 0x00000104, + 0xa2c, 0x00d30000, + 0xa70, 0x101fbf00, + 0xa74, 0x00000007, + 0xc00, 0x48071d40, + 0xc04, 0x03a05611, + 0xc08, 0x000000e4, + 0xc0c, 0x6c6c6c6c, + 0xc10, 0x08800000, + 0xc14, 0x40000100, + 0xc18, 0x08800000, + 0xc1c, 0x40000100, + 0xc20, 0x00000000, + 0xc24, 0x00000000, + 0xc28, 0x00000000, + 0xc2c, 0x00000000, + 0xc30, 0x69e9ac44, + 0xc34, 0x469652cf, + 0xc38, 0x49795994, + 0xc3c, 0x0a97971c, + 0xc40, 0x1f7c403f, + 0xc44, 0x000100b7, + 0xc48, 0xec020107, + 0xc4c, 0x007f037f, + 0xc50, 0x6954342e, + 0xc54, 0x43bc0094, + 0xc58, 0x6954342f, + 0xc5c, 0x433c0094, + 0xc60, 0x00000000, + 0xc64, 0x5116848b, + 0xc68, 0x47c00bff, + 0xc6c, 0x00000036, + 0xc70, 0x2c46000d, + 0xc74, 0x018610db, + 0xc78, 0x0000001f, + 0xc7c, 0x00b91612, + 0xc80, 0x24000090, + 0xc84, 0x20f60000, + 0xc88, 0x24000090, + 0xc8c, 0x20200000, + 0xc90, 0x00121820, + 0xc94, 0x00000000, + 0xc98, 0x00121820, + 0xc9c, 0x00007f7f, + 0xca0, 0x00000000, + 0xca4, 0x00000080, + 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, 0x00000000, + 0xce8, 0x37644302, + 0xcec, 0x2f97d40c, + 0xd00, 0x00080740, + 0xd04, 0x00020401, + 0xd08, 0x0000907f, + 0xd0c, 0x20010201, + 0xd10, 0xa0633333, + 0xd14, 0x3333bc43, + 0xd18, 0x7a8f5b6b, + 0xd2c, 0xcc979975, + 0xd30, 0x00000000, + 0xd34, 0x80608000, + 0xd38, 0x00000000, + 0xd3c, 0x00027293, + 0xd40, 0x00000000, + 0xd44, 0x00000000, + 0xd48, 0x00000000, + 0xd4c, 0x00000000, + 0xd50, 0x6437140a, + 0xd54, 0x00000000, + 0xd58, 0x00000000, + 0xd5c, 0x30032064, + 0xd60, 0x4653de68, + 0xd64, 0x04518a3c, + 0xd68, 0x00002101, + 0xd6c, 0x2a201c16, + 0xd70, 0x1812362e, + 0xd74, 0x322c2220, + 0xd78, 0x000e3c24, + 0xe00, 0x24242424, + 0xe04, 0x24242424, + 0xe08, 0x03902024, + 0xe10, 0x24242424, + 0xe14, 0x24242424, + 0xe18, 0x24242424, + 0xe1c, 0x24242424, + 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, 0x001b25a4, + 0xe6c, 0x631b25a0, + 0xe70, 0x631b25a0, + 0xe74, 0x081b25a0, + 0xe78, 0x081b25a0, + 0xe7c, 0x081b25a0, + 0xe80, 0x081b25a0, + 0xe84, 0x631b25a0, + 0xe88, 0x081b25a0, + 0xe8c, 0x631b25a0, + 0xed0, 0x631b25a0, + 0xed4, 0x631b25a0, + 0xed8, 0x631b25a0, + 0xedc, 0x001b25a0, + 0xee0, 0x001b25a0, + 0xeec, 0x6b1b25a0, + 0xee8, 0x31555448, + 0xf14, 0x00000003, + 0xf4c, 0x00000000, + 0xf00, 0x00000300, +}; + +u32 RTL8192CUPHY_REG_Array_PG_HP[RTL8192CUPHY_REG_Array_PG_HPLength] = { + 0xe00, 0xffffffff, 0x06080808, + 0xe04, 0xffffffff, 0x00040406, + 0xe08, 0x0000ff00, 0x00000000, + 0x86c, 0xffffff00, 0x00000000, + 0xe10, 0xffffffff, 0x04060608, + 0xe14, 0xffffffff, 0x00020204, + 0xe18, 0xffffffff, 0x04060608, + 0xe1c, 0xffffffff, 0x00020204, + 0x830, 0xffffffff, 0x06080808, + 0x834, 0xffffffff, 0x00040406, + 0x838, 0xffffff00, 0x00000000, + 0x86c, 0x000000ff, 0x00000000, + 0x83c, 0xffffffff, 0x04060608, + 0x848, 0xffffffff, 0x00020204, + 0x84c, 0xffffffff, 0x04060608, + 0x868, 0xffffffff, 0x00020204, + 0xe00, 0xffffffff, 0x00000000, + 0xe04, 0xffffffff, 0x00000000, + 0xe08, 0x0000ff00, 0x00000000, + 0x86c, 0xffffff00, 0x00000000, + 0xe10, 0xffffffff, 0x00000000, + 0xe14, 0xffffffff, 0x00000000, + 0xe18, 0xffffffff, 0x00000000, + 0xe1c, 0xffffffff, 0x00000000, + 0x830, 0xffffffff, 0x00000000, + 0x834, 0xffffffff, 0x00000000, + 0x838, 0xffffff00, 0x00000000, + 0x86c, 0x000000ff, 0x00000000, + 0x83c, 0xffffffff, 0x00000000, + 0x848, 0xffffffff, 0x00000000, + 0x84c, 0xffffffff, 0x00000000, + 0x868, 0xffffffff, 0x00000000, + 0xe00, 0xffffffff, 0x00000000, + 0xe04, 0xffffffff, 0x00000000, + 0xe08, 0x0000ff00, 0x00000000, + 0x86c, 0xffffff00, 0x00000000, + 0xe10, 0xffffffff, 0x00000000, + 0xe14, 0xffffffff, 0x00000000, + 0xe18, 0xffffffff, 0x00000000, + 0xe1c, 0xffffffff, 0x00000000, + 0x830, 0xffffffff, 0x00000000, + 0x834, 0xffffffff, 0x00000000, + 0x838, 0xffffff00, 0x00000000, + 0x86c, 0x000000ff, 0x00000000, + 0x83c, 0xffffffff, 0x00000000, + 0x848, 0xffffffff, 0x00000000, + 0x84c, 0xffffffff, 0x00000000, + 0x868, 0xffffffff, 0x00000000, + 0xe00, 0xffffffff, 0x00000000, + 0xe04, 0xffffffff, 0x00000000, + 0xe08, 0x0000ff00, 0x00000000, + 0x86c, 0xffffff00, 0x00000000, + 0xe10, 0xffffffff, 0x00000000, + 0xe14, 0xffffffff, 0x00000000, + 0xe18, 0xffffffff, 0x00000000, + 0xe1c, 0xffffffff, 0x00000000, + 0x830, 0xffffffff, 0x00000000, + 0x834, 0xffffffff, 0x00000000, + 0x838, 0xffffff00, 0x00000000, + 0x86c, 0x000000ff, 0x00000000, + 0x83c, 0xffffffff, 0x00000000, + 0x848, 0xffffffff, 0x00000000, + 0x84c, 0xffffffff, 0x00000000, + 0x868, 0xffffffff, 0x00000000, + 0xe00, 0xffffffff, 0x00000000, + 0xe04, 0xffffffff, 0x00000000, + 0xe08, 0x0000ff00, 0x00000000, + 0x86c, 0xffffff00, 0x00000000, + 0xe10, 0xffffffff, 0x00000000, + 0xe14, 0xffffffff, 0x00000000, + 0xe18, 0xffffffff, 0x00000000, + 0xe1c, 0xffffffff, 0x00000000, + 0x830, 0xffffffff, 0x00000000, + 0x834, 0xffffffff, 0x00000000, + 0x838, 0xffffff00, 0x00000000, + 0x86c, 0x000000ff, 0x00000000, + 0x83c, 0xffffffff, 0x00000000, + 0x848, 0xffffffff, 0x00000000, + 0x84c, 0xffffffff, 0x00000000, + 0x868, 0xffffffff, 0x00000000, + 0xe00, 0xffffffff, 0x00000000, + 0xe04, 0xffffffff, 0x00000000, + 0xe08, 0x0000ff00, 0x00000000, + 0x86c, 0xffffff00, 0x00000000, + 0xe10, 0xffffffff, 0x00000000, + 0xe14, 0xffffffff, 0x00000000, + 0xe18, 0xffffffff, 0x00000000, + 0xe1c, 0xffffffff, 0x00000000, + 0x830, 0xffffffff, 0x00000000, + 0x834, 0xffffffff, 0x00000000, + 0x838, 0xffffff00, 0x00000000, + 0x86c, 0x000000ff, 0x00000000, + 0x83c, 0xffffffff, 0x00000000, + 0x848, 0xffffffff, 0x00000000, + 0x84c, 0xffffffff, 0x00000000, + 0x868, 0xffffffff, 0x00000000, + 0xe00, 0xffffffff, 0x00000000, + 0xe04, 0xffffffff, 0x00000000, + 0xe08, 0x0000ff00, 0x00000000, + 0x86c, 0xffffff00, 0x00000000, + 0xe10, 0xffffffff, 0x00000000, + 0xe14, 0xffffffff, 0x00000000, + 0xe18, 0xffffffff, 0x00000000, + 0xe1c, 0xffffffff, 0x00000000, + 0x830, 0xffffffff, 0x00000000, + 0x834, 0xffffffff, 0x00000000, + 0x838, 0xffffff00, 0x00000000, + 0x86c, 0x000000ff, 0x00000000, + 0x83c, 0xffffffff, 0x00000000, + 0x848, 0xffffffff, 0x00000000, + 0x84c, 0xffffffff, 0x00000000, + 0x868, 0xffffffff, 0x00000000, +}; + +u32 RTL8192CURadioA_1T_HPArray[RTL8192CURadioA_1T_HPArrayLength] = { + 0x000, 0x00030159, + 0x001, 0x00031284, + 0x002, 0x00098000, + 0x003, 0x00018c63, + 0x004, 0x000210e7, + 0x009, 0x0002044f, + 0x00a, 0x0001adb0, + 0x00b, 0x00054867, + 0x00c, 0x0008992e, + 0x00d, 0x0000e529, + 0x00e, 0x00039ce7, + 0x00f, 0x00000451, + 0x019, 0x00000000, + 0x01a, 0x00000255, + 0x01b, 0x00060a00, + 0x01c, 0x000fc378, + 0x01d, 0x000a1250, + 0x01e, 0x0004445f, + 0x01f, 0x00080001, + 0x020, 0x0000b614, + 0x021, 0x0006c000, + 0x022, 0x0000083c, + 0x023, 0x00001558, + 0x024, 0x00000060, + 0x025, 0x00000483, + 0x026, 0x0004f000, + 0x027, 0x000ec7d9, + 0x028, 0x000977c0, + 0x029, 0x00004783, + 0x02a, 0x00000001, + 0x02b, 0x00021334, + 0x02a, 0x00000000, + 0x02b, 0x00000054, + 0x02a, 0x00000001, + 0x02b, 0x00000808, + 0x02b, 0x00053333, + 0x02c, 0x0000000c, + 0x02a, 0x00000002, + 0x02b, 0x00000808, + 0x02b, 0x0005b333, + 0x02c, 0x0000000d, + 0x02a, 0x00000003, + 0x02b, 0x00000808, + 0x02b, 0x00063333, + 0x02c, 0x0000000d, + 0x02a, 0x00000004, + 0x02b, 0x00000808, + 0x02b, 0x0006b333, + 0x02c, 0x0000000d, + 0x02a, 0x00000005, + 0x02b, 0x00000808, + 0x02b, 0x00073333, + 0x02c, 0x0000000d, + 0x02a, 0x00000006, + 0x02b, 0x00000709, + 0x02b, 0x0005b333, + 0x02c, 0x0000000d, + 0x02a, 0x00000007, + 0x02b, 0x00000709, + 0x02b, 0x00063333, + 0x02c, 0x0000000d, + 0x02a, 0x00000008, + 0x02b, 0x0000060a, + 0x02b, 0x0004b333, + 0x02c, 0x0000000d, + 0x02a, 0x00000009, + 0x02b, 0x0000060a, + 0x02b, 0x00053333, + 0x02c, 0x0000000d, + 0x02a, 0x0000000a, + 0x02b, 0x0000060a, + 0x02b, 0x0005b333, + 0x02c, 0x0000000d, + 0x02a, 0x0000000b, + 0x02b, 0x0000060a, + 0x02b, 0x00063333, + 0x02c, 0x0000000d, + 0x02a, 0x0000000c, + 0x02b, 0x0000060a, + 0x02b, 0x0006b333, + 0x02c, 0x0000000d, + 0x02a, 0x0000000d, + 0x02b, 0x0000060a, + 0x02b, 0x00073333, + 0x02c, 0x0000000d, + 0x02a, 0x0000000e, + 0x02b, 0x0000050b, + 0x02b, 0x00066666, + 0x02c, 0x0000001a, + 0x02a, 0x000e0000, + 0x010, 0x0004000f, + 0x011, 0x000e31fc, + 0x010, 0x0006000f, + 0x011, 0x000ff9f8, + 0x010, 0x0002000f, + 0x011, 0x000203f9, + 0x010, 0x0003000f, + 0x011, 0x000ff500, + 0x010, 0x00000000, + 0x011, 0x00000000, + 0x010, 0x0008000f, + 0x011, 0x0003f100, + 0x010, 0x0009000f, + 0x011, 0x00023100, + 0x012, 0x000d8000, + 0x012, 0x00090000, + 0x012, 0x00051000, + 0x012, 0x00012000, + 0x013, 0x00028fb4, + 0x013, 0x00024fa8, + 0x013, 0x000207a4, + 0x013, 0x0001c798, + 0x013, 0x000183a4, + 0x013, 0x00014398, + 0x013, 0x000101a4, + 0x013, 0x0000c198, + 0x013, 0x000080a4, + 0x013, 0x00004098, + 0x013, 0x00000000, + 0x014, 0x0001944c, + 0x014, 0x00059444, + 0x014, 0x0009944c, + 0x014, 0x000d9444, + 0x015, 0x0000f405, + 0x015, 0x0004f405, + 0x015, 0x0008f405, + 0x015, 0x000cf405, + 0x016, 0x000e0330, + 0x016, 0x000a0330, + 0x016, 0x00060330, + 0x016, 0x00020330, + 0x000, 0x00010159, + 0x018, 0x0000f401, + 0x0fe, 0x00000000, + 0x0fe, 0x00000000, + 0x01f, 0x00080003, + 0x0fe, 0x00000000, + 0x0fe, 0x00000000, + 0x01e, 0x00044457, + 0x01f, 0x00080000, + 0x000, 0x00030159, +}; + +u32 Rtl8192CUAGCTAB_1T_HPArray[RTL8192CUAGCTAB_1T_HPArrayLength] = { + 0xc78, 0x7b000001, + 0xc78, 0x7b010001, + 0xc78, 0x7b020001, + 0xc78, 0x7b030001, + 0xc78, 0x7b040001, + 0xc78, 0x7b050001, + 0xc78, 0x7b060001, + 0xc78, 0x7b070001, + 0xc78, 0x7b080001, + 0xc78, 0x7a090001, + 0xc78, 0x790a0001, + 0xc78, 0x780b0001, + 0xc78, 0x770c0001, + 0xc78, 0x760d0001, + 0xc78, 0x750e0001, + 0xc78, 0x740f0001, + 0xc78, 0x73100001, + 0xc78, 0x72110001, + 0xc78, 0x71120001, + 0xc78, 0x70130001, + 0xc78, 0x6f140001, + 0xc78, 0x6e150001, + 0xc78, 0x6d160001, + 0xc78, 0x6c170001, + 0xc78, 0x6b180001, + 0xc78, 0x6a190001, + 0xc78, 0x691a0001, + 0xc78, 0x681b0001, + 0xc78, 0x671c0001, + 0xc78, 0x661d0001, + 0xc78, 0x651e0001, + 0xc78, 0x641f0001, + 0xc78, 0x63200001, + 0xc78, 0x62210001, + 0xc78, 0x61220001, + 0xc78, 0x60230001, + 0xc78, 0x46240001, + 0xc78, 0x45250001, + 0xc78, 0x44260001, + 0xc78, 0x43270001, + 0xc78, 0x42280001, + 0xc78, 0x41290001, + 0xc78, 0x402a0001, + 0xc78, 0x262b0001, + 0xc78, 0x252c0001, + 0xc78, 0x242d0001, + 0xc78, 0x232e0001, + 0xc78, 0x222f0001, + 0xc78, 0x21300001, + 0xc78, 0x20310001, + 0xc78, 0x06320001, + 0xc78, 0x05330001, + 0xc78, 0x04340001, + 0xc78, 0x03350001, + 0xc78, 0x02360001, + 0xc78, 0x01370001, + 0xc78, 0x00380001, + 0xc78, 0x00390001, + 0xc78, 0x003a0001, + 0xc78, 0x003b0001, + 0xc78, 0x003c0001, + 0xc78, 0x003d0001, + 0xc78, 0x003e0001, + 0xc78, 0x003f0001, + 0xc78, 0x7b400001, + 0xc78, 0x7b410001, + 0xc78, 0x7b420001, + 0xc78, 0x7b430001, + 0xc78, 0x7b440001, + 0xc78, 0x7b450001, + 0xc78, 0x7b460001, + 0xc78, 0x7b470001, + 0xc78, 0x7b480001, + 0xc78, 0x7a490001, + 0xc78, 0x794a0001, + 0xc78, 0x784b0001, + 0xc78, 0x774c0001, + 0xc78, 0x764d0001, + 0xc78, 0x754e0001, + 0xc78, 0x744f0001, + 0xc78, 0x73500001, + 0xc78, 0x72510001, + 0xc78, 0x71520001, + 0xc78, 0x70530001, + 0xc78, 0x6f540001, + 0xc78, 0x6e550001, + 0xc78, 0x6d560001, + 0xc78, 0x6c570001, + 0xc78, 0x6b580001, + 0xc78, 0x6a590001, + 0xc78, 0x695a0001, + 0xc78, 0x685b0001, + 0xc78, 0x675c0001, + 0xc78, 0x665d0001, + 0xc78, 0x655e0001, + 0xc78, 0x645f0001, + 0xc78, 0x63600001, + 0xc78, 0x62610001, + 0xc78, 0x61620001, + 0xc78, 0x60630001, + 0xc78, 0x46640001, + 0xc78, 0x45650001, + 0xc78, 0x44660001, + 0xc78, 0x43670001, + 0xc78, 0x42680001, + 0xc78, 0x41690001, + 0xc78, 0x406a0001, + 0xc78, 0x266b0001, + 0xc78, 0x256c0001, + 0xc78, 0x246d0001, + 0xc78, 0x236e0001, + 0xc78, 0x226f0001, + 0xc78, 0x21700001, + 0xc78, 0x20710001, + 0xc78, 0x06720001, + 0xc78, 0x05730001, + 0xc78, 0x04740001, + 0xc78, 0x03750001, + 0xc78, 0x02760001, + 0xc78, 0x01770001, + 0xc78, 0x00780001, + 0xc78, 0x00790001, + 0xc78, 0x007a0001, + 0xc78, 0x007b0001, + 0xc78, 0x007c0001, + 0xc78, 0x007d0001, + 0xc78, 0x007e0001, + 0xc78, 0x007f0001, + 0xc78, 0x3800001e, + 0xc78, 0x3801001e, + 0xc78, 0x3802001e, + 0xc78, 0x3803001e, + 0xc78, 0x3804001e, + 0xc78, 0x3805001e, + 0xc78, 0x3806001e, + 0xc78, 0x3807001e, + 0xc78, 0x3808001e, + 0xc78, 0x3c09001e, + 0xc78, 0x3e0a001e, + 0xc78, 0x400b001e, + 0xc78, 0x440c001e, + 0xc78, 0x480d001e, + 0xc78, 0x4c0e001e, + 0xc78, 0x500f001e, + 0xc78, 0x5210001e, + 0xc78, 0x5611001e, + 0xc78, 0x5a12001e, + 0xc78, 0x5e13001e, + 0xc78, 0x6014001e, + 0xc78, 0x6015001e, + 0xc78, 0x6016001e, + 0xc78, 0x6217001e, + 0xc78, 0x6218001e, + 0xc78, 0x6219001e, + 0xc78, 0x621a001e, + 0xc78, 0x621b001e, + 0xc78, 0x621c001e, + 0xc78, 0x621d001e, + 0xc78, 0x621e001e, + 0xc78, 0x621f001e, +}; diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/table.h b/drivers/net/wireless/rtlwifi/rtl8192cu/table.h new file mode 100644 index 00000000..4b020e9e --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/table.h @@ -0,0 +1,71 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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. + * + * 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 __RTL92CU_TABLE__H_ +#define __RTL92CU_TABLE__H_ + +#include <linux/types.h> + +#define RTL8192CUPHY_REG_2TARRAY_LENGTH 374 +extern u32 RTL8192CUPHY_REG_2TARRAY[RTL8192CUPHY_REG_2TARRAY_LENGTH]; +#define RTL8192CUPHY_REG_1TARRAY_LENGTH 374 +extern u32 RTL8192CUPHY_REG_1TARRAY[RTL8192CUPHY_REG_1TARRAY_LENGTH]; + +#define RTL8192CUPHY_REG_ARRAY_PGLENGTH 336 +extern u32 RTL8192CUPHY_REG_ARRAY_PG[RTL8192CUPHY_REG_ARRAY_PGLENGTH]; + +#define RTL8192CURADIOA_2TARRAYLENGTH 282 +extern u32 RTL8192CURADIOA_2TARRAY[RTL8192CURADIOA_2TARRAYLENGTH]; +#define RTL8192CURADIOB_2TARRAYLENGTH 78 +extern u32 RTL8192CU_RADIOB_2TARRAY[RTL8192CURADIOB_2TARRAYLENGTH]; +#define RTL8192CURADIOA_1TARRAYLENGTH 282 +extern u32 RTL8192CU_RADIOA_1TARRAY[RTL8192CURADIOA_1TARRAYLENGTH]; +#define RTL8192CURADIOB_1TARRAYLENGTH 1 +extern u32 RTL8192CU_RADIOB_1TARRAY[RTL8192CURADIOB_1TARRAYLENGTH]; + +#define RTL8192CUMAC_2T_ARRAYLENGTH 172 +extern u32 RTL8192CUMAC_2T_ARRAY[RTL8192CUMAC_2T_ARRAYLENGTH]; + +#define RTL8192CUAGCTAB_2TARRAYLENGTH 320 +extern u32 RTL8192CUAGCTAB_2TARRAY[RTL8192CUAGCTAB_2TARRAYLENGTH]; +#define RTL8192CUAGCTAB_1TARRAYLENGTH 320 +extern u32 RTL8192CUAGCTAB_1TARRAY[RTL8192CUAGCTAB_1TARRAYLENGTH]; + +#define RTL8192CUPHY_REG_1T_HPArrayLength 378 +extern u32 RTL8192CUPHY_REG_1T_HPArray[RTL8192CUPHY_REG_1T_HPArrayLength]; + +#define RTL8192CUPHY_REG_Array_PG_HPLength 336 +extern u32 RTL8192CUPHY_REG_Array_PG_HP[RTL8192CUPHY_REG_Array_PG_HPLength]; + +#define RTL8192CURadioA_1T_HPArrayLength 282 +extern u32 RTL8192CURadioA_1T_HPArray[RTL8192CURadioA_1T_HPArrayLength]; +#define RTL8192CUAGCTAB_1T_HPArrayLength 320 +extern u32 Rtl8192CUAGCTAB_1T_HPArray[RTL8192CUAGCTAB_1T_HPArrayLength]; + +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c new file mode 100644 index 00000000..21bc827c --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c @@ -0,0 +1,687 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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. + * + * 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> + * + *****************************************************************************/ + +#include "../wifi.h" +#include "../usb.h" +#include "../ps.h" +#include "../base.h" +#include "reg.h" +#include "def.h" +#include "phy.h" +#include "rf.h" +#include "dm.h" +#include "mac.h" +#include "trx.h" + +static int _ConfigVerTOutEP(struct ieee80211_hw *hw) +{ + u8 ep_cfg, txqsele; + u8 ep_nums = 0; + + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_usb_priv *usb_priv = rtl_usbpriv(hw); + struct rtl_usb *rtlusb = rtl_usbdev(usb_priv); + + rtlusb->out_queue_sel = 0; + ep_cfg = rtl_read_byte(rtlpriv, REG_TEST_SIE_OPTIONAL); + ep_cfg = (ep_cfg & USB_TEST_EP_MASK) >> USB_TEST_EP_SHIFT; + switch (ep_cfg) { + case 0: /* 2 bulk OUT, 1 bulk IN */ + case 3: + rtlusb->out_queue_sel = TX_SELE_HQ | TX_SELE_LQ; + ep_nums = 2; + break; + case 1: /* 1 bulk IN/OUT => map all endpoint to Low queue */ + case 2: /* 1 bulk IN, 1 bulk OUT => map all endpoint to High queue */ + txqsele = rtl_read_byte(rtlpriv, REG_TEST_USB_TXQS); + if (txqsele & 0x0F) /* /map all endpoint to High queue */ + rtlusb->out_queue_sel = TX_SELE_HQ; + else if (txqsele&0xF0) /* map all endpoint to Low queue */ + rtlusb->out_queue_sel = TX_SELE_LQ; + ep_nums = 1; + break; + default: + break; + } + return (rtlusb->out_ep_nums == ep_nums) ? 0 : -EINVAL; +} + +static int _ConfigVerNOutEP(struct ieee80211_hw *hw) +{ + u8 ep_cfg; + u8 ep_nums = 0; + + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_usb_priv *usb_priv = rtl_usbpriv(hw); + struct rtl_usb *rtlusb = rtl_usbdev(usb_priv); + + rtlusb->out_queue_sel = 0; + /* Normal and High queue */ + ep_cfg = rtl_read_byte(rtlpriv, (REG_NORMAL_SIE_EP + 1)); + if (ep_cfg & USB_NORMAL_SIE_EP_MASK) { + rtlusb->out_queue_sel |= TX_SELE_HQ; + ep_nums++; + } + if ((ep_cfg >> USB_NORMAL_SIE_EP_SHIFT) & USB_NORMAL_SIE_EP_MASK) { + rtlusb->out_queue_sel |= TX_SELE_NQ; + ep_nums++; + } + /* Low queue */ + ep_cfg = rtl_read_byte(rtlpriv, (REG_NORMAL_SIE_EP + 2)); + if (ep_cfg & USB_NORMAL_SIE_EP_MASK) { + rtlusb->out_queue_sel |= TX_SELE_LQ; + ep_nums++; + } + return (rtlusb->out_ep_nums == ep_nums) ? 0 : -EINVAL; +} + +static void _TwoOutEpMapping(struct ieee80211_hw *hw, bool bIsChipB, + bool bwificfg, struct rtl_ep_map *ep_map) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + if (bwificfg) { /* for WMM */ + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "USB Chip-B & WMM Setting.....\n"); + ep_map->ep_mapping[RTL_TXQ_BE] = 2; + ep_map->ep_mapping[RTL_TXQ_BK] = 3; + ep_map->ep_mapping[RTL_TXQ_VI] = 3; + ep_map->ep_mapping[RTL_TXQ_VO] = 2; + ep_map->ep_mapping[RTL_TXQ_MGT] = 2; + ep_map->ep_mapping[RTL_TXQ_BCN] = 2; + ep_map->ep_mapping[RTL_TXQ_HI] = 2; + } else { /* typical setting */ + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "USB typical Setting.....\n"); + ep_map->ep_mapping[RTL_TXQ_BE] = 3; + ep_map->ep_mapping[RTL_TXQ_BK] = 3; + ep_map->ep_mapping[RTL_TXQ_VI] = 2; + ep_map->ep_mapping[RTL_TXQ_VO] = 2; + ep_map->ep_mapping[RTL_TXQ_MGT] = 2; + ep_map->ep_mapping[RTL_TXQ_BCN] = 2; + ep_map->ep_mapping[RTL_TXQ_HI] = 2; + } +} + +static void _ThreeOutEpMapping(struct ieee80211_hw *hw, bool bwificfg, + struct rtl_ep_map *ep_map) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + if (bwificfg) { /* for WMM */ + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "USB 3EP Setting for WMM.....\n"); + ep_map->ep_mapping[RTL_TXQ_BE] = 5; + ep_map->ep_mapping[RTL_TXQ_BK] = 3; + ep_map->ep_mapping[RTL_TXQ_VI] = 3; + ep_map->ep_mapping[RTL_TXQ_VO] = 2; + ep_map->ep_mapping[RTL_TXQ_MGT] = 2; + ep_map->ep_mapping[RTL_TXQ_BCN] = 2; + ep_map->ep_mapping[RTL_TXQ_HI] = 2; + } else { /* typical setting */ + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "USB 3EP Setting for typical.....\n"); + ep_map->ep_mapping[RTL_TXQ_BE] = 5; + ep_map->ep_mapping[RTL_TXQ_BK] = 5; + ep_map->ep_mapping[RTL_TXQ_VI] = 3; + ep_map->ep_mapping[RTL_TXQ_VO] = 2; + ep_map->ep_mapping[RTL_TXQ_MGT] = 2; + ep_map->ep_mapping[RTL_TXQ_BCN] = 2; + ep_map->ep_mapping[RTL_TXQ_HI] = 2; + } +} + +static void _OneOutEpMapping(struct ieee80211_hw *hw, struct rtl_ep_map *ep_map) +{ + ep_map->ep_mapping[RTL_TXQ_BE] = 2; + ep_map->ep_mapping[RTL_TXQ_BK] = 2; + ep_map->ep_mapping[RTL_TXQ_VI] = 2; + ep_map->ep_mapping[RTL_TXQ_VO] = 2; + ep_map->ep_mapping[RTL_TXQ_MGT] = 2; + ep_map->ep_mapping[RTL_TXQ_BCN] = 2; + ep_map->ep_mapping[RTL_TXQ_HI] = 2; +} +static int _out_ep_mapping(struct ieee80211_hw *hw) +{ + int err = 0; + bool bIsChipN, bwificfg = false; + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_usb_priv *usb_priv = rtl_usbpriv(hw); + struct rtl_usb *rtlusb = rtl_usbdev(usb_priv); + struct rtl_ep_map *ep_map = &(rtlusb->ep_map); + + bIsChipN = IS_NORMAL_CHIP(rtlhal->version); + switch (rtlusb->out_ep_nums) { + case 2: + _TwoOutEpMapping(hw, bIsChipN, bwificfg, ep_map); + break; + case 3: + /* Test chip doesn't support three out EPs. */ + if (!bIsChipN) { + err = -EINVAL; + goto err_out; + } + _ThreeOutEpMapping(hw, bIsChipN, ep_map); + break; + case 1: + _OneOutEpMapping(hw, ep_map); + break; + default: + err = -EINVAL; + break; + } +err_out: + return err; + +} +/* endpoint mapping */ +int rtl8192cu_endpoint_mapping(struct ieee80211_hw *hw) +{ + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + int error = 0; + if (likely(IS_NORMAL_CHIP(rtlhal->version))) + error = _ConfigVerNOutEP(hw); + else + error = _ConfigVerTOutEP(hw); + if (error) + goto err_out; + error = _out_ep_mapping(hw); + if (error) + goto err_out; +err_out: + return error; +} + +u16 rtl8192cu_mq_to_hwq(__le16 fc, u16 mac80211_queue_index) +{ + u16 hw_queue_index; + + if (unlikely(ieee80211_is_beacon(fc))) { + hw_queue_index = RTL_TXQ_BCN; + goto out; + } + if (ieee80211_is_mgmt(fc)) { + hw_queue_index = RTL_TXQ_MGT; + goto out; + } + switch (mac80211_queue_index) { + case 0: + hw_queue_index = RTL_TXQ_VO; + break; + case 1: + hw_queue_index = RTL_TXQ_VI; + break; + case 2: + hw_queue_index = RTL_TXQ_BE; + break; + case 3: + hw_queue_index = RTL_TXQ_BK; + break; + default: + hw_queue_index = RTL_TXQ_BE; + RT_ASSERT(false, "QSLT_BE queue, skb_queue:%d\n", + mac80211_queue_index); + break; + } +out: + return hw_queue_index; +} + +static enum rtl_desc_qsel _rtl8192cu_mq_to_descq(struct ieee80211_hw *hw, + __le16 fc, u16 mac80211_queue_index) +{ + enum rtl_desc_qsel qsel; + struct rtl_priv *rtlpriv = rtl_priv(hw); + + if (unlikely(ieee80211_is_beacon(fc))) { + qsel = QSLT_BEACON; + goto out; + } + if (ieee80211_is_mgmt(fc)) { + qsel = QSLT_MGNT; + goto out; + } + switch (mac80211_queue_index) { + case 0: /* VO */ + qsel = QSLT_VO; + RT_TRACE(rtlpriv, COMP_USB, DBG_DMESG, + "VO queue, set qsel = 0x%x\n", QSLT_VO); + break; + case 1: /* VI */ + qsel = QSLT_VI; + RT_TRACE(rtlpriv, COMP_USB, DBG_DMESG, + "VI queue, set qsel = 0x%x\n", QSLT_VI); + break; + case 3: /* BK */ + qsel = QSLT_BK; + RT_TRACE(rtlpriv, COMP_USB, DBG_DMESG, + "BK queue, set qsel = 0x%x\n", QSLT_BK); + break; + case 2: /* BE */ + default: + qsel = QSLT_BE; + RT_TRACE(rtlpriv, COMP_USB, DBG_DMESG, + "BE queue, set qsel = 0x%x\n", QSLT_BE); + break; + } +out: + return qsel; +} + +/* =============================================================== */ + +/*---------------------------------------------------------------------- + * + * Rx handler + * + *---------------------------------------------------------------------- */ +bool rtl92cu_rx_query_desc(struct ieee80211_hw *hw, + struct rtl_stats *stats, + struct ieee80211_rx_status *rx_status, + u8 *p_desc, struct sk_buff *skb) +{ + struct rx_fwinfo_92c *p_drvinfo; + struct rx_desc_92c *pdesc = (struct rx_desc_92c *)p_desc; + u32 phystatus = GET_RX_DESC_PHY_STATUS(pdesc); + + stats->length = (u16) GET_RX_DESC_PKT_LEN(pdesc); + stats->rx_drvinfo_size = (u8)GET_RX_DESC_DRVINFO_SIZE(pdesc) * + RX_DRV_INFO_SIZE_UNIT; + stats->rx_bufshift = (u8) (GET_RX_DESC_SHIFT(pdesc) & 0x03); + stats->icv = (u16) GET_RX_DESC_ICV(pdesc); + stats->crc = (u16) GET_RX_DESC_CRC32(pdesc); + stats->hwerror = (stats->crc | stats->icv); + stats->decrypted = !GET_RX_DESC_SWDEC(pdesc); + stats->rate = (u8) GET_RX_DESC_RX_MCS(pdesc); + stats->shortpreamble = (u16) GET_RX_DESC_SPLCP(pdesc); + stats->isampdu = (bool) (GET_RX_DESC_PAGGR(pdesc) == 1); + stats->isampdu = (bool) ((GET_RX_DESC_PAGGR(pdesc) == 1) + && (GET_RX_DESC_FAGGR(pdesc) == 1)); + stats->timestamp_low = GET_RX_DESC_TSFL(pdesc); + stats->rx_is40Mhzpacket = (bool) GET_RX_DESC_BW(pdesc); + rx_status->freq = hw->conf.channel->center_freq; + rx_status->band = hw->conf.channel->band; + if (GET_RX_DESC_CRC32(pdesc)) + rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; + if (!GET_RX_DESC_SWDEC(pdesc)) + rx_status->flag |= RX_FLAG_DECRYPTED; + if (GET_RX_DESC_BW(pdesc)) + rx_status->flag |= RX_FLAG_40MHZ; + if (GET_RX_DESC_RX_HT(pdesc)) + rx_status->flag |= RX_FLAG_HT; + rx_status->flag |= RX_FLAG_MACTIME_MPDU; + if (stats->decrypted) + rx_status->flag |= RX_FLAG_DECRYPTED; + rx_status->rate_idx = rtlwifi_rate_mapping(hw, + (bool)GET_RX_DESC_RX_HT(pdesc), + (u8)GET_RX_DESC_RX_MCS(pdesc), + (bool)GET_RX_DESC_PAGGR(pdesc)); + rx_status->mactime = GET_RX_DESC_TSFL(pdesc); + if (phystatus) { + p_drvinfo = (struct rx_fwinfo_92c *)(pdesc + RTL_RX_DESC_SIZE); + rtl92c_translate_rx_signal_stuff(hw, skb, stats, pdesc, + p_drvinfo); + } + /*rx_status->qual = stats->signal; */ + rx_status->signal = stats->rssi + 10; + /*rx_status->noise = -stats->noise; */ + return true; +} + +#define RTL_RX_DRV_INFO_UNIT 8 + +static void _rtl_rx_process(struct ieee80211_hw *hw, struct sk_buff *skb) +{ + struct ieee80211_rx_status *rx_status = + (struct ieee80211_rx_status *)IEEE80211_SKB_RXCB(skb); + u32 skb_len, pkt_len, drvinfo_len; + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 *rxdesc; + struct rtl_stats stats = { + .signal = 0, + .noise = -98, + .rate = 0, + }; + struct rx_fwinfo_92c *p_drvinfo; + bool bv; + __le16 fc; + struct ieee80211_hdr *hdr; + + memset(rx_status, 0, sizeof(*rx_status)); + rxdesc = skb->data; + skb_len = skb->len; + drvinfo_len = (GET_RX_DESC_DRVINFO_SIZE(rxdesc) * RTL_RX_DRV_INFO_UNIT); + pkt_len = GET_RX_DESC_PKT_LEN(rxdesc); + /* TODO: Error recovery. drop this skb or something. */ + WARN_ON(skb_len < (pkt_len + RTL_RX_DESC_SIZE + drvinfo_len)); + stats.length = (u16) GET_RX_DESC_PKT_LEN(rxdesc); + stats.rx_drvinfo_size = (u8)GET_RX_DESC_DRVINFO_SIZE(rxdesc) * + RX_DRV_INFO_SIZE_UNIT; + stats.rx_bufshift = (u8) (GET_RX_DESC_SHIFT(rxdesc) & 0x03); + stats.icv = (u16) GET_RX_DESC_ICV(rxdesc); + stats.crc = (u16) GET_RX_DESC_CRC32(rxdesc); + stats.hwerror = (stats.crc | stats.icv); + stats.decrypted = !GET_RX_DESC_SWDEC(rxdesc); + stats.rate = (u8) GET_RX_DESC_RX_MCS(rxdesc); + stats.shortpreamble = (u16) GET_RX_DESC_SPLCP(rxdesc); + stats.isampdu = (bool) ((GET_RX_DESC_PAGGR(rxdesc) == 1) + && (GET_RX_DESC_FAGGR(rxdesc) == 1)); + stats.timestamp_low = GET_RX_DESC_TSFL(rxdesc); + stats.rx_is40Mhzpacket = (bool) GET_RX_DESC_BW(rxdesc); + /* TODO: is center_freq changed when doing scan? */ + /* TODO: Shall we add protection or just skip those two step? */ + rx_status->freq = hw->conf.channel->center_freq; + rx_status->band = hw->conf.channel->band; + if (GET_RX_DESC_CRC32(rxdesc)) + rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; + if (!GET_RX_DESC_SWDEC(rxdesc)) + rx_status->flag |= RX_FLAG_DECRYPTED; + if (GET_RX_DESC_BW(rxdesc)) + rx_status->flag |= RX_FLAG_40MHZ; + if (GET_RX_DESC_RX_HT(rxdesc)) + rx_status->flag |= RX_FLAG_HT; + /* Data rate */ + rx_status->rate_idx = rtlwifi_rate_mapping(hw, + (bool)GET_RX_DESC_RX_HT(rxdesc), + (u8)GET_RX_DESC_RX_MCS(rxdesc), + (bool)GET_RX_DESC_PAGGR(rxdesc)); + /* There is a phy status after this rx descriptor. */ + if (GET_RX_DESC_PHY_STATUS(rxdesc)) { + p_drvinfo = (struct rx_fwinfo_92c *)(rxdesc + RTL_RX_DESC_SIZE); + rtl92c_translate_rx_signal_stuff(hw, skb, &stats, + (struct rx_desc_92c *)rxdesc, p_drvinfo); + } + skb_pull(skb, (drvinfo_len + RTL_RX_DESC_SIZE)); + hdr = (struct ieee80211_hdr *)(skb->data); + fc = hdr->frame_control; + bv = ieee80211_is_probe_resp(fc); + if (bv) + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "Got probe response frame\n"); + if (ieee80211_is_beacon(fc)) + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "Got beacon frame\n"); + if (ieee80211_is_data(fc)) + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "Got data frame\n"); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "Fram: fc = 0x%X addr1 = 0x%02X:0x%02X:0x%02X:0x%02X:0x%02X:0x%02X\n", + fc, + (u32)hdr->addr1[0], (u32)hdr->addr1[1], + (u32)hdr->addr1[2], (u32)hdr->addr1[3], + (u32)hdr->addr1[4], (u32)hdr->addr1[5]); + memcpy(IEEE80211_SKB_RXCB(skb), rx_status, sizeof(*rx_status)); + ieee80211_rx_irqsafe(hw, skb); +} + +void rtl8192cu_rx_hdl(struct ieee80211_hw *hw, struct sk_buff * skb) +{ + _rtl_rx_process(hw, skb); +} + +void rtl8192c_rx_segregate_hdl( + struct ieee80211_hw *hw, + struct sk_buff *skb, + struct sk_buff_head *skb_list) +{ +} + +/*---------------------------------------------------------------------- + * + * Tx handler + * + *---------------------------------------------------------------------- */ +void rtl8192c_tx_cleanup(struct ieee80211_hw *hw, struct sk_buff *skb) +{ +} + +int rtl8192c_tx_post_hdl(struct ieee80211_hw *hw, struct urb *urb, + struct sk_buff *skb) +{ + return 0; +} + +struct sk_buff *rtl8192c_tx_aggregate_hdl(struct ieee80211_hw *hw, + struct sk_buff_head *list) +{ + return skb_dequeue(list); +} + +/*======================================== trx ===============================*/ + +static void _rtl_fill_usb_tx_desc(u8 *txdesc) +{ + SET_TX_DESC_OWN(txdesc, 1); + SET_TX_DESC_LAST_SEG(txdesc, 1); + SET_TX_DESC_FIRST_SEG(txdesc, 1); +} +/** + * For HW recovery information + */ +static void _rtl_tx_desc_checksum(u8 *txdesc) +{ + u16 *ptr = (u16 *)txdesc; + u16 checksum = 0; + u32 index; + + /* Clear first */ + SET_TX_DESC_TX_DESC_CHECKSUM(txdesc, 0); + for (index = 0; index < 16; index++) + checksum = checksum ^ (*(ptr + index)); + SET_TX_DESC_TX_DESC_CHECKSUM(txdesc, cpu_to_le16(checksum)); +} + +void rtl92cu_tx_fill_desc(struct ieee80211_hw *hw, + struct ieee80211_hdr *hdr, u8 *pdesc_tx, + struct ieee80211_tx_info *info, struct sk_buff *skb, + u8 queue_index, + struct rtl_tcb_desc *tcb_desc) +{ + 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 defaultadapter = true; + struct ieee80211_sta *sta = info->control.sta = info->control.sta; + u8 *qc = ieee80211_get_qos_ctl(hdr); + u8 tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; + u16 seq_number; + __le16 fc = hdr->frame_control; + u8 rate_flag = info->control.rates[0].flags; + u16 pktlen = skb->len; + enum rtl_desc_qsel fw_qsel = _rtl8192cu_mq_to_descq(hw, fc, + skb_get_queue_mapping(skb)); + u8 *txdesc; + + seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4; + rtl_get_tcb_desc(hw, info, sta, skb, tcb_desc); + txdesc = (u8 *)skb_push(skb, RTL_TX_HEADER_SIZE); + memset(txdesc, 0, RTL_TX_HEADER_SIZE); + SET_TX_DESC_PKT_SIZE(txdesc, pktlen); + SET_TX_DESC_LINIP(txdesc, 0); + SET_TX_DESC_PKT_OFFSET(txdesc, RTL_DUMMY_OFFSET); + SET_TX_DESC_OFFSET(txdesc, RTL_TX_HEADER_SIZE); + SET_TX_DESC_TX_RATE(txdesc, tcb_desc->hw_rate); + if (tcb_desc->use_shortgi || tcb_desc->use_shortpreamble) + SET_TX_DESC_DATA_SHORTGI(txdesc, 1); + if (mac->tids[tid].agg.agg_state == RTL_AGG_ON && + info->flags & IEEE80211_TX_CTL_AMPDU) { + SET_TX_DESC_AGG_ENABLE(txdesc, 1); + SET_TX_DESC_MAX_AGG_NUM(txdesc, 0x14); + } else { + SET_TX_DESC_AGG_BREAK(txdesc, 1); + } + SET_TX_DESC_SEQ(txdesc, seq_number); + SET_TX_DESC_RTS_ENABLE(txdesc, ((tcb_desc->rts_enable && + !tcb_desc->cts_enable) ? 1 : 0)); + SET_TX_DESC_HW_RTS_ENABLE(txdesc, ((tcb_desc->rts_enable || + tcb_desc->cts_enable) ? 1 : 0)); + SET_TX_DESC_CTS2SELF(txdesc, ((tcb_desc->cts_enable) ? 1 : 0)); + SET_TX_DESC_RTS_STBC(txdesc, ((tcb_desc->rts_stbc) ? 1 : 0)); + SET_TX_DESC_RTS_RATE(txdesc, tcb_desc->rts_rate); + SET_TX_DESC_RTS_BW(txdesc, 0); + SET_TX_DESC_RTS_SC(txdesc, tcb_desc->rts_sc); + SET_TX_DESC_RTS_SHORT(txdesc, + ((tcb_desc->rts_rate <= DESC92_RATE54M) ? + (tcb_desc->rts_use_shortpreamble ? 1 : 0) + : (tcb_desc->rts_use_shortgi ? 1 : 0))); + if (mac->bw_40) { + if (rate_flag & IEEE80211_TX_RC_DUP_DATA) { + SET_TX_DESC_DATA_BW(txdesc, 1); + SET_TX_DESC_DATA_SC(txdesc, 3); + } else if(rate_flag & IEEE80211_TX_RC_40_MHZ_WIDTH){ + SET_TX_DESC_DATA_BW(txdesc, 1); + SET_TX_DESC_DATA_SC(txdesc, mac->cur_40_prime_sc); + } else { + SET_TX_DESC_DATA_BW(txdesc, 0); + SET_TX_DESC_DATA_SC(txdesc, 0); + } + } else { + SET_TX_DESC_DATA_BW(txdesc, 0); + SET_TX_DESC_DATA_SC(txdesc, 0); + } + rcu_read_lock(); + sta = ieee80211_find_sta(mac->vif, mac->bssid); + if (sta) { + u8 ampdu_density = sta->ht_cap.ampdu_density; + SET_TX_DESC_AMPDU_DENSITY(txdesc, ampdu_density); + } + rcu_read_unlock(); + if (info->control.hw_key) { + struct ieee80211_key_conf *keyconf = info->control.hw_key; + switch (keyconf->cipher) { + case WLAN_CIPHER_SUITE_WEP40: + case WLAN_CIPHER_SUITE_WEP104: + case WLAN_CIPHER_SUITE_TKIP: + SET_TX_DESC_SEC_TYPE(txdesc, 0x1); + break; + case WLAN_CIPHER_SUITE_CCMP: + SET_TX_DESC_SEC_TYPE(txdesc, 0x3); + break; + default: + SET_TX_DESC_SEC_TYPE(txdesc, 0x0); + break; + } + } + SET_TX_DESC_PKT_ID(txdesc, 0); + SET_TX_DESC_QUEUE_SEL(txdesc, fw_qsel); + SET_TX_DESC_DATA_RATE_FB_LIMIT(txdesc, 0x1F); + SET_TX_DESC_RTS_RATE_FB_LIMIT(txdesc, 0xF); + SET_TX_DESC_DISABLE_FB(txdesc, 0); + SET_TX_DESC_USE_RATE(txdesc, tcb_desc->use_driver_rate ? 1 : 0); + if (ieee80211_is_data_qos(fc)) { + if (mac->rdg_en) { + RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE, + "Enable RDG function\n"); + SET_TX_DESC_RDG_ENABLE(txdesc, 1); + SET_TX_DESC_HTC(txdesc, 1); + } + } + if (rtlpriv->dm.useramask) { + SET_TX_DESC_RATE_ID(txdesc, tcb_desc->ratr_index); + SET_TX_DESC_MACID(txdesc, tcb_desc->mac_id); + } else { + SET_TX_DESC_RATE_ID(txdesc, 0xC + tcb_desc->ratr_index); + SET_TX_DESC_MACID(txdesc, tcb_desc->ratr_index); + } + if ((!ieee80211_is_data_qos(fc)) && ppsc->leisure_ps && + ppsc->fwctrl_lps) { + SET_TX_DESC_HWSEQ_EN(txdesc, 1); + SET_TX_DESC_PKT_ID(txdesc, 8); + if (!defaultadapter) + SET_TX_DESC_QOS(txdesc, 1); + } + if (ieee80211_has_morefrags(fc)) + SET_TX_DESC_MORE_FRAG(txdesc, 1); + if (is_multicast_ether_addr(ieee80211_get_DA(hdr)) || + is_broadcast_ether_addr(ieee80211_get_DA(hdr))) + SET_TX_DESC_BMC(txdesc, 1); + _rtl_fill_usb_tx_desc(txdesc); + _rtl_tx_desc_checksum(txdesc); + RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE, "==>\n"); +} + +void rtl92cu_fill_fake_txdesc(struct ieee80211_hw *hw, u8 * pDesc, + u32 buffer_len, bool bIsPsPoll) +{ + /* Clear all status */ + memset(pDesc, 0, RTL_TX_HEADER_SIZE); + SET_TX_DESC_FIRST_SEG(pDesc, 1); /* bFirstSeg; */ + SET_TX_DESC_LAST_SEG(pDesc, 1); /* bLastSeg; */ + SET_TX_DESC_OFFSET(pDesc, RTL_TX_HEADER_SIZE); /* Offset = 32 */ + SET_TX_DESC_PKT_SIZE(pDesc, buffer_len); /* Buffer size + command hdr */ + SET_TX_DESC_QUEUE_SEL(pDesc, QSLT_MGNT); /* Fixed queue of Mgnt queue */ + /* Set NAVUSEHDR to prevent Ps-poll AId filed to be changed to error + * vlaue by Hw. */ + if (bIsPsPoll) { + SET_TX_DESC_NAV_USE_HDR(pDesc, 1); + } else { + SET_TX_DESC_HWSEQ_EN(pDesc, 1); /* Hw set sequence number */ + SET_TX_DESC_PKT_ID(pDesc, 0x100); /* set bit3 to 1. */ + } + SET_TX_DESC_USE_RATE(pDesc, 1); /* use data rate which is set by Sw */ + SET_TX_DESC_OWN(pDesc, 1); + SET_TX_DESC_TX_RATE(pDesc, DESC92_RATE1M); + _rtl_tx_desc_checksum(pDesc); +} + +void rtl92cu_tx_fill_cmddesc(struct ieee80211_hw *hw, + u8 *pdesc, bool firstseg, + bool lastseg, struct sk_buff *skb) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 fw_queue = QSLT_BEACON; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data); + __le16 fc = hdr->frame_control; + + memset((void *)pdesc, 0, RTL_TX_HEADER_SIZE); + if (firstseg) + SET_TX_DESC_OFFSET(pdesc, RTL_TX_HEADER_SIZE); + SET_TX_DESC_TX_RATE(pdesc, DESC92_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_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, 0x20); + SET_TX_DESC_USE_RATE(pdesc, 1); + if (!ieee80211_is_data_qos(fc)) { + SET_TX_DESC_HWSEQ_EN(pdesc, 1); + SET_TX_DESC_PKT_ID(pdesc, 8); + } + RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD, "H2C Tx Cmd Content", + pdesc, RTL_TX_DESC_SIZE); +} + +bool rtl92cu_cmd_send_packet(struct ieee80211_hw *hw, struct sk_buff *skb) +{ + return true; +} diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.h b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.h new file mode 100644 index 00000000..332b06e7 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.h @@ -0,0 +1,433 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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. + * + * 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 __RTL92CU_TRX_H__ +#define __RTL92CU_TRX_H__ + +#define RTL92C_USB_BULK_IN_NUM 1 +#define RTL92C_NUM_RX_URBS 8 +#define RTL92C_NUM_TX_URBS 32 + +#define RTL92C_SIZE_MAX_RX_BUFFER 15360 /* 8192 */ +#define RX_DRV_INFO_SIZE_UNIT 8 + +#define RTL_AGG_ON 1 + +enum usb_rx_agg_mode { + USB_RX_AGG_DISABLE, + USB_RX_AGG_DMA, + USB_RX_AGG_USB, + USB_RX_AGG_DMA_USB +}; + +#define TX_SELE_HQ BIT(0) /* High Queue */ +#define TX_SELE_LQ BIT(1) /* Low Queue */ +#define TX_SELE_NQ BIT(2) /* Normal Queue */ + +#define RTL_USB_TX_AGG_NUM_DESC 5 + +#define RTL_USB_RX_AGG_PAGE_NUM 4 +#define RTL_USB_RX_AGG_PAGE_TIMEOUT 3 + +#define RTL_USB_RX_AGG_BLOCK_NUM 5 +#define RTL_USB_RX_AGG_BLOCK_TIMEOUT 3 + +/*======================== rx status =========================================*/ + +struct rx_drv_info_92c { + /* + * Driver info contain PHY status and other variabel size info + * PHY Status content as below + */ + + /* DWORD 0 */ + u8 gain_trsw[4]; + + /* DWORD 1 */ + u8 pwdb_all; + u8 cfosho[4]; + + /* DWORD 2 */ + u8 cfotail[4]; + + /* DWORD 3 */ + s8 rxevm[2]; + s8 rxsnr[4]; + + /* DWORD 4 */ + u8 pdsnr[2]; + + /* DWORD 5 */ + u8 csi_current[2]; + u8 csi_target[2]; + + /* DWORD 6 */ + u8 sigevm; + u8 max_ex_pwr; + u8 ex_intf_flag:1; + u8 sgi_en:1; + u8 rxsc:2; + u8 reserve:4; +} __packed; + +/* Define a macro that takes a le32 word, converts it to host ordering, + * right shifts by a specified count, creates a mask of the specified + * bit count, and extracts that number of bits. + */ + +#define SHIFT_AND_MASK_LE(__pdesc, __shift, __bits) \ + ((le32_to_cpu(*(((__le32 *)(__pdesc)))) >> (__shift)) & \ + BIT_LEN_MASK_32(__bits)) + +/* Define a macro that clears a bit field in an le32 word and + * sets the specified value into that bit field. The resulting + * value remains in le32 ordering; however, it is properly converted + * to host ordering for the clear and set operations before conversion + * back to le32. + */ + +#define SET_BITS_OFFSET_LE(__pdesc, __shift, __len, __val) \ + (*(__le32 *)(__pdesc) = \ + (cpu_to_le32((le32_to_cpu(*((__le32 *)(__pdesc))) & \ + (~(BIT_OFFSET_LEN_MASK_32((__shift), __len)))) | \ + (((u32)(__val) & BIT_LEN_MASK_32(__len)) << (__shift))))); + +/* macros to read various fields in RX descriptor */ + +/* DWORD 0 */ +#define GET_RX_DESC_PKT_LEN(__rxdesc) \ + SHIFT_AND_MASK_LE((__rxdesc), 0, 14) +#define GET_RX_DESC_CRC32(__rxdesc) \ + SHIFT_AND_MASK_LE(__rxdesc, 14, 1) +#define GET_RX_DESC_ICV(__rxdesc) \ + SHIFT_AND_MASK_LE(__rxdesc, 15, 1) +#define GET_RX_DESC_DRVINFO_SIZE(__rxdesc) \ + SHIFT_AND_MASK_LE(__rxdesc, 16, 4) +#define GET_RX_DESC_SECURITY(__rxdesc) \ + SHIFT_AND_MASK_LE(__rxdesc, 20, 3) +#define GET_RX_DESC_QOS(__rxdesc) \ + SHIFT_AND_MASK_LE(__rxdesc, 23, 1) +#define GET_RX_DESC_SHIFT(__rxdesc) \ + SHIFT_AND_MASK_LE(__rxdesc, 24, 2) +#define GET_RX_DESC_PHY_STATUS(__rxdesc) \ + SHIFT_AND_MASK_LE(__rxdesc, 26, 1) +#define GET_RX_DESC_SWDEC(__rxdesc) \ + SHIFT_AND_MASK_LE(__rxdesc, 27, 1) +#define GET_RX_DESC_LAST_SEG(__rxdesc) \ + SHIFT_AND_MASK_LE(__rxdesc, 28, 1) +#define GET_RX_DESC_FIRST_SEG(__rxdesc) \ + SHIFT_AND_MASK_LE(__rxdesc, 29, 1) +#define GET_RX_DESC_EOR(__rxdesc) \ + SHIFT_AND_MASK_LE(__rxdesc, 30, 1) +#define GET_RX_DESC_OWN(__rxdesc) \ + SHIFT_AND_MASK_LE(__rxdesc, 31, 1) + +/* DWORD 1 */ +#define GET_RX_DESC_MACID(__rxdesc) \ + SHIFT_AND_MASK_LE(__rxdesc+4, 0, 5) +#define GET_RX_DESC_TID(__rxdesc) \ + SHIFT_AND_MASK_LE(__rxdesc+4, 5, 4) +#define GET_RX_DESC_PAGGR(__rxdesc) \ + SHIFT_AND_MASK_LE(__rxdesc+4, 14, 1) +#define GET_RX_DESC_FAGGR(__rxdesc) \ + SHIFT_AND_MASK_LE(__rxdesc+4, 15, 1) +#define GET_RX_DESC_A1_FIT(__rxdesc) \ + SHIFT_AND_MASK_LE(__rxdesc+4, 16, 4) +#define GET_RX_DESC_A2_FIT(__rxdesc) \ + SHIFT_AND_MASK_LE(__rxdesc+4, 20, 4) +#define GET_RX_DESC_PAM(__rxdesc) \ + SHIFT_AND_MASK_LE(__rxdesc+4, 24, 1) +#define GET_RX_DESC_PWR(__rxdesc) \ + SHIFT_AND_MASK_LE(__rxdesc+4, 25, 1) +#define GET_RX_DESC_MORE_DATA(__rxdesc) \ + SHIFT_AND_MASK_LE(__rxdesc+4, 26, 1) +#define GET_RX_DESC_MORE_FRAG(__rxdesc) \ + SHIFT_AND_MASK_LE(__rxdesc+4, 27, 1) +#define GET_RX_DESC_TYPE(__rxdesc) \ + SHIFT_AND_MASK_LE(__rxdesc+4, 28, 2) +#define GET_RX_DESC_MC(__rxdesc) \ + SHIFT_AND_MASK_LE(__rxdesc+4, 30, 1) +#define GET_RX_DESC_BC(__rxdesc) \ + SHIFT_AND_MASK_LE(__rxdesc+4, 31, 1) + +/* DWORD 2 */ +#define GET_RX_DESC_SEQ(__rxdesc) \ + SHIFT_AND_MASK_LE(__rxdesc+8, 0, 12) +#define GET_RX_DESC_FRAG(__rxdesc) \ + SHIFT_AND_MASK_LE(__rxdesc+8, 12, 4) +#define GET_RX_DESC_USB_AGG_PKTNUM(__rxdesc) \ + SHIFT_AND_MASK_LE(__rxdesc+8, 16, 8) +#define GET_RX_DESC_NEXT_IND(__rxdesc) \ + SHIFT_AND_MASK_LE(__rxdesc+8, 30, 1) + +/* DWORD 3 */ +#define GET_RX_DESC_RX_MCS(__rxdesc) \ + SHIFT_AND_MASK_LE(__rxdesc+12, 0, 6) +#define GET_RX_DESC_RX_HT(__rxdesc) \ + SHIFT_AND_MASK_LE(__rxdesc+12, 6, 1) +#define GET_RX_DESC_AMSDU(__rxdesc) \ + SHIFT_AND_MASK_LE(__rxdesc+12, 7, 1) +#define GET_RX_DESC_SPLCP(__rxdesc) \ + SHIFT_AND_MASK_LE(__rxdesc+12, 8, 1) +#define GET_RX_DESC_BW(__rxdesc) \ + SHIFT_AND_MASK_LE(__rxdesc+12, 9, 1) +#define GET_RX_DESC_HTC(__rxdesc) \ + SHIFT_AND_MASK_LE(__rxdesc+12, 10, 1) +#define GET_RX_DESC_TCP_CHK_RPT(__rxdesc) \ + SHIFT_AND_MASK_LE(__rxdesc+12, 11, 1) +#define GET_RX_DESC_IP_CHK_RPT(__rxdesc) \ + SHIFT_AND_MASK_LE(__rxdesc+12, 12, 1) +#define GET_RX_DESC_TCP_CHK_VALID(__rxdesc) \ + SHIFT_AND_MASK_LE(__rxdesc+12, 13, 1) +#define GET_RX_DESC_HWPC_ERR(__rxdesc) \ + SHIFT_AND_MASK_LE(__rxdesc+12, 14, 1) +#define GET_RX_DESC_HWPC_IND(__rxdesc) \ + SHIFT_AND_MASK_LE(__rxdesc+12, 15, 1) +#define GET_RX_DESC_IV0(__rxdesc) \ + SHIFT_AND_MASK_LE(__rxdesc+12, 16, 16) + +/* DWORD 4 */ +#define GET_RX_DESC_IV1(__rxdesc) \ + SHIFT_AND_MASK_LE(__rxdesc+16, 0, 32) + +/* DWORD 5 */ +#define GET_RX_DESC_TSFL(__rxdesc) \ + SHIFT_AND_MASK_LE(__rxdesc+20, 0, 32) + +/*======================= tx desc ============================================*/ + +/* macros to set various fields in TX descriptor */ + +/* Dword 0 */ +#define SET_TX_DESC_PKT_SIZE(__txdesc, __value) \ + SET_BITS_OFFSET_LE(__txdesc, 0, 16, __value) +#define SET_TX_DESC_OFFSET(__txdesc, __value) \ + SET_BITS_OFFSET_LE(__txdesc, 16, 8, __value) +#define SET_TX_DESC_BMC(__txdesc, __value) \ + SET_BITS_OFFSET_LE(__txdesc, 24, 1, __value) +#define SET_TX_DESC_HTC(__txdesc, __value) \ + SET_BITS_OFFSET_LE(__txdesc, 25, 1, __value) +#define SET_TX_DESC_LAST_SEG(__txdesc, __value) \ + SET_BITS_OFFSET_LE(__txdesc, 26, 1, __value) +#define SET_TX_DESC_FIRST_SEG(__txdesc, __value) \ + SET_BITS_OFFSET_LE(__txdesc, 27, 1, __value) +#define SET_TX_DESC_LINIP(__txdesc, __value) \ + SET_BITS_OFFSET_LE(__txdesc, 28, 1, __value) +#define SET_TX_DESC_NO_ACM(__txdesc, __value) \ + SET_BITS_OFFSET_LE(__txdesc, 29, 1, __value) +#define SET_TX_DESC_GF(__txdesc, __value) \ + SET_BITS_OFFSET_LE(__txdesc, 30, 1, __value) +#define SET_TX_DESC_OWN(__txdesc, __value) \ + SET_BITS_OFFSET_LE(__txdesc, 31, 1, __value) + + +/* Dword 1 */ +#define SET_TX_DESC_MACID(__txdesc, __value) \ + SET_BITS_OFFSET_LE(__txdesc+4, 0, 5, __value) +#define SET_TX_DESC_AGG_ENABLE(__txdesc, __value) \ + SET_BITS_OFFSET_LE(__txdesc+4, 5, 1, __value) +#define SET_TX_DESC_AGG_BREAK(__txdesc, __value) \ + SET_BITS_OFFSET_LE(__txdesc+4, 6, 1, __value) +#define SET_TX_DESC_RDG_ENABLE(__txdesc, __value) \ + SET_BITS_OFFSET_LE(__txdesc+4, 7, 1, __value) +#define SET_TX_DESC_QUEUE_SEL(__txdesc, __value) \ + SET_BITS_OFFSET_LE(__txdesc+4, 8, 5, __value) +#define SET_TX_DESC_RDG_NAV_EXT(__txdesc, __value) \ + SET_BITS_OFFSET_LE(__txdesc+4, 13, 1, __value) +#define SET_TX_DESC_LSIG_TXOP_EN(__txdesc, __value) \ + SET_BITS_OFFSET_LE(__txdesc+4, 14, 1, __value) +#define SET_TX_DESC_PIFS(__txdesc, __value) \ + SET_BITS_OFFSET_LE(__txdesc+4, 15, 1, __value) +#define SET_TX_DESC_RATE_ID(__txdesc, __value) \ + SET_BITS_OFFSET_LE(__txdesc+4, 16, 4, __value) +#define SET_TX_DESC_RA_BRSR_ID(__txdesc, __value) \ + SET_BITS_OFFSET_LE(__txdesc+4, 16, 4, __value) +#define SET_TX_DESC_NAV_USE_HDR(__txdesc, __value) \ + SET_BITS_OFFSET_LE(__txdesc+4, 20, 1, __value) +#define SET_TX_DESC_EN_DESC_ID(__txdesc, __value) \ + SET_BITS_OFFSET_LE(__txdesc+4, 21, 1, __value) +#define SET_TX_DESC_SEC_TYPE(__txdesc, __value) \ + SET_BITS_OFFSET_LE(__txdesc+4, 22, 2, __value) +#define SET_TX_DESC_PKT_OFFSET(__txdesc, __value) \ + SET_BITS_OFFSET_LE(__txdesc+4, 26, 5, __value) + +/* Dword 2 */ +#define SET_TX_DESC_RTS_RC(__txdesc, __value) \ + SET_BITS_OFFSET_LE(__txdesc+8, 0, 6, __value) +#define SET_TX_DESC_DATA_RC(__txdesc, __value) \ + SET_BITS_OFFSET_LE(__txdesc+8, 6, 6, __value) +#define SET_TX_DESC_BAR_RTY_TH(__txdesc, __value) \ + SET_BITS_OFFSET_LE(__txdesc+8, 14, 2, __value) +#define SET_TX_DESC_MORE_FRAG(__txdesc, __value) \ + SET_BITS_OFFSET_LE(__txdesc+8, 17, 1, __value) +#define SET_TX_DESC_RAW(__txdesc, __value) \ + SET_BITS_OFFSET_LE(__txdesc+8, 18, 1, __value) +#define SET_TX_DESC_CCX(__txdesc, __value) \ + SET_BITS_OFFSET_LE(__txdesc+8, 19, 1, __value) +#define SET_TX_DESC_AMPDU_DENSITY(__txdesc, __value) \ + SET_BITS_OFFSET_LE(__txdesc+8, 20, 3, __value) +#define SET_TX_DESC_ANTSEL_A(__txdesc, __value) \ + SET_BITS_OFFSET_LE(__txdesc+8, 24, 1, __value) +#define SET_TX_DESC_ANTSEL_B(__txdesc, __value) \ + SET_BITS_OFFSET_LE(__txdesc+8, 25, 1, __value) +#define SET_TX_DESC_TX_ANT_CCK(__txdesc, __value) \ + SET_BITS_OFFSET_LE(__txdesc+8, 26, 2, __value) +#define SET_TX_DESC_TX_ANTL(__txdesc, __value) \ + SET_BITS_OFFSET_LE(__txdesc+8, 28, 2, __value) +#define SET_TX_DESC_TX_ANT_HT(__txdesc, __value) \ + SET_BITS_OFFSET_LE(__txdesc+8, 30, 2, __value) + +/* Dword 3 */ +#define SET_TX_DESC_NEXT_HEAP_PAGE(__txdesc, __value) \ + SET_BITS_OFFSET_LE(__txdesc+12, 0, 8, __value) +#define SET_TX_DESC_TAIL_PAGE(__txdesc, __value) \ + SET_BITS_OFFSET_LE(__txdesc+12, 8, 8, __value) +#define SET_TX_DESC_SEQ(__txdesc, __value) \ + SET_BITS_OFFSET_LE(__txdesc+12, 16, 12, __value) +#define SET_TX_DESC_PKT_ID(__txdesc, __value) \ + SET_BITS_OFFSET_LE(__txdesc+12, 28, 4, __value) + +/* Dword 4 */ +#define SET_TX_DESC_RTS_RATE(__txdesc, __value) \ + SET_BITS_OFFSET_LE(__txdesc+16, 0, 5, __value) +#define SET_TX_DESC_AP_DCFE(__txdesc, __value) \ + SET_BITS_OFFSET_LE(__txdesc+16, 5, 1, __value) +#define SET_TX_DESC_QOS(__txdesc, __value) \ + SET_BITS_OFFSET_LE(__txdesc+16, 6, 1, __value) +#define SET_TX_DESC_HWSEQ_EN(__txdesc, __value) \ + SET_BITS_OFFSET_LE(__txdesc+16, 7, 1, __value) +#define SET_TX_DESC_USE_RATE(__txdesc, __value) \ + SET_BITS_OFFSET_LE(__txdesc+16, 8, 1, __value) +#define SET_TX_DESC_DISABLE_RTS_FB(__txdesc, __value) \ + SET_BITS_OFFSET_LE(__txdesc+16, 9, 1, __value) +#define SET_TX_DESC_DISABLE_FB(__txdesc, __value) \ + SET_BITS_OFFSET_LE(__txdesc+16, 10, 1, __value) +#define SET_TX_DESC_CTS2SELF(__txdesc, __value) \ + SET_BITS_OFFSET_LE(__txdesc+16, 11, 1, __value) +#define SET_TX_DESC_RTS_ENABLE(__txdesc, __value) \ + SET_BITS_OFFSET_LE(__txdesc+16, 12, 1, __value) +#define SET_TX_DESC_HW_RTS_ENABLE(__txdesc, __value) \ + SET_BITS_OFFSET_LE(__txdesc+16, 13, 1, __value) +#define SET_TX_DESC_WAIT_DCTS(__txdesc, __value) \ + SET_BITS_OFFSET_LE(__txdesc+16, 18, 1, __value) +#define SET_TX_DESC_CTS2AP_EN(__txdesc, __value) \ + SET_BITS_OFFSET_LE(__txdesc+16, 19, 1, __value) +#define SET_TX_DESC_DATA_SC(__txdesc, __value) \ + SET_BITS_OFFSET_LE(__txdesc+16, 20, 2, __value) +#define SET_TX_DESC_DATA_STBC(__txdesc, __value) \ + SET_BITS_OFFSET_LE(__txdesc+16, 22, 2, __value) +#define SET_TX_DESC_DATA_SHORT(__txdesc, __value) \ + SET_BITS_OFFSET_LE(__txdesc+16, 24, 1, __value) +#define SET_TX_DESC_DATA_BW(__txdesc, __value) \ + SET_BITS_OFFSET_LE(__txdesc+16, 25, 1, __value) +#define SET_TX_DESC_RTS_SHORT(__txdesc, __value) \ + SET_BITS_OFFSET_LE(__txdesc+16, 26, 1, __value) +#define SET_TX_DESC_RTS_BW(__txdesc, __value) \ + SET_BITS_OFFSET_LE(__txdesc+16, 27, 1, __value) +#define SET_TX_DESC_RTS_SC(__txdesc, __value) \ + SET_BITS_OFFSET_LE(__txdesc+16, 28, 2, __value) +#define SET_TX_DESC_RTS_STBC(__txdesc, __value) \ + SET_BITS_OFFSET_LE(__txdesc+16, 30, 2, __value) + +/* Dword 5 */ +#define SET_TX_DESC_TX_RATE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+20, 0, 6, __val) +#define SET_TX_DESC_DATA_SHORTGI(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+20, 6, 1, __val) +#define SET_TX_DESC_CCX_TAG(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+20, 7, 1, __val) +#define SET_TX_DESC_DATA_RATE_FB_LIMIT(__txdesc, __value) \ + SET_BITS_OFFSET_LE(__txdesc+20, 8, 5, __value) +#define SET_TX_DESC_RTS_RATE_FB_LIMIT(__txdesc, __value) \ + SET_BITS_OFFSET_LE(__txdesc+20, 13, 4, __value) +#define SET_TX_DESC_RETRY_LIMIT_ENABLE(__txdesc, __value) \ + SET_BITS_OFFSET_LE(__txdesc+20, 17, 1, __value) +#define SET_TX_DESC_DATA_RETRY_LIMIT(__txdesc, __value) \ + SET_BITS_OFFSET_LE(__txdesc+20, 18, 6, __value) +#define SET_TX_DESC_USB_TXAGG_NUM(__txdesc, __value) \ + SET_BITS_OFFSET_LE(__txdesc+20, 24, 8, __value) + +/* Dword 6 */ +#define SET_TX_DESC_TXAGC_A(__txdesc, __value) \ + SET_BITS_OFFSET_LE(__txdesc+24, 0, 5, __value) +#define SET_TX_DESC_TXAGC_B(__txdesc, __value) \ + SET_BITS_OFFSET_LE(__txdesc+24, 5, 5, __value) +#define SET_TX_DESC_USB_MAX_LEN(__txdesc, __value) \ + SET_BITS_OFFSET_LE(__txdesc+24, 10, 1, __value) +#define SET_TX_DESC_MAX_AGG_NUM(__txdesc, __value) \ + SET_BITS_OFFSET_LE(__txdesc+24, 11, 5, __value) +#define SET_TX_DESC_MCSG1_MAX_LEN(__txdesc, __value) \ + SET_BITS_OFFSET_LE(__txdesc+24, 16, 4, __value) +#define SET_TX_DESC_MCSG2_MAX_LEN(__txdesc, __value) \ + SET_BITS_OFFSET_LE(__txdesc+24, 20, 4, __value) +#define SET_TX_DESC_MCSG3_MAX_LEN(__txdesc, __value) \ + SET_BITS_OFFSET_LE(__txdesc+24, 24, 4, __value) +#define SET_TX_DESC_MCSG7_MAX_LEN(__txdesc, __value) \ + SET_BITS_OFFSET_LE(__txdesc+24, 28, 4, __value) + +/* Dword 7 */ +#define SET_TX_DESC_TX_DESC_CHECKSUM(__txdesc, __value) \ + SET_BITS_OFFSET_LE(__txdesc+28, 0, 16, __value) +#define SET_TX_DESC_MCSG4_MAX_LEN(__txdesc, __value) \ + SET_BITS_OFFSET_LE(__txdesc+28, 16, 4, __value) +#define SET_TX_DESC_MCSG5_MAX_LEN(__txdesc, __value) \ + SET_BITS_OFFSET_LE(__txdesc+28, 20, 4, __value) +#define SET_TX_DESC_MCSG6_MAX_LEN(__txdesc, __value) \ + SET_BITS_OFFSET_LE(__txdesc+28, 24, 4, __value) +#define SET_TX_DESC_MCSG15_MAX_LEN(__txdesc, __value) \ + SET_BITS_OFFSET_LE(__txdesc+28, 28, 4, __value) + + +int rtl8192cu_endpoint_mapping(struct ieee80211_hw *hw); +u16 rtl8192cu_mq_to_hwq(__le16 fc, u16 mac80211_queue_index); +bool rtl92cu_rx_query_desc(struct ieee80211_hw *hw, + struct rtl_stats *stats, + struct ieee80211_rx_status *rx_status, + u8 *p_desc, struct sk_buff *skb); +void rtl8192cu_rx_hdl(struct ieee80211_hw *hw, struct sk_buff * skb); +void rtl8192c_rx_segregate_hdl(struct ieee80211_hw *, struct sk_buff *, + struct sk_buff_head *); +void rtl8192c_tx_cleanup(struct ieee80211_hw *hw, struct sk_buff *skb); +int rtl8192c_tx_post_hdl(struct ieee80211_hw *hw, struct urb *urb, + struct sk_buff *skb); +struct sk_buff *rtl8192c_tx_aggregate_hdl(struct ieee80211_hw *, + struct sk_buff_head *); +void rtl92cu_tx_fill_desc(struct ieee80211_hw *hw, + struct ieee80211_hdr *hdr, u8 *pdesc_tx, + struct ieee80211_tx_info *info, struct sk_buff *skb, + u8 queue_index, + struct rtl_tcb_desc *tcb_desc); +void rtl92cu_fill_fake_txdesc(struct ieee80211_hw *hw, u8 * pDesc, + u32 buffer_len, bool bIsPsPoll); +void rtl92cu_tx_fill_cmddesc(struct ieee80211_hw *hw, + u8 *pdesc, bool b_firstseg, + bool b_lastseg, struct sk_buff *skb); +bool rtl92cu_cmd_send_packet(struct ieee80211_hw *hw, struct sk_buff *skb); + +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/Makefile b/drivers/net/wireless/rtlwifi/rtl8192de/Makefile new file mode 100644 index 00000000..e3213c82 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192de/Makefile @@ -0,0 +1,14 @@ +rtl8192de-objs := \ + dm.o \ + fw.o \ + hw.o \ + led.o \ + phy.o \ + rf.o \ + sw.o \ + table.o \ + trx.o + +obj-$(CONFIG_RTL8192DE) += rtl8192de.o + +ccflags-y += -D__CHECK_ENDIAN__ diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/def.h b/drivers/net/wireless/rtlwifi/rtl8192de/def.h new file mode 100644 index 00000000..eafdf76e --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192de/def.h @@ -0,0 +1,273 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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 __RTL92D_DEF_H__ +#define __RTL92D_DEF_H__ + +/* Min Spacing related settings. */ +#define MAX_MSS_DENSITY_2T 0x13 +#define MAX_MSS_DENSITY_1T 0x0A + +#define RF6052_MAX_TX_PWR 0x3F +#define RF6052_MAX_REG 0x3F +#define RF6052_MAX_PATH 2 + +#define HAL_RETRY_LIMIT_INFRA 48 +#define HAL_RETRY_LIMIT_AP_ADHOC 7 + +#define PHY_RSSI_SLID_WIN_MAX 100 +#define PHY_LINKQUALITY_SLID_WIN_MAX 20 +#define PHY_BEACON_RSSI_SLID_WIN_MAX 10 + +#define RESET_DELAY_8185 20 + +#define RT_IBSS_INT_MASKS (IMR_BCNINT | IMR_TBDOK | IMR_TBDER) +#define RT_AC_INT_MASKS (IMR_VIDOK | IMR_VODOK | IMR_BEDOK|IMR_BKDOK) + +#define NUM_OF_FIRMWARE_QUEUE 10 +#define NUM_OF_PAGES_IN_FW 0x100 +#define NUM_OF_PAGE_IN_FW_QUEUE_BK 0x07 +#define NUM_OF_PAGE_IN_FW_QUEUE_BE 0x07 +#define NUM_OF_PAGE_IN_FW_QUEUE_VI 0x07 +#define NUM_OF_PAGE_IN_FW_QUEUE_VO 0x07 +#define NUM_OF_PAGE_IN_FW_QUEUE_HCCA 0x0 +#define NUM_OF_PAGE_IN_FW_QUEUE_CMD 0x0 +#define NUM_OF_PAGE_IN_FW_QUEUE_MGNT 0x02 +#define NUM_OF_PAGE_IN_FW_QUEUE_HIGH 0x02 +#define NUM_OF_PAGE_IN_FW_QUEUE_BCN 0x2 +#define NUM_OF_PAGE_IN_FW_QUEUE_PUB 0xA1 + +#define NUM_OF_PAGE_IN_FW_QUEUE_BK_DTM 0x026 +#define NUM_OF_PAGE_IN_FW_QUEUE_BE_DTM 0x048 +#define NUM_OF_PAGE_IN_FW_QUEUE_VI_DTM 0x048 +#define NUM_OF_PAGE_IN_FW_QUEUE_VO_DTM 0x026 +#define NUM_OF_PAGE_IN_FW_QUEUE_PUB_DTM 0x00 + +#define MAX_LINES_HWCONFIG_TXT 1000 +#define MAX_BYTES_LINE_HWCONFIG_TXT 256 + +#define SW_THREE_WIRE 0 +#define HW_THREE_WIRE 2 + +#define BT_DEMO_BOARD 0 +#define BT_QA_BOARD 1 +#define BT_FPGA 2 + +#define RX_SMOOTH_FACTOR 20 + +#define HAL_PRIME_CHNL_OFFSET_DONT_CARE 0 +#define HAL_PRIME_CHNL_OFFSET_LOWER 1 +#define HAL_PRIME_CHNL_OFFSET_UPPER 2 + +#define MAX_H2C_QUEUE_NUM 10 + +#define RX_MPDU_QUEUE 0 +#define RX_CMD_QUEUE 1 +#define RX_MAX_QUEUE 2 + +#define C2H_RX_CMD_HDR_LEN 8 +#define GET_C2H_CMD_CMD_LEN(__prxhdr) \ + LE_BITS_TO_4BYTE((__prxhdr), 0, 16) +#define GET_C2H_CMD_ELEMENT_ID(__prxhdr) \ + LE_BITS_TO_4BYTE((__prxhdr), 16, 8) +#define GET_C2H_CMD_CMD_SEQ(__prxhdr) \ + LE_BITS_TO_4BYTE((__prxhdr), 24, 7) +#define GET_C2H_CMD_CONTINUE(__prxhdr) \ + LE_BITS_TO_4BYTE((__prxhdr), 31, 1) +#define GET_C2H_CMD_CONTENT(__prxhdr) \ + ((u8 *)(__prxhdr) + C2H_RX_CMD_HDR_LEN) + +#define GET_C2H_CMD_FEEDBACK_ELEMENT_ID(__pcmdfbhdr) \ + LE_BITS_TO_4BYTE((__pcmdfbhdr), 0, 8) +#define GET_C2H_CMD_FEEDBACK_CCX_LEN(__pcmdfbhdr) \ + LE_BITS_TO_4BYTE((__pcmdfbhdr), 8, 8) +#define GET_C2H_CMD_FEEDBACK_CCX_CMD_CNT(__pcmdfbhdr) \ + LE_BITS_TO_4BYTE((__pcmdfbhdr), 16, 16) +#define GET_C2H_CMD_FEEDBACK_CCX_MAC_ID(__pcmdfbhdr) \ + LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 0, 5) +#define GET_C2H_CMD_FEEDBACK_CCX_VALID(__pcmdfbhdr) \ + LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 7, 1) +#define GET_C2H_CMD_FEEDBACK_CCX_RETRY_CNT(__pcmdfbhdr) \ + LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 8, 5) +#define GET_C2H_CMD_FEEDBACK_CCX_TOK(__pcmdfbhdr) \ + LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 15, 1) +#define GET_C2H_CMD_FEEDBACK_CCX_QSEL(__pcmdfbhdr) \ + LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 16, 4) +#define GET_C2H_CMD_FEEDBACK_CCX_SEQ(__pcmdfbhdr) \ + LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 20, 12) + +enum version_8192d { + VERSION_TEST_CHIP_88C = 0x0000, + VERSION_TEST_CHIP_92C = 0x0020, + VERSION_TEST_UMC_CHIP_8723 = 0x0081, + VERSION_NORMAL_TSMC_CHIP_88C = 0x0008, + VERSION_NORMAL_TSMC_CHIP_92C = 0x0028, + VERSION_NORMAL_TSMC_CHIP_92C_1T2R = 0x0018, + VERSION_NORMAL_UMC_CHIP_88C_A_CUT = 0x0088, + VERSION_NORMAL_UMC_CHIP_92C_A_CUT = 0x00a8, + VERSION_NORMAL_UMC_CHIP_92C_1T2R_A_CUT = 0x0098, + VERSION_NORMAL_UMC_CHIP_8723_1T1R_A_CUT = 0x0089, + VERSION_NORMAL_UMC_CHIP_8723_1T1R_B_CUT = 0x1089, + VERSION_NORMAL_UMC_CHIP_88C_B_CUT = 0x1088, + VERSION_NORMAL_UMC_CHIP_92C_B_CUT = 0x10a8, + VERSION_NORMAL_UMC_CHIP_92C_1T2R_B_CUT = 0x1090, + VERSION_TEST_CHIP_92D_SINGLEPHY = 0x0022, + VERSION_TEST_CHIP_92D_DUALPHY = 0x0002, + VERSION_NORMAL_CHIP_92D_SINGLEPHY = 0x002a, + VERSION_NORMAL_CHIP_92D_DUALPHY = 0x000a, + VERSION_NORMAL_CHIP_92D_C_CUT_SINGLEPHY = 0x202a, + VERSION_NORMAL_CHIP_92D_C_CUT_DUALPHY = 0x200a, + VERSION_NORMAL_CHIP_92D_D_CUT_SINGLEPHY = 0x302a, + VERSION_NORMAL_CHIP_92D_D_CUT_DUALPHY = 0x300a, + VERSION_NORMAL_CHIP_92D_E_CUT_SINGLEPHY = 0x402a, + VERSION_NORMAL_CHIP_92D_E_CUT_DUALPHY = 0x400a, +}; + +/* for 92D */ +#define CHIP_92D_SINGLEPHY BIT(9) +#define C_CUT_VERSION BIT(13) +#define D_CUT_VERSION ((BIT(12)|BIT(13))) +#define E_CUT_VERSION BIT(14) + +/* Chip specific */ +#define CHIP_BONDING_IDENTIFIER(_value) (((_value)>>22)&0x3) +#define CHIP_BONDING_92C_1T2R 0x1 +#define CHIP_BONDING_88C_USB_MCARD 0x2 +#define CHIP_BONDING_88C_USB_HP 0x1 + +/* [15:12] IC version(CUT): A-cut=0, B-cut=1, C-cut=2, D-cut=3 */ +/* [7] Manufacturer: TSMC=0, UMC=1 */ +/* [6:4] RF type: 1T1R=0, 1T2R=1, 2T2R=2 */ +/* [3] Chip type: TEST=0, NORMAL=1 */ +/* [2:0] IC type: 81xxC=0, 8723=1, 92D=2 */ +#define CHIP_8723 BIT(0) +#define CHIP_92D BIT(1) +#define NORMAL_CHIP BIT(3) +#define RF_TYPE_1T1R (~(BIT(4)|BIT(5)|BIT(6))) +#define RF_TYPE_1T2R BIT(4) +#define RF_TYPE_2T2R BIT(5) +#define CHIP_VENDOR_UMC BIT(7) +#define B_CUT_VERSION BIT(12) + +/* MASK */ +#define IC_TYPE_MASK (BIT(0)|BIT(1)|BIT(2)) +#define CHIP_TYPE_MASK BIT(3) +#define RF_TYPE_MASK (BIT(4)|BIT(5)|BIT(6)) +#define MANUFACTUER_MASK BIT(7) +#define ROM_VERSION_MASK (BIT(11)|BIT(10)|BIT(9)|BIT(8)) +#define CUT_VERSION_MASK (BIT(15)|BIT(14)|BIT(13)|BIT(12)) + + +/* Get element */ +#define GET_CVID_IC_TYPE(version) ((version) & IC_TYPE_MASK) +#define GET_CVID_CHIP_TYPE(version) ((version) & CHIP_TYPE_MASK) +#define GET_CVID_RF_TYPE(version) ((version) & RF_TYPE_MASK) +#define GET_CVID_MANUFACTUER(version) ((version) & MANUFACTUER_MASK) +#define GET_CVID_ROM_VERSION(version) ((version) & ROM_VERSION_MASK) +#define GET_CVID_CUT_VERSION(version) ((version) & CUT_VERSION_MASK) + +#define IS_1T1R(version) ((GET_CVID_RF_TYPE(version)) ? \ + false : true) +#define IS_1T2R(version) ((GET_CVID_RF_TYPE(version) == \ + RF_TYPE_1T2R) ? true : false) +#define IS_2T2R(version) ((GET_CVID_RF_TYPE(version) == \ + RF_TYPE_2T2R) ? true : false) + +#define IS_92D_SINGLEPHY(version) ((IS_92D(version)) ? \ + (IS_2T2R(version) ? true : false) : false) +#define IS_92D(version) ((GET_CVID_IC_TYPE(version) == \ + CHIP_92D) ? true : false) +#define IS_92D_C_CUT(version) ((IS_92D(version)) ? \ + ((GET_CVID_CUT_VERSION(version) == \ + 0x2000) ? true : false) : false) +#define IS_92D_D_CUT(version) ((IS_92D(version)) ? \ + ((GET_CVID_CUT_VERSION(version) == \ + 0x3000) ? true : false) : false) +#define IS_92D_E_CUT(version) ((IS_92D(version)) ? \ + ((GET_CVID_CUT_VERSION(version) == \ + 0x4000) ? true : false) : false) +#define CHIP_92D_C_CUT BIT(10) +#define CHIP_92D_D_CUT BIT(11) + +enum rf_optype { + RF_OP_BY_SW_3WIRE = 0, + RF_OP_BY_FW, + RF_OP_MAX +}; + +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 channel_plan { + CHPL_FCC = 0, + CHPL_IC = 1, + CHPL_ETSI = 2, + CHPL_SPAIN = 3, + CHPL_FRANCE = 4, + CHPL_MKK = 5, + CHPL_MKK1 = 6, + CHPL_ISRAEL = 7, + CHPL_TELEC = 8, + CHPL_GLOBAL = 9, + CHPL_WORLD = 10, +}; + +struct phy_sts_cck_8192d { + u8 adc_pwdb_X[4]; + u8 sq_rpt; + u8 cck_agc_rpt; +}; + +struct h2c_cmd_8192c { + u8 element_id; + u32 cmd_len; + u8 *p_cmdbuffer; +}; + +struct txpower_info { + u8 cck_index[RF6052_MAX_PATH][CHANNEL_GROUP_MAX]; + u8 ht40_1sindex[RF6052_MAX_PATH][CHANNEL_GROUP_MAX]; + u8 ht40_2sindexdiff[RF6052_MAX_PATH][CHANNEL_GROUP_MAX]; + u8 ht20indexdiff[RF6052_MAX_PATH][CHANNEL_GROUP_MAX]; + u8 ofdmindexdiff[RF6052_MAX_PATH][CHANNEL_GROUP_MAX]; + u8 ht40maxoffset[RF6052_MAX_PATH][CHANNEL_GROUP_MAX]; + u8 ht20maxoffset[RF6052_MAX_PATH][CHANNEL_GROUP_MAX]; + u8 tssi_a[3]; /* 5GL/5GM/5GH */ + u8 tssi_b[3]; +}; + +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/dm.c b/drivers/net/wireless/rtlwifi/rtl8192de/dm.c new file mode 100644 index 00000000..4737018c --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192de/dm.c @@ -0,0 +1,1332 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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> + * + *****************************************************************************/ + +#include "../wifi.h" +#include "../base.h" +#include "reg.h" +#include "def.h" +#include "phy.h" +#include "dm.h" +#include "fw.h" + +#define UNDEC_SM_PWDB entry_min_undecoratedsmoothed_pwdb + +struct dig_t de_digtable; + +static const u32 ofdmswing_table[OFDM_TABLE_SIZE_92D] = { + 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 rtl92d_dm_diginit(struct ieee80211_hw *hw) +{ + de_digtable.dig_enable_flag = true; + de_digtable.dig_ext_port_stage = DIG_EXT_PORT_STAGE_MAX; + de_digtable.cur_igvalue = 0x20; + de_digtable.pre_igvalue = 0x0; + de_digtable.cursta_connectctate = DIG_STA_DISCONNECT; + de_digtable.presta_connectstate = DIG_STA_DISCONNECT; + de_digtable.curmultista_connectstate = DIG_MULTISTA_DISCONNECT; + de_digtable.rssi_lowthresh = DM_DIG_THRESH_LOW; + de_digtable.rssi_highthresh = DM_DIG_THRESH_HIGH; + de_digtable.fa_lowthresh = DM_FALSEALARM_THRESH_LOW; + de_digtable.fa_highthresh = DM_FALSEALARM_THRESH_HIGH; + de_digtable.rx_gain_range_max = DM_DIG_FA_UPPER; + de_digtable.rx_gain_range_min = DM_DIG_FA_LOWER; + de_digtable.backoff_val = DM_DIG_BACKOFF_DEFAULT; + de_digtable.backoff_val_range_max = DM_DIG_BACKOFF_MAX; + de_digtable.backoff_val_range_min = DM_DIG_BACKOFF_MIN; + de_digtable.pre_cck_pd_state = CCK_PD_STAGE_LOWRSSI; + de_digtable.cur_cck_pd_state = CCK_PD_STAGE_MAX; + de_digtable.large_fa_hit = 0; + de_digtable.recover_cnt = 0; + de_digtable.forbidden_igi = DM_DIG_FA_LOWER; +} + +static void rtl92d_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); + unsigned long flag = 0; + + /* hold ofdm counter */ + rtl_set_bbreg(hw, ROFDM0_LSTF, BIT(31), 1); /* hold page C counter */ + rtl_set_bbreg(hw, ROFDM1_LSTF, BIT(31), 1); /*hold page D counter */ + + ret_value = rtl_get_bbreg(hw, ROFDM0_FRAMESYNC, BMASKDWORD); + 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, ROFDM_PHYCOUNTER1, BMASKDWORD); + falsealm_cnt->cnt_parity_fail = ((ret_value & 0xffff0000) >> 16); + ret_value = rtl_get_bbreg(hw, ROFDM_PHYCOUNTER2, BMASKDWORD); + falsealm_cnt->cnt_rate_illegal = (ret_value & 0xffff); + falsealm_cnt->cnt_crc8_fail = ((ret_value & 0xffff0000) >> 16); + ret_value = rtl_get_bbreg(hw, ROFDM_PHYCOUNTER3, BMASKDWORD); + 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; + + if (rtlpriv->rtlhal.current_bandtype != BAND_ON_5G) { + /* hold cck counter */ + rtl92d_acquire_cckandrw_pagea_ctl(hw, &flag); + ret_value = rtl_get_bbreg(hw, RCCK0_FACOUNTERLOWER, BMASKBYTE0); + falsealm_cnt->cnt_cck_fail = ret_value; + ret_value = rtl_get_bbreg(hw, RCCK0_FACOUNTERUPPER, BMASKBYTE3); + falsealm_cnt->cnt_cck_fail += (ret_value & 0xff) << 8; + rtl92d_release_cckandrw_pagea_ctl(hw, &flag); + } else { + falsealm_cnt->cnt_cck_fail = 0; + } + + /* reset false alarm counter registers */ + 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; + + rtl_set_bbreg(hw, ROFDM1_LSTF, 0x08000000, 1); + /* update ofdm counter */ + rtl_set_bbreg(hw, ROFDM1_LSTF, 0x08000000, 0); + /* update page C counter */ + rtl_set_bbreg(hw, ROFDM0_LSTF, BIT(31), 0); + /* update page D counter */ + rtl_set_bbreg(hw, ROFDM1_LSTF, BIT(31), 0); + if (rtlpriv->rtlhal.current_bandtype != BAND_ON_5G) { + /* reset cck counter */ + rtl92d_acquire_cckandrw_pagea_ctl(hw, &flag); + rtl_set_bbreg(hw, RCCK0_FALSEALARMREPORT, 0x0000c000, 0); + /* enable cck counter */ + rtl_set_bbreg(hw, RCCK0_FALSEALARMREPORT, 0x0000c000, 2); + rtl92d_release_cckandrw_pagea_ctl(hw, &flag); + } + RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, + "Cnt_Fast_Fsync_fail = %x, Cnt_SB_Search_fail = %x\n", + falsealm_cnt->cnt_fast_fsync_fail, + falsealm_cnt->cnt_sb_search_fail); + RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, + "Cnt_Parity_Fail = %x, Cnt_Rate_Illegal = %x, Cnt_Crc8_fail = %x, Cnt_Mcs_fail = %x\n", + falsealm_cnt->cnt_parity_fail, + falsealm_cnt->cnt_rate_illegal, + falsealm_cnt->cnt_crc8_fail, + falsealm_cnt->cnt_mcs_fail); + RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, + "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 rtl92d_dm_find_minimum_rssi(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtlpriv); + + /* Determine the minimum RSSI */ + if ((mac->link_state < MAC80211_LINKED) && + (rtlpriv->dm.UNDEC_SM_PWDB == 0)) { + de_digtable.min_undecorated_pwdb_for_dm = 0; + RT_TRACE(rtlpriv, 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) { + de_digtable.min_undecorated_pwdb_for_dm = + rtlpriv->dm.UNDEC_SM_PWDB; + RT_TRACE(rtlpriv, COMP_BB_POWERSAVING, DBG_LOUD, + "AP Client PWDB = 0x%lx\n", + rtlpriv->dm.UNDEC_SM_PWDB); + } else { + de_digtable.min_undecorated_pwdb_for_dm = + rtlpriv->dm.undecorated_smoothed_pwdb; + RT_TRACE(rtlpriv, COMP_BB_POWERSAVING, DBG_LOUD, + "STA Default Port PWDB = 0x%x\n", + de_digtable.min_undecorated_pwdb_for_dm); + } + } else { + de_digtable.min_undecorated_pwdb_for_dm = + rtlpriv->dm.UNDEC_SM_PWDB; + RT_TRACE(rtlpriv, COMP_BB_POWERSAVING, DBG_LOUD, + "AP Ext Port or disconnect PWDB = 0x%x\n", + de_digtable.min_undecorated_pwdb_for_dm); + } + + RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, "MinUndecoratedPWDBForDM =%d\n", + de_digtable.min_undecorated_pwdb_for_dm); +} + +static void rtl92d_dm_cck_packet_detection_thresh(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + unsigned long flag = 0; + + if (de_digtable.cursta_connectctate == DIG_STA_CONNECT) { + if (de_digtable.pre_cck_pd_state == CCK_PD_STAGE_LOWRSSI) { + if (de_digtable.min_undecorated_pwdb_for_dm <= 25) + de_digtable.cur_cck_pd_state = + CCK_PD_STAGE_LOWRSSI; + else + de_digtable.cur_cck_pd_state = + CCK_PD_STAGE_HIGHRSSI; + } else { + if (de_digtable.min_undecorated_pwdb_for_dm <= 20) + de_digtable.cur_cck_pd_state = + CCK_PD_STAGE_LOWRSSI; + else + de_digtable.cur_cck_pd_state = + CCK_PD_STAGE_HIGHRSSI; + } + } else { + de_digtable.cur_cck_pd_state = CCK_PD_STAGE_LOWRSSI; + } + if (de_digtable.pre_cck_pd_state != de_digtable.cur_cck_pd_state) { + if (de_digtable.cur_cck_pd_state == CCK_PD_STAGE_LOWRSSI) { + rtl92d_acquire_cckandrw_pagea_ctl(hw, &flag); + rtl_set_bbreg(hw, RCCK0_CCA, BMASKBYTE2, 0x83); + rtl92d_release_cckandrw_pagea_ctl(hw, &flag); + } else { + rtl92d_acquire_cckandrw_pagea_ctl(hw, &flag); + rtl_set_bbreg(hw, RCCK0_CCA, BMASKBYTE2, 0xcd); + rtl92d_release_cckandrw_pagea_ctl(hw, &flag); + } + de_digtable.pre_cck_pd_state = de_digtable.cur_cck_pd_state; + } + RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, "CurSTAConnectState=%s\n", + de_digtable.cursta_connectctate == DIG_STA_CONNECT ? + "DIG_STA_CONNECT " : "DIG_STA_DISCONNECT"); + RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, "CCKPDStage=%s\n", + de_digtable.cur_cck_pd_state == CCK_PD_STAGE_LOWRSSI ? + "Low RSSI " : "High RSSI "); + RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, "is92d single phy =%x\n", + IS_92D_SINGLEPHY(rtlpriv->rtlhal.version)); + +} + +void rtl92d_dm_write_dig(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, + "cur_igvalue = 0x%x, pre_igvalue = 0x%x, backoff_val = %d\n", + de_digtable.cur_igvalue, de_digtable.pre_igvalue, + de_digtable.backoff_val); + if (de_digtable.dig_enable_flag == false) { + RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, "DIG is disabled\n"); + de_digtable.pre_igvalue = 0x17; + return; + } + if (de_digtable.pre_igvalue != de_digtable.cur_igvalue) { + rtl_set_bbreg(hw, ROFDM0_XAAGCCORE1, 0x7f, + de_digtable.cur_igvalue); + rtl_set_bbreg(hw, ROFDM0_XBAGCCORE1, 0x7f, + de_digtable.cur_igvalue); + de_digtable.pre_igvalue = de_digtable.cur_igvalue; + } +} + +static void rtl92d_early_mode_enabled(struct rtl_priv *rtlpriv) +{ + if ((rtlpriv->mac80211.link_state >= MAC80211_LINKED) && + (rtlpriv->mac80211.vendor == PEER_CISCO)) { + RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, "IOT_PEER = CISCO\n"); + if (de_digtable.last_min_undecorated_pwdb_for_dm >= 50 + && de_digtable.min_undecorated_pwdb_for_dm < 50) { + rtl_write_byte(rtlpriv, REG_EARLY_MODE_CONTROL, 0x00); + RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, + "Early Mode Off\n"); + } else if (de_digtable.last_min_undecorated_pwdb_for_dm <= 55 && + de_digtable.min_undecorated_pwdb_for_dm > 55) { + rtl_write_byte(rtlpriv, REG_EARLY_MODE_CONTROL, 0x0f); + RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, + "Early Mode On\n"); + } + } else if (!(rtl_read_byte(rtlpriv, REG_EARLY_MODE_CONTROL) & 0xf)) { + rtl_write_byte(rtlpriv, REG_EARLY_MODE_CONTROL, 0x0f); + RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, "Early Mode On\n"); + } +} + +static void rtl92d_dm_dig(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 value_igi = de_digtable.cur_igvalue; + struct false_alarm_statistics *falsealm_cnt = &(rtlpriv->falsealm_cnt); + + RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, "==>\n"); + if (rtlpriv->rtlhal.earlymode_enable) { + rtl92d_early_mode_enabled(rtlpriv); + de_digtable.last_min_undecorated_pwdb_for_dm = + de_digtable.min_undecorated_pwdb_for_dm; + } + if (!rtlpriv->dm.dm_initialgain_enable) + return; + + /* because we will send data pkt when scanning + * this will cause some ap like gear-3700 wep TP + * lower if we retrun here, this is the diff of + * mac80211 driver vs ieee80211 driver */ + /* if (rtlpriv->mac80211.act_scanning) + * return; */ + + /* Not STA mode return tmp */ + if (rtlpriv->mac80211.opmode != NL80211_IFTYPE_STATION) + return; + RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, "progress\n"); + /* Decide the current status and if modify initial gain or not */ + if (rtlpriv->mac80211.link_state >= MAC80211_LINKED) + de_digtable.cursta_connectctate = DIG_STA_CONNECT; + else + de_digtable.cursta_connectctate = DIG_STA_DISCONNECT; + + /* adjust initial gain according to false alarm counter */ + if (falsealm_cnt->cnt_all < DM_DIG_FA_TH0) + value_igi--; + else if (falsealm_cnt->cnt_all < DM_DIG_FA_TH1) + value_igi += 0; + else if (falsealm_cnt->cnt_all < DM_DIG_FA_TH2) + value_igi++; + else if (falsealm_cnt->cnt_all >= DM_DIG_FA_TH2) + value_igi += 2; + RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, + "dm_DIG() Before: large_fa_hit=%d, forbidden_igi=%x\n", + de_digtable.large_fa_hit, de_digtable.forbidden_igi); + RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, + "dm_DIG() Before: Recover_cnt=%d, rx_gain_range_min=%x\n", + de_digtable.recover_cnt, de_digtable.rx_gain_range_min); + + /* deal with abnorally large false alarm */ + if (falsealm_cnt->cnt_all > 10000) { + RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, + "dm_DIG(): Abnormally false alarm case\n"); + + de_digtable.large_fa_hit++; + if (de_digtable.forbidden_igi < de_digtable.cur_igvalue) { + de_digtable.forbidden_igi = de_digtable.cur_igvalue; + de_digtable.large_fa_hit = 1; + } + if (de_digtable.large_fa_hit >= 3) { + if ((de_digtable.forbidden_igi + 1) > DM_DIG_MAX) + de_digtable.rx_gain_range_min = DM_DIG_MAX; + else + de_digtable.rx_gain_range_min = + (de_digtable.forbidden_igi + 1); + de_digtable.recover_cnt = 3600; /* 3600=2hr */ + } + } else { + /* Recovery mechanism for IGI lower bound */ + if (de_digtable.recover_cnt != 0) { + de_digtable.recover_cnt--; + } else { + if (de_digtable.large_fa_hit == 0) { + if ((de_digtable.forbidden_igi - 1) < + DM_DIG_FA_LOWER) { + de_digtable.forbidden_igi = + DM_DIG_FA_LOWER; + de_digtable.rx_gain_range_min = + DM_DIG_FA_LOWER; + + } else { + de_digtable.forbidden_igi--; + de_digtable.rx_gain_range_min = + (de_digtable.forbidden_igi + 1); + } + } else if (de_digtable.large_fa_hit == 3) { + de_digtable.large_fa_hit = 0; + } + } + } + RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, + "dm_DIG() After: large_fa_hit=%d, forbidden_igi=%x\n", + de_digtable.large_fa_hit, de_digtable.forbidden_igi); + RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, + "dm_DIG() After: recover_cnt=%d, rx_gain_range_min=%x\n", + de_digtable.recover_cnt, de_digtable.rx_gain_range_min); + + if (value_igi > DM_DIG_MAX) + value_igi = DM_DIG_MAX; + else if (value_igi < de_digtable.rx_gain_range_min) + value_igi = de_digtable.rx_gain_range_min; + de_digtable.cur_igvalue = value_igi; + rtl92d_dm_write_dig(hw); + if (rtlpriv->rtlhal.current_bandtype != BAND_ON_5G) + rtl92d_dm_cck_packet_detection_thresh(hw); + RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, "<<==\n"); +} + +static void rtl92d_dm_init_dynamic_txpower(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtlpriv->dm.dynamic_txpower_enable = true; + rtlpriv->dm.last_dtp_lvl = TXHIGHPWRLEVEL_NORMAL; + rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_NORMAL; +} + +static void rtl92d_dm_dynamic_txpower(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + long undecorated_smoothed_pwdb; + + if ((!rtlpriv->dm.dynamic_txpower_enable) + || rtlpriv->dm.dm_flag & HAL_DM_HIPWR_DISABLE) { + rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_NORMAL; + return; + } + if ((mac->link_state < MAC80211_LINKED) && + (rtlpriv->dm.UNDEC_SM_PWDB == 0)) { + RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE, + "Not connected to any\n"); + rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_NORMAL; + rtlpriv->dm.last_dtp_lvl = TXHIGHPWRLEVEL_NORMAL; + return; + } + if (mac->link_state >= MAC80211_LINKED) { + if (mac->opmode == NL80211_IFTYPE_ADHOC) { + undecorated_smoothed_pwdb = + rtlpriv->dm.UNDEC_SM_PWDB; + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + "IBSS Client PWDB = 0x%lx\n", + undecorated_smoothed_pwdb); + } else { + undecorated_smoothed_pwdb = + rtlpriv->dm.undecorated_smoothed_pwdb; + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + "STA Default Port PWDB = 0x%lx\n", + undecorated_smoothed_pwdb); + } + } else { + undecorated_smoothed_pwdb = + rtlpriv->dm.UNDEC_SM_PWDB; + + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + "AP Ext Port PWDB = 0x%lx\n", + undecorated_smoothed_pwdb); + } + if (rtlhal->current_bandtype == BAND_ON_5G) { + if (undecorated_smoothed_pwdb >= 0x33) { + rtlpriv->dm.dynamic_txhighpower_lvl = + TXHIGHPWRLEVEL_LEVEL2; + RT_TRACE(rtlpriv, COMP_HIPWR, DBG_LOUD, + "5G:TxHighPwrLevel_Level2 (TxPwr=0x0)\n"); + } else if ((undecorated_smoothed_pwdb < 0x33) + && (undecorated_smoothed_pwdb >= 0x2b)) { + rtlpriv->dm.dynamic_txhighpower_lvl = + TXHIGHPWRLEVEL_LEVEL1; + RT_TRACE(rtlpriv, COMP_HIPWR, DBG_LOUD, + "5G:TxHighPwrLevel_Level1 (TxPwr=0x10)\n"); + } else if (undecorated_smoothed_pwdb < 0x2b) { + rtlpriv->dm.dynamic_txhighpower_lvl = + TXHIGHPWRLEVEL_NORMAL; + RT_TRACE(rtlpriv, COMP_HIPWR, DBG_LOUD, + "5G:TxHighPwrLevel_Normal\n"); + } + } else { + if (undecorated_smoothed_pwdb >= + TX_POWER_NEAR_FIELD_THRESH_LVL2) { + rtlpriv->dm.dynamic_txhighpower_lvl = + TXHIGHPWRLEVEL_LEVEL2; + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + "TXHIGHPWRLEVEL_LEVEL1 (TxPwr=0x0)\n"); + } else + if ((undecorated_smoothed_pwdb < + (TX_POWER_NEAR_FIELD_THRESH_LVL2 - 3)) + && (undecorated_smoothed_pwdb >= + TX_POWER_NEAR_FIELD_THRESH_LVL1)) { + + rtlpriv->dm.dynamic_txhighpower_lvl = + TXHIGHPWRLEVEL_LEVEL1; + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + "TXHIGHPWRLEVEL_LEVEL1 (TxPwr=0x10)\n"); + } else if (undecorated_smoothed_pwdb < + (TX_POWER_NEAR_FIELD_THRESH_LVL1 - 5)) { + rtlpriv->dm.dynamic_txhighpower_lvl = + TXHIGHPWRLEVEL_NORMAL; + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + "TXHIGHPWRLEVEL_NORMAL\n"); + } + } + if ((rtlpriv->dm.dynamic_txhighpower_lvl != rtlpriv->dm.last_dtp_lvl)) { + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + "PHY_SetTxPowerLevel8192S() Channel = %d\n", + rtlphy->current_channel); + rtl92d_phy_set_txpower_level(hw, rtlphy->current_channel); + } + rtlpriv->dm.last_dtp_lvl = rtlpriv->dm.dynamic_txhighpower_lvl; +} + +static void rtl92d_dm_pwdb_monitor(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + /* AP & ADHOC & MESH will return tmp */ + if (rtlpriv->mac80211.opmode != NL80211_IFTYPE_STATION) + return; + /* Indicate Rx signal strength to FW. */ + if (rtlpriv->dm.useramask) { + u32 temp = rtlpriv->dm.undecorated_smoothed_pwdb; + + temp <<= 16; + temp |= 0x100; + /* fw v12 cmdid 5:use max macid ,for nic , + * default macid is 0 ,max macid is 1 */ + rtl92d_fill_h2c_cmd(hw, H2C_RSSI_REPORT, 3, (u8 *) (&temp)); + } else { + rtl_write_byte(rtlpriv, 0x4fe, + (u8) rtlpriv->dm.undecorated_smoothed_pwdb); + } +} + +void rtl92d_dm_init_edca_turbo(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtlpriv->dm.current_turbo_edca = false; + rtlpriv->dm.is_any_nonbepkts = false; + rtlpriv->dm.is_cur_rdlstate = false; +} + +static void rtl92d_dm_check_edca_turbo(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + static u64 last_txok_cnt; + static u64 last_rxok_cnt; + u64 cur_txok_cnt; + u64 cur_rxok_cnt; + u32 edca_be_ul = 0x5ea42b; + u32 edca_be_dl = 0x5ea42b; + + if (mac->link_state != MAC80211_LINKED) { + rtlpriv->dm.current_turbo_edca = false; + goto exit; + } + + /* Enable BEQ TxOP limit configuration in wireless G-mode. */ + /* To check whether we shall force turn on TXOP configuration. */ + if ((!rtlpriv->dm.disable_framebursting) && + (rtlpriv->sec.pairwise_enc_algorithm == WEP40_ENCRYPTION || + rtlpriv->sec.pairwise_enc_algorithm == WEP104_ENCRYPTION || + rtlpriv->sec.pairwise_enc_algorithm == TKIP_ENCRYPTION)) { + /* Force TxOP limit to 0x005e for UL. */ + if (!(edca_be_ul & 0xffff0000)) + edca_be_ul |= 0x005e0000; + /* Force TxOP limit to 0x005e for DL. */ + if (!(edca_be_dl & 0xffff0000)) + edca_be_dl |= 0x005e0000; + } + + if ((!rtlpriv->dm.is_any_nonbepkts) && + (!rtlpriv->dm.disable_framebursting)) { + cur_txok_cnt = rtlpriv->stats.txbytesunicast - last_txok_cnt; + cur_rxok_cnt = rtlpriv->stats.rxbytesunicast - last_rxok_cnt; + if (cur_rxok_cnt > 4 * cur_txok_cnt) { + if (!rtlpriv->dm.is_cur_rdlstate || + !rtlpriv->dm.current_turbo_edca) { + rtl_write_dword(rtlpriv, REG_EDCA_BE_PARAM, + edca_be_dl); + rtlpriv->dm.is_cur_rdlstate = true; + } + } else { + if (rtlpriv->dm.is_cur_rdlstate || + !rtlpriv->dm.current_turbo_edca) { + rtl_write_dword(rtlpriv, REG_EDCA_BE_PARAM, + edca_be_ul); + rtlpriv->dm.is_cur_rdlstate = false; + } + } + rtlpriv->dm.current_turbo_edca = true; + } else { + if (rtlpriv->dm.current_turbo_edca) { + u8 tmp = AC0_BE; + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_AC_PARAM, + (u8 *) (&tmp)); + rtlpriv->dm.current_turbo_edca = false; + } + } + +exit: + rtlpriv->dm.is_any_nonbepkts = false; + last_txok_cnt = rtlpriv->stats.txbytesunicast; + last_rxok_cnt = rtlpriv->stats.rxbytesunicast; +} + +static void rtl92d_dm_rxgain_tracking_thermalmeter(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 index_mapping[RX_INDEX_MAPPING_NUM] = { + 0x0f, 0x0f, 0x0d, 0x0c, 0x0b, + 0x0a, 0x09, 0x08, 0x07, 0x06, + 0x05, 0x04, 0x04, 0x03, 0x02 + }; + int i; + u32 u4tmp; + + u4tmp = (index_mapping[(rtlpriv->efuse.eeprom_thermalmeter - + rtlpriv->dm.thermalvalue_rxgain)]) << 12; + RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, + "===> Rx Gain %x\n", u4tmp); + for (i = RF90_PATH_A; i < rtlpriv->phy.num_total_rfpath; i++) + rtl_set_rfreg(hw, i, 0x3C, BRFREGOFFSETMASK, + (rtlpriv->phy.reg_rf3c[i] & (~(0xF000))) | u4tmp); +} + +static void rtl92d_bandtype_2_4G(struct ieee80211_hw *hw, long *temp_cckg, + u8 *cck_index_old) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + int i; + unsigned long flag = 0; + long temp_cck; + + /* Query CCK default setting From 0xa24 */ + rtl92d_acquire_cckandrw_pagea_ctl(hw, &flag); + temp_cck = rtl_get_bbreg(hw, RCCK0_TXFILTER2, + BMASKDWORD) & BMASKCCK; + rtl92d_release_cckandrw_pagea_ctl(hw, &flag); + for (i = 0; i < CCK_TABLE_LENGTH; i++) { + if (rtlpriv->dm.cck_inch14) { + if (!memcmp((void *)&temp_cck, + (void *)&cckswing_table_ch14[i][2], 4)) { + *cck_index_old = (u8) i; + RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, + "Initial reg0x%x = 0x%lx, cck_index=0x%x, ch 14 %d\n", + RCCK0_TXFILTER2, temp_cck, + *cck_index_old, + rtlpriv->dm.cck_inch14); + break; + } + } else { + if (!memcmp((void *) &temp_cck, + &cckswing_table_ch1ch13[i][2], 4)) { + *cck_index_old = (u8) i; + RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, + "Initial reg0x%x = 0x%lx, cck_index = 0x%x, ch14 %d\n", + RCCK0_TXFILTER2, temp_cck, + *cck_index_old, + rtlpriv->dm.cck_inch14); + break; + } + } + } + *temp_cckg = temp_cck; +} + +static void rtl92d_bandtype_5G(struct rtl_hal *rtlhal, u8 *ofdm_index, + bool *internal_pa, u8 thermalvalue, u8 delta, + u8 rf, struct rtl_efuse *rtlefuse, + struct rtl_priv *rtlpriv, struct rtl_phy *rtlphy, + u8 index_mapping[5][INDEX_MAPPING_NUM], + u8 index_mapping_pa[8][INDEX_MAPPING_NUM]) +{ + int i; + u8 index; + u8 offset = 0; + + for (i = 0; i < rf; i++) { + if (rtlhal->macphymode == DUALMAC_DUALPHY && + rtlhal->interfaceindex == 1) /* MAC 1 5G */ + *internal_pa = rtlefuse->internal_pa_5g[1]; + else + *internal_pa = rtlefuse->internal_pa_5g[i]; + if (*internal_pa) { + if (rtlhal->interfaceindex == 1 || i == rf) + offset = 4; + else + offset = 0; + if (rtlphy->current_channel >= 100 && + rtlphy->current_channel <= 165) + offset += 2; + } else { + if (rtlhal->interfaceindex == 1 || i == rf) + offset = 2; + else + offset = 0; + } + if (thermalvalue > rtlefuse->eeprom_thermalmeter) + offset++; + if (*internal_pa) { + if (delta > INDEX_MAPPING_NUM - 1) + index = index_mapping_pa[offset] + [INDEX_MAPPING_NUM - 1]; + else + index = + index_mapping_pa[offset][delta]; + } else { + if (delta > INDEX_MAPPING_NUM - 1) + index = + index_mapping[offset][INDEX_MAPPING_NUM - 1]; + else + index = index_mapping[offset][delta]; + } + if (thermalvalue > rtlefuse->eeprom_thermalmeter) { + if (*internal_pa && thermalvalue > 0x12) { + ofdm_index[i] = rtlpriv->dm.ofdm_index[i] - + ((delta / 2) * 3 + (delta % 2)); + } else { + ofdm_index[i] -= index; + } + } else { + ofdm_index[i] += index; + } + } +} + +static void rtl92d_dm_txpower_tracking_callback_thermalmeter( + 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_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + u8 thermalvalue, delta, delta_lck, delta_iqk, delta_rxgain; + u8 offset, thermalvalue_avg_count = 0; + u32 thermalvalue_avg = 0; + bool internal_pa = false; + long ele_a = 0, ele_d, temp_cck, val_x, value32; + long val_y, ele_c = 0; + u8 ofdm_index[2]; + u8 cck_index = 0; + u8 ofdm_index_old[2]; + u8 cck_index_old = 0; + u8 index; + int i; + bool is2t = IS_92D_SINGLEPHY(rtlhal->version); + u8 ofdm_min_index = 6, ofdm_min_index_internal_pa = 3, rf; + u8 indexforchannel = + rtl92d_get_rightchnlplace_for_iqk(rtlphy->current_channel); + u8 index_mapping[5][INDEX_MAPPING_NUM] = { + /* 5G, path A/MAC 0, decrease power */ + {0, 1, 3, 6, 8, 9, 11, 13, 14, 16, 17, 18, 18}, + /* 5G, path A/MAC 0, increase power */ + {0, 2, 4, 5, 7, 10, 12, 14, 16, 18, 18, 18, 18}, + /* 5G, path B/MAC 1, decrease power */ + {0, 2, 3, 6, 8, 9, 11, 13, 14, 16, 17, 18, 18}, + /* 5G, path B/MAC 1, increase power */ + {0, 2, 4, 5, 7, 10, 13, 16, 16, 18, 18, 18, 18}, + /* 2.4G, for decreas power */ + {0, 1, 2, 3, 4, 5, 6, 7, 7, 8, 9, 10, 10}, + }; + u8 index_mapping_internal_pa[8][INDEX_MAPPING_NUM] = { + /* 5G, path A/MAC 0, ch36-64, decrease power */ + {0, 1, 2, 4, 6, 7, 9, 11, 12, 14, 15, 16, 16}, + /* 5G, path A/MAC 0, ch36-64, increase power */ + {0, 2, 4, 5, 7, 10, 12, 14, 16, 18, 18, 18, 18}, + /* 5G, path A/MAC 0, ch100-165, decrease power */ + {0, 1, 2, 3, 5, 6, 8, 10, 11, 13, 14, 15, 15}, + /* 5G, path A/MAC 0, ch100-165, increase power */ + {0, 2, 4, 5, 7, 10, 12, 14, 16, 18, 18, 18, 18}, + /* 5G, path B/MAC 1, ch36-64, decrease power */ + {0, 1, 2, 4, 6, 7, 9, 11, 12, 14, 15, 16, 16}, + /* 5G, path B/MAC 1, ch36-64, increase power */ + {0, 2, 4, 5, 7, 10, 13, 16, 16, 18, 18, 18, 18}, + /* 5G, path B/MAC 1, ch100-165, decrease power */ + {0, 1, 2, 3, 5, 6, 8, 9, 10, 12, 13, 14, 14}, + /* 5G, path B/MAC 1, ch100-165, increase power */ + {0, 2, 4, 5, 7, 10, 13, 16, 16, 18, 18, 18, 18}, + }; + + rtlpriv->dm.txpower_trackinginit = true; + RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, "\n"); + thermalvalue = (u8) rtl_get_rfreg(hw, RF90_PATH_A, RF_T_METER, 0xf800); + RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, + "Readback Thermal Meter = 0x%x pre thermal meter 0x%x eeprom_thermalmeter 0x%x\n", + thermalvalue, + rtlpriv->dm.thermalvalue, rtlefuse->eeprom_thermalmeter); + rtl92d_phy_ap_calibrate(hw, (thermalvalue - + rtlefuse->eeprom_thermalmeter)); + if (is2t) + rf = 2; + else + rf = 1; + if (thermalvalue) { + ele_d = rtl_get_bbreg(hw, ROFDM0_XATxIQIMBALANCE, + BMASKDWORD) & BMASKOFDM_D; + for (i = 0; i < OFDM_TABLE_SIZE_92D; i++) { + if (ele_d == (ofdmswing_table[i] & BMASKOFDM_D)) { + ofdm_index_old[0] = (u8) i; + + RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, + "Initial pathA ele_d reg0x%x = 0x%lx, ofdm_index=0x%x\n", + ROFDM0_XATxIQIMBALANCE, + ele_d, ofdm_index_old[0]); + break; + } + } + if (is2t) { + ele_d = rtl_get_bbreg(hw, ROFDM0_XBTxIQIMBALANCE, + BMASKDWORD) & BMASKOFDM_D; + for (i = 0; i < OFDM_TABLE_SIZE_92D; i++) { + if (ele_d == + (ofdmswing_table[i] & BMASKOFDM_D)) { + ofdm_index_old[1] = (u8) i; + RT_TRACE(rtlpriv, COMP_POWER_TRACKING, + DBG_LOUD, + "Initial pathB ele_d reg 0x%x = 0x%lx, ofdm_index = 0x%x\n", + ROFDM0_XBTxIQIMBALANCE, ele_d, + ofdm_index_old[1]); + break; + } + } + } + if (rtlhal->current_bandtype == BAND_ON_2_4G) { + rtl92d_bandtype_2_4G(hw, &temp_cck, &cck_index_old); + } else { + temp_cck = 0x090e1317; + cck_index_old = 12; + } + + if (!rtlpriv->dm.thermalvalue) { + rtlpriv->dm.thermalvalue = + rtlefuse->eeprom_thermalmeter; + rtlpriv->dm.thermalvalue_lck = thermalvalue; + rtlpriv->dm.thermalvalue_iqk = thermalvalue; + rtlpriv->dm.thermalvalue_rxgain = + rtlefuse->eeprom_thermalmeter; + for (i = 0; i < rf; i++) + rtlpriv->dm.ofdm_index[i] = ofdm_index_old[i]; + rtlpriv->dm.cck_index = cck_index_old; + } + if (rtlhal->reloadtxpowerindex) { + for (i = 0; i < rf; i++) + rtlpriv->dm.ofdm_index[i] = ofdm_index_old[i]; + rtlpriv->dm.cck_index = cck_index_old; + RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, + "reload ofdm index for band switch\n"); + } + rtlpriv->dm.thermalvalue_avg + [rtlpriv->dm.thermalvalue_avg_index] = thermalvalue; + rtlpriv->dm.thermalvalue_avg_index++; + if (rtlpriv->dm.thermalvalue_avg_index == AVG_THERMAL_NUM) + rtlpriv->dm.thermalvalue_avg_index = 0; + for (i = 0; i < AVG_THERMAL_NUM; i++) { + if (rtlpriv->dm.thermalvalue_avg[i]) { + thermalvalue_avg += + rtlpriv->dm.thermalvalue_avg[i]; + thermalvalue_avg_count++; + } + } + if (thermalvalue_avg_count) + thermalvalue = (u8) (thermalvalue_avg / + thermalvalue_avg_count); + if (rtlhal->reloadtxpowerindex) { + delta = (thermalvalue > rtlefuse->eeprom_thermalmeter) ? + (thermalvalue - rtlefuse->eeprom_thermalmeter) : + (rtlefuse->eeprom_thermalmeter - thermalvalue); + rtlhal->reloadtxpowerindex = false; + rtlpriv->dm.done_txpower = false; + } else if (rtlpriv->dm.done_txpower) { + delta = (thermalvalue > rtlpriv->dm.thermalvalue) ? + (thermalvalue - rtlpriv->dm.thermalvalue) : + (rtlpriv->dm.thermalvalue - thermalvalue); + } else { + delta = (thermalvalue > rtlefuse->eeprom_thermalmeter) ? + (thermalvalue - rtlefuse->eeprom_thermalmeter) : + (rtlefuse->eeprom_thermalmeter - thermalvalue); + } + delta_lck = (thermalvalue > rtlpriv->dm.thermalvalue_lck) ? + (thermalvalue - rtlpriv->dm.thermalvalue_lck) : + (rtlpriv->dm.thermalvalue_lck - thermalvalue); + delta_iqk = (thermalvalue > rtlpriv->dm.thermalvalue_iqk) ? + (thermalvalue - rtlpriv->dm.thermalvalue_iqk) : + (rtlpriv->dm.thermalvalue_iqk - thermalvalue); + delta_rxgain = + (thermalvalue > rtlpriv->dm.thermalvalue_rxgain) ? + (thermalvalue - rtlpriv->dm.thermalvalue_rxgain) : + (rtlpriv->dm.thermalvalue_rxgain - thermalvalue); + RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, + "Readback Thermal Meter = 0x%x pre thermal meter 0x%x eeprom_thermalmeter 0x%x delta 0x%x delta_lck 0x%x delta_iqk 0x%x\n", + thermalvalue, rtlpriv->dm.thermalvalue, + rtlefuse->eeprom_thermalmeter, delta, delta_lck, + delta_iqk); + if ((delta_lck > rtlefuse->delta_lck) && + (rtlefuse->delta_lck != 0)) { + rtlpriv->dm.thermalvalue_lck = thermalvalue; + rtl92d_phy_lc_calibrate(hw); + } + if (delta > 0 && rtlpriv->dm.txpower_track_control) { + rtlpriv->dm.done_txpower = true; + delta = (thermalvalue > rtlefuse->eeprom_thermalmeter) ? + (thermalvalue - rtlefuse->eeprom_thermalmeter) : + (rtlefuse->eeprom_thermalmeter - thermalvalue); + if (rtlhal->current_bandtype == BAND_ON_2_4G) { + offset = 4; + if (delta > INDEX_MAPPING_NUM - 1) + index = index_mapping[offset] + [INDEX_MAPPING_NUM - 1]; + else + index = index_mapping[offset][delta]; + if (thermalvalue > rtlpriv->dm.thermalvalue) { + for (i = 0; i < rf; i++) + ofdm_index[i] -= delta; + cck_index -= delta; + } else { + for (i = 0; i < rf; i++) + ofdm_index[i] += index; + cck_index += index; + } + } else if (rtlhal->current_bandtype == BAND_ON_5G) { + rtl92d_bandtype_5G(rtlhal, ofdm_index, + &internal_pa, thermalvalue, + delta, rf, rtlefuse, rtlpriv, + rtlphy, index_mapping, + index_mapping_internal_pa); + } + if (is2t) { + RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, + "temp OFDM_A_index=0x%x, OFDM_B_index = 0x%x,cck_index=0x%x\n", + rtlpriv->dm.ofdm_index[0], + rtlpriv->dm.ofdm_index[1], + rtlpriv->dm.cck_index); + } else { + RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, + "temp OFDM_A_index=0x%x,cck_index = 0x%x\n", + rtlpriv->dm.ofdm_index[0], + rtlpriv->dm.cck_index); + } + for (i = 0; i < rf; i++) { + if (ofdm_index[i] > OFDM_TABLE_SIZE_92D - 1) + ofdm_index[i] = OFDM_TABLE_SIZE_92D - 1; + else if (ofdm_index[i] < ofdm_min_index) + ofdm_index[i] = ofdm_min_index; + } + if (rtlhal->current_bandtype == BAND_ON_2_4G) { + if (cck_index > CCK_TABLE_SIZE - 1) { + cck_index = CCK_TABLE_SIZE - 1; + } else if (internal_pa || + rtlhal->current_bandtype == + BAND_ON_2_4G) { + if (ofdm_index[i] < + ofdm_min_index_internal_pa) + ofdm_index[i] = + ofdm_min_index_internal_pa; + } else if (cck_index < 0) { + cck_index = 0; + } + } + if (is2t) { + RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, + "new OFDM_A_index=0x%x, OFDM_B_index = 0x%x, cck_index=0x%x\n", + ofdm_index[0], ofdm_index[1], + cck_index); + } else { + RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, + "new OFDM_A_index=0x%x,cck_index = 0x%x\n", + ofdm_index[0], cck_index); + } + ele_d = (ofdmswing_table[(u8) ofdm_index[0]] & + 0xFFC00000) >> 22; + val_x = rtlphy->iqk_matrix_regsetting + [indexforchannel].value[0][0]; + val_y = rtlphy->iqk_matrix_regsetting + [indexforchannel].value[0][1]; + if (val_x != 0) { + if ((val_x & 0x00000200) != 0) + val_x = val_x | 0xFFFFFC00; + ele_a = + ((val_x * ele_d) >> 8) & 0x000003FF; + + /* new element C = element D x Y */ + if ((val_y & 0x00000200) != 0) + val_y = val_y | 0xFFFFFC00; + ele_c = ((val_y * ele_d) >> 8) & 0x000003FF; + + /* wirte new elements A, C, D to regC80 and + * regC94, element B is always 0 */ + value32 = (ele_d << 22) | ((ele_c & 0x3F) << + 16) | ele_a; + rtl_set_bbreg(hw, ROFDM0_XATxIQIMBALANCE, + BMASKDWORD, value32); + + value32 = (ele_c & 0x000003C0) >> 6; + rtl_set_bbreg(hw, ROFDM0_XCTxAFE, BMASKH4BITS, + value32); + + value32 = ((val_x * ele_d) >> 7) & 0x01; + rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD, BIT(24), + value32); + + } else { + rtl_set_bbreg(hw, ROFDM0_XATxIQIMBALANCE, + BMASKDWORD, + ofdmswing_table + [(u8)ofdm_index[0]]); + rtl_set_bbreg(hw, ROFDM0_XCTxAFE, BMASKH4BITS, + 0x00); + rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD, + BIT(24), 0x00); + } + + RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, + "TxPwrTracking for interface %d path A: X = 0x%lx, Y = 0x%lx ele_A = 0x%lx ele_C = 0x%lx ele_D = 0x%lx 0xe94 = 0x%lx 0xe9c = 0x%lx\n", + rtlhal->interfaceindex, + val_x, val_y, ele_a, ele_c, ele_d, + val_x, val_y); + + if (rtlhal->current_bandtype == BAND_ON_2_4G) { + /* Adjust CCK according to IQK result */ + if (!rtlpriv->dm.cck_inch14) { + rtl_write_byte(rtlpriv, 0xa22, + cckswing_table_ch1ch13 + [(u8)cck_index][0]); + rtl_write_byte(rtlpriv, 0xa23, + cckswing_table_ch1ch13 + [(u8)cck_index][1]); + rtl_write_byte(rtlpriv, 0xa24, + cckswing_table_ch1ch13 + [(u8)cck_index][2]); + rtl_write_byte(rtlpriv, 0xa25, + cckswing_table_ch1ch13 + [(u8)cck_index][3]); + rtl_write_byte(rtlpriv, 0xa26, + cckswing_table_ch1ch13 + [(u8)cck_index][4]); + rtl_write_byte(rtlpriv, 0xa27, + cckswing_table_ch1ch13 + [(u8)cck_index][5]); + rtl_write_byte(rtlpriv, 0xa28, + cckswing_table_ch1ch13 + [(u8)cck_index][6]); + rtl_write_byte(rtlpriv, 0xa29, + cckswing_table_ch1ch13 + [(u8)cck_index][7]); + } else { + rtl_write_byte(rtlpriv, 0xa22, + cckswing_table_ch14 + [(u8)cck_index][0]); + rtl_write_byte(rtlpriv, 0xa23, + cckswing_table_ch14 + [(u8)cck_index][1]); + rtl_write_byte(rtlpriv, 0xa24, + cckswing_table_ch14 + [(u8)cck_index][2]); + rtl_write_byte(rtlpriv, 0xa25, + cckswing_table_ch14 + [(u8)cck_index][3]); + rtl_write_byte(rtlpriv, 0xa26, + cckswing_table_ch14 + [(u8)cck_index][4]); + rtl_write_byte(rtlpriv, 0xa27, + cckswing_table_ch14 + [(u8)cck_index][5]); + rtl_write_byte(rtlpriv, 0xa28, + cckswing_table_ch14 + [(u8)cck_index][6]); + rtl_write_byte(rtlpriv, 0xa29, + cckswing_table_ch14 + [(u8)cck_index][7]); + } + } + if (is2t) { + ele_d = (ofdmswing_table[(u8) ofdm_index[1]] & + 0xFFC00000) >> 22; + val_x = rtlphy->iqk_matrix_regsetting + [indexforchannel].value[0][4]; + val_y = rtlphy->iqk_matrix_regsetting + [indexforchannel].value[0][5]; + if (val_x != 0) { + if ((val_x & 0x00000200) != 0) + /* consider minus */ + val_x = val_x | 0xFFFFFC00; + ele_a = ((val_x * ele_d) >> 8) & + 0x000003FF; + /* new element C = element D x Y */ + if ((val_y & 0x00000200) != 0) + val_y = + val_y | 0xFFFFFC00; + ele_c = + ((val_y * + ele_d) >> 8) & 0x00003FF; + /* write new elements A, C, D to regC88 + * and regC9C, element B is always 0 + */ + value32 = (ele_d << 22) | + ((ele_c & 0x3F) << 16) | + ele_a; + rtl_set_bbreg(hw, + ROFDM0_XBTxIQIMBALANCE, + BMASKDWORD, value32); + value32 = (ele_c & 0x000003C0) >> 6; + rtl_set_bbreg(hw, ROFDM0_XDTxAFE, + BMASKH4BITS, value32); + value32 = ((val_x * ele_d) >> 7) & 0x01; + rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD, + BIT(28), value32); + } else { + rtl_set_bbreg(hw, + ROFDM0_XBTxIQIMBALANCE, + BMASKDWORD, + ofdmswing_table + [(u8) ofdm_index[1]]); + rtl_set_bbreg(hw, ROFDM0_XDTxAFE, + BMASKH4BITS, 0x00); + rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD, + BIT(28), 0x00); + } + RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, + "TxPwrTracking path B: X = 0x%lx, Y = 0x%lx ele_A = 0x%lx ele_C = 0x%lx ele_D = 0x%lx 0xeb4 = 0x%lx 0xebc = 0x%lx\n", + val_x, val_y, ele_a, ele_c, + ele_d, val_x, val_y); + } + RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, + "TxPwrTracking 0xc80 = 0x%x, 0xc94 = 0x%x RF 0x24 = 0x%x\n", + rtl_get_bbreg(hw, 0xc80, BMASKDWORD), + rtl_get_bbreg(hw, 0xc94, BMASKDWORD), + rtl_get_rfreg(hw, RF90_PATH_A, 0x24, + BRFREGOFFSETMASK)); + } + if ((delta_iqk > rtlefuse->delta_iqk) && + (rtlefuse->delta_iqk != 0)) { + rtl92d_phy_reset_iqk_result(hw); + rtlpriv->dm.thermalvalue_iqk = thermalvalue; + rtl92d_phy_iq_calibrate(hw); + } + if (delta_rxgain > 0 && rtlhal->current_bandtype == BAND_ON_5G + && thermalvalue <= rtlefuse->eeprom_thermalmeter) { + rtlpriv->dm.thermalvalue_rxgain = thermalvalue; + rtl92d_dm_rxgain_tracking_thermalmeter(hw); + } + if (rtlpriv->dm.txpower_track_control) + rtlpriv->dm.thermalvalue = thermalvalue; + } + + RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, "<===\n"); +} + +static void rtl92d_dm_initialize_txpower_tracking(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtlpriv->dm.txpower_tracking = true; + rtlpriv->dm.txpower_trackinginit = false; + rtlpriv->dm.txpower_track_control = true; + RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, + "pMgntInfo->txpower_tracking = %d\n", + rtlpriv->dm.txpower_tracking); +} + +void rtl92d_dm_check_txpower_tracking_thermal_meter(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + static u8 tm_trigger; + + if (!rtlpriv->dm.txpower_tracking) + return; + + if (!tm_trigger) { + rtl_set_rfreg(hw, RF90_PATH_A, RF_T_METER, BIT(17) | + BIT(16), 0x03); + RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, + "Trigger 92S Thermal Meter!!\n"); + tm_trigger = 1; + return; + } else { + RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, + "Schedule TxPowerTracking direct call!!\n"); + rtl92d_dm_txpower_tracking_callback_thermalmeter(hw); + tm_trigger = 0; + } +} + +void rtl92d_dm_init_rate_adaptive_mask(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rate_adaptive *ra = &(rtlpriv->ra); + + ra->ratr_state = DM_RATR_STA_INIT; + ra->pre_ratr_state = DM_RATR_STA_INIT; + if (rtlpriv->dm.dm_type == DM_TYPE_BYDRIVER) + rtlpriv->dm.useramask = true; + else + rtlpriv->dm.useramask = false; +} + +void rtl92d_dm_init(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtlpriv->dm.dm_type = DM_TYPE_BYDRIVER; + rtl92d_dm_diginit(hw); + rtl92d_dm_init_dynamic_txpower(hw); + rtl92d_dm_init_edca_turbo(hw); + rtl92d_dm_init_rate_adaptive_mask(hw); + rtl92d_dm_initialize_txpower_tracking(hw); +} + +void rtl92d_dm_watchdog(struct ieee80211_hw *hw) +{ + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + bool fw_current_inpsmode = false; + bool fwps_awake = true; + + /* 1. RF is OFF. (No need to do DM.) + * 2. Fw is under power saving mode for FwLPS. + * (Prevent from SW/FW I/O racing.) + * 3. IPS workitem is scheduled. (Prevent from IPS sequence + * to be swapped with DM. + * 4. RFChangeInProgress is TRUE. + * (Prevent from broken by IPS/HW/SW Rf off.) */ + + if ((ppsc->rfpwr_state == ERFON) && ((!fw_current_inpsmode) && + fwps_awake) && (!ppsc->rfchange_inprogress)) { + rtl92d_dm_pwdb_monitor(hw); + rtl92d_dm_false_alarm_counter_statistics(hw); + rtl92d_dm_find_minimum_rssi(hw); + rtl92d_dm_dig(hw); + /* rtl92d_dm_dynamic_bb_powersaving(hw); */ + rtl92d_dm_dynamic_txpower(hw); + /* rtl92d_dm_check_txpower_tracking_thermal_meter(hw); */ + /* rtl92d_dm_refresh_rate_adaptive_mask(hw); */ + /* rtl92d_dm_interrupt_migration(hw); */ + rtl92d_dm_check_edca_turbo(hw); + } +} diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/dm.h b/drivers/net/wireless/rtlwifi/rtl8192de/dm.h new file mode 100644 index 00000000..91030ec8 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192de/dm.h @@ -0,0 +1,212 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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 __RTL92C_DM_H__ +#define __RTL92C_DM_H__ + +#define HAL_DM_DIG_DISABLE BIT(0) +#define HAL_DM_HIPWR_DISABLE BIT(1) + +#define OFDM_TABLE_LENGTH 37 +#define OFDM_TABLE_SIZE_92D 43 +#define CCK_TABLE_LENGTH 33 + +#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 0x1c + +#define DM_DIG_FA_UPPER 0x32 +#define DM_DIG_FA_LOWER 0x20 +#define DM_DIG_FA_TH0 0x100 +#define DM_DIG_FA_TH1 0x400 +#define DM_DIG_FA_TH2 0x600 + +#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 INDEX_MAPPING_NUM 13 + +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; + + char backoff_val; + char backoff_val_range_max; + char backoff_val_range_min; + u8 rx_gain_range_max; + u8 rx_gain_range_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 pre_cck_fa_state; + u8 cur_cck_fa_state; + + u8 pre_ccastate; + u8 cur_ccasate; + + u8 large_fa_hit; + u8 forbidden_igi; + u32 recover_cnt; +}; + +struct swat { + u8 failure_cnt; + u8 try_flag; + u8 stop_trying; + long pre_rssi; + long trying_threshold; + u8 cur_antenna; + u8 pre_antenna; +}; + +enum tag_dynamic_init_gain_operation_type_definition { + DIG_TYPE_THRESH_HIGH = 0, + DIG_TYPE_THRESH_LOW = 1, + DIG_TYPE_BACKOFF = 2, + DIG_TYPE_RX_GAIN_MIN = 3, + DIG_TYPE_RX_GAIN_MAX = 4, + DIG_TYPE_ENABLE = 5, + DIG_TYPE_DISABLE = 6, + DIG_OP_TYPE_MAX +}; + +enum tag_cck_packet_detection_threshold_type_definition { + CCK_PD_STAGE_LOWRSSI = 0, + CCK_PD_STAGE_HIGHRSSI = 1, + CCK_FA_STAGE_LOW = 2, + CCK_FA_STAGE_HIGH = 3, + CCK_PD_STAGE_MAX = 4, +}; + +enum dm_1r_cca { + CCA_1R = 0, + CCA_2R = 1, + CCA_MAX = 2, +}; + +enum dm_rf { + RF_SAVE = 0, + RF_NORMAL = 1, + RF_MAX = 2, +}; + +enum dm_sw_ant_switch { + ANS_ANTENNA_B = 1, + ANS_ANTENNA_A = 2, + ANS_ANTENNA_MAX = 3, +}; + +enum dm_dig_ext_port_alg { + DIG_EXT_PORT_STAGE_0 = 0, + DIG_EXT_PORT_STAGE_1 = 1, + DIG_EXT_PORT_STAGE_2 = 2, + DIG_EXT_PORT_STAGE_3 = 3, + DIG_EXT_PORT_STAGE_MAX = 4, +}; + +enum dm_dig_connect { + DIG_STA_DISCONNECT = 0, + DIG_STA_CONNECT = 1, + DIG_STA_BEFORE_CONNECT = 2, + DIG_MULTISTA_DISCONNECT = 3, + DIG_MULTISTA_CONNECT = 4, + DIG_CONNECT_MAX +}; + +extern struct dig_t de_digtable; + +void rtl92d_dm_init(struct ieee80211_hw *hw); +void rtl92d_dm_watchdog(struct ieee80211_hw *hw); +void rtl92d_dm_init_edca_turbo(struct ieee80211_hw *hw); +void rtl92d_dm_write_dig(struct ieee80211_hw *hw); +void rtl92d_dm_check_txpower_tracking_thermal_meter(struct ieee80211_hw *hw); +void rtl92d_dm_init_rate_adaptive_mask(struct ieee80211_hw *hw); + +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/fw.c b/drivers/net/wireless/rtlwifi/rtl8192de/fw.c new file mode 100644 index 00000000..f548a8d0 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192de/fw.c @@ -0,0 +1,781 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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> + * + *****************************************************************************/ + +#include "../wifi.h" +#include "../pci.h" +#include "../base.h" +#include "reg.h" +#include "def.h" +#include "fw.h" +#include "sw.h" + +static bool _rtl92d_is_fw_downloaded(struct rtl_priv *rtlpriv) +{ + return (rtl_read_dword(rtlpriv, REG_MCUFWDL) & MCUFWDL_RDY) ? + true : false; +} + +static void _rtl92d_enable_fw_download(struct ieee80211_hw *hw, bool enable) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 tmp; + + if (enable) { + tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1); + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, tmp | 0x04); + tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL); + rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp | 0x01); + 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); + /* Reserved for fw extension. + * 0x81[7] is used for mac0 status , + * so don't write this reg here + * rtl_write_byte(rtlpriv, REG_MCUFWDL + 1, 0x00);*/ + } +} + +static void _rtl92d_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_8192D_START_ADDRESS + offset), + *(pu4BytePtr + i)); + } + if (remainSize) { + offset = blockCount * blocksize; + bufferptr += offset; + for (i = 0; i < remainSize; i++) { + rtl_write_byte(rtlpriv, (FW_8192D_START_ADDRESS + + offset + i), *(bufferptr + i)); + } + } +} + +static void _rtl92d_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); + _rtl92d_fw_block_write(hw, buffer, size); +} + +static void _rtl92d_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 _rtl92d_write_fw(struct ieee80211_hw *hw, + enum version_8192d version, u8 *buffer, u32 size) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u8 *bufferPtr = (u8 *) buffer; + u32 pagenums, remainSize; + u32 page, offset; + + RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, "FW size is %d bytes,\n", size); + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192DE) + _rtl92d_fill_dummy(bufferPtr, &size); + pagenums = size / FW_8192D_PAGE_SIZE; + remainSize = size % FW_8192D_PAGE_SIZE; + if (pagenums > 8) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "Page numbers should not greater then 8\n"); + } + for (page = 0; page < pagenums; page++) { + offset = page * FW_8192D_PAGE_SIZE; + _rtl92d_fw_page_write(hw, page, (bufferPtr + offset), + FW_8192D_PAGE_SIZE); + } + if (remainSize) { + offset = pagenums * FW_8192D_PAGE_SIZE; + page = pagenums; + _rtl92d_fw_page_write(hw, page, (bufferPtr + offset), + remainSize); + } +} + +static int _rtl92d_fw_free_to_go(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 counter = 0; + u32 value32; + + do { + value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL); + } while ((counter++ < FW_8192D_POLLING_TIMEOUT_COUNT) && + (!(value32 & FWDL_ChkSum_rpt))); + if (counter >= FW_8192D_POLLING_TIMEOUT_COUNT) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "chksum report faill ! REG_MCUFWDL:0x%08x\n", + value32); + return -EIO; + } + RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, + "Checksum report OK ! REG_MCUFWDL:0x%08x\n", value32); + value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL); + value32 |= MCUFWDL_RDY; + rtl_write_dword(rtlpriv, REG_MCUFWDL, value32); + return 0; +} + +void rtl92d_firmware_selfreset(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 u1b_tmp; + u8 delay = 100; + + /* Set (REG_HMETFR + 3) to 0x20 is reset 8051 */ + rtl_write_byte(rtlpriv, REG_HMETFR + 3, 0x20); + u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1); + while (u1b_tmp & BIT(2)) { + delay--; + if (delay == 0) + break; + udelay(50); + u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1); + } + RT_ASSERT((delay > 0), "8051 reset failed!\n"); + RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG, + "=====> 8051 reset success (%d)\n", delay); +} + +static int _rtl92d_fw_init(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u32 counter; + + RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG, "FW already have download\n"); + /* polling for FW ready */ + counter = 0; + do { + if (rtlhal->interfaceindex == 0) { + if (rtl_read_byte(rtlpriv, FW_MAC0_READY) & + MAC0_READY) { + RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG, + "Polling FW ready success!! REG_MCUFWDL: 0x%x\n", + rtl_read_byte(rtlpriv, + FW_MAC0_READY)); + return 0; + } + udelay(5); + } else { + if (rtl_read_byte(rtlpriv, FW_MAC1_READY) & + MAC1_READY) { + RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG, + "Polling FW ready success!! REG_MCUFWDL: 0x%x\n", + rtl_read_byte(rtlpriv, + FW_MAC1_READY)); + return 0; + } + udelay(5); + } + } while (counter++ < POLLING_READY_TIMEOUT_COUNT); + + if (rtlhal->interfaceindex == 0) { + RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG, + "Polling FW ready fail!! MAC0 FW init not ready: 0x%x\n", + rtl_read_byte(rtlpriv, FW_MAC0_READY)); + } else { + RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG, + "Polling FW ready fail!! MAC1 FW init not ready: 0x%x\n", + rtl_read_byte(rtlpriv, FW_MAC1_READY)); + } + RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG, + "Polling FW ready fail!! REG_MCUFWDL:0x%08ul\n", + rtl_read_dword(rtlpriv, REG_MCUFWDL)); + return -1; +} + +int rtl92d_download_fw(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u8 *pfwheader; + u8 *pfwdata; + u32 fwsize; + int err; + enum version_8192d version = rtlhal->version; + u8 value; + u32 count; + bool fw_downloaded = false, fwdl_in_process = false; + unsigned long flags; + + if (rtlpriv->max_fw_size == 0 || !rtlhal->pfirmware) + return 1; + fwsize = rtlhal->fwsize; + pfwheader = (u8 *) rtlhal->pfirmware; + pfwdata = (u8 *) rtlhal->pfirmware; + rtlhal->fw_version = (u16) GET_FIRMWARE_HDR_VERSION(pfwheader); + rtlhal->fw_subversion = (u16) GET_FIRMWARE_HDR_SUB_VER(pfwheader); + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "FirmwareVersion(%d), FirmwareSubVersion(%d), Signature(%#x)\n", + rtlhal->fw_version, rtlhal->fw_subversion, + GET_FIRMWARE_HDR_SIGNATURE(pfwheader)); + if (IS_FW_HEADER_EXIST(pfwheader)) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "Shift 32 bytes for FW header!!\n"); + pfwdata = pfwdata + 32; + fwsize = fwsize - 32; + } + + spin_lock_irqsave(&globalmutex_for_fwdownload, flags); + fw_downloaded = _rtl92d_is_fw_downloaded(rtlpriv); + if ((rtl_read_byte(rtlpriv, 0x1f) & BIT(5)) == BIT(5)) + fwdl_in_process = true; + else + fwdl_in_process = false; + if (fw_downloaded) { + spin_unlock_irqrestore(&globalmutex_for_fwdownload, flags); + goto exit; + } else if (fwdl_in_process) { + spin_unlock_irqrestore(&globalmutex_for_fwdownload, flags); + for (count = 0; count < 5000; count++) { + udelay(500); + spin_lock_irqsave(&globalmutex_for_fwdownload, flags); + fw_downloaded = _rtl92d_is_fw_downloaded(rtlpriv); + if ((rtl_read_byte(rtlpriv, 0x1f) & BIT(5)) == BIT(5)) + fwdl_in_process = true; + else + fwdl_in_process = false; + spin_unlock_irqrestore(&globalmutex_for_fwdownload, + flags); + if (fw_downloaded) + goto exit; + else if (!fwdl_in_process) + break; + else + RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG, + "Wait for another mac download fw\n"); + } + spin_lock_irqsave(&globalmutex_for_fwdownload, flags); + value = rtl_read_byte(rtlpriv, 0x1f); + value |= BIT(5); + rtl_write_byte(rtlpriv, 0x1f, value); + spin_unlock_irqrestore(&globalmutex_for_fwdownload, flags); + } else { + value = rtl_read_byte(rtlpriv, 0x1f); + value |= BIT(5); + rtl_write_byte(rtlpriv, 0x1f, value); + spin_unlock_irqrestore(&globalmutex_for_fwdownload, flags); + } + + /* If 8051 is running in RAM code, driver should + * inform Fw to reset by itself, or it will cause + * download Fw fail.*/ + /* 8051 RAM code */ + if (rtl_read_byte(rtlpriv, REG_MCUFWDL) & BIT(7)) { + rtl92d_firmware_selfreset(hw); + rtl_write_byte(rtlpriv, REG_MCUFWDL, 0x00); + } + _rtl92d_enable_fw_download(hw, true); + _rtl92d_write_fw(hw, version, pfwdata, fwsize); + _rtl92d_enable_fw_download(hw, false); + spin_lock_irqsave(&globalmutex_for_fwdownload, flags); + err = _rtl92d_fw_free_to_go(hw); + /* download fw over,clear 0x1f[5] */ + value = rtl_read_byte(rtlpriv, 0x1f); + value &= (~BIT(5)); + rtl_write_byte(rtlpriv, 0x1f, value); + spin_unlock_irqrestore(&globalmutex_for_fwdownload, flags); + if (err) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "fw is not ready to run!\n"); + goto exit; + } else { + RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, "fw is ready to run!\n"); + } +exit: + err = _rtl92d_fw_init(hw); + return err; +} + +static bool _rtl92d_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 _rtl92d_fill_h2c_command(struct ieee80211_hw *hw, + u8 element_id, u32 cmd_len, u8 *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 wait_writeh2c_limmit = 100; + u8 boxcontent[4], boxextcontent[2]; + u32 h2c_waitcounter = 0; + unsigned long flag; + u8 idx; + + if (ppsc->rfpwr_state == ERFOFF || ppsc->inactive_pwrstate == ERFOFF) { + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, + "Return as RF is off!!!\n"); + return; + } + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "come in\n"); + while (true) { + spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag); + if (rtlhal->h2c_setinprogress) { + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, + "H2C set in progress! Wait to set..element_id(%d)\n", + element_id); + + while (rtlhal->h2c_setinprogress) { + spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, + flag); + h2c_waitcounter++; + RT_TRACE(rtlpriv, 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->h2c_setinprogress = true; + spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag); + break; + } + } + while (!bwrite_sucess) { + wait_writeh2c_limmit--; + if (wait_writeh2c_limmit == 0) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "Write H2C fail because no trigger for FW INT!\n"); + break; + } + 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(rtlpriv, COMP_ERR, DBG_EMERG, + "switch case not processed\n"); + break; + } + isfw_read = _rtl92d_check_fw_read_last_h2c(hw, boxnum); + while (!isfw_read) { + wait_h2c_limmit--; + if (wait_h2c_limmit == 0) { + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, + "Waiting too long for FW read clear HMEBox(%d)!\n", + boxnum); + break; + } + udelay(10); + isfw_read = _rtl92d_check_fw_read_last_h2c(hw, boxnum); + u1b_tmp = rtl_read_byte(rtlpriv, 0x1BF); + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, + "Waiting for FW read clear HMEBox(%d)!!! 0x1BF = %2x\n", + boxnum, u1b_tmp); + } + if (!isfw_read) { + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, + "Write H2C register BOX[%d] fail!!!!! Fw do not read.\n", + boxnum); + break; + } + memset(boxcontent, 0, sizeof(boxcontent)); + memset(boxextcontent, 0, sizeof(boxextcontent)); + boxcontent[0] = element_id; + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, + "Write element_id box_reg(%4x) = %2x\n", + box_reg, element_id); + switch (cmd_len) { + case 1: + boxcontent[0] &= ~(BIT(7)); + memcpy(boxcontent + 1, cmdbuffer + buf_index, 1); + for (idx = 0; idx < 4; idx++) + rtl_write_byte(rtlpriv, box_reg + idx, + boxcontent[idx]); + break; + case 2: + boxcontent[0] &= ~(BIT(7)); + memcpy(boxcontent + 1, cmdbuffer + buf_index, 2); + for (idx = 0; idx < 4; idx++) + rtl_write_byte(rtlpriv, box_reg + idx, + boxcontent[idx]); + break; + case 3: + boxcontent[0] &= ~(BIT(7)); + memcpy(boxcontent + 1, cmdbuffer + buf_index, 3); + for (idx = 0; idx < 4; idx++) + rtl_write_byte(rtlpriv, box_reg + idx, + boxcontent[idx]); + break; + case 4: + boxcontent[0] |= (BIT(7)); + memcpy(boxextcontent, cmdbuffer + buf_index, 2); + memcpy(boxcontent + 1, cmdbuffer + buf_index + 2, 2); + for (idx = 0; idx < 2; 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; + case 5: + boxcontent[0] |= (BIT(7)); + memcpy(boxextcontent, cmdbuffer + buf_index, 2); + memcpy(boxcontent + 1, cmdbuffer + buf_index + 2, 3); + for (idx = 0; idx < 2; 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(rtlpriv, COMP_ERR, DBG_EMERG, + "switch case not processed\n"); + break; + } + bwrite_sucess = true; + rtlhal->last_hmeboxnum = boxnum + 1; + if (rtlhal->last_hmeboxnum == 4) + rtlhal->last_hmeboxnum = 0; + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, + "pHalData->last_hmeboxnum = %d\n", + rtlhal->last_hmeboxnum); + } + spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag); + rtlhal->h2c_setinprogress = false; + spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag); + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "go out\n"); +} + +void rtl92d_fill_h2c_cmd(struct ieee80211_hw *hw, + u8 element_id, u32 cmd_len, u8 *cmdbuffer) +{ + u32 tmp_cmdbuf[2]; + + memset(tmp_cmdbuf, 0, 8); + memcpy(tmp_cmdbuf, cmdbuffer, cmd_len); + _rtl92d_fill_h2c_command(hw, element_id, cmd_len, (u8 *)&tmp_cmdbuf); + return; +} + +void rtl92d_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 u1_h2c_set_pwrmode[3] = { 0 }; + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, "FW LPS mode = %d\n", mode); + SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, mode); + SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode, 1); + SET_H2CCMD_PWRMODE_PARM_BCN_PASS_TIME(u1_h2c_set_pwrmode, + ppsc->reg_max_lps_awakeintvl); + RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG, + "rtl92d_set_fw_rsvdpagepkt(): u1_h2c_set_pwrmode", + u1_h2c_set_pwrmode, 3); + rtl92d_fill_h2c_cmd(hw, H2C_SETPWRMODE, 3, u1_h2c_set_pwrmode); +} + +static bool _rtl92d_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; + u8 idx = 0; + unsigned long flags; + struct sk_buff *pskb; + + 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); + pdesc = &ring->desc[idx]; + /* discard output from call below */ + rtlpriv->cfg->ops->get_desc((u8 *) pdesc, true, HW_DESC_OWN); + 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); + rtlpriv->cfg->ops->tx_polling(hw, BEACON_QUEUE); + 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, 0x76, 0x00, 0x42, + 0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x50, 0x08, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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 1 beacon */ + 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, + 0x10, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* page 2 ps-poll */ + 0xA4, 0x10, 0x01, 0xC0, 0x00, 0x40, 0x10, 0x10, + 0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42, + 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, + 0x18, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* page 3 null */ + 0x48, 0x01, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10, + 0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42, + 0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 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, + 0x72, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 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 rtl92d_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool 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[3] = { 0 }; + bool 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, + "rtl92d_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL", + &reserved_page_packet[0], totalpacketlen); + RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG, + "rtl92d_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL", + u1RsvdPageLoc, 3); + skb = dev_alloc_skb(totalpacketlen); + if (!skb) { + dlok = false; + } else { + memcpy((u8 *) skb_put(skb, totalpacketlen), + &reserved_page_packet, totalpacketlen); + rtstatus = _rtl92d_cmd_send_packet(hw, skb); + + if (rtstatus) + dlok = true; + } + if (dlok) { + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + "Set RSVD page location to Fw\n"); + RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG, + "H2C_RSVDPAGE", u1RsvdPageLoc, 3); + rtl92d_fill_h2c_cmd(hw, H2C_RSVDPAGE, + sizeof(u1RsvdPageLoc), u1RsvdPageLoc); + } else + RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, + "Set RSVD page location to Fw FAIL!!!!!!\n"); +} + +void rtl92d_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus) +{ + u8 u1_joinbssrpt_parm[1] = {0}; + + SET_H2CCMD_JOINBSSRPT_PARM_OPMODE(u1_joinbssrpt_parm, mstatus); + rtl92d_fill_h2c_cmd(hw, H2C_JOINBSSRPT, 1, u1_joinbssrpt_parm); +} diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/fw.h b/drivers/net/wireless/rtlwifi/rtl8192de/fw.h new file mode 100644 index 00000000..1ffacdda --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192de/fw.h @@ -0,0 +1,155 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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 __RTL92D__FW__H__ +#define __RTL92D__FW__H__ + +#define FW_8192D_START_ADDRESS 0x1000 +#define FW_8192D_PAGE_SIZE 4096 +#define FW_8192D_POLLING_TIMEOUT_COUNT 1000 + +#define IS_FW_HEADER_EXIST(_pfwhdr) \ + ((GET_FIRMWARE_HDR_SIGNATURE(_pfwhdr) & 0xFFF0) == 0x92C0 || \ + (GET_FIRMWARE_HDR_SIGNATURE(_pfwhdr) & 0xFFF0) == 0x88C0 || \ + (GET_FIRMWARE_HDR_SIGNATURE(_pfwhdr) & 0xFFFF) == 0x92D0 || \ + (GET_FIRMWARE_HDR_SIGNATURE(_pfwhdr) & 0xFFFF) == 0x92D1 || \ + (GET_FIRMWARE_HDR_SIGNATURE(_pfwhdr) & 0xFFFF) == 0x92D2 || \ + (GET_FIRMWARE_HDR_SIGNATURE(_pfwhdr) & 0xFFFF) == 0x92D3) + +/* Define a macro that takes an le32 word, converts it to host ordering, + * right shifts by a specified count, creates a mask of the specified + * bit count, and extracts that number of bits. + */ + +#define SHIFT_AND_MASK_LE(__pdesc, __shift, __mask) \ + ((le32_to_cpu(*(((__le32 *)(__pdesc)))) >> (__shift)) & \ + BIT_LEN_MASK_32(__mask)) + +/* Firmware Header(8-byte alinment required) */ +/* --- LONG WORD 0 ---- */ +#define GET_FIRMWARE_HDR_SIGNATURE(__fwhdr) \ + SHIFT_AND_MASK_LE(__fwhdr, 0, 16) +#define GET_FIRMWARE_HDR_CATEGORY(__fwhdr) \ + SHIFT_AND_MASK_LE(__fwhdr, 16, 8) +#define GET_FIRMWARE_HDR_FUNCTION(__fwhdr) \ + SHIFT_AND_MASK_LE(__fwhdr, 24, 8) +#define GET_FIRMWARE_HDR_VERSION(__fwhdr) \ + SHIFT_AND_MASK_LE(__fwhdr + 4, 0, 16) +#define GET_FIRMWARE_HDR_SUB_VER(__fwhdr) \ + SHIFT_AND_MASK_LE(__fwhdr + 4, 16, 8) +#define GET_FIRMWARE_HDR_RSVD1(__fwhdr) \ + SHIFT_AND_MASK_LE(__fwhdr + 4, 24, 8) + +/* --- LONG WORD 1 ---- */ +#define GET_FIRMWARE_HDR_MONTH(__fwhdr) \ + SHIFT_AND_MASK_LE(__fwhdr + 8, 0, 8) +#define GET_FIRMWARE_HDR_DATE(__fwhdr) \ + SHIFT_AND_MASK_LE(__fwhdr + 8, 8, 8) +#define GET_FIRMWARE_HDR_HOUR(__fwhdr) \ + SHIFT_AND_MASK_LE(__fwhdr + 8, 16, 8) +#define GET_FIRMWARE_HDR_MINUTE(__fwhdr) \ + SHIFT_AND_MASK_LE(__fwhdr + 8, 24, 8) +#define GET_FIRMWARE_HDR_ROMCODE_SIZE(__fwhdr) \ + SHIFT_AND_MASK_LE(__fwhdr + 12, 0, 16) +#define GET_FIRMWARE_HDR_RSVD2(__fwhdr) \ + SHIFT_AND_MASK_LE(__fwhdr + 12, 16, 16) + +/* --- LONG WORD 2 ---- */ +#define GET_FIRMWARE_HDR_SVN_IDX(__fwhdr) \ + SHIFT_AND_MASK_LE(__fwhdr + 16, 0, 32) +#define GET_FIRMWARE_HDR_RSVD3(__fwhdr) \ + SHIFT_AND_MASK_LE(__fwhdr + 20, 0, 32) + +/* --- LONG WORD 3 ---- */ +#define GET_FIRMWARE_HDR_RSVD4(__fwhdr) \ + SHIFT_AND_MASK_LE(__fwhdr + 24, 0, 32) +#define GET_FIRMWARE_HDR_RSVD5(__fwhdr) \ + SHIFT_AND_MASK_LE(__fwhdr + 28, 0, 32) + +#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_SMART_PS(__ph2ccmd, __val) \ + SET_BITS_TO_LE_1BYTE((__ph2ccmd) + 1, 0, 8, __val) +#define SET_H2CCMD_PWRMODE_PARM_BCN_PASS_TIME(__ph2ccmd, __val) \ + SET_BITS_TO_LE_1BYTE((__ph2ccmd) + 2, 0, 8, __val) +#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) + +struct rtl92d_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 rtl8192d_h2c_cmd { + H2C_AP_OFFLOAD = 0, + H2C_SETPWRMODE = 1, + H2C_JOINBSSRPT = 2, + H2C_RSVDPAGE = 3, + H2C_RSSI_REPORT = 5, + H2C_RA_MASK = 6, + H2C_MAC_MODE_SEL = 9, + H2C_PWRM = 15, + MAX_H2CCMD +}; + +int rtl92d_download_fw(struct ieee80211_hw *hw); +void rtl92d_fill_h2c_cmd(struct ieee80211_hw *hw, u8 element_id, + u32 cmd_len, u8 *p_cmdbuffer); +void rtl92d_firmware_selfreset(struct ieee80211_hw *hw); +void rtl92d_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode); +void rtl92d_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished); +void rtl92d_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus); + +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/hw.c b/drivers/net/wireless/rtlwifi/rtl8192de/hw.c new file mode 100644 index 00000000..509f5af3 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192de/hw.c @@ -0,0 +1,2320 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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> + * + *****************************************************************************/ + +#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 "sw.h" +#include "hw.h" + +u32 rtl92de_read_dword_dbi(struct ieee80211_hw *hw, u16 offset, u8 direct) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 value; + + rtl_write_word(rtlpriv, REG_DBI_CTRL, (offset & 0xFFC)); + rtl_write_byte(rtlpriv, REG_DBI_FLAG, BIT(1) | direct); + udelay(10); + value = rtl_read_dword(rtlpriv, REG_DBI_RDATA); + return value; +} + +void rtl92de_write_dword_dbi(struct ieee80211_hw *hw, + u16 offset, u32 value, u8 direct) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtl_write_word(rtlpriv, REG_DBI_CTRL, ((offset & 0xFFC) | 0xF000)); + rtl_write_dword(rtlpriv, REG_DBI_WDATA, value); + rtl_write_byte(rtlpriv, REG_DBI_FLAG, BIT(0) | direct); +} + +static void _rtl92de_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 _rtl92de_stop_tx_beacon(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 tmp1byte; + + tmp1byte = rtl_read_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2); + rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2, tmp1byte & (~BIT(6))); + rtl_write_byte(rtlpriv, REG_BCN_MAX_ERR, 0xff); + rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 1, 0x64); + tmp1byte = rtl_read_byte(rtlpriv, REG_TBTT_PROHIBIT + 2); + tmp1byte &= ~(BIT(0)); + rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 2, tmp1byte); +} + +static void _rtl92de_resume_tx_beacon(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 tmp1byte; + + tmp1byte = rtl_read_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2); + rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2, tmp1byte | BIT(6)); + rtl_write_byte(rtlpriv, REG_BCN_MAX_ERR, 0x0a); + rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 1, 0xff); + tmp1byte = rtl_read_byte(rtlpriv, REG_TBTT_PROHIBIT + 2); + tmp1byte |= BIT(0); + rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 2, tmp1byte); +} + +static void _rtl92de_enable_bcn_sub_func(struct ieee80211_hw *hw) +{ + _rtl92de_set_bcn_ctrl_reg(hw, 0, BIT(1)); +} + +static void _rtl92de_disable_bcn_sub_func(struct ieee80211_hw *hw) +{ + _rtl92de_set_bcn_ctrl_reg(hw, BIT(1), 0); +} + +void rtl92de_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->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; + } + case HW_VAR_INT_MIGRATION: + *((bool *)(val)) = rtlpriv->dm.interrupt_migration; + break; + case HW_VAR_INT_AC: + *((bool *)(val)) = rtlpriv->dm.disable_tx_int; + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "switch case not processed\n"); + break; + } +} + +void rtl92de_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_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_efuse *rtlefuse = 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 rate_cfg = ((u16 *) val)[0]; + u8 rate_index = 0; + + rate_cfg = rate_cfg & 0x15f; + if (mac->vendor == PEER_CISCO && + ((rate_cfg & 0x150) == 0)) + rate_cfg |= 0x01; + rtl_write_byte(rtlpriv, REG_RRSR, rate_cfg & 0xff); + rtl_write_byte(rtlpriv, REG_RRSR + 1, + (rate_cfg >> 8) & 0xff); + while (rate_cfg > 0x1) { + rate_cfg = (rate_cfg >> 1); + rate_index++; + } + if (rtlhal->fw_version > 0xe) + rtl_write_byte(rtlpriv, REG_INIRTS_RATE_SEL, + rate_index); + 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(rtlpriv, COMP_MLME, DBG_LOUD, + "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 = (mac->cur_40_prime_sc) << 5; + if (short_preamble) + reg_tmp |= 0x80; + rtl_write_byte(rtlpriv, REG_RRSR + 2, reg_tmp); + break; + } + case HW_VAR_AMPDU_MIN_SPACE: { + u8 min_spacing_to_set; + u8 sec_min_space; + + min_spacing_to_set = *((u8 *) val); + if (min_spacing_to_set <= 7) { + sec_min_space = 0; + if (min_spacing_to_set < sec_min_space) + min_spacing_to_set = sec_min_space; + mac->min_space_cfg = ((mac->min_space_cfg & 0xf8) | + min_spacing_to_set); + *val = min_spacing_to_set; + RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD, + "Set HW_VAR_AMPDU_MIN_SPACE: %#x\n", + mac->min_space_cfg); + rtl_write_byte(rtlpriv, REG_AMPDU_MIN_SPACE, + mac->min_space_cfg); + } + break; + } + case HW_VAR_SHORTGI_DENSITY: { + u8 density_to_set; + + density_to_set = *((u8 *) val); + mac->min_space_cfg = rtlpriv->rtlhal.minspace_cfg; + mac->min_space_cfg |= (density_to_set << 3); + RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD, + "Set HW_VAR_SHORTGI_DENSITY: %#x\n", + mac->min_space_cfg); + rtl_write_byte(rtlpriv, REG_AMPDU_MIN_SPACE, + mac->min_space_cfg); + break; + } + case HW_VAR_AMPDU_FACTOR: { + u8 factor_toset; + u32 regtoSet; + u8 *ptmp_byte = NULL; + u8 index; + + if (rtlhal->macphymode == DUALMAC_DUALPHY) + regtoSet = 0xb9726641; + else if (rtlhal->macphymode == DUALMAC_SINGLEPHY) + regtoSet = 0x66626641; + else + regtoSet = 0xb972a841; + factor_toset = *((u8 *) val); + if (factor_toset <= 3) { + factor_toset = (1 << (factor_toset + 2)); + if (factor_toset > 0xf) + factor_toset = 0xf; + for (index = 0; index < 4; index++) { + ptmp_byte = (u8 *) (®toSet) + index; + if ((*ptmp_byte & 0xf0) > + (factor_toset << 4)) + *ptmp_byte = (*ptmp_byte & 0x0f) + | (factor_toset << 4); + if ((*ptmp_byte & 0x0f) > factor_toset) + *ptmp_byte = (*ptmp_byte & 0xf0) + | (factor_toset); + } + rtl_write_dword(rtlpriv, REG_AGGLEN_LMT, regtoSet); + RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD, + "Set HW_VAR_AMPDU_FACTOR: %#x\n", + factor_toset); + } + break; + } + case HW_VAR_AC_PARAM: { + u8 e_aci = *((u8 *) val); + rtl92d_dm_init_edca_turbo(hw); + 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 *p_aci_aifsn = + (union aci_aifsn *)(&(mac->ac[0].aifs)); + u8 acm = p_aci_aifsn->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(rtlpriv, 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_VOQEN); + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "switch case not processed\n"); + break; + } + } + RT_TRACE(rtlpriv, 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_RL, + 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: + rtlefuse->efuse_usedbytes = *((u16 *) val); + break; + case HW_VAR_EFUSE_USAGE: + rtlefuse->efuse_usedpercentage = *((u8 *) val); + break; + case HW_VAR_IO_CMD: + rtl92d_phy_set_io_cmd(hw, (*(enum io_type *)val)); + break; + case HW_VAR_WPA_CONFIG: + rtl_write_byte(rtlpriv, REG_SECCFG, *((u8 *) val)); + break; + case HW_VAR_SET_RPWM: + rtl92d_fill_h2c_cmd(hw, H2C_PWRM, 1, (u8 *) (val)); + break; + case HW_VAR_H2C_FW_PWRMODE: + break; + case HW_VAR_FW_PSMODE_STATUS: + ppsc->fw_current_inpsmode = *((bool *) val); + break; + case HW_VAR_H2C_FW_JOINBSSRPT: { + u8 mstatus = (*(u8 *) val); + u8 tmp_regcr, tmp_reg422; + bool recover = false; + + if (mstatus == RT_MEDIA_CONNECT) { + rtlpriv->cfg->ops->set_hw_reg(hw, + HW_VAR_AID, NULL); + tmp_regcr = rtl_read_byte(rtlpriv, REG_CR + 1); + rtl_write_byte(rtlpriv, REG_CR + 1, + (tmp_regcr | BIT(0))); + _rtl92de_set_bcn_ctrl_reg(hw, 0, BIT(3)); + _rtl92de_set_bcn_ctrl_reg(hw, BIT(4), 0); + tmp_reg422 = rtl_read_byte(rtlpriv, + REG_FWHW_TXQ_CTRL + 2); + if (tmp_reg422 & BIT(6)) + recover = true; + rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2, + tmp_reg422 & (~BIT(6))); + rtl92d_set_fw_rsvdpagepkt(hw, 0); + _rtl92de_set_bcn_ctrl_reg(hw, BIT(3), 0); + _rtl92de_set_bcn_ctrl_reg(hw, 0, BIT(4)); + if (recover) + rtl_write_byte(rtlpriv, + REG_FWHW_TXQ_CTRL + 2, + tmp_reg422); + rtl_write_byte(rtlpriv, REG_CR + 1, + (tmp_regcr & ~(BIT(0)))); + } + rtl92d_set_fw_joinbss_report_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) + _rtl92de_stop_tx_beacon(hw); + _rtl92de_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)); + _rtl92de_set_bcn_ctrl_reg(hw, BIT(3), 0); + if (btype_ibss) + _rtl92de_resume_tx_beacon(hw); + + break; + } + case HW_VAR_INT_MIGRATION: { + bool int_migration = *(bool *) (val); + + if (int_migration) { + /* Set interrupt migration timer and + * corresponding Tx/Rx counter. + * timer 25ns*0xfa0=100us for 0xf packets. + * 0x306:Rx, 0x307:Tx */ + rtl_write_dword(rtlpriv, REG_INT_MIG, 0xfe000fa0); + rtlpriv->dm.interrupt_migration = int_migration; + } else { + /* Reset all interrupt migration settings. */ + rtl_write_dword(rtlpriv, REG_INT_MIG, 0); + rtlpriv->dm.interrupt_migration = int_migration; + } + break; + } + case HW_VAR_INT_AC: { + bool disable_ac_int = *((bool *) val); + + /* Disable four ACs interrupts. */ + if (disable_ac_int) { + /* Disable VO, VI, BE and BK four AC interrupts + * to gain more efficient CPU utilization. + * When extremely highly Rx OK occurs, + * we will disable Tx interrupts. + */ + rtlpriv->cfg->ops->update_interrupt_mask(hw, 0, + RT_AC_INT_MASKS); + rtlpriv->dm.disable_tx_int = disable_ac_int; + /* Enable four ACs interrupts. */ + } else { + rtlpriv->cfg->ops->update_interrupt_mask(hw, + RT_AC_INT_MASKS, 0); + rtlpriv->dm.disable_tx_int = disable_ac_int; + } + break; + } + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "switch case not processed\n"); + break; + } +} + +static bool _rtl92de_llt_write(struct ieee80211_hw *hw, u32 address, u32 data) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + bool status = true; + long count = 0; + u32 value = _LLT_INIT_ADDR(address) | + _LLT_INIT_DATA(data) | _LLT_OP(_LLT_WRITE_ACCESS); + + rtl_write_dword(rtlpriv, REG_LLT_INIT, value); + do { + value = rtl_read_dword(rtlpriv, REG_LLT_INIT); + if (_LLT_NO_ACTIVE == _LLT_OP_VALUE(value)) + break; + if (count > POLLING_LLT_THRESHOLD) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "Failed to polling write LLT done at address %d!\n", + address); + status = false; + break; + } + } while (++count); + return status; +} + +static bool _rtl92de_llt_table_init(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + unsigned short i; + u8 txpktbuf_bndy; + u8 maxPage; + bool status; + u32 value32; /* High+low page number */ + u8 value8; /* normal page number */ + + if (rtlpriv->rtlhal.macphymode == SINGLEMAC_SINGLEPHY) { + maxPage = 255; + txpktbuf_bndy = 246; + value8 = 0; + value32 = 0x80bf0d29; + } else if (rtlpriv->rtlhal.macphymode != SINGLEMAC_SINGLEPHY) { + maxPage = 127; + txpktbuf_bndy = 123; + value8 = 0; + value32 = 0x80750005; + } + + /* Set reserved page for each queue */ + /* 11. RQPN 0x200[31:0] = 0x80BD1C1C */ + /* load RQPN */ + rtl_write_byte(rtlpriv, REG_RQPN_NPQ, value8); + rtl_write_dword(rtlpriv, REG_RQPN, value32); + + /* 12. TXRKTBUG_PG_BNDY 0x114[31:0] = 0x27FF00F6 */ + /* TXRKTBUG_PG_BNDY */ + rtl_write_dword(rtlpriv, REG_TRXFF_BNDY, + (rtl_read_word(rtlpriv, REG_TRXFF_BNDY + 2) << 16 | + txpktbuf_bndy)); + + /* 13. TDECTRL[15:8] 0x209[7:0] = 0xF6 */ + /* Beacon Head for TXDMA */ + rtl_write_byte(rtlpriv, REG_TDECTRL + 1, txpktbuf_bndy); + + /* 14. BCNQ_PGBNDY 0x424[7:0] = 0xF6 */ + /* BCNQ_PGBNDY */ + rtl_write_byte(rtlpriv, REG_TXPKTBUF_BCNQ_BDNY, txpktbuf_bndy); + rtl_write_byte(rtlpriv, REG_TXPKTBUF_MGQ_BDNY, txpktbuf_bndy); + + /* 15. WMAC_LBK_BF_HD 0x45D[7:0] = 0xF6 */ + /* WMAC_LBK_BF_HD */ + rtl_write_byte(rtlpriv, 0x45D, txpktbuf_bndy); + + /* Set Tx/Rx page size (Tx must be 128 Bytes, */ + /* Rx can be 64,128,256,512,1024 bytes) */ + /* 16. PBP [7:0] = 0x11 */ + /* TRX page size */ + rtl_write_byte(rtlpriv, REG_PBP, 0x11); + + /* 17. DRV_INFO_SZ = 0x04 */ + rtl_write_byte(rtlpriv, REG_RX_DRVINFO_SZ, 0x4); + + /* 18. LLT_table_init(Adapter); */ + for (i = 0; i < (txpktbuf_bndy - 1); i++) { + status = _rtl92de_llt_write(hw, i, i + 1); + if (true != status) + return status; + } + + /* end of list */ + status = _rtl92de_llt_write(hw, (txpktbuf_bndy - 1), 0xFF); + if (true != status) + return status; + + /* Make the other pages as ring buffer */ + /* This ring buffer is used as beacon buffer if we */ + /* config this MAC as two MAC transfer. */ + /* Otherwise used as local loopback buffer. */ + for (i = txpktbuf_bndy; i < maxPage; i++) { + status = _rtl92de_llt_write(hw, i, (i + 1)); + if (true != status) + return status; + } + + /* Let last entry point to the start entry of ring buffer */ + status = _rtl92de_llt_write(hw, maxPage, txpktbuf_bndy); + if (true != status) + return status; + + return true; +} + +static void _rtl92de_gen_refresh_led_state(struct ieee80211_hw *hw) +{ + struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + struct rtl_led *pLed0 = &(pcipriv->ledctl.sw_led0); + + if (rtlpci->up_first_time) + return; + if (ppsc->rfoff_reason == RF_CHANGE_BY_IPS) + rtl92de_sw_led_on(hw, pLed0); + else if (ppsc->rfoff_reason == RF_CHANGE_BY_INIT) + rtl92de_sw_led_on(hw, pLed0); + else + rtl92de_sw_led_off(hw, pLed0); +} + +static bool _rtl92de_init_mac(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + unsigned char bytetmp; + unsigned short wordtmp; + u16 retry; + + rtl92d_phy_set_poweron(hw); + /* Add for resume sequence of power domain according + * to power document V11. Chapter V.11.... */ + /* 0. RSV_CTRL 0x1C[7:0] = 0x00 */ + /* unlock ISO/CLK/Power control register */ + rtl_write_byte(rtlpriv, REG_RSV_CTRL, 0x00); + rtl_write_byte(rtlpriv, REG_LDOA15_CTRL, 0x05); + + /* 1. AFE_XTAL_CTRL [7:0] = 0x0F enable XTAL */ + /* 2. SPS0_CTRL 0x11[7:0] = 0x2b enable SPS into PWM mode */ + /* 3. delay (1ms) this is not necessary when initially power on */ + + /* C. Resume Sequence */ + /* a. SPS0_CTRL 0x11[7:0] = 0x2b */ + rtl_write_byte(rtlpriv, REG_SPS0_CTRL, 0x2b); + + /* b. AFE_XTAL_CTRL [7:0] = 0x0F */ + rtl_write_byte(rtlpriv, REG_AFE_XTAL_CTRL, 0x0F); + + /* c. DRV runs power on init flow */ + + /* auto enable WLAN */ + /* 4. APS_FSMCO 0x04[8] = 1; wait till 0x04[8] = 0 */ + /* Power On Reset for MAC Block */ + bytetmp = rtl_read_byte(rtlpriv, REG_APS_FSMCO + 1) | BIT(0); + udelay(2); + rtl_write_byte(rtlpriv, REG_APS_FSMCO + 1, bytetmp); + udelay(2); + + /* 5. Wait while 0x04[8] == 0 goto 2, otherwise goto 1 */ + bytetmp = rtl_read_byte(rtlpriv, REG_APS_FSMCO + 1); + udelay(50); + retry = 0; + while ((bytetmp & BIT(0)) && retry < 1000) { + retry++; + bytetmp = rtl_read_byte(rtlpriv, REG_APS_FSMCO + 1); + udelay(50); + } + + /* Enable Radio off, GPIO, and LED function */ + /* 6. APS_FSMCO 0x04[15:0] = 0x0012 when enable HWPDN */ + rtl_write_word(rtlpriv, REG_APS_FSMCO, 0x1012); + + /* release RF digital isolation */ + /* 7. SYS_ISO_CTRL 0x01[1] = 0x0; */ + /*Set REG_SYS_ISO_CTRL 0x1=0x82 to prevent wake# problem. */ + rtl_write_byte(rtlpriv, REG_SYS_ISO_CTRL + 1, 0x82); + udelay(2); + + /* make sure that BB reset OK. */ + /* rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE3); */ + + /* Disable REG_CR before enable it to assure reset */ + rtl_write_word(rtlpriv, REG_CR, 0x0); + + /* Release MAC IO register reset */ + rtl_write_word(rtlpriv, REG_CR, 0x2ff); + + /* clear stopping tx/rx dma */ + rtl_write_byte(rtlpriv, REG_PCIE_CTRL_REG + 1, 0x0); + + /* rtl_write_word(rtlpriv,REG_CR+2, 0x2); */ + + /* System init */ + /* 18. LLT_table_init(Adapter); */ + if (!_rtl92de_llt_table_init(hw)) + return false; + + /* Clear interrupt and enable interrupt */ + /* 19. HISR 0x124[31:0] = 0xffffffff; */ + /* HISRE 0x12C[7:0] = 0xFF */ + rtl_write_dword(rtlpriv, REG_HISR, 0xffffffff); + rtl_write_byte(rtlpriv, REG_HISRE, 0xff); + + /* 20. HIMR 0x120[31:0] |= [enable INT mask bit map]; */ + /* 21. HIMRE 0x128[7:0] = [enable INT mask bit map] */ + /* The IMR should be enabled later after all init sequence + * is finished. */ + + /* 22. PCIE configuration space configuration */ + /* 23. Ensure PCIe Device 0x80[15:0] = 0x0143 (ASPM+CLKREQ), */ + /* and PCIe gated clock function is enabled. */ + /* PCIE configuration space will be written after + * all init sequence.(Or by BIOS) */ + + rtl92d_phy_config_maccoexist_rfpage(hw); + + /* THe below section is not related to power document Vxx . */ + /* This is only useful for driver and OS setting. */ + /* -------------------Software Relative Setting---------------------- */ + wordtmp = rtl_read_word(rtlpriv, REG_TRXDMA_CTRL); + wordtmp &= 0xf; + wordtmp |= 0xF771; + rtl_write_word(rtlpriv, REG_TRXDMA_CTRL, wordtmp); + + /* Reported Tx status from HW for rate adaptive. */ + /* This should be realtive to power on step 14. But in document V11 */ + /* still not contain the description.!!! */ + rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 1, 0x1F); + + /* Set Tx/Rx page size (Tx must be 128 Bytes, + * Rx can be 64,128,256,512,1024 bytes) */ + /* rtl_write_byte(rtlpriv,REG_PBP, 0x11); */ + + /* Set RCR register */ + rtl_write_dword(rtlpriv, REG_RCR, rtlpci->receive_config); + /* rtl_write_byte(rtlpriv,REG_RX_DRVINFO_SZ, 4); */ + + /* Set TCR register */ + rtl_write_dword(rtlpriv, REG_TCR, rtlpci->transmit_config); + + /* disable earlymode */ + rtl_write_byte(rtlpriv, 0x4d0, 0x0); + + /* Set TX/RX descriptor physical address(from OS API). */ + rtl_write_dword(rtlpriv, REG_BCNQ_DESA, + rtlpci->tx_ring[BEACON_QUEUE].dma); + rtl_write_dword(rtlpriv, REG_MGQ_DESA, rtlpci->tx_ring[MGNT_QUEUE].dma); + rtl_write_dword(rtlpriv, REG_VOQ_DESA, rtlpci->tx_ring[VO_QUEUE].dma); + rtl_write_dword(rtlpriv, REG_VIQ_DESA, rtlpci->tx_ring[VI_QUEUE].dma); + rtl_write_dword(rtlpriv, REG_BEQ_DESA, rtlpci->tx_ring[BE_QUEUE].dma); + rtl_write_dword(rtlpriv, REG_BKQ_DESA, rtlpci->tx_ring[BK_QUEUE].dma); + rtl_write_dword(rtlpriv, REG_HQ_DESA, rtlpci->tx_ring[HIGH_QUEUE].dma); + /* Set RX Desc Address */ + rtl_write_dword(rtlpriv, REG_RX_DESA, + rtlpci->rx_ring[RX_MPDU_QUEUE].dma); + + /* if we want to support 64 bit DMA, we should set it here, + * but now we do not support 64 bit DMA*/ + + rtl_write_byte(rtlpriv, REG_PCIE_CTRL_REG + 3, 0x33); + + /* Reset interrupt migration setting when initialization */ + rtl_write_dword(rtlpriv, REG_INT_MIG, 0); + + /* Reconsider when to do this operation after asking HWSD. */ + bytetmp = rtl_read_byte(rtlpriv, REG_APSD_CTRL); + rtl_write_byte(rtlpriv, REG_APSD_CTRL, bytetmp & ~BIT(6)); + do { + retry++; + bytetmp = rtl_read_byte(rtlpriv, REG_APSD_CTRL); + } while ((retry < 200) && !(bytetmp & BIT(7))); + + /* After MACIO reset,we must refresh LED state. */ + _rtl92de_gen_refresh_led_state(hw); + + /* Reset H2C protection register */ + rtl_write_dword(rtlpriv, REG_MCUTST_1, 0x0); + + return true; +} + +static void _rtl92de_hw_configure(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(rtl_priv(hw)); + u8 reg_bw_opmode = BW_OPMODE_20MHZ; + u32 reg_rrsr; + + reg_rrsr = RATE_ALL_CCK | RATE_ALL_OFDM_AG; + rtl_write_byte(rtlpriv, REG_INIRTS_RATE_SEL, 0x8); + rtl_write_byte(rtlpriv, REG_BWOPMODE, reg_bw_opmode); + rtl_write_dword(rtlpriv, REG_RRSR, reg_rrsr); + rtl_write_byte(rtlpriv, REG_SLOT, 0x09); + rtl_write_byte(rtlpriv, REG_AMPDU_MIN_SPACE, 0x0); + rtl_write_word(rtlpriv, REG_FWHW_TXQ_CTRL, 0x1F80); + rtl_write_word(rtlpriv, REG_RL, 0x0707); + rtl_write_dword(rtlpriv, REG_BAR_MODE_CTRL, 0x02012802); + rtl_write_byte(rtlpriv, REG_HWSEQ_CTRL, 0xFF); + 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); + /* Aggregation threshold */ + if (rtlhal->macphymode == DUALMAC_DUALPHY) + rtl_write_dword(rtlpriv, REG_AGGLEN_LMT, 0xb9726641); + else if (rtlhal->macphymode == DUALMAC_SINGLEPHY) + rtl_write_dword(rtlpriv, REG_AGGLEN_LMT, 0x66626641); + else + rtl_write_dword(rtlpriv, REG_AGGLEN_LMT, 0xb972a841); + rtl_write_byte(rtlpriv, REG_ATIMWND, 0x2); + rtl_write_byte(rtlpriv, REG_BCN_MAX_ERR, 0x0a); + rtlpci->reg_bcn_ctrl_val = 0x1f; + rtl_write_byte(rtlpriv, REG_BCN_CTRL, rtlpci->reg_bcn_ctrl_val); + rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 1, 0xff); + rtl_write_byte(rtlpriv, REG_PIFS, 0x1C); + rtl_write_byte(rtlpriv, REG_AGGR_BREAK_TIME, 0x16); + rtl_write_word(rtlpriv, REG_NAV_PROT_LEN, 0x0020); + /* For throughput */ + rtl_write_word(rtlpriv, REG_FAST_EDCA_CTRL, 0x6666); + /* ACKTO for IOT issue. */ + rtl_write_byte(rtlpriv, REG_ACKTO, 0x40); + /* Set Spec SIFS (used in NAV) */ + rtl_write_word(rtlpriv, REG_SPEC_SIFS, 0x1010); + rtl_write_word(rtlpriv, REG_MAC_SPEC_SIFS, 0x1010); + /* Set SIFS for CCK */ + rtl_write_word(rtlpriv, REG_SIFS_CTX, 0x1010); + /* Set SIFS for OFDM */ + rtl_write_word(rtlpriv, REG_SIFS_TRX, 0x1010); + /* Set Multicast Address. */ + rtl_write_dword(rtlpriv, REG_MAR, 0xffffffff); + rtl_write_dword(rtlpriv, REG_MAR + 4, 0xffffffff); + switch (rtlpriv->phy.rf_type) { + case RF_1T2R: + case RF_1T1R: + rtlhal->minspace_cfg = (MAX_MSS_DENSITY_1T << 3); + break; + case RF_2T2R: + case RF_2T2R_GREEN: + rtlhal->minspace_cfg = (MAX_MSS_DENSITY_2T << 3); + break; + } +} + +static void _rtl92de_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)); + + rtl_write_byte(rtlpriv, 0x34b, 0x93); + rtl_write_word(rtlpriv, 0x350, 0x870c); + rtl_write_byte(rtlpriv, 0x352, 0x1); + if (ppsc->support_backdoor) + rtl_write_byte(rtlpriv, 0x349, 0x1b); + else + rtl_write_byte(rtlpriv, 0x349, 0x03); + rtl_write_word(rtlpriv, 0x350, 0x2718); + rtl_write_byte(rtlpriv, 0x352, 0x1); +} + +void rtl92de_enable_hw_security_config(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 sec_reg_value; + + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "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(rtlpriv, COMP_SEC, DBG_DMESG, + "not open hw encryption\n"); + return; + } + sec_reg_value = SCR_TXENCENABLE | SCR_RXENCENABLE; + if (rtlpriv->sec.use_defaultkey) { + sec_reg_value |= SCR_TXUSEDK; + sec_reg_value |= SCR_RXUSEDK; + } + sec_reg_value |= (SCR_RXBCUSEDK | SCR_TXBCUSEDK); + rtl_write_byte(rtlpriv, REG_CR + 1, 0x02); + RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, + "The SECR-value %x\n", sec_reg_value); + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_WPA_CONFIG, &sec_reg_value); +} + +int rtl92de_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_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + bool rtstatus = true; + u8 tmp_u1b; + int i; + int err; + unsigned long flags; + + rtlpci->being_init_adapter = true; + rtlpci->init_ready = false; + spin_lock_irqsave(&globalmutex_for_power_and_efuse, flags); + /* we should do iqk after disable/enable */ + rtl92d_phy_reset_iqk_result(hw); + /* rtlpriv->intf_ops->disable_aspm(hw); */ + rtstatus = _rtl92de_init_mac(hw); + if (!rtstatus) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Init MAC failed\n"); + err = 1; + spin_unlock_irqrestore(&globalmutex_for_power_and_efuse, flags); + return err; + } + err = rtl92d_download_fw(hw); + spin_unlock_irqrestore(&globalmutex_for_power_and_efuse, flags); + if (err) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, + "Failed to download FW. Init HW without FW..\n"); + return 1; + } + rtlhal->last_hmeboxnum = 0; + rtlpriv->psc.fw_current_inpsmode = false; + + tmp_u1b = rtl_read_byte(rtlpriv, 0x605); + tmp_u1b = tmp_u1b | 0x30; + rtl_write_byte(rtlpriv, 0x605, tmp_u1b); + + if (rtlhal->earlymode_enable) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "EarlyMode Enabled!!!\n"); + + tmp_u1b = rtl_read_byte(rtlpriv, 0x4d0); + tmp_u1b = tmp_u1b | 0x1f; + rtl_write_byte(rtlpriv, 0x4d0, tmp_u1b); + + rtl_write_byte(rtlpriv, 0x4d3, 0x80); + + tmp_u1b = rtl_read_byte(rtlpriv, 0x605); + tmp_u1b = tmp_u1b | 0x40; + rtl_write_byte(rtlpriv, 0x605, tmp_u1b); + } + + if (mac->rdg_en) { + rtl_write_byte(rtlpriv, REG_RD_CTRL, 0xff); + rtl_write_word(rtlpriv, REG_RD_NAV_NXT, 0x200); + rtl_write_byte(rtlpriv, REG_RD_RESP_PKT_TH, 0x05); + } + + rtl92d_phy_mac_config(hw); + /* because last function modify RCR, so we update + * rcr var here, or TP will unstable for receive_config + * is wrong, RX RCR_ACRC32 will cause TP unstabel & Rx + * RCR_APP_ICV will cause mac80211 unassoc for cisco 1252*/ + rtlpci->receive_config = rtl_read_dword(rtlpriv, REG_RCR); + rtlpci->receive_config &= ~(RCR_ACRC32 | RCR_AICV); + + rtl92d_phy_bb_config(hw); + + rtlphy->rf_mode = RF_OP_BY_SW_3WIRE; + /* set before initialize RF */ + rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER4, 0x00f00000, 0xf); + + /* config RF */ + rtl92d_phy_rf_config(hw); + + /* After read predefined TXT, we must set BB/MAC/RF + * register as our requirement */ + /* After load BB,RF params,we need do more for 92D. */ + rtl92d_update_bbrf_configuration(hw); + /* set default value after initialize RF, */ + rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER4, 0x00f00000, 0); + rtlphy->rfreg_chnlval[0] = rtl_get_rfreg(hw, (enum radio_path)0, + RF_CHNLBW, BRFREGOFFSETMASK); + rtlphy->rfreg_chnlval[1] = rtl_get_rfreg(hw, (enum radio_path)1, + RF_CHNLBW, BRFREGOFFSETMASK); + + /*---- Set CCK and OFDM Block "ON"----*/ + if (rtlhal->current_bandtype == BAND_ON_2_4G) + rtl_set_bbreg(hw, RFPGA0_RFMOD, BCCKEN, 0x1); + rtl_set_bbreg(hw, RFPGA0_RFMOD, BOFDMEN, 0x1); + if (rtlhal->interfaceindex == 0) { + /* RFPGA0_ANALOGPARAMETER2: cck clock select, + * set to 20MHz by default */ + rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER2, BIT(10) | + BIT(11), 3); + } else { + /* Mac1 */ + rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER2, BIT(11) | + BIT(10), 3); + } + + _rtl92de_hw_configure(hw); + + /* reset hw sec */ + rtl_cam_reset_all_entry(hw); + rtl92de_enable_hw_security_config(hw); + + /* Read EEPROM TX power index and PHY_REG_PG.txt to capture correct */ + /* TX power index for different rate set. */ + rtl92d_phy_get_hw_reg_originalvalue(hw); + rtl92d_phy_set_txpower_level(hw, rtlphy->current_channel); + + ppsc->rfpwr_state = ERFON; + + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_ETHER_ADDR, mac->mac_addr); + + _rtl92de_enable_aspm_back_door(hw); + /* rtlpriv->intf_ops->enable_aspm(hw); */ + + rtl92d_dm_init(hw); + rtlpci->being_init_adapter = false; + + if (ppsc->rfpwr_state == ERFON) { + rtl92d_phy_lc_calibrate(hw); + /* 5G and 2.4G must wait sometime to let RF LO ready */ + if (rtlhal->macphymode == DUALMAC_DUALPHY) { + u32 tmp_rega; + for (i = 0; i < 10000; i++) { + udelay(MAX_STALL_TIME); + + tmp_rega = rtl_get_rfreg(hw, + (enum radio_path)RF90_PATH_A, + 0x2a, BMASKDWORD); + + if (((tmp_rega & BIT(11)) == BIT(11))) + break; + } + /* check that loop was successful. If not, exit now */ + if (i == 10000) { + rtlpci->init_ready = false; + return 1; + } + } + } + rtlpci->init_ready = true; + return err; +} + +static enum version_8192d _rtl92de_read_chip_version(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + enum version_8192d version = VERSION_NORMAL_CHIP_92D_SINGLEPHY; + u32 value32; + + value32 = rtl_read_dword(rtlpriv, REG_SYS_CFG); + if (!(value32 & 0x000f0000)) { + version = VERSION_TEST_CHIP_92D_SINGLEPHY; + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "TEST CHIP!!!\n"); + } else { + version = VERSION_NORMAL_CHIP_92D_SINGLEPHY; + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "Normal CHIP!!!\n"); + } + return version; +} + +static int _rtl92de_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 bcnfunc_enable; + + bt_msr &= 0xfc; + + if (type == NL80211_IFTYPE_UNSPECIFIED || + type == NL80211_IFTYPE_STATION) { + _rtl92de_stop_tx_beacon(hw); + _rtl92de_enable_bcn_sub_func(hw); + } else if (type == NL80211_IFTYPE_ADHOC || + type == NL80211_IFTYPE_AP) { + _rtl92de_resume_tx_beacon(hw); + _rtl92de_disable_bcn_sub_func(hw); + } else { + RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, + "Set HW_VAR_MEDIA_STATUS: No such media status(%x)\n", + type); + } + bcnfunc_enable = rtl_read_byte(rtlpriv, REG_BCN_CTRL); + switch (type) { + case NL80211_IFTYPE_UNSPECIFIED: + bt_msr |= MSR_NOLINK; + ledaction = LED_CTL_LINK; + bcnfunc_enable &= 0xF7; + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + "Set Network type to NO LINK!\n"); + break; + case NL80211_IFTYPE_ADHOC: + bt_msr |= MSR_ADHOC; + bcnfunc_enable |= 0x08; + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + "Set Network type to Ad Hoc!\n"); + break; + case NL80211_IFTYPE_STATION: + bt_msr |= MSR_INFRA; + ledaction = LED_CTL_LINK; + bcnfunc_enable &= 0xF7; + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + "Set Network type to STA!\n"); + break; + case NL80211_IFTYPE_AP: + bt_msr |= MSR_AP; + bcnfunc_enable |= 0x08; + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + "Set Network type to AP!\n"); + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "Network type %d not supported!\n", type); + return 1; + break; + + } + rtl_write_byte(rtlpriv, REG_CR + 2, bt_msr); + rtlpriv->cfg->ops->led_control(hw, ledaction); + if ((bt_msr & 0xfc) == MSR_AP) + rtl_write_byte(rtlpriv, REG_BCNTCFG + 1, 0x00); + else + rtl_write_byte(rtlpriv, REG_BCNTCFG + 1, 0x66); + return 0; +} + +void rtl92de_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) { + reg_rcr |= (RCR_CBSSID_DATA | RCR_CBSSID_BCN); + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR, (u8 *)(®_rcr)); + _rtl92de_set_bcn_ctrl_reg(hw, 0, BIT(4)); + } else if (!check_bssid) { + reg_rcr &= (~(RCR_CBSSID_DATA | RCR_CBSSID_BCN)); + _rtl92de_set_bcn_ctrl_reg(hw, BIT(4), 0); + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR, (u8 *)(®_rcr)); + } +} + +int rtl92de_set_network_type(struct ieee80211_hw *hw, enum nl80211_iftype type) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + if (_rtl92de_set_media_status(hw, type)) + return -EOPNOTSUPP; + + /* check bssid */ + if (rtlpriv->mac80211.link_state == MAC80211_LINKED) { + if (type != NL80211_IFTYPE_AP) + rtl92de_set_check_bssid(hw, true); + } else { + rtl92de_set_check_bssid(hw, false); + } + return 0; +} + +/* do iqk or reload iqk */ +/* windows just rtl92d_phy_reload_iqk_setting in set channel, + * but it's very strict for time sequence so we add + * rtl92d_phy_reload_iqk_setting here */ +void rtl92d_linked_set_reg(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + u8 indexforchannel; + u8 channel = rtlphy->current_channel; + + indexforchannel = rtl92d_get_rightchnlplace_for_iqk(channel); + if (!rtlphy->iqk_matrix_regsetting[indexforchannel].iqk_done) { + RT_TRACE(rtlpriv, COMP_SCAN | COMP_INIT, DBG_DMESG, + "Do IQK for channel:%d\n", channel); + rtl92d_phy_iq_calibrate(hw); + } +} + +/* don't set REG_EDCA_BE_PARAM here because + * mac80211 will send pkt when scan */ +void rtl92de_set_qos(struct ieee80211_hw *hw, int aci) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + rtl92d_dm_init_edca_turbo(hw); + return; + switch (aci) { + case AC1_BK: + rtl_write_dword(rtlpriv, REG_EDCA_BK_PARAM, 0xa44f); + break; + case AC0_BE: + 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; + } +} + +void rtl92de_enable_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, rtlpci->irq_mask[0] & 0xFFFFFFFF); + rtl_write_dword(rtlpriv, REG_HIMRE, rtlpci->irq_mask[1] & 0xFFFFFFFF); +} + +void rtl92de_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, IMR8190_DISABLED); + rtl_write_dword(rtlpriv, REG_HIMRE, IMR8190_DISABLED); + synchronize_irq(rtlpci->pdev->irq); +} + +static void _rtl92de_poweroff_adapter(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 u1b_tmp; + unsigned long flags; + + rtlpriv->intf_ops->enable_aspm(hw); + rtl_write_byte(rtlpriv, REG_RF_CTRL, 0x00); + rtl_set_bbreg(hw, RFPGA0_XCD_RFPARAMETER, BIT(3), 0); + rtl_set_bbreg(hw, RFPGA0_XCD_RFPARAMETER, BIT(15), 0); + + /* 0x20:value 05-->04 */ + rtl_write_byte(rtlpriv, REG_LDOA15_CTRL, 0x04); + + /* ==== Reset digital sequence ====== */ + rtl92d_firmware_selfreset(hw); + + /* f. SYS_FUNC_EN 0x03[7:0]=0x51 reset MCU, MAC register, DCORE */ + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, 0x51); + + /* g. MCUFWDL 0x80[1:0]=0 reset MCU ready status */ + rtl_write_byte(rtlpriv, REG_MCUFWDL, 0x00); + + /* ==== Pull GPIO PIN to balance level and LED control ====== */ + + /* h. GPIO_PIN_CTRL 0x44[31:0]=0x000 */ + rtl_write_dword(rtlpriv, REG_GPIO_PIN_CTRL, 0x00000000); + + /* i. Value = GPIO_PIN_CTRL[7:0] */ + u1b_tmp = rtl_read_byte(rtlpriv, REG_GPIO_PIN_CTRL); + + /* j. GPIO_PIN_CTRL 0x44[31:0] = 0x00FF0000 | (value <<8); */ + /* write external PIN level */ + rtl_write_dword(rtlpriv, REG_GPIO_PIN_CTRL, + 0x00FF0000 | (u1b_tmp << 8)); + + /* k. GPIO_MUXCFG 0x42 [15:0] = 0x0780 */ + rtl_write_word(rtlpriv, REG_GPIO_IO_SEL, 0x0790); + + /* l. LEDCFG 0x4C[15:0] = 0x8080 */ + rtl_write_word(rtlpriv, REG_LEDCFG0, 0x8080); + + /* ==== Disable analog sequence === */ + + /* m. AFE_PLL_CTRL[7:0] = 0x80 disable PLL */ + rtl_write_byte(rtlpriv, REG_AFE_PLL_CTRL, 0x80); + + /* n. SPS0_CTRL 0x11[7:0] = 0x22 enter PFM mode */ + rtl_write_byte(rtlpriv, REG_SPS0_CTRL, 0x23); + + /* o. AFE_XTAL_CTRL 0x24[7:0] = 0x0E disable XTAL, if No BT COEX */ + rtl_write_byte(rtlpriv, REG_AFE_XTAL_CTRL, 0x0e); + + /* p. RSV_CTRL 0x1C[7:0] = 0x0E lock ISO/CLK/Power control register */ + rtl_write_byte(rtlpriv, REG_RSV_CTRL, 0x0e); + + /* ==== interface into suspend === */ + + /* q. APS_FSMCO[15:8] = 0x58 PCIe suspend mode */ + /* According to power document V11, we need to set this */ + /* value as 0x18. Otherwise, we may not L0s sometimes. */ + /* This indluences power consumption. Bases on SD1's test, */ + /* set as 0x00 do not affect power current. And if it */ + /* is set as 0x18, they had ever met auto load fail problem. */ + rtl_write_byte(rtlpriv, REG_APS_FSMCO + 1, 0x10); + + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "In PowerOff,reg0x%x=%X\n", + REG_SPS0_CTRL, rtl_read_byte(rtlpriv, REG_SPS0_CTRL)); + /* r. Note: for PCIe interface, PON will not turn */ + /* off m-bias and BandGap in PCIe suspend mode. */ + + /* 0x17[7] 1b': power off in process 0b' : power off over */ + if (rtlpriv->rtlhal.macphymode != SINGLEMAC_SINGLEPHY) { + spin_lock_irqsave(&globalmutex_power, flags); + u1b_tmp = rtl_read_byte(rtlpriv, REG_POWER_OFF_IN_PROCESS); + u1b_tmp &= (~BIT(7)); + rtl_write_byte(rtlpriv, REG_POWER_OFF_IN_PROCESS, u1b_tmp); + spin_unlock_irqrestore(&globalmutex_power, flags); + } + + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "<=======\n"); +} + +void rtl92de_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_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + enum nl80211_iftype opmode; + + mac->link_state = MAC80211_NOLINK; + opmode = NL80211_IFTYPE_UNSPECIFIED; + _rtl92de_set_media_status(hw, opmode); + + if (rtlpci->driver_is_goingto_unload || + ppsc->rfoff_reason > RF_CHANGE_BY_PS) + rtlpriv->cfg->ops->led_control(hw, LED_CTL_POWER_OFF); + RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC); + /* Power sequence for each MAC. */ + /* a. stop tx DMA */ + /* b. close RF */ + /* c. clear rx buf */ + /* d. stop rx DMA */ + /* e. reset MAC */ + + /* a. stop tx DMA */ + rtl_write_byte(rtlpriv, REG_PCIE_CTRL_REG + 1, 0xFE); + udelay(50); + + /* b. TXPAUSE 0x522[7:0] = 0xFF Pause MAC TX queue */ + + /* c. ========RF OFF sequence========== */ + /* 0x88c[23:20] = 0xf. */ + rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER4, 0x00f00000, 0xf); + rtl_set_rfreg(hw, RF90_PATH_A, 0x00, BRFREGOFFSETMASK, 0x00); + + /* APSD_CTRL 0x600[7:0] = 0x40 */ + rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x40); + + /* Close antenna 0,0xc04,0xd04 */ + rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, BMASKBYTE0, 0); + rtl_set_bbreg(hw, ROFDM1_TRXPATHENABLE, BDWORD, 0); + + /* SYS_FUNC_EN 0x02[7:0] = 0xE2 reset BB state machine */ + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE2); + + /* Mac0 can not do Global reset. Mac1 can do. */ + /* SYS_FUNC_EN 0x02[7:0] = 0xE0 reset BB state machine */ + if (rtlpriv->rtlhal.interfaceindex == 1) + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE0); + udelay(50); + + /* d. stop tx/rx dma before disable REG_CR (0x100) to fix */ + /* dma hang issue when disable/enable device. */ + rtl_write_byte(rtlpriv, REG_PCIE_CTRL_REG + 1, 0xff); + udelay(50); + rtl_write_byte(rtlpriv, REG_CR, 0x0); + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "==> Do power off.......\n"); + if (rtl92d_phy_check_poweroff(hw)) + _rtl92de_poweroff_adapter(hw); + return; +} + +void rtl92de_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, ISR + 4, *p_intb); + */ +} + +void rtl92de_set_beacon_related_registers(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + u16 bcn_interval, atim_window; + + bcn_interval = mac->beacon_interval; + atim_window = 2; + /*rtl92de_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, 0x20); + if (rtlpriv->rtlhal.current_bandtype == BAND_ON_5G) + rtl_write_byte(rtlpriv, REG_RXTSF_OFFSET_OFDM, 0x30); + else + rtl_write_byte(rtlpriv, REG_RXTSF_OFFSET_OFDM, 0x20); + rtl_write_byte(rtlpriv, 0x606, 0x30); +} + +void rtl92de_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(rtlpriv, COMP_BEACON, DBG_DMESG, + "beacon_interval:%d\n", bcn_interval); + /* rtl92de_disable_interrupt(hw); */ + rtl_write_word(rtlpriv, REG_BCN_INTERVAL, bcn_interval); + /* rtl92de_enable_interrupt(hw); */ +} + +void rtl92de_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(rtlpriv, 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); + rtl92de_disable_interrupt(hw); + rtl92de_enable_interrupt(hw); +} + +static void _rtl92de_readpowervalue_fromprom(struct txpower_info *pwrinfo, + u8 *rom_content, bool autoLoadfail) +{ + u32 rfpath, eeaddr, group, offset1, offset2; + u8 i; + + memset(pwrinfo, 0, sizeof(struct txpower_info)); + if (autoLoadfail) { + for (group = 0; group < CHANNEL_GROUP_MAX; group++) { + for (rfpath = 0; rfpath < RF6052_MAX_PATH; rfpath++) { + if (group < CHANNEL_GROUP_MAX_2G) { + pwrinfo->cck_index[rfpath][group] = + EEPROM_DEFAULT_TXPOWERLEVEL_2G; + pwrinfo->ht40_1sindex[rfpath][group] = + EEPROM_DEFAULT_TXPOWERLEVEL_2G; + } else { + pwrinfo->ht40_1sindex[rfpath][group] = + EEPROM_DEFAULT_TXPOWERLEVEL_5G; + } + pwrinfo->ht40_2sindexdiff[rfpath][group] = + EEPROM_DEFAULT_HT40_2SDIFF; + pwrinfo->ht20indexdiff[rfpath][group] = + EEPROM_DEFAULT_HT20_DIFF; + pwrinfo->ofdmindexdiff[rfpath][group] = + EEPROM_DEFAULT_LEGACYHTTXPOWERDIFF; + pwrinfo->ht40maxoffset[rfpath][group] = + EEPROM_DEFAULT_HT40_PWRMAXOFFSET; + pwrinfo->ht20maxoffset[rfpath][group] = + EEPROM_DEFAULT_HT20_PWRMAXOFFSET; + } + } + for (i = 0; i < 3; i++) { + pwrinfo->tssi_a[i] = EEPROM_DEFAULT_TSSI; + pwrinfo->tssi_b[i] = EEPROM_DEFAULT_TSSI; + } + return; + } + + /* Maybe autoload OK,buf the tx power index value is not filled. + * If we find it, we set it to default value. */ + for (rfpath = 0; rfpath < RF6052_MAX_PATH; rfpath++) { + for (group = 0; group < CHANNEL_GROUP_MAX_2G; group++) { + eeaddr = EEPROM_CCK_TX_PWR_INX_2G + (rfpath * 3) + + group; + pwrinfo->cck_index[rfpath][group] = + (rom_content[eeaddr] == 0xFF) ? + (eeaddr > 0x7B ? + EEPROM_DEFAULT_TXPOWERLEVEL_5G : + EEPROM_DEFAULT_TXPOWERLEVEL_2G) : + rom_content[eeaddr]; + } + } + for (rfpath = 0; rfpath < RF6052_MAX_PATH; rfpath++) { + for (group = 0; group < CHANNEL_GROUP_MAX; group++) { + offset1 = group / 3; + offset2 = group % 3; + eeaddr = EEPROM_HT40_1S_TX_PWR_INX_2G + (rfpath * 3) + + offset2 + offset1 * 21; + pwrinfo->ht40_1sindex[rfpath][group] = + (rom_content[eeaddr] == 0xFF) ? (eeaddr > 0x7B ? + EEPROM_DEFAULT_TXPOWERLEVEL_5G : + EEPROM_DEFAULT_TXPOWERLEVEL_2G) : + rom_content[eeaddr]; + } + } + /* These just for 92D efuse offset. */ + for (group = 0; group < CHANNEL_GROUP_MAX; group++) { + for (rfpath = 0; rfpath < RF6052_MAX_PATH; rfpath++) { + int base1 = EEPROM_HT40_2S_TX_PWR_INX_DIFF_2G; + + offset1 = group / 3; + offset2 = group % 3; + + if (rom_content[base1 + offset2 + offset1 * 21] != 0xFF) + pwrinfo->ht40_2sindexdiff[rfpath][group] = + (rom_content[base1 + + offset2 + offset1 * 21] >> (rfpath * 4)) + & 0xF; + else + pwrinfo->ht40_2sindexdiff[rfpath][group] = + EEPROM_DEFAULT_HT40_2SDIFF; + if (rom_content[EEPROM_HT20_TX_PWR_INX_DIFF_2G + offset2 + + offset1 * 21] != 0xFF) + pwrinfo->ht20indexdiff[rfpath][group] = + (rom_content[EEPROM_HT20_TX_PWR_INX_DIFF_2G + + offset2 + offset1 * 21] >> (rfpath * 4)) + & 0xF; + else + pwrinfo->ht20indexdiff[rfpath][group] = + EEPROM_DEFAULT_HT20_DIFF; + if (rom_content[EEPROM_OFDM_TX_PWR_INX_DIFF_2G + offset2 + + offset1 * 21] != 0xFF) + pwrinfo->ofdmindexdiff[rfpath][group] = + (rom_content[EEPROM_OFDM_TX_PWR_INX_DIFF_2G + + offset2 + offset1 * 21] >> (rfpath * 4)) + & 0xF; + else + pwrinfo->ofdmindexdiff[rfpath][group] = + EEPROM_DEFAULT_LEGACYHTTXPOWERDIFF; + if (rom_content[EEPROM_HT40_MAX_PWR_OFFSET_2G + offset2 + + offset1 * 21] != 0xFF) + pwrinfo->ht40maxoffset[rfpath][group] = + (rom_content[EEPROM_HT40_MAX_PWR_OFFSET_2G + + offset2 + offset1 * 21] >> (rfpath * 4)) + & 0xF; + else + pwrinfo->ht40maxoffset[rfpath][group] = + EEPROM_DEFAULT_HT40_PWRMAXOFFSET; + if (rom_content[EEPROM_HT20_MAX_PWR_OFFSET_2G + offset2 + + offset1 * 21] != 0xFF) + pwrinfo->ht20maxoffset[rfpath][group] = + (rom_content[EEPROM_HT20_MAX_PWR_OFFSET_2G + + offset2 + offset1 * 21] >> (rfpath * 4)) & + 0xF; + else + pwrinfo->ht20maxoffset[rfpath][group] = + EEPROM_DEFAULT_HT20_PWRMAXOFFSET; + } + } + if (rom_content[EEPROM_TSSI_A_5G] != 0xFF) { + /* 5GL */ + pwrinfo->tssi_a[0] = rom_content[EEPROM_TSSI_A_5G] & 0x3F; + pwrinfo->tssi_b[0] = rom_content[EEPROM_TSSI_B_5G] & 0x3F; + /* 5GM */ + pwrinfo->tssi_a[1] = rom_content[EEPROM_TSSI_AB_5G] & 0x3F; + pwrinfo->tssi_b[1] = + (rom_content[EEPROM_TSSI_AB_5G] & 0xC0) >> 6 | + (rom_content[EEPROM_TSSI_AB_5G + 1] & 0x0F) << 2; + /* 5GH */ + pwrinfo->tssi_a[2] = (rom_content[EEPROM_TSSI_AB_5G + 1] & + 0xF0) >> 4 | + (rom_content[EEPROM_TSSI_AB_5G + 2] & 0x03) << 4; + pwrinfo->tssi_b[2] = (rom_content[EEPROM_TSSI_AB_5G + 2] & + 0xFC) >> 2; + } else { + for (i = 0; i < 3; i++) { + pwrinfo->tssi_a[i] = EEPROM_DEFAULT_TSSI; + pwrinfo->tssi_b[i] = EEPROM_DEFAULT_TSSI; + } + } +} + +static void _rtl92de_read_txpower_info(struct ieee80211_hw *hw, + bool autoload_fail, u8 *hwinfo) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + struct txpower_info pwrinfo; + u8 tempval[2], i, pwr, diff; + u32 ch, rfPath, group; + + _rtl92de_readpowervalue_fromprom(&pwrinfo, hwinfo, autoload_fail); + if (!autoload_fail) { + /* bit0~2 */ + rtlefuse->eeprom_regulatory = (hwinfo[EEPROM_RF_OPT1] & 0x7); + rtlefuse->eeprom_thermalmeter = + hwinfo[EEPROM_THERMAL_METER] & 0x1f; + rtlefuse->crystalcap = hwinfo[EEPROM_XTAL_K]; + tempval[0] = hwinfo[EEPROM_IQK_DELTA] & 0x03; + tempval[1] = (hwinfo[EEPROM_LCK_DELTA] & 0x0C) >> 2; + rtlefuse->txpwr_fromeprom = true; + if (IS_92D_D_CUT(rtlpriv->rtlhal.version) || + IS_92D_E_CUT(rtlpriv->rtlhal.version)) { + rtlefuse->internal_pa_5g[0] = + !((hwinfo[EEPROM_TSSI_A_5G] & BIT(6)) >> 6); + rtlefuse->internal_pa_5g[1] = + !((hwinfo[EEPROM_TSSI_B_5G] & BIT(6)) >> 6); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "Is D cut,Internal PA0 %d Internal PA1 %d\n", + rtlefuse->internal_pa_5g[0], + rtlefuse->internal_pa_5g[1]); + } + rtlefuse->eeprom_c9 = hwinfo[EEPROM_RF_OPT6]; + rtlefuse->eeprom_cc = hwinfo[EEPROM_RF_OPT7]; + } else { + rtlefuse->eeprom_regulatory = 0; + rtlefuse->eeprom_thermalmeter = EEPROM_DEFAULT_THERMALMETER; + rtlefuse->crystalcap = EEPROM_DEFAULT_CRYSTALCAP; + tempval[0] = tempval[1] = 3; + } + + /* Use default value to fill parameters if + * efuse is not filled on some place. */ + + /* ThermalMeter from EEPROM */ + if (rtlefuse->eeprom_thermalmeter < 0x06 || + rtlefuse->eeprom_thermalmeter > 0x1c) + rtlefuse->eeprom_thermalmeter = 0x12; + rtlefuse->thermalmeter[0] = rtlefuse->eeprom_thermalmeter; + + /* check XTAL_K */ + if (rtlefuse->crystalcap == 0xFF) + rtlefuse->crystalcap = 0; + if (rtlefuse->eeprom_regulatory > 3) + rtlefuse->eeprom_regulatory = 0; + + for (i = 0; i < 2; i++) { + switch (tempval[i]) { + case 0: + tempval[i] = 5; + break; + case 1: + tempval[i] = 4; + break; + case 2: + tempval[i] = 3; + break; + case 3: + default: + tempval[i] = 0; + break; + } + } + + rtlefuse->delta_iqk = tempval[0]; + if (tempval[1] > 0) + rtlefuse->delta_lck = tempval[1] - 1; + if (rtlefuse->eeprom_c9 == 0xFF) + rtlefuse->eeprom_c9 = 0x00; + RT_TRACE(rtlpriv, COMP_INTR, DBG_LOUD, + "EEPROMRegulatory = 0x%x\n", rtlefuse->eeprom_regulatory); + RT_TRACE(rtlpriv, COMP_INTR, DBG_LOUD, + "ThermalMeter = 0x%x\n", rtlefuse->eeprom_thermalmeter); + RT_TRACE(rtlpriv, COMP_INTR, DBG_LOUD, + "CrystalCap = 0x%x\n", rtlefuse->crystalcap); + RT_TRACE(rtlpriv, COMP_INTR, DBG_LOUD, + "Delta_IQK = 0x%x Delta_LCK = 0x%x\n", + rtlefuse->delta_iqk, rtlefuse->delta_lck); + + for (rfPath = 0; rfPath < RF6052_MAX_PATH; rfPath++) { + for (ch = 0; ch < CHANNEL_MAX_NUMBER; ch++) { + group = rtl92d_get_chnlgroup_fromarray((u8) ch); + if (ch < CHANNEL_MAX_NUMBER_2G) + rtlefuse->txpwrlevel_cck[rfPath][ch] = + pwrinfo.cck_index[rfPath][group]; + rtlefuse->txpwrlevel_ht40_1s[rfPath][ch] = + pwrinfo.ht40_1sindex[rfPath][group]; + rtlefuse->txpwr_ht20diff[rfPath][ch] = + pwrinfo.ht20indexdiff[rfPath][group]; + rtlefuse->txpwr_legacyhtdiff[rfPath][ch] = + pwrinfo.ofdmindexdiff[rfPath][group]; + rtlefuse->pwrgroup_ht20[rfPath][ch] = + pwrinfo.ht20maxoffset[rfPath][group]; + rtlefuse->pwrgroup_ht40[rfPath][ch] = + pwrinfo.ht40maxoffset[rfPath][group]; + pwr = pwrinfo.ht40_1sindex[rfPath][group]; + diff = pwrinfo.ht40_2sindexdiff[rfPath][group]; + rtlefuse->txpwrlevel_ht40_2s[rfPath][ch] = + (pwr > diff) ? (pwr - diff) : 0; + } + } +} + +static void _rtl92de_read_macphymode_from_prom(struct ieee80211_hw *hw, + u8 *content) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u8 macphy_crvalue = content[EEPROM_MAC_FUNCTION]; + + if (macphy_crvalue & BIT(3)) { + rtlhal->macphymode = SINGLEMAC_SINGLEPHY; + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "MacPhyMode SINGLEMAC_SINGLEPHY\n"); + } else { + rtlhal->macphymode = DUALMAC_DUALPHY; + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "MacPhyMode DUALMAC_DUALPHY\n"); + } +} + +static void _rtl92de_read_macphymode_and_bandtype(struct ieee80211_hw *hw, + u8 *content) +{ + _rtl92de_read_macphymode_from_prom(hw, content); + rtl92d_phy_config_macphymode(hw); + rtl92d_phy_config_macphymode_info(hw); +} + +static void _rtl92de_efuse_update_chip_version(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + enum version_8192d chipver = rtlpriv->rtlhal.version; + u8 cutvalue[2]; + u16 chipvalue; + + rtlpriv->intf_ops->read_efuse_byte(hw, EEPROME_CHIP_VERSION_H, + &cutvalue[1]); + rtlpriv->intf_ops->read_efuse_byte(hw, EEPROME_CHIP_VERSION_L, + &cutvalue[0]); + chipvalue = (cutvalue[1] << 8) | cutvalue[0]; + switch (chipvalue) { + case 0xAA55: + chipver |= CHIP_92D_C_CUT; + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "C-CUT!!!\n"); + break; + case 0x9966: + chipver |= CHIP_92D_D_CUT; + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "D-CUT!!!\n"); + break; + default: + chipver |= CHIP_92D_D_CUT; + RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG, "Unkown CUT!\n"); + break; + } + rtlpriv->rtlhal.version = chipver; +} + +static void _rtl92de_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; + unsigned long flags; + + if (rtlefuse->epromtype == EEPROM_BOOT_EFUSE) { + spin_lock_irqsave(&globalmutex_for_power_and_efuse, flags); + rtl_efuse_shadow_map_update(hw); + _rtl92de_efuse_update_chip_version(hw); + spin_unlock_irqrestore(&globalmutex_for_power_and_efuse, flags); + memcpy((void *)hwinfo, (void *)&rtlefuse->efuse_map + [EFUSE_INIT_MAP][0], + HWSET_MAX_SIZE); + } else if (rtlefuse->epromtype == EEPROM_93C46) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "RTL819X Not boot from eeprom, check it !!\n"); + } + RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_DMESG, "MAP", + hwinfo, HWSET_MAX_SIZE); + + eeprom_id = *((u16 *)&hwinfo[0]); + if (eeprom_id != RTL8190_EEPROM_ID) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, + "EEPROM ID(%#x) is invalid!!\n", eeprom_id); + rtlefuse->autoload_failflag = true; + } else { + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "Autoload OK\n"); + rtlefuse->autoload_failflag = false; + } + if (rtlefuse->autoload_failflag) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "RTL819X Not boot from eeprom, check it !!\n"); + return; + } + rtlefuse->eeprom_oemid = *(u8 *)&hwinfo[EEPROM_CUSTOMER_ID]; + _rtl92de_read_macphymode_and_bandtype(hw, hwinfo); + + /* VID, DID SE 0xA-D */ + 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(rtlpriv, COMP_INIT, DBG_LOUD, "EEPROMId = 0x%4x\n", eeprom_id); + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "EEPROM VID = 0x%4x\n", rtlefuse->eeprom_vid); + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "EEPROM DID = 0x%4x\n", rtlefuse->eeprom_did); + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "EEPROM SVID = 0x%4x\n", rtlefuse->eeprom_svid); + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "EEPROM SMID = 0x%4x\n", rtlefuse->eeprom_smid); + + /* Read Permanent MAC address */ + if (rtlhal->interfaceindex == 0) { + for (i = 0; i < 6; i += 2) { + usvalue = *(u16 *)&hwinfo[EEPROM_MAC_ADDR_MAC0_92D + i]; + *((u16 *) (&rtlefuse->dev_addr[i])) = usvalue; + } + } else { + for (i = 0; i < 6; i += 2) { + usvalue = *(u16 *)&hwinfo[EEPROM_MAC_ADDR_MAC1_92D + i]; + *((u16 *) (&rtlefuse->dev_addr[i])) = usvalue; + } + } + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_ETHER_ADDR, + rtlefuse->dev_addr); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "%pM\n", rtlefuse->dev_addr); + _rtl92de_read_txpower_info(hw, rtlefuse->autoload_failflag, hwinfo); + + /* Read Channel Plan */ + switch (rtlhal->bandset) { + case BAND_ON_2_4G: + rtlefuse->channel_plan = COUNTRY_CODE_TELEC; + break; + case BAND_ON_5G: + rtlefuse->channel_plan = COUNTRY_CODE_FCC; + break; + case BAND_ON_BOTH: + rtlefuse->channel_plan = COUNTRY_CODE_FCC; + break; + default: + rtlefuse->channel_plan = COUNTRY_CODE_FCC; + break; + } + rtlefuse->eeprom_version = *(u16 *)&hwinfo[EEPROM_VERSION]; + rtlefuse->txpwr_fromeprom = true; + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "EEPROM Customer ID: 0x%2x\n", rtlefuse->eeprom_oemid); +} + +void rtl92de_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_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u8 tmp_u1b; + + rtlhal->version = _rtl92de_read_chip_version(hw); + tmp_u1b = rtl_read_byte(rtlpriv, REG_9346CR); + rtlefuse->autoload_status = tmp_u1b; + if (tmp_u1b & BIT(4)) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "Boot from EEPROM\n"); + rtlefuse->epromtype = EEPROM_93C46; + } else { + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "Boot from EFUSE\n"); + rtlefuse->epromtype = EEPROM_BOOT_EFUSE; + } + if (tmp_u1b & BIT(5)) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "Autoload OK\n"); + + rtlefuse->autoload_failflag = false; + _rtl92de_read_adapter_info(hw); + } else { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Autoload ERR!!\n"); + } + return; +} + +static void rtl92de_update_hal_rate_table(struct ieee80211_hw *hw, + struct ieee80211_sta *sta) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u32 ratr_value; + u8 ratr_index = 0; + u8 nmode = mac->ht_enable; + u8 mimo_ps = IEEE80211_SMPS_OFF; + u16 shortgi_rate; + u32 tmp_ratr_value; + u8 curtxbw_40mhz = mac->bw_40; + u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ? + 1 : 0; + u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ? + 1 : 0; + enum wireless_mode wirelessmode = mac->mode; + + if (rtlhal->current_bandtype == BAND_ON_5G) + ratr_value = sta->supp_rates[1] << 4; + else + ratr_value = sta->supp_rates[0]; + ratr_value |= (sta->ht_cap.mcs.rx_mask[1] << 20 | + sta->ht_cap.mcs.rx_mask[0] << 12); + switch (wirelessmode) { + case WIRELESS_MODE_A: + ratr_value &= 0x00000FF0; + break; + case WIRELESS_MODE_B: + if (ratr_value & 0x0000000c) + ratr_value &= 0x0000000d; + else + ratr_value &= 0x0000000f; + break; + case WIRELESS_MODE_G: + ratr_value &= 0x00000FF5; + break; + case WIRELESS_MODE_N_24G: + case WIRELESS_MODE_N_5G: + nmode = 1; + if (mimo_ps == IEEE80211_SMPS_STATIC) { + ratr_value &= 0x0007F005; + } else { + u32 ratr_mask; + + if (get_rf_type(rtlphy) == RF_1T2R || + get_rf_type(rtlphy) == RF_1T1R) { + ratr_mask = 0x000ff005; + } else { + ratr_mask = 0x0f0ff005; + } + + ratr_value &= ratr_mask; + } + break; + default: + if (rtlphy->rf_type == RF_1T2R) + ratr_value &= 0x000ff0ff; + else + ratr_value &= 0x0f0ff0ff; + + break; + } + ratr_value &= 0x0FFFFFFF; + if (nmode && ((curtxbw_40mhz && curshortgi_40mhz) || + (!curtxbw_40mhz && curshortgi_20mhz))) { + ratr_value |= 0x10000000; + tmp_ratr_value = (ratr_value >> 12); + for (shortgi_rate = 15; shortgi_rate > 0; shortgi_rate--) { + if ((1 << shortgi_rate) & tmp_ratr_value) + break; + } + shortgi_rate = (shortgi_rate << 12) | (shortgi_rate << 8) | + (shortgi_rate << 4) | (shortgi_rate); + } + rtl_write_dword(rtlpriv, REG_ARFR0 + ratr_index * 4, ratr_value); + RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG, "%x\n", + rtl_read_dword(rtlpriv, REG_ARFR0)); +} + +static void rtl92de_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_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_sta_info *sta_entry = NULL; + u32 ratr_bitmap; + u8 ratr_index; + u8 curtxbw_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) + ? 1 : 0; + u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ? + 1 : 0; + u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ? + 1 : 0; + enum wireless_mode wirelessmode = 0; + bool shortgi = false; + u32 value[2]; + u8 macid = 0; + u8 mimo_ps = IEEE80211_SMPS_OFF; + + sta_entry = (struct rtl_sta_info *) sta->drv_priv; + mimo_ps = sta_entry->mimo_ps; + wirelessmode = sta_entry->wireless_mode; + if (mac->opmode == NL80211_IFTYPE_STATION) + curtxbw_40mhz = mac->bw_40; + else if (mac->opmode == NL80211_IFTYPE_AP || + mac->opmode == NL80211_IFTYPE_ADHOC) + macid = sta->aid + 1; + + if (rtlhal->current_bandtype == BAND_ON_5G) + ratr_bitmap = sta->supp_rates[1] << 4; + else + ratr_bitmap = sta->supp_rates[0]; + 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_A: + ratr_index = RATR_INX_WIRELESS_G; + ratr_bitmap &= 0x00000ff0; + break; + case WIRELESS_MODE_N_24G: + case WIRELESS_MODE_N_5G: + if (wirelessmode == WIRELESS_MODE_N_24G) + ratr_index = RATR_INX_WIRELESS_NGB; + else + ratr_index = RATR_INX_WIRELESS_NG; + if (mimo_ps == IEEE80211_SMPS_STATIC) { + if (rssi_level == 1) + ratr_bitmap &= 0x00070000; + else if (rssi_level == 2) + ratr_bitmap &= 0x0007f000; + else + ratr_bitmap &= 0x0007f005; + } else { + if (rtlphy->rf_type == RF_1T2R || + rtlphy->rf_type == RF_1T1R) { + if (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 (curtxbw_40mhz) { + if (rssi_level == 1) + ratr_bitmap &= 0x0f0f0000; + else if (rssi_level == 2) + ratr_bitmap &= 0x0f0ff000; + else + ratr_bitmap &= 0x0f0ff015; + } else { + if (rssi_level == 1) + ratr_bitmap &= 0x0f0f0000; + else if (rssi_level == 2) + ratr_bitmap &= 0x0f0ff000; + else + ratr_bitmap &= 0x0f0ff005; + } + } + } + if ((curtxbw_40mhz && curshortgi_40mhz) || + (!curtxbw_40mhz && curshortgi_20mhz)) { + + if (macid == 0) + shortgi = true; + else if (macid == 1) + shortgi = false; + } + break; + default: + ratr_index = RATR_INX_WIRELESS_NGB; + + if (rtlphy->rf_type == RF_1T2R) + ratr_bitmap &= 0x000ff0ff; + else + ratr_bitmap &= 0x0f0ff0ff; + break; + } + + value[0] = (ratr_bitmap & 0x0fffffff) | (ratr_index << 28); + value[1] = macid | (shortgi ? 0x20 : 0x00) | 0x80; + RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG, + "ratr_bitmap :%x value0:%x value1:%x\n", + ratr_bitmap, value[0], value[1]); + rtl92d_fill_h2c_cmd(hw, H2C_RA_MASK, 5, (u8 *) value); + if (macid != 0) + sta_entry->ratr_index = ratr_index; +} + +void rtl92de_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.useramask) + rtl92de_update_hal_rate_mask(hw, sta, rssi_level); + else + rtl92de_update_hal_rate_table(hw, sta); +} + +void rtl92de_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 = 0x1010; + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SIFS, (u8 *)&sifs_timer); +} + +bool rtl92de_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 *valid) +{ + 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)); + enum rf_pwrstate e_rfpowerstate_toset; + u8 u1tmp; + bool actuallyset = false; + unsigned long flag; + + if (rtlpci->being_init_adapter) + return false; + if (ppsc->swrf_processing) + return false; + spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flag); + if (ppsc->rfchange_inprogress) { + spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag); + return false; + } else { + ppsc->rfchange_inprogress = true; + spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag); + } + rtl_write_byte(rtlpriv, REG_MAC_PINMUX_CFG, rtl_read_byte(rtlpriv, + REG_MAC_PINMUX_CFG) & ~(BIT(3))); + u1tmp = rtl_read_byte(rtlpriv, REG_GPIO_IO_SEL); + e_rfpowerstate_toset = (u1tmp & BIT(3)) ? ERFON : ERFOFF; + if (ppsc->hwradiooff && (e_rfpowerstate_toset == ERFON)) { + RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG, + "GPIOChangeRF - HW Radio ON, RF ON\n"); + e_rfpowerstate_toset = ERFON; + ppsc->hwradiooff = false; + actuallyset = true; + } else if (!ppsc->hwradiooff && (e_rfpowerstate_toset == ERFOFF)) { + RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG, + "GPIOChangeRF - HW Radio OFF, RF OFF\n"); + e_rfpowerstate_toset = ERFOFF; + ppsc->hwradiooff = true; + actuallyset = true; + } + if (actuallyset) { + spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flag); + ppsc->rfchange_inprogress = false; + spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag); + } else { + if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_HALT_NIC) + RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC); + spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flag); + ppsc->rfchange_inprogress = false; + spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag); + } + *valid = 1; + return !ppsc->hwradiooff; +} + +void rtl92de_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; + 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; + u8 cam_offset = 0; + u8 clear_number = 5; + RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, "clear_all\n"); + for (idx = 0; idx < clear_number; idx++) { + rtl_cam_mark_invalid(hw, cam_offset + idx); + 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(rtlpriv, COMP_ERR, DBG_EMERG, + "switch case not processed\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) { + entry_id = rtl_cam_get_free_entry(hw, + p_macaddr); + if (entry_id >= TOTAL_CAM_ENTRY) { + RT_TRACE(rtlpriv, 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(rtlpriv, COMP_SEC, DBG_DMESG, + "delete one entry, entry_id is %d\n", + entry_id); + if (mac->opmode == NL80211_IFTYPE_AP) + rtl_cam_del_entry(hw, p_macaddr); + rtl_cam_delete_one_entry(hw, p_macaddr, entry_id); + } else { + RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, + "The insert KEY length is %d\n", + rtlpriv->sec.key_len[PAIRWISE_KEYIDX]); + RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, + "The insert KEY is %x %x\n", + rtlpriv->sec.key_buf[0][0], + rtlpriv->sec.key_buf[0][1]); + RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, + "add one entry\n"); + if (is_pairwise) { + RT_PRINT_DATA(rtlpriv, COMP_SEC, DBG_LOUD, + "Pairwise Key content", + rtlpriv->sec.pairwise_key, + rtlpriv-> + sec.key_len[PAIRWISE_KEYIDX]); + RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, + "set Pairwise key\n"); + 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(rtlpriv, COMP_SEC, DBG_DMESG, + "set group key\n"); + if (mac->opmode == NL80211_IFTYPE_ADHOC) { + 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]); + } + rtl_cam_add_one_entry(hw, macaddr, key_index, + entry_id, enc_algo, + CAM_CONFIG_NO_USEDK, + rtlpriv->sec.key_buf + [entry_id]); + } + } + } +} + +void rtl92de_suspend(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtlpriv->rtlhal.macphyctl_reg = rtl_read_byte(rtlpriv, + REG_MAC_PHY_CTRL_NORMAL); +} + +void rtl92de_resume(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtl_write_byte(rtlpriv, REG_MAC_PHY_CTRL_NORMAL, + rtlpriv->rtlhal.macphyctl_reg); +} diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/hw.h b/drivers/net/wireless/rtlwifi/rtl8192de/hw.h new file mode 100644 index 00000000..7c9f7a2f --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192de/hw.h @@ -0,0 +1,66 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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 __RTL92DE_HW_H__ +#define __RTL92DE_HW_H__ + +void rtl92de_get_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val); +void rtl92de_read_eeprom_info(struct ieee80211_hw *hw); +void rtl92de_interrupt_recognized(struct ieee80211_hw *hw, + u32 *p_inta, u32 *p_intb); +int rtl92de_hw_init(struct ieee80211_hw *hw); +void rtl92de_card_disable(struct ieee80211_hw *hw); +void rtl92de_enable_interrupt(struct ieee80211_hw *hw); +void rtl92de_disable_interrupt(struct ieee80211_hw *hw); +int rtl92de_set_network_type(struct ieee80211_hw *hw, enum nl80211_iftype type); +void rtl92de_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid); +void rtl92de_set_qos(struct ieee80211_hw *hw, int aci); +void rtl92de_set_beacon_related_registers(struct ieee80211_hw *hw); +void rtl92de_set_beacon_interval(struct ieee80211_hw *hw); +void rtl92de_update_interrupt_mask(struct ieee80211_hw *hw, + u32 add_msr, u32 rm_msr); +void rtl92de_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val); +void rtl92de_update_hal_rate_tbl(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, u8 rssi_level); +void rtl92de_update_channel_access_setting(struct ieee80211_hw *hw); +bool rtl92de_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 *valid); +void rtl92de_enable_hw_security_config(struct ieee80211_hw *hw); +void rtl92de_set_key(struct ieee80211_hw *hw, u32 key_index, + u8 *p_macaddr, bool is_group, u8 enc_algo, + bool is_wepkey, bool clear_all); + +extern void rtl92de_write_dword_dbi(struct ieee80211_hw *hw, u16 offset, + u32 value, u8 direct); +extern u32 rtl92de_read_dword_dbi(struct ieee80211_hw *hw, u16 offset, + u8 direct); +void rtl92de_suspend(struct ieee80211_hw *hw); +void rtl92de_resume(struct ieee80211_hw *hw); +void rtl92d_linked_set_reg(struct ieee80211_hw *hw); + +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/led.c b/drivers/net/wireless/rtlwifi/rtl8192de/led.c new file mode 100644 index 00000000..76a57ae4 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192de/led.c @@ -0,0 +1,159 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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> + * + *****************************************************************************/ + +#include "../wifi.h" +#include "../pci.h" +#include "reg.h" +#include "led.h" + +static void _rtl92ce_init_led(struct ieee80211_hw *hw, + struct rtl_led *pled, enum rtl_led_pin ledpin) +{ + pled->hw = hw; + pled->ledpin = ledpin; + pled->ledon = false; +} + +void rtl92de_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled) +{ + u8 ledcfg; + struct rtl_priv *rtlpriv = rtl_priv(hw); + + RT_TRACE(rtlpriv, 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_byte(rtlpriv, REG_LEDCFG2); + + if ((rtlpriv->efuse.eeprom_did == 0x8176) || + (rtlpriv->efuse.eeprom_did == 0x8193)) + /* BIT7 of REG_LEDCFG2 should be set to + * make sure we could emit the led2. */ + rtl_write_byte(rtlpriv, REG_LEDCFG2, (ledcfg & 0xf0) | + BIT(7) | BIT(5) | BIT(6)); + else + rtl_write_byte(rtlpriv, REG_LEDCFG2, (ledcfg & 0xf0) | + BIT(7) | BIT(5)); + break; + case LED_PIN_LED1: + ledcfg = rtl_read_byte(rtlpriv, REG_LEDCFG1); + + rtl_write_byte(rtlpriv, REG_LEDCFG2, (ledcfg & 0x0f) | BIT(5)); + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "switch case not processed\n"); + break; + } + pled->ledon = true; +} + +void rtl92de_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); + u8 ledcfg; + + RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD, "LedAddr:%X ledpin=%d\n", + REG_LEDCFG2, pled->ledpin); + + ledcfg = rtl_read_byte(rtlpriv, REG_LEDCFG2); + + switch (pled->ledpin) { + case LED_PIN_GPIO0: + break; + case LED_PIN_LED0: + ledcfg &= 0xf0; + if (pcipriv->ledctl.led_opendrain) + rtl_write_byte(rtlpriv, REG_LEDCFG2, + (ledcfg | BIT(1) | BIT(5) | BIT(6))); + else + rtl_write_byte(rtlpriv, REG_LEDCFG2, + (ledcfg | BIT(3) | BIT(5) | BIT(6))); + break; + case LED_PIN_LED1: + ledcfg &= 0x0f; + rtl_write_byte(rtlpriv, REG_LEDCFG2, (ledcfg | BIT(3))); + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "switch case not processed\n"); + break; + } + pled->ledon = false; +} + +void rtl92de_init_sw_leds(struct ieee80211_hw *hw) +{ + struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); + _rtl92ce_init_led(hw, &(pcipriv->ledctl.sw_led0), LED_PIN_LED0); + _rtl92ce_init_led(hw, &(pcipriv->ledctl.sw_led1), LED_PIN_LED1); +} + +static void _rtl92ce_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: + rtl92de_sw_led_on(hw, pLed0); + break; + case LED_CTL_POWER_OFF: + rtl92de_sw_led_off(hw, pLed0); + break; + default: + break; + } +} + +void rtl92de_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(rtlpriv, COMP_LED, DBG_LOUD, "ledaction %d,\n", ledaction); + + _rtl92ce_sw_led_control(hw, ledaction); +} diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/led.h b/drivers/net/wireless/rtlwifi/rtl8192de/led.h new file mode 100644 index 00000000..a29df30c --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192de/led.h @@ -0,0 +1,38 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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 __RTL92CE_LED_H__ +#define __RTL92CE_LED_H__ + +void rtl92de_init_sw_leds(struct ieee80211_hw *hw); +void rtl92de_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled); +void rtl92de_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled); +void rtl92de_led_control(struct ieee80211_hw *hw, enum led_ctl_mode ledaction); + +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/phy.c b/drivers/net/wireless/rtlwifi/rtl8192de/phy.c new file mode 100644 index 00000000..28fc5fb8 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192de/phy.c @@ -0,0 +1,3713 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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> + * + *****************************************************************************/ + +#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" +#include "sw.h" +#include "hw.h" + +#define MAX_RF_IMR_INDEX 12 +#define MAX_RF_IMR_INDEX_NORMAL 13 +#define RF_REG_NUM_FOR_C_CUT_5G 6 +#define RF_REG_NUM_FOR_C_CUT_5G_INTERNALPA 7 +#define RF_REG_NUM_FOR_C_CUT_2G 5 +#define RF_CHNL_NUM_5G 19 +#define RF_CHNL_NUM_5G_40M 17 +#define TARGET_CHNL_NUM_5G 221 +#define TARGET_CHNL_NUM_2G 14 +#define CV_CURVE_CNT 64 + +static u32 rf_reg_for_5g_swchnl_normal[MAX_RF_IMR_INDEX_NORMAL] = { + 0, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x0 +}; + +static u8 rf_reg_for_c_cut_5g[RF_REG_NUM_FOR_C_CUT_5G] = { + RF_SYN_G1, RF_SYN_G2, RF_SYN_G3, RF_SYN_G4, RF_SYN_G5, RF_SYN_G6 +}; + +static u8 rf_reg_for_c_cut_2g[RF_REG_NUM_FOR_C_CUT_2G] = { + RF_SYN_G1, RF_SYN_G2, RF_SYN_G3, RF_SYN_G7, RF_SYN_G8 +}; + +static u8 rf_for_c_cut_5g_internal_pa[RF_REG_NUM_FOR_C_CUT_5G_INTERNALPA] = { + 0x0B, 0x48, 0x49, 0x4B, 0x03, 0x04, 0x0E +}; + +static u32 rf_reg_mask_for_c_cut_2g[RF_REG_NUM_FOR_C_CUT_2G] = { + BIT(19) | BIT(18) | BIT(17) | BIT(14) | BIT(1), + BIT(10) | BIT(9), + BIT(18) | BIT(17) | BIT(16) | BIT(1), + BIT(2) | BIT(1), + BIT(15) | BIT(14) | BIT(13) | BIT(12) | BIT(11) +}; + +static u8 rf_chnl_5g[RF_CHNL_NUM_5G] = { + 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, + 112, 116, 120, 124, 128, 132, 136, 140 +}; + +static u8 rf_chnl_5g_40m[RF_CHNL_NUM_5G_40M] = { + 38, 42, 46, 50, 54, 58, 62, 102, 106, 110, 114, + 118, 122, 126, 130, 134, 138 +}; +static u32 rf_reg_pram_c_5g[5][RF_REG_NUM_FOR_C_CUT_5G] = { + {0xE43BE, 0xFC638, 0x77C0A, 0xDE471, 0xd7110, 0x8EB04}, + {0xE43BE, 0xFC078, 0xF7C1A, 0xE0C71, 0xD7550, 0xAEB04}, + {0xE43BF, 0xFF038, 0xF7C0A, 0xDE471, 0xE5550, 0xAEB04}, + {0xE43BF, 0xFF079, 0xF7C1A, 0xDE471, 0xE5550, 0xAEB04}, + {0xE43BF, 0xFF038, 0xF7C1A, 0xDE471, 0xd7550, 0xAEB04} +}; + +static u32 rf_reg_param_for_c_cut_2g[3][RF_REG_NUM_FOR_C_CUT_2G] = { + {0x643BC, 0xFC038, 0x77C1A, 0x41289, 0x01840}, + {0x643BC, 0xFC038, 0x07C1A, 0x41289, 0x01840}, + {0x243BC, 0xFC438, 0x07C1A, 0x4128B, 0x0FC41} +}; + +static u32 rf_syn_g4_for_c_cut_2g = 0xD1C31 & 0x7FF; + +static u32 rf_pram_c_5g_int_pa[3][RF_REG_NUM_FOR_C_CUT_5G_INTERNALPA] = { + {0x01a00, 0x40443, 0x00eb5, 0x89bec, 0x94a12, 0x94a12, 0x94a12}, + {0x01800, 0xc0443, 0x00730, 0x896ee, 0x94a52, 0x94a52, 0x94a52}, + {0x01800, 0xc0443, 0x00730, 0x896ee, 0x94a12, 0x94a12, 0x94a12} +}; + +/* [mode][patha+b][reg] */ +static u32 rf_imr_param_normal[1][3][MAX_RF_IMR_INDEX_NORMAL] = { + { + /* channel 1-14. */ + { + 0x70000, 0x00ff0, 0x4400f, 0x00ff0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x64888, 0xe266c, 0x00090, 0x22fff + }, + /* path 36-64 */ + { + 0x70000, 0x22880, 0x4470f, 0x55880, 0x00070, 0x88000, + 0x0, 0x88080, 0x70000, 0x64a82, 0xe466c, 0x00090, + 0x32c9a + }, + /* 100 -165 */ + { + 0x70000, 0x44880, 0x4477f, 0x77880, 0x00070, 0x88000, + 0x0, 0x880b0, 0x0, 0x64b82, 0xe466c, 0x00090, 0x32c9a + } + } +}; + +static u32 curveindex_5g[TARGET_CHNL_NUM_5G] = {0}; + +static u32 curveindex_2g[TARGET_CHNL_NUM_2G] = {0}; + +static u32 targetchnl_5g[TARGET_CHNL_NUM_5G] = { + 25141, 25116, 25091, 25066, 25041, + 25016, 24991, 24966, 24941, 24917, + 24892, 24867, 24843, 24818, 24794, + 24770, 24765, 24721, 24697, 24672, + 24648, 24624, 24600, 24576, 24552, + 24528, 24504, 24480, 24457, 24433, + 24409, 24385, 24362, 24338, 24315, + 24291, 24268, 24245, 24221, 24198, + 24175, 24151, 24128, 24105, 24082, + 24059, 24036, 24013, 23990, 23967, + 23945, 23922, 23899, 23876, 23854, + 23831, 23809, 23786, 23764, 23741, + 23719, 23697, 23674, 23652, 23630, + 23608, 23586, 23564, 23541, 23519, + 23498, 23476, 23454, 23432, 23410, + 23388, 23367, 23345, 23323, 23302, + 23280, 23259, 23237, 23216, 23194, + 23173, 23152, 23130, 23109, 23088, + 23067, 23046, 23025, 23003, 22982, + 22962, 22941, 22920, 22899, 22878, + 22857, 22837, 22816, 22795, 22775, + 22754, 22733, 22713, 22692, 22672, + 22652, 22631, 22611, 22591, 22570, + 22550, 22530, 22510, 22490, 22469, + 22449, 22429, 22409, 22390, 22370, + 22350, 22336, 22310, 22290, 22271, + 22251, 22231, 22212, 22192, 22173, + 22153, 22134, 22114, 22095, 22075, + 22056, 22037, 22017, 21998, 21979, + 21960, 21941, 21921, 21902, 21883, + 21864, 21845, 21826, 21807, 21789, + 21770, 21751, 21732, 21713, 21695, + 21676, 21657, 21639, 21620, 21602, + 21583, 21565, 21546, 21528, 21509, + 21491, 21473, 21454, 21436, 21418, + 21400, 21381, 21363, 21345, 21327, + 21309, 21291, 21273, 21255, 21237, + 21219, 21201, 21183, 21166, 21148, + 21130, 21112, 21095, 21077, 21059, + 21042, 21024, 21007, 20989, 20972, + 25679, 25653, 25627, 25601, 25575, + 25549, 25523, 25497, 25471, 25446, + 25420, 25394, 25369, 25343, 25318, + 25292, 25267, 25242, 25216, 25191, + 25166 +}; + +/* channel 1~14 */ +static u32 targetchnl_2g[TARGET_CHNL_NUM_2G] = { + 26084, 26030, 25976, 25923, 25869, 25816, 25764, + 25711, 25658, 25606, 25554, 25502, 25451, 25328 +}; + +static u32 _rtl92d_phy_calculate_bit_shift(u32 bitmask) +{ + u32 i; + + for (i = 0; i <= 31; i++) { + if (((bitmask >> i) & 0x1) == 1) + break; + } + + return i; +} + +u32 rtl92d_phy_query_bb_reg(struct ieee80211_hw *hw, u32 regaddr, u32 bitmask) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + u32 returnvalue, originalvalue, bitshift; + u8 dbi_direct; + + RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, "regaddr(%#x), bitmask(%#x)\n", + regaddr, bitmask); + if (rtlhal->during_mac1init_radioa || rtlhal->during_mac0init_radiob) { + /* mac1 use phy0 read radio_b. */ + /* mac0 use phy1 read radio_b. */ + if (rtlhal->during_mac1init_radioa) + dbi_direct = BIT(3); + else if (rtlhal->during_mac0init_radiob) + dbi_direct = BIT(3) | BIT(2); + originalvalue = rtl92de_read_dword_dbi(hw, (u16)regaddr, + dbi_direct); + } else { + originalvalue = rtl_read_dword(rtlpriv, regaddr); + } + bitshift = _rtl92d_phy_calculate_bit_shift(bitmask); + returnvalue = (originalvalue & bitmask) >> bitshift; + RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, + "BBR MASK=0x%x Addr[0x%x]=0x%x\n", + bitmask, regaddr, originalvalue); + return returnvalue; +} + +void rtl92d_phy_set_bb_reg(struct ieee80211_hw *hw, + u32 regaddr, u32 bitmask, u32 data) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + u8 dbi_direct = 0; + u32 originalvalue, bitshift; + + RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, + "regaddr(%#x), bitmask(%#x), data(%#x)\n", + regaddr, bitmask, data); + if (rtlhal->during_mac1init_radioa) + dbi_direct = BIT(3); + else if (rtlhal->during_mac0init_radiob) + /* mac0 use phy1 write radio_b. */ + dbi_direct = BIT(3) | BIT(2); + if (bitmask != BMASKDWORD) { + if (rtlhal->during_mac1init_radioa || + rtlhal->during_mac0init_radiob) + originalvalue = rtl92de_read_dword_dbi(hw, + (u16) regaddr, + dbi_direct); + else + originalvalue = rtl_read_dword(rtlpriv, regaddr); + bitshift = _rtl92d_phy_calculate_bit_shift(bitmask); + data = ((originalvalue & (~bitmask)) | (data << bitshift)); + } + if (rtlhal->during_mac1init_radioa || rtlhal->during_mac0init_radiob) + rtl92de_write_dword_dbi(hw, (u16) regaddr, data, dbi_direct); + else + rtl_write_dword(rtlpriv, regaddr, data); + RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, + "regaddr(%#x), bitmask(%#x), data(%#x)\n", + regaddr, bitmask, data); +} + +static u32 _rtl92d_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; + + newoffset = offset; + tmplong = rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, BMASKDWORD); + if (rfpath == RF90_PATH_A) + tmplong2 = tmplong; + else + tmplong2 = rtl_get_bbreg(hw, pphyreg->rfhssi_para2, BMASKDWORD); + tmplong2 = (tmplong2 & (~BLSSIREADADDRESS)) | + (newoffset << 23) | BLSSIREADEDGE; + rtl_set_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, BMASKDWORD, + tmplong & (~BLSSIREADEDGE)); + udelay(10); + rtl_set_bbreg(hw, pphyreg->rfhssi_para2, BMASKDWORD, tmplong2); + udelay(50); + udelay(50); + rtl_set_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, BMASKDWORD, + tmplong | BLSSIREADEDGE); + udelay(10); + 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(rtlpriv, COMP_RF, DBG_TRACE, "RFR-%d Addr[0x%x] = 0x%x\n", + rfpath, pphyreg->rflssi_readback, retvalue); + return retvalue; +} + +static void _rtl92d_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]; + + newoffset = offset; + /* T65 RF */ + data_and_addr = ((newoffset << 20) | (data & 0x000fffff)) & 0x0fffffff; + rtl_set_bbreg(hw, pphyreg->rf3wire_offset, BMASKDWORD, data_and_addr); + RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, "RFW-%d Addr[0x%x]=0x%x\n", + rfpath, pphyreg->rf3wire_offset, data_and_addr); +} + +u32 rtl92d_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(rtlpriv, COMP_RF, DBG_TRACE, + "regaddr(%#x), rfpath(%#x), bitmask(%#x)\n", + regaddr, rfpath, bitmask); + spin_lock_irqsave(&rtlpriv->locks.rf_lock, flags); + original_value = _rtl92d_phy_rf_serial_read(hw, rfpath, regaddr); + bitshift = _rtl92d_phy_calculate_bit_shift(bitmask); + readback_value = (original_value & bitmask) >> bitshift; + spin_unlock_irqrestore(&rtlpriv->locks.rf_lock, flags); + RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, + "regaddr(%#x), rfpath(%#x), bitmask(%#x), original_value(%#x)\n", + regaddr, rfpath, bitmask, original_value); + return readback_value; +} + +void rtl92d_phy_set_rf_reg(struct ieee80211_hw *hw, enum radio_path rfpath, + u32 regaddr, u32 bitmask, u32 data) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + u32 original_value, bitshift; + unsigned long flags; + + RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, + "regaddr(%#x), bitmask(%#x), data(%#x), rfpath(%#x)\n", + regaddr, bitmask, data, rfpath); + if (bitmask == 0) + return; + spin_lock_irqsave(&rtlpriv->locks.rf_lock, flags); + if (rtlphy->rf_mode != RF_OP_BY_FW) { + if (bitmask != BRFREGOFFSETMASK) { + original_value = _rtl92d_phy_rf_serial_read(hw, + rfpath, regaddr); + bitshift = _rtl92d_phy_calculate_bit_shift(bitmask); + data = ((original_value & (~bitmask)) | + (data << bitshift)); + } + _rtl92d_phy_rf_serial_write(hw, rfpath, regaddr, data); + } + spin_unlock_irqrestore(&rtlpriv->locks.rf_lock, flags); + RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, + "regaddr(%#x), bitmask(%#x), data(%#x), rfpath(%#x)\n", + regaddr, bitmask, data, rfpath); +} + +bool rtl92d_phy_mac_config(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 i; + u32 arraylength; + u32 *ptrarray; + + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "Read Rtl819XMACPHY_Array\n"); + arraylength = MAC_2T_ARRAYLENGTH; + ptrarray = rtl8192de_mac_2tarray; + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "Img:Rtl819XMAC_Array\n"); + for (i = 0; i < arraylength; i = i + 2) + rtl_write_byte(rtlpriv, ptrarray[i], (u8) ptrarray[i + 1]); + if (rtlpriv->rtlhal.macphymode == SINGLEMAC_SINGLEPHY) { + /* improve 2-stream TX EVM */ + /* rtl_write_byte(rtlpriv, 0x14,0x71); */ + /* AMPDU aggregation number 9 */ + /* rtl_write_word(rtlpriv, REG_MAX_AGGR_NUM, MAX_AGGR_NUM); */ + rtl_write_byte(rtlpriv, REG_MAX_AGGR_NUM, 0x0B); + } else { + /* 92D need to test to decide the num. */ + rtl_write_byte(rtlpriv, REG_MAX_AGGR_NUM, 0x07); + } + return true; +} + +static void _rtl92d_phy_init_bb_rf_register_definition(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + + /* RF Interface Sowrtware Control */ + /* 16 LSBs if read 32-bit from 0x870 */ + rtlphy->phyreg_def[RF90_PATH_A].rfintfs = RFPGA0_XAB_RFINTERFACESW; + /* 16 MSBs if read 32-bit from 0x870 (16-bit for 0x872) */ + rtlphy->phyreg_def[RF90_PATH_B].rfintfs = RFPGA0_XAB_RFINTERFACESW; + /* 16 LSBs if read 32-bit from 0x874 */ + rtlphy->phyreg_def[RF90_PATH_C].rfintfs = RFPGA0_XCD_RFINTERFACESW; + /* 16 MSBs if read 32-bit from 0x874 (16-bit for 0x876) */ + + rtlphy->phyreg_def[RF90_PATH_D].rfintfs = RFPGA0_XCD_RFINTERFACESW; + /* RF Interface Readback Value */ + /* 16 LSBs if read 32-bit from 0x8E0 */ + rtlphy->phyreg_def[RF90_PATH_A].rfintfi = RFPGA0_XAB_RFINTERFACERB; + /* 16 MSBs if read 32-bit from 0x8E0 (16-bit for 0x8E2) */ + rtlphy->phyreg_def[RF90_PATH_B].rfintfi = RFPGA0_XAB_RFINTERFACERB; + /* 16 LSBs if read 32-bit from 0x8E4 */ + rtlphy->phyreg_def[RF90_PATH_C].rfintfi = RFPGA0_XCD_RFINTERFACERB; + /* 16 MSBs if read 32-bit from 0x8E4 (16-bit for 0x8E6) */ + rtlphy->phyreg_def[RF90_PATH_D].rfintfi = RFPGA0_XCD_RFINTERFACERB; + + /* RF Interface Output (and Enable) */ + /* 16 LSBs if read 32-bit from 0x860 */ + rtlphy->phyreg_def[RF90_PATH_A].rfintfo = RFPGA0_XA_RFINTERFACEOE; + /* 16 LSBs if read 32-bit from 0x864 */ + rtlphy->phyreg_def[RF90_PATH_B].rfintfo = RFPGA0_XB_RFINTERFACEOE; + + /* RF Interface (Output and) Enable */ + /* 16 MSBs if read 32-bit from 0x860 (16-bit for 0x862) */ + rtlphy->phyreg_def[RF90_PATH_A].rfintfe = RFPGA0_XA_RFINTERFACEOE; + /* 16 MSBs if read 32-bit from 0x864 (16-bit for 0x866) */ + rtlphy->phyreg_def[RF90_PATH_B].rfintfe = RFPGA0_XB_RFINTERFACEOE; + + /* Addr of LSSI. Wirte RF register by driver */ + /* LSSI Parameter */ + rtlphy->phyreg_def[RF90_PATH_A].rf3wire_offset = + RFPGA0_XA_LSSIPARAMETER; + rtlphy->phyreg_def[RF90_PATH_B].rf3wire_offset = + RFPGA0_XB_LSSIPARAMETER; + + /* RF parameter */ + /* BB Band Select */ + rtlphy->phyreg_def[RF90_PATH_A].rflssi_select = RFPGA0_XAB_RFPARAMETER; + rtlphy->phyreg_def[RF90_PATH_B].rflssi_select = RFPGA0_XAB_RFPARAMETER; + rtlphy->phyreg_def[RF90_PATH_C].rflssi_select = RFPGA0_XCD_RFPARAMETER; + rtlphy->phyreg_def[RF90_PATH_D].rflssi_select = RFPGA0_XCD_RFPARAMETER; + + /* Tx AGC Gain Stage (same for all path. Should we remove this?) */ + /* Tx gain stage */ + rtlphy->phyreg_def[RF90_PATH_A].rftxgain_stage = RFPGA0_TXGAINSTAGE; + /* Tx gain stage */ + rtlphy->phyreg_def[RF90_PATH_B].rftxgain_stage = RFPGA0_TXGAINSTAGE; + /* Tx gain stage */ + rtlphy->phyreg_def[RF90_PATH_C].rftxgain_stage = RFPGA0_TXGAINSTAGE; + /* Tx gain stage */ + rtlphy->phyreg_def[RF90_PATH_D].rftxgain_stage = RFPGA0_TXGAINSTAGE; + + /* Tranceiver A~D HSSI Parameter-1 */ + /* wire control parameter1 */ + rtlphy->phyreg_def[RF90_PATH_A].rfhssi_para1 = RFPGA0_XA_HSSIPARAMETER1; + /* wire control parameter1 */ + rtlphy->phyreg_def[RF90_PATH_B].rfhssi_para1 = RFPGA0_XB_HSSIPARAMETER1; + + /* Tranceiver A~D HSSI Parameter-2 */ + /* wire control parameter2 */ + rtlphy->phyreg_def[RF90_PATH_A].rfhssi_para2 = RFPGA0_XA_HSSIPARAMETER2; + /* wire control parameter2 */ + rtlphy->phyreg_def[RF90_PATH_B].rfhssi_para2 = RFPGA0_XB_HSSIPARAMETER2; + + /* RF switch Control */ + /* TR/Ant switch control */ + rtlphy->phyreg_def[RF90_PATH_A].rfswitch_control = + RFPGA0_XAB_SWITCHCONTROL; + rtlphy->phyreg_def[RF90_PATH_B].rfswitch_control = + RFPGA0_XAB_SWITCHCONTROL; + rtlphy->phyreg_def[RF90_PATH_C].rfswitch_control = + RFPGA0_XCD_SWITCHCONTROL; + rtlphy->phyreg_def[RF90_PATH_D].rfswitch_control = + RFPGA0_XCD_SWITCHCONTROL; + + /* AGC control 1 */ + rtlphy->phyreg_def[RF90_PATH_A].rfagc_control1 = ROFDM0_XAAGCCORE1; + rtlphy->phyreg_def[RF90_PATH_B].rfagc_control1 = ROFDM0_XBAGCCORE1; + rtlphy->phyreg_def[RF90_PATH_C].rfagc_control1 = ROFDM0_XCAGCCORE1; + rtlphy->phyreg_def[RF90_PATH_D].rfagc_control1 = ROFDM0_XDAGCCORE1; + + /* AGC control 2 */ + rtlphy->phyreg_def[RF90_PATH_A].rfagc_control2 = ROFDM0_XAAGCCORE2; + rtlphy->phyreg_def[RF90_PATH_B].rfagc_control2 = ROFDM0_XBAGCCORE2; + rtlphy->phyreg_def[RF90_PATH_C].rfagc_control2 = ROFDM0_XCAGCCORE2; + rtlphy->phyreg_def[RF90_PATH_D].rfagc_control2 = ROFDM0_XDAGCCORE2; + + /* RX AFE control 1 */ + rtlphy->phyreg_def[RF90_PATH_A].rfrxiq_imbalance = + ROFDM0_XARXIQIMBALANCE; + rtlphy->phyreg_def[RF90_PATH_B].rfrxiq_imbalance = + ROFDM0_XBRXIQIMBALANCE; + rtlphy->phyreg_def[RF90_PATH_C].rfrxiq_imbalance = + ROFDM0_XCRXIQIMBALANCE; + rtlphy->phyreg_def[RF90_PATH_D].rfrxiq_imbalance = + ROFDM0_XDRXIQIMBALANCE; + + /*RX AFE control 1 */ + rtlphy->phyreg_def[RF90_PATH_A].rfrx_afe = ROFDM0_XARXAFE; + rtlphy->phyreg_def[RF90_PATH_B].rfrx_afe = ROFDM0_XBRXAFE; + rtlphy->phyreg_def[RF90_PATH_C].rfrx_afe = ROFDM0_XCRXAFE; + rtlphy->phyreg_def[RF90_PATH_D].rfrx_afe = ROFDM0_XDRXAFE; + + /* Tx AFE control 1 */ + rtlphy->phyreg_def[RF90_PATH_A].rftxiq_imbalance = + ROFDM0_XATxIQIMBALANCE; + rtlphy->phyreg_def[RF90_PATH_B].rftxiq_imbalance = + ROFDM0_XBTxIQIMBALANCE; + rtlphy->phyreg_def[RF90_PATH_C].rftxiq_imbalance = + ROFDM0_XCTxIQIMBALANCE; + rtlphy->phyreg_def[RF90_PATH_D].rftxiq_imbalance = + ROFDM0_XDTxIQIMBALANCE; + + /* Tx AFE control 2 */ + rtlphy->phyreg_def[RF90_PATH_A].rftx_afe = ROFDM0_XATxAFE; + rtlphy->phyreg_def[RF90_PATH_B].rftx_afe = ROFDM0_XBTxAFE; + rtlphy->phyreg_def[RF90_PATH_C].rftx_afe = ROFDM0_XCTxAFE; + rtlphy->phyreg_def[RF90_PATH_D].rftx_afe = ROFDM0_XDTxAFE; + + /* Tranceiver LSSI Readback SI mode */ + 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_C].rflssi_readback = + RFPGA0_XC_LSSIREADBACK; + rtlphy->phyreg_def[RF90_PATH_D].rflssi_readback = + RFPGA0_XD_LSSIREADBACK; + + /* Tranceiver LSSI Readback PI mode */ + rtlphy->phyreg_def[RF90_PATH_A].rflssi_readbackpi = + TRANSCEIVERA_HSPI_READBACK; + rtlphy->phyreg_def[RF90_PATH_B].rflssi_readbackpi = + TRANSCEIVERB_HSPI_READBACK; +} + +static bool _rtl92d_phy_config_bb_with_headerfile(struct ieee80211_hw *hw, + u8 configtype) +{ + int i; + u32 *phy_regarray_table; + u32 *agctab_array_table = NULL; + u32 *agctab_5garray_table; + u16 phy_reg_arraylen, agctab_arraylen = 0, agctab_5garraylen; + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + + /* Normal chip,Mac0 use AGC_TAB.txt for 2G and 5G band. */ + if (rtlhal->interfaceindex == 0) { + agctab_arraylen = AGCTAB_ARRAYLENGTH; + agctab_array_table = rtl8192de_agctab_array; + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + " ===> phy:MAC0, Rtl819XAGCTAB_Array\n"); + } else { + if (rtlhal->current_bandtype == BAND_ON_2_4G) { + agctab_arraylen = AGCTAB_2G_ARRAYLENGTH; + agctab_array_table = rtl8192de_agctab_2garray; + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + " ===> phy:MAC1, Rtl819XAGCTAB_2GArray\n"); + } else { + agctab_5garraylen = AGCTAB_5G_ARRAYLENGTH; + agctab_5garray_table = rtl8192de_agctab_5garray; + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + " ===> phy:MAC1, Rtl819XAGCTAB_5GArray\n"); + + } + } + phy_reg_arraylen = PHY_REG_2T_ARRAYLENGTH; + phy_regarray_table = rtl8192de_phy_reg_2tarray; + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + " ===> phy:Rtl819XPHY_REG_Array_PG\n"); + if (configtype == BASEBAND_CONFIG_PHY_REG) { + for (i = 0; i < phy_reg_arraylen; i = i + 2) { + if (phy_regarray_table[i] == 0xfe) + mdelay(50); + else if (phy_regarray_table[i] == 0xfd) + mdelay(5); + else if (phy_regarray_table[i] == 0xfc) + mdelay(1); + else if (phy_regarray_table[i] == 0xfb) + udelay(50); + else if (phy_regarray_table[i] == 0xfa) + udelay(5); + else if (phy_regarray_table[i] == 0xf9) + udelay(1); + rtl_set_bbreg(hw, phy_regarray_table[i], BMASKDWORD, + phy_regarray_table[i + 1]); + udelay(1); + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + "The phy_regarray_table[0] is %x Rtl819XPHY_REGArray[1] is %x\n", + phy_regarray_table[i], + phy_regarray_table[i + 1]); + } + } else if (configtype == BASEBAND_CONFIG_AGC_TAB) { + if (rtlhal->interfaceindex == 0) { + for (i = 0; i < agctab_arraylen; i = i + 2) { + rtl_set_bbreg(hw, agctab_array_table[i], + BMASKDWORD, + agctab_array_table[i + 1]); + /* Add 1us delay between BB/RF register + * setting. */ + udelay(1); + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + "The Rtl819XAGCTAB_Array_Table[0] is %ul Rtl819XPHY_REGArray[1] is %ul\n", + agctab_array_table[i], + agctab_array_table[i + 1]); + } + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "Normal Chip, MAC0, load Rtl819XAGCTAB_Array\n"); + } else { + if (rtlhal->current_bandtype == BAND_ON_2_4G) { + for (i = 0; i < agctab_arraylen; i = i + 2) { + rtl_set_bbreg(hw, agctab_array_table[i], + BMASKDWORD, + agctab_array_table[i + 1]); + /* Add 1us delay between BB/RF register + * setting. */ + udelay(1); + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + "The Rtl819XAGCTAB_Array_Table[0] is %ul Rtl819XPHY_REGArray[1] is %ul\n", + agctab_array_table[i], + agctab_array_table[i + 1]); + } + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "Load Rtl819XAGCTAB_2GArray\n"); + } else { + for (i = 0; i < agctab_5garraylen; i = i + 2) { + rtl_set_bbreg(hw, + agctab_5garray_table[i], + BMASKDWORD, + agctab_5garray_table[i + 1]); + /* Add 1us delay between BB/RF registeri + * setting. */ + udelay(1); + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + "The Rtl819XAGCTAB_5GArray_Table[0] is %ul Rtl819XPHY_REGArray[1] is %ul\n", + agctab_5garray_table[i], + agctab_5garray_table[i + 1]); + } + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "Load Rtl819XAGCTAB_5GArray\n"); + } + } + } + return true; +} + +static void _rtl92d_store_pwrindex_diffrate_offset(struct ieee80211_hw *hw, + u32 regaddr, u32 bitmask, + u32 data) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + int index; + + if (regaddr == RTXAGC_A_RATE18_06) + index = 0; + else if (regaddr == RTXAGC_A_RATE54_24) + index = 1; + else if (regaddr == RTXAGC_A_CCK1_MCS32) + index = 6; + else if (regaddr == RTXAGC_B_CCK11_A_CCK2_11 && bitmask == 0xffffff00) + index = 7; + else if (regaddr == RTXAGC_A_MCS03_MCS00) + index = 2; + else if (regaddr == RTXAGC_A_MCS07_MCS04) + index = 3; + else if (regaddr == RTXAGC_A_MCS11_MCS08) + index = 4; + else if (regaddr == RTXAGC_A_MCS15_MCS12) + index = 5; + else if (regaddr == RTXAGC_B_RATE18_06) + index = 8; + else if (regaddr == RTXAGC_B_RATE54_24) + index = 9; + else if (regaddr == RTXAGC_B_CCK1_55_MCS32) + index = 14; + else if (regaddr == RTXAGC_B_CCK11_A_CCK2_11 && bitmask == 0x000000ff) + index = 15; + else if (regaddr == RTXAGC_B_MCS03_MCS00) + index = 10; + else if (regaddr == RTXAGC_B_MCS07_MCS04) + index = 11; + else if (regaddr == RTXAGC_B_MCS11_MCS08) + index = 12; + else if (regaddr == RTXAGC_B_MCS15_MCS12) + index = 13; + else + return; + + rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][index] = data; + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + "MCSTxPowerLevelOriginalOffset[%d][%d] = 0x%ulx\n", + rtlphy->pwrgroup_cnt, index, + rtlphy->mcs_txpwrlevel_origoffset + [rtlphy->pwrgroup_cnt][index]); + if (index == 13) + rtlphy->pwrgroup_cnt++; +} + +static bool _rtl92d_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; + + phy_regarray_pg_len = PHY_REG_ARRAY_PG_LENGTH; + phy_regarray_table_pg = rtl8192de_phy_reg_array_pg; + if (configtype == BASEBAND_CONFIG_PHY_REG) { + for (i = 0; i < phy_regarray_pg_len; i = i + 3) { + if (phy_regarray_table_pg[i] == 0xfe) + mdelay(50); + else if (phy_regarray_table_pg[i] == 0xfd) + mdelay(5); + else if (phy_regarray_table_pg[i] == 0xfc) + mdelay(1); + else if (phy_regarray_table_pg[i] == 0xfb) + udelay(50); + else if (phy_regarray_table_pg[i] == 0xfa) + udelay(5); + else if (phy_regarray_table_pg[i] == 0xf9) + udelay(1); + _rtl92d_store_pwrindex_diffrate_offset(hw, + phy_regarray_table_pg[i], + phy_regarray_table_pg[i + 1], + phy_regarray_table_pg[i + 2]); + } + } else { + RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE, + "configtype != BaseBand_Config_PHY_REG\n"); + } + return true; +} + +static bool _rtl92d_phy_bb_config(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 = true; + + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "==>\n"); + rtstatus = _rtl92d_phy_config_bb_with_headerfile(hw, + BASEBAND_CONFIG_PHY_REG); + if (!rtstatus) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Write BB Reg Fail!!\n"); + return false; + } + + /* if (rtlphy->rf_type == RF_1T2R) { + * _rtl92c_phy_bb_config_1t(hw); + * RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "Config to 1T!!\n"); + *} */ + + if (rtlefuse->autoload_failflag == false) { + rtlphy->pwrgroup_cnt = 0; + rtstatus = _rtl92d_phy_config_bb_with_pgheaderfile(hw, + BASEBAND_CONFIG_PHY_REG); + } + if (!rtstatus) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "BB_PG Reg Fail!!\n"); + return false; + } + rtstatus = _rtl92d_phy_config_bb_with_headerfile(hw, + BASEBAND_CONFIG_AGC_TAB); + if (!rtstatus) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "AGC Table Fail\n"); + return false; + } + rtlphy->cck_high_power = (bool) (rtl_get_bbreg(hw, + RFPGA0_XA_HSSIPARAMETER2, 0x200)); + + return true; +} + +bool rtl92d_phy_bb_config(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u16 regval; + u32 regvaldw; + u8 value; + + _rtl92d_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_AFE_PLL_CTRL, 0x83); + rtl_write_byte(rtlpriv, REG_AFE_PLL_CTRL + 1, 0xdb); + /* 0x1f bit7 bit6 represent for mac0/mac1 driver ready */ + value = rtl_read_byte(rtlpriv, REG_RF_CTRL); + rtl_write_byte(rtlpriv, REG_RF_CTRL, value | 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); + if (!(IS_92D_SINGLEPHY(rtlpriv->rtlhal.version))) { + regvaldw = rtl_read_dword(rtlpriv, REG_LEDCFG0); + rtl_write_dword(rtlpriv, REG_LEDCFG0, regvaldw | BIT(23)); + } + + return _rtl92d_phy_bb_config(hw); +} + +bool rtl92d_phy_rf_config(struct ieee80211_hw *hw) +{ + return rtl92d_phy_rf6052_config(hw); +} + +bool rtl92d_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, + enum rf_content content, + enum radio_path rfpath) +{ + int i; + u32 *radioa_array_table; + u32 *radiob_array_table; + u16 radioa_arraylen, radiob_arraylen; + struct rtl_priv *rtlpriv = rtl_priv(hw); + + radioa_arraylen = RADIOA_2T_ARRAYLENGTH; + radioa_array_table = rtl8192de_radioa_2tarray; + radiob_arraylen = RADIOB_2T_ARRAYLENGTH; + radiob_array_table = rtl8192de_radiob_2tarray; + if (rtlpriv->efuse.internal_pa_5g[0]) { + radioa_arraylen = RADIOA_2T_INT_PA_ARRAYLENGTH; + radioa_array_table = rtl8192de_radioa_2t_int_paarray; + } + if (rtlpriv->efuse.internal_pa_5g[1]) { + radiob_arraylen = RADIOB_2T_INT_PA_ARRAYLENGTH; + radiob_array_table = rtl8192de_radiob_2t_int_paarray; + } + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "PHY_ConfigRFWithHeaderFile() Radio_A:Rtl819XRadioA_1TArray\n"); + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "PHY_ConfigRFWithHeaderFile() Radio_B:Rtl819XRadioB_1TArray\n"); + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "Radio No %x\n", rfpath); + + /* this only happens when DMDP, mac0 start on 2.4G, + * mac1 start on 5G, mac 0 has to set phy0&phy1 + * pathA or mac1 has to set phy0&phy1 pathA */ + if ((content == radiob_txt) && (rfpath == RF90_PATH_A)) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + " ===> althougth Path A, we load radiob.txt\n"); + radioa_arraylen = radiob_arraylen; + radioa_array_table = radiob_array_table; + } + switch (rfpath) { + case RF90_PATH_A: + for (i = 0; i < radioa_arraylen; i = i + 2) { + if (radioa_array_table[i] == 0xfe) { + mdelay(50); + } else if (radioa_array_table[i] == 0xfd) { + /* delay_ms(5); */ + mdelay(5); + } else if (radioa_array_table[i] == 0xfc) { + /* delay_ms(1); */ + mdelay(1); + } else if (radioa_array_table[i] == 0xfb) { + udelay(50); + } else if (radioa_array_table[i] == 0xfa) { + udelay(5); + } else if (radioa_array_table[i] == 0xf9) { + udelay(1); + } else { + rtl_set_rfreg(hw, rfpath, radioa_array_table[i], + BRFREGOFFSETMASK, + radioa_array_table[i + 1]); + /* Add 1us delay between BB/RF register set. */ + udelay(1); + } + } + break; + case RF90_PATH_B: + for (i = 0; i < radiob_arraylen; i = i + 2) { + if (radiob_array_table[i] == 0xfe) { + /* Delay specific ms. Only RF configuration + * requires delay. */ + mdelay(50); + } else if (radiob_array_table[i] == 0xfd) { + /* delay_ms(5); */ + mdelay(5); + } else if (radiob_array_table[i] == 0xfc) { + /* delay_ms(1); */ + mdelay(1); + } else if (radiob_array_table[i] == 0xfb) { + udelay(50); + } else if (radiob_array_table[i] == 0xfa) { + udelay(5); + } else if (radiob_array_table[i] == 0xf9) { + udelay(1); + } else { + rtl_set_rfreg(hw, rfpath, radiob_array_table[i], + BRFREGOFFSETMASK, + radiob_array_table[i + 1]); + /* Add 1us delay between BB/RF register set. */ + udelay(1); + } + } + break; + case RF90_PATH_C: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "switch case not processed\n"); + break; + case RF90_PATH_D: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "switch case not processed\n"); + break; + } + return true; +} + +void rtl92d_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, BMASKBYTE0); + rtlphy->default_initialgain[1] = + (u8) rtl_get_bbreg(hw, ROFDM0_XBAGCCORE1, BMASKBYTE0); + rtlphy->default_initialgain[2] = + (u8) rtl_get_bbreg(hw, ROFDM0_XCAGCCORE1, BMASKBYTE0); + rtlphy->default_initialgain[3] = + (u8) rtl_get_bbreg(hw, ROFDM0_XDAGCCORE1, BMASKBYTE0); + RT_TRACE(rtlpriv, 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, + BMASKBYTE0); + rtlphy->framesync_c34 = rtl_get_bbreg(hw, ROFDM0_RXDETECTOR2, + BMASKDWORD); + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + "Default framesync (0x%x) = 0x%x\n", + ROFDM0_RXDETECTOR3, rtlphy->framesync); +} + +static void _rtl92d_get_txpower_index(struct ieee80211_hw *hw, u8 channel, + u8 *cckpowerlevel, u8 *ofdmpowerlevel) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_hal *rtlhal = &(rtlpriv->rtlhal); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + u8 index = (channel - 1); + + /* 1. CCK */ + if (rtlhal->current_bandtype == BAND_ON_2_4G) { + /* RF-A */ + cckpowerlevel[RF90_PATH_A] = + rtlefuse->txpwrlevel_cck[RF90_PATH_A][index]; + /* RF-B */ + cckpowerlevel[RF90_PATH_B] = + rtlefuse->txpwrlevel_cck[RF90_PATH_B][index]; + } else { + cckpowerlevel[RF90_PATH_A] = 0; + cckpowerlevel[RF90_PATH_B] = 0; + } + /* 2. OFDM for 1S or 2S */ + if (rtlphy->rf_type == RF_1T2R || rtlphy->rf_type == RF_1T1R) { + /* Read HT 40 OFDM TX power */ + ofdmpowerlevel[RF90_PATH_A] = + rtlefuse->txpwrlevel_ht40_1s[RF90_PATH_A][index]; + ofdmpowerlevel[RF90_PATH_B] = + rtlefuse->txpwrlevel_ht40_1s[RF90_PATH_B][index]; + } else if (rtlphy->rf_type == RF_2T2R) { + /* Read HT 40 OFDM TX power */ + ofdmpowerlevel[RF90_PATH_A] = + rtlefuse->txpwrlevel_ht40_2s[RF90_PATH_A][index]; + ofdmpowerlevel[RF90_PATH_B] = + rtlefuse->txpwrlevel_ht40_2s[RF90_PATH_B][index]; + } +} + +static void _rtl92d_ccxpower_index_check(struct ieee80211_hw *hw, + u8 channel, u8 *cckpowerlevel, u8 *ofdmpowerlevel) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + + rtlphy->cur_cck_txpwridx = cckpowerlevel[0]; + rtlphy->cur_ofdm24g_txpwridx = ofdmpowerlevel[0]; +} + +static u8 _rtl92c_phy_get_rightchnlplace(u8 chnl) +{ + u8 channel_5g[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_5g); place++) { + if (channel_5g[place] == chnl) { + place++; + break; + } + } + } + return place; +} + +void rtl92d_phy_set_txpower_level(struct ieee80211_hw *hw, u8 channel) +{ + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 cckpowerlevel[2], ofdmpowerlevel[2]; + + if (!rtlefuse->txpwr_fromeprom) + return; + channel = _rtl92c_phy_get_rightchnlplace(channel); + _rtl92d_get_txpower_index(hw, channel, &cckpowerlevel[0], + &ofdmpowerlevel[0]); + if (rtlpriv->rtlhal.current_bandtype == BAND_ON_2_4G) + _rtl92d_ccxpower_index_check(hw, channel, &cckpowerlevel[0], + &ofdmpowerlevel[0]); + if (rtlpriv->rtlhal.current_bandtype == BAND_ON_2_4G) + rtl92d_phy_rf6052_set_cck_txpower(hw, &cckpowerlevel[0]); + rtl92d_phy_rf6052_set_ofdm_txpower(hw, &ofdmpowerlevel[0], channel); +} + +void rtl92d_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: + rtlhal->current_bandtypebackup = + rtlhal->current_bandtype; + iotype = IO_CMD_PAUSE_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(rtlpriv, COMP_ERR, DBG_EMERG, + "Unknown Scan Backup operation\n"); + break; + } + } +} + +void rtl92d_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)); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + unsigned long flag = 0; + u8 reg_prsr_rsc; + u8 reg_bw_opmode; + + if (rtlphy->set_bwmode_inprogress) + return; + if ((is_hal_stop(rtlhal)) || (RT_CANNOT_IO(hw))) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, + "FALSE driver sleep or unload\n"); + return; + } + rtlphy->set_bwmode_inprogress = true; + RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE, "Switch to %s bandwidth\n", + rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20 ? + "20MHz" : "40MHz"); + 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(rtlpriv, 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); + /* SET BIT10 BIT11 for receive cck */ + rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER2, BIT(10) | + BIT(11), 3); + break; + case HT_CHANNEL_WIDTH_20_40: + rtl_set_bbreg(hw, RFPGA0_RFMOD, BRFMOD, 0x1); + rtl_set_bbreg(hw, RFPGA1_RFMOD, BRFMOD, 0x1); + /* Set Control channel to upper or lower. + * These settings are required only for 40MHz */ + if (rtlhal->current_bandtype == BAND_ON_2_4G) { + rtl92d_acquire_cckandrw_pagea_ctl(hw, &flag); + rtl_set_bbreg(hw, RCCK0_SYSTEM, BCCKSIDEBAND, + (mac->cur_40_prime_sc >> 1)); + rtl92d_release_cckandrw_pagea_ctl(hw, &flag); + } + rtl_set_bbreg(hw, ROFDM1_LSTF, 0xC00, mac->cur_40_prime_sc); + /* SET BIT10 BIT11 for receive cck */ + rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER2, BIT(10) | + BIT(11), 0); + 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(rtlpriv, COMP_ERR, DBG_EMERG, + "unknown bandwidth: %#X\n", rtlphy->current_chan_bw); + break; + + } + rtl92d_phy_rf6052_set_bandwidth(hw, rtlphy->current_chan_bw); + rtlphy->set_bwmode_inprogress = false; + RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE, "<==\n"); +} + +static void _rtl92d_phy_stop_trx_before_changeband(struct ieee80211_hw *hw) +{ + rtl_set_bbreg(hw, RFPGA0_RFMOD, BCCKEN, 0); + rtl_set_bbreg(hw, RFPGA0_RFMOD, BOFDMEN, 0); + rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, BMASKBYTE0, 0x00); + rtl_set_bbreg(hw, ROFDM1_TRXPATHENABLE, BDWORD, 0x0); +} + +static void rtl92d_phy_switch_wirelessband(struct ieee80211_hw *hw, u8 band) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u8 value8; + + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "==>\n"); + rtlhal->bandset = band; + rtlhal->current_bandtype = band; + if (IS_92D_SINGLEPHY(rtlhal->version)) + rtlhal->bandset = BAND_ON_BOTH; + /* stop RX/Tx */ + _rtl92d_phy_stop_trx_before_changeband(hw); + /* reconfig BB/RF according to wireless mode */ + if (rtlhal->current_bandtype == BAND_ON_2_4G) { + /* BB & RF Config */ + RT_TRACE(rtlpriv, COMP_CMD, DBG_DMESG, "====>2.4G\n"); + if (rtlhal->interfaceindex == 1) + _rtl92d_phy_config_bb_with_headerfile(hw, + BASEBAND_CONFIG_AGC_TAB); + } else { + /* 5G band */ + RT_TRACE(rtlpriv, COMP_CMD, DBG_DMESG, "====>5G\n"); + if (rtlhal->interfaceindex == 1) + _rtl92d_phy_config_bb_with_headerfile(hw, + BASEBAND_CONFIG_AGC_TAB); + } + rtl92d_update_bbrf_configuration(hw); + if (rtlhal->current_bandtype == BAND_ON_2_4G) + rtl_set_bbreg(hw, RFPGA0_RFMOD, BCCKEN, 0x1); + rtl_set_bbreg(hw, RFPGA0_RFMOD, BOFDMEN, 0x1); + + /* 20M BW. */ + /* rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER2, BIT(10), 1); */ + rtlhal->reloadtxpowerindex = true; + /* notice fw know band status 0x81[1]/0x53[1] = 0: 5G, 1: 2G */ + if (rtlhal->current_bandtype == BAND_ON_2_4G) { + value8 = rtl_read_byte(rtlpriv, (rtlhal->interfaceindex == + 0 ? REG_MAC0 : REG_MAC1)); + value8 |= BIT(1); + rtl_write_byte(rtlpriv, (rtlhal->interfaceindex == + 0 ? REG_MAC0 : REG_MAC1), value8); + } else { + value8 = rtl_read_byte(rtlpriv, (rtlhal->interfaceindex == + 0 ? REG_MAC0 : REG_MAC1)); + value8 &= (~BIT(1)); + rtl_write_byte(rtlpriv, (rtlhal->interfaceindex == + 0 ? REG_MAC0 : REG_MAC1), value8); + } + mdelay(1); + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "<==Switch Band OK\n"); +} + +static void _rtl92d_phy_reload_imr_setting(struct ieee80211_hw *hw, + u8 channel, u8 rfpath) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 imr_num = MAX_RF_IMR_INDEX; + u32 rfmask = BRFREGOFFSETMASK; + u8 group, i; + unsigned long flag = 0; + + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "====>path %d\n", rfpath); + if (rtlpriv->rtlhal.current_bandtype == BAND_ON_5G) { + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "====>5G\n"); + rtl_set_bbreg(hw, RFPGA0_RFMOD, BIT(25) | BIT(24), 0); + rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER4, 0x00f00000, 0xf); + /* fc area 0xd2c */ + if (channel > 99) + rtl_set_bbreg(hw, ROFDM1_CFOTRACKING, BIT(13) | + BIT(14), 2); + else + rtl_set_bbreg(hw, ROFDM1_CFOTRACKING, BIT(13) | + BIT(14), 1); + /* leave 0 for channel1-14. */ + group = channel <= 64 ? 1 : 2; + imr_num = MAX_RF_IMR_INDEX_NORMAL; + for (i = 0; i < imr_num; i++) + rtl_set_rfreg(hw, (enum radio_path)rfpath, + rf_reg_for_5g_swchnl_normal[i], rfmask, + rf_imr_param_normal[0][group][i]); + rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER4, 0x00f00000, 0); + rtl_set_bbreg(hw, RFPGA0_RFMOD, BOFDMEN, 1); + } else { + /* G band. */ + RT_TRACE(rtlpriv, COMP_SCAN, DBG_LOUD, + "Load RF IMR parameters for G band. IMR already setting %d\n", + rtlpriv->rtlhal.load_imrandiqk_setting_for2g); + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "====>2.4G\n"); + if (!rtlpriv->rtlhal.load_imrandiqk_setting_for2g) { + RT_TRACE(rtlpriv, COMP_SCAN, DBG_LOUD, + "Load RF IMR parameters for G band. %d\n", + rfpath); + rtl92d_acquire_cckandrw_pagea_ctl(hw, &flag); + rtl_set_bbreg(hw, RFPGA0_RFMOD, BIT(25) | BIT(24), 0); + rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER4, + 0x00f00000, 0xf); + imr_num = MAX_RF_IMR_INDEX_NORMAL; + for (i = 0; i < imr_num; i++) { + rtl_set_rfreg(hw, (enum radio_path)rfpath, + rf_reg_for_5g_swchnl_normal[i], + BRFREGOFFSETMASK, + rf_imr_param_normal[0][0][i]); + } + rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER4, + 0x00f00000, 0); + rtl_set_bbreg(hw, RFPGA0_RFMOD, BOFDMEN | BCCKEN, 3); + rtl92d_release_cckandrw_pagea_ctl(hw, &flag); + } + } + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "<====\n"); +} + +static void _rtl92d_phy_enable_rf_env(struct ieee80211_hw *hw, + u8 rfpath, u32 *pu4_regval) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct bb_reg_def *pphyreg = &rtlphy->phyreg_def[rfpath]; + + RT_TRACE(rtlpriv, COMP_RF, DBG_LOUD, "====>\n"); + /*----Store original RFENV control type----*/ + switch (rfpath) { + case RF90_PATH_A: + case RF90_PATH_C: + *pu4_regval = rtl_get_bbreg(hw, pphyreg->rfintfs, BRFSI_RFENV); + break; + case RF90_PATH_B: + case RF90_PATH_D: + *pu4_regval = + rtl_get_bbreg(hw, pphyreg->rfintfs, BRFSI_RFENV << 16); + break; + } + /*----Set RF_ENV enable----*/ + rtl_set_bbreg(hw, pphyreg->rfintfe, BRFSI_RFENV << 16, 0x1); + udelay(1); + /*----Set RF_ENV output high----*/ + rtl_set_bbreg(hw, pphyreg->rfintfo, BRFSI_RFENV, 0x1); + udelay(1); + /* Set bit number of Address and Data for RF register */ + /* Set 1 to 4 bits for 8255 */ + rtl_set_bbreg(hw, pphyreg->rfhssi_para2, B3WIREADDRESSLENGTH, 0x0); + udelay(1); + /*Set 0 to 12 bits for 8255 */ + rtl_set_bbreg(hw, pphyreg->rfhssi_para2, B3WIREDATALENGTH, 0x0); + udelay(1); + RT_TRACE(rtlpriv, COMP_RF, DBG_LOUD, "<====\n"); +} + +static void _rtl92d_phy_restore_rf_env(struct ieee80211_hw *hw, u8 rfpath, + u32 *pu4_regval) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct bb_reg_def *pphyreg = &rtlphy->phyreg_def[rfpath]; + + RT_TRACE(rtlpriv, COMP_RF, DBG_LOUD, "=====>\n"); + /*----Restore RFENV control type----*/ ; + switch (rfpath) { + case RF90_PATH_A: + case RF90_PATH_C: + rtl_set_bbreg(hw, pphyreg->rfintfs, BRFSI_RFENV, *pu4_regval); + break; + case RF90_PATH_B: + case RF90_PATH_D: + rtl_set_bbreg(hw, pphyreg->rfintfs, BRFSI_RFENV << 16, + *pu4_regval); + break; + } + RT_TRACE(rtlpriv, COMP_RF, DBG_LOUD, "<=====\n"); +} + +static void _rtl92d_phy_switch_rf_setting(struct ieee80211_hw *hw, u8 channel) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_hal *rtlhal = &(rtlpriv->rtlhal); + u8 path = rtlhal->current_bandtype == + BAND_ON_5G ? RF90_PATH_A : RF90_PATH_B; + u8 index = 0, i = 0, rfpath = RF90_PATH_A; + bool need_pwr_down = false, internal_pa = false; + u32 u4regvalue, mask = 0x1C000, value = 0, u4tmp, u4tmp2; + + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "====>\n"); + /* config path A for 5G */ + if (rtlhal->current_bandtype == BAND_ON_5G) { + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "====>5G\n"); + u4tmp = curveindex_5g[channel - 1]; + RTPRINT(rtlpriv, FINIT, INIT_IQK, + "ver 1 set RF-A, 5G, 0x28 = 0x%x !!\n", u4tmp); + for (i = 0; i < RF_CHNL_NUM_5G; i++) { + if (channel == rf_chnl_5g[i] && channel <= 140) + index = 0; + } + for (i = 0; i < RF_CHNL_NUM_5G_40M; i++) { + if (channel == rf_chnl_5g_40m[i] && channel <= 140) + index = 1; + } + if (channel == 149 || channel == 155 || channel == 161) + index = 2; + else if (channel == 151 || channel == 153 || channel == 163 + || channel == 165) + index = 3; + else if (channel == 157 || channel == 159) + index = 4; + + if (rtlhal->macphymode == DUALMAC_DUALPHY + && rtlhal->interfaceindex == 1) { + need_pwr_down = rtl92d_phy_enable_anotherphy(hw, false); + rtlhal->during_mac1init_radioa = true; + /* asume no this case */ + if (need_pwr_down) + _rtl92d_phy_enable_rf_env(hw, path, + &u4regvalue); + } + for (i = 0; i < RF_REG_NUM_FOR_C_CUT_5G; i++) { + if (i == 0 && (rtlhal->macphymode == DUALMAC_DUALPHY)) { + rtl_set_rfreg(hw, (enum radio_path)path, + rf_reg_for_c_cut_5g[i], + BRFREGOFFSETMASK, 0xE439D); + } else if (rf_reg_for_c_cut_5g[i] == RF_SYN_G4) { + u4tmp2 = (rf_reg_pram_c_5g[index][i] & + 0x7FF) | (u4tmp << 11); + if (channel == 36) + u4tmp2 &= ~(BIT(7) | BIT(6)); + rtl_set_rfreg(hw, (enum radio_path)path, + rf_reg_for_c_cut_5g[i], + BRFREGOFFSETMASK, u4tmp2); + } else { + rtl_set_rfreg(hw, (enum radio_path)path, + rf_reg_for_c_cut_5g[i], + BRFREGOFFSETMASK, + rf_reg_pram_c_5g[index][i]); + } + RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, + "offset 0x%x value 0x%x path %d index %d readback 0x%x\n", + rf_reg_for_c_cut_5g[i], + rf_reg_pram_c_5g[index][i], + path, index, + rtl_get_rfreg(hw, (enum radio_path)path, + rf_reg_for_c_cut_5g[i], + BRFREGOFFSETMASK)); + } + if (need_pwr_down) + _rtl92d_phy_restore_rf_env(hw, path, &u4regvalue); + if (rtlhal->during_mac1init_radioa) + rtl92d_phy_powerdown_anotherphy(hw, false); + if (channel < 149) + value = 0x07; + else if (channel >= 149) + value = 0x02; + if (channel >= 36 && channel <= 64) + index = 0; + else if (channel >= 100 && channel <= 140) + index = 1; + else + index = 2; + for (rfpath = RF90_PATH_A; rfpath < rtlphy->num_total_rfpath; + rfpath++) { + if (rtlhal->macphymode == DUALMAC_DUALPHY && + rtlhal->interfaceindex == 1) /* MAC 1 5G */ + internal_pa = rtlpriv->efuse.internal_pa_5g[1]; + else + internal_pa = + rtlpriv->efuse.internal_pa_5g[rfpath]; + if (internal_pa) { + for (i = 0; + i < RF_REG_NUM_FOR_C_CUT_5G_INTERNALPA; + i++) { + rtl_set_rfreg(hw, rfpath, + rf_for_c_cut_5g_internal_pa[i], + BRFREGOFFSETMASK, + rf_pram_c_5g_int_pa[index][i]); + RT_TRACE(rtlpriv, COMP_RF, DBG_LOUD, + "offset 0x%x value 0x%x path %d index %d\n", + rf_for_c_cut_5g_internal_pa[i], + rf_pram_c_5g_int_pa[index][i], + rfpath, index); + } + } else { + rtl_set_rfreg(hw, (enum radio_path)rfpath, 0x0B, + mask, value); + } + } + } else if (rtlhal->current_bandtype == BAND_ON_2_4G) { + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "====>2.4G\n"); + u4tmp = curveindex_2g[channel - 1]; + RTPRINT(rtlpriv, FINIT, INIT_IQK, + "ver 3 set RF-B, 2G, 0x28 = 0x%x !!\n", u4tmp); + if (channel == 1 || channel == 2 || channel == 4 || channel == 9 + || channel == 10 || channel == 11 || channel == 12) + index = 0; + else if (channel == 3 || channel == 13 || channel == 14) + index = 1; + else if (channel >= 5 && channel <= 8) + index = 2; + if (rtlhal->macphymode == DUALMAC_DUALPHY) { + path = RF90_PATH_A; + if (rtlhal->interfaceindex == 0) { + need_pwr_down = + rtl92d_phy_enable_anotherphy(hw, true); + rtlhal->during_mac0init_radiob = true; + + if (need_pwr_down) + _rtl92d_phy_enable_rf_env(hw, path, + &u4regvalue); + } + } + for (i = 0; i < RF_REG_NUM_FOR_C_CUT_2G; i++) { + if (rf_reg_for_c_cut_2g[i] == RF_SYN_G7) + rtl_set_rfreg(hw, (enum radio_path)path, + rf_reg_for_c_cut_2g[i], + BRFREGOFFSETMASK, + (rf_reg_param_for_c_cut_2g[index][i] | + BIT(17))); + else + rtl_set_rfreg(hw, (enum radio_path)path, + rf_reg_for_c_cut_2g[i], + BRFREGOFFSETMASK, + rf_reg_param_for_c_cut_2g + [index][i]); + RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, + "offset 0x%x value 0x%x mak 0x%x path %d index %d readback 0x%x\n", + rf_reg_for_c_cut_2g[i], + rf_reg_param_for_c_cut_2g[index][i], + rf_reg_mask_for_c_cut_2g[i], path, index, + rtl_get_rfreg(hw, (enum radio_path)path, + rf_reg_for_c_cut_2g[i], + BRFREGOFFSETMASK)); + } + RTPRINT(rtlpriv, FINIT, INIT_IQK, + "cosa ver 3 set RF-B, 2G, 0x28 = 0x%x !!\n", + rf_syn_g4_for_c_cut_2g | (u4tmp << 11)); + + rtl_set_rfreg(hw, (enum radio_path)path, RF_SYN_G4, + BRFREGOFFSETMASK, + rf_syn_g4_for_c_cut_2g | (u4tmp << 11)); + if (need_pwr_down) + _rtl92d_phy_restore_rf_env(hw, path, &u4regvalue); + if (rtlhal->during_mac0init_radiob) + rtl92d_phy_powerdown_anotherphy(hw, true); + } + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "<====\n"); +} + +u8 rtl92d_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; +} + +#define MAX_TOLERANCE 5 +#define IQK_DELAY_TIME 1 /* ms */ +#define MAX_TOLERANCE_92D 3 + +/* bit0 = 1 => Tx OK, bit1 = 1 => Rx OK */ +static u8 _rtl92d_phy_patha_iqk(struct ieee80211_hw *hw, bool configpathb) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u32 regeac, rege94, rege9c, regea4; + u8 result = 0; + + RTPRINT(rtlpriv, FINIT, INIT_IQK, "Path A IQK!\n"); + /* path-A IQK setting */ + RTPRINT(rtlpriv, FINIT, INIT_IQK, "Path-A IQK setting!\n"); + if (rtlhal->interfaceindex == 0) { + rtl_set_bbreg(hw, 0xe30, BMASKDWORD, 0x10008c1f); + rtl_set_bbreg(hw, 0xe34, BMASKDWORD, 0x10008c1f); + } else { + rtl_set_bbreg(hw, 0xe30, BMASKDWORD, 0x10008c22); + rtl_set_bbreg(hw, 0xe34, BMASKDWORD, 0x10008c22); + } + rtl_set_bbreg(hw, 0xe38, BMASKDWORD, 0x82140102); + rtl_set_bbreg(hw, 0xe3c, BMASKDWORD, 0x28160206); + /* path-B IQK setting */ + if (configpathb) { + rtl_set_bbreg(hw, 0xe50, BMASKDWORD, 0x10008c22); + rtl_set_bbreg(hw, 0xe54, BMASKDWORD, 0x10008c22); + rtl_set_bbreg(hw, 0xe58, BMASKDWORD, 0x82140102); + rtl_set_bbreg(hw, 0xe5c, BMASKDWORD, 0x28160206); + } + /* LO calibration setting */ + RTPRINT(rtlpriv, FINIT, INIT_IQK, "LO calibration setting!\n"); + rtl_set_bbreg(hw, 0xe4c, BMASKDWORD, 0x00462911); + /* One shot, path A LOK & IQK */ + RTPRINT(rtlpriv, FINIT, INIT_IQK, "One shot, path A LOK & IQK!\n"); + rtl_set_bbreg(hw, 0xe48, BMASKDWORD, 0xf9000000); + rtl_set_bbreg(hw, 0xe48, BMASKDWORD, 0xf8000000); + /* delay x ms */ + RTPRINT(rtlpriv, FINIT, INIT_IQK, + "Delay %d ms for One shot, path A LOK & IQK\n", + IQK_DELAY_TIME); + mdelay(IQK_DELAY_TIME); + /* Check failed */ + regeac = rtl_get_bbreg(hw, 0xeac, BMASKDWORD); + RTPRINT(rtlpriv, FINIT, INIT_IQK, "0xeac = 0x%x\n", regeac); + rege94 = rtl_get_bbreg(hw, 0xe94, BMASKDWORD); + RTPRINT(rtlpriv, FINIT, INIT_IQK, "0xe94 = 0x%x\n", rege94); + rege9c = rtl_get_bbreg(hw, 0xe9c, BMASKDWORD); + RTPRINT(rtlpriv, FINIT, INIT_IQK, "0xe9c = 0x%x\n", rege9c); + regea4 = rtl_get_bbreg(hw, 0xea4, BMASKDWORD); + RTPRINT(rtlpriv, FINIT, INIT_IQK, "0xea4 = 0x%x\n", regea4); + if (!(regeac & BIT(28)) && (((rege94 & 0x03FF0000) >> 16) != 0x142) && + (((rege9c & 0x03FF0000) >> 16) != 0x42)) + result |= 0x01; + else /* if Tx not OK, ignore Rx */ + return result; + /* if Tx is OK, check whether Rx is OK */ + if (!(regeac & BIT(27)) && (((regea4 & 0x03FF0000) >> 16) != 0x132) && + (((regeac & 0x03FF0000) >> 16) != 0x36)) + result |= 0x02; + else + RTPRINT(rtlpriv, FINIT, INIT_IQK, "Path A Rx IQK fail!!\n"); + return result; +} + +/* bit0 = 1 => Tx OK, bit1 = 1 => Rx OK */ +static u8 _rtl92d_phy_patha_iqk_5g_normal(struct ieee80211_hw *hw, + bool configpathb) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + u32 regeac, rege94, rege9c, regea4; + u8 result = 0; + u8 i; + u8 retrycount = 2; + u32 TxOKBit = BIT(28), RxOKBit = BIT(27); + + if (rtlhal->interfaceindex == 1) { /* PHY1 */ + TxOKBit = BIT(31); + RxOKBit = BIT(30); + } + RTPRINT(rtlpriv, FINIT, INIT_IQK, "Path A IQK!\n"); + /* path-A IQK setting */ + RTPRINT(rtlpriv, FINIT, INIT_IQK, "Path-A IQK setting!\n"); + rtl_set_bbreg(hw, 0xe30, BMASKDWORD, 0x18008c1f); + rtl_set_bbreg(hw, 0xe34, BMASKDWORD, 0x18008c1f); + rtl_set_bbreg(hw, 0xe38, BMASKDWORD, 0x82140307); + rtl_set_bbreg(hw, 0xe3c, BMASKDWORD, 0x68160960); + /* path-B IQK setting */ + if (configpathb) { + rtl_set_bbreg(hw, 0xe50, BMASKDWORD, 0x18008c2f); + rtl_set_bbreg(hw, 0xe54, BMASKDWORD, 0x18008c2f); + rtl_set_bbreg(hw, 0xe58, BMASKDWORD, 0x82110000); + rtl_set_bbreg(hw, 0xe5c, BMASKDWORD, 0x68110000); + } + /* LO calibration setting */ + RTPRINT(rtlpriv, FINIT, INIT_IQK, "LO calibration setting!\n"); + rtl_set_bbreg(hw, 0xe4c, BMASKDWORD, 0x00462911); + /* path-A PA on */ + rtl_set_bbreg(hw, RFPGA0_XAB_RFINTERFACESW, BMASKDWORD, 0x07000f60); + rtl_set_bbreg(hw, RFPGA0_XA_RFINTERFACEOE, BMASKDWORD, 0x66e60e30); + for (i = 0; i < retrycount; i++) { + /* One shot, path A LOK & IQK */ + RTPRINT(rtlpriv, FINIT, INIT_IQK, + "One shot, path A LOK & IQK!\n"); + rtl_set_bbreg(hw, 0xe48, BMASKDWORD, 0xf9000000); + rtl_set_bbreg(hw, 0xe48, BMASKDWORD, 0xf8000000); + /* delay x ms */ + RTPRINT(rtlpriv, FINIT, INIT_IQK, + "Delay %d ms for One shot, path A LOK & IQK.\n", + IQK_DELAY_TIME); + mdelay(IQK_DELAY_TIME * 10); + /* Check failed */ + regeac = rtl_get_bbreg(hw, 0xeac, BMASKDWORD); + RTPRINT(rtlpriv, FINIT, INIT_IQK, "0xeac = 0x%x\n", regeac); + rege94 = rtl_get_bbreg(hw, 0xe94, BMASKDWORD); + RTPRINT(rtlpriv, FINIT, INIT_IQK, "0xe94 = 0x%x\n", rege94); + rege9c = rtl_get_bbreg(hw, 0xe9c, BMASKDWORD); + RTPRINT(rtlpriv, FINIT, INIT_IQK, "0xe9c = 0x%x\n", rege9c); + regea4 = rtl_get_bbreg(hw, 0xea4, BMASKDWORD); + RTPRINT(rtlpriv, FINIT, INIT_IQK, "0xea4 = 0x%x\n", regea4); + if (!(regeac & TxOKBit) && + (((rege94 & 0x03FF0000) >> 16) != 0x142)) { + result |= 0x01; + } else { /* if Tx not OK, ignore Rx */ + RTPRINT(rtlpriv, FINIT, INIT_IQK, + "Path A Tx IQK fail!!\n"); + continue; + } + + /* if Tx is OK, check whether Rx is OK */ + if (!(regeac & RxOKBit) && + (((regea4 & 0x03FF0000) >> 16) != 0x132)) { + result |= 0x02; + break; + } else { + RTPRINT(rtlpriv, FINIT, INIT_IQK, + "Path A Rx IQK fail!!\n"); + } + } + /* path A PA off */ + rtl_set_bbreg(hw, RFPGA0_XAB_RFINTERFACESW, BMASKDWORD, + rtlphy->iqk_bb_backup[0]); + rtl_set_bbreg(hw, RFPGA0_XA_RFINTERFACEOE, BMASKDWORD, + rtlphy->iqk_bb_backup[1]); + return result; +} + +/* bit0 = 1 => Tx OK, bit1 = 1 => Rx OK */ +static u8 _rtl92d_phy_pathb_iqk(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 regeac, regeb4, regebc, regec4, regecc; + u8 result = 0; + + RTPRINT(rtlpriv, FINIT, INIT_IQK, "Path B IQK!\n"); + /* One shot, path B LOK & IQK */ + RTPRINT(rtlpriv, FINIT, INIT_IQK, "One shot, path A LOK & IQK!\n"); + rtl_set_bbreg(hw, 0xe60, BMASKDWORD, 0x00000002); + rtl_set_bbreg(hw, 0xe60, BMASKDWORD, 0x00000000); + /* delay x ms */ + RTPRINT(rtlpriv, FINIT, INIT_IQK, + "Delay %d ms for One shot, path B LOK & IQK\n", IQK_DELAY_TIME); + mdelay(IQK_DELAY_TIME); + /* Check failed */ + regeac = rtl_get_bbreg(hw, 0xeac, BMASKDWORD); + RTPRINT(rtlpriv, FINIT, INIT_IQK, "0xeac = 0x%x\n", regeac); + regeb4 = rtl_get_bbreg(hw, 0xeb4, BMASKDWORD); + RTPRINT(rtlpriv, FINIT, INIT_IQK, "0xeb4 = 0x%x\n", regeb4); + regebc = rtl_get_bbreg(hw, 0xebc, BMASKDWORD); + RTPRINT(rtlpriv, FINIT, INIT_IQK, "0xebc = 0x%x\n", regebc); + regec4 = rtl_get_bbreg(hw, 0xec4, BMASKDWORD); + RTPRINT(rtlpriv, FINIT, INIT_IQK, "0xec4 = 0x%x\n", regec4); + regecc = rtl_get_bbreg(hw, 0xecc, BMASKDWORD); + RTPRINT(rtlpriv, FINIT, INIT_IQK, "0xecc = 0x%x\n", regecc); + if (!(regeac & BIT(31)) && (((regeb4 & 0x03FF0000) >> 16) != 0x142) && + (((regebc & 0x03FF0000) >> 16) != 0x42)) + result |= 0x01; + else + return result; + if (!(regeac & BIT(30)) && (((regec4 & 0x03FF0000) >> 16) != 0x132) && + (((regecc & 0x03FF0000) >> 16) != 0x36)) + result |= 0x02; + else + RTPRINT(rtlpriv, FINIT, INIT_IQK, "Path B Rx IQK fail!!\n"); + return result; +} + +/* bit0 = 1 => Tx OK, bit1 = 1 => Rx OK */ +static u8 _rtl92d_phy_pathb_iqk_5g_normal(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + u32 regeac, regeb4, regebc, regec4, regecc; + u8 result = 0; + u8 i; + u8 retrycount = 2; + + RTPRINT(rtlpriv, FINIT, INIT_IQK, "Path B IQK!\n"); + /* path-A IQK setting */ + RTPRINT(rtlpriv, FINIT, INIT_IQK, "Path-A IQK setting!\n"); + rtl_set_bbreg(hw, 0xe30, BMASKDWORD, 0x18008c1f); + rtl_set_bbreg(hw, 0xe34, BMASKDWORD, 0x18008c1f); + rtl_set_bbreg(hw, 0xe38, BMASKDWORD, 0x82110000); + rtl_set_bbreg(hw, 0xe3c, BMASKDWORD, 0x68110000); + + /* path-B IQK setting */ + rtl_set_bbreg(hw, 0xe50, BMASKDWORD, 0x18008c2f); + rtl_set_bbreg(hw, 0xe54, BMASKDWORD, 0x18008c2f); + rtl_set_bbreg(hw, 0xe58, BMASKDWORD, 0x82140307); + rtl_set_bbreg(hw, 0xe5c, BMASKDWORD, 0x68160960); + + /* LO calibration setting */ + RTPRINT(rtlpriv, FINIT, INIT_IQK, "LO calibration setting!\n"); + rtl_set_bbreg(hw, 0xe4c, BMASKDWORD, 0x00462911); + + /* path-B PA on */ + rtl_set_bbreg(hw, RFPGA0_XAB_RFINTERFACESW, BMASKDWORD, 0x0f600700); + rtl_set_bbreg(hw, RFPGA0_XB_RFINTERFACEOE, BMASKDWORD, 0x061f0d30); + + for (i = 0; i < retrycount; i++) { + /* One shot, path B LOK & IQK */ + RTPRINT(rtlpriv, FINIT, INIT_IQK, + "One shot, path A LOK & IQK!\n"); + rtl_set_bbreg(hw, 0xe48, BMASKDWORD, 0xfa000000); + rtl_set_bbreg(hw, 0xe48, BMASKDWORD, 0xf8000000); + + /* delay x ms */ + RTPRINT(rtlpriv, FINIT, INIT_IQK, + "Delay %d ms for One shot, path B LOK & IQK.\n", 10); + mdelay(IQK_DELAY_TIME * 10); + + /* Check failed */ + regeac = rtl_get_bbreg(hw, 0xeac, BMASKDWORD); + RTPRINT(rtlpriv, FINIT, INIT_IQK, "0xeac = 0x%x\n", regeac); + regeb4 = rtl_get_bbreg(hw, 0xeb4, BMASKDWORD); + RTPRINT(rtlpriv, FINIT, INIT_IQK, "0xeb4 = 0x%x\n", regeb4); + regebc = rtl_get_bbreg(hw, 0xebc, BMASKDWORD); + RTPRINT(rtlpriv, FINIT, INIT_IQK, "0xebc = 0x%x\n", regebc); + regec4 = rtl_get_bbreg(hw, 0xec4, BMASKDWORD); + RTPRINT(rtlpriv, FINIT, INIT_IQK, "0xec4 = 0x%x\n", regec4); + regecc = rtl_get_bbreg(hw, 0xecc, BMASKDWORD); + RTPRINT(rtlpriv, FINIT, INIT_IQK, "0xecc = 0x%x\n", regecc); + if (!(regeac & BIT(31)) && + (((regeb4 & 0x03FF0000) >> 16) != 0x142)) + result |= 0x01; + else + continue; + if (!(regeac & BIT(30)) && + (((regec4 & 0x03FF0000) >> 16) != 0x132)) { + result |= 0x02; + break; + } else { + RTPRINT(rtlpriv, FINIT, INIT_IQK, + "Path B Rx IQK fail!!\n"); + } + } + + /* path B PA off */ + rtl_set_bbreg(hw, RFPGA0_XAB_RFINTERFACESW, BMASKDWORD, + rtlphy->iqk_bb_backup[0]); + rtl_set_bbreg(hw, RFPGA0_XB_RFINTERFACEOE, BMASKDWORD, + rtlphy->iqk_bb_backup[2]); + return result; +} + +static void _rtl92d_phy_save_adda_registers(struct ieee80211_hw *hw, + u32 *adda_reg, u32 *adda_backup, + u32 regnum) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 i; + + RTPRINT(rtlpriv, FINIT, INIT_IQK, "Save ADDA parameters.\n"); + for (i = 0; i < regnum; i++) + adda_backup[i] = rtl_get_bbreg(hw, adda_reg[i], BMASKDWORD); +} + +static void _rtl92d_phy_save_mac_registers(struct ieee80211_hw *hw, + u32 *macreg, u32 *macbackup) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 i; + + RTPRINT(rtlpriv, FINIT, INIT_IQK, "Save MAC parameters.\n"); + 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 _rtl92d_phy_reload_adda_registers(struct ieee80211_hw *hw, + u32 *adda_reg, u32 *adda_backup, + u32 regnum) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 i; + + RTPRINT(rtlpriv, FINIT, INIT_IQK, + "Reload ADDA power saving parameters !\n"); + for (i = 0; i < regnum; i++) + rtl_set_bbreg(hw, adda_reg[i], BMASKDWORD, adda_backup[i]); +} + +static void _rtl92d_phy_reload_mac_registers(struct ieee80211_hw *hw, + u32 *macreg, u32 *macbackup) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 i; + + RTPRINT(rtlpriv, FINIT, INIT_IQK, "Reload MAC parameters !\n"); + for (i = 0; i < (IQK_MAC_REG_NUM - 1); i++) + rtl_write_byte(rtlpriv, macreg[i], (u8) macbackup[i]); + rtl_write_byte(rtlpriv, macreg[i], macbackup[i]); +} + +static void _rtl92d_phy_path_adda_on(struct ieee80211_hw *hw, + u32 *adda_reg, bool patha_on, bool is2t) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 pathon; + u32 i; + + RTPRINT(rtlpriv, FINIT, INIT_IQK, "ADDA ON.\n"); + pathon = patha_on ? 0x04db25a4 : 0x0b1b25a4; + if (patha_on) + pathon = rtlpriv->rtlhal.interfaceindex == 0 ? + 0x04db25a4 : 0x0b1b25a4; + for (i = 0; i < IQK_ADDA_REG_NUM; i++) + rtl_set_bbreg(hw, adda_reg[i], BMASKDWORD, pathon); +} + +static void _rtl92d_phy_mac_setting_calibration(struct ieee80211_hw *hw, + u32 *macreg, u32 *macbackup) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 i; + + RTPRINT(rtlpriv, FINIT, INIT_IQK, "MAC settings for Calibration.\n"); + rtl_write_byte(rtlpriv, macreg[0], 0x3F); + + for (i = 1; i < (IQK_MAC_REG_NUM - 1); i++) + rtl_write_byte(rtlpriv, macreg[i], (u8)(macbackup[i] & + (~BIT(3)))); + rtl_write_byte(rtlpriv, macreg[i], (u8) (macbackup[i] & (~BIT(5)))); +} + +static void _rtl92d_phy_patha_standby(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + RTPRINT(rtlpriv, FINIT, INIT_IQK, "Path-A standby mode!\n"); + + rtl_set_bbreg(hw, 0xe28, BMASKDWORD, 0x0); + rtl_set_bbreg(hw, RFPGA0_XA_LSSIPARAMETER, BMASKDWORD, 0x00010000); + rtl_set_bbreg(hw, 0xe28, BMASKDWORD, 0x80800000); +} + +static void _rtl92d_phy_pimode_switch(struct ieee80211_hw *hw, bool pi_mode) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 mode; + + RTPRINT(rtlpriv, FINIT, INIT_IQK, + "BB Switch to %s mode!\n", pi_mode ? "PI" : "SI"); + mode = pi_mode ? 0x01000100 : 0x01000000; + rtl_set_bbreg(hw, 0x820, BMASKDWORD, mode); + rtl_set_bbreg(hw, 0x828, BMASKDWORD, mode); +} + +static void _rtl92d_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; + static u32 adda_reg[IQK_ADDA_REG_NUM] = { + RFPGA0_XCD_SWITCHCONTROL, 0xe6c, 0xe70, 0xe74, + 0xe78, 0xe7c, 0xe80, 0xe84, + 0xe88, 0xe8c, 0xed0, 0xed4, + 0xed8, 0xedc, 0xee0, 0xeec + }; + static u32 iqk_mac_reg[IQK_MAC_REG_NUM] = { + 0x522, 0x550, 0x551, 0x040 + }; + static u32 iqk_bb_reg[IQK_BB_REG_NUM] = { + RFPGA0_XAB_RFINTERFACESW, RFPGA0_XA_RFINTERFACEOE, + RFPGA0_XB_RFINTERFACEOE, ROFDM0_TRMUXPAR, + RFPGA0_XCD_RFINTERFACESW, ROFDM0_TRXPATHENABLE, + RFPGA0_RFMOD, RFPGA0_ANALOGPARAMETER4, + ROFDM0_XAAGCCORE1, ROFDM0_XBAGCCORE1 + }; + const u32 retrycount = 2; + u32 bbvalue; + + RTPRINT(rtlpriv, FINIT, INIT_IQK, "IQK for 2.4G :Start!!!\n"); + if (t == 0) { + bbvalue = rtl_get_bbreg(hw, RFPGA0_RFMOD, BMASKDWORD); + RTPRINT(rtlpriv, FINIT, INIT_IQK, "==>0x%08x\n", bbvalue); + RTPRINT(rtlpriv, FINIT, INIT_IQK, "IQ Calibration for %s\n", + is2t ? "2T2R" : "1T1R"); + + /* Save ADDA parameters, turn Path A ADDA on */ + _rtl92d_phy_save_adda_registers(hw, adda_reg, + rtlphy->adda_backup, IQK_ADDA_REG_NUM); + _rtl92d_phy_save_mac_registers(hw, iqk_mac_reg, + rtlphy->iqk_mac_backup); + _rtl92d_phy_save_adda_registers(hw, iqk_bb_reg, + rtlphy->iqk_bb_backup, IQK_BB_REG_NUM); + } + _rtl92d_phy_path_adda_on(hw, adda_reg, true, is2t); + if (t == 0) + rtlphy->rfpi_enable = (u8) rtl_get_bbreg(hw, + RFPGA0_XA_HSSIPARAMETER1, BIT(8)); + + /* Switch BB to PI mode to do IQ Calibration. */ + if (!rtlphy->rfpi_enable) + _rtl92d_phy_pimode_switch(hw, true); + + rtl_set_bbreg(hw, RFPGA0_RFMOD, BIT(24), 0x00); + rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, BMASKDWORD, 0x03a05600); + rtl_set_bbreg(hw, ROFDM0_TRMUXPAR, BMASKDWORD, 0x000800e4); + rtl_set_bbreg(hw, RFPGA0_XCD_RFINTERFACESW, BMASKDWORD, 0x22204000); + rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER4, 0xf00000, 0x0f); + if (is2t) { + rtl_set_bbreg(hw, RFPGA0_XA_LSSIPARAMETER, BMASKDWORD, + 0x00010000); + rtl_set_bbreg(hw, RFPGA0_XB_LSSIPARAMETER, BMASKDWORD, + 0x00010000); + } + /* MAC settings */ + _rtl92d_phy_mac_setting_calibration(hw, iqk_mac_reg, + rtlphy->iqk_mac_backup); + /* Page B init */ + rtl_set_bbreg(hw, 0xb68, BMASKDWORD, 0x0f600000); + if (is2t) + rtl_set_bbreg(hw, 0xb6c, BMASKDWORD, 0x0f600000); + /* IQ calibration setting */ + RTPRINT(rtlpriv, FINIT, INIT_IQK, "IQK setting!\n"); + rtl_set_bbreg(hw, 0xe28, BMASKDWORD, 0x80800000); + rtl_set_bbreg(hw, 0xe40, BMASKDWORD, 0x01007c00); + rtl_set_bbreg(hw, 0xe44, BMASKDWORD, 0x01004800); + for (i = 0; i < retrycount; i++) { + patha_ok = _rtl92d_phy_patha_iqk(hw, is2t); + if (patha_ok == 0x03) { + RTPRINT(rtlpriv, FINIT, INIT_IQK, + "Path A IQK Success!!\n"); + result[t][0] = (rtl_get_bbreg(hw, 0xe94, BMASKDWORD) & + 0x3FF0000) >> 16; + result[t][1] = (rtl_get_bbreg(hw, 0xe9c, BMASKDWORD) & + 0x3FF0000) >> 16; + result[t][2] = (rtl_get_bbreg(hw, 0xea4, BMASKDWORD) & + 0x3FF0000) >> 16; + result[t][3] = (rtl_get_bbreg(hw, 0xeac, BMASKDWORD) & + 0x3FF0000) >> 16; + break; + } else if (i == (retrycount - 1) && patha_ok == 0x01) { + /* Tx IQK OK */ + RTPRINT(rtlpriv, FINIT, INIT_IQK, + "Path A IQK Only Tx Success!!\n"); + + result[t][0] = (rtl_get_bbreg(hw, 0xe94, BMASKDWORD) & + 0x3FF0000) >> 16; + result[t][1] = (rtl_get_bbreg(hw, 0xe9c, BMASKDWORD) & + 0x3FF0000) >> 16; + } + } + if (0x00 == patha_ok) + RTPRINT(rtlpriv, FINIT, INIT_IQK, "Path A IQK failed!!\n"); + if (is2t) { + _rtl92d_phy_patha_standby(hw); + /* Turn Path B ADDA on */ + _rtl92d_phy_path_adda_on(hw, adda_reg, false, is2t); + for (i = 0; i < retrycount; i++) { + pathb_ok = _rtl92d_phy_pathb_iqk(hw); + if (pathb_ok == 0x03) { + RTPRINT(rtlpriv, FINIT, INIT_IQK, + "Path B IQK Success!!\n"); + result[t][4] = (rtl_get_bbreg(hw, 0xeb4, + BMASKDWORD) & 0x3FF0000) >> 16; + result[t][5] = (rtl_get_bbreg(hw, 0xebc, + BMASKDWORD) & 0x3FF0000) >> 16; + result[t][6] = (rtl_get_bbreg(hw, 0xec4, + BMASKDWORD) & 0x3FF0000) >> 16; + result[t][7] = (rtl_get_bbreg(hw, 0xecc, + BMASKDWORD) & 0x3FF0000) >> 16; + break; + } else if (i == (retrycount - 1) && pathb_ok == 0x01) { + /* Tx IQK OK */ + RTPRINT(rtlpriv, FINIT, INIT_IQK, + "Path B Only Tx IQK Success!!\n"); + result[t][4] = (rtl_get_bbreg(hw, 0xeb4, + BMASKDWORD) & 0x3FF0000) >> 16; + result[t][5] = (rtl_get_bbreg(hw, 0xebc, + BMASKDWORD) & 0x3FF0000) >> 16; + } + } + if (0x00 == pathb_ok) + RTPRINT(rtlpriv, FINIT, INIT_IQK, + "Path B IQK failed!!\n"); + } + + /* Back to BB mode, load original value */ + RTPRINT(rtlpriv, FINIT, INIT_IQK, + "IQK:Back to BB mode, load original value!\n"); + + rtl_set_bbreg(hw, 0xe28, BMASKDWORD, 0); + if (t != 0) { + /* Switch back BB to SI mode after finish IQ Calibration. */ + if (!rtlphy->rfpi_enable) + _rtl92d_phy_pimode_switch(hw, false); + /* Reload ADDA power saving parameters */ + _rtl92d_phy_reload_adda_registers(hw, adda_reg, + rtlphy->adda_backup, IQK_ADDA_REG_NUM); + /* Reload MAC parameters */ + _rtl92d_phy_reload_mac_registers(hw, iqk_mac_reg, + rtlphy->iqk_mac_backup); + if (is2t) + _rtl92d_phy_reload_adda_registers(hw, iqk_bb_reg, + rtlphy->iqk_bb_backup, + IQK_BB_REG_NUM); + else + _rtl92d_phy_reload_adda_registers(hw, iqk_bb_reg, + rtlphy->iqk_bb_backup, + IQK_BB_REG_NUM - 1); + /* load 0xe30 IQC default value */ + rtl_set_bbreg(hw, 0xe30, BMASKDWORD, 0x01008c00); + rtl_set_bbreg(hw, 0xe34, BMASKDWORD, 0x01008c00); + } + RTPRINT(rtlpriv, FINIT, INIT_IQK, "<==\n"); +} + +static void _rtl92d_phy_iq_calibrate_5g_normal(struct ieee80211_hw *hw, + long result[][8], u8 t) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_hal *rtlhal = &(rtlpriv->rtlhal); + u8 patha_ok, pathb_ok; + static u32 adda_reg[IQK_ADDA_REG_NUM] = { + RFPGA0_XCD_SWITCHCONTROL, 0xe6c, 0xe70, 0xe74, + 0xe78, 0xe7c, 0xe80, 0xe84, + 0xe88, 0xe8c, 0xed0, 0xed4, + 0xed8, 0xedc, 0xee0, 0xeec + }; + static u32 iqk_mac_reg[IQK_MAC_REG_NUM] = { + 0x522, 0x550, 0x551, 0x040 + }; + static u32 iqk_bb_reg[IQK_BB_REG_NUM] = { + RFPGA0_XAB_RFINTERFACESW, RFPGA0_XA_RFINTERFACEOE, + RFPGA0_XB_RFINTERFACEOE, ROFDM0_TRMUXPAR, + RFPGA0_XCD_RFINTERFACESW, ROFDM0_TRXPATHENABLE, + RFPGA0_RFMOD, RFPGA0_ANALOGPARAMETER4, + ROFDM0_XAAGCCORE1, ROFDM0_XBAGCCORE1 + }; + u32 bbvalue; + bool is2t = IS_92D_SINGLEPHY(rtlhal->version); + + /* Note: IQ calibration must be performed after loading + * PHY_REG.txt , and radio_a, radio_b.txt */ + + RTPRINT(rtlpriv, FINIT, INIT_IQK, "IQK for 5G NORMAL:Start!!!\n"); + mdelay(IQK_DELAY_TIME * 20); + if (t == 0) { + bbvalue = rtl_get_bbreg(hw, RFPGA0_RFMOD, BMASKDWORD); + RTPRINT(rtlpriv, FINIT, INIT_IQK, "==>0x%08x\n", bbvalue); + RTPRINT(rtlpriv, FINIT, INIT_IQK, "IQ Calibration for %s\n", + is2t ? "2T2R" : "1T1R"); + /* Save ADDA parameters, turn Path A ADDA on */ + _rtl92d_phy_save_adda_registers(hw, adda_reg, + rtlphy->adda_backup, + IQK_ADDA_REG_NUM); + _rtl92d_phy_save_mac_registers(hw, iqk_mac_reg, + rtlphy->iqk_mac_backup); + if (is2t) + _rtl92d_phy_save_adda_registers(hw, iqk_bb_reg, + rtlphy->iqk_bb_backup, + IQK_BB_REG_NUM); + else + _rtl92d_phy_save_adda_registers(hw, iqk_bb_reg, + rtlphy->iqk_bb_backup, + IQK_BB_REG_NUM - 1); + } + _rtl92d_phy_path_adda_on(hw, adda_reg, true, is2t); + /* MAC settings */ + _rtl92d_phy_mac_setting_calibration(hw, iqk_mac_reg, + rtlphy->iqk_mac_backup); + if (t == 0) + rtlphy->rfpi_enable = (u8) rtl_get_bbreg(hw, + RFPGA0_XA_HSSIPARAMETER1, BIT(8)); + /* Switch BB to PI mode to do IQ Calibration. */ + if (!rtlphy->rfpi_enable) + _rtl92d_phy_pimode_switch(hw, true); + rtl_set_bbreg(hw, RFPGA0_RFMOD, BIT(24), 0x00); + rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, BMASKDWORD, 0x03a05600); + rtl_set_bbreg(hw, ROFDM0_TRMUXPAR, BMASKDWORD, 0x000800e4); + rtl_set_bbreg(hw, RFPGA0_XCD_RFINTERFACESW, BMASKDWORD, 0x22208000); + rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER4, 0xf00000, 0x0f); + + /* Page B init */ + rtl_set_bbreg(hw, 0xb68, BMASKDWORD, 0x0f600000); + if (is2t) + rtl_set_bbreg(hw, 0xb6c, BMASKDWORD, 0x0f600000); + /* IQ calibration setting */ + RTPRINT(rtlpriv, FINIT, INIT_IQK, "IQK setting!\n"); + rtl_set_bbreg(hw, 0xe28, BMASKDWORD, 0x80800000); + rtl_set_bbreg(hw, 0xe40, BMASKDWORD, 0x10007c00); + rtl_set_bbreg(hw, 0xe44, BMASKDWORD, 0x01004800); + patha_ok = _rtl92d_phy_patha_iqk_5g_normal(hw, is2t); + if (patha_ok == 0x03) { + RTPRINT(rtlpriv, FINIT, INIT_IQK, "Path A IQK Success!!\n"); + result[t][0] = (rtl_get_bbreg(hw, 0xe94, BMASKDWORD) & + 0x3FF0000) >> 16; + result[t][1] = (rtl_get_bbreg(hw, 0xe9c, BMASKDWORD) & + 0x3FF0000) >> 16; + result[t][2] = (rtl_get_bbreg(hw, 0xea4, BMASKDWORD) & + 0x3FF0000) >> 16; + result[t][3] = (rtl_get_bbreg(hw, 0xeac, BMASKDWORD) & + 0x3FF0000) >> 16; + } else if (patha_ok == 0x01) { /* Tx IQK OK */ + RTPRINT(rtlpriv, FINIT, INIT_IQK, + "Path A IQK Only Tx Success!!\n"); + + result[t][0] = (rtl_get_bbreg(hw, 0xe94, BMASKDWORD) & + 0x3FF0000) >> 16; + result[t][1] = (rtl_get_bbreg(hw, 0xe9c, BMASKDWORD) & + 0x3FF0000) >> 16; + } else { + RTPRINT(rtlpriv, FINIT, INIT_IQK, "Path A IQK Fail!!\n"); + } + if (is2t) { + /* _rtl92d_phy_patha_standby(hw); */ + /* Turn Path B ADDA on */ + _rtl92d_phy_path_adda_on(hw, adda_reg, false, is2t); + pathb_ok = _rtl92d_phy_pathb_iqk_5g_normal(hw); + if (pathb_ok == 0x03) { + RTPRINT(rtlpriv, FINIT, INIT_IQK, + "Path B IQK Success!!\n"); + result[t][4] = (rtl_get_bbreg(hw, 0xeb4, BMASKDWORD) & + 0x3FF0000) >> 16; + result[t][5] = (rtl_get_bbreg(hw, 0xebc, BMASKDWORD) & + 0x3FF0000) >> 16; + result[t][6] = (rtl_get_bbreg(hw, 0xec4, BMASKDWORD) & + 0x3FF0000) >> 16; + result[t][7] = (rtl_get_bbreg(hw, 0xecc, BMASKDWORD) & + 0x3FF0000) >> 16; + } else if (pathb_ok == 0x01) { /* Tx IQK OK */ + RTPRINT(rtlpriv, FINIT, INIT_IQK, + "Path B Only Tx IQK Success!!\n"); + result[t][4] = (rtl_get_bbreg(hw, 0xeb4, BMASKDWORD) & + 0x3FF0000) >> 16; + result[t][5] = (rtl_get_bbreg(hw, 0xebc, BMASKDWORD) & + 0x3FF0000) >> 16; + } else { + RTPRINT(rtlpriv, FINIT, INIT_IQK, + "Path B IQK failed!!\n"); + } + } + + /* Back to BB mode, load original value */ + RTPRINT(rtlpriv, FINIT, INIT_IQK, + "IQK:Back to BB mode, load original value!\n"); + rtl_set_bbreg(hw, 0xe28, BMASKDWORD, 0); + if (t != 0) { + if (is2t) + _rtl92d_phy_reload_adda_registers(hw, iqk_bb_reg, + rtlphy->iqk_bb_backup, + IQK_BB_REG_NUM); + else + _rtl92d_phy_reload_adda_registers(hw, iqk_bb_reg, + rtlphy->iqk_bb_backup, + IQK_BB_REG_NUM - 1); + /* Reload MAC parameters */ + _rtl92d_phy_reload_mac_registers(hw, iqk_mac_reg, + rtlphy->iqk_mac_backup); + /* Switch back BB to SI mode after finish IQ Calibration. */ + if (!rtlphy->rfpi_enable) + _rtl92d_phy_pimode_switch(hw, false); + /* Reload ADDA power saving parameters */ + _rtl92d_phy_reload_adda_registers(hw, adda_reg, + rtlphy->adda_backup, + IQK_ADDA_REG_NUM); + } + RTPRINT(rtlpriv, FINIT, INIT_IQK, "<==\n"); +} + +static bool _rtl92d_phy_simularity_compare(struct ieee80211_hw *hw, + long result[][8], u8 c1, u8 c2) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = &(rtlpriv->rtlhal); + u32 i, j, diff, sim_bitmap, bound; + u8 final_candidate[2] = {0xFF, 0xFF}; /* for path A and path B */ + bool bresult = true; + bool is2t = IS_92D_SINGLEPHY(rtlhal->version); + + if (is2t) + bound = 8; + else + bound = 4; + sim_bitmap = 0; + for (i = 0; i < bound; i++) { + diff = (result[c1][i] > result[c2][i]) ? (result[c1][i] - + result[c2][i]) : (result[c2][i] - result[c1][i]); + if (diff > MAX_TOLERANCE_92D) { + if ((i == 2 || i == 6) && !sim_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 + sim_bitmap = sim_bitmap | (1 << i); + } else { + sim_bitmap = sim_bitmap | (1 << i); + } + } + } + if (sim_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; + } + if (!(sim_bitmap & 0x0F)) { /* path A OK */ + for (i = 0; i < 4; i++) + result[3][i] = result[c1][i]; + } else if (!(sim_bitmap & 0x03)) { /* path A, Tx OK */ + for (i = 0; i < 2; i++) + result[3][i] = result[c1][i]; + } + if (!(sim_bitmap & 0xF0) && is2t) { /* path B OK */ + for (i = 4; i < 8; i++) + result[3][i] = result[c1][i]; + } else if (!(sim_bitmap & 0x30)) { /* path B, Tx OK */ + for (i = 4; i < 6; i++) + result[3][i] = result[c1][i]; + } + return false; +} + +static void _rtl92d_phy_patha_fill_iqk_matrix(struct ieee80211_hw *hw, + bool iqk_ok, long result[][8], + u8 final_candidate, bool txonly) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = &(rtlpriv->rtlhal); + u32 oldval_0, val_x, tx0_a, reg; + long val_y, tx0_c; + bool is2t = IS_92D_SINGLEPHY(rtlhal->version) || + rtlhal->macphymode == DUALMAC_DUALPHY; + + RTPRINT(rtlpriv, FINIT, INIT_IQK, + "Path A IQ Calibration %s !\n", iqk_ok ? "Success" : "Failed"); + if (final_candidate == 0xFF) { + return; + } else if (iqk_ok) { + oldval_0 = (rtl_get_bbreg(hw, ROFDM0_XATxIQIMBALANCE, + BMASKDWORD) >> 22) & 0x3FF; /* OFDM0_D */ + val_x = result[final_candidate][0]; + if ((val_x & 0x00000200) != 0) + val_x = val_x | 0xFFFFFC00; + tx0_a = (val_x * oldval_0) >> 8; + RTPRINT(rtlpriv, FINIT, INIT_IQK, + "X = 0x%x, tx0_a = 0x%x, oldval_0 0x%x\n", + val_x, tx0_a, oldval_0); + rtl_set_bbreg(hw, ROFDM0_XATxIQIMBALANCE, 0x3FF, tx0_a); + rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD, BIT(24), + ((val_x * oldval_0 >> 7) & 0x1)); + val_y = result[final_candidate][1]; + if ((val_y & 0x00000200) != 0) + val_y = val_y | 0xFFFFFC00; + /* path B IQK result + 3 */ + if (rtlhal->interfaceindex == 1 && + rtlhal->current_bandtype == BAND_ON_5G) + val_y += 3; + tx0_c = (val_y * oldval_0) >> 8; + RTPRINT(rtlpriv, FINIT, INIT_IQK, + "Y = 0x%lx, tx0_c = 0x%lx\n", + val_y, tx0_c); + rtl_set_bbreg(hw, ROFDM0_XCTxAFE, 0xF0000000, + ((tx0_c & 0x3C0) >> 6)); + rtl_set_bbreg(hw, ROFDM0_XATxIQIMBALANCE, 0x003F0000, + (tx0_c & 0x3F)); + if (is2t) + rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD, BIT(26), + ((val_y * oldval_0 >> 7) & 0x1)); + RTPRINT(rtlpriv, FINIT, INIT_IQK, "0xC80 = 0x%x\n", + rtl_get_bbreg(hw, ROFDM0_XATxIQIMBALANCE, + BMASKDWORD)); + if (txonly) { + RTPRINT(rtlpriv, FINIT, INIT_IQK, "only Tx OK\n"); + 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, 0xca0, 0xF0000000, reg); + } +} + +static void _rtl92d_phy_pathb_fill_iqk_matrix(struct ieee80211_hw *hw, + bool iqk_ok, long result[][8], u8 final_candidate, bool txonly) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = &(rtlpriv->rtlhal); + u32 oldval_1, val_x, tx1_a, reg; + long val_y, tx1_c; + + RTPRINT(rtlpriv, FINIT, INIT_IQK, "Path B IQ Calibration %s !\n", + iqk_ok ? "Success" : "Failed"); + if (final_candidate == 0xFF) { + return; + } else if (iqk_ok) { + oldval_1 = (rtl_get_bbreg(hw, ROFDM0_XBTxIQIMBALANCE, + BMASKDWORD) >> 22) & 0x3FF; + val_x = result[final_candidate][4]; + if ((val_x & 0x00000200) != 0) + val_x = val_x | 0xFFFFFC00; + tx1_a = (val_x * oldval_1) >> 8; + RTPRINT(rtlpriv, FINIT, INIT_IQK, "X = 0x%x, tx1_a = 0x%x\n", + val_x, tx1_a); + rtl_set_bbreg(hw, ROFDM0_XBTxIQIMBALANCE, 0x3FF, tx1_a); + rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD, BIT(28), + ((val_x * oldval_1 >> 7) & 0x1)); + val_y = result[final_candidate][5]; + if ((val_y & 0x00000200) != 0) + val_y = val_y | 0xFFFFFC00; + if (rtlhal->current_bandtype == BAND_ON_5G) + val_y += 3; + tx1_c = (val_y * oldval_1) >> 8; + RTPRINT(rtlpriv, FINIT, INIT_IQK, "Y = 0x%lx, tx1_c = 0x%lx\n", + val_y, tx1_c); + 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(30), + ((val_y * oldval_1 >> 7) & 0x1)); + if (txonly) + 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, 0x0000F000, reg); + } +} + +void rtl92d_phy_iq_calibrate(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_hal *rtlhal = &(rtlpriv->rtlhal); + long result[4][8]; + u8 i, final_candidate, indexforchannel; + bool patha_ok, pathb_ok; + long rege94, rege9c, regea4, regeac, regeb4; + long regebc, regec4, regecc, regtmp = 0; + bool is12simular, is13simular, is23simular; + unsigned long flag = 0; + + RTPRINT(rtlpriv, FINIT, INIT_IQK, + "IQK:Start!!!channel %d\n", rtlphy->current_channel); + for (i = 0; i < 8; i++) { + result[0][i] = 0; + result[1][i] = 0; + result[2][i] = 0; + result[3][i] = 0; + } + final_candidate = 0xff; + patha_ok = false; + pathb_ok = false; + is12simular = false; + is23simular = false; + is13simular = false; + RTPRINT(rtlpriv, FINIT, INIT_IQK, + "IQK !!!currentband %d\n", rtlhal->current_bandtype); + rtl92d_acquire_cckandrw_pagea_ctl(hw, &flag); + for (i = 0; i < 3; i++) { + if (rtlhal->current_bandtype == BAND_ON_5G) { + _rtl92d_phy_iq_calibrate_5g_normal(hw, result, i); + } else if (rtlhal->current_bandtype == BAND_ON_2_4G) { + if (IS_92D_SINGLEPHY(rtlhal->version)) + _rtl92d_phy_iq_calibrate(hw, result, i, true); + else + _rtl92d_phy_iq_calibrate(hw, result, i, false); + } + if (i == 1) { + is12simular = _rtl92d_phy_simularity_compare(hw, result, + 0, 1); + if (is12simular) { + final_candidate = 0; + break; + } + } + if (i == 2) { + is13simular = _rtl92d_phy_simularity_compare(hw, result, + 0, 2); + if (is13simular) { + final_candidate = 0; + break; + } + is23simular = _rtl92d_phy_simularity_compare(hw, result, + 1, 2); + if (is23simular) { + final_candidate = 1; + } else { + for (i = 0; i < 8; i++) + regtmp += result[3][i]; + + if (regtmp != 0) + final_candidate = 3; + else + final_candidate = 0xFF; + } + } + } + rtl92d_release_cckandrw_pagea_ctl(hw, &flag); + for (i = 0; i < 4; i++) { + rege94 = result[i][0]; + rege9c = result[i][1]; + regea4 = result[i][2]; + regeac = result[i][3]; + regeb4 = result[i][4]; + regebc = result[i][5]; + regec4 = result[i][6]; + regecc = result[i][7]; + RTPRINT(rtlpriv, FINIT, INIT_IQK, + "IQK: rege94=%lx rege9c=%lx regea4=%lx regeac=%lx regeb4=%lx regebc=%lx regec4=%lx regecc=%lx\n", + rege94, rege9c, regea4, regeac, regeb4, regebc, regec4, + regecc); + } + if (final_candidate != 0xff) { + rtlphy->reg_e94 = rege94 = result[final_candidate][0]; + rtlphy->reg_e9c = rege9c = result[final_candidate][1]; + regea4 = result[final_candidate][2]; + regeac = result[final_candidate][3]; + rtlphy->reg_eb4 = regeb4 = result[final_candidate][4]; + rtlphy->reg_ebc = regebc = result[final_candidate][5]; + regec4 = result[final_candidate][6]; + regecc = result[final_candidate][7]; + RTPRINT(rtlpriv, FINIT, INIT_IQK, + "IQK: final_candidate is %x\n", final_candidate); + RTPRINT(rtlpriv, FINIT, INIT_IQK, + "IQK: rege94=%lx rege9c=%lx regea4=%lx regeac=%lx regeb4=%lx regebc=%lx regec4=%lx regecc=%lx\n", + rege94, rege9c, regea4, regeac, regeb4, regebc, regec4, + regecc); + patha_ok = pathb_ok = true; + } else { + rtlphy->reg_e94 = rtlphy->reg_eb4 = 0x100; /* X default value */ + rtlphy->reg_e9c = rtlphy->reg_ebc = 0x0; /* Y default value */ + } + if ((rege94 != 0) /*&&(regea4 != 0) */) + _rtl92d_phy_patha_fill_iqk_matrix(hw, patha_ok, result, + final_candidate, (regea4 == 0)); + if (IS_92D_SINGLEPHY(rtlhal->version)) { + if ((regeb4 != 0) /*&&(regec4 != 0) */) + _rtl92d_phy_pathb_fill_iqk_matrix(hw, pathb_ok, result, + final_candidate, (regec4 == 0)); + } + if (final_candidate != 0xFF) { + indexforchannel = rtl92d_get_rightchnlplace_for_iqk( + rtlphy->current_channel); + + for (i = 0; i < IQK_MATRIX_REG_NUM; i++) + rtlphy->iqk_matrix_regsetting[indexforchannel]. + value[0][i] = result[final_candidate][i]; + rtlphy->iqk_matrix_regsetting[indexforchannel].iqk_done = + true; + + RT_TRACE(rtlpriv, COMP_SCAN | COMP_MLME, DBG_LOUD, + "IQK OK indexforchannel %d\n", indexforchannel); + } +} + +void rtl92d_phy_reload_iqk_setting(struct ieee80211_hw *hw, u8 channel) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_hal *rtlhal = &(rtlpriv->rtlhal); + u8 indexforchannel; + + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "channel %d\n", channel); + /*------Do IQK for normal chip and test chip 5G band------- */ + indexforchannel = rtl92d_get_rightchnlplace_for_iqk(channel); + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "indexforchannel %d done %d\n", + indexforchannel, + rtlphy->iqk_matrix_regsetting[indexforchannel].iqk_done); + if (0 && !rtlphy->iqk_matrix_regsetting[indexforchannel].iqk_done && + rtlphy->need_iqk) { + /* Re Do IQK. */ + RT_TRACE(rtlpriv, COMP_SCAN | COMP_INIT, DBG_LOUD, + "Do IQK Matrix reg for channel:%d....\n", channel); + rtl92d_phy_iq_calibrate(hw); + } else { + /* Just load the value. */ + /* 2G band just load once. */ + if (((!rtlhal->load_imrandiqk_setting_for2g) && + indexforchannel == 0) || indexforchannel > 0) { + RT_TRACE(rtlpriv, COMP_SCAN, DBG_LOUD, + "Just Read IQK Matrix reg for channel:%d....\n", + channel); + if ((rtlphy->iqk_matrix_regsetting[indexforchannel]. + value[0] != NULL) + /*&&(regea4 != 0) */) + _rtl92d_phy_patha_fill_iqk_matrix(hw, true, + rtlphy->iqk_matrix_regsetting[ + indexforchannel].value, 0, + (rtlphy->iqk_matrix_regsetting[ + indexforchannel].value[0][2] == 0)); + if (IS_92D_SINGLEPHY(rtlhal->version)) { + if ((rtlphy->iqk_matrix_regsetting[ + indexforchannel].value[0][4] != 0) + /*&&(regec4 != 0) */) + _rtl92d_phy_pathb_fill_iqk_matrix(hw, + true, + rtlphy->iqk_matrix_regsetting[ + indexforchannel].value, 0, + (rtlphy->iqk_matrix_regsetting[ + indexforchannel].value[0][6] + == 0)); + } + } + } + rtlphy->need_iqk = false; + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "<====\n"); +} + +static u32 _rtl92d_phy_get_abs(u32 val1, u32 val2) +{ + u32 ret; + + if (val1 >= val2) + ret = val1 - val2; + else + ret = val2 - val1; + return ret; +} + +static bool _rtl92d_is_legal_5g_channel(struct ieee80211_hw *hw, u8 channel) +{ + + int i; + u8 channel_5g[45] = { + 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 + }; + + for (i = 0; i < sizeof(channel_5g); i++) + if (channel == channel_5g[i]) + return true; + return false; +} + +static void _rtl92d_phy_calc_curvindex(struct ieee80211_hw *hw, + u32 *targetchnl, u32 * curvecount_val, + bool is5g, u32 *curveindex) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 smallest_abs_val = 0xffffffff, u4tmp; + u8 i, j; + u8 chnl_num = is5g ? TARGET_CHNL_NUM_5G : TARGET_CHNL_NUM_2G; + + for (i = 0; i < chnl_num; i++) { + if (is5g && !_rtl92d_is_legal_5g_channel(hw, i + 1)) + continue; + curveindex[i] = 0; + for (j = 0; j < (CV_CURVE_CNT * 2); j++) { + u4tmp = _rtl92d_phy_get_abs(targetchnl[i], + curvecount_val[j]); + + if (u4tmp < smallest_abs_val) { + curveindex[i] = j; + smallest_abs_val = u4tmp; + } + } + smallest_abs_val = 0xffffffff; + RTPRINT(rtlpriv, FINIT, INIT_IQK, "curveindex[%d] = %x\n", + i, curveindex[i]); + } +} + +static void _rtl92d_phy_reload_lck_setting(struct ieee80211_hw *hw, + u8 channel) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 erfpath = rtlpriv->rtlhal.current_bandtype == + BAND_ON_5G ? RF90_PATH_A : + IS_92D_SINGLEPHY(rtlpriv->rtlhal.version) ? + RF90_PATH_B : RF90_PATH_A; + u32 u4tmp = 0, u4regvalue = 0; + bool bneed_powerdown_radio = false; + + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "path %d\n", erfpath); + RTPRINT(rtlpriv, FINIT, INIT_IQK, "band type = %d\n", + rtlpriv->rtlhal.current_bandtype); + RTPRINT(rtlpriv, FINIT, INIT_IQK, "channel = %d\n", channel); + if (rtlpriv->rtlhal.current_bandtype == BAND_ON_5G) {/* Path-A for 5G */ + u4tmp = curveindex_5g[channel-1]; + RTPRINT(rtlpriv, FINIT, INIT_IQK, + "ver 1 set RF-A, 5G, 0x28 = 0x%ulx !!\n", u4tmp); + if (rtlpriv->rtlhal.macphymode == DUALMAC_DUALPHY && + rtlpriv->rtlhal.interfaceindex == 1) { + bneed_powerdown_radio = + rtl92d_phy_enable_anotherphy(hw, false); + rtlpriv->rtlhal.during_mac1init_radioa = true; + /* asume no this case */ + if (bneed_powerdown_radio) + _rtl92d_phy_enable_rf_env(hw, erfpath, + &u4regvalue); + } + rtl_set_rfreg(hw, erfpath, RF_SYN_G4, 0x3f800, u4tmp); + if (bneed_powerdown_radio) + _rtl92d_phy_restore_rf_env(hw, erfpath, &u4regvalue); + if (rtlpriv->rtlhal.during_mac1init_radioa) + rtl92d_phy_powerdown_anotherphy(hw, false); + } else if (rtlpriv->rtlhal.current_bandtype == BAND_ON_2_4G) { + u4tmp = curveindex_2g[channel-1]; + RTPRINT(rtlpriv, FINIT, INIT_IQK, + "ver 3 set RF-B, 2G, 0x28 = 0x%ulx !!\n", u4tmp); + if (rtlpriv->rtlhal.macphymode == DUALMAC_DUALPHY && + rtlpriv->rtlhal.interfaceindex == 0) { + bneed_powerdown_radio = + rtl92d_phy_enable_anotherphy(hw, true); + rtlpriv->rtlhal.during_mac0init_radiob = true; + if (bneed_powerdown_radio) + _rtl92d_phy_enable_rf_env(hw, erfpath, + &u4regvalue); + } + rtl_set_rfreg(hw, erfpath, RF_SYN_G4, 0x3f800, u4tmp); + RTPRINT(rtlpriv, FINIT, INIT_IQK, + "ver 3 set RF-B, 2G, 0x28 = 0x%ulx !!\n", + rtl_get_rfreg(hw, erfpath, RF_SYN_G4, 0x3f800)); + if (bneed_powerdown_radio) + _rtl92d_phy_restore_rf_env(hw, erfpath, &u4regvalue); + if (rtlpriv->rtlhal.during_mac0init_radiob) + rtl92d_phy_powerdown_anotherphy(hw, true); + } + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "<====\n"); +} + +static void _rtl92d_phy_lc_calibrate_sw(struct ieee80211_hw *hw, bool is2t) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = &(rtlpriv->rtlhal); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + u8 tmpreg, index, rf_mode[2]; + u8 path = is2t ? 2 : 1; + u8 i; + u32 u4tmp, offset; + u32 curvecount_val[CV_CURVE_CNT * 2] = {0}; + u16 timeout = 800, timecount = 0; + + /* Check continuous TX and Packet TX */ + tmpreg = rtl_read_byte(rtlpriv, 0xd03); + /* if Deal with contisuous TX case, disable all continuous TX */ + /* if Deal with Packet TX case, block all queues */ + if ((tmpreg & 0x70) != 0) + rtl_write_byte(rtlpriv, 0xd03, tmpreg & 0x8F); + else + rtl_write_byte(rtlpriv, REG_TXPAUSE, 0xFF); + rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER4, 0xF00000, 0x0F); + for (index = 0; index < path; index++) { + /* 1. Read original RF mode */ + offset = index == 0 ? ROFDM0_XAAGCCORE1 : ROFDM0_XBAGCCORE1; + rf_mode[index] = rtl_read_byte(rtlpriv, offset); + /* 2. Set RF mode = standby mode */ + rtl_set_rfreg(hw, (enum radio_path)index, RF_AC, + BRFREGOFFSETMASK, 0x010000); + if (rtlpci->init_ready) { + /* switch CV-curve control by LC-calibration */ + rtl_set_rfreg(hw, (enum radio_path)index, RF_SYN_G7, + BIT(17), 0x0); + /* 4. Set LC calibration begin */ + rtl_set_rfreg(hw, (enum radio_path)index, RF_CHNLBW, + 0x08000, 0x01); + } + u4tmp = rtl_get_rfreg(hw, (enum radio_path)index, RF_SYN_G6, + BRFREGOFFSETMASK); + while ((!(u4tmp & BIT(11))) && timecount <= timeout) { + mdelay(50); + timecount += 50; + u4tmp = rtl_get_rfreg(hw, (enum radio_path)index, + RF_SYN_G6, BRFREGOFFSETMASK); + } + RTPRINT(rtlpriv, FINIT, INIT_IQK, + "PHY_LCK finish delay for %d ms=2\n", timecount); + u4tmp = rtl_get_rfreg(hw, index, RF_SYN_G4, BRFREGOFFSETMASK); + if (index == 0 && rtlhal->interfaceindex == 0) { + RTPRINT(rtlpriv, FINIT, INIT_IQK, + "path-A / 5G LCK\n"); + } else { + RTPRINT(rtlpriv, FINIT, INIT_IQK, + "path-B / 2.4G LCK\n"); + } + memset(&curvecount_val[0], 0, CV_CURVE_CNT * 2); + /* Set LC calibration off */ + rtl_set_rfreg(hw, (enum radio_path)index, RF_CHNLBW, + 0x08000, 0x0); + RTPRINT(rtlpriv, FINIT, INIT_IQK, "set RF 0x18[15] = 0\n"); + /* save Curve-counting number */ + for (i = 0; i < CV_CURVE_CNT; i++) { + u32 readval = 0, readval2 = 0; + rtl_set_rfreg(hw, (enum radio_path)index, 0x3F, + 0x7f, i); + + rtl_set_rfreg(hw, (enum radio_path)index, 0x4D, + BRFREGOFFSETMASK, 0x0); + readval = rtl_get_rfreg(hw, (enum radio_path)index, + 0x4F, BRFREGOFFSETMASK); + curvecount_val[2 * i + 1] = (readval & 0xfffe0) >> 5; + /* reg 0x4f [4:0] */ + /* reg 0x50 [19:10] */ + readval2 = rtl_get_rfreg(hw, (enum radio_path)index, + 0x50, 0xffc00); + curvecount_val[2 * i] = (((readval & 0x1F) << 10) | + readval2); + } + if (index == 0 && rtlhal->interfaceindex == 0) + _rtl92d_phy_calc_curvindex(hw, targetchnl_5g, + curvecount_val, + true, curveindex_5g); + else + _rtl92d_phy_calc_curvindex(hw, targetchnl_2g, + curvecount_val, + false, curveindex_2g); + /* switch CV-curve control mode */ + rtl_set_rfreg(hw, (enum radio_path)index, RF_SYN_G7, + BIT(17), 0x1); + } + + /* Restore original situation */ + for (index = 0; index < path; index++) { + offset = index == 0 ? ROFDM0_XAAGCCORE1 : ROFDM0_XBAGCCORE1; + rtl_write_byte(rtlpriv, offset, 0x50); + rtl_write_byte(rtlpriv, offset, rf_mode[index]); + } + if ((tmpreg & 0x70) != 0) + rtl_write_byte(rtlpriv, 0xd03, tmpreg); + else /*Deal with Packet TX case */ + rtl_write_byte(rtlpriv, REG_TXPAUSE, 0x00); + rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER4, 0xF00000, 0x00); + _rtl92d_phy_reload_lck_setting(hw, rtlpriv->phy.current_channel); +} + +static void _rtl92d_phy_lc_calibrate(struct ieee80211_hw *hw, bool is2t) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + RTPRINT(rtlpriv, FINIT, INIT_IQK, "cosa PHY_LCK ver=2\n"); + _rtl92d_phy_lc_calibrate_sw(hw, is2t); +} + +void rtl92d_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); + if (IS_92D_SINGLEPHY(rtlhal->version)) { + _rtl92d_phy_lc_calibrate(hw, true); + } else { + /* For 1T1R */ + _rtl92d_phy_lc_calibrate(hw, false); + } + rtlphy->lck_inprogress = false; + RTPRINT(rtlpriv, FINIT, INIT_IQK, "LCK:Finish!!!\n"); +} + +void rtl92d_phy_ap_calibrate(struct ieee80211_hw *hw, char delta) +{ + return; +} + +static bool _rtl92d_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; +} + +void rtl92d_phy_reset_iqk_result(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + u8 i; + + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "settings regs %d default regs %d\n", + (int)(sizeof(rtlphy->iqk_matrix_regsetting) / + sizeof(struct iqk_matrix_regs)), + IQK_MATRIX_REG_NUM); + /* 0xe94, 0xe9c, 0xea4, 0xeac, 0xeb4, 0xebc, 0xec4, 0xecc */ + for (i = 0; i < IQK_MATRIX_SETTINGS_NUM; i++) { + rtlphy->iqk_matrix_regsetting[i].value[0][0] = 0x100; + rtlphy->iqk_matrix_regsetting[i].value[0][2] = 0x100; + rtlphy->iqk_matrix_regsetting[i].value[0][4] = 0x100; + rtlphy->iqk_matrix_regsetting[i].value[0][6] = 0x100; + rtlphy->iqk_matrix_regsetting[i].value[0][1] = 0x0; + rtlphy->iqk_matrix_regsetting[i].value[0][3] = 0x0; + rtlphy->iqk_matrix_regsetting[i].value[0][5] = 0x0; + rtlphy->iqk_matrix_regsetting[i].value[0][7] = 0x0; + rtlphy->iqk_matrix_regsetting[i].iqk_done = false; + } +} + +static bool _rtl92d_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; + _rtl92d_phy_set_sw_chnl_cmdarray(precommoncmd, precommoncmdcnt++, + MAX_PRECMD_CNT, + CMDID_SET_TXPOWEROWER_LEVEL, 0, 0, 0); + _rtl92d_phy_set_sw_chnl_cmdarray(precommoncmd, precommoncmdcnt++, + MAX_PRECMD_CNT, CMDID_END, 0, 0, 0); + postcommoncmdcnt = 0; + _rtl92d_phy_set_sw_chnl_cmdarray(postcommoncmd, postcommoncmdcnt++, + MAX_POSTCMD_CNT, CMDID_END, 0, 0, 0); + rfdependcmdcnt = 0; + _rtl92d_phy_set_sw_chnl_cmdarray(rfdependcmd, rfdependcmdcnt++, + MAX_RFDEPENDCMD_CNT, CMDID_RF_WRITEREG, + RF_CHNLBW, channel, 0); + _rtl92d_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; + } + if (currentcmd->cmdid == CMDID_END) { + if ((*stage) == 2) { + return true; + } else { + (*stage)++; + (*step) = 0; + continue; + } + } + switch (currentcmd->cmdid) { + case CMDID_SET_TXPOWEROWER_LEVEL: + rtl92d_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] & + 0xffffff00) | currentcmd->para2); + if (rtlpriv->rtlhal.current_bandtype == + BAND_ON_5G) { + if (currentcmd->para2 > 99) + rtlphy->rfreg_chnlval[rfpath] = + rtlphy->rfreg_chnlval + [rfpath] | (BIT(18)); + else + rtlphy->rfreg_chnlval[rfpath] = + rtlphy->rfreg_chnlval + [rfpath] & (~BIT(18)); + rtlphy->rfreg_chnlval[rfpath] |= + (BIT(16) | BIT(8)); + } else { + rtlphy->rfreg_chnlval[rfpath] &= + ~(BIT(8) | BIT(16) | BIT(18)); + } + rtl_set_rfreg(hw, (enum radio_path)rfpath, + currentcmd->para1, + BRFREGOFFSETMASK, + rtlphy->rfreg_chnlval[rfpath]); + _rtl92d_phy_reload_imr_setting(hw, channel, + rfpath); + } + _rtl92d_phy_switch_rf_setting(hw, channel); + /* do IQK when all parameters are ready */ + rtl92d_phy_reload_iqk_setting(hw, channel); + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "switch case not processed\n"); + break; + } + break; + } while (true); + (*delay) = currentcmd->msdelay; + (*step)++; + return false; +} + +u8 rtl92d_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)); + u32 delay; + u32 timeout = 1000, timecount = 0; + u8 channel = rtlphy->current_channel; + u32 ret_value; + + if (rtlphy->sw_chnl_inprogress) + return 0; + if (rtlphy->set_bwmode_inprogress) + return 0; + + if ((is_hal_stop(rtlhal)) || (RT_CANNOT_IO(hw))) { + RT_TRACE(rtlpriv, COMP_CHAN, DBG_LOUD, + "sw_chnl_inprogress false driver sleep or unload\n"); + return 0; + } + while (rtlphy->lck_inprogress && timecount < timeout) { + mdelay(50); + timecount += 50; + } + if (rtlhal->macphymode == SINGLEMAC_SINGLEPHY && + rtlhal->bandset == BAND_ON_BOTH) { + ret_value = rtl_get_bbreg(hw, RFPGA0_XAB_RFPARAMETER, + BMASKDWORD); + if (rtlphy->current_channel > 14 && !(ret_value & BIT(0))) + rtl92d_phy_switch_wirelessband(hw, BAND_ON_5G); + else if (rtlphy->current_channel <= 14 && (ret_value & BIT(0))) + rtl92d_phy_switch_wirelessband(hw, BAND_ON_2_4G); + } + switch (rtlhal->current_bandtype) { + case BAND_ON_5G: + /* Get first channel error when change between + * 5G and 2.4G band. */ + if (channel <= 14) + return 0; + RT_ASSERT((channel > 14), "5G but channel<=14\n"); + break; + case BAND_ON_2_4G: + /* Get first channel error when change between + * 5G and 2.4G band. */ + if (channel > 14) + return 0; + RT_ASSERT((channel <= 14), "2G but channel>14\n"); + break; + default: + RT_ASSERT(false, "Invalid WirelessMode(%#x)!!\n", + rtlpriv->mac80211.mode); + break; + } + rtlphy->sw_chnl_inprogress = true; + if (channel == 0) + channel = 1; + rtlphy->sw_chnl_stage = 0; + rtlphy->sw_chnl_step = 0; + RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE, + "switch to channel%d\n", rtlphy->current_channel); + + do { + if (!rtlphy->sw_chnl_inprogress) + break; + if (!_rtl92d_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(rtlpriv, COMP_SCAN, DBG_TRACE, "<==\n"); + rtlphy->sw_chnl_inprogress = false; + return 1; +} + +static void rtl92d_phy_set_io(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + + RT_TRACE(rtlpriv, 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: + de_digtable.cur_igvalue = rtlphy->initgain_backup.xaagccore1; + rtl92d_dm_write_dig(hw); + rtl92d_phy_set_txpower_level(hw, rtlphy->current_channel); + break; + case IO_CMD_PAUSE_DM_BY_SCAN: + rtlphy->initgain_backup.xaagccore1 = de_digtable.cur_igvalue; + de_digtable.cur_igvalue = 0x37; + rtl92d_dm_write_dig(hw); + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "switch case not processed\n"); + break; + } + rtlphy->set_io_inprogress = false; + RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE, "<---(%#x)\n", + rtlphy->current_io_type); +} + +bool rtl92d_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 postprocessing = false; + + RT_TRACE(rtlpriv, 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(rtlpriv, COMP_CMD, DBG_TRACE, + "[IO CMD] Resume DM after scan\n"); + postprocessing = true; + break; + case IO_CMD_PAUSE_DM_BY_SCAN: + RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE, + "[IO CMD] Pause DM before scan\n"); + postprocessing = true; + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "switch case not processed\n"); + break; + } + } while (false); + if (postprocessing && !rtlphy->set_io_inprogress) { + rtlphy->set_io_inprogress = true; + rtlphy->current_io_type = iotype; + } else { + return false; + } + rtl92d_phy_set_io(hw); + RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE, "<--IO Type(%#x)\n", iotype); + return true; +} + +static void _rtl92d_phy_set_rfon(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + /* a. SYS_CLKR 0x08[11] = 1 restore MAC clock */ + /* b. SPS_CTRL 0x11[7:0] = 0x2b */ + if (rtlpriv->rtlhal.macphymode == SINGLEMAC_SINGLEPHY) + rtl_write_byte(rtlpriv, REG_SPS0_CTRL, 0x2b); + /* c. For PCIE: SYS_FUNC_EN 0x02[7:0] = 0xE3 enable BB TRX function */ + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE3); + /* RF_ON_EXCEP(d~g): */ + /* d. APSD_CTRL 0x600[7:0] = 0x00 */ + rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x00); + /* e. SYS_FUNC_EN 0x02[7:0] = 0xE2 reset BB TRX function again */ + /* f. SYS_FUNC_EN 0x02[7:0] = 0xE3 enable BB TRX function*/ + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE2); + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE3); + /* g. txpause 0x522[7:0] = 0x00 enable mac tx queue */ + rtl_write_byte(rtlpriv, REG_TXPAUSE, 0x00); +} + +static void _rtl92d_phy_set_rfsleep(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 u4btmp; + u8 delay = 5; + + /* a. TXPAUSE 0x522[7:0] = 0xFF Pause MAC TX queue */ + rtl_write_byte(rtlpriv, REG_TXPAUSE, 0xFF); + /* b. RF path 0 offset 0x00 = 0x00 disable RF */ + rtl_set_rfreg(hw, RF90_PATH_A, 0x00, BRFREGOFFSETMASK, 0x00); + /* c. APSD_CTRL 0x600[7:0] = 0x40 */ + rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x40); + /* d. APSD_CTRL 0x600[7:0] = 0x00 + * APSD_CTRL 0x600[7:0] = 0x00 + * RF path 0 offset 0x00 = 0x00 + * APSD_CTRL 0x600[7:0] = 0x40 + * */ + u4btmp = rtl_get_rfreg(hw, RF90_PATH_A, 0, BRFREGOFFSETMASK); + while (u4btmp != 0 && delay > 0) { + rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x0); + rtl_set_rfreg(hw, RF90_PATH_A, 0x00, BRFREGOFFSETMASK, 0x00); + rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x40); + u4btmp = rtl_get_rfreg(hw, RF90_PATH_A, 0, BRFREGOFFSETMASK); + delay--; + } + if (delay == 0) { + /* Jump out the LPS turn off sequence to RF_ON_EXCEP */ + 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); + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + "Fail !!! Switch RF timeout\n"); + return; + } + /* e. For PCIE: SYS_FUNC_EN 0x02[7:0] = 0xE2 reset BB TRX function */ + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE2); + /* f. SPS_CTRL 0x11[7:0] = 0x22 */ + if (rtlpriv->rtlhal.macphymode == SINGLEMAC_SINGLEPHY) + rtl_write_byte(rtlpriv, REG_SPS0_CTRL, 0x22); + /* g. SYS_CLKR 0x08[11] = 0 gated MAC clock */ +} + +bool rtl92d_phy_set_rf_power_state(struct ieee80211_hw *hw, + enum rf_pwrstate rfpwr_state) +{ + + bool bresult = true; + 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)); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + u8 i, queue_id; + struct rtl8192_tx_ring *ring = NULL; + + if (rfpwr_state == ppsc->rfpwr_state) + return false; + switch (rfpwr_state) { + case ERFON: + if ((ppsc->rfpwr_state == ERFOFF) && + RT_IN_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC)) { + bool rtstatus; + u32 InitializeCount = 0; + do { + InitializeCount++; + RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG, + "IPS Set eRf nic enable\n"); + rtstatus = rtl_ps_enable_nic(hw); + } while (!rtstatus && (InitializeCount < 10)); + + RT_CLEAR_PS_LEVEL(ppsc, + RT_RF_OFF_LEVL_HALT_NIC); + } else { + RT_TRACE(rtlpriv, COMP_POWER, DBG_DMESG, + "awake, sleeped:%d ms state_inap:%x\n", + jiffies_to_msecs(jiffies - + ppsc->last_sleep_jiffies), + rtlpriv->psc.state_inap); + ppsc->last_awake_jiffies = jiffies; + _rtl92d_phy_set_rfon(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: + if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_HALT_NIC) { + RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG, + "IPS Set eRf nic disable\n"); + 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) + return false; + + 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 == BEACON_QUEUE) { + queue_id++; + continue; + } else if (rtlpci->pdev->current_state != PCI_D0) { + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + "eRf Off/Sleep: %d times TcbBusyQueue[%d] !=0 but lower power state!\n", + i + 1, queue_id); + break; + } else { + RT_TRACE(rtlpriv, 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(rtlpriv, COMP_ERR, DBG_WARNING, + "ERFOFF: %d times TcbBusyQueue[%d] = %d !\n", + MAX_DOZE_WAITING_TIMES_9x, queue_id, + skb_queue_len(&ring->queue)); + break; + } + } + RT_TRACE(rtlpriv, COMP_POWER, DBG_DMESG, + "Set rfsleep awaked:%d ms\n", + jiffies_to_msecs(jiffies - ppsc->last_awake_jiffies)); + RT_TRACE(rtlpriv, COMP_POWER, DBG_DMESG, + "sleep awaked:%d ms state_inap:%x\n", + jiffies_to_msecs(jiffies - + ppsc->last_awake_jiffies), + rtlpriv->psc.state_inap); + ppsc->last_sleep_jiffies = jiffies; + _rtl92d_phy_set_rfsleep(hw); + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "switch case not processed\n"); + bresult = false; + break; + } + if (bresult) + ppsc->rfpwr_state = rfpwr_state; + return bresult; +} + +void rtl92d_phy_config_macphymode(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u8 offset = REG_MAC_PHY_CTRL_NORMAL; + + switch (rtlhal->macphymode) { + case DUALMAC_DUALPHY: + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "MacPhyMode: DUALMAC_DUALPHY\n"); + rtl_write_byte(rtlpriv, offset, 0xF3); + break; + case SINGLEMAC_SINGLEPHY: + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "MacPhyMode: SINGLEMAC_SINGLEPHY\n"); + rtl_write_byte(rtlpriv, offset, 0xF4); + break; + case DUALMAC_SINGLEPHY: + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "MacPhyMode: DUALMAC_SINGLEPHY\n"); + rtl_write_byte(rtlpriv, offset, 0xF1); + break; + } +} + +void rtl92d_phy_config_macphymode_info(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); + + switch (rtlhal->macphymode) { + case DUALMAC_SINGLEPHY: + rtlphy->rf_type = RF_2T2R; + rtlhal->version |= CHIP_92D_SINGLEPHY; + rtlhal->bandset = BAND_ON_BOTH; + rtlhal->current_bandtype = BAND_ON_2_4G; + break; + + case SINGLEMAC_SINGLEPHY: + rtlphy->rf_type = RF_2T2R; + rtlhal->version |= CHIP_92D_SINGLEPHY; + rtlhal->bandset = BAND_ON_BOTH; + rtlhal->current_bandtype = BAND_ON_2_4G; + break; + + case DUALMAC_DUALPHY: + rtlphy->rf_type = RF_1T1R; + rtlhal->version &= (~CHIP_92D_SINGLEPHY); + /* Now we let MAC0 run on 5G band. */ + if (rtlhal->interfaceindex == 0) { + rtlhal->bandset = BAND_ON_5G; + rtlhal->current_bandtype = BAND_ON_5G; + } else { + rtlhal->bandset = BAND_ON_2_4G; + rtlhal->current_bandtype = BAND_ON_2_4G; + } + break; + default: + break; + } +} + +u8 rtl92d_get_chnlgroup_fromarray(u8 chnl) +{ + u8 group; + u8 channel_info[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 + }; + + if (channel_info[chnl] <= 3) + group = 0; + else if (channel_info[chnl] <= 9) + group = 1; + else if (channel_info[chnl] <= 14) + group = 2; + else if (channel_info[chnl] <= 44) + group = 3; + else if (channel_info[chnl] <= 54) + group = 4; + else if (channel_info[chnl] <= 64) + group = 5; + else if (channel_info[chnl] <= 112) + group = 6; + else if (channel_info[chnl] <= 126) + group = 7; + else if (channel_info[chnl] <= 140) + group = 8; + else if (channel_info[chnl] <= 153) + group = 9; + else if (channel_info[chnl] <= 159) + group = 10; + else + group = 11; + return group; +} + +void rtl92d_phy_set_poweron(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + unsigned long flags; + u8 value8; + u16 i; + u32 mac_reg = (rtlhal->interfaceindex == 0 ? REG_MAC0 : REG_MAC1); + + /* notice fw know band status 0x81[1]/0x53[1] = 0: 5G, 1: 2G */ + if (rtlhal->current_bandtype == BAND_ON_2_4G) { + value8 = rtl_read_byte(rtlpriv, mac_reg); + value8 |= BIT(1); + rtl_write_byte(rtlpriv, mac_reg, value8); + } else { + value8 = rtl_read_byte(rtlpriv, mac_reg); + value8 &= (~BIT(1)); + rtl_write_byte(rtlpriv, mac_reg, value8); + } + + if (rtlhal->macphymode == SINGLEMAC_SINGLEPHY) { + value8 = rtl_read_byte(rtlpriv, REG_MAC0); + rtl_write_byte(rtlpriv, REG_MAC0, value8 | MAC0_ON); + } else { + spin_lock_irqsave(&globalmutex_power, flags); + if (rtlhal->interfaceindex == 0) { + value8 = rtl_read_byte(rtlpriv, REG_MAC0); + rtl_write_byte(rtlpriv, REG_MAC0, value8 | MAC0_ON); + } else { + value8 = rtl_read_byte(rtlpriv, REG_MAC1); + rtl_write_byte(rtlpriv, REG_MAC1, value8 | MAC1_ON); + } + value8 = rtl_read_byte(rtlpriv, REG_POWER_OFF_IN_PROCESS); + spin_unlock_irqrestore(&globalmutex_power, flags); + for (i = 0; i < 200; i++) { + if ((value8 & BIT(7)) == 0) { + break; + } else { + udelay(500); + spin_lock_irqsave(&globalmutex_power, flags); + value8 = rtl_read_byte(rtlpriv, + REG_POWER_OFF_IN_PROCESS); + spin_unlock_irqrestore(&globalmutex_power, + flags); + } + } + if (i == 200) + RT_ASSERT(false, "Another mac power off over time\n"); + } +} + +void rtl92d_phy_config_maccoexist_rfpage(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + switch (rtlpriv->rtlhal.macphymode) { + case DUALMAC_DUALPHY: + rtl_write_byte(rtlpriv, REG_DMC, 0x0); + rtl_write_byte(rtlpriv, REG_RX_PKT_LIMIT, 0x08); + rtl_write_word(rtlpriv, REG_TRXFF_BNDY + 2, 0x13ff); + break; + case DUALMAC_SINGLEPHY: + rtl_write_byte(rtlpriv, REG_DMC, 0xf8); + rtl_write_byte(rtlpriv, REG_RX_PKT_LIMIT, 0x08); + rtl_write_word(rtlpriv, REG_TRXFF_BNDY + 2, 0x13ff); + break; + case SINGLEMAC_SINGLEPHY: + rtl_write_byte(rtlpriv, REG_DMC, 0x0); + rtl_write_byte(rtlpriv, REG_RX_PKT_LIMIT, 0x10); + rtl_write_word(rtlpriv, (REG_TRXFF_BNDY + 2), 0x27FF); + break; + default: + break; + } +} + +void rtl92d_update_bbrf_configuration(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_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + u8 rfpath, i; + + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "==>\n"); + /* r_select_5G for path_A/B 0 for 2.4G, 1 for 5G */ + if (rtlhal->current_bandtype == BAND_ON_2_4G) { + /* r_select_5G for path_A/B,0x878 */ + rtl_set_bbreg(hw, RFPGA0_XAB_RFPARAMETER, BIT(0), 0x0); + rtl_set_bbreg(hw, RFPGA0_XAB_RFPARAMETER, BIT(15), 0x0); + if (rtlhal->macphymode != DUALMAC_DUALPHY) { + rtl_set_bbreg(hw, RFPGA0_XAB_RFPARAMETER, BIT(16), 0x0); + rtl_set_bbreg(hw, RFPGA0_XAB_RFPARAMETER, BIT(31), 0x0); + } + /* rssi_table_select:index 0 for 2.4G.1~3 for 5G,0xc78 */ + rtl_set_bbreg(hw, ROFDM0_AGCRSSITABLE, BIT(6) | BIT(7), 0x0); + /* fc_area 0xd2c */ + rtl_set_bbreg(hw, ROFDM1_CFOTRACKING, BIT(14) | BIT(13), 0x0); + /* 5G LAN ON */ + rtl_set_bbreg(hw, 0xB30, 0x00F00000, 0xa); + /* TX BB gain shift*1,Just for testchip,0xc80,0xc88 */ + rtl_set_bbreg(hw, ROFDM0_XATxIQIMBALANCE, BMASKDWORD, + 0x40000100); + rtl_set_bbreg(hw, ROFDM0_XBTxIQIMBALANCE, BMASKDWORD, + 0x40000100); + if (rtlhal->macphymode == DUALMAC_DUALPHY) { + rtl_set_bbreg(hw, RFPGA0_XAB_RFINTERFACESW, + BIT(10) | BIT(6) | BIT(5), + ((rtlefuse->eeprom_c9 & BIT(3)) >> 3) | + (rtlefuse->eeprom_c9 & BIT(1)) | + ((rtlefuse->eeprom_cc & BIT(1)) << 4)); + rtl_set_bbreg(hw, RFPGA0_XA_RFINTERFACEOE, + BIT(10) | BIT(6) | BIT(5), + ((rtlefuse->eeprom_c9 & BIT(2)) >> 2) | + ((rtlefuse->eeprom_c9 & BIT(0)) << 1) | + ((rtlefuse->eeprom_cc & BIT(0)) << 5)); + rtl_set_bbreg(hw, RFPGA0_XAB_RFPARAMETER, BIT(15), 0); + } else { + rtl_set_bbreg(hw, RFPGA0_XAB_RFINTERFACESW, + BIT(26) | BIT(22) | BIT(21) | BIT(10) | + BIT(6) | BIT(5), + ((rtlefuse->eeprom_c9 & BIT(3)) >> 3) | + (rtlefuse->eeprom_c9 & BIT(1)) | + ((rtlefuse->eeprom_cc & BIT(1)) << 4) | + ((rtlefuse->eeprom_c9 & BIT(7)) << 9) | + ((rtlefuse->eeprom_c9 & BIT(5)) << 12) | + ((rtlefuse->eeprom_cc & BIT(3)) << 18)); + rtl_set_bbreg(hw, RFPGA0_XA_RFINTERFACEOE, + BIT(10) | BIT(6) | BIT(5), + ((rtlefuse->eeprom_c9 & BIT(2)) >> 2) | + ((rtlefuse->eeprom_c9 & BIT(0)) << 1) | + ((rtlefuse->eeprom_cc & BIT(0)) << 5)); + rtl_set_bbreg(hw, RFPGA0_XB_RFINTERFACEOE, + BIT(10) | BIT(6) | BIT(5), + ((rtlefuse->eeprom_c9 & BIT(6)) >> 6) | + ((rtlefuse->eeprom_c9 & BIT(4)) >> 3) | + ((rtlefuse->eeprom_cc & BIT(2)) << 3)); + rtl_set_bbreg(hw, RFPGA0_XAB_RFPARAMETER, + BIT(31) | BIT(15), 0); + } + /* 1.5V_LDO */ + } else { + /* r_select_5G for path_A/B */ + rtl_set_bbreg(hw, RFPGA0_XAB_RFPARAMETER, BIT(0), 0x1); + rtl_set_bbreg(hw, RFPGA0_XAB_RFPARAMETER, BIT(15), 0x1); + if (rtlhal->macphymode != DUALMAC_DUALPHY) { + rtl_set_bbreg(hw, RFPGA0_XAB_RFPARAMETER, BIT(16), 0x1); + rtl_set_bbreg(hw, RFPGA0_XAB_RFPARAMETER, BIT(31), 0x1); + } + /* rssi_table_select:index 0 for 2.4G.1~3 for 5G */ + rtl_set_bbreg(hw, ROFDM0_AGCRSSITABLE, BIT(6) | BIT(7), 0x1); + /* fc_area */ + rtl_set_bbreg(hw, ROFDM1_CFOTRACKING, BIT(14) | BIT(13), 0x1); + /* 5G LAN ON */ + rtl_set_bbreg(hw, 0xB30, 0x00F00000, 0x0); + /* TX BB gain shift,Just for testchip,0xc80,0xc88 */ + if (rtlefuse->internal_pa_5g[0]) + rtl_set_bbreg(hw, ROFDM0_XATxIQIMBALANCE, BMASKDWORD, + 0x2d4000b5); + else + rtl_set_bbreg(hw, ROFDM0_XATxIQIMBALANCE, BMASKDWORD, + 0x20000080); + if (rtlefuse->internal_pa_5g[1]) + rtl_set_bbreg(hw, ROFDM0_XBTxIQIMBALANCE, BMASKDWORD, + 0x2d4000b5); + else + rtl_set_bbreg(hw, ROFDM0_XBTxIQIMBALANCE, BMASKDWORD, + 0x20000080); + if (rtlhal->macphymode == DUALMAC_DUALPHY) { + rtl_set_bbreg(hw, RFPGA0_XAB_RFINTERFACESW, + BIT(10) | BIT(6) | BIT(5), + (rtlefuse->eeprom_cc & BIT(5))); + rtl_set_bbreg(hw, RFPGA0_XA_RFINTERFACEOE, BIT(10), + ((rtlefuse->eeprom_cc & BIT(4)) >> 4)); + rtl_set_bbreg(hw, RFPGA0_XAB_RFPARAMETER, BIT(15), + (rtlefuse->eeprom_cc & BIT(4)) >> 4); + } else { + rtl_set_bbreg(hw, RFPGA0_XAB_RFINTERFACESW, + BIT(26) | BIT(22) | BIT(21) | BIT(10) | + BIT(6) | BIT(5), + (rtlefuse->eeprom_cc & BIT(5)) | + ((rtlefuse->eeprom_cc & BIT(7)) << 14)); + rtl_set_bbreg(hw, RFPGA0_XA_RFINTERFACEOE, BIT(10), + ((rtlefuse->eeprom_cc & BIT(4)) >> 4)); + rtl_set_bbreg(hw, RFPGA0_XB_RFINTERFACEOE, BIT(10), + ((rtlefuse->eeprom_cc & BIT(6)) >> 6)); + rtl_set_bbreg(hw, RFPGA0_XAB_RFPARAMETER, + BIT(31) | BIT(15), + ((rtlefuse->eeprom_cc & BIT(4)) >> 4) | + ((rtlefuse->eeprom_cc & BIT(6)) << 10)); + } + } + /* update IQK related settings */ + rtl_set_bbreg(hw, ROFDM0_XARXIQIMBALANCE, BMASKDWORD, 0x40000100); + rtl_set_bbreg(hw, ROFDM0_XBRXIQIMBALANCE, BMASKDWORD, 0x40000100); + rtl_set_bbreg(hw, ROFDM0_XCTxAFE, 0xF0000000, 0x00); + rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD, BIT(30) | BIT(28) | + BIT(26) | BIT(24), 0x00); + rtl_set_bbreg(hw, ROFDM0_XDTxAFE, 0xF0000000, 0x00); + rtl_set_bbreg(hw, 0xca0, 0xF0000000, 0x00); + rtl_set_bbreg(hw, ROFDM0_AGCRSSITABLE, 0x0000F000, 0x00); + + /* Update RF */ + for (rfpath = RF90_PATH_A; rfpath < rtlphy->num_total_rfpath; + rfpath++) { + if (rtlhal->current_bandtype == BAND_ON_2_4G) { + /* MOD_AG for RF paht_A 0x18 BIT8,BIT16 */ + rtl_set_rfreg(hw, rfpath, RF_CHNLBW, BIT(8) | BIT(16) | + BIT(18), 0); + /* RF0x0b[16:14] =3b'111 */ + rtl_set_rfreg(hw, (enum radio_path)rfpath, 0x0B, + 0x1c000, 0x07); + } else { + /* MOD_AG for RF paht_A 0x18 BIT8,BIT16 */ + rtl_set_rfreg(hw, rfpath, RF_CHNLBW, BIT(8) | + BIT(16) | BIT(18), + (BIT(16) | BIT(8)) >> 8); + } + } + /* Update for all band. */ + /* DMDP */ + if (rtlphy->rf_type == RF_1T1R) { + /* Use antenna 0,0xc04,0xd04 */ + rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, BMASKBYTE0, 0x11); + rtl_set_bbreg(hw, ROFDM1_TRXPATHENABLE, BDWORD, 0x1); + + /* enable ad/da clock1 for dual-phy reg0x888 */ + if (rtlhal->interfaceindex == 0) { + rtl_set_bbreg(hw, RFPGA0_ADDALLOCKEN, BIT(12) | + BIT(13), 0x3); + } else { + rtl92d_phy_enable_anotherphy(hw, false); + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "MAC1 use DBI to update 0x888\n"); + /* 0x888 */ + rtl92de_write_dword_dbi(hw, RFPGA0_ADDALLOCKEN, + rtl92de_read_dword_dbi(hw, + RFPGA0_ADDALLOCKEN, + BIT(3)) | BIT(12) | BIT(13), + BIT(3)); + rtl92d_phy_powerdown_anotherphy(hw, false); + } + } else { + /* Single PHY */ + /* Use antenna 0 & 1,0xc04,0xd04 */ + rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, BMASKBYTE0, 0x33); + rtl_set_bbreg(hw, ROFDM1_TRXPATHENABLE, BDWORD, 0x3); + /* disable ad/da clock1,0x888 */ + rtl_set_bbreg(hw, RFPGA0_ADDALLOCKEN, BIT(12) | BIT(13), 0); + } + for (rfpath = RF90_PATH_A; rfpath < rtlphy->num_total_rfpath; + rfpath++) { + rtlphy->rfreg_chnlval[rfpath] = rtl_get_rfreg(hw, rfpath, + RF_CHNLBW, BRFREGOFFSETMASK); + rtlphy->reg_rf3c[rfpath] = rtl_get_rfreg(hw, rfpath, 0x3C, + BRFREGOFFSETMASK); + } + for (i = 0; i < 2; i++) + RT_TRACE(rtlpriv, COMP_RF, DBG_LOUD, "RF 0x18 = 0x%x\n", + rtlphy->rfreg_chnlval[i]); + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "<==\n"); + +} + +bool rtl92d_phy_check_poweroff(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u8 u1btmp; + unsigned long flags; + + if (rtlhal->macphymode == SINGLEMAC_SINGLEPHY) { + u1btmp = rtl_read_byte(rtlpriv, REG_MAC0); + rtl_write_byte(rtlpriv, REG_MAC0, u1btmp & (~MAC0_ON)); + return true; + } + spin_lock_irqsave(&globalmutex_power, flags); + if (rtlhal->interfaceindex == 0) { + u1btmp = rtl_read_byte(rtlpriv, REG_MAC0); + rtl_write_byte(rtlpriv, REG_MAC0, u1btmp & (~MAC0_ON)); + u1btmp = rtl_read_byte(rtlpriv, REG_MAC1); + u1btmp &= MAC1_ON; + } else { + u1btmp = rtl_read_byte(rtlpriv, REG_MAC1); + rtl_write_byte(rtlpriv, REG_MAC1, u1btmp & (~MAC1_ON)); + u1btmp = rtl_read_byte(rtlpriv, REG_MAC0); + u1btmp &= MAC0_ON; + } + if (u1btmp) { + spin_unlock_irqrestore(&globalmutex_power, flags); + return false; + } + u1btmp = rtl_read_byte(rtlpriv, REG_POWER_OFF_IN_PROCESS); + u1btmp |= BIT(7); + rtl_write_byte(rtlpriv, REG_POWER_OFF_IN_PROCESS, u1btmp); + spin_unlock_irqrestore(&globalmutex_power, flags); + return true; +} diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/phy.h b/drivers/net/wireless/rtlwifi/rtl8192de/phy.h new file mode 100644 index 00000000..f074952b --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192de/phy.h @@ -0,0 +1,178 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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 __RTL92D_PHY_H__ +#define __RTL92D_PHY_H__ + +#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 MAX_TOLERANCE 5 +#define IQK_DELAY_TIME 1 + +#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 ANTENNA_DIVERSITY_VALUE 0x80 +#define MAX_TXPWR_IDX_NMODE_92S 63 +#define RESET_CNT_LIMIT 3 + +#define IQK_ADDA_REG_NUM 16 +#define IQK_BB_REG_NUM 10 +#define IQK_BB_REG_NUM_test 6 +#define IQK_MAC_REG_NUM 4 +#define RX_INDEX_MAPPING_NUM 15 + +#define IQK_DELAY_TIME 1 + +#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 + +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 rf_content { + radioa_txt = 0, + radiob_txt = 1, + radioc_txt = 2, + radiod_txt = 3 +}; + +static inline void rtl92d_acquire_cckandrw_pagea_ctl(struct ieee80211_hw *hw, + unsigned long *flag) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + if (rtlpriv->rtlhal.interfaceindex == 1) + spin_lock_irqsave(&rtlpriv->locks.cck_and_rw_pagea_lock, *flag); +} + +static inline void rtl92d_release_cckandrw_pagea_ctl(struct ieee80211_hw *hw, + unsigned long *flag) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + if (rtlpriv->rtlhal.interfaceindex == 1) + spin_unlock_irqrestore(&rtlpriv->locks.cck_and_rw_pagea_lock, + *flag); +} + +extern u32 rtl92d_phy_query_bb_reg(struct ieee80211_hw *hw, + u32 regaddr, u32 bitmask); +extern void rtl92d_phy_set_bb_reg(struct ieee80211_hw *hw, + u32 regaddr, u32 bitmask, u32 data); +extern u32 rtl92d_phy_query_rf_reg(struct ieee80211_hw *hw, + enum radio_path rfpath, u32 regaddr, + u32 bitmask); +extern void rtl92d_phy_set_rf_reg(struct ieee80211_hw *hw, + enum radio_path rfpath, u32 regaddr, + u32 bitmask, u32 data); +extern bool rtl92d_phy_mac_config(struct ieee80211_hw *hw); +extern bool rtl92d_phy_bb_config(struct ieee80211_hw *hw); +extern bool rtl92d_phy_rf_config(struct ieee80211_hw *hw); +extern bool rtl92c_phy_config_rf_with_feaderfile(struct ieee80211_hw *hw, + enum radio_path rfpath); +extern void rtl92d_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw); +extern void rtl92d_phy_set_txpower_level(struct ieee80211_hw *hw, u8 channel); +extern void rtl92d_phy_scan_operation_backup(struct ieee80211_hw *hw, + u8 operation); +extern void rtl92d_phy_set_bw_mode(struct ieee80211_hw *hw, + enum nl80211_channel_type ch_type); +extern u8 rtl92d_phy_sw_chnl(struct ieee80211_hw *hw); +bool rtl92d_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, + enum rf_content content, + enum radio_path rfpath); +bool rtl92d_phy_set_io_cmd(struct ieee80211_hw *hw, enum io_type iotype); +extern bool rtl92d_phy_set_rf_power_state(struct ieee80211_hw *hw, + enum rf_pwrstate rfpwr_state); + +void rtl92d_phy_config_macphymode(struct ieee80211_hw *hw); +void rtl92d_phy_config_macphymode_info(struct ieee80211_hw *hw); +u8 rtl92d_get_chnlgroup_fromarray(u8 chnl); +void rtl92d_phy_set_poweron(struct ieee80211_hw *hw); +void rtl92d_phy_config_maccoexist_rfpage(struct ieee80211_hw *hw); +bool rtl92d_phy_check_poweroff(struct ieee80211_hw *hw); +void rtl92d_phy_lc_calibrate(struct ieee80211_hw *hw); +void rtl92d_update_bbrf_configuration(struct ieee80211_hw *hw); +void rtl92d_phy_ap_calibrate(struct ieee80211_hw *hw, char delta); +void rtl92d_phy_iq_calibrate(struct ieee80211_hw *hw); +void rtl92d_phy_reset_iqk_result(struct ieee80211_hw *hw); +void rtl92d_release_cckandrw_pagea_ctl(struct ieee80211_hw *hw, + unsigned long *flag); +void rtl92d_acquire_cckandrw_pagea_ctl(struct ieee80211_hw *hw, + unsigned long *flag); +u8 rtl92d_get_rightchnlplace_for_iqk(u8 chnl); +void rtl92d_phy_reload_iqk_setting(struct ieee80211_hw *hw, u8 channel); +void rtl92d_phy_iq_calibrate(struct ieee80211_hw *hw); + +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/reg.h b/drivers/net/wireless/rtlwifi/rtl8192de/reg.h new file mode 100644 index 00000000..ebb1d5f5 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192de/reg.h @@ -0,0 +1,1312 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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 __RTL92D_REG_H__ +#define __RTL92D_REG_H__ + +/* ----------------------------------------------------- */ +/* 0x0000h ~ 0x00FFh System Configuration */ +/* ----------------------------------------------------- */ +#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_AFE_MISC 0x0010 +#define REG_SPS0_CTRL 0x0011 +#define REG_POWER_OFF_IN_PROCESS 0x0017 +#define REG_SPS_OCP_CFG 0x0018 +#define REG_RSV_CTRL 0x001C +#define REG_RF_CTRL 0x001F +#define REG_LDOA15_CTRL 0x0020 +#define REG_LDOV12D_CTRL 0x0021 +#define REG_LDOHCI12_CTRL 0x0022 +#define REG_LPLDO_CTRL 0x0023 +#define REG_AFE_XTAL_CTRL 0x0024 +#define REG_AFE_PLL_CTRL 0x0028 +/* for 92d, DMDP,SMSP,DMSP contrl */ +#define REG_MAC_PHY_CTRL 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_MCUFWDL 0x0080 + +#define REG_HMEBOX_EXT_0 0x0088 +#define REG_HMEBOX_EXT_1 0x008A +#define REG_HMEBOX_EXT_2 0x008C +#define REG_HMEBOX_EXT_3 0x008E + +#define REG_BIST_SCAN 0x00D0 +#define REG_BIST_RPT 0x00D4 +#define REG_BIST_ROM_RPT 0x00D8 +#define REG_USB_SIE_INTF 0x00E0 +#define REG_PCIE_MIO_INTF 0x00E4 +#define REG_PCIE_MIO_INTD 0x00E8 +#define REG_HPON_FSM 0x00EC +#define REG_SYS_CFG 0x00F0 +#define REG_MAC_PHY_CTRL_NORMAL 0x00f8 + +#define REG_MAC0 0x0081 +#define REG_MAC1 0x0053 +#define FW_MAC0_READY 0x18 +#define FW_MAC1_READY 0x1A +#define MAC0_ON BIT(7) +#define MAC1_ON BIT(0) +#define MAC0_READY BIT(0) +#define MAC1_READY BIT(0) + +/* ----------------------------------------------------- */ +/* 0x0100h ~ 0x01FFh MACTOP General Configuration */ +/* ----------------------------------------------------- */ +#define REG_CR 0x0100 +#define REG_PBP 0x0104 +#define REG_TRXDMA_CTRL 0x010C +#define REG_TRXFF_BNDY 0x0114 +#define REG_TRXFF_STATUS 0x0118 +#define REG_RXFF_PTR 0x011C +#define REG_HIMR 0x0120 +#define REG_HISR 0x0124 +#define REG_HIMRE 0x0128 +#define REG_HISRE 0x012C +#define REG_CPWM 0x012F +#define REG_FWIMR 0x0130 +#define REG_FWISR 0x0134 +#define REG_PKTBUF_DBG_CTRL 0x0140 +#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_MBIST_START 0x0174 +#define REG_MBIST_DONE 0x0178 +#define REG_MBIST_FAIL 0x017C +#define REG_C2HEVT_MSG_NORMAL 0x01A0 +#define REG_C2HEVT_MSG_TEST 0x01B8 +#define REG_C2HEVT_CLEAR 0x01BF +#define REG_MCUTST_1 0x01c0 +#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_BB_ACCEESS_CTRL 0x01E8 +#define REG_BB_ACCESS_DATA 0x01EC + + +/* ----------------------------------------------------- */ +/* 0x0200h ~ 0x027Fh TXDMA Configuration */ +/* ----------------------------------------------------- */ +#define REG_RQPN 0x0200 +#define REG_FIFOPAGE 0x0204 +#define REG_TDECTRL 0x0208 +#define REG_TXDMA_OFFSET_CHK 0x020C +#define REG_TXDMA_STATUS 0x0210 +#define REG_RQPN_NPQ 0x0214 + +/* ----------------------------------------------------- */ +/* 0x0280h ~ 0x02FFh RXDMA Configuration */ +/* ----------------------------------------------------- */ +#define REG_RXDMA_AGG_PG_TH 0x0280 +#define REG_RXPKT_NUM 0x0284 +#define REG_RXDMA_STATUS 0x0288 + +/* ----------------------------------------------------- */ +/* 0x0300h ~ 0x03FFh PCIe */ +/* ----------------------------------------------------- */ +#define REG_PCIE_CTRL_REG 0x0300 +#define REG_INT_MIG 0x0304 +#define REG_BCNQ_DESA 0x0308 +#define REG_HQ_DESA 0x0310 +#define REG_MGQ_DESA 0x0318 +#define REG_VOQ_DESA 0x0320 +#define REG_VIQ_DESA 0x0328 +#define REG_BEQ_DESA 0x0330 +#define REG_BKQ_DESA 0x0338 +#define REG_RX_DESA 0x0340 +#define REG_DBI 0x0348 +#define REG_DBI_WDATA 0x0348 +#define REG_DBI_RDATA 0x034C +#define REG_DBI_CTRL 0x0350 +#define REG_DBI_FLAG 0x0352 +#define REG_MDIO 0x0354 +#define REG_DBG_SEL 0x0360 +#define REG_PCIE_HRPWM 0x0361 +#define REG_PCIE_HCPWM 0x0363 +#define REG_UART_CTRL 0x0364 +#define REG_UART_TX_DESA 0x0370 +#define REG_UART_RX_DESA 0x0378 + +/* ----------------------------------------------------- */ +/* 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_CPU_MGQ_INFORMATION 0x041C +#define REG_FWHW_TXQ_CTRL 0x0420 +#define REG_HWSEQ_CTRL 0x0423 +#define REG_TXPKTBUF_BCNQ_BDNY 0x0424 +#define REG_TXPKTBUF_MGQ_BDNY 0x0425 +#define REG_MULTI_BCNQ_EN 0x0426 +#define REG_MULTI_BCNQ_OFFSET 0x0427 +#define REG_SPEC_SIFS 0x0428 +#define REG_RL 0x042A +#define REG_DARFRC 0x0430 +#define REG_RARFRC 0x0438 +#define REG_RRSR 0x0440 +#define REG_ARFR0 0x0444 +#define REG_ARFR1 0x0448 +#define REG_ARFR2 0x044C +#define REG_ARFR3 0x0450 +#define REG_AGGLEN_LMT 0x0458 +#define REG_AMPDU_MIN_SPACE 0x045C +#define REG_TXPKTBUF_WMAC_LBK_BF_HD 0x045D +#define REG_FAST_EDCA_CTRL 0x0460 +#define REG_RD_RESP_PKT_TH 0x0463 +#define REG_INIRTS_RATE_SEL 0x0480 +#define REG_INIDATA_RATE_SEL 0x0484 +#define REG_POWER_STATUS 0x04A4 +#define REG_POWER_STAGE1 0x04B4 +#define REG_POWER_STAGE2 0x04B8 +#define REG_PKT_LIFE_TIME 0x04C0 +#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_EARLY_MODE_CONTROL 0x4D0 +#define REG_NQOS_SEQ 0x04DC +#define REG_QOS_SEQ 0x04DE +#define REG_NEED_CPU_HANDLE 0x04E0 +#define REG_PKT_LOSE_RPT 0x04E1 +#define REG_PTCL_ERR_STATUS 0x04E2 +#define REG_DUMMY 0x04FC + +/* ----------------------------------------------------- */ +/* 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_USTIME_TSF 0x0551 +#define REG_MBID_NUM 0x0552 +#define REG_DUAL_TSF_RST 0x0553 +#define REG_BCN_INTERVAL 0x0554 +#define REG_MBSSID_BCN_SPACE 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_INIT_TSFTR 0x0564 +#define REG_PSTIMER 0x0580 +#define REG_TIMER0 0x0584 +#define REG_TIMER1 0x0588 +#define REG_ACMHWCTRL 0x05C0 +#define REG_ACMRSTCTRL 0x05C1 +#define REG_ACMAVG 0x05C2 +#define REG_VO_ADMTIME 0x05C4 +#define REG_VI_ADMTIME 0x05C6 +#define REG_BE_ADMTIME 0x05C8 +#define REG_EDCA_RANDOM_GEN 0x05CC +#define REG_SCH_TXCMD 0x05D0 + +/* Dual MAC Co-Existence Register */ +#define REG_DMC 0x05F0 + +/* ----------------------------------------------------- */ +/* 0x0600h ~ 0x07FFh WMAC Configuration */ +/* ----------------------------------------------------- */ +#define REG_APSD_CTRL 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 + + +/* WMA, BA, CCX */ +#define REG_NAV_CTRL 0x0650 +#define REG_BACAMCMD 0x0654 +#define REG_BACAMCONTENT 0x0658 +#define REG_LBDLY 0x0660 +#define REG_FWDLY 0x0661 +#define REG_RXERR_RPT 0x0664 +#define REG_WMAC_TRXPTCL_CTL 0x0668 + + +/* 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_PSSTATUS 0x0691 +#define REG_PS_RX_INFO 0x0692 +#define REG_LPNAV_CTRL 0x0694 +#define REG_WKFMCAM_CMD 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_CALB32K_CTRL 0x06AC +#define REG_PKT_MON_CTRL 0x06B4 +#define REG_BT_COEX_TABLE 0x06C0 +#define REG_WMAC_RESP_TXINFO 0x06D8 + + +/* ----------------------------------------------------- */ +/* Redifine 8192C register definition for compatibility */ +/* ----------------------------------------------------- */ +#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 + +/* ----------------------------------------------------- */ +/* 8192C (MSR) Media Status Register(Offset 0x4C, 8 bits)*/ +/* ----------------------------------------------------- */ +#define MSR_NOLINK 0x00 +#define MSR_ADHOC 0x01 +#define MSR_INFRA 0x02 +#define MSR_AP 0x03 + +/* 6. Adaptive Control Registers (Offset: 0x0160 - 0x01CF) */ +/* ----------------------------------------------------- */ +/* 8192C Response Rate Set Register(offset 0x181, 24bits)*/ +/* ----------------------------------------------------- */ +#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 BIT0 +#define RRSR_2M BIT1 +#define RRSR_5_5M BIT2 +#define RRSR_11M BIT3 +#define RRSR_6M BIT4 +#define RRSR_9M BIT5 +#define RRSR_12M BIT6 +#define RRSR_18M BIT7 +#define RRSR_24M BIT8 +#define RRSR_36M BIT9 +#define RRSR_48M BIT10 +#define RRSR_54M BIT11 +#define RRSR_MCS0 BIT12 +#define RRSR_MCS1 BIT13 +#define RRSR_MCS2 BIT14 +#define RRSR_MCS3 BIT15 +#define RRSR_MCS4 BIT16 +#define RRSR_MCS5 BIT17 +#define RRSR_MCS6 BIT18 +#define RRSR_MCS7 BIT19 +#define BRSR_ACKSHORTPMB BIT23 + +/* ----------------------------------------------------- */ +/* 8192C Rate Definition */ +/* ----------------------------------------------------- */ +/* CCK */ +#define RATR_1M 0x00000001 +#define RATR_2M 0x00000002 +#define RATR_55M 0x00000004 +#define RATR_11M 0x00000008 +/* OFDM */ +#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 +/* MCS 1 Spatial Stream */ +#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 +/* MCS 2 Spatial Stream */ +#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 + +/* CCK */ +#define RATE_1M BIT(0) +#define RATE_2M BIT(1) +#define RATE_5_5M BIT(2) +#define RATE_11M BIT(3) +/* OFDM */ +#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) +/* MCS 1 Spatial Stream */ +#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) +/* MCS 2 Spatial Stream */ +#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) + +/* ALL CCK Rate */ +#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) + +/* ----------------------------------------------------- */ +/* 8192C BW_OPMODE bits (Offset 0x203, 8bit) */ +/* ----------------------------------------------------- */ +#define BW_OPMODE_20MHZ BIT(2) +#define BW_OPMODE_5G BIT(1) +#define BW_OPMODE_11J BIT(0) + + +/* ----------------------------------------------------- */ +/* 8192C CAM Config Setting (offset 0x250, 1 byte) */ +/* ----------------------------------------------------- */ +#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 CAM_SMS4 0x6 + + +#define TOTAL_CAM_ENTRY 32 +#define HALF_CAM_ENTRY 16 + +#define CAM_WRITE BIT(16) +#define CAM_READ 0x00000000 +#define CAM_POLLINIG BIT(31) + +/* 10. Power Save Control Registers (Offset: 0x0260 - 0x02DF) */ +#define WOW_PMEN BIT0 /* Power management Enable. */ +#define WOW_WOMEN BIT1 /* WoW function on or off. */ +#define WOW_MAGIC BIT2 /* Magic packet */ +#define WOW_UWF BIT3 /* Unicast Wakeup frame. */ + +/* 12. Host Interrupt Status Registers (Offset: 0x0300 - 0x030F) */ +/* ----------------------------------------------------- */ +/* 8190 IMR/ISR bits (offset 0xfd, 8bits) */ +/* ----------------------------------------------------- */ +#define IMR8190_DISABLED 0x0 +#define IMR_BCNDMAINT6 BIT(31) +#define IMR_BCNDMAINT5 BIT(30) +#define IMR_BCNDMAINT4 BIT(29) +#define IMR_BCNDMAINT3 BIT(28) +#define IMR_BCNDMAINT2 BIT(27) +#define IMR_BCNDMAINT1 BIT(26) +#define IMR_BCNDOK8 BIT(25) +#define IMR_BCNDOK7 BIT(24) +#define IMR_BCNDOK6 BIT(23) +#define IMR_BCNDOK5 BIT(22) +#define IMR_BCNDOK4 BIT(21) +#define IMR_BCNDOK3 BIT(20) +#define IMR_BCNDOK2 BIT(19) +#define IMR_BCNDOK1 BIT(18) +#define IMR_TIMEOUT2 BIT(17) +#define IMR_TIMEOUT1 BIT(16) +#define IMR_TXFOVW BIT(15) +#define IMR_PSTIMEOUT BIT(14) +#define IMR_BcnInt BIT(13) +#define IMR_RXFOVW BIT(12) +#define IMR_RDU BIT(11) +#define IMR_ATIMEND BIT(10) +#define IMR_BDOK BIT(9) +#define IMR_HIGHDOK BIT(8) +#define IMR_TBDOK BIT(7) +#define IMR_MGNTDOK BIT(6) +#define IMR_TBDER BIT(5) +#define IMR_BKDOK BIT(4) +#define IMR_BEDOK BIT(3) +#define IMR_VIDOK BIT(2) +#define IMR_VODOK BIT(1) +#define IMR_ROK BIT(0) + +#define IMR_TXERR BIT(11) +#define IMR_RXERR BIT(10) +#define IMR_C2HCMD BIT(9) +#define IMR_CPWM BIT(8) +#define IMR_OCPINT BIT(1) +#define IMR_WLANOFF BIT(0) + +/* ----------------------------------------------------- */ +/* 8192C EFUSE */ +/* ----------------------------------------------------- */ +#define HWSET_MAX_SIZE 256 +#define EFUSE_MAX_SECTION 32 +#define EFUSE_REAL_CONTENT_LEN 512 + +/* ----------------------------------------------------- */ +/* 8192C EEPROM/EFUSE share register definition. */ +/* ----------------------------------------------------- */ +#define EEPROM_DEFAULT_TSSI 0x0 +#define EEPROM_DEFAULT_CRYSTALCAP 0x0 +#define EEPROM_DEFAULT_THERMALMETER 0x12 + +#define EEPROM_DEFAULT_TXPOWERLEVEL_2G 0x2C +#define EEPROM_DEFAULT_TXPOWERLEVEL_5G 0x22 + +#define EEPROM_DEFAULT_HT40_2SDIFF 0x0 +/* HT20<->40 default Tx Power Index Difference */ +#define EEPROM_DEFAULT_HT20_DIFF 2 +/* OFDM Tx Power index diff */ +#define EEPROM_DEFAULT_LEGACYHTTXPOWERDIFF 0x4 +#define EEPROM_DEFAULT_HT40_PWRMAXOFFSET 0 +#define EEPROM_DEFAULT_HT20_PWRMAXOFFSET 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 RTL8192_EEPROM_ID 0x8129 +#define EEPROM_WAPI_SUPPORT 0x78 + + +#define RTL8190_EEPROM_ID 0x8129 /* 0-1 */ +#define EEPROM_HPON 0x02 /* LDO settings.2-5 */ +#define EEPROM_CLK 0x06 /* Clock settings.6-7 */ +#define EEPROM_MAC_FUNCTION 0x08 /* SE Test mode.8 */ + +#define EEPROM_VID 0x28 /* SE Vendor ID.A-B */ +#define EEPROM_DID 0x2A /* SE Device ID. C-D */ +#define EEPROM_SVID 0x2C /* SE Vendor ID.E-F */ +#define EEPROM_SMID 0x2E /* SE PCI Subsystem ID. 10-11 */ + +#define EEPROM_MAC_ADDR 0x16 /* SEMAC Address. 12-17 */ +#define EEPROM_MAC_ADDR_MAC0_92D 0x55 +#define EEPROM_MAC_ADDR_MAC1_92D 0x5B + +/* 2.4G band Tx power index setting */ +#define EEPROM_CCK_TX_PWR_INX_2G 0x61 +#define EEPROM_HT40_1S_TX_PWR_INX_2G 0x67 +#define EEPROM_HT40_2S_TX_PWR_INX_DIFF_2G 0x6D +#define EEPROM_HT20_TX_PWR_INX_DIFF_2G 0x70 +#define EEPROM_OFDM_TX_PWR_INX_DIFF_2G 0x73 +#define EEPROM_HT40_MAX_PWR_OFFSET_2G 0x76 +#define EEPROM_HT20_MAX_PWR_OFFSET_2G 0x79 + +/*5GL channel 32-64 */ +#define EEPROM_HT40_1S_TX_PWR_INX_5GL 0x7C +#define EEPROM_HT40_2S_TX_PWR_INX_DIFF_5GL 0x82 +#define EEPROM_HT20_TX_PWR_INX_DIFF_5GL 0x85 +#define EEPROM_OFDM_TX_PWR_INX_DIFF_5GL 0x88 +#define EEPROM_HT40_MAX_PWR_OFFSET_5GL 0x8B +#define EEPROM_HT20_MAX_PWR_OFFSET_5GL 0x8E + +/* 5GM channel 100-140 */ +#define EEPROM_HT40_1S_TX_PWR_INX_5GM 0x91 +#define EEPROM_HT40_2S_TX_PWR_INX_DIFF_5GM 0x97 +#define EEPROM_HT20_TX_PWR_INX_DIFF_5GM 0x9A +#define EEPROM_OFDM_TX_PWR_INX_DIFF_5GM 0x9D +#define EEPROM_HT40_MAX_PWR_OFFSET_5GM 0xA0 +#define EEPROM_HT20_MAX_PWR_OFFSET_5GM 0xA3 + +/* 5GH channel 149-165 */ +#define EEPROM_HT40_1S_TX_PWR_INX_5GH 0xA6 +#define EEPROM_HT40_2S_TX_PWR_INX_DIFF_5GH 0xAC +#define EEPROM_HT20_TX_PWR_INX_DIFF_5GH 0xAF +#define EEPROM_OFDM_TX_PWR_INX_DIFF_5GH 0xB2 +#define EEPROM_HT40_MAX_PWR_OFFSET_5GH 0xB5 +#define EEPROM_HT20_MAX_PWR_OFFSET_5GH 0xB8 + +/* Map of supported channels. */ +#define EEPROM_CHANNEL_PLAN 0xBB +#define EEPROM_IQK_DELTA 0xBC +#define EEPROM_LCK_DELTA 0xBC +#define EEPROM_XTAL_K 0xBD /* [7:5] */ +#define EEPROM_TSSI_A_5G 0xBE +#define EEPROM_TSSI_B_5G 0xBF +#define EEPROM_TSSI_AB_5G 0xC0 +#define EEPROM_THERMAL_METER 0xC3 /* [4:0] */ +#define EEPROM_RF_OPT1 0xC4 +#define EEPROM_RF_OPT2 0xC5 +#define EEPROM_RF_OPT3 0xC6 +#define EEPROM_RF_OPT4 0xC7 +#define EEPROM_RF_OPT5 0xC8 +#define EEPROM_RF_OPT6 0xC9 +#define EEPROM_VERSION 0xCA +#define EEPROM_CUSTOMER_ID 0xCB +#define EEPROM_RF_OPT7 0xCC + +#define EEPROM_DEF_PART_NO 0x3FD /* Byte */ +#define EEPROME_CHIP_VERSION_L 0x3FF +#define EEPROME_CHIP_VERSION_H 0x3FE + +/* + * Current IOREG MAP + * 0x0000h ~ 0x00FFh System Configuration (256 Bytes) + * 0x0100h ~ 0x01FFh MACTOP General Configuration (256 Bytes) + * 0x0200h ~ 0x027Fh TXDMA Configuration (128 Bytes) + * 0x0280h ~ 0x02FFh RXDMA Configuration (128 Bytes) + * 0x0300h ~ 0x03FFh PCIE EMAC Reserved Region (256 Bytes) + * 0x0400h ~ 0x04FFh Protocol Configuration (256 Bytes) + * 0x0500h ~ 0x05FFh EDCA Configuration (256 Bytes) + * 0x0600h ~ 0x07FFh WMAC Configuration (512 Bytes) + * 0x2000h ~ 0x3FFFh 8051 FW Download Region (8196 Bytes) + */ + +/* ----------------------------------------------------- */ +/* 8192C (RCR) (Offset 0x608, 32 bits) */ +/* ----------------------------------------------------- */ +#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_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 + +/* ----------------------------------------------------- */ +/* 8192C Regsiter Bit and Content definition */ +/* ----------------------------------------------------- */ +/* ----------------------------------------------------- */ +/* 0x0000h ~ 0x00FFh System Configuration */ +/* ----------------------------------------------------- */ + +/* SPS0_CTRL */ +#define SW18_FPWM BIT(3) + + +/* SYS_ISO_CTRL */ +#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) + + +/* SYS_FUNC_EN */ +#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) + +/* APS_FSMCO */ +#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) + +/* SYS_CLKR */ +#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) + + +/* 9346CR */ +#define BOOT_FROM_EEPROM BIT(4) +#define EEPROM_EN BIT(5) + +/* AFE_MISC */ +#define AFE_BGEN BIT(0) +#define AFE_MBEN BIT(1) +#define MAC_ID_EN BIT(7) + +/* RSV_CTRL */ +#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) + +/* RF_CTRL */ +#define RF_EN BIT(0) +#define RF_RSTB BIT(1) +#define RF_SDMRSTB BIT(2) + + + +/* LDOA15_CTRL */ +#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) + + + +/* LDOV12D_CTRL */ +#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) + + +/* AFE_XTAL_CTRL */ +#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) + + +/* AFE_PLL_CTRL */ +#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) + + +/* EFUSE_CTRL */ +#define ALD_EN BIT(18) +#define EF_PD BIT(19) +#define EF_FLAG BIT(31) + +/* EFUSE_TEST */ +#define EF_TRPT BIT(7) +#define LDOE25_EN BIT(31) + +/* MCUFWDL */ +#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 MAC1_WINTINI_RDY BIT(11) +#define CPRST BIT(23) + +/* REG_SYS_CFG */ +#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 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) + +/* LLT_INIT */ +#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) + + +/* ----------------------------------------------------- */ +/* 0x0400h ~ 0x047Fh Protocol Configuration */ +/* ----------------------------------------------------- */ +#define RETRY_LIMIT_SHORT_SHIFT 8 +#define RETRY_LIMIT_LONG_SHIFT 0 + + +/* ----------------------------------------------------- */ +/* 0x0500h ~ 0x05FFh EDCA Configuration */ +/* ----------------------------------------------------- */ +/* EDCA setting */ +#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 + +/* ACMHWCTRL */ +#define ACMHW_HWEN BIT(0) +#define ACMHW_BEQEN BIT(1) +#define ACMHW_VIQEN BIT(2) +#define ACMHW_VOQEN BIT(3) + +/* ----------------------------------------------------- */ +/* 0x0600h ~ 0x07FFh WMAC Configuration */ +/* ----------------------------------------------------- */ + +/* TCR */ +#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) + +/* SECCFG */ +#define SCR_TXUSEDK BIT(0) +#define SCR_RXUSEDK BIT(1) +#define SCR_TXENCENABLE BIT(2) +#define SCR_RXENCENABLE BIT(3) +#define SCR_SKBYA2 BIT(4) +#define SCR_NOSKMC BIT(5) +#define SCR_TXBCUSEDK BIT(6) +#define SCR_RXBCUSEDK BIT(7) + +/* General definitions */ +#define LAST_ENTRY_OF_TX_PKT_BUFFER 255 +#define LAST_ENTRY_OF_TX_PKT_BUFFER_DUAL_MAC 127 + +#define POLLING_LLT_THRESHOLD 20 +#define POLLING_READY_TIMEOUT_COUNT 1000 + +/* Min Spacing related settings. */ +#define MAX_MSS_DENSITY_2T 0x13 +#define MAX_MSS_DENSITY_1T 0x0A + + +/* BB-PHY register PMAC 0x100 PHY 0x800 - 0xEFF */ +/* 1. PMAC duplicate register due to connection: */ +/* RF_Mode, TRxRN, NumOf L-STF */ +/* 2. 0x800/0x900/0xA00/0xC00/0xD00/0xE00 */ +/* 3. RF register 0x00-2E */ +/* 4. Bit Mask for BB/RF register */ +/* 5. Other defintion for BB/RF R/W */ + +/* 3. Page8(0x800) */ +#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_ADDALLOCKEN 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 TRANSCEIVERA_HSPI_READBACK 0x8b8 +#define TRANSCEIVERB_HSPI_READBACK 0x8bc +#define RFPGA0_XAB_RFINTERFACERB 0x8e0 +#define RFPGA0_XCD_RFINTERFACERB 0x8e4 + +/* 4. Page9(0x900) */ +#define RFPGA1_RFMOD 0x900 + +#define RFPGA1_TXBLOCK 0x904 +#define RFPGA1_DEBUGSELECT 0x908 +#define RFPGA1_TXINFO 0x90c + +/* 5. PageA(0xA00) */ +#define RCCK0_SYSTEM 0xa00 + +#define RCCK0_AFESSTTING 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 + +/* 6. PageC(0xC00) */ +#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_XCRXIQIMBALANCE 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_RXHPPARAMETER 0xce0 +#define ROFDM0_TXPSEUDONOISEWGT 0xce4 +#define ROFDM0_FRAMESYNC 0xcf0 +#define ROFDM0_DFSREPORT 0xcf4 +#define ROFDM0_TXCOEFF1 0xca4 +#define ROFDM0_TXCOEFF2 0xca8 +#define ROFDM0_TXCOEFF3 0xcac +#define ROFDM0_TXCOEFF4 0xcb0 +#define ROFDM0_TXCOEFF5 0xcb4 +#define ROFDM0_TXCOEFF6 0xcb8 + +/* 7. PageD(0xD00) */ +#define ROFDM1_LSTF 0xd00 +#define ROFDM1_TRXPATHENABLE 0xd04 + +#define ROFDM1_CFO 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_TAILCFOAB 0xdbc +#define ROFDM_TAILCFOCD 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 + +/* 8. PageE(0xE00) */ +#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 + +/* RL6052 Register definition */ +#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 + +/* Bit Mask */ + +/* 2. Page8(0x800) */ +#define BRFMOD 0x1 +#define BCCKTXSC 0x30 +#define BCCKEN 0x1000000 +#define BOFDMEN 0x2000000 + +#define B3WIREDATALENGTH 0x800 +#define B3WIREADDRESSLENGTH 0x400 + +#define BRFSI_RFENV 0x10 + +#define BLSSIREADADDRESS 0x7f800000 +#define BLSSIREADEDGE 0x80000000 +#define BLSSIREADBACKDATA 0xfffff +/* 4. PageA(0xA00) */ +#define BCCKSIDEBAND 0x10 + +/* Other Definition */ +#define BBYTE0 0x1 +#define BBYTE1 0x2 +#define BBYTE2 0x4 +#define BBYTE3 0x8 +#define BWORD0 0x3 +#define BWORD1 0xc +#define BDWORD 0xf + +#define BMASKBYTE0 0xff +#define BMASKBYTE1 0xff00 +#define BMASKBYTE2 0xff0000 +#define BMASKBYTE3 0xff000000 +#define BMASKHWORD 0xffff0000 +#define BMASKLWORD 0x0000ffff +#define BMASKDWORD 0xffffffff +#define BMASK12BITS 0xfff +#define BMASKH4BITS 0xf0000000 +#define BMASKOFDM_D 0xffc00000 +#define BMASKCCK 0x3f3f3f3f + +#define BRFREGOFFSETMASK 0xfffff + +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/rf.c b/drivers/net/wireless/rtlwifi/rtl8192de/rf.c new file mode 100644 index 00000000..3066a7fb --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192de/rf.c @@ -0,0 +1,625 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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> + * + *****************************************************************************/ + +#include "../wifi.h" +#include "reg.h" +#include "def.h" +#include "phy.h" +#include "rf.h" +#include "dm.h" +#include "hw.h" + +void rtl92d_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw, u8 bandwidth) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + u8 rfpath; + + switch (bandwidth) { + case HT_CHANNEL_WIDTH_20: + for (rfpath = 0; rfpath < rtlphy->num_total_rfpath; rfpath++) { + rtlphy->rfreg_chnlval[rfpath] = ((rtlphy->rfreg_chnlval + [rfpath] & 0xfffff3ff) | 0x0400); + rtl_set_rfreg(hw, rfpath, RF_CHNLBW, BIT(10) | + BIT(11), 0x01); + + RT_TRACE(rtlpriv, COMP_RF, DBG_LOUD, + "20M RF 0x18 = 0x%x\n", + rtlphy->rfreg_chnlval[rfpath]); + } + + break; + case HT_CHANNEL_WIDTH_20_40: + for (rfpath = 0; rfpath < rtlphy->num_total_rfpath; rfpath++) { + rtlphy->rfreg_chnlval[rfpath] = + ((rtlphy->rfreg_chnlval[rfpath] & 0xfffff3ff)); + rtl_set_rfreg(hw, rfpath, RF_CHNLBW, BIT(10) | BIT(11), + 0x00); + RT_TRACE(rtlpriv, COMP_RF, DBG_LOUD, + "40M RF 0x18 = 0x%x\n", + rtlphy->rfreg_chnlval[rfpath]); + } + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "unknown bandwidth: %#X\n", bandwidth); + break; + } +} + +void rtl92d_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw, + u8 *ppowerlevel) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + u32 tx_agc[2] = {0, 0}, tmpval; + bool turbo_scanoff = false; + u8 idx1, idx2; + u8 *ptr; + + if (rtlefuse->eeprom_regulatory != 0) + turbo_scanoff = true; + if (mac->act_scanning) { + tx_agc[RF90_PATH_A] = 0x3f3f3f3f; + tx_agc[RF90_PATH_B] = 0x3f3f3f3f; + if (turbo_scanoff) { + for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B; idx1++) { + tx_agc[idx1] = ppowerlevel[idx1] | + (ppowerlevel[idx1] << 8) | + (ppowerlevel[idx1] << 16) | + (ppowerlevel[idx1] << 24); + } + } + } else { + for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B; idx1++) { + tx_agc[idx1] = ppowerlevel[idx1] | + (ppowerlevel[idx1] << 8) | + (ppowerlevel[idx1] << 16) | + (ppowerlevel[idx1] << 24); + } + if (rtlefuse->eeprom_regulatory == 0) { + tmpval = (rtlphy->mcs_txpwrlevel_origoffset[0][6]) + + (rtlphy->mcs_txpwrlevel_origoffset[0][7] << 8); + tx_agc[RF90_PATH_A] += tmpval; + tmpval = (rtlphy->mcs_txpwrlevel_origoffset[0][14]) + + (rtlphy->mcs_txpwrlevel_origoffset[0][15] << 24); + tx_agc[RF90_PATH_B] += tmpval; + } + } + + for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B; idx1++) { + ptr = (u8 *) (&(tx_agc[idx1])); + for (idx2 = 0; idx2 < 4; idx2++) { + if (*ptr > RF6052_MAX_TX_PWR) + *ptr = RF6052_MAX_TX_PWR; + ptr++; + } + } + + tmpval = tx_agc[RF90_PATH_A] & 0xff; + rtl_set_bbreg(hw, RTXAGC_A_CCK1_MCS32, BMASKBYTE1, tmpval); + RTPRINT(rtlpriv, FPHY, PHY_TXPWR, + "CCK PWR 1M (rf-A) = 0x%x (reg 0x%x)\n", + tmpval, RTXAGC_A_CCK1_MCS32); + tmpval = tx_agc[RF90_PATH_A] >> 8; + rtl_set_bbreg(hw, RTXAGC_B_CCK11_A_CCK2_11, 0xffffff00, tmpval); + RTPRINT(rtlpriv, FPHY, PHY_TXPWR, + "CCK PWR 2~11M (rf-A) = 0x%x (reg 0x%x)\n", + tmpval, RTXAGC_B_CCK11_A_CCK2_11); + tmpval = tx_agc[RF90_PATH_B] >> 24; + rtl_set_bbreg(hw, RTXAGC_B_CCK11_A_CCK2_11, BMASKBYTE0, tmpval); + RTPRINT(rtlpriv, FPHY, PHY_TXPWR, + "CCK PWR 11M (rf-B) = 0x%x (reg 0x%x)\n", + tmpval, RTXAGC_B_CCK11_A_CCK2_11); + tmpval = tx_agc[RF90_PATH_B] & 0x00ffffff; + rtl_set_bbreg(hw, RTXAGC_B_CCK1_55_MCS32, 0xffffff00, tmpval); + RTPRINT(rtlpriv, FPHY, PHY_TXPWR, + "CCK PWR 1~5.5M (rf-B) = 0x%x (reg 0x%x)\n", + tmpval, RTXAGC_B_CCK1_55_MCS32); +} + +static void _rtl92d_phy_get_power_base(struct ieee80211_hw *hw, + u8 *ppowerlevel, u8 channel, + u32 *ofdmbase, u32 *mcsbase) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + u32 powerbase0, powerbase1; + u8 legacy_pwrdiff, ht20_pwrdiff; + u8 i, powerlevel[2]; + + for (i = 0; i < 2; i++) { + powerlevel[i] = ppowerlevel[i]; + legacy_pwrdiff = rtlefuse->txpwr_legacyhtdiff[i][channel - 1]; + powerbase0 = powerlevel[i] + legacy_pwrdiff; + powerbase0 = (powerbase0 << 24) | (powerbase0 << 16) | + (powerbase0 << 8) | powerbase0; + *(ofdmbase + i) = powerbase0; + RTPRINT(rtlpriv, FPHY, PHY_TXPWR, + " [OFDM power base index rf(%c) = 0x%x]\n", + i == 0 ? 'A' : 'B', *(ofdmbase + i)); + } + + for (i = 0; i < 2; i++) { + if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20) { + ht20_pwrdiff = rtlefuse->txpwr_ht20diff[i][channel - 1]; + powerlevel[i] += ht20_pwrdiff; + } + powerbase1 = powerlevel[i]; + powerbase1 = (powerbase1 << 24) | (powerbase1 << 16) | + (powerbase1 << 8) | powerbase1; + *(mcsbase + i) = powerbase1; + RTPRINT(rtlpriv, FPHY, PHY_TXPWR, + " [MCS power base index rf(%c) = 0x%x]\n", + i == 0 ? 'A' : 'B', *(mcsbase + i)); + } +} + +static u8 _rtl92d_phy_get_chnlgroup_bypg(u8 chnlindex) +{ + u8 group; + u8 channel_info[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 + }; + + if (channel_info[chnlindex] <= 3) /* Chanel 1-3 */ + group = 0; + else if (channel_info[chnlindex] <= 9) /* Channel 4-9 */ + group = 1; + else if (channel_info[chnlindex] <= 14) /* Channel 10-14 */ + group = 2; + else if (channel_info[chnlindex] <= 64) + group = 6; + else if (channel_info[chnlindex] <= 140) + group = 7; + else + group = 8; + return group; +} + +static void _rtl92d_get_txpower_writeval_by_regulatory(struct ieee80211_hw *hw, + u8 channel, u8 index, + u32 *powerbase0, + u32 *powerbase1, + u32 *p_outwriteval) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + u8 i, chnlgroup = 0, pwr_diff_limit[4]; + u32 writeval = 0, customer_limit, rf; + + for (rf = 0; rf < 2; rf++) { + switch (rtlefuse->eeprom_regulatory) { + case 0: + chnlgroup = 0; + writeval = rtlphy->mcs_txpwrlevel_origoffset + [chnlgroup][index + + (rf ? 8 : 0)] + ((index < 2) ? + powerbase0[rf] : + powerbase1[rf]); + RTPRINT(rtlpriv, FPHY, PHY_TXPWR, + "RTK better performance, writeval(%c) = 0x%x\n", + rf == 0 ? 'A' : 'B', writeval); + break; + case 1: + if (rtlphy->pwrgroup_cnt == 1) + chnlgroup = 0; + if (rtlphy->pwrgroup_cnt >= MAX_PG_GROUP) { + chnlgroup = _rtl92d_phy_get_chnlgroup_bypg( + channel - 1); + if (rtlphy->current_chan_bw == + HT_CHANNEL_WIDTH_20) + chnlgroup++; + else + chnlgroup += 4; + writeval = rtlphy->mcs_txpwrlevel_origoffset + [chnlgroup][index + + (rf ? 8 : 0)] + ((index < 2) ? + powerbase0[rf] : + powerbase1[rf]); + RTPRINT(rtlpriv, FPHY, PHY_TXPWR, + "Realtek regulatory, 20MHz, writeval(%c) = 0x%x\n", + rf == 0 ? 'A' : 'B', writeval); + } + break; + case 2: + writeval = ((index < 2) ? powerbase0[rf] : + powerbase1[rf]); + RTPRINT(rtlpriv, FPHY, PHY_TXPWR, + "Better regulatory, writeval(%c) = 0x%x\n", + rf == 0 ? 'A' : 'B', writeval); + break; + case 3: + chnlgroup = 0; + if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) { + RTPRINT(rtlpriv, FPHY, PHY_TXPWR, + "customer's limit, 40MHz rf(%c) = 0x%x\n", + rf == 0 ? 'A' : 'B', + rtlefuse->pwrgroup_ht40[rf] + [channel - 1]); + } else { + RTPRINT(rtlpriv, FPHY, PHY_TXPWR, + "customer's limit, 20MHz rf(%c) = 0x%x\n", + rf == 0 ? 'A' : 'B', + rtlefuse->pwrgroup_ht20[rf] + [channel - 1]); + } + for (i = 0; i < 4; i++) { + pwr_diff_limit[i] = + (u8)((rtlphy->mcs_txpwrlevel_origoffset + [chnlgroup][index + (rf ? 8 : 0)] & + (0x7f << (i * 8))) >> (i * 8)); + if (rtlphy->current_chan_bw == + HT_CHANNEL_WIDTH_20_40) { + if (pwr_diff_limit[i] > + rtlefuse->pwrgroup_ht40[rf] + [channel - 1]) + pwr_diff_limit[i] = + rtlefuse->pwrgroup_ht40 + [rf][channel - 1]; + } else { + if (pwr_diff_limit[i] > + rtlefuse->pwrgroup_ht20[rf][ + channel - 1]) + pwr_diff_limit[i] = + rtlefuse->pwrgroup_ht20[rf] + [channel - 1]; + } + } + customer_limit = (pwr_diff_limit[3] << 24) | + (pwr_diff_limit[2] << 16) | + (pwr_diff_limit[1] << 8) | + (pwr_diff_limit[0]); + RTPRINT(rtlpriv, FPHY, PHY_TXPWR, + "Customer's limit rf(%c) = 0x%x\n", + rf == 0 ? 'A' : 'B', customer_limit); + writeval = customer_limit + ((index < 2) ? + powerbase0[rf] : powerbase1[rf]); + RTPRINT(rtlpriv, FPHY, PHY_TXPWR, + "Customer, writeval rf(%c)= 0x%x\n", + rf == 0 ? 'A' : 'B', writeval); + break; + default: + chnlgroup = 0; + writeval = rtlphy->mcs_txpwrlevel_origoffset + [chnlgroup][index + + (rf ? 8 : 0)] + ((index < 2) ? + powerbase0[rf] : powerbase1[rf]); + RTPRINT(rtlpriv, FPHY, PHY_TXPWR, + "RTK better performance, writeval rf(%c) = 0x%x\n", + rf == 0 ? 'A' : 'B', writeval); + break; + } + *(p_outwriteval + rf) = writeval; + } +} + +static void _rtl92d_write_ofdm_power_reg(struct ieee80211_hw *hw, + u8 index, u32 *pvalue) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + static u16 regoffset_a[6] = { + RTXAGC_A_RATE18_06, RTXAGC_A_RATE54_24, + RTXAGC_A_MCS03_MCS00, RTXAGC_A_MCS07_MCS04, + RTXAGC_A_MCS11_MCS08, RTXAGC_A_MCS15_MCS12 + }; + static u16 regoffset_b[6] = { + RTXAGC_B_RATE18_06, RTXAGC_B_RATE54_24, + RTXAGC_B_MCS03_MCS00, RTXAGC_B_MCS07_MCS04, + RTXAGC_B_MCS11_MCS08, RTXAGC_B_MCS15_MCS12 + }; + u8 i, rf, pwr_val[4]; + u32 writeval; + u16 regoffset; + + for (rf = 0; rf < 2; rf++) { + writeval = pvalue[rf]; + for (i = 0; i < 4; i++) { + pwr_val[i] = (u8) ((writeval & (0x7f << + (i * 8))) >> (i * 8)); + if (pwr_val[i] > RF6052_MAX_TX_PWR) + pwr_val[i] = RF6052_MAX_TX_PWR; + } + writeval = (pwr_val[3] << 24) | (pwr_val[2] << 16) | + (pwr_val[1] << 8) | pwr_val[0]; + if (rf == 0) + regoffset = regoffset_a[index]; + else + regoffset = regoffset_b[index]; + rtl_set_bbreg(hw, regoffset, BMASKDWORD, writeval); + RTPRINT(rtlpriv, FPHY, PHY_TXPWR, + "Set 0x%x = %08x\n", regoffset, writeval); + if (((get_rf_type(rtlphy) == RF_2T2R) && + (regoffset == RTXAGC_A_MCS15_MCS12 || + regoffset == RTXAGC_B_MCS15_MCS12)) || + ((get_rf_type(rtlphy) != RF_2T2R) && + (regoffset == RTXAGC_A_MCS07_MCS04 || + regoffset == RTXAGC_B_MCS07_MCS04))) { + writeval = pwr_val[3]; + if (regoffset == RTXAGC_A_MCS15_MCS12 || + regoffset == RTXAGC_A_MCS07_MCS04) + regoffset = 0xc90; + if (regoffset == RTXAGC_B_MCS15_MCS12 || + regoffset == RTXAGC_B_MCS07_MCS04) + regoffset = 0xc98; + for (i = 0; i < 3; i++) { + if (i != 2) + writeval = (writeval > 8) ? + (writeval - 8) : 0; + else + writeval = (writeval > 6) ? + (writeval - 6) : 0; + rtl_write_byte(rtlpriv, (u32) (regoffset + i), + (u8) writeval); + } + } + } +} + +void rtl92d_phy_rf6052_set_ofdm_txpower(struct ieee80211_hw *hw, + u8 *ppowerlevel, u8 channel) +{ + u32 writeval[2], powerbase0[2], powerbase1[2]; + u8 index; + + _rtl92d_phy_get_power_base(hw, ppowerlevel, channel, + &powerbase0[0], &powerbase1[0]); + for (index = 0; index < 6; index++) { + _rtl92d_get_txpower_writeval_by_regulatory(hw, + channel, index, &powerbase0[0], + &powerbase1[0], &writeval[0]); + _rtl92d_write_ofdm_power_reg(hw, index, &writeval[0]); + } +} + +bool rtl92d_phy_enable_anotherphy(struct ieee80211_hw *hw, bool bmac0) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = &(rtlpriv->rtlhal); + u8 u1btmp; + u8 direct = bmac0 ? BIT(3) | BIT(2) : BIT(3); + u8 mac_reg = bmac0 ? REG_MAC1 : REG_MAC0; + u8 mac_on_bit = bmac0 ? MAC1_ON : MAC0_ON; + bool bresult = true; /* true: need to enable BB/RF power */ + + rtlhal->during_mac0init_radiob = false; + rtlhal->during_mac1init_radioa = false; + RT_TRACE(rtlpriv, COMP_RF, DBG_LOUD, "===>\n"); + /* MAC0 Need PHY1 load radio_b.txt . Driver use DBI to write. */ + u1btmp = rtl_read_byte(rtlpriv, mac_reg); + if (!(u1btmp & mac_on_bit)) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "enable BB & RF\n"); + /* Enable BB and RF power */ + rtl92de_write_dword_dbi(hw, REG_SYS_ISO_CTRL, + rtl92de_read_dword_dbi(hw, REG_SYS_ISO_CTRL, direct) | + BIT(29) | BIT(16) | BIT(17), direct); + } else { + /* We think if MAC1 is ON,then radio_a.txt + * and radio_b.txt has been load. */ + bresult = false; + } + RT_TRACE(rtlpriv, COMP_RF, DBG_LOUD, "<===\n"); + return bresult; + +} + +void rtl92d_phy_powerdown_anotherphy(struct ieee80211_hw *hw, bool bmac0) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = &(rtlpriv->rtlhal); + u8 u1btmp; + u8 direct = bmac0 ? BIT(3) | BIT(2) : BIT(3); + u8 mac_reg = bmac0 ? REG_MAC1 : REG_MAC0; + u8 mac_on_bit = bmac0 ? MAC1_ON : MAC0_ON; + + rtlhal->during_mac0init_radiob = false; + rtlhal->during_mac1init_radioa = false; + RT_TRACE(rtlpriv, COMP_RF, DBG_LOUD, "====>\n"); + /* check MAC0 enable or not again now, if + * enabled, not power down radio A. */ + u1btmp = rtl_read_byte(rtlpriv, mac_reg); + if (!(u1btmp & mac_on_bit)) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "power down\n"); + /* power down RF radio A according to YuNan's advice. */ + rtl92de_write_dword_dbi(hw, RFPGA0_XA_LSSIPARAMETER, + 0x00000000, direct); + } + RT_TRACE(rtlpriv, COMP_RF, DBG_LOUD, "<====\n"); +} + +bool rtl92d_phy_rf6052_config(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + bool rtstatus = true; + struct rtl_hal *rtlhal = &(rtlpriv->rtlhal); + u32 u4_regvalue = 0; + u8 rfpath; + struct bb_reg_def *pphyreg; + bool mac1_initradioa_first = false, mac0_initradiob_first = false; + bool need_pwrdown_radioa = false, need_pwrdown_radiob = false; + bool true_bpath = false; + + if (rtlphy->rf_type == RF_1T1R) + rtlphy->num_total_rfpath = 1; + else + rtlphy->num_total_rfpath = 2; + + /* Single phy mode: use radio_a radio_b config path_A path_B */ + /* seperately by MAC0, and MAC1 needn't configure RF; */ + /* Dual PHY mode:MAC0 use radio_a config 1st phy path_A, */ + /* MAC1 use radio_b config 2nd PHY path_A. */ + /* DMDP,MAC0 on G band,MAC1 on A band. */ + if (rtlhal->macphymode == DUALMAC_DUALPHY) { + if (rtlhal->current_bandtype == BAND_ON_2_4G && + rtlhal->interfaceindex == 0) { + /* MAC0 needs PHY1 load radio_b.txt. + * Driver use DBI to write. */ + if (rtl92d_phy_enable_anotherphy(hw, true)) { + rtlphy->num_total_rfpath = 2; + mac0_initradiob_first = true; + } else { + /* We think if MAC1 is ON,then radio_a.txt and + * radio_b.txt has been load. */ + return rtstatus; + } + } else if (rtlhal->current_bandtype == BAND_ON_5G && + rtlhal->interfaceindex == 1) { + /* MAC1 needs PHY0 load radio_a.txt. + * Driver use DBI to write. */ + if (rtl92d_phy_enable_anotherphy(hw, false)) { + rtlphy->num_total_rfpath = 2; + mac1_initradioa_first = true; + } else { + /* We think if MAC0 is ON,then radio_a.txt and + * radio_b.txt has been load. */ + return rtstatus; + } + } else if (rtlhal->interfaceindex == 1) { + /* MAC0 enabled, only init radia B. */ + true_bpath = true; + } + } + + for (rfpath = 0; rfpath < rtlphy->num_total_rfpath; rfpath++) { + /* Mac1 use PHY0 write */ + if (mac1_initradioa_first) { + if (rfpath == RF90_PATH_A) { + rtlhal->during_mac1init_radioa = true; + need_pwrdown_radioa = true; + } else if (rfpath == RF90_PATH_B) { + rtlhal->during_mac1init_radioa = false; + mac1_initradioa_first = false; + rfpath = RF90_PATH_A; + true_bpath = true; + rtlphy->num_total_rfpath = 1; + } + } else if (mac0_initradiob_first) { + /* Mac0 use PHY1 write */ + if (rfpath == RF90_PATH_A) + rtlhal->during_mac0init_radiob = false; + if (rfpath == RF90_PATH_B) { + rtlhal->during_mac0init_radiob = true; + mac0_initradiob_first = false; + need_pwrdown_radiob = true; + rfpath = RF90_PATH_A; + true_bpath = true; + rtlphy->num_total_rfpath = 1; + } + } + 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); + /* Set bit number of Address and Data for RF register */ + /* Set 1 to 4 bits for 8255 */ + rtl_set_bbreg(hw, pphyreg->rfhssi_para2, + B3WIREADDRESSLENGTH, 0x0); + udelay(1); + /* Set 0 to 12 bits for 8255 */ + rtl_set_bbreg(hw, pphyreg->rfhssi_para2, B3WIREDATALENGTH, 0x0); + udelay(1); + switch (rfpath) { + case RF90_PATH_A: + if (true_bpath) + rtstatus = rtl92d_phy_config_rf_with_headerfile( + hw, radiob_txt, + (enum radio_path)rfpath); + else + rtstatus = rtl92d_phy_config_rf_with_headerfile( + hw, radioa_txt, + (enum radio_path)rfpath); + break; + case RF90_PATH_B: + rtstatus = + rtl92d_phy_config_rf_with_headerfile(hw, radiob_txt, + (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(rtlpriv, COMP_INIT, DBG_TRACE, + "Radio[%d] Fail!!", rfpath); + goto phy_rf_cfg_fail; + } + + } + + /* check MAC0 enable or not again, if enabled, + * not power down radio A. */ + /* check MAC1 enable or not again, if enabled, + * not power down radio B. */ + if (need_pwrdown_radioa) + rtl92d_phy_powerdown_anotherphy(hw, false); + else if (need_pwrdown_radiob) + rtl92d_phy_powerdown_anotherphy(hw, true); + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "<---\n"); + return rtstatus; + +phy_rf_cfg_fail: + return rtstatus; +} diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/rf.h b/drivers/net/wireless/rtlwifi/rtl8192de/rf.h new file mode 100644 index 00000000..0fe1a485 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192de/rf.h @@ -0,0 +1,44 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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 __RTL92D_RF_H__ +#define __RTL92D_RF_H__ + +extern void rtl92d_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw, + u8 bandwidth); +extern void rtl92d_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw, + u8 *ppowerlevel); +extern void rtl92d_phy_rf6052_set_ofdm_txpower(struct ieee80211_hw *hw, + u8 *ppowerlevel, u8 channel); +extern bool rtl92d_phy_rf6052_config(struct ieee80211_hw *hw); +extern bool rtl92d_phy_enable_anotherphy(struct ieee80211_hw *hw, bool bmac0); +extern void rtl92d_phy_powerdown_anotherphy(struct ieee80211_hw *hw, + bool bmac0); + +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/sw.c b/drivers/net/wireless/rtlwifi/rtl8192de/sw.c new file mode 100644 index 00000000..480862c0 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192de/sw.c @@ -0,0 +1,424 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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> + * + *****************************************************************************/ + +#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 "trx.h" +#include "led.h" + +#include <linux/module.h> + +static void rtl92d_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; +} + +static int rtl92d_init_sw_vars(struct ieee80211_hw *hw) +{ + int err; + u8 tid; + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + + rtlpriv->dm.dm_initialgain_enable = true; + rtlpriv->dm.dm_flag = 0; + rtlpriv->dm.disable_framebursting = false; + rtlpriv->dm.thermalvalue = 0; + rtlpriv->dm.useramask = true; + + /* dual mac */ + if (rtlpriv->rtlhal.current_bandtype == BAND_ON_5G) + rtlpriv->phy.current_channel = 36; + else + rtlpriv->phy.current_channel = 1; + + if (rtlpriv->rtlhal.macphymode != SINGLEMAC_SINGLEPHY) { + rtlpriv->rtlhal.disable_amsdu_8k = true; + /* No long RX - reduce fragmentation */ + rtlpci->rxbuffersize = 4096; + } + + rtlpci->transmit_config = CFENDFORM | BIT(12) | BIT(13); + + rtlpci->receive_config = ( + RCR_APPFCS + | RCR_AMF + | RCR_ADF + | RCR_APP_MIC + | RCR_APP_ICV + | RCR_AICV + | RCR_ACRC32 + | RCR_AB + | RCR_AM + | RCR_APM + | RCR_APP_PHYST_RXFF + | RCR_HTC_LOC_CTRL + ); + + rtlpci->irq_mask[0] = (u32) ( + IMR_ROK + | IMR_VODOK + | IMR_VIDOK + | IMR_BEDOK + | IMR_BKDOK + | IMR_MGNTDOK + | IMR_HIGHDOK + | IMR_BDOK + | IMR_RDU + | IMR_RXFOVW + ); + + rtlpci->irq_mask[1] = (u32) (IMR_CPWM | IMR_C2HCMD); + + /* for debug level */ + rtlpriv->dbg.global_debuglevel = rtlpriv->cfg->mod_params->debug; + /* for LPS & IPS */ + rtlpriv->psc.inactiveps = rtlpriv->cfg->mod_params->inactiveps; + rtlpriv->psc.swctrl_lps = rtlpriv->cfg->mod_params->swctrl_lps; + rtlpriv->psc.fwctrl_lps = rtlpriv->cfg->mod_params->fwctrl_lps; + if (!rtlpriv->psc.inactiveps) + pr_info("Power Save off (module option)\n"); + if (!rtlpriv->psc.fwctrl_lps) + pr_info("FW Power Save off (module option)\n"); + rtlpriv->psc.reg_fwctrl_lps = 3; + rtlpriv->psc.reg_max_lps_awakeintvl = 5; + /* for ASPM, you can close aspm through + * set const_support_pciaspm = 0 */ + rtl92d_init_aspm_vars(hw); + + if (rtlpriv->psc.reg_fwctrl_lps == 1) + rtlpriv->psc.fwctrl_psmode = FW_PS_MIN_MODE; + else if (rtlpriv->psc.reg_fwctrl_lps == 2) + rtlpriv->psc.fwctrl_psmode = FW_PS_MAX_MODE; + else if (rtlpriv->psc.reg_fwctrl_lps == 3) + rtlpriv->psc.fwctrl_psmode = FW_PS_DTIM_MODE; + + /* for early mode */ + rtlpriv->rtlhal.earlymode_enable = true; + for (tid = 0; tid < 8; tid++) + skb_queue_head_init(&rtlpriv->mac80211.skb_waitq[tid]); + + /* for firmware buf */ + rtlpriv->rtlhal.pfirmware = vzalloc(0x8000); + if (!rtlpriv->rtlhal.pfirmware) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "Can't alloc buffer for fw\n"); + return 1; + } + + rtlpriv->max_fw_size = 0x8000; + pr_info("Driver for Realtek RTL8192DE WLAN interface\n"); + pr_info("Loading firmware file %s\n", rtlpriv->cfg->fw_name); + + /* request fw */ + err = request_firmware_nowait(THIS_MODULE, 1, rtlpriv->cfg->fw_name, + rtlpriv->io.dev, GFP_KERNEL, hw, + rtl_fw_cb); + if (err) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "Failed to request firmware!\n"); + return 1; + } + + return 0; +} + +static void rtl92d_deinit_sw_vars(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 tid; + + if (rtlpriv->rtlhal.pfirmware) { + vfree(rtlpriv->rtlhal.pfirmware); + rtlpriv->rtlhal.pfirmware = NULL; + } + for (tid = 0; tid < 8; tid++) + skb_queue_purge(&rtlpriv->mac80211.skb_waitq[tid]); +} + +static struct rtl_hal_ops rtl8192de_hal_ops = { + .init_sw_vars = rtl92d_init_sw_vars, + .deinit_sw_vars = rtl92d_deinit_sw_vars, + .read_eeprom_info = rtl92de_read_eeprom_info, + .interrupt_recognized = rtl92de_interrupt_recognized, + .hw_init = rtl92de_hw_init, + .hw_disable = rtl92de_card_disable, + .hw_suspend = rtl92de_suspend, + .hw_resume = rtl92de_resume, + .enable_interrupt = rtl92de_enable_interrupt, + .disable_interrupt = rtl92de_disable_interrupt, + .set_network_type = rtl92de_set_network_type, + .set_chk_bssid = rtl92de_set_check_bssid, + .set_qos = rtl92de_set_qos, + .set_bcn_reg = rtl92de_set_beacon_related_registers, + .set_bcn_intv = rtl92de_set_beacon_interval, + .update_interrupt_mask = rtl92de_update_interrupt_mask, + .get_hw_reg = rtl92de_get_hw_reg, + .set_hw_reg = rtl92de_set_hw_reg, + .update_rate_tbl = rtl92de_update_hal_rate_tbl, + .fill_tx_desc = rtl92de_tx_fill_desc, + .fill_tx_cmddesc = rtl92de_tx_fill_cmddesc, + .query_rx_desc = rtl92de_rx_query_desc, + .set_channel_access = rtl92de_update_channel_access_setting, + .radio_onoff_checking = rtl92de_gpio_radio_on_off_checking, + .set_bw_mode = rtl92d_phy_set_bw_mode, + .switch_channel = rtl92d_phy_sw_chnl, + .dm_watchdog = rtl92d_dm_watchdog, + .scan_operation_backup = rtl92d_phy_scan_operation_backup, + .set_rf_power_state = rtl92d_phy_set_rf_power_state, + .led_control = rtl92de_led_control, + .set_desc = rtl92de_set_desc, + .get_desc = rtl92de_get_desc, + .tx_polling = rtl92de_tx_polling, + .enable_hw_sec = rtl92de_enable_hw_security_config, + .set_key = rtl92de_set_key, + .init_sw_leds = rtl92de_init_sw_leds, + .get_bbreg = rtl92d_phy_query_bb_reg, + .set_bbreg = rtl92d_phy_set_bb_reg, + .get_rfreg = rtl92d_phy_query_rf_reg, + .set_rfreg = rtl92d_phy_set_rf_reg, + .linked_set_reg = rtl92d_linked_set_reg, +}; + +static struct rtl_mod_params rtl92de_mod_params = { + .sw_crypto = false, + .inactiveps = true, + .swctrl_lps = true, + .fwctrl_lps = false, + .debug = DBG_EMERG, +}; + +static struct rtl_hal_cfg rtl92de_hal_cfg = { + .bar_id = 2, + .write_readback = true, + .name = "rtl8192de", + .fw_name = "rtlwifi/rtl8192defw.bin", + .ops = &rtl8192de_hal_ops, + .mod_params = &rtl92de_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] = RCR_AM, + .maps[MAC_RCR_AB] = RCR_AB, + .maps[MAC_RCR_ACRC32] = RCR_ACRC32, + .maps[MAC_RCR_ACF] = RCR_ACF, + .maps[MAC_RCR_AAP] = RCR_AAP, + + .maps[EFUSE_TEST] = REG_EFUSE_TEST, + .maps[EFUSE_CTRL] = REG_EFUSE_CTRL, + .maps[EFUSE_CLK] = 0, /* just for 92se */ + .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] = 0, /* just for 92se */ + .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[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, + .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_BcnInt, + .maps[RTL_IMR_RXFOVW] = IMR_RXFOVW, + .maps[RTL_IMR_RDU] = IMR_RDU, + .maps[RTL_IMR_ATIMEND] = IMR_ATIMEND, + .maps[RTL_IMR_BDOK] = IMR_BDOK, + .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_BcnInt | IMR_TBDOK | IMR_TBDER), + + .maps[RTL_RC_CCK_RATE1M] = DESC92_RATE1M, + .maps[RTL_RC_CCK_RATE2M] = DESC92_RATE2M, + .maps[RTL_RC_CCK_RATE5_5M] = DESC92_RATE5_5M, + .maps[RTL_RC_CCK_RATE11M] = DESC92_RATE11M, + .maps[RTL_RC_OFDM_RATE6M] = DESC92_RATE6M, + .maps[RTL_RC_OFDM_RATE9M] = DESC92_RATE9M, + .maps[RTL_RC_OFDM_RATE12M] = DESC92_RATE12M, + .maps[RTL_RC_OFDM_RATE18M] = DESC92_RATE18M, + .maps[RTL_RC_OFDM_RATE24M] = DESC92_RATE24M, + .maps[RTL_RC_OFDM_RATE36M] = DESC92_RATE36M, + .maps[RTL_RC_OFDM_RATE48M] = DESC92_RATE48M, + .maps[RTL_RC_OFDM_RATE54M] = DESC92_RATE54M, + + .maps[RTL_RC_HT_RATEMCS7] = DESC92_RATEMCS7, + .maps[RTL_RC_HT_RATEMCS15] = DESC92_RATEMCS15, +}; + +static struct pci_device_id rtl92de_pci_ids[] __devinitdata = { + {RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8193, rtl92de_hal_cfg)}, + {RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x002B, rtl92de_hal_cfg)}, + {}, +}; + +MODULE_DEVICE_TABLE(pci, rtl92de_pci_ids); + +MODULE_AUTHOR("lizhaoming <chaoming_li@realsil.com.cn>"); +MODULE_AUTHOR("Realtek WlanFAE <wlanfae@realtek.com>"); +MODULE_AUTHOR("Larry Finger <Larry.Finger@lwfinger.net>"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Realtek 8192DE 802.11n Dual Mac PCI wireless"); +MODULE_FIRMWARE("rtlwifi/rtl8192defw.bin"); + +module_param_named(swenc, rtl92de_mod_params.sw_crypto, bool, 0444); +module_param_named(debug, rtl92de_mod_params.debug, int, 0444); +module_param_named(ips, rtl92de_mod_params.inactiveps, bool, 0444); +module_param_named(swlps, rtl92de_mod_params.swctrl_lps, bool, 0444); +module_param_named(fwlps, rtl92de_mod_params.fwctrl_lps, bool, 0444); +MODULE_PARM_DESC(swenc, "Set to 1 for software crypto (default 0)\n"); +MODULE_PARM_DESC(ips, "Set to 0 to not use link power save (default 1)\n"); +MODULE_PARM_DESC(swlps, "Set to 1 to use SW control power save (default 0)\n"); +MODULE_PARM_DESC(fwlps, "Set to 1 to use FW control power save (default 1)\n"); +MODULE_PARM_DESC(debug, "Set debug level (0-5) (default 0)"); + +static const struct dev_pm_ops rtlwifi_pm_ops = { + .suspend = rtl_pci_suspend, + .resume = rtl_pci_resume, + .freeze = rtl_pci_suspend, + .thaw = rtl_pci_resume, + .poweroff = rtl_pci_suspend, + .restore = rtl_pci_resume, +}; + +static struct pci_driver rtl92de_driver = { + .name = KBUILD_MODNAME, + .id_table = rtl92de_pci_ids, + .probe = rtl_pci_probe, + .remove = rtl_pci_disconnect, + .driver.pm = &rtlwifi_pm_ops, +}; + +/* add global spin lock to solve the problem that + * Dul mac register operation on the same time */ +spinlock_t globalmutex_power; +spinlock_t globalmutex_for_fwdownload; +spinlock_t globalmutex_for_power_and_efuse; + +static int __init rtl92de_module_init(void) +{ + int ret = 0; + + spin_lock_init(&globalmutex_power); + spin_lock_init(&globalmutex_for_fwdownload); + spin_lock_init(&globalmutex_for_power_and_efuse); + + ret = pci_register_driver(&rtl92de_driver); + if (ret) + RT_ASSERT(false, "No device found\n"); + return ret; +} + +static void __exit rtl92de_module_exit(void) +{ + pci_unregister_driver(&rtl92de_driver); +} + +module_init(rtl92de_module_init); +module_exit(rtl92de_module_exit); diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/sw.h b/drivers/net/wireless/rtlwifi/rtl8192de/sw.h new file mode 100644 index 00000000..0e6035b8 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192de/sw.h @@ -0,0 +1,37 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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 __RTL92DE_SW_H__ +#define __RTL92DE_SW_H__ + +extern spinlock_t globalmutex_power; +extern spinlock_t globalmutex_for_fwdownload; +extern spinlock_t globalmutex_for_power_and_efuse; + +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/table.c b/drivers/net/wireless/rtlwifi/rtl8192de/table.c new file mode 100644 index 00000000..8ea6f528 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192de/table.c @@ -0,0 +1,1690 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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> + * + * Created on 2010/12/23, 6:38 + *****************************************************************************/ + +#include <linux/types.h> + +#include "table.h" + +u32 rtl8192de_phy_reg_2tarray[PHY_REG_2T_ARRAYLENGTH] = { + 0x024, 0x0011800d, + 0x028, 0x00ffdb83, + 0x014, 0x088ba955, + 0x010, 0x49022b03, + 0x800, 0x80040002, + 0x804, 0x00000003, + 0x808, 0x0000fc00, + 0x80c, 0x0000000a, + 0x810, 0x80706388, + 0x814, 0x020c3d10, + 0x818, 0x02200385, + 0x81c, 0x00000000, + 0x820, 0x01000100, + 0x824, 0x00390004, + 0x828, 0x01000100, + 0x82c, 0x00390004, + 0x830, 0x27272727, + 0x834, 0x27272727, + 0x838, 0x27272727, + 0x83c, 0x27272727, + 0x840, 0x00010000, + 0x844, 0x00010000, + 0x848, 0x27272727, + 0x84c, 0x27272727, + 0x850, 0x00000000, + 0x854, 0x00000000, + 0x858, 0x569a569a, + 0x85c, 0x0c1b25a4, + 0x860, 0x66e60230, + 0x864, 0x061f0130, + 0x868, 0x27272727, + 0x86c, 0x272b2b2b, + 0x870, 0x07000700, + 0x874, 0x22188000, + 0x878, 0x08080808, + 0x87c, 0x00007ff8, + 0x880, 0xc0083070, + 0x884, 0x00000cd5, + 0x888, 0x00000000, + 0x88c, 0xcc0000c0, + 0x890, 0x00000800, + 0x894, 0xfffffffe, + 0x898, 0x40302010, + 0x89c, 0x00706050, + 0x900, 0x00000000, + 0x904, 0x00000023, + 0x908, 0x00000000, + 0x90c, 0x81121313, + 0xa00, 0x00d047c8, + 0xa04, 0x80ff000c, + 0xa08, 0x8c838300, + 0xa0c, 0x2e68120f, + 0xa10, 0x9500bb78, + 0xa14, 0x11144028, + 0xa18, 0x00881117, + 0xa1c, 0x89140f00, + 0xa20, 0x1a1b0000, + 0xa24, 0x090e1317, + 0xa28, 0x00000204, + 0xa2c, 0x00d30000, + 0xa70, 0x101fbf00, + 0xa74, 0x00000007, + 0xc00, 0x40071d40, + 0xc04, 0x03a05633, + 0xc08, 0x001000e4, + 0xc0c, 0x6c6c6c6c, + 0xc10, 0x08800000, + 0xc14, 0x40000100, + 0xc18, 0x08800000, + 0xc1c, 0x40000100, + 0xc20, 0x00000000, + 0xc24, 0x00000000, + 0xc28, 0x00000000, + 0xc2c, 0x00000000, + 0xc30, 0x69e9ac44, + 0xc34, 0x469652cf, + 0xc38, 0x49795994, + 0xc3c, 0x0a979718, + 0xc40, 0x1f7c403f, + 0xc44, 0x000100b7, + 0xc48, 0xec020107, + 0xc4c, 0x007f037f, + 0xc50, 0x69543420, + 0xc54, 0x43bc009e, + 0xc58, 0x69543420, + 0xc5c, 0x433c00a8, + 0xc60, 0x00000000, + 0xc64, 0x5116848b, + 0xc68, 0x47c00bff, + 0xc6c, 0x00000036, + 0xc70, 0x2c7f000d, + 0xc74, 0x058610db, + 0xc78, 0x0000001f, + 0xc7c, 0x40b95612, + 0xc80, 0x40000100, + 0xc84, 0x20f60000, + 0xc88, 0x40000100, + 0xc8c, 0x20e00000, + 0xc90, 0x00121820, + 0xc94, 0x00000007, + 0xc98, 0x00121820, + 0xc9c, 0x00007f7f, + 0xca0, 0x00000000, + 0xca4, 0x00000080, + 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, 0x64b11e20, + 0xcdc, 0xe8767533, + 0xce0, 0x00222222, + 0xce4, 0x00000000, + 0xce8, 0x37644302, + 0xcec, 0x2f97d40c, + 0xd00, 0x00080740, + 0xd04, 0x00020403, + 0xd08, 0x0000907f, + 0xd0c, 0x20010201, + 0xd10, 0xa0633333, + 0xd14, 0x3333bc43, + 0xd18, 0x7a8f5b6b, + 0xd2c, 0xcc979975, + 0xd30, 0x00000000, + 0xd34, 0x80608404, + 0xd38, 0x00000000, + 0xd3c, 0x00027293, + 0xd40, 0x00000000, + 0xd44, 0x00000000, + 0xd48, 0x00000000, + 0xd4c, 0x00000000, + 0xd50, 0x6437140a, + 0xd54, 0x00000000, + 0xd58, 0x00000000, + 0xd5c, 0x30032064, + 0xd60, 0x4653de68, + 0xd64, 0x04518a3c, + 0xd68, 0x00002101, + 0xd6c, 0x2a201c16, + 0xd70, 0x1812362e, + 0xd74, 0x322c2220, + 0xd78, 0x000e3c24, + 0xe00, 0x2a2a2a2a, + 0xe04, 0x2a2a2a2a, + 0xe08, 0x03902a2a, + 0xe10, 0x2a2a2a2a, + 0xe14, 0x2a2a2a2a, + 0xe18, 0x2a2a2a2a, + 0xe1c, 0x2a2a2a2a, + 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, 0x00000010, + 0xe68, 0x001b25a4, + 0xe6c, 0x63db25a4, + 0xe70, 0x63db25a4, + 0xe74, 0x0c126da4, + 0xe78, 0x0c126da4, + 0xe7c, 0x0c126da4, + 0xe80, 0x0c126da4, + 0xe84, 0x63db25a4, + 0xe88, 0x0c126da4, + 0xe8c, 0x63db25a4, + 0xed0, 0x63db25a4, + 0xed4, 0x63db25a4, + 0xed8, 0x63db25a4, + 0xedc, 0x001b25a4, + 0xee0, 0x001b25a4, + 0xeec, 0x6fdb25a4, + 0xf14, 0x00000003, + 0xf1c, 0x00000064, + 0xf4c, 0x00000004, + 0xf00, 0x00000300, +}; + +u32 rtl8192de_phy_reg_array_pg[PHY_REG_ARRAY_PG_LENGTH] = { + 0xe00, 0xffffffff, 0x07090c0c, + 0xe04, 0xffffffff, 0x01020405, + 0xe08, 0x0000ff00, 0x00000000, + 0x86c, 0xffffff00, 0x00000000, + 0xe10, 0xffffffff, 0x0b0c0c0e, + 0xe14, 0xffffffff, 0x01030506, + 0xe18, 0xffffffff, 0x0b0c0d0e, + 0xe1c, 0xffffffff, 0x01030509, + 0x830, 0xffffffff, 0x07090c0c, + 0x834, 0xffffffff, 0x01020405, + 0x838, 0xffffff00, 0x00000000, + 0x86c, 0x000000ff, 0x00000000, + 0x83c, 0xffffffff, 0x0b0c0c0e, + 0x848, 0xffffffff, 0x01030506, + 0x84c, 0xffffffff, 0x0b0c0d0e, + 0x868, 0xffffffff, 0x01030509, + 0xe00, 0xffffffff, 0x00000000, + 0xe04, 0xffffffff, 0x00000000, + 0xe08, 0x0000ff00, 0x00000000, + 0x86c, 0xffffff00, 0x00000000, + 0xe10, 0xffffffff, 0x00000000, + 0xe14, 0xffffffff, 0x00000000, + 0xe18, 0xffffffff, 0x00000000, + 0xe1c, 0xffffffff, 0x00000000, + 0x830, 0xffffffff, 0x00000000, + 0x834, 0xffffffff, 0x00000000, + 0x838, 0xffffff00, 0x00000000, + 0x86c, 0x000000ff, 0x00000000, + 0x83c, 0xffffffff, 0x00000000, + 0x848, 0xffffffff, 0x00000000, + 0x84c, 0xffffffff, 0x00000000, + 0x868, 0xffffffff, 0x00000000, + 0xe00, 0xffffffff, 0x04040404, + 0xe04, 0xffffffff, 0x00020204, + 0xe08, 0x0000ff00, 0x00000000, + 0x86c, 0xffffff00, 0x00000000, + 0xe10, 0xffffffff, 0x06060606, + 0xe14, 0xffffffff, 0x00020406, + 0xe18, 0xffffffff, 0x00000000, + 0xe1c, 0xffffffff, 0x00000000, + 0x830, 0xffffffff, 0x04040404, + 0x834, 0xffffffff, 0x00020204, + 0x838, 0xffffff00, 0x00000000, + 0x86c, 0x000000ff, 0x00000000, + 0x83c, 0xffffffff, 0x06060606, + 0x848, 0xffffffff, 0x00020406, + 0x84c, 0xffffffff, 0x00000000, + 0x868, 0xffffffff, 0x00000000, + 0xe00, 0xffffffff, 0x00000000, + 0xe04, 0xffffffff, 0x00000000, + 0xe08, 0x0000ff00, 0x00000000, + 0x86c, 0xffffff00, 0x00000000, + 0xe10, 0xffffffff, 0x00000000, + 0xe14, 0xffffffff, 0x00000000, + 0xe18, 0xffffffff, 0x00000000, + 0xe1c, 0xffffffff, 0x00000000, + 0x830, 0xffffffff, 0x00000000, + 0x834, 0xffffffff, 0x00000000, + 0x838, 0xffffff00, 0x00000000, + 0x86c, 0x000000ff, 0x00000000, + 0x83c, 0xffffffff, 0x00000000, + 0x848, 0xffffffff, 0x00000000, + 0x84c, 0xffffffff, 0x00000000, + 0x868, 0xffffffff, 0x00000000, + 0xe00, 0xffffffff, 0x00000000, + 0xe04, 0xffffffff, 0x00000000, + 0xe08, 0x0000ff00, 0x00000000, + 0x86c, 0xffffff00, 0x00000000, + 0xe10, 0xffffffff, 0x00000000, + 0xe14, 0xffffffff, 0x00000000, + 0xe18, 0xffffffff, 0x00000000, + 0xe1c, 0xffffffff, 0x00000000, + 0x830, 0xffffffff, 0x00000000, + 0x834, 0xffffffff, 0x00000000, + 0x838, 0xffffff00, 0x00000000, + 0x86c, 0x000000ff, 0x00000000, + 0x83c, 0xffffffff, 0x00000000, + 0x848, 0xffffffff, 0x00000000, + 0x84c, 0xffffffff, 0x00000000, + 0x868, 0xffffffff, 0x00000000, + 0xe00, 0xffffffff, 0x04040404, + 0xe04, 0xffffffff, 0x00020204, + 0xe08, 0x0000ff00, 0x00000000, + 0x86c, 0xffffff00, 0x00000000, + 0xe10, 0xffffffff, 0x00000000, + 0xe14, 0xffffffff, 0x00000000, + 0xe18, 0xffffffff, 0x00000000, + 0xe1c, 0xffffffff, 0x00000000, + 0x830, 0xffffffff, 0x04040404, + 0x834, 0xffffffff, 0x00020204, + 0x838, 0xffffff00, 0x00000000, + 0x86c, 0x000000ff, 0x00000000, + 0x83c, 0xffffffff, 0x00000000, + 0x848, 0xffffffff, 0x00000000, + 0x84c, 0xffffffff, 0x00000000, + 0x868, 0xffffffff, 0x00000000, + 0xe00, 0xffffffff, 0x00000000, + 0xe04, 0xffffffff, 0x00000000, + 0xe08, 0x0000ff00, 0x00000000, + 0x86c, 0xffffff00, 0x00000000, + 0xe10, 0xffffffff, 0x00000000, + 0xe14, 0xffffffff, 0x00000000, + 0xe18, 0xffffffff, 0x00000000, + 0xe1c, 0xffffffff, 0x00000000, + 0x830, 0xffffffff, 0x00000000, + 0x834, 0xffffffff, 0x00000000, + 0x838, 0xffffff00, 0x00000000, + 0x86c, 0x000000ff, 0x00000000, + 0x83c, 0xffffffff, 0x00000000, + 0x848, 0xffffffff, 0x00000000, + 0x84c, 0xffffffff, 0x00000000, + 0x868, 0xffffffff, 0x00000000, + 0xe00, 0xffffffff, 0x04040404, + 0xe04, 0xffffffff, 0x00020204, + 0xe08, 0x0000ff00, 0x00000000, + 0x86c, 0xffffff00, 0x00000000, + 0xe10, 0xffffffff, 0x08080808, + 0xe14, 0xffffffff, 0x00040408, + 0xe18, 0xffffffff, 0x00000000, + 0xe1c, 0xffffffff, 0x00000000, + 0x830, 0xffffffff, 0x04040404, + 0x834, 0xffffffff, 0x00020204, + 0x838, 0xffffff00, 0x00000000, + 0x86c, 0x000000ff, 0x00000000, + 0x83c, 0xffffffff, 0x08080808, + 0x848, 0xffffffff, 0x00040408, + 0x84c, 0xffffffff, 0x00000000, + 0x868, 0xffffffff, 0x00000000, + 0xe00, 0xffffffff, 0x04040404, + 0xe04, 0xffffffff, 0x00020204, + 0xe08, 0x0000ff00, 0x00000000, + 0x86c, 0xffffff00, 0x00000000, + 0xe10, 0xffffffff, 0x08080808, + 0xe14, 0xffffffff, 0x00040408, + 0xe18, 0xffffffff, 0x00000000, + 0xe1c, 0xffffffff, 0x00000000, + 0x830, 0xffffffff, 0x04040404, + 0x834, 0xffffffff, 0x00020204, + 0x838, 0xffffff00, 0x00000000, + 0x86c, 0x000000ff, 0x00000000, + 0x83c, 0xffffffff, 0x08080808, + 0x848, 0xffffffff, 0x00040408, + 0x84c, 0xffffffff, 0x00000000, + 0x868, 0xffffffff, 0x00000000, + 0xe00, 0xffffffff, 0x04040404, + 0xe04, 0xffffffff, 0x00020204, + 0xe08, 0x0000ff00, 0x00000000, + 0x86c, 0xffffff00, 0x00000000, + 0xe10, 0xffffffff, 0x08080808, + 0xe14, 0xffffffff, 0x00040408, + 0xe18, 0xffffffff, 0x00000000, + 0xe1c, 0xffffffff, 0x00000000, + 0x830, 0xffffffff, 0x04040404, + 0x834, 0xffffffff, 0x00020204, + 0x838, 0xffffff00, 0x00000000, + 0x86c, 0x000000ff, 0x00000000, + 0x83c, 0xffffffff, 0x08080808, + 0x848, 0xffffffff, 0x00040408, + 0x84c, 0xffffffff, 0x00000000, + 0x868, 0xffffffff, 0x00000000, + 0xe00, 0xffffffff, 0x04040404, + 0xe04, 0xffffffff, 0x00020204, + 0xe08, 0x0000ff00, 0x00000000, + 0x86c, 0xffffff00, 0x00000000, + 0xe10, 0xffffffff, 0x08080808, + 0xe14, 0xffffffff, 0x00040408, + 0xe18, 0xffffffff, 0x00000000, + 0xe1c, 0xffffffff, 0x00000000, + 0x830, 0xffffffff, 0x04040404, + 0x834, 0xffffffff, 0x00020204, + 0x838, 0xffffff00, 0x00000000, + 0x86c, 0x000000ff, 0x00000000, + 0x83c, 0xffffffff, 0x08080808, + 0x848, 0xffffffff, 0x00040408, + 0x84c, 0xffffffff, 0x00000000, + 0x868, 0xffffffff, 0x00000000, + 0xe00, 0xffffffff, 0x04040404, + 0xe04, 0xffffffff, 0x00020204, + 0xe08, 0x0000ff00, 0x00000000, + 0x86c, 0xffffff00, 0x00000000, + 0xe10, 0xffffffff, 0x08080808, + 0xe14, 0xffffffff, 0x00040408, + 0xe18, 0xffffffff, 0x00000000, + 0xe1c, 0xffffffff, 0x00000000, + 0x830, 0xffffffff, 0x04040404, + 0x834, 0xffffffff, 0x00020204, + 0x838, 0xffffff00, 0x00000000, + 0x86c, 0x000000ff, 0x00000000, + 0x83c, 0xffffffff, 0x08080808, + 0x848, 0xffffffff, 0x00040408, + 0x84c, 0xffffffff, 0x00000000, + 0x868, 0xffffffff, 0x00000000, + 0xe00, 0xffffffff, 0x04040404, + 0xe04, 0xffffffff, 0x00020204, + 0xe08, 0x0000ff00, 0x00000000, + 0x86c, 0xffffff00, 0x00000000, + 0xe10, 0xffffffff, 0x08080808, + 0xe14, 0xffffffff, 0x00040408, + 0xe18, 0xffffffff, 0x00000000, + 0xe1c, 0xffffffff, 0x00000000, + 0x830, 0xffffffff, 0x04040404, + 0x834, 0xffffffff, 0x00020204, + 0x838, 0xffffff00, 0x00000000, + 0x86c, 0x000000ff, 0x00000000, + 0x83c, 0xffffffff, 0x08080808, + 0x848, 0xffffffff, 0x00040408, + 0x84c, 0xffffffff, 0x00000000, + 0x868, 0xffffffff, 0x00000000, +}; + +u32 rtl8192de_radioa_2tarray[RADIOA_2T_ARRAYLENGTH] = { + 0x000, 0x00030000, + 0x001, 0x00030000, + 0x002, 0x00000000, + 0x003, 0x00018c63, + 0x004, 0x00018c63, + 0x008, 0x00084000, + 0x00b, 0x0001c000, + 0x00e, 0x00018c67, + 0x00f, 0x00000851, + 0x014, 0x00021440, + 0x018, 0x00017524, + 0x019, 0x00000000, + 0x01d, 0x000a1290, + 0x023, 0x00001558, + 0x01a, 0x00030a99, + 0x01b, 0x00040b00, + 0x01c, 0x000fc339, + 0x03a, 0x000a57eb, + 0x03b, 0x00020000, + 0x03c, 0x000ff454, + 0x020, 0x0000aa52, + 0x021, 0x00054000, + 0x040, 0x0000aa52, + 0x041, 0x00014000, + 0x025, 0x000803be, + 0x026, 0x000fc638, + 0x027, 0x00077c18, + 0x028, 0x000de471, + 0x029, 0x000d7110, + 0x02a, 0x0008cb04, + 0x02b, 0x0004128b, + 0x02c, 0x00001840, + 0x043, 0x0002444f, + 0x044, 0x0001adb0, + 0x045, 0x00056467, + 0x046, 0x0008992c, + 0x047, 0x0000452c, + 0x048, 0x000f9c43, + 0x049, 0x00002e0c, + 0x04a, 0x000546eb, + 0x04b, 0x0008966c, + 0x04c, 0x0000dde9, + 0x018, 0x00007401, + 0x000, 0x00070000, + 0x012, 0x000dc000, + 0x012, 0x00090000, + 0x012, 0x00051000, + 0x012, 0x00012000, + 0x013, 0x000287b7, + 0x013, 0x000247ab, + 0x013, 0x0002079f, + 0x013, 0x0001c793, + 0x013, 0x0001839b, + 0x013, 0x00014392, + 0x013, 0x0001019a, + 0x013, 0x0000c191, + 0x013, 0x00008194, + 0x013, 0x000040a0, + 0x013, 0x00000018, + 0x015, 0x0000f424, + 0x015, 0x0004f424, + 0x015, 0x0008f424, + 0x016, 0x000e1330, + 0x016, 0x000a1330, + 0x016, 0x00061330, + 0x016, 0x00021330, + 0x018, 0x00017524, + 0x000, 0x00070000, + 0x012, 0x000cf000, + 0x012, 0x000bc000, + 0x012, 0x00078000, + 0x012, 0x00000000, + 0x013, 0x000287bc, + 0x013, 0x000247b0, + 0x013, 0x000203b4, + 0x013, 0x0001c3a8, + 0x013, 0x000181b4, + 0x013, 0x000141a8, + 0x013, 0x000100b0, + 0x013, 0x0000c0a4, + 0x013, 0x0000b02c, + 0x013, 0x00004020, + 0x013, 0x00000014, + 0x015, 0x0000f4c3, + 0x015, 0x0004f4c3, + 0x015, 0x0008f4c3, + 0x016, 0x000e085f, + 0x016, 0x000a085f, + 0x016, 0x0006085f, + 0x016, 0x0002085f, + 0x018, 0x00037524, + 0x000, 0x00070000, + 0x012, 0x000cf000, + 0x012, 0x000bc000, + 0x012, 0x00078000, + 0x012, 0x00000000, + 0x013, 0x000287bc, + 0x013, 0x000247b0, + 0x013, 0x000203b4, + 0x013, 0x0001c3a8, + 0x013, 0x000181b4, + 0x013, 0x000141a8, + 0x013, 0x000100b0, + 0x013, 0x0000c0a4, + 0x013, 0x0000b02c, + 0x013, 0x00004020, + 0x013, 0x00000014, + 0x015, 0x0000f4c3, + 0x015, 0x0004f4c3, + 0x015, 0x0008f4c3, + 0x016, 0x000e085f, + 0x016, 0x000a085f, + 0x016, 0x0006085f, + 0x016, 0x0002085f, + 0x018, 0x00057568, + 0x000, 0x00070000, + 0x012, 0x000cf000, + 0x012, 0x000bc000, + 0x012, 0x00078000, + 0x012, 0x00000000, + 0x013, 0x000287bc, + 0x013, 0x000247b0, + 0x013, 0x000203b4, + 0x013, 0x0001c3a8, + 0x013, 0x000181b4, + 0x013, 0x000141a8, + 0x013, 0x000100b0, + 0x013, 0x0000c0a4, + 0x013, 0x0000b02c, + 0x013, 0x00004020, + 0x013, 0x00000014, + 0x015, 0x0000f4c3, + 0x015, 0x0004f4c3, + 0x015, 0x0008f4c3, + 0x016, 0x000e085f, + 0x016, 0x000a085f, + 0x016, 0x0006085f, + 0x016, 0x0002085f, + 0x030, 0x0004470f, + 0x031, 0x00044ff0, + 0x032, 0x00000070, + 0x033, 0x000dd480, + 0x034, 0x000ffac0, + 0x035, 0x000b80c0, + 0x036, 0x00077000, + 0x037, 0x00064ff2, + 0x038, 0x000e7661, + 0x039, 0x00000e90, + 0x000, 0x00030000, + 0x018, 0x0000f401, + 0x0fe, 0x00000000, + 0x0fe, 0x00000000, + 0x01e, 0x00088009, + 0x01f, 0x00080003, + 0x0fe, 0x00000000, + 0x01e, 0x00088001, + 0x01f, 0x00080000, + 0x0fe, 0x00000000, + 0x018, 0x00097524, + 0x0fe, 0x00000000, + 0x0fe, 0x00000000, + 0x0fe, 0x00000000, + 0x0fe, 0x00000000, + 0x02b, 0x00041289, + 0x0fe, 0x00000000, + 0x02d, 0x0006aaaa, + 0x02e, 0x000b4d01, + 0x02d, 0x00080000, + 0x02e, 0x00004d02, + 0x02d, 0x00095555, + 0x02e, 0x00054d03, + 0x02d, 0x000aaaaa, + 0x02e, 0x000b4d04, + 0x02d, 0x000c0000, + 0x02e, 0x00004d05, + 0x02d, 0x000d5555, + 0x02e, 0x00054d06, + 0x02d, 0x000eaaaa, + 0x02e, 0x000b4d07, + 0x02d, 0x00000000, + 0x02e, 0x00005108, + 0x02d, 0x00015555, + 0x02e, 0x00055109, + 0x02d, 0x0002aaaa, + 0x02e, 0x000b510a, + 0x02d, 0x00040000, + 0x02e, 0x0000510b, + 0x02d, 0x00055555, + 0x02e, 0x0005510c, +}; + +u32 rtl8192de_radiob_2tarray[RADIOB_2T_ARRAYLENGTH] = { + 0x000, 0x00030000, + 0x001, 0x00030000, + 0x002, 0x00000000, + 0x003, 0x00018c63, + 0x004, 0x00018c63, + 0x008, 0x00084000, + 0x00b, 0x0001c000, + 0x00e, 0x00018c67, + 0x00f, 0x00000851, + 0x014, 0x00021440, + 0x018, 0x00007401, + 0x019, 0x00000060, + 0x01d, 0x000a1290, + 0x023, 0x00001558, + 0x01a, 0x00030a99, + 0x01b, 0x00040b00, + 0x01c, 0x000fc339, + 0x03a, 0x000a57eb, + 0x03b, 0x00020000, + 0x03c, 0x000ff454, + 0x020, 0x0000aa52, + 0x021, 0x00054000, + 0x040, 0x0000aa52, + 0x041, 0x00014000, + 0x025, 0x000803be, + 0x026, 0x000fc638, + 0x027, 0x00077c18, + 0x028, 0x000d1c31, + 0x029, 0x000d7110, + 0x02a, 0x000aeb04, + 0x02b, 0x0004128b, + 0x02c, 0x00001840, + 0x043, 0x0002444f, + 0x044, 0x0001adb0, + 0x045, 0x00056467, + 0x046, 0x0008992c, + 0x047, 0x0000452c, + 0x048, 0x000f9c43, + 0x049, 0x00002e0c, + 0x04a, 0x000546eb, + 0x04b, 0x0008966c, + 0x04c, 0x0000dde9, + 0x018, 0x00007401, + 0x000, 0x00070000, + 0x012, 0x000dc000, + 0x012, 0x00090000, + 0x012, 0x00051000, + 0x012, 0x00012000, + 0x013, 0x000287b7, + 0x013, 0x000247ab, + 0x013, 0x0002079f, + 0x013, 0x0001c793, + 0x013, 0x0001839b, + 0x013, 0x00014392, + 0x013, 0x0001019a, + 0x013, 0x0000c191, + 0x013, 0x00008194, + 0x013, 0x000040a0, + 0x013, 0x00000018, + 0x015, 0x0000f424, + 0x015, 0x0004f424, + 0x015, 0x0008f424, + 0x016, 0x000e1330, + 0x016, 0x000a1330, + 0x016, 0x00061330, + 0x016, 0x00021330, + 0x018, 0x00017524, + 0x000, 0x00070000, + 0x012, 0x000cf000, + 0x012, 0x000bc000, + 0x012, 0x00078000, + 0x012, 0x00000000, + 0x013, 0x000287bc, + 0x013, 0x000247b0, + 0x013, 0x000203b4, + 0x013, 0x0001c3a8, + 0x013, 0x000181b4, + 0x013, 0x000141a8, + 0x013, 0x000100b0, + 0x013, 0x0000c0a4, + 0x013, 0x0000b02c, + 0x013, 0x00004020, + 0x013, 0x00000014, + 0x015, 0x0000f4c3, + 0x015, 0x0004f4c3, + 0x015, 0x0008f4c3, + 0x016, 0x000e085f, + 0x016, 0x000a085f, + 0x016, 0x0006085f, + 0x016, 0x0002085f, + 0x018, 0x00037524, + 0x000, 0x00070000, + 0x012, 0x000cf000, + 0x012, 0x000bc000, + 0x012, 0x00078000, + 0x012, 0x00000000, + 0x013, 0x000287bc, + 0x013, 0x000247b0, + 0x013, 0x000203b4, + 0x013, 0x0001c3a8, + 0x013, 0x000181b4, + 0x013, 0x000141a8, + 0x013, 0x000100b0, + 0x013, 0x0000c0a4, + 0x013, 0x0000b02c, + 0x013, 0x00004020, + 0x013, 0x00000014, + 0x015, 0x0000f4c3, + 0x015, 0x0004f4c3, + 0x015, 0x0008f4c3, + 0x016, 0x000e085f, + 0x016, 0x000a085f, + 0x016, 0x0006085f, + 0x016, 0x0002085f, + 0x018, 0x00057524, + 0x000, 0x00070000, + 0x012, 0x000cf000, + 0x012, 0x000bc000, + 0x012, 0x00078000, + 0x012, 0x00000000, + 0x013, 0x000287bc, + 0x013, 0x000247b0, + 0x013, 0x000203b4, + 0x013, 0x0001c3a8, + 0x013, 0x000181b4, + 0x013, 0x000141a8, + 0x013, 0x000100b0, + 0x013, 0x0000c0a4, + 0x013, 0x0000b02c, + 0x013, 0x00004020, + 0x013, 0x00000014, + 0x015, 0x0000f4c3, + 0x015, 0x0004f4c3, + 0x015, 0x0008f4c3, + 0x016, 0x000e085f, + 0x016, 0x000a085f, + 0x016, 0x0006085f, + 0x016, 0x0002085f, + 0x030, 0x0004470f, + 0x031, 0x00044ff0, + 0x032, 0x00000070, + 0x033, 0x000dd480, + 0x034, 0x000ffac0, + 0x035, 0x000b80c0, + 0x036, 0x00077000, + 0x037, 0x00064ff2, + 0x038, 0x000e7661, + 0x039, 0x00000e90, + 0x000, 0x00030000, + 0x018, 0x0000f401, + 0x0fe, 0x00000000, + 0x0fe, 0x00000000, + 0x01e, 0x00088009, + 0x01f, 0x00080003, + 0x0fe, 0x00000000, + 0x01e, 0x00088001, + 0x01f, 0x00080000, + 0x0fe, 0x00000000, + 0x018, 0x00087401, + 0x0fe, 0x00000000, + 0x0fe, 0x00000000, + 0x0fe, 0x00000000, + 0x02b, 0x00041289, + 0x0fe, 0x00000000, + 0x02d, 0x00066666, + 0x02e, 0x00064001, + 0x02d, 0x00091111, + 0x02e, 0x00014002, + 0x02d, 0x000bbbbb, + 0x02e, 0x000b4003, + 0x02d, 0x000e6666, + 0x02e, 0x00064004, + 0x02d, 0x00088888, + 0x02e, 0x00084005, + 0x02d, 0x0009dddd, + 0x02e, 0x000d4006, + 0x02d, 0x000b3333, + 0x02e, 0x00034007, + 0x02d, 0x00048888, + 0x02e, 0x00084408, + 0x02d, 0x000bbbbb, + 0x02e, 0x000b4409, + 0x02d, 0x000e6666, + 0x02e, 0x0006440a, + 0x02d, 0x00011111, + 0x02e, 0x0001480b, + 0x02d, 0x0003bbbb, + 0x02e, 0x000b480c, + 0x02d, 0x00066666, + 0x02e, 0x0006480d, + 0x02d, 0x000ccccc, + 0x02e, 0x000c480e, +}; + +u32 rtl8192de_radioa_2t_int_paarray[RADIOA_2T_INT_PA_ARRAYLENGTH] = { + 0x000, 0x00030000, + 0x001, 0x00030000, + 0x002, 0x00000000, + 0x003, 0x00018c63, + 0x004, 0x00018c63, + 0x008, 0x00084000, + 0x00b, 0x0001c000, + 0x00e, 0x00018c67, + 0x00f, 0x00000851, + 0x014, 0x00021440, + 0x018, 0x00017524, + 0x019, 0x00000000, + 0x01d, 0x000a1290, + 0x023, 0x00001558, + 0x01a, 0x00030a99, + 0x01b, 0x00040b00, + 0x01c, 0x000fc339, + 0x03a, 0x000a57eb, + 0x03b, 0x00020000, + 0x03c, 0x000ff454, + 0x020, 0x0000aa52, + 0x021, 0x00054000, + 0x040, 0x0000aa52, + 0x041, 0x00014000, + 0x025, 0x000803be, + 0x026, 0x000fc638, + 0x027, 0x00077c18, + 0x028, 0x000de471, + 0x029, 0x000d7110, + 0x02a, 0x0008eb04, + 0x02b, 0x0004128b, + 0x02c, 0x00001840, + 0x043, 0x0002444f, + 0x044, 0x0001adb0, + 0x045, 0x00056467, + 0x046, 0x0008992c, + 0x047, 0x0000452c, + 0x048, 0x000c0443, + 0x049, 0x00000730, + 0x04a, 0x00050f0f, + 0x04b, 0x000896ee, + 0x04c, 0x0000ddee, + 0x018, 0x00007401, + 0x000, 0x00070000, + 0x012, 0x000dc000, + 0x012, 0x00090000, + 0x012, 0x00051000, + 0x012, 0x00012000, + 0x013, 0x000287b7, + 0x013, 0x000247ab, + 0x013, 0x0002079f, + 0x013, 0x0001c793, + 0x013, 0x0001839b, + 0x013, 0x00014392, + 0x013, 0x0001019a, + 0x013, 0x0000c191, + 0x013, 0x00008194, + 0x013, 0x000040a0, + 0x013, 0x00000018, + 0x015, 0x0000f424, + 0x015, 0x0004f424, + 0x015, 0x0008f424, + 0x016, 0x000e1330, + 0x016, 0x000a1330, + 0x016, 0x00061330, + 0x016, 0x00021330, + 0x018, 0x00017524, + 0x000, 0x00070000, + 0x012, 0x000cf000, + 0x012, 0x000bc000, + 0x012, 0x00078000, + 0x012, 0x00000000, + 0x013, 0x000287bf, + 0x013, 0x000247b3, + 0x013, 0x000207a7, + 0x013, 0x0001c79b, + 0x013, 0x0001839f, + 0x013, 0x00014393, + 0x013, 0x00010399, + 0x013, 0x0000c38d, + 0x013, 0x00008199, + 0x013, 0x0000418d, + 0x013, 0x00000099, + 0x015, 0x0000f495, + 0x015, 0x0004f495, + 0x015, 0x0008f495, + 0x016, 0x000e1874, + 0x016, 0x000a1874, + 0x016, 0x00061874, + 0x016, 0x00021874, + 0x018, 0x00037564, + 0x000, 0x00070000, + 0x012, 0x000cf000, + 0x012, 0x000bc000, + 0x012, 0x00078000, + 0x012, 0x00000000, + 0x013, 0x000287bf, + 0x013, 0x000247b3, + 0x013, 0x000207a7, + 0x013, 0x0001c79b, + 0x013, 0x0001839f, + 0x013, 0x00014393, + 0x013, 0x00010399, + 0x013, 0x0000c38d, + 0x013, 0x00008199, + 0x013, 0x0000418d, + 0x013, 0x00000099, + 0x015, 0x0000f495, + 0x015, 0x0004f495, + 0x015, 0x0008f495, + 0x016, 0x000e1874, + 0x016, 0x000a1874, + 0x016, 0x00061874, + 0x016, 0x00021874, + 0x018, 0x00057595, + 0x000, 0x00070000, + 0x012, 0x000cf000, + 0x012, 0x000bc000, + 0x012, 0x00078000, + 0x012, 0x00000000, + 0x013, 0x000287bf, + 0x013, 0x000247b3, + 0x013, 0x000207a7, + 0x013, 0x0001c79b, + 0x013, 0x0001839f, + 0x013, 0x00014393, + 0x013, 0x00010399, + 0x013, 0x0000c38d, + 0x013, 0x00008199, + 0x013, 0x0000418d, + 0x013, 0x00000099, + 0x015, 0x0000f495, + 0x015, 0x0004f495, + 0x015, 0x0008f495, + 0x016, 0x000e1874, + 0x016, 0x000a1874, + 0x016, 0x00061874, + 0x016, 0x00021874, + 0x030, 0x0004470f, + 0x031, 0x00044ff0, + 0x032, 0x00000070, + 0x033, 0x000dd480, + 0x034, 0x000ffac0, + 0x035, 0x000b80c0, + 0x036, 0x00077000, + 0x037, 0x00064ff2, + 0x038, 0x000e7661, + 0x039, 0x00000e90, + 0x000, 0x00030000, + 0x018, 0x0000f401, + 0x0fe, 0x00000000, + 0x0fe, 0x00000000, + 0x01e, 0x00088009, + 0x01f, 0x00080003, + 0x0fe, 0x00000000, + 0x01e, 0x00088001, + 0x01f, 0x00080000, + 0x0fe, 0x00000000, + 0x018, 0x00097524, + 0x0fe, 0x00000000, + 0x0fe, 0x00000000, + 0x0fe, 0x00000000, + 0x0fe, 0x00000000, + 0x02b, 0x00041289, + 0x0fe, 0x00000000, + 0x02d, 0x0006aaaa, + 0x02e, 0x000b4d01, + 0x02d, 0x00080000, + 0x02e, 0x00004d02, + 0x02d, 0x00095555, + 0x02e, 0x00054d03, + 0x02d, 0x000aaaaa, + 0x02e, 0x000b4d04, + 0x02d, 0x000c0000, + 0x02e, 0x00004d05, + 0x02d, 0x000d5555, + 0x02e, 0x00054d06, + 0x02d, 0x000eaaaa, + 0x02e, 0x000b4d07, + 0x02d, 0x00000000, + 0x02e, 0x00005108, + 0x02d, 0x00015555, + 0x02e, 0x00055109, + 0x02d, 0x0002aaaa, + 0x02e, 0x000b510a, + 0x02d, 0x00040000, + 0x02e, 0x0000510b, + 0x02d, 0x00055555, + 0x02e, 0x0005510c, +}; + +u32 rtl8192de_radiob_2t_int_paarray[RADIOB_2T_INT_PA_ARRAYLENGTH] = { + 0x000, 0x00030000, + 0x001, 0x00030000, + 0x002, 0x00000000, + 0x003, 0x00018c63, + 0x004, 0x00018c63, + 0x008, 0x00084000, + 0x00b, 0x0001c000, + 0x00e, 0x00018c67, + 0x00f, 0x00000851, + 0x014, 0x00021440, + 0x018, 0x00007401, + 0x019, 0x00000060, + 0x01d, 0x000a1290, + 0x023, 0x00001558, + 0x01a, 0x00030a99, + 0x01b, 0x00040b00, + 0x01c, 0x000fc339, + 0x03a, 0x000a57eb, + 0x03b, 0x00020000, + 0x03c, 0x000ff454, + 0x020, 0x0000aa52, + 0x021, 0x00054000, + 0x040, 0x0000aa52, + 0x041, 0x00014000, + 0x025, 0x000803be, + 0x026, 0x000fc638, + 0x027, 0x00077c18, + 0x028, 0x000d1c31, + 0x029, 0x000d7110, + 0x02a, 0x000aeb04, + 0x02b, 0x0004128b, + 0x02c, 0x00001840, + 0x043, 0x0002444f, + 0x044, 0x0001adb0, + 0x045, 0x00056467, + 0x046, 0x0008992c, + 0x047, 0x0000452c, + 0x048, 0x000c0443, + 0x049, 0x00000730, + 0x04a, 0x00050f0f, + 0x04b, 0x000896ee, + 0x04c, 0x0000ddee, + 0x018, 0x00007401, + 0x000, 0x00070000, + 0x012, 0x000dc000, + 0x012, 0x00090000, + 0x012, 0x00051000, + 0x012, 0x00012000, + 0x013, 0x000287b7, + 0x013, 0x000247ab, + 0x013, 0x0002079f, + 0x013, 0x0001c793, + 0x013, 0x0001839b, + 0x013, 0x00014392, + 0x013, 0x0001019a, + 0x013, 0x0000c191, + 0x013, 0x00008194, + 0x013, 0x000040a0, + 0x013, 0x00000018, + 0x015, 0x0000f424, + 0x015, 0x0004f424, + 0x015, 0x0008f424, + 0x016, 0x000e1330, + 0x016, 0x000a1330, + 0x016, 0x00061330, + 0x016, 0x00021330, + 0x018, 0x00017524, + 0x000, 0x00070000, + 0x012, 0x000cf000, + 0x012, 0x000bc000, + 0x012, 0x00078000, + 0x012, 0x00000000, + 0x013, 0x000287bf, + 0x013, 0x000247b3, + 0x013, 0x000207a7, + 0x013, 0x0001c79b, + 0x013, 0x0001839f, + 0x013, 0x00014393, + 0x013, 0x00010399, + 0x013, 0x0000c38d, + 0x013, 0x00008199, + 0x013, 0x0000418d, + 0x013, 0x00000099, + 0x015, 0x0000f495, + 0x015, 0x0004f495, + 0x015, 0x0008f495, + 0x016, 0x000e1874, + 0x016, 0x000a1874, + 0x016, 0x00061874, + 0x016, 0x00021874, + 0x018, 0x00037564, + 0x000, 0x00070000, + 0x012, 0x000cf000, + 0x012, 0x000bc000, + 0x012, 0x00078000, + 0x012, 0x00000000, + 0x013, 0x000287bf, + 0x013, 0x000247b3, + 0x013, 0x000207a7, + 0x013, 0x0001c79b, + 0x013, 0x0001839f, + 0x013, 0x00014393, + 0x013, 0x00010399, + 0x013, 0x0000c38d, + 0x013, 0x00008199, + 0x013, 0x0000418d, + 0x013, 0x00000099, + 0x015, 0x0000f495, + 0x015, 0x0004f495, + 0x015, 0x0008f495, + 0x016, 0x000e1874, + 0x016, 0x000a1874, + 0x016, 0x00061874, + 0x016, 0x00021874, + 0x018, 0x00057595, + 0x000, 0x00070000, + 0x012, 0x000cf000, + 0x012, 0x000bc000, + 0x012, 0x00078000, + 0x012, 0x00000000, + 0x013, 0x000287bf, + 0x013, 0x000247b3, + 0x013, 0x000207a7, + 0x013, 0x0001c79b, + 0x013, 0x0001839f, + 0x013, 0x00014393, + 0x013, 0x00010399, + 0x013, 0x0000c38d, + 0x013, 0x00008199, + 0x013, 0x0000418d, + 0x013, 0x00000099, + 0x015, 0x0000f495, + 0x015, 0x0004f495, + 0x015, 0x0008f495, + 0x016, 0x000e1874, + 0x016, 0x000a1874, + 0x016, 0x00061874, + 0x016, 0x00021874, + 0x030, 0x0004470f, + 0x031, 0x00044ff0, + 0x032, 0x00000070, + 0x033, 0x000dd480, + 0x034, 0x000ffac0, + 0x035, 0x000b80c0, + 0x036, 0x00077000, + 0x037, 0x00064ff2, + 0x038, 0x000e7661, + 0x039, 0x00000e90, + 0x000, 0x00030000, + 0x018, 0x0000f401, + 0x0fe, 0x00000000, + 0x0fe, 0x00000000, + 0x01e, 0x00088009, + 0x01f, 0x00080003, + 0x0fe, 0x00000000, + 0x01e, 0x00088001, + 0x01f, 0x00080000, + 0x0fe, 0x00000000, + 0x018, 0x00087401, + 0x0fe, 0x00000000, + 0x0fe, 0x00000000, + 0x0fe, 0x00000000, + 0x02b, 0x00041289, + 0x0fe, 0x00000000, + 0x02d, 0x00066666, + 0x02e, 0x00064001, + 0x02d, 0x00091111, + 0x02e, 0x00014002, + 0x02d, 0x000bbbbb, + 0x02e, 0x000b4003, + 0x02d, 0x000e6666, + 0x02e, 0x00064004, + 0x02d, 0x00088888, + 0x02e, 0x00084005, + 0x02d, 0x0009dddd, + 0x02e, 0x000d4006, + 0x02d, 0x000b3333, + 0x02e, 0x00034007, + 0x02d, 0x00048888, + 0x02e, 0x00084408, + 0x02d, 0x000bbbbb, + 0x02e, 0x000b4409, + 0x02d, 0x000e6666, + 0x02e, 0x0006440a, + 0x02d, 0x00011111, + 0x02e, 0x0001480b, + 0x02d, 0x0003bbbb, + 0x02e, 0x000b480c, + 0x02d, 0x00066666, + 0x02e, 0x0006480d, + 0x02d, 0x000ccccc, + 0x02e, 0x000c480e, +}; + +u32 rtl8192de_mac_2tarray[MAC_2T_ARRAYLENGTH] = { + 0x420, 0x00000080, + 0x423, 0x00000000, + 0x430, 0x00000000, + 0x431, 0x00000000, + 0x432, 0x00000000, + 0x433, 0x00000001, + 0x434, 0x00000004, + 0x435, 0x00000005, + 0x436, 0x00000006, + 0x437, 0x00000007, + 0x438, 0x00000000, + 0x439, 0x00000000, + 0x43a, 0x00000000, + 0x43b, 0x00000001, + 0x43c, 0x00000004, + 0x43d, 0x00000005, + 0x43e, 0x00000006, + 0x43f, 0x00000007, + 0x440, 0x00000050, + 0x441, 0x00000001, + 0x442, 0x00000000, + 0x444, 0x00000015, + 0x445, 0x000000f0, + 0x446, 0x0000000f, + 0x447, 0x00000000, + 0x462, 0x00000008, + 0x463, 0x00000003, + 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, + 0x515, 0x00000010, + 0x516, 0x0000000a, + 0x517, 0x00000010, + 0x51a, 0x00000016, + 0x524, 0x0000000f, + 0x525, 0x0000004f, + 0x546, 0x00000040, + 0x547, 0x00000000, + 0x550, 0x00000010, + 0x551, 0x00000010, + 0x559, 0x00000002, + 0x55a, 0x00000002, + 0x55d, 0x000000ff, + 0x605, 0x00000030, + 0x608, 0x0000000e, + 0x609, 0x0000002a, + 0x652, 0x00000020, + 0x63c, 0x0000000a, + 0x63d, 0x0000000a, + 0x63e, 0x0000000e, + 0x63f, 0x0000000e, + 0x66e, 0x00000005, + 0x700, 0x00000021, + 0x701, 0x00000043, + 0x702, 0x00000065, + 0x703, 0x00000087, + 0x708, 0x00000021, + 0x709, 0x00000043, + 0x70a, 0x00000065, + 0x70b, 0x00000087, +}; + +u32 rtl8192de_agctab_array[AGCTAB_ARRAYLENGTH] = { + 0xc78, 0x7b000001, + 0xc78, 0x7b010001, + 0xc78, 0x7b020001, + 0xc78, 0x7b030001, + 0xc78, 0x7b040001, + 0xc78, 0x7b050001, + 0xc78, 0x7b060001, + 0xc78, 0x7a070001, + 0xc78, 0x79080001, + 0xc78, 0x78090001, + 0xc78, 0x770a0001, + 0xc78, 0x760b0001, + 0xc78, 0x750c0001, + 0xc78, 0x740d0001, + 0xc78, 0x730e0001, + 0xc78, 0x720f0001, + 0xc78, 0x71100001, + 0xc78, 0x70110001, + 0xc78, 0x6f120001, + 0xc78, 0x6e130001, + 0xc78, 0x6d140001, + 0xc78, 0x6c150001, + 0xc78, 0x6b160001, + 0xc78, 0x6a170001, + 0xc78, 0x69180001, + 0xc78, 0x68190001, + 0xc78, 0x671a0001, + 0xc78, 0x661b0001, + 0xc78, 0x651c0001, + 0xc78, 0x641d0001, + 0xc78, 0x631e0001, + 0xc78, 0x621f0001, + 0xc78, 0x61200001, + 0xc78, 0x60210001, + 0xc78, 0x49220001, + 0xc78, 0x48230001, + 0xc78, 0x47240001, + 0xc78, 0x46250001, + 0xc78, 0x45260001, + 0xc78, 0x44270001, + 0xc78, 0x43280001, + 0xc78, 0x42290001, + 0xc78, 0x412a0001, + 0xc78, 0x402b0001, + 0xc78, 0x262c0001, + 0xc78, 0x252d0001, + 0xc78, 0x242e0001, + 0xc78, 0x232f0001, + 0xc78, 0x22300001, + 0xc78, 0x21310001, + 0xc78, 0x20320001, + 0xc78, 0x06330001, + 0xc78, 0x05340001, + 0xc78, 0x04350001, + 0xc78, 0x03360001, + 0xc78, 0x02370001, + 0xc78, 0x01380001, + 0xc78, 0x00390001, + 0xc78, 0x003a0001, + 0xc78, 0x003b0001, + 0xc78, 0x003c0001, + 0xc78, 0x003d0001, + 0xc78, 0x003e0001, + 0xc78, 0x003f0001, + 0xc78, 0x7b400001, + 0xc78, 0x7b410001, + 0xc78, 0x7a420001, + 0xc78, 0x79430001, + 0xc78, 0x78440001, + 0xc78, 0x77450001, + 0xc78, 0x76460001, + 0xc78, 0x75470001, + 0xc78, 0x74480001, + 0xc78, 0x73490001, + 0xc78, 0x724a0001, + 0xc78, 0x714b0001, + 0xc78, 0x704c0001, + 0xc78, 0x6f4d0001, + 0xc78, 0x6e4e0001, + 0xc78, 0x6d4f0001, + 0xc78, 0x6c500001, + 0xc78, 0x6b510001, + 0xc78, 0x6a520001, + 0xc78, 0x69530001, + 0xc78, 0x68540001, + 0xc78, 0x67550001, + 0xc78, 0x66560001, + 0xc78, 0x65570001, + 0xc78, 0x64580001, + 0xc78, 0x63590001, + 0xc78, 0x625a0001, + 0xc78, 0x615b0001, + 0xc78, 0x605c0001, + 0xc78, 0x485d0001, + 0xc78, 0x475e0001, + 0xc78, 0x465f0001, + 0xc78, 0x45600001, + 0xc78, 0x44610001, + 0xc78, 0x43620001, + 0xc78, 0x42630001, + 0xc78, 0x41640001, + 0xc78, 0x40650001, + 0xc78, 0x27660001, + 0xc78, 0x26670001, + 0xc78, 0x25680001, + 0xc78, 0x24690001, + 0xc78, 0x236a0001, + 0xc78, 0x226b0001, + 0xc78, 0x216c0001, + 0xc78, 0x206d0001, + 0xc78, 0x206e0001, + 0xc78, 0x206f0001, + 0xc78, 0x20700001, + 0xc78, 0x20710001, + 0xc78, 0x20720001, + 0xc78, 0x20730001, + 0xc78, 0x20740001, + 0xc78, 0x20750001, + 0xc78, 0x20760001, + 0xc78, 0x20770001, + 0xc78, 0x20780001, + 0xc78, 0x20790001, + 0xc78, 0x207a0001, + 0xc78, 0x207b0001, + 0xc78, 0x207c0001, + 0xc78, 0x207d0001, + 0xc78, 0x207e0001, + 0xc78, 0x207f0001, + 0xc78, 0x38000002, + 0xc78, 0x38010002, + 0xc78, 0x38020002, + 0xc78, 0x38030002, + 0xc78, 0x38040002, + 0xc78, 0x38050002, + 0xc78, 0x38060002, + 0xc78, 0x38070002, + 0xc78, 0x38080002, + 0xc78, 0x3c090002, + 0xc78, 0x3e0a0002, + 0xc78, 0x400b0002, + 0xc78, 0x440c0002, + 0xc78, 0x480d0002, + 0xc78, 0x4c0e0002, + 0xc78, 0x500f0002, + 0xc78, 0x52100002, + 0xc78, 0x56110002, + 0xc78, 0x5a120002, + 0xc78, 0x5e130002, + 0xc78, 0x60140002, + 0xc78, 0x60150002, + 0xc78, 0x60160002, + 0xc78, 0x62170002, + 0xc78, 0x62180002, + 0xc78, 0x62190002, + 0xc78, 0x621a0002, + 0xc78, 0x621b0002, + 0xc78, 0x621c0002, + 0xc78, 0x621d0002, + 0xc78, 0x621e0002, + 0xc78, 0x621f0002, + 0xc78, 0x32000044, + 0xc78, 0x32010044, + 0xc78, 0x32020044, + 0xc78, 0x32030044, + 0xc78, 0x32040044, + 0xc78, 0x32050044, + 0xc78, 0x32060044, + 0xc78, 0x32070044, + 0xc78, 0x32080044, + 0xc78, 0x34090044, + 0xc78, 0x350a0044, + 0xc78, 0x360b0044, + 0xc78, 0x370c0044, + 0xc78, 0x380d0044, + 0xc78, 0x390e0044, + 0xc78, 0x3a0f0044, + 0xc78, 0x3e100044, + 0xc78, 0x42110044, + 0xc78, 0x44120044, + 0xc78, 0x46130044, + 0xc78, 0x4a140044, + 0xc78, 0x4e150044, + 0xc78, 0x50160044, + 0xc78, 0x55170044, + 0xc78, 0x5a180044, + 0xc78, 0x5e190044, + 0xc78, 0x641a0044, + 0xc78, 0x6e1b0044, + 0xc78, 0x6e1c0044, + 0xc78, 0x6e1d0044, + 0xc78, 0x6e1e0044, + 0xc78, 0x6e1f0044, + 0xc78, 0x6e1f0000, +}; + +u32 rtl8192de_agctab_5garray[AGCTAB_5G_ARRAYLENGTH] = { + 0xc78, 0x7b000001, + 0xc78, 0x7b010001, + 0xc78, 0x7a020001, + 0xc78, 0x79030001, + 0xc78, 0x78040001, + 0xc78, 0x77050001, + 0xc78, 0x76060001, + 0xc78, 0x75070001, + 0xc78, 0x74080001, + 0xc78, 0x73090001, + 0xc78, 0x720a0001, + 0xc78, 0x710b0001, + 0xc78, 0x700c0001, + 0xc78, 0x6f0d0001, + 0xc78, 0x6e0e0001, + 0xc78, 0x6d0f0001, + 0xc78, 0x6c100001, + 0xc78, 0x6b110001, + 0xc78, 0x6a120001, + 0xc78, 0x69130001, + 0xc78, 0x68140001, + 0xc78, 0x67150001, + 0xc78, 0x66160001, + 0xc78, 0x65170001, + 0xc78, 0x64180001, + 0xc78, 0x63190001, + 0xc78, 0x621a0001, + 0xc78, 0x611b0001, + 0xc78, 0x601c0001, + 0xc78, 0x481d0001, + 0xc78, 0x471e0001, + 0xc78, 0x461f0001, + 0xc78, 0x45200001, + 0xc78, 0x44210001, + 0xc78, 0x43220001, + 0xc78, 0x42230001, + 0xc78, 0x41240001, + 0xc78, 0x40250001, + 0xc78, 0x27260001, + 0xc78, 0x26270001, + 0xc78, 0x25280001, + 0xc78, 0x24290001, + 0xc78, 0x232a0001, + 0xc78, 0x222b0001, + 0xc78, 0x212c0001, + 0xc78, 0x202d0001, + 0xc78, 0x202e0001, + 0xc78, 0x202f0001, + 0xc78, 0x20300001, + 0xc78, 0x20310001, + 0xc78, 0x20320001, + 0xc78, 0x20330001, + 0xc78, 0x20340001, + 0xc78, 0x20350001, + 0xc78, 0x20360001, + 0xc78, 0x20370001, + 0xc78, 0x20380001, + 0xc78, 0x20390001, + 0xc78, 0x203a0001, + 0xc78, 0x203b0001, + 0xc78, 0x203c0001, + 0xc78, 0x203d0001, + 0xc78, 0x203e0001, + 0xc78, 0x203f0001, + 0xc78, 0x32000044, + 0xc78, 0x32010044, + 0xc78, 0x32020044, + 0xc78, 0x32030044, + 0xc78, 0x32040044, + 0xc78, 0x32050044, + 0xc78, 0x32060044, + 0xc78, 0x32070044, + 0xc78, 0x32080044, + 0xc78, 0x34090044, + 0xc78, 0x350a0044, + 0xc78, 0x360b0044, + 0xc78, 0x370c0044, + 0xc78, 0x380d0044, + 0xc78, 0x390e0044, + 0xc78, 0x3a0f0044, + 0xc78, 0x3e100044, + 0xc78, 0x42110044, + 0xc78, 0x44120044, + 0xc78, 0x46130044, + 0xc78, 0x4a140044, + 0xc78, 0x4e150044, + 0xc78, 0x50160044, + 0xc78, 0x55170044, + 0xc78, 0x5a180044, + 0xc78, 0x5e190044, + 0xc78, 0x641a0044, + 0xc78, 0x6e1b0044, + 0xc78, 0x6e1c0044, + 0xc78, 0x6e1d0044, + 0xc78, 0x6e1e0044, + 0xc78, 0x6e1f0044, + 0xc78, 0x6e1f0000, +}; + +u32 rtl8192de_agctab_2garray[AGCTAB_2G_ARRAYLENGTH] = { + 0xc78, 0x7b000001, + 0xc78, 0x7b010001, + 0xc78, 0x7b020001, + 0xc78, 0x7b030001, + 0xc78, 0x7b040001, + 0xc78, 0x7b050001, + 0xc78, 0x7b060001, + 0xc78, 0x7a070001, + 0xc78, 0x79080001, + 0xc78, 0x78090001, + 0xc78, 0x770a0001, + 0xc78, 0x760b0001, + 0xc78, 0x750c0001, + 0xc78, 0x740d0001, + 0xc78, 0x730e0001, + 0xc78, 0x720f0001, + 0xc78, 0x71100001, + 0xc78, 0x70110001, + 0xc78, 0x6f120001, + 0xc78, 0x6e130001, + 0xc78, 0x6d140001, + 0xc78, 0x6c150001, + 0xc78, 0x6b160001, + 0xc78, 0x6a170001, + 0xc78, 0x69180001, + 0xc78, 0x68190001, + 0xc78, 0x671a0001, + 0xc78, 0x661b0001, + 0xc78, 0x651c0001, + 0xc78, 0x641d0001, + 0xc78, 0x631e0001, + 0xc78, 0x621f0001, + 0xc78, 0x61200001, + 0xc78, 0x60210001, + 0xc78, 0x49220001, + 0xc78, 0x48230001, + 0xc78, 0x47240001, + 0xc78, 0x46250001, + 0xc78, 0x45260001, + 0xc78, 0x44270001, + 0xc78, 0x43280001, + 0xc78, 0x42290001, + 0xc78, 0x412a0001, + 0xc78, 0x402b0001, + 0xc78, 0x262c0001, + 0xc78, 0x252d0001, + 0xc78, 0x242e0001, + 0xc78, 0x232f0001, + 0xc78, 0x22300001, + 0xc78, 0x21310001, + 0xc78, 0x20320001, + 0xc78, 0x06330001, + 0xc78, 0x05340001, + 0xc78, 0x04350001, + 0xc78, 0x03360001, + 0xc78, 0x02370001, + 0xc78, 0x01380001, + 0xc78, 0x00390001, + 0xc78, 0x003a0001, + 0xc78, 0x003b0001, + 0xc78, 0x003c0001, + 0xc78, 0x003d0001, + 0xc78, 0x003e0001, + 0xc78, 0x003f0001, + 0xc78, 0x38000002, + 0xc78, 0x38010002, + 0xc78, 0x38020002, + 0xc78, 0x38030002, + 0xc78, 0x38040002, + 0xc78, 0x38050002, + 0xc78, 0x38060002, + 0xc78, 0x38070002, + 0xc78, 0x38080002, + 0xc78, 0x3c090002, + 0xc78, 0x3e0a0002, + 0xc78, 0x400b0002, + 0xc78, 0x440c0002, + 0xc78, 0x480d0002, + 0xc78, 0x4c0e0002, + 0xc78, 0x500f0002, + 0xc78, 0x52100002, + 0xc78, 0x56110002, + 0xc78, 0x5a120002, + 0xc78, 0x5e130002, + 0xc78, 0x60140002, + 0xc78, 0x60150002, + 0xc78, 0x60160002, + 0xc78, 0x62170002, + 0xc78, 0x62180002, + 0xc78, 0x62190002, + 0xc78, 0x621a0002, + 0xc78, 0x621b0002, + 0xc78, 0x621c0002, + 0xc78, 0x621d0002, + 0xc78, 0x621e0002, + 0xc78, 0x621f0002, + 0xc78, 0x6e1f0000, +}; diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/table.h b/drivers/net/wireless/rtlwifi/rtl8192de/table.h new file mode 100644 index 00000000..8b724a86 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192de/table.h @@ -0,0 +1,57 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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> + * + * Created on 2010/ 5/18, 1:41 + *****************************************************************************/ + +#ifndef __RTL92DE_TABLE__H_ +#define __RTL92DE_TABLE__H_ + +/*Created on 2011/ 1/14, 1:35*/ + +#define PHY_REG_2T_ARRAYLENGTH 380 +extern u32 rtl8192de_phy_reg_2tarray[PHY_REG_2T_ARRAYLENGTH]; +#define PHY_REG_ARRAY_PG_LENGTH 624 +extern u32 rtl8192de_phy_reg_array_pg[PHY_REG_ARRAY_PG_LENGTH]; +#define RADIOA_2T_ARRAYLENGTH 378 +extern u32 rtl8192de_radioa_2tarray[RADIOA_2T_ARRAYLENGTH]; +#define RADIOB_2T_ARRAYLENGTH 384 +extern u32 rtl8192de_radiob_2tarray[RADIOB_2T_ARRAYLENGTH]; +#define RADIOA_2T_INT_PA_ARRAYLENGTH 378 +extern u32 rtl8192de_radioa_2t_int_paarray[RADIOA_2T_INT_PA_ARRAYLENGTH]; +#define RADIOB_2T_INT_PA_ARRAYLENGTH 384 +extern u32 rtl8192de_radiob_2t_int_paarray[RADIOB_2T_INT_PA_ARRAYLENGTH]; +#define MAC_2T_ARRAYLENGTH 160 +extern u32 rtl8192de_mac_2tarray[MAC_2T_ARRAYLENGTH]; +#define AGCTAB_ARRAYLENGTH 386 +extern u32 rtl8192de_agctab_array[AGCTAB_ARRAYLENGTH]; +#define AGCTAB_5G_ARRAYLENGTH 194 +extern u32 rtl8192de_agctab_5garray[AGCTAB_5G_ARRAYLENGTH]; +#define AGCTAB_2G_ARRAYLENGTH 194 +extern u32 rtl8192de_agctab_2garray[AGCTAB_2G_ARRAYLENGTH]; + +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/trx.c b/drivers/net/wireless/rtlwifi/rtl8192de/trx.c new file mode 100644 index 00000000..a7f6126e --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192de/trx.c @@ -0,0 +1,866 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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> + * + *****************************************************************************/ + +#include "../wifi.h" +#include "../pci.h" +#include "../base.h" +#include "reg.h" +#include "def.h" +#include "phy.h" +#include "trx.h" +#include "led.h" + +static u8 _rtl92de_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)) + return QSLT_MGNT; + + return skb->priority; +} + +static u8 _rtl92d_query_rxpwrpercentage(char antpower) +{ + if ((antpower <= -100) || (antpower >= 20)) + return 0; + else if (antpower >= 0) + return 100; + else + return 100 + antpower; +} + +static u8 _rtl92d_evm_db_to_percentage(char value) +{ + char 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; +} + +static long _rtl92de_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; +} + +static long _rtl92de_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; +} + +static void _rtl92de_query_rxphystatus(struct ieee80211_hw *hw, + struct rtl_stats *pstats, + struct rx_desc_92d *pdesc, + struct rx_fwinfo_92d *p_drvinfo, + bool packet_match_bssid, + bool packet_toself, + bool packet_beacon) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_ps_ctl *ppsc = rtl_psc(rtlpriv); + struct phy_sts_cck_8192d *cck_buf; + s8 rx_pwr_all, rx_pwr[4]; + u8 rf_rx_num = 0, evm, pwdb_all; + u8 i, max_spatial_stream; + u32 rssi, total_rssi = 0; + bool is_cck_rate; + + is_cck_rate = RX_HAL_IS_CCK_RATE(pdesc); + pstats->packet_matchbssid = packet_match_bssid; + pstats->packet_toself = packet_toself; + pstats->packet_beacon = packet_beacon; + pstats->is_cck = is_cck_rate; + pstats->rx_mimo_signalquality[0] = -1; + pstats->rx_mimo_signalquality[1] = -1; + + if (is_cck_rate) { + u8 report, cck_highpwr; + cck_buf = (struct phy_sts_cck_8192d *)p_drvinfo; + if (ppsc->rfpwr_state == ERFON) + cck_highpwr = (u8) rtl_get_bbreg(hw, + RFPGA0_XA_HSSIPARAMETER2, + BIT(9)); + else + cck_highpwr = false; + if (!cck_highpwr) { + u8 cck_agc_rpt = cck_buf->cck_agc_rpt; + report = cck_buf->cck_agc_rpt & 0xc0; + report = report >> 6; + switch (report) { + case 0x3: + rx_pwr_all = -46 - (cck_agc_rpt & 0x3e); + break; + case 0x2: + rx_pwr_all = -26 - (cck_agc_rpt & 0x3e); + break; + case 0x1: + rx_pwr_all = -12 - (cck_agc_rpt & 0x3e); + break; + case 0x0: + rx_pwr_all = 16 - (cck_agc_rpt & 0x3e); + break; + } + } else { + u8 cck_agc_rpt = cck_buf->cck_agc_rpt; + report = p_drvinfo->cfosho[0] & 0x60; + report = report >> 5; + switch (report) { + case 0x3: + rx_pwr_all = -46 - ((cck_agc_rpt & 0x1f) << 1); + break; + case 0x2: + rx_pwr_all = -26 - ((cck_agc_rpt & 0x1f) << 1); + break; + case 0x1: + rx_pwr_all = -12 - ((cck_agc_rpt & 0x1f) << 1); + break; + case 0x0: + rx_pwr_all = 16 - ((cck_agc_rpt & 0x1f) << 1); + break; + } + } + pwdb_all = _rtl92d_query_rxpwrpercentage(rx_pwr_all); + /* CCK gain is smaller than OFDM/MCS gain, */ + /* so we add gain diff by experiences, the val is 6 */ + pwdb_all += 6; + if (pwdb_all > 100) + pwdb_all = 100; + /* modify the offset to make the same gain index with OFDM. */ + if (pwdb_all > 34 && pwdb_all <= 42) + pwdb_all -= 2; + else if (pwdb_all > 26 && pwdb_all <= 34) + pwdb_all -= 6; + else if (pwdb_all > 14 && pwdb_all <= 26) + pwdb_all -= 8; + else if (pwdb_all > 4 && pwdb_all <= 14) + pwdb_all -= 4; + pstats->rx_pwdb_all = pwdb_all; + pstats->recvsignalpower = rx_pwr_all; + if (packet_match_bssid) { + u8 sq; + if (pstats->rx_pwdb_all > 40) { + sq = 100; + } else { + sq = cck_buf->sq_rpt; + if (sq > 64) + sq = 0; + else if (sq < 20) + sq = 100; + else + sq = ((64 - sq) * 100) / 44; + } + pstats->signalquality = sq; + pstats->rx_mimo_signalquality[0] = sq; + pstats->rx_mimo_signalquality[1] = -1; + } + } else { + rtlpriv->dm.rfpath_rxenable[0] = true; + rtlpriv->dm.rfpath_rxenable[1] = true; + for (i = RF90_PATH_A; i < RF6052_MAX_PATH; i++) { + if (rtlpriv->dm.rfpath_rxenable[i]) + rf_rx_num++; + rx_pwr[i] = ((p_drvinfo->gain_trsw[i] & 0x3f) * 2) + - 110; + rssi = _rtl92d_query_rxpwrpercentage(rx_pwr[i]); + total_rssi += rssi; + rtlpriv->stats.rx_snr_db[i] = + (long)(p_drvinfo->rxsnr[i] / 2); + if (packet_match_bssid) + pstats->rx_mimo_signalstrength[i] = (u8) rssi; + } + rx_pwr_all = ((p_drvinfo->pwdb_all >> 1) & 0x7f) - 106; + pwdb_all = _rtl92d_query_rxpwrpercentage(rx_pwr_all); + pstats->rx_pwdb_all = pwdb_all; + pstats->rxpower = rx_pwr_all; + pstats->recvsignalpower = rx_pwr_all; + if (pdesc->rxht && pdesc->rxmcs >= DESC92_RATEMCS8 && + pdesc->rxmcs <= DESC92_RATEMCS15) + max_spatial_stream = 2; + else + max_spatial_stream = 1; + for (i = 0; i < max_spatial_stream; i++) { + evm = _rtl92d_evm_db_to_percentage(p_drvinfo->rxevm[i]); + if (packet_match_bssid) { + if (i == 0) + pstats->signalquality = + (u8)(evm & 0xff); + pstats->rx_mimo_signalquality[i] = + (u8)(evm & 0xff); + } + } + } + if (is_cck_rate) + pstats->signalstrength = (u8)(_rtl92de_signal_scale_mapping(hw, + pwdb_all)); + else if (rf_rx_num != 0) + pstats->signalstrength = (u8)(_rtl92de_signal_scale_mapping(hw, + total_rssi /= rf_rx_num)); +} + +static void rtl92d_loop_over_paths(struct ieee80211_hw *hw, + struct rtl_stats *pstats) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + u8 rfpath; + + 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] = + pstats->rx_mimo_signalstrength[rfpath]; + + } + if (pstats->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)) + + (pstats->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)) + + (pstats->rx_mimo_signalstrength[rfpath])) / + (RX_SMOOTH_FACTOR); + } + } +} + +static void _rtl92de_process_ui_rssi(struct ieee80211_hw *hw, + struct rtl_stats *pstats) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 last_rssi, tmpval; + + if (pstats->packet_toself || pstats->packet_beacon) { + 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 += pstats->signalstrength; + rtlpriv->stats.ui_rssi.elements + [rtlpriv->stats.ui_rssi.index++] = + pstats->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 = _rtl92de_translate_todbm(hw, + (u8) tmpval); + pstats->rssi = rtlpriv->stats.signal_strength; + } + if (!pstats->is_cck && pstats->packet_toself) + rtl92d_loop_over_paths(hw, pstats); +} + +static void _rtl92de_update_rxsignalstatistics(struct ieee80211_hw *hw, + struct rtl_stats *pstats) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + int weighting = 0; + + if (rtlpriv->stats.recv_signal_power == 0) + rtlpriv->stats.recv_signal_power = pstats->recvsignalpower; + if (pstats->recvsignalpower > rtlpriv->stats.recv_signal_power) + weighting = 5; + else if (pstats->recvsignalpower < rtlpriv->stats.recv_signal_power) + weighting = (-5); + rtlpriv->stats.recv_signal_power = (rtlpriv->stats.recv_signal_power * + 5 + pstats->recvsignalpower + weighting) / 6; +} + +static void _rtl92de_process_pwdb(struct ieee80211_hw *hw, + struct rtl_stats *pstats) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + long undecorated_smoothed_pwdb; + + if (mac->opmode == NL80211_IFTYPE_ADHOC || + mac->opmode == NL80211_IFTYPE_AP) + return; + else + undecorated_smoothed_pwdb = + rtlpriv->dm.undecorated_smoothed_pwdb; + + if (pstats->packet_toself || pstats->packet_beacon) { + if (undecorated_smoothed_pwdb < 0) + undecorated_smoothed_pwdb = pstats->rx_pwdb_all; + if (pstats->rx_pwdb_all > (u32) undecorated_smoothed_pwdb) { + undecorated_smoothed_pwdb = + (((undecorated_smoothed_pwdb) * + (RX_SMOOTH_FACTOR - 1)) + + (pstats->rx_pwdb_all)) / (RX_SMOOTH_FACTOR); + undecorated_smoothed_pwdb = + undecorated_smoothed_pwdb + 1; + } else { + undecorated_smoothed_pwdb = + (((undecorated_smoothed_pwdb) * + (RX_SMOOTH_FACTOR - 1)) + + (pstats->rx_pwdb_all)) / (RX_SMOOTH_FACTOR); + } + rtlpriv->dm.undecorated_smoothed_pwdb = + undecorated_smoothed_pwdb; + _rtl92de_update_rxsignalstatistics(hw, pstats); + } +} + +static void rtl92d_loop_over_streams(struct ieee80211_hw *hw, + struct rtl_stats *pstats) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + int stream; + + for (stream = 0; stream < 2; stream++) { + if (pstats->rx_mimo_signalquality[stream] != -1) { + if (rtlpriv->stats.rx_evm_percentage[stream] == 0) { + rtlpriv->stats.rx_evm_percentage[stream] = + pstats->rx_mimo_signalquality[stream]; + } + rtlpriv->stats.rx_evm_percentage[stream] = + ((rtlpriv->stats.rx_evm_percentage[stream] + * (RX_SMOOTH_FACTOR - 1)) + + (pstats->rx_mimo_signalquality[stream] * 1)) / + (RX_SMOOTH_FACTOR); + } + } +} + +static void _rtl92de_process_ui_link_quality(struct ieee80211_hw *hw, + struct rtl_stats *pstats) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 last_evm, tmpval; + + if (pstats->signalquality == 0) + return; + if (pstats->packet_toself || pstats->packet_beacon) { + 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 += + pstats->signalquality; + rtlpriv->stats.ui_link_quality.elements[ + rtlpriv->stats.ui_link_quality.index++] = + pstats->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; + rtl92d_loop_over_streams(hw, pstats); + } +} + +static void _rtl92de_process_phyinfo(struct ieee80211_hw *hw, + u8 *buffer, + struct rtl_stats *pcurrent_stats) +{ + + if (!pcurrent_stats->packet_matchbssid && + !pcurrent_stats->packet_beacon) + return; + + _rtl92de_process_ui_rssi(hw, pcurrent_stats); + _rtl92de_process_pwdb(hw, pcurrent_stats); + _rtl92de_process_ui_link_quality(hw, pcurrent_stats); +} + +static void _rtl92de_translate_rx_signal_stuff(struct ieee80211_hw *hw, + struct sk_buff *skb, + struct rtl_stats *pstats, + struct rx_desc_92d *pdesc, + struct rx_fwinfo_92d *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; + u16 type, cfc; + __le16 fc; + bool packet_matchbssid, packet_toself, packet_beacon; + + tmp_buf = skb->data + pstats->rx_drvinfo_size + pstats->rx_bufshift; + hdr = (struct ieee80211_hdr *)tmp_buf; + fc = hdr->frame_control; + cfc = le16_to_cpu(fc); + type = WLAN_FC_GET_TYPE(fc); + praddr = hdr->addr1; + packet_matchbssid = ((IEEE80211_FTYPE_CTL != type) && + (!compare_ether_addr(mac->bssid, (cfc & IEEE80211_FCTL_TODS) ? + hdr->addr1 : (cfc & IEEE80211_FCTL_FROMDS) ? + hdr->addr2 : hdr->addr3)) && (!pstats->hwerror) && + (!pstats->crc) && (!pstats->icv)); + packet_toself = packet_matchbssid && + (!compare_ether_addr(praddr, rtlefuse->dev_addr)); + if (ieee80211_is_beacon(fc)) + packet_beacon = true; + _rtl92de_query_rxphystatus(hw, pstats, pdesc, p_drvinfo, + packet_matchbssid, packet_toself, + packet_beacon); + _rtl92de_process_phyinfo(hw, tmp_buf, pstats); +} + +bool rtl92de_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *stats, + struct ieee80211_rx_status *rx_status, + u8 *p_desc, struct sk_buff *skb) +{ + struct rx_fwinfo_92d *p_drvinfo; + struct rx_desc_92d *pdesc = (struct rx_desc_92d *)p_desc; + u32 phystatus = GET_RX_DESC_PHYST(pdesc); + + stats->length = (u16) GET_RX_DESC_PKT_LEN(pdesc); + stats->rx_drvinfo_size = (u8) GET_RX_DESC_DRV_INFO_SIZE(pdesc) * + RX_DRV_INFO_SIZE_UNIT; + stats->rx_bufshift = (u8) (GET_RX_DESC_SHIFT(pdesc) & 0x03); + stats->icv = (u16) GET_RX_DESC_ICV(pdesc); + stats->crc = (u16) GET_RX_DESC_CRC32(pdesc); + stats->hwerror = (stats->crc | stats->icv); + stats->decrypted = !GET_RX_DESC_SWDEC(pdesc); + stats->rate = (u8) GET_RX_DESC_RXMCS(pdesc); + stats->shortpreamble = (u16) GET_RX_DESC_SPLCP(pdesc); + stats->isampdu = (bool) (GET_RX_DESC_PAGGR(pdesc) == 1); + stats->isfirst_ampdu = (bool) ((GET_RX_DESC_PAGGR(pdesc) == 1) + && (GET_RX_DESC_FAGGR(pdesc) == 1)); + stats->timestamp_low = GET_RX_DESC_TSFL(pdesc); + stats->rx_is40Mhzpacket = (bool) GET_RX_DESC_BW(pdesc); + rx_status->freq = hw->conf.channel->center_freq; + rx_status->band = hw->conf.channel->band; + if (GET_RX_DESC_CRC32(pdesc)) + rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; + if (!GET_RX_DESC_SWDEC(pdesc)) + rx_status->flag |= RX_FLAG_DECRYPTED; + if (GET_RX_DESC_BW(pdesc)) + rx_status->flag |= RX_FLAG_40MHZ; + if (GET_RX_DESC_RXHT(pdesc)) + rx_status->flag |= RX_FLAG_HT; + rx_status->flag |= RX_FLAG_MACTIME_MPDU; + if (stats->decrypted) + rx_status->flag |= RX_FLAG_DECRYPTED; + rx_status->rate_idx = rtlwifi_rate_mapping(hw, + (bool)GET_RX_DESC_RXHT(pdesc), + (u8)GET_RX_DESC_RXMCS(pdesc), + (bool)GET_RX_DESC_PAGGR(pdesc)); + rx_status->mactime = GET_RX_DESC_TSFL(pdesc); + if (phystatus) { + p_drvinfo = (struct rx_fwinfo_92d *)(skb->data + + stats->rx_bufshift); + _rtl92de_translate_rx_signal_stuff(hw, + skb, stats, pdesc, + p_drvinfo); + } + /*rx_status->qual = stats->signal; */ + rx_status->signal = stats->rssi + 10; + /*rx_status->noise = -stats->noise; */ + return true; +} + +static void _rtl92de_insert_emcontent(struct rtl_tcb_desc *ptcb_desc, + u8 *virtualaddress) +{ + memset(virtualaddress, 0, 8); + + SET_EARLYMODE_PKTNUM(virtualaddress, ptcb_desc->empkt_num); + SET_EARLYMODE_LEN0(virtualaddress, ptcb_desc->empkt_len[0]); + SET_EARLYMODE_LEN1(virtualaddress, ptcb_desc->empkt_len[1]); + SET_EARLYMODE_LEN2_1(virtualaddress, ptcb_desc->empkt_len[2] & 0xF); + SET_EARLYMODE_LEN2_2(virtualaddress, ptcb_desc->empkt_len[2] >> 4); + SET_EARLYMODE_LEN3(virtualaddress, ptcb_desc->empkt_len[3]); + SET_EARLYMODE_LEN4(virtualaddress, ptcb_desc->empkt_len[4]); +} + +void rtl92de_tx_fill_desc(struct ieee80211_hw *hw, + struct ieee80211_hdr *hdr, u8 *pdesc_tx, + struct ieee80211_tx_info *info, 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); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + struct ieee80211_sta *sta = info->control.sta; + u8 *pdesc = (u8 *) pdesc_tx; + u16 seq_number; + __le16 fc = hdr->frame_control; + unsigned int buf_len = 0; + unsigned int skb_len = skb->len; + u8 fw_qsel = _rtl92de_map_hwqueue_to_fwqueue(skb, hw_queue); + bool firstseg = ((hdr->seq_ctrl & + cpu_to_le16(IEEE80211_SCTL_FRAG)) == 0); + bool lastseg = ((hdr->frame_control & + cpu_to_le16(IEEE80211_FCTL_MOREFRAGS)) == 0); + dma_addr_t mapping; + u8 bw_40 = 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; + rtl_get_tcb_desc(hw, info, sta, skb, ptcb_desc); + /* reserve 8 byte for AMPDU early mode */ + if (rtlhal->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); + CLEAR_PCI_TX_DESC_CONTENT(pdesc, sizeof(struct tx_desc_92d)); + if (ieee80211_is_nullfunc(fc) || ieee80211_is_ctl(fc)) { + firstseg = true; + lastseg = true; + } + if (firstseg) { + if (rtlhal->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(rtlpriv, COMP_SEND, DBG_LOUD, + "Insert 8 byte.pTcb->EMPktNum:%d\n", + ptcb_desc->empkt_num); + _rtl92de_insert_emcontent(ptcb_desc, + (u8 *)(skb->data)); + } + } else { + SET_TX_DESC_OFFSET(pdesc, USB_HWDESC_HEADER_LEN); + } + /* 5G have no CCK rate */ + if (rtlhal->current_bandtype == BAND_ON_5G) + if (ptcb_desc->hw_rate < DESC92_RATE6M) + ptcb_desc->hw_rate = DESC92_RATE6M; + SET_TX_DESC_TX_RATE(pdesc, ptcb_desc->hw_rate); + if (ptcb_desc->use_shortgi || ptcb_desc->use_shortpreamble) + SET_TX_DESC_DATA_SHORTGI(pdesc, 1); + + if (rtlhal->macphymode == DUALMAC_DUALPHY && + ptcb_desc->hw_rate == DESC92_RATEMCS7) + SET_TX_DESC_DATA_SHORTGI(pdesc, 1); + + 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->rts_enable && + !ptcb_desc->cts_enable) ? 1 : 0)); + SET_TX_DESC_HW_RTS_ENABLE(pdesc, ((ptcb_desc->rts_enable + || ptcb_desc->cts_enable) ? 1 : 0)); + SET_TX_DESC_CTS2SELF(pdesc, ((ptcb_desc->cts_enable) ? 1 : 0)); + SET_TX_DESC_RTS_STBC(pdesc, ((ptcb_desc->rts_stbc) ? 1 : 0)); + /* 5G have no CCK rate */ + if (rtlhal->current_bandtype == BAND_ON_5G) + if (ptcb_desc->rts_rate < DESC92_RATE6M) + ptcb_desc->rts_rate = DESC92_RATE6M; + SET_TX_DESC_RTS_RATE(pdesc, ptcb_desc->rts_rate); + SET_TX_DESC_RTS_BW(pdesc, 0); + SET_TX_DESC_RTS_SC(pdesc, ptcb_desc->rts_sc); + SET_TX_DESC_RTS_SHORT(pdesc, ((ptcb_desc->rts_rate <= + DESC92_RATE54M) ? + (ptcb_desc->rts_use_shortpreamble ? 1 : 0) : + (ptcb_desc->rts_use_shortgi ? 1 : 0))); + if (bw_40) { + if (ptcb_desc->packet_bw) { + 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); + SET_TX_DESC_PKT_SIZE(pdesc, (u16) skb_len); + 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 *keyconf; + + keyconf = info->control.hw_key; + switch (keyconf->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_PKT_ID(pdesc, 0); + 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 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(rtlpriv, 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, (firstseg ? 1 : 0)); + SET_TX_DESC_LAST_SEG(pdesc, (lastseg ? 1 : 0)); + SET_TX_DESC_TX_BUFFER_SIZE(pdesc, (u16) buf_len); + SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, mapping); + if (rtlpriv->dm.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); + } + if (ieee80211_is_data_qos(fc)) + SET_TX_DESC_QOS(pdesc, 1); + + if ((!ieee80211_is_data_qos(fc)) && ppsc->fwctrl_lps) { + SET_TX_DESC_HWSEQ_EN(pdesc, 1); + SET_TX_DESC_PKT_ID(pdesc, 8); + } + SET_TX_DESC_MORE_FRAG(pdesc, (lastseg ? 0 : 1)); + RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE, "\n"); +} + +void rtl92de_tx_fill_cmddesc(struct ieee80211_hw *hw, + u8 *pdesc, bool firstseg, + bool lastseg, struct sk_buff *skb) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_ps_ctl *ppsc = rtl_psc(rtlpriv); + struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + u8 fw_queue = QSLT_BEACON; + dma_addr_t mapping = pci_map_single(rtlpci->pdev, + skb->data, skb->len, PCI_DMA_TODEVICE); + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data); + __le16 fc = hdr->frame_control; + + CLEAR_PCI_TX_DESC_CONTENT(pdesc, TX_DESC_SIZE); + if (firstseg) + SET_TX_DESC_OFFSET(pdesc, USB_HWDESC_HEADER_LEN); + /* 5G have no CCK rate + * Caution: The macros below are multi-line expansions. + * The braces are needed no matter what checkpatch says + */ + if (rtlhal->current_bandtype == BAND_ON_5G) { + SET_TX_DESC_TX_RATE(pdesc, DESC92_RATE6M); + } else { + SET_TX_DESC_TX_RATE(pdesc, DESC92_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_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, 0x20); + SET_TX_DESC_USE_RATE(pdesc, 1); + + if (!ieee80211_is_data_qos(fc) && ppsc->fwctrl_lps) { + SET_TX_DESC_HWSEQ_EN(pdesc, 1); + SET_TX_DESC_PKT_ID(pdesc, 8); + } + + RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD, + "H2C Tx Cmd Content", pdesc, TX_DESC_SIZE); + wmb(); + SET_TX_DESC_OWN(pdesc, 1); +} + +void rtl92de_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val) +{ + if (istx) { + switch (desc_name) { + case HW_DESC_OWN: + wmb(); + SET_TX_DESC_OWN(pdesc, 1); + break; + case HW_DESC_TX_NEXTDESC_ADDR: + SET_TX_DESC_NEXT_DESC_ADDRESS(pdesc, *(u32 *) val); + break; + default: + RT_ASSERT(false, "ERR txdesc :%d not process\n", + desc_name); + break; + } + } else { + switch (desc_name) { + case HW_DESC_RXOWN: + wmb(); + SET_RX_DESC_OWN(pdesc, 1); + break; + case HW_DESC_RXBUFF_ADDR: + SET_RX_DESC_BUFF_ADDR(pdesc, *(u32 *) val); + break; + case HW_DESC_RXPKT_LEN: + SET_RX_DESC_PKT_LEN(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 rtl92de_get_desc(u8 *p_desc, bool istx, u8 desc_name) +{ + u32 ret = 0; + + if (istx) { + switch (desc_name) { + case HW_DESC_OWN: + ret = GET_TX_DESC_OWN(p_desc); + break; + case HW_DESC_TXBUFF_ADDR: + ret = GET_TX_DESC_TX_BUFFER_ADDRESS(p_desc); + break; + default: + RT_ASSERT(false, "ERR txdesc :%d not process\n", + desc_name); + break; + } + } else { + struct rx_desc_92c *pdesc = (struct rx_desc_92c *)p_desc; + 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; + default: + RT_ASSERT(false, "ERR rxdesc :%d not process\n", + desc_name); + break; + } + } + return ret; +} + +void rtl92de_tx_polling(struct ieee80211_hw *hw, u8 hw_queue) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + if (hw_queue == BEACON_QUEUE) + rtl_write_word(rtlpriv, REG_PCIE_CTRL_REG, BIT(4)); + else + rtl_write_word(rtlpriv, REG_PCIE_CTRL_REG, + BIT(0) << (hw_queue)); +} diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/trx.h b/drivers/net/wireless/rtlwifi/rtl8192de/trx.h new file mode 100644 index 00000000..0dc736c2 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192de/trx.h @@ -0,0 +1,750 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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 __RTL92DE_TRX_H__ +#define __RTL92DE_TRX_H__ + +#define TX_DESC_SIZE 64 +#define TX_DESC_AGGR_SUBFRAME_SIZE 32 + +#define RX_DESC_SIZE 32 +#define RX_DRV_INFO_SIZE_UNIT 8 + +#define TX_DESC_NEXT_DESC_OFFSET 40 +#define USB_HWDESC_HEADER_LEN 32 +#define CRCLENGTH 4 + +/* Define a macro that takes a le32 word, converts it to host ordering, + * right shifts by a specified count, creates a mask of the specified + * bit count, and extracts that number of bits. + */ + +#define SHIFT_AND_MASK_LE(__pdesc, __shift, __mask) \ + ((le32_to_cpu(*(((__le32 *)(__pdesc)))) >> (__shift)) & \ + BIT_LEN_MASK_32(__mask)) + +/* Define a macro that clears a bit field in an le32 word and + * sets the specified value into that bit field. The resulting + * value remains in le32 ordering; however, it is properly converted + * to host ordering for the clear and set operations before conversion + * back to le32. + */ + +#define SET_BITS_OFFSET_LE(__pdesc, __shift, __len, __val) \ + (*(__le32 *)(__pdesc) = \ + (cpu_to_le32((le32_to_cpu(*((__le32 *)(__pdesc))) & \ + (~(BIT_OFFSET_LEN_MASK_32((__shift), __len)))) | \ + (((u32)(__val) & BIT_LEN_MASK_32(__len)) << (__shift))))); + +/* macros to read/write various fields in RX or TX descriptors */ + +#define SET_TX_DESC_PKT_SIZE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 0, 16, __val) +#define SET_TX_DESC_OFFSET(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 16, 8, __val) +#define SET_TX_DESC_BMC(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 24, 1, __val) +#define SET_TX_DESC_HTC(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 25, 1, __val) +#define SET_TX_DESC_LAST_SEG(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 26, 1, __val) +#define SET_TX_DESC_FIRST_SEG(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 27, 1, __val) +#define SET_TX_DESC_LINIP(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 28, 1, __val) +#define SET_TX_DESC_NO_ACM(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 29, 1, __val) +#define SET_TX_DESC_GF(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 30, 1, __val) +#define SET_TX_DESC_OWN(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 31, 1, __val) + +#define GET_TX_DESC_PKT_SIZE(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 0, 16) +#define GET_TX_DESC_OFFSET(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 16, 8) +#define GET_TX_DESC_BMC(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 24, 1) +#define GET_TX_DESC_HTC(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 25, 1) +#define GET_TX_DESC_LAST_SEG(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 26, 1) +#define GET_TX_DESC_FIRST_SEG(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 27, 1) +#define GET_TX_DESC_LINIP(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 28, 1) +#define GET_TX_DESC_NO_ACM(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 29, 1) +#define GET_TX_DESC_GF(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 30, 1) +#define GET_TX_DESC_OWN(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 31, 1) + +#define SET_TX_DESC_MACID(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+4, 0, 5, __val) +#define SET_TX_DESC_AGG_ENABLE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+4, 5, 1, __val) +#define SET_TX_DESC_BK(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+4, 6, 1, __val) +#define SET_TX_DESC_RDG_ENABLE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+4, 7, 1, __val) +#define SET_TX_DESC_QUEUE_SEL(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+4, 8, 5, __val) +#define SET_TX_DESC_RDG_NAV_EXT(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+4, 13, 1, __val) +#define SET_TX_DESC_LSIG_TXOP_EN(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+4, 14, 1, __val) +#define SET_TX_DESC_PIFS(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+4, 15, 1, __val) +#define SET_TX_DESC_RATE_ID(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+4, 16, 4, __val) +#define SET_TX_DESC_NAV_USE_HDR(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+4, 20, 1, __val) +#define SET_TX_DESC_EN_DESC_ID(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+4, 21, 1, __val) +#define SET_TX_DESC_SEC_TYPE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+4, 22, 2, __val) +#define SET_TX_DESC_PKT_OFFSET(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+4, 26, 8, __val) + +#define GET_TX_DESC_MACID(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+4, 0, 5) +#define GET_TX_DESC_AGG_ENABLE(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+4, 5, 1) +#define GET_TX_DESC_AGG_BREAK(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+4, 6, 1) +#define GET_TX_DESC_RDG_ENABLE(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+4, 7, 1) +#define GET_TX_DESC_QUEUE_SEL(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+4, 8, 5) +#define GET_TX_DESC_RDG_NAV_EXT(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+4, 13, 1) +#define GET_TX_DESC_LSIG_TXOP_EN(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+4, 14, 1) +#define GET_TX_DESC_PIFS(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+4, 15, 1) +#define GET_TX_DESC_RATE_ID(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+4, 16, 4) +#define GET_TX_DESC_NAV_USE_HDR(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+4, 20, 1) +#define GET_TX_DESC_EN_DESC_ID(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+4, 21, 1) +#define GET_TX_DESC_SEC_TYPE(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+4, 22, 2) +#define GET_TX_DESC_PKT_OFFSET(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+4, 24, 8) + +#define SET_TX_DESC_RTS_RC(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+8, 0, 6, __val) +#define SET_TX_DESC_DATA_RC(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+8, 6, 6, __val) +#define SET_TX_DESC_BAR_RTY_TH(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+8, 14, 2, __val) +#define SET_TX_DESC_MORE_FRAG(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+8, 17, 1, __val) +#define SET_TX_DESC_RAW(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+8, 18, 1, __val) +#define SET_TX_DESC_CCX(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+8, 19, 1, __val) +#define SET_TX_DESC_AMPDU_DENSITY(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+8, 20, 3, __val) +#define SET_TX_DESC_ANTSEL_A(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+8, 24, 1, __val) +#define SET_TX_DESC_ANTSEL_B(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+8, 25, 1, __val) +#define SET_TX_DESC_TX_ANT_CCK(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+8, 26, 2, __val) +#define SET_TX_DESC_TX_ANTL(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+8, 28, 2, __val) +#define SET_TX_DESC_TX_ANT_HT(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+8, 30, 2, __val) + +#define GET_TX_DESC_RTS_RC(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+8, 0, 6) +#define GET_TX_DESC_DATA_RC(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+8, 6, 6) +#define GET_TX_DESC_BAR_RTY_TH(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+8, 14, 2) +#define GET_TX_DESC_MORE_FRAG(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+8, 17, 1) +#define GET_TX_DESC_RAW(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+8, 18, 1) +#define GET_TX_DESC_CCX(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+8, 19, 1) +#define GET_TX_DESC_AMPDU_DENSITY(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+8, 20, 3) +#define GET_TX_DESC_ANTSEL_A(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+8, 24, 1) +#define GET_TX_DESC_ANTSEL_B(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+8, 25, 1) +#define GET_TX_DESC_TX_ANT_CCK(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+8, 26, 2) +#define GET_TX_DESC_TX_ANTL(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+8, 28, 2) +#define GET_TX_DESC_TX_ANT_HT(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+8, 30, 2) + +#define SET_TX_DESC_NEXT_HEAP_PAGE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+12, 0, 8, __val) +#define SET_TX_DESC_TAIL_PAGE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+12, 8, 8, __val) +#define SET_TX_DESC_SEQ(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+12, 16, 12, __val) +#define SET_TX_DESC_PKT_ID(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+12, 28, 4, __val) + +#define GET_TX_DESC_NEXT_HEAP_PAGE(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+12, 0, 8) +#define GET_TX_DESC_TAIL_PAGE(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+12, 8, 8) +#define GET_TX_DESC_SEQ(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+12, 16, 12) +#define GET_TX_DESC_PKT_ID(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+12, 28, 4) + +#define SET_TX_DESC_RTS_RATE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+16, 0, 5, __val) +#define SET_TX_DESC_AP_DCFE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+16, 5, 1, __val) +#define SET_TX_DESC_QOS(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+16, 6, 1, __val) +#define SET_TX_DESC_HWSEQ_EN(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+16, 7, 1, __val) +#define SET_TX_DESC_USE_RATE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+16, 8, 1, __val) +#define SET_TX_DESC_DISABLE_RTS_FB(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+16, 9, 1, __val) +#define SET_TX_DESC_DISABLE_FB(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+16, 10, 1, __val) +#define SET_TX_DESC_CTS2SELF(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+16, 11, 1, __val) +#define SET_TX_DESC_RTS_ENABLE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+16, 12, 1, __val) +#define SET_TX_DESC_HW_RTS_ENABLE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+16, 13, 1, __val) +#define SET_TX_DESC_PORT_ID(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+16, 14, 1, __val) +#define SET_TX_DESC_WAIT_DCTS(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+16, 18, 1, __val) +#define SET_TX_DESC_CTS2AP_EN(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+16, 19, 1, __val) +#define SET_TX_DESC_TX_SUB_CARRIER(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+16, 20, 2, __val) +#define SET_TX_DESC_TX_STBC(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+16, 22, 2, __val) +#define SET_TX_DESC_DATA_SHORT(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+16, 24, 1, __val) +#define SET_TX_DESC_DATA_BW(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+16, 25, 1, __val) +#define SET_TX_DESC_RTS_SHORT(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+16, 26, 1, __val) +#define SET_TX_DESC_RTS_BW(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+16, 27, 1, __val) +#define SET_TX_DESC_RTS_SC(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+16, 28, 2, __val) +#define SET_TX_DESC_RTS_STBC(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+16, 30, 2, __val) + +#define GET_TX_DESC_RTS_RATE(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+16, 0, 5) +#define GET_TX_DESC_AP_DCFE(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+16, 5, 1) +#define GET_TX_DESC_QOS(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+16, 6, 1) +#define GET_TX_DESC_HWSEQ_EN(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+16, 7, 1) +#define GET_TX_DESC_USE_RATE(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+16, 8, 1) +#define GET_TX_DESC_DISABLE_RTS_FB(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+16, 9, 1) +#define GET_TX_DESC_DISABLE_FB(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+16, 10, 1) +#define GET_TX_DESC_CTS2SELF(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+16, 11, 1) +#define GET_TX_DESC_RTS_ENABLE(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+16, 12, 1) +#define GET_TX_DESC_HW_RTS_ENABLE(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+16, 13, 1) +#define GET_TX_DESC_PORT_ID(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+16, 14, 1) +#define GET_TX_DESC_WAIT_DCTS(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+16, 18, 1) +#define GET_TX_DESC_CTS2AP_EN(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+16, 19, 1) +#define GET_TX_DESC_TX_SUB_CARRIER(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+16, 20, 2) +#define GET_TX_DESC_TX_STBC(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+16, 22, 2) +#define GET_TX_DESC_DATA_SHORT(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+16, 24, 1) +#define GET_TX_DESC_DATA_BW(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+16, 25, 1) +#define GET_TX_DESC_RTS_SHORT(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+16, 26, 1) +#define GET_TX_DESC_RTS_BW(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+16, 27, 1) +#define GET_TX_DESC_RTS_SC(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+16, 28, 2) +#define GET_TX_DESC_RTS_STBC(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+16, 30, 2) + +#define SET_TX_DESC_TX_RATE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+20, 0, 6, __val) +#define SET_TX_DESC_DATA_SHORTGI(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+20, 6, 1, __val) +#define SET_TX_DESC_CCX_TAG(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+20, 7, 1, __val) +#define SET_TX_DESC_DATA_RATE_FB_LIMIT(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+20, 8, 5, __val) +#define SET_TX_DESC_RTS_RATE_FB_LIMIT(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+20, 13, 4, __val) +#define SET_TX_DESC_RETRY_LIMIT_ENABLE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+20, 17, 1, __val) +#define SET_TX_DESC_DATA_RETRY_LIMIT(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+20, 18, 6, __val) +#define SET_TX_DESC_USB_TXAGG_NUM(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+20, 24, 8, __val) + +#define GET_TX_DESC_TX_RATE(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+20, 0, 6) +#define GET_TX_DESC_DATA_SHORTGI(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+20, 6, 1) +#define GET_TX_DESC_CCX_TAG(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+20, 7, 1) +#define GET_TX_DESC_DATA_RATE_FB_LIMIT(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+20, 8, 5) +#define GET_TX_DESC_RTS_RATE_FB_LIMIT(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+20, 13, 4) +#define GET_TX_DESC_RETRY_LIMIT_ENABLE(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+20, 17, 1) +#define GET_TX_DESC_DATA_RETRY_LIMIT(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+20, 18, 6) +#define GET_TX_DESC_USB_TXAGG_NUM(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+20, 24, 8) + +#define SET_TX_DESC_TXAGC_A(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+24, 0, 5, __val) +#define SET_TX_DESC_TXAGC_B(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+24, 5, 5, __val) +#define SET_TX_DESC_USE_MAX_LEN(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+24, 10, 1, __val) +#define SET_TX_DESC_MAX_AGG_NUM(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+24, 11, 5, __val) +#define SET_TX_DESC_MCSG1_MAX_LEN(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+24, 16, 4, __val) +#define SET_TX_DESC_MCSG2_MAX_LEN(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+24, 20, 4, __val) +#define SET_TX_DESC_MCSG3_MAX_LEN(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+24, 24, 4, __val) +#define SET_TX_DESC_MCS7_SGI_MAX_LEN(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+24, 28, 4, __val) + +#define GET_TX_DESC_TXAGC_A(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+24, 0, 5) +#define GET_TX_DESC_TXAGC_B(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+24, 5, 5) +#define GET_TX_DESC_USE_MAX_LEN(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+24, 10, 1) +#define GET_TX_DESC_MAX_AGG_NUM(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+24, 11, 5) +#define GET_TX_DESC_MCSG1_MAX_LEN(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+24, 16, 4) +#define GET_TX_DESC_MCSG2_MAX_LEN(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+24, 20, 4) +#define GET_TX_DESC_MCSG3_MAX_LEN(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+24, 24, 4) +#define GET_TX_DESC_MCS7_SGI_MAX_LEN(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+24, 28, 4) + +#define SET_TX_DESC_TX_BUFFER_SIZE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+28, 0, 16, __val) +#define SET_TX_DESC_MCSG4_MAX_LEN(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+28, 16, 4, __val) +#define SET_TX_DESC_MCSG5_MAX_LEN(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+28, 20, 4, __val) +#define SET_TX_DESC_MCSG6_MAX_LEN(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+28, 24, 4, __val) +#define SET_TX_DESC_MCS15_SGI_MAX_LEN(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+28, 28, 4, __val) + +#define GET_TX_DESC_TX_BUFFER_SIZE(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+28, 0, 16) +#define GET_TX_DESC_MCSG4_MAX_LEN(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+28, 16, 4) +#define GET_TX_DESC_MCSG5_MAX_LEN(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+28, 20, 4) +#define GET_TX_DESC_MCSG6_MAX_LEN(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+28, 24, 4) +#define GET_TX_DESC_MCS15_SGI_MAX_LEN(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+28, 28, 4) + +#define SET_TX_DESC_TX_BUFFER_ADDRESS(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+32, 0, 32, __val) +#define SET_TX_DESC_TX_BUFFER_ADDRESS64(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+36, 0, 32, __val) + +#define GET_TX_DESC_TX_BUFFER_ADDRESS(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+32, 0, 32) +#define GET_TX_DESC_TX_BUFFER_ADDRESS64(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+36, 0, 32) + +#define SET_TX_DESC_NEXT_DESC_ADDRESS(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+40, 0, 32, __val) +#define SET_TX_DESC_NEXT_DESC_ADDRESS64(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+44, 0, 32, __val) + +#define GET_TX_DESC_NEXT_DESC_ADDRESS(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+40, 0, 32) +#define GET_TX_DESC_NEXT_DESC_ADDRESS64(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+44, 0, 32) + +#define GET_RX_DESC_PKT_LEN(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 0, 14) +#define GET_RX_DESC_CRC32(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 14, 1) +#define GET_RX_DESC_ICV(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 15, 1) +#define GET_RX_DESC_DRV_INFO_SIZE(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 16, 4) +#define GET_RX_DESC_SECURITY(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 20, 3) +#define GET_RX_DESC_QOS(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 23, 1) +#define GET_RX_DESC_SHIFT(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 24, 2) +#define GET_RX_DESC_PHYST(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 26, 1) +#define GET_RX_DESC_SWDEC(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 27, 1) +#define GET_RX_DESC_LS(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 28, 1) +#define GET_RX_DESC_FS(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 29, 1) +#define GET_RX_DESC_EOR(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 30, 1) +#define GET_RX_DESC_OWN(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 31, 1) + +#define SET_RX_DESC_PKT_LEN(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 0, 14, __val) +#define SET_RX_DESC_EOR(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 30, 1, __val) +#define SET_RX_DESC_OWN(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 31, 1, __val) + +#define GET_RX_DESC_MACID(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+4, 0, 5) +#define GET_RX_DESC_TID(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+4, 5, 4) +#define GET_RX_DESC_HWRSVD(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+4, 9, 5) +#define GET_RX_DESC_PAGGR(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+4, 14, 1) +#define GET_RX_DESC_FAGGR(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+4, 15, 1) +#define GET_RX_DESC_A1_FIT(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+4, 16, 4) +#define GET_RX_DESC_A2_FIT(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+4, 20, 4) +#define GET_RX_DESC_PAM(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+4, 24, 1) +#define GET_RX_DESC_PWR(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+4, 25, 1) +#define GET_RX_DESC_MD(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+4, 26, 1) +#define GET_RX_DESC_MF(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+4, 27, 1) +#define GET_RX_DESC_TYPE(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+4, 28, 2) +#define GET_RX_DESC_MC(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+4, 30, 1) +#define GET_RX_DESC_BC(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+4, 31, 1) +#define GET_RX_DESC_SEQ(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+8, 0, 12) +#define GET_RX_DESC_FRAG(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+8, 12, 4) +#define GET_RX_DESC_NEXT_PKT_LEN(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+8, 16, 14) +#define GET_RX_DESC_NEXT_IND(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+8, 30, 1) +#define GET_RX_DESC_RSVD(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+8, 31, 1) + +#define GET_RX_DESC_RXMCS(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+12, 0, 6) +#define GET_RX_DESC_RXHT(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+12, 6, 1) +#define GET_RX_DESC_SPLCP(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+12, 8, 1) +#define GET_RX_DESC_BW(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+12, 9, 1) +#define GET_RX_DESC_HTC(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+12, 10, 1) +#define GET_RX_DESC_HWPC_ERR(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+12, 14, 1) +#define GET_RX_DESC_HWPC_IND(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+12, 15, 1) +#define GET_RX_DESC_IV0(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+12, 16, 16) + +#define GET_RX_DESC_IV1(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+16, 0, 32) +#define GET_RX_DESC_TSFL(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+20, 0, 32) + +#define GET_RX_DESC_BUFF_ADDR(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+24, 0, 32) +#define GET_RX_DESC_BUFF_ADDR64(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+28, 0, 32) + +#define SET_RX_DESC_BUFF_ADDR(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+24, 0, 32, __val) +#define SET_RX_DESC_BUFF_ADDR64(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+28, 0, 32, __val) + +#define CLEAR_PCI_TX_DESC_CONTENT(__pdesc, _size) \ +do { \ + if (_size > TX_DESC_NEXT_DESC_OFFSET) \ + memset((void *)__pdesc, 0, TX_DESC_NEXT_DESC_OFFSET); \ + else \ + memset((void *)__pdesc, 0, _size); \ +} while (0); + +/* For 92D early mode */ +#define SET_EARLYMODE_PKTNUM(__paddr, __value) \ + SET_BITS_OFFSET_LE(__paddr, 0, 3, __value) +#define SET_EARLYMODE_LEN0(__paddr, __value) \ + SET_BITS_OFFSET_LE(__paddr, 4, 12, __value) +#define SET_EARLYMODE_LEN1(__paddr, __value) \ + SET_BITS_OFFSET_LE(__paddr, 16, 12, __value) +#define SET_EARLYMODE_LEN2_1(__paddr, __value) \ + SET_BITS_OFFSET_LE(__paddr, 28, 4, __value) +#define SET_EARLYMODE_LEN2_2(__paddr, __value) \ + SET_BITS_OFFSET_LE(__paddr+4, 0, 8, __value) +#define SET_EARLYMODE_LEN3(__paddr, __value) \ + SET_BITS_OFFSET_LE(__paddr+4, 8, 12, __value) +#define SET_EARLYMODE_LEN4(__paddr, __value) \ + SET_BITS_OFFSET_LE(__paddr+4, 20, 12, __value) + +struct rx_fwinfo_92d { + 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_92d { + 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:5; + u32 agg_en:1; + u32 bk:1; + u32 rdg_en:1; + 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 rsvd0:2; + u32 bar_retryht:2; + u32 rsvd1:1; + u32 morefrag:1; + u32 raw:1; + u32 ccx:1; + u32 ampdudensity:3; + u32 rsvd2: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 pktid:4; + + u32 rtsrate:5; + u32 apdcfe:1; + u32 qos:1; + u32 hwseq_enable: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 rsvd3: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 mcsg4maxlen:4; + u32 mcsg5maxlen:4; + u32 mcsg6maxlen:4; + u32 mcsg15sgimaxlen:4; + + u32 txbuffaddr; + u32 txbufferaddr64; + u32 nextdescaddress; + u32 nextdescaddress64; + + u32 reserve_pass_pcie_mm_limit[4]; +} __packed; + +struct rx_desc_92d { + 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:5; + 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 rtl92de_tx_fill_desc(struct ieee80211_hw *hw, + struct ieee80211_hdr *hdr, + u8 *pdesc, struct ieee80211_tx_info *info, + struct sk_buff *skb, u8 hw_queue, + struct rtl_tcb_desc *ptcb_desc); +bool rtl92de_rx_query_desc(struct ieee80211_hw *hw, + struct rtl_stats *stats, + struct ieee80211_rx_status *rx_status, + u8 *pdesc, struct sk_buff *skb); +void rtl92de_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val); +u32 rtl92de_get_desc(u8 *pdesc, bool istx, u8 desc_name); +void rtl92de_tx_polling(struct ieee80211_hw *hw, u8 hw_queue); +void rtl92de_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc, + bool b_firstseg, bool b_lastseg, + struct sk_buff *skb); + +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/Makefile b/drivers/net/wireless/rtlwifi/rtl8192se/Makefile new file mode 100644 index 00000000..b7eb1381 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192se/Makefile @@ -0,0 +1,15 @@ +rtl8192se-objs := \ + dm.o \ + fw.o \ + hw.o \ + led.o \ + phy.o \ + rf.o \ + sw.o \ + table.o \ + trx.o + +obj-$(CONFIG_RTL8192SE) += rtl8192se.o + +ccflags-y += -D__CHECK_ENDIAN__ + diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/def.h b/drivers/net/wireless/rtlwifi/rtl8192se/def.h new file mode 100644 index 00000000..d1b0a1e1 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192se/def.h @@ -0,0 +1,567 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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 __REALTEK_92S_DEF_H__ +#define __REALTEK_92S_DEF_H__ + +#define RX_MPDU_QUEUE 0 +#define RX_CMD_QUEUE 1 +#define RX_MAX_QUEUE 2 + +#define SHORT_SLOT_TIME 9 +#define NON_SHORT_SLOT_TIME 20 + +/* Rx smooth factor */ +#define RX_SMOOTH_FACTOR 20 + +/* Queue Select Value in TxDesc */ +#define QSLT_BK 0x2 +#define QSLT_BE 0x0 +#define QSLT_VI 0x5 +#define QSLT_VO 0x6 +#define QSLT_BEACON 0x10 +#define QSLT_HIGH 0x11 +#define QSLT_MGNT 0x12 +#define QSLT_CMD 0x13 + +#define PHY_RSSI_SLID_WIN_MAX 100 +#define PHY_LINKQUALITY_SLID_WIN_MAX 20 +#define PHY_BEACON_RSSI_SLID_WIN_MAX 10 + +/* Tx Desc */ +#define TX_DESC_SIZE_RTL8192S (16 * 4) +#define TX_CMDDESC_SIZE_RTL8192S (16 * 4) + +/* Define a macro that takes a le32 word, converts it to host ordering, + * right shifts by a specified count, creates a mask of the specified + * bit count, and extracts that number of bits. + */ + +#define SHIFT_AND_MASK_LE(__pdesc, __shift, __mask) \ + ((le32_to_cpu(*(((__le32 *)(__pdesc)))) >> (__shift)) & \ + BIT_LEN_MASK_32(__mask)) + +/* Define a macro that clears a bit field in an le32 word and + * sets the specified value into that bit field. The resulting + * value remains in le32 ordering; however, it is properly converted + * to host ordering for the clear and set operations before conversion + * back to le32. + */ + +#define SET_BITS_OFFSET_LE(__pdesc, __shift, __len, __val) \ + (*(__le32 *)(__pdesc) = \ + (cpu_to_le32((le32_to_cpu(*((__le32 *)(__pdesc))) & \ + (~(BIT_OFFSET_LEN_MASK_32((__shift), __len)))) | \ + (((u32)(__val) & BIT_LEN_MASK_32(__len)) << (__shift))))); + +/* macros to read/write various fields in RX or TX descriptors */ + +/* Dword 0 */ +#define SET_TX_DESC_PKT_SIZE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 0, 16, __val) +#define SET_TX_DESC_OFFSET(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 16, 8, __val) +#define SET_TX_DESC_TYPE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 24, 2, __val) +#define SET_TX_DESC_LAST_SEG(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 26, 1, __val) +#define SET_TX_DESC_FIRST_SEG(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 27, 1, __val) +#define SET_TX_DESC_LINIP(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 28, 1, __val) +#define SET_TX_DESC_AMSDU(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 29, 1, __val) +#define SET_TX_DESC_GREEN_FIELD(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 30, 1, __val) +#define SET_TX_DESC_OWN(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 31, 1, __val) + +#define GET_TX_DESC_OWN(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 31, 1) + +/* Dword 1 */ +#define SET_TX_DESC_MACID(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 0, 5, __val) +#define SET_TX_DESC_MORE_DATA(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 5, 1, __val) +#define SET_TX_DESC_MORE_FRAG(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 6, 1, __val) +#define SET_TX_DESC_PIFS(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 7, 1, __val) +#define SET_TX_DESC_QUEUE_SEL(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 8, 5, __val) +#define SET_TX_DESC_ACK_POLICY(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 13, 2, __val) +#define SET_TX_DESC_NO_ACM(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 15, 1, __val) +#define SET_TX_DESC_NON_QOS(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 16, 1, __val) +#define SET_TX_DESC_KEY_ID(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 17, 2, __val) +#define SET_TX_DESC_OUI(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 19, 1, __val) +#define SET_TX_DESC_PKT_TYPE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 20, 1, __val) +#define SET_TX_DESC_EN_DESC_ID(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 21, 1, __val) +#define SET_TX_DESC_SEC_TYPE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 22, 2, __val) +#define SET_TX_DESC_WDS(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 24, 1, __val) +#define SET_TX_DESC_HTC(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 25, 1, __val) +#define SET_TX_DESC_PKT_OFFSET(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 26, 5, __val) +#define SET_TX_DESC_HWPC(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 27, 1, __val) + +/* Dword 2 */ +#define SET_TX_DESC_DATA_RETRY_LIMIT(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 8, 0, 6, __val) +#define SET_TX_DESC_RETRY_LIMIT_ENABLE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 8, 6, 1, __val) +#define SET_TX_DESC_TSFL(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 8, 7, 5, __val) +#define SET_TX_DESC_RTS_RETRY_COUNT(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 8, 12, 6, __val) +#define SET_TX_DESC_DATA_RETRY_COUNT(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 8, 18, 6, __val) +#define SET_TX_DESC_RSVD_MACID(__pdesc, __val) \ + SET_BITS_OFFSET_LE(((__pdesc) + 8), 24, 5, __val) +#define SET_TX_DESC_AGG_ENABLE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 8, 29, 1, __val) +#define SET_TX_DESC_AGG_BREAK(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 8, 30, 1, __val) +#define SET_TX_DESC_OWN_MAC(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 8, 31, 1, __val) + +/* Dword 3 */ +#define SET_TX_DESC_NEXT_HEAP_PAGE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 12, 0, 8, __val) +#define SET_TX_DESC_TAIL_PAGE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 12, 8, 8, __val) +#define SET_TX_DESC_SEQ(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 12, 16, 12, __val) +#define SET_TX_DESC_FRAG(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 12, 28, 4, __val) + +/* Dword 4 */ +#define SET_TX_DESC_RTS_RATE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 16, 0, 6, __val) +#define SET_TX_DESC_DISABLE_RTS_FB(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 16, 6, 1, __val) +#define SET_TX_DESC_RTS_RATE_FB_LIMIT(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 16, 7, 4, __val) +#define SET_TX_DESC_CTS_ENABLE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 16, 11, 1, __val) +#define SET_TX_DESC_RTS_ENABLE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 16, 12, 1, __val) +#define SET_TX_DESC_RA_BRSR_ID(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 16, 13, 3, __val) +#define SET_TX_DESC_TXHT(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 16, 16, 1, __val) +#define SET_TX_DESC_TX_SHORT(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 16, 17, 1, __val) +#define SET_TX_DESC_TX_BANDWIDTH(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 16, 18, 1, __val) +#define SET_TX_DESC_TX_SUB_CARRIER(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 16, 19, 2, __val) +#define SET_TX_DESC_TX_STBC(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 16, 21, 2, __val) +#define SET_TX_DESC_TX_REVERSE_DIRECTION(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 16, 23, 1, __val) +#define SET_TX_DESC_RTS_HT(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 16, 24, 1, __val) +#define SET_TX_DESC_RTS_SHORT(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 16, 25, 1, __val) +#define SET_TX_DESC_RTS_BANDWIDTH(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 16, 26, 1, __val) +#define SET_TX_DESC_RTS_SUB_CARRIER(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 16, 27, 2, __val) +#define SET_TX_DESC_RTS_STBC(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 16, 29, 2, __val) +#define SET_TX_DESC_USER_RATE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 16, 31, 1, __val) + +/* Dword 5 */ +#define SET_TX_DESC_PACKET_ID(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 20, 0, 9, __val) +#define SET_TX_DESC_TX_RATE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 20, 9, 6, __val) +#define SET_TX_DESC_DISABLE_FB(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 20, 15, 1, __val) +#define SET_TX_DESC_DATA_RATE_FB_LIMIT(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 20, 16, 5, __val) +#define SET_TX_DESC_TX_AGC(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 20, 21, 11, __val) + +/* Dword 6 */ +#define SET_TX_DESC_IP_CHECK_SUM(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 24, 0, 16, __val) +#define SET_TX_DESC_TCP_CHECK_SUM(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 24, 16, 16, __val) + +/* Dword 7 */ +#define SET_TX_DESC_TX_BUFFER_SIZE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 28, 0, 16, __val) +#define SET_TX_DESC_IP_HEADER_OFFSET(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 28, 16, 8, __val) +#define SET_TX_DESC_TCP_ENABLE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 28, 31, 1, __val) + +/* Dword 8 */ +#define SET_TX_DESC_TX_BUFFER_ADDRESS(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 32, 0, 32, __val) +#define GET_TX_DESC_TX_BUFFER_ADDRESS(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 32, 0, 32) + +/* Dword 9 */ +#define SET_TX_DESC_NEXT_DESC_ADDRESS(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 36, 0, 32, __val) + +/* Because the PCI Tx descriptors are chaied at the + * initialization and all the NextDescAddresses in + * these descriptors cannot not be cleared (,or + * driver/HW cannot find the next descriptor), the + * offset 36 (NextDescAddresses) is reserved when + * the desc is cleared. */ +#define TX_DESC_NEXT_DESC_OFFSET 36 +#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); + +/* Rx Desc */ +#define RX_STATUS_DESC_SIZE 24 +#define RX_DRV_INFO_SIZE_UNIT 8 + +/* DWORD 0 */ +#define SET_RX_STATUS_DESC_PKT_LEN(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 0, 14, __val) +#define SET_RX_STATUS_DESC_CRC32(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 14, 1, __val) +#define SET_RX_STATUS_DESC_ICV(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 15, 1, __val) +#define SET_RX_STATUS_DESC_DRVINFO_SIZE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 16, 4, __val) +#define SET_RX_STATUS_DESC_SECURITY(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 20, 3, __val) +#define SET_RX_STATUS_DESC_QOS(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 23, 1, __val) +#define SET_RX_STATUS_DESC_SHIFT(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 24, 2, __val) +#define SET_RX_STATUS_DESC_PHY_STATUS(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 26, 1, __val) +#define SET_RX_STATUS_DESC_SWDEC(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 27, 1, __val) +#define SET_RX_STATUS_DESC_LAST_SEG(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 28, 1, __val) +#define SET_RX_STATUS_DESC_FIRST_SEG(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 29, 1, __val) +#define SET_RX_STATUS_DESC_EOR(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 30, 1, __val) +#define SET_RX_STATUS_DESC_OWN(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 31, 1, __val) + +#define GET_RX_STATUS_DESC_PKT_LEN(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 0, 14) +#define GET_RX_STATUS_DESC_CRC32(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 14, 1) +#define GET_RX_STATUS_DESC_ICV(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 15, 1) +#define GET_RX_STATUS_DESC_DRVINFO_SIZE(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 16, 4) +#define GET_RX_STATUS_DESC_SECURITY(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 20, 3) +#define GET_RX_STATUS_DESC_QOS(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 23, 1) +#define GET_RX_STATUS_DESC_SHIFT(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 24, 2) +#define GET_RX_STATUS_DESC_PHY_STATUS(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 26, 1) +#define GET_RX_STATUS_DESC_SWDEC(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 27, 1) +#define GET_RX_STATUS_DESC_LAST_SEG(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 28, 1) +#define GET_RX_STATUS_DESC_FIRST_SEG(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 29, 1) +#define GET_RX_STATUS_DESC_EOR(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 30, 1) +#define GET_RX_STATUS_DESC_OWN(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 31, 1) + +/* DWORD 1 */ +#define SET_RX_STATUS_DESC_MACID(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 0, 5, __val) +#define SET_RX_STATUS_DESC_TID(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 5, 4, __val) +#define SET_RX_STATUS_DESC_PAGGR(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 14, 1, __val) +#define SET_RX_STATUS_DESC_FAGGR(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 15, 1, __val) +#define SET_RX_STATUS_DESC_A1_FIT(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 16, 4, __val) +#define SET_RX_STATUS_DESC_A2_FIT(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 20, 4, __val) +#define SET_RX_STATUS_DESC_PAM(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 24, 1, __val) +#define SET_RX_STATUS_DESC_PWR(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 25, 1, __val) +#define SET_RX_STATUS_DESC_MOREDATA(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 26, 1, __val) +#define SET_RX_STATUS_DESC_MOREFRAG(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 27, 1, __val) +#define SET_RX_STATUS_DESC_TYPE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 28, 2, __val) +#define SET_RX_STATUS_DESC_MC(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 30, 1, __val) +#define SET_RX_STATUS_DESC_BC(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 31, 1, __val) + +#define GET_RX_STATUS_DEC_MACID(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 4, 0, 5) +#define GET_RX_STATUS_DESC_TID(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 4, 5, 4) +#define GET_RX_STATUS_DESC_PAGGR(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 4, 14, 1) +#define GET_RX_STATUS_DESC_FAGGR(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 4, 15, 1) +#define GET_RX_STATUS_DESC_A1_FIT(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 4, 16, 4) +#define GET_RX_STATUS_DESC_A2_FIT(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 4, 20, 4) +#define GET_RX_STATUS_DESC_PAM(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 4, 24, 1) +#define GET_RX_STATUS_DESC_PWR(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 4, 25, 1) +#define GET_RX_STATUS_DESC_MORE_DATA(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 4, 26, 1) +#define GET_RX_STATUS_DESC_MORE_FRAG(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 4, 27, 1) +#define GET_RX_STATUS_DESC_TYPE(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 4, 28, 2) +#define GET_RX_STATUS_DESC_MC(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 4, 30, 1) +#define GET_RX_STATUS_DESC_BC(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 4, 31, 1) + +/* DWORD 2 */ +#define SET_RX_STATUS_DESC_SEQ(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 8, 0, 12, __val) +#define SET_RX_STATUS_DESC_FRAG(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 8, 12, 4, __val) +#define SET_RX_STATUS_DESC_NEXT_PKTLEN(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 8, 16, 8, __val) +#define SET_RX_STATUS_DESC_NEXT_IND(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 8, 30, 1, __val) + +#define GET_RX_STATUS_DESC_SEQ(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 8, 0, 12) +#define GET_RX_STATUS_DESC_FRAG(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 8, 12, 4) +#define GET_RX_STATUS_DESC_NEXT_PKTLEN(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 8, 16, 8) +#define GET_RX_STATUS_DESC_NEXT_IND(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 8, 30, 1) + +/* DWORD 3 */ +#define SET_RX_STATUS_DESC_RX_MCS(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 12, 0, 6, __val) +#define SET_RX_STATUS_DESC_RX_HT(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 12, 6, 1, __val) +#define SET_RX_STATUS_DESC_AMSDU(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 12, 7, 1, __val) +#define SET_RX_STATUS_DESC_SPLCP(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 12, 8, 1, __val) +#define SET_RX_STATUS_DESC_BW(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 12, 9, 1, __val) +#define SET_RX_STATUS_DESC_HTC(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 12, 10, 1, __val) +#define SET_RX_STATUS_DESC_TCP_CHK_RPT(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 12, 11, 1, __val) +#define SET_RX_STATUS_DESC_IP_CHK_RPT(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 12, 12, 1, __val) +#define SET_RX_STATUS_DESC_TCP_CHK_VALID(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 12, 13, 1, __val) +#define SET_RX_STATUS_DESC_HWPC_ERR(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 12, 14, 1, __val) +#define SET_RX_STATUS_DESC_HWPC_IND(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 12, 15, 1, __val) +#define SET_RX_STATUS_DESC_IV0(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 12, 16, 16, __val) + +#define GET_RX_STATUS_DESC_RX_MCS(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 12, 0, 6) +#define GET_RX_STATUS_DESC_RX_HT(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 12, 6, 1) +#define GET_RX_STATUS_DESC_AMSDU(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 12, 7, 1) +#define GET_RX_STATUS_DESC_SPLCP(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 12, 8, 1) +#define GET_RX_STATUS_DESC_BW(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 12, 9, 1) +#define GET_RX_STATUS_DESC_HTC(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 12, 10, 1) +#define GET_RX_STATUS_DESC_TCP_CHK_RPT(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 12, 11, 1) +#define GET_RX_STATUS_DESC_IP_CHK_RPT(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 12, 12, 1) +#define GET_RX_STATUS_DESC_TCP_CHK_VALID(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 12, 13, 1) +#define GET_RX_STATUS_DESC_HWPC_ERR(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 12, 14, 1) +#define GET_RX_STATUS_DESC_HWPC_IND(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 12, 15, 1) +#define GET_RX_STATUS_DESC_IV0(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 12, 16, 16) + +/* DWORD 4 */ +#define SET_RX_STATUS_DESC_IV1(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 16, 0, 32, __val) +#define GET_RX_STATUS_DESC_IV1(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 16, 0, 32) + +/* DWORD 5 */ +#define SET_RX_STATUS_DESC_TSFL(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 20, 0, 32, __val) +#define GET_RX_STATUS_DESC_TSFL(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 20, 0, 32) + +/* DWORD 6 */ +#define SET_RX_STATUS__DESC_BUFF_ADDR(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 24, 0, 32, __val) + +#define SE_RX_HAL_IS_CCK_RATE(_pdesc)\ + (GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC92_RATE1M || \ + GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC92_RATE2M || \ + GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC92_RATE5_5M ||\ + GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC92_RATE11M) + +enum rf_optype { + RF_OP_BY_SW_3WIRE = 0, + RF_OP_BY_FW, + RF_OP_MAX +}; + +enum ic_inferiority { + IC_INFERIORITY_A = 0, + IC_INFERIORITY_B = 1, +}; + +enum fwcmd_iotype { + /* For DIG DM */ + FW_CMD_DIG_ENABLE = 0, + FW_CMD_DIG_DISABLE = 1, + FW_CMD_DIG_HALT = 2, + FW_CMD_DIG_RESUME = 3, + /* For High Power DM */ + FW_CMD_HIGH_PWR_ENABLE = 4, + FW_CMD_HIGH_PWR_DISABLE = 5, + /* For Rate adaptive DM */ + FW_CMD_RA_RESET = 6, + FW_CMD_RA_ACTIVE = 7, + FW_CMD_RA_REFRESH_N = 8, + FW_CMD_RA_REFRESH_BG = 9, + FW_CMD_RA_INIT = 10, + /* For FW supported IQK */ + FW_CMD_IQK_INIT = 11, + /* Tx power tracking switch, + * MP driver only */ + FW_CMD_TXPWR_TRACK_ENABLE = 12, + /* Tx power tracking switch, + * MP driver only */ + FW_CMD_TXPWR_TRACK_DISABLE = 13, + /* Tx power tracking with thermal + * indication, for Normal driver */ + FW_CMD_TXPWR_TRACK_THERMAL = 14, + FW_CMD_PAUSE_DM_BY_SCAN = 15, + FW_CMD_RESUME_DM_BY_SCAN = 16, + FW_CMD_RA_REFRESH_N_COMB = 17, + FW_CMD_RA_REFRESH_BG_COMB = 18, + FW_CMD_ANTENNA_SW_ENABLE = 19, + FW_CMD_ANTENNA_SW_DISABLE = 20, + /* Tx Status report for CCX from FW */ + FW_CMD_TX_FEEDBACK_CCX_ENABLE = 21, + /* Indifate firmware that driver + * enters LPS, For PS-Poll issue */ + FW_CMD_LPS_ENTER = 22, + /* Indicate firmware that driver + * leave LPS*/ + FW_CMD_LPS_LEAVE = 23, + /* Set DIG mode to signal strength */ + FW_CMD_DIG_MODE_SS = 24, + /* Set DIG mode to false alarm. */ + FW_CMD_DIG_MODE_FA = 25, + FW_CMD_ADD_A2_ENTRY = 26, + FW_CMD_CTRL_DM_BY_DRIVER = 27, + FW_CMD_CTRL_DM_BY_DRIVER_NEW = 28, + FW_CMD_PAPE_CONTROL = 29, + FW_CMD_IQK_ENABLE = 30, +}; + +/* + * Driver info contain PHY status + * and other variabel size info + * PHY Status content as below + */ +struct rx_fwinfo { + /* DWORD 0 */ + u8 gain_trsw[4]; + /* DWORD 1 */ + u8 pwdb_all; + u8 cfosho[4]; + /* DWORD 2 */ + u8 cfotail[4]; + /* DWORD 3 */ + s8 rxevm[2]; + s8 rxsnr[4]; + /* DWORD 4 */ + u8 pdsnr[2]; + /* DWORD 5 */ + u8 csi_current[2]; + u8 csi_target[2]; + /* DWORD 6 */ + u8 sigevm; + u8 max_ex_pwr; + u8 ex_intf_flag:1; + u8 sgi_en:1; + u8 rxsc:2; + u8 reserve:4; +}; + +struct phy_sts_cck_8192s_t { + u8 adc_pwdb_x[4]; + u8 sq_rpt; + u8 cck_agc_rpt; +}; + +#endif + diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/dm.c b/drivers/net/wireless/rtlwifi/rtl8192se/dm.c new file mode 100644 index 00000000..fbabae17 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192se/dm.c @@ -0,0 +1,728 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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> + * + *****************************************************************************/ + +#include "../wifi.h" +#include "../base.h" +#include "reg.h" +#include "def.h" +#include "phy.h" +#include "dm.h" +#include "fw.h" + +struct dig_t digtable; +static const u32 edca_setting_dl[PEER_MAX] = { + 0xa44f, /* 0 UNKNOWN */ + 0x5ea44f, /* 1 REALTEK_90 */ + 0x5ea44f, /* 2 REALTEK_92SE */ + 0xa630, /* 3 BROAD */ + 0xa44f, /* 4 RAL */ + 0xa630, /* 5 ATH */ + 0xa630, /* 6 CISCO */ + 0xa42b, /* 7 MARV */ +}; + +static const u32 edca_setting_dl_gmode[PEER_MAX] = { + 0x4322, /* 0 UNKNOWN */ + 0xa44f, /* 1 REALTEK_90 */ + 0x5ea44f, /* 2 REALTEK_92SE */ + 0xa42b, /* 3 BROAD */ + 0x5e4322, /* 4 RAL */ + 0x4322, /* 5 ATH */ + 0xa430, /* 6 CISCO */ + 0x5ea44f, /* 7 MARV */ +}; + +static const u32 edca_setting_ul[PEER_MAX] = { + 0x5e4322, /* 0 UNKNOWN */ + 0xa44f, /* 1 REALTEK_90 */ + 0x5ea44f, /* 2 REALTEK_92SE */ + 0x5ea322, /* 3 BROAD */ + 0x5ea422, /* 4 RAL */ + 0x5ea322, /* 5 ATH */ + 0x3ea44f, /* 6 CISCO */ + 0x5ea44f, /* 7 MARV */ +}; + +static void _rtl92s_dm_check_edca_turbo(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(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 = edca_setting_ul[mac->vendor]; + u32 edca_be_dl = edca_setting_dl[mac->vendor]; + u32 edca_gmode = edca_setting_dl_gmode[mac->vendor]; + + if (mac->link_state != MAC80211_LINKED) { + rtlpriv->dm.current_turbo_edca = false; + goto dm_checkedcaturbo_exit; + } + + if ((!rtlpriv->dm.is_any_nonbepkts) && + (!rtlpriv->dm.disable_framebursting)) { + cur_txok_cnt = rtlpriv->stats.txbytesunicast - last_txok_cnt; + cur_rxok_cnt = rtlpriv->stats.rxbytesunicast - last_rxok_cnt; + + if (rtlpriv->phy.rf_type == RF_1T2R) { + if (cur_txok_cnt > 4 * cur_rxok_cnt) { + /* Uplink TP is present. */ + if (rtlpriv->dm.is_cur_rdlstate || + !rtlpriv->dm.current_turbo_edca) { + rtl_write_dword(rtlpriv, EDCAPARA_BE, + edca_be_ul); + rtlpriv->dm.is_cur_rdlstate = false; + } + } else {/* Balance TP is present. */ + if (!rtlpriv->dm.is_cur_rdlstate || + !rtlpriv->dm.current_turbo_edca) { + if (mac->mode == WIRELESS_MODE_G || + mac->mode == WIRELESS_MODE_B) + rtl_write_dword(rtlpriv, + EDCAPARA_BE, + edca_gmode); + else + rtl_write_dword(rtlpriv, + EDCAPARA_BE, + edca_be_dl); + rtlpriv->dm.is_cur_rdlstate = true; + } + } + rtlpriv->dm.current_turbo_edca = true; + } else { + if (cur_rxok_cnt > 4 * cur_txok_cnt) { + if (!rtlpriv->dm.is_cur_rdlstate || + !rtlpriv->dm.current_turbo_edca) { + if (mac->mode == WIRELESS_MODE_G || + mac->mode == WIRELESS_MODE_B) + rtl_write_dword(rtlpriv, + EDCAPARA_BE, + edca_gmode); + else + rtl_write_dword(rtlpriv, + EDCAPARA_BE, + edca_be_dl); + rtlpriv->dm.is_cur_rdlstate = true; + } + } else { + if (rtlpriv->dm.is_cur_rdlstate || + !rtlpriv->dm.current_turbo_edca) { + rtl_write_dword(rtlpriv, EDCAPARA_BE, + edca_be_ul); + rtlpriv->dm.is_cur_rdlstate = false; + } + } + rtlpriv->dm.current_turbo_edca = true; + } + } else { + if (rtlpriv->dm.current_turbo_edca) { + u8 tmp = AC0_BE; + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_AC_PARAM, + (u8 *)(&tmp)); + rtlpriv->dm.current_turbo_edca = false; + } + } + +dm_checkedcaturbo_exit: + rtlpriv->dm.is_any_nonbepkts = false; + last_txok_cnt = rtlpriv->stats.txbytesunicast; + last_rxok_cnt = rtlpriv->stats.rxbytesunicast; +} + +static void _rtl92s_dm_txpowertracking_callback_thermalmeter( + struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + u8 thermalvalue = 0; + + rtlpriv->dm.txpower_trackinginit = true; + + thermalvalue = (u8)rtl_get_rfreg(hw, RF90_PATH_A, RF_T_METER, 0x1f); + + RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, + "Readback Thermal Meter = 0x%x pre thermal meter 0x%x eeprom_thermal meter 0x%x\n", + thermalvalue, + rtlpriv->dm.thermalvalue, rtlefuse->eeprom_thermalmeter); + + if (thermalvalue) { + rtlpriv->dm.thermalvalue = thermalvalue; + rtl92s_phy_set_fw_cmd(hw, FW_CMD_TXPWR_TRACK_THERMAL); + } + + rtlpriv->dm.txpowercount = 0; +} + +static void _rtl92s_dm_check_txpowertracking_thermalmeter( + struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + static u8 tm_trigger; + u8 tx_power_checkcnt = 5; + + /* 2T2R TP issue */ + if (rtlphy->rf_type == RF_2T2R) + return; + + if (!rtlpriv->dm.txpower_tracking) + return; + + if (rtlpriv->dm.txpowercount <= tx_power_checkcnt) { + rtlpriv->dm.txpowercount++; + return; + } + + if (!tm_trigger) { + rtl_set_rfreg(hw, RF90_PATH_A, RF_T_METER, + RFREG_OFFSET_MASK, 0x60); + tm_trigger = 1; + } else { + _rtl92s_dm_txpowertracking_callback_thermalmeter(hw); + tm_trigger = 0; + } +} + +static void _rtl92s_dm_refresh_rateadaptive_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 *ra = &(rtlpriv->ra); + + u32 low_rssi_thresh = 0; + u32 middle_rssi_thresh = 0; + u32 high_rssi_thresh = 0; + struct ieee80211_sta *sta = NULL; + + if (is_hal_stop(rtlhal)) + return; + + if (!rtlpriv->dm.useramask) + return; + + if (!rtlpriv->dm.inform_fw_driverctrldm) { + rtl92s_phy_set_fw_cmd(hw, FW_CMD_CTRL_DM_BY_DRIVER); + rtlpriv->dm.inform_fw_driverctrldm = true; + } + + rcu_read_lock(); + if (mac->opmode == NL80211_IFTYPE_STATION) + sta = get_sta(hw, mac->vif, mac->bssid); + if ((mac->link_state == MAC80211_LINKED) && + (mac->opmode == NL80211_IFTYPE_STATION)) { + switch (ra->pre_ratr_state) { + case DM_RATR_STA_HIGH: + high_rssi_thresh = 40; + middle_rssi_thresh = 30; + low_rssi_thresh = 20; + break; + case DM_RATR_STA_MIDDLE: + high_rssi_thresh = 44; + middle_rssi_thresh = 30; + low_rssi_thresh = 20; + break; + case DM_RATR_STA_LOW: + high_rssi_thresh = 44; + middle_rssi_thresh = 34; + low_rssi_thresh = 20; + break; + case DM_RATR_STA_ULTRALOW: + high_rssi_thresh = 44; + middle_rssi_thresh = 34; + low_rssi_thresh = 24; + break; + default: + high_rssi_thresh = 44; + middle_rssi_thresh = 34; + low_rssi_thresh = 24; + break; + } + + if (rtlpriv->dm.undecorated_smoothed_pwdb > + (long)high_rssi_thresh) { + ra->ratr_state = DM_RATR_STA_HIGH; + } else if (rtlpriv->dm.undecorated_smoothed_pwdb > + (long)middle_rssi_thresh) { + ra->ratr_state = DM_RATR_STA_LOW; + } else if (rtlpriv->dm.undecorated_smoothed_pwdb > + (long)low_rssi_thresh) { + ra->ratr_state = DM_RATR_STA_LOW; + } else { + ra->ratr_state = DM_RATR_STA_ULTRALOW; + } + + if (ra->pre_ratr_state != ra->ratr_state) { + RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD, + "RSSI = %ld RSSI_LEVEL = %d PreState = %d, CurState = %d\n", + rtlpriv->dm.undecorated_smoothed_pwdb, + ra->ratr_state, + ra->pre_ratr_state, ra->ratr_state); + + rtlpriv->cfg->ops->update_rate_tbl(hw, sta, + ra->ratr_state); + ra->pre_ratr_state = ra->ratr_state; + } + } + rcu_read_unlock(); +} + +static void _rtl92s_dm_switch_baseband_mrc(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)); + bool current_mrc; + bool enable_mrc = true; + long tmpentry_maxpwdb = 0; + u8 rssi_a = 0; + u8 rssi_b = 0; + + if (is_hal_stop(rtlhal)) + return; + + if ((rtlphy->rf_type == RF_1T1R) || (rtlphy->rf_type == RF_2T2R)) + return; + + rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_MRC, (u8 *)(¤t_mrc)); + + if (mac->link_state >= MAC80211_LINKED) { + if (rtlpriv->dm.undecorated_smoothed_pwdb > tmpentry_maxpwdb) { + rssi_a = rtlpriv->stats.rx_rssi_percentage[RF90_PATH_A]; + rssi_b = rtlpriv->stats.rx_rssi_percentage[RF90_PATH_B]; + } + } + + /* MRC settings would NOT affect TP on Wireless B mode. */ + if (mac->mode != WIRELESS_MODE_B) { + if ((rssi_a == 0) && (rssi_b == 0)) { + enable_mrc = true; + } else if (rssi_b > 30) { + /* Turn on B-Path */ + enable_mrc = true; + } else if (rssi_b < 5) { + /* Turn off B-path */ + enable_mrc = false; + /* Take care of RSSI differentiation. */ + } else if (rssi_a > 15 && (rssi_a >= rssi_b)) { + if ((rssi_a - rssi_b) > 15) + /* Turn off B-path */ + enable_mrc = false; + else if ((rssi_a - rssi_b) < 10) + /* Turn on B-Path */ + enable_mrc = true; + else + enable_mrc = current_mrc; + } else { + /* Turn on B-Path */ + enable_mrc = true; + } + } + + /* Update MRC settings if needed. */ + if (enable_mrc != current_mrc) + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_MRC, + (u8 *)&enable_mrc); + +} + +void rtl92s_dm_init_edca_turbo(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtlpriv->dm.current_turbo_edca = false; + rtlpriv->dm.is_any_nonbepkts = false; + rtlpriv->dm.is_cur_rdlstate = false; +} + +static void _rtl92s_dm_init_rate_adaptive_mask(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rate_adaptive *ra = &(rtlpriv->ra); + + ra->ratr_state = DM_RATR_STA_MAX; + ra->pre_ratr_state = DM_RATR_STA_MAX; + + if (rtlpriv->dm.dm_type == DM_TYPE_BYDRIVER) + rtlpriv->dm.useramask = true; + else + rtlpriv->dm.useramask = false; + + rtlpriv->dm.useramask = false; + rtlpriv->dm.inform_fw_driverctrldm = false; +} + +static void _rtl92s_dm_init_txpowertracking_thermalmeter( + struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtlpriv->dm.txpower_tracking = true; + rtlpriv->dm.txpowercount = 0; + rtlpriv->dm.txpower_trackinginit = false; +} + +static void _rtl92s_dm_false_alarm_counter_statistics(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct false_alarm_statistics *falsealm_cnt = &(rtlpriv->falsealm_cnt); + u32 ret_value; + + ret_value = rtl_get_bbreg(hw, ROFDM_PHYCOUNTER1, MASKDWORD); + falsealm_cnt->cnt_parity_fail = ((ret_value & 0xffff0000) >> 16); + + ret_value = rtl_get_bbreg(hw, ROFDM_PHYCOUNTER2, MASKDWORD); + falsealm_cnt->cnt_rate_illegal = (ret_value & 0xffff); + falsealm_cnt->cnt_crc8_fail = ((ret_value & 0xffff0000) >> 16); + ret_value = rtl_get_bbreg(hw, ROFDM_PHYCOUNTER3, 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; + + /* read CCK false alarm */ + ret_value = rtl_get_bbreg(hw, 0xc64, MASKDWORD); + falsealm_cnt->cnt_cck_fail = (ret_value & 0xffff); + falsealm_cnt->cnt_all = falsealm_cnt->cnt_ofdm_fail + + falsealm_cnt->cnt_cck_fail; +} + +static void rtl92s_backoff_enable_flag(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct false_alarm_statistics *falsealm_cnt = &(rtlpriv->falsealm_cnt); + + if (falsealm_cnt->cnt_all > digtable.fa_highthresh) { + if ((digtable.backoff_val - 6) < + digtable.backoffval_range_min) + digtable.backoff_val = digtable.backoffval_range_min; + else + digtable.backoff_val -= 6; + } else if (falsealm_cnt->cnt_all < digtable.fa_lowthresh) { + if ((digtable.backoff_val + 6) > + digtable.backoffval_range_max) + digtable.backoff_val = + digtable.backoffval_range_max; + else + digtable.backoff_val += 6; + } +} + +static void _rtl92s_dm_initial_gain_sta_beforeconnect(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct false_alarm_statistics *falsealm_cnt = &(rtlpriv->falsealm_cnt); + static u8 initialized, force_write; + u8 initial_gain = 0; + + if ((digtable.pre_sta_connectstate == digtable.cur_sta_connectstate) || + (digtable.cur_sta_connectstate == DIG_STA_BEFORE_CONNECT)) { + if (digtable.cur_sta_connectstate == DIG_STA_BEFORE_CONNECT) { + if (rtlpriv->psc.rfpwr_state != ERFON) + return; + + if (digtable.backoff_enable_flag) + rtl92s_backoff_enable_flag(hw); + else + digtable.backoff_val = DM_DIG_BACKOFF; + + if ((digtable.rssi_val + 10 - digtable.backoff_val) > + digtable.rx_gain_range_max) + digtable.cur_igvalue = + digtable.rx_gain_range_max; + else if ((digtable.rssi_val + 10 - digtable.backoff_val) + < digtable.rx_gain_range_min) + digtable.cur_igvalue = + digtable.rx_gain_range_min; + else + digtable.cur_igvalue = digtable.rssi_val + 10 - + digtable.backoff_val; + + if (falsealm_cnt->cnt_all > 10000) + digtable.cur_igvalue = + (digtable.cur_igvalue > 0x33) ? + digtable.cur_igvalue : 0x33; + + if (falsealm_cnt->cnt_all > 16000) + digtable.cur_igvalue = + digtable.rx_gain_range_max; + /* connected -> connected or disconnected -> disconnected */ + } else { + /* Firmware control DIG, do nothing in driver dm */ + return; + } + /* disconnected -> connected or connected -> + * disconnected or beforeconnect->(dis)connected */ + } else { + /* Enable FW DIG */ + digtable.dig_ext_port_stage = DIG_EXT_PORT_STAGE_MAX; + rtl92s_phy_set_fw_cmd(hw, FW_CMD_DIG_ENABLE); + + digtable.backoff_val = DM_DIG_BACKOFF; + digtable.cur_igvalue = rtlpriv->phy.default_initialgain[0]; + digtable.pre_igvalue = 0; + return; + } + + /* Forced writing to prevent from fw-dig overwriting. */ + if (digtable.pre_igvalue != rtl_get_bbreg(hw, ROFDM0_XAAGCCORE1, + MASKBYTE0)) + force_write = 1; + + if ((digtable.pre_igvalue != digtable.cur_igvalue) || + !initialized || force_write) { + /* Disable FW DIG */ + rtl92s_phy_set_fw_cmd(hw, FW_CMD_DIG_DISABLE); + + initial_gain = (u8)digtable.cur_igvalue; + + /* Set initial gain. */ + rtl_set_bbreg(hw, ROFDM0_XAAGCCORE1, MASKBYTE0, initial_gain); + rtl_set_bbreg(hw, ROFDM0_XBAGCCORE1, MASKBYTE0, initial_gain); + digtable.pre_igvalue = digtable.cur_igvalue; + initialized = 1; + force_write = 0; + } +} + +static void _rtl92s_dm_ctrl_initgain_bytwoport(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + if (rtlpriv->mac80211.act_scanning) + return; + + /* Decide the current status and if modify initial gain or not */ + if (rtlpriv->mac80211.link_state >= MAC80211_LINKED || + rtlpriv->mac80211.opmode == NL80211_IFTYPE_ADHOC) + digtable.cur_sta_connectstate = DIG_STA_CONNECT; + else + digtable.cur_sta_connectstate = DIG_STA_DISCONNECT; + + digtable.rssi_val = rtlpriv->dm.undecorated_smoothed_pwdb; + + /* Change dig mode to rssi */ + if (digtable.cur_sta_connectstate != DIG_STA_DISCONNECT) { + if (digtable.dig_twoport_algorithm == + DIG_TWO_PORT_ALGO_FALSE_ALARM) { + digtable.dig_twoport_algorithm = DIG_TWO_PORT_ALGO_RSSI; + rtl92s_phy_set_fw_cmd(hw, FW_CMD_DIG_MODE_SS); + } + } + + _rtl92s_dm_false_alarm_counter_statistics(hw); + _rtl92s_dm_initial_gain_sta_beforeconnect(hw); + + digtable.pre_sta_connectstate = digtable.cur_sta_connectstate; +} + +static void _rtl92s_dm_ctrl_initgain_byrssi(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + + /* 2T2R TP issue */ + if (rtlphy->rf_type == RF_2T2R) + return; + + if (!rtlpriv->dm.dm_initialgain_enable) + return; + + if (digtable.dig_enable_flag == false) + return; + + _rtl92s_dm_ctrl_initgain_bytwoport(hw); +} + +static void _rtl92s_dm_dynamic_txpower(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + long undecorated_smoothed_pwdb; + long txpwr_threshold_lv1, txpwr_threshold_lv2; + + /* 2T2R TP issue */ + if (rtlphy->rf_type == RF_2T2R) + return; + + if (!rtlpriv->dm.dynamic_txpower_enable || + rtlpriv->dm.dm_flag & HAL_DM_HIPWR_DISABLE) { + rtlpriv->dm.dynamic_txhighpower_lvl = TX_HIGHPWR_LEVEL_NORMAL; + return; + } + + if ((mac->link_state < MAC80211_LINKED) && + (rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb == 0)) { + RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE, + "Not connected to any\n"); + + rtlpriv->dm.dynamic_txhighpower_lvl = TX_HIGHPWR_LEVEL_NORMAL; + + rtlpriv->dm.last_dtp_lvl = TX_HIGHPWR_LEVEL_NORMAL; + return; + } + + if (mac->link_state >= MAC80211_LINKED) { + if (mac->opmode == NL80211_IFTYPE_ADHOC) { + undecorated_smoothed_pwdb = + rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb; + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + "AP Client PWDB = 0x%lx\n", + undecorated_smoothed_pwdb); + } else { + undecorated_smoothed_pwdb = + rtlpriv->dm.undecorated_smoothed_pwdb; + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + "STA Default Port PWDB = 0x%lx\n", + undecorated_smoothed_pwdb); + } + } else { + undecorated_smoothed_pwdb = + rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb; + + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + "AP Ext Port PWDB = 0x%lx\n", + undecorated_smoothed_pwdb); + } + + txpwr_threshold_lv2 = TX_POWER_NEAR_FIELD_THRESH_LVL2; + txpwr_threshold_lv1 = TX_POWER_NEAR_FIELD_THRESH_LVL1; + + if (rtl_get_bbreg(hw, 0xc90, MASKBYTE0) == 1) + rtlpriv->dm.dynamic_txhighpower_lvl = TX_HIGHPWR_LEVEL_NORMAL; + else if (undecorated_smoothed_pwdb >= txpwr_threshold_lv2) + rtlpriv->dm.dynamic_txhighpower_lvl = TX_HIGHPWR_LEVEL_NORMAL2; + else if ((undecorated_smoothed_pwdb < (txpwr_threshold_lv2 - 3)) && + (undecorated_smoothed_pwdb >= txpwr_threshold_lv1)) + rtlpriv->dm.dynamic_txhighpower_lvl = TX_HIGHPWR_LEVEL_NORMAL1; + else if (undecorated_smoothed_pwdb < (txpwr_threshold_lv1 - 3)) + rtlpriv->dm.dynamic_txhighpower_lvl = TX_HIGHPWR_LEVEL_NORMAL; + + if ((rtlpriv->dm.dynamic_txhighpower_lvl != rtlpriv->dm.last_dtp_lvl)) + rtl92s_phy_set_txpower(hw, rtlphy->current_channel); + + rtlpriv->dm.last_dtp_lvl = rtlpriv->dm.dynamic_txhighpower_lvl; +} + +static void _rtl92s_dm_init_dig(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + /* Disable DIG scheme now.*/ + digtable.dig_enable_flag = true; + digtable.backoff_enable_flag = true; + + if ((rtlpriv->dm.dm_type == DM_TYPE_BYDRIVER) && + (hal_get_firmwareversion(rtlpriv) >= 0x3c)) + digtable.dig_algorithm = DIG_ALGO_BY_TOW_PORT; + else + digtable.dig_algorithm = + DIG_ALGO_BEFORE_CONNECT_BY_RSSI_AND_ALARM; + + digtable.dig_twoport_algorithm = DIG_TWO_PORT_ALGO_RSSI; + digtable.dig_ext_port_stage = DIG_EXT_PORT_STAGE_MAX; + /* off=by real rssi value, on=by digtable.rssi_val for new dig */ + digtable.dig_dbgmode = DM_DBG_OFF; + digtable.dig_slgorithm_switch = 0; + + /* 2007/10/04 MH Define init gain threshol. */ + digtable.dig_state = DM_STA_DIG_MAX; + digtable.dig_highpwrstate = DM_STA_DIG_MAX; + + digtable.cur_sta_connectstate = DIG_STA_DISCONNECT; + digtable.pre_sta_connectstate = DIG_STA_DISCONNECT; + digtable.cur_ap_connectstate = DIG_AP_DISCONNECT; + digtable.pre_ap_connectstate = DIG_AP_DISCONNECT; + + digtable.rssi_lowthresh = DM_DIG_THRESH_LOW; + digtable.rssi_highthresh = DM_DIG_THRESH_HIGH; + + digtable.fa_lowthresh = DM_FALSEALARM_THRESH_LOW; + digtable.fa_highthresh = DM_FALSEALARM_THRESH_HIGH; + + digtable.rssi_highpower_lowthresh = DM_DIG_HIGH_PWR_THRESH_LOW; + digtable.rssi_highpower_highthresh = DM_DIG_HIGH_PWR_THRESH_HIGH; + + /* for dig debug rssi value */ + digtable.rssi_val = 50; + digtable.backoff_val = DM_DIG_BACKOFF; + digtable.rx_gain_range_max = DM_DIG_MAX; + + digtable.rx_gain_range_min = DM_DIG_MIN; + + digtable.backoffval_range_max = DM_DIG_BACKOFF_MAX; + digtable.backoffval_range_min = DM_DIG_BACKOFF_MIN; +} + +static void _rtl92s_dm_init_dynamic_txpower(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + if ((hal_get_firmwareversion(rtlpriv) >= 60) && + (rtlpriv->dm.dm_type == DM_TYPE_BYDRIVER)) + rtlpriv->dm.dynamic_txpower_enable = true; + else + rtlpriv->dm.dynamic_txpower_enable = false; + + rtlpriv->dm.last_dtp_lvl = TX_HIGHPWR_LEVEL_NORMAL; + rtlpriv->dm.dynamic_txhighpower_lvl = TX_HIGHPWR_LEVEL_NORMAL; +} + +void rtl92s_dm_init(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtlpriv->dm.dm_type = DM_TYPE_BYDRIVER; + rtlpriv->dm.undecorated_smoothed_pwdb = -1; + + _rtl92s_dm_init_dynamic_txpower(hw); + rtl92s_dm_init_edca_turbo(hw); + _rtl92s_dm_init_rate_adaptive_mask(hw); + _rtl92s_dm_init_txpowertracking_thermalmeter(hw); + _rtl92s_dm_init_dig(hw); + + rtl_write_dword(rtlpriv, WFM5, FW_CCA_CHK_ENABLE); +} + +void rtl92s_dm_watchdog(struct ieee80211_hw *hw) +{ + _rtl92s_dm_check_edca_turbo(hw); + _rtl92s_dm_check_txpowertracking_thermalmeter(hw); + _rtl92s_dm_ctrl_initgain_byrssi(hw); + _rtl92s_dm_dynamic_txpower(hw); + _rtl92s_dm_refresh_rateadaptive_mask(hw); + _rtl92s_dm_switch_baseband_mrc(hw); +} + diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/dm.h b/drivers/net/wireless/rtlwifi/rtl8192se/dm.h new file mode 100644 index 00000000..e1b19a64 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192se/dm.h @@ -0,0 +1,164 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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 __RTL_92S_DM_H__ +#define __RTL_92S_DM_H__ + +struct dig_t { + u8 dig_enable_flag; + u8 dig_algorithm; + u8 dig_twoport_algorithm; + u8 dig_ext_port_stage; + u8 dig_dbgmode; + u8 dig_slgorithm_switch; + + long rssi_lowthresh; + long rssi_highthresh; + + u32 fa_lowthresh; + u32 fa_highthresh; + + long rssi_highpower_lowthresh; + long rssi_highpower_highthresh; + + u8 dig_state; + u8 dig_highpwrstate; + u8 cur_sta_connectstate; + u8 pre_sta_connectstate; + u8 cur_ap_connectstate; + u8 pre_ap_connectstate; + + u8 cur_pd_thstate; + u8 pre_pd_thstate; + u8 cur_cs_ratiostate; + u8 pre_cs_ratiostate; + + u32 pre_igvalue; + u32 cur_igvalue; + + u8 backoff_enable_flag; + char backoff_val; + char backoffval_range_max; + char backoffval_range_min; + u8 rx_gain_range_max; + u8 rx_gain_range_min; + + long rssi_val; +}; + +enum dm_dig_alg { + DIG_ALGO_BY_FALSE_ALARM = 0, + DIG_ALGO_BY_RSSI = 1, + DIG_ALGO_BEFORE_CONNECT_BY_RSSI_AND_ALARM = 2, + DIG_ALGO_BY_TOW_PORT = 3, + DIG_ALGO_MAX +}; + +enum dm_dig_two_port_alg { + DIG_TWO_PORT_ALGO_RSSI = 0, + DIG_TWO_PORT_ALGO_FALSE_ALARM = 1, +}; + +enum dm_dig_dbg { + DM_DBG_OFF = 0, + DM_DBG_ON = 1, + DM_DBG_MAX +}; + +enum dm_dig_sta { + DM_STA_DIG_OFF = 0, + DM_STA_DIG_ON, + DM_STA_DIG_MAX +}; + +enum dm_dig_connect { + DIG_STA_DISCONNECT = 0, + DIG_STA_CONNECT = 1, + DIG_STA_BEFORE_CONNECT = 2, + DIG_AP_DISCONNECT = 3, + DIG_AP_CONNECT = 4, + DIG_AP_ADD_STATION = 5, + DIG_CONNECT_MAX +}; + +enum dm_dig_ext_port_alg { + DIG_EXT_PORT_STAGE_0 = 0, + DIG_EXT_PORT_STAGE_1 = 1, + DIG_EXT_PORT_STAGE_2 = 2, + DIG_EXT_PORT_STAGE_3 = 3, + DIG_EXT_PORT_STAGE_MAX = 4, +}; + +enum dm_ratr_sta { + DM_RATR_STA_HIGH = 0, + DM_RATR_STA_MIDDLEHIGH = 1, + DM_RATR_STA_MIDDLE = 2, + DM_RATR_STA_MIDDLELOW = 3, + DM_RATR_STA_LOW = 4, + DM_RATR_STA_ULTRALOW = 5, + DM_RATR_STA_MAX +}; + +#define DM_TYPE_BYFW 0 +#define DM_TYPE_BYDRIVER 1 + +#define TX_HIGH_PWR_LEVEL_NORMAL 0 +#define TX_HIGH_PWR_LEVEL_LEVEL1 1 +#define TX_HIGH_PWR_LEVEL_LEVEL2 2 + +#define HAL_DM_DIG_DISABLE BIT(0) /* Disable Dig */ +#define HAL_DM_HIPWR_DISABLE BIT(1) /* Disable High Power */ + +#define TX_HIGHPWR_LEVEL_NORMAL 0 +#define TX_HIGHPWR_LEVEL_NORMAL1 1 +#define TX_HIGHPWR_LEVEL_NORMAL2 2 + +#define TX_POWER_NEAR_FIELD_THRESH_LVL2 74 +#define TX_POWER_NEAR_FIELD_THRESH_LVL1 67 + +#define DM_DIG_THRESH_HIGH 40 +#define DM_DIG_THRESH_LOW 35 +#define DM_FALSEALARM_THRESH_LOW 40 +#define DM_FALSEALARM_THRESH_HIGH 1000 +#define DM_DIG_HIGH_PWR_THRESH_HIGH 75 +#define DM_DIG_HIGH_PWR_THRESH_LOW 70 +#define DM_DIG_BACKOFF 12 +#define DM_DIG_MAX 0x3e +#define DM_DIG_MIN 0x1c +#define DM_DIG_MIN_Netcore 0x12 +#define DM_DIG_BACKOFF_MAX 12 +#define DM_DIG_BACKOFF_MIN -4 + +extern struct dig_t digtable; + +void rtl92s_dm_watchdog(struct ieee80211_hw *hw); +void rtl92s_dm_init(struct ieee80211_hw *hw); +void rtl92s_dm_init_edca_turbo(struct ieee80211_hw *hw); + +#endif + diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/fw.c b/drivers/net/wireless/rtlwifi/rtl8192se/fw.c new file mode 100644 index 00000000..380e7d4b --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192se/fw.c @@ -0,0 +1,656 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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> + * + *****************************************************************************/ + +#include "../wifi.h" +#include "../pci.h" +#include "../base.h" +#include "reg.h" +#include "def.h" +#include "fw.h" + +static void _rtl92s_fw_set_rqpn(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtl_write_dword(rtlpriv, RQPN, 0xffffffff); + rtl_write_dword(rtlpriv, RQPN + 4, 0xffffffff); + rtl_write_byte(rtlpriv, RQPN + 8, 0xff); + rtl_write_byte(rtlpriv, RQPN + 0xB, 0x80); +} + +static bool _rtl92s_firmware_enable_cpu(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 ichecktime = 200; + u16 tmpu2b; + u8 tmpu1b, cpustatus = 0; + + _rtl92s_fw_set_rqpn(hw); + + /* Enable CPU. */ + tmpu1b = rtl_read_byte(rtlpriv, SYS_CLKR); + /* AFE source */ + rtl_write_byte(rtlpriv, SYS_CLKR, (tmpu1b | SYS_CPU_CLKSEL)); + + tmpu2b = rtl_read_word(rtlpriv, REG_SYS_FUNC_EN); + rtl_write_word(rtlpriv, REG_SYS_FUNC_EN, (tmpu2b | FEN_CPUEN)); + + /* Polling IMEM Ready after CPU has refilled. */ + do { + cpustatus = rtl_read_byte(rtlpriv, TCR); + if (cpustatus & IMEM_RDY) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "IMEM Ready after CPU has refilled\n"); + break; + } + + udelay(100); + } while (ichecktime--); + + if (!(cpustatus & IMEM_RDY)) + return false; + + return true; +} + +static enum fw_status _rtl92s_firmware_get_nextstatus( + enum fw_status fw_currentstatus) +{ + enum fw_status next_fwstatus = 0; + + switch (fw_currentstatus) { + case FW_STATUS_INIT: + next_fwstatus = FW_STATUS_LOAD_IMEM; + break; + case FW_STATUS_LOAD_IMEM: + next_fwstatus = FW_STATUS_LOAD_EMEM; + break; + case FW_STATUS_LOAD_EMEM: + next_fwstatus = FW_STATUS_LOAD_DMEM; + break; + case FW_STATUS_LOAD_DMEM: + next_fwstatus = FW_STATUS_READY; + break; + default: + break; + } + + return next_fwstatus; +} + +static u8 _rtl92s_firmware_header_map_rftype(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + + switch (rtlphy->rf_type) { + case RF_1T1R: + return 0x11; + break; + case RF_1T2R: + return 0x12; + break; + case RF_2T2R: + return 0x22; + break; + default: + RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG, "Unknown RF type(%x)\n", + rtlphy->rf_type); + break; + } + return 0x22; +} + +static void _rtl92s_firmwareheader_priveupdate(struct ieee80211_hw *hw, + struct fw_priv *pfw_priv) +{ + /* Update RF types for RATR settings. */ + pfw_priv->rf_config = _rtl92s_firmware_header_map_rftype(hw); +} + + + +static bool _rtl92s_cmd_send_packet(struct ieee80211_hw *hw, + struct sk_buff *skb, u8 last) +{ + 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; + u8 idx = 0; + + ring = &rtlpci->tx_ring[TXCMD_QUEUE]; + + spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags); + + idx = (ring->idx + skb_queue_len(&ring->queue)) % ring->entries; + pdesc = &ring->desc[idx]; + 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; +} + +static bool _rtl92s_firmware_downloadcode(struct ieee80211_hw *hw, + u8 *code_virtual_address, u32 buffer_len) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct sk_buff *skb; + struct rtl_tcb_desc *tcb_desc; + unsigned char *seg_ptr; + u16 frag_threshold = MAX_FIRMWARE_CODE_SIZE; + u16 frag_length, frag_offset = 0; + u16 extra_descoffset = 0; + u8 last_inipkt = 0; + + _rtl92s_fw_set_rqpn(hw); + + if (buffer_len >= MAX_FIRMWARE_CODE_SIZE) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "Size over FIRMWARE_CODE_SIZE!\n"); + + return false; + } + + extra_descoffset = 0; + + do { + if ((buffer_len - frag_offset) > frag_threshold) { + frag_length = frag_threshold + extra_descoffset; + } else { + frag_length = (u16)(buffer_len - frag_offset + + extra_descoffset); + last_inipkt = 1; + } + + /* Allocate skb buffer to contain firmware */ + /* info and tx descriptor info. */ + skb = dev_alloc_skb(frag_length); + if (!skb) + return false; + skb_reserve(skb, extra_descoffset); + seg_ptr = (u8 *)skb_put(skb, (u32)(frag_length - + extra_descoffset)); + memcpy(seg_ptr, code_virtual_address + frag_offset, + (u32)(frag_length - extra_descoffset)); + + tcb_desc = (struct rtl_tcb_desc *)(skb->cb); + tcb_desc->queue_index = TXCMD_QUEUE; + tcb_desc->cmd_or_init = DESC_PACKET_TYPE_INIT; + tcb_desc->last_inipkt = last_inipkt; + + _rtl92s_cmd_send_packet(hw, skb, last_inipkt); + + frag_offset += (frag_length - extra_descoffset); + + } while (frag_offset < buffer_len); + + rtl_write_byte(rtlpriv, TP_POLL, TPPOLL_CQ); + + return true ; +} + +static bool _rtl92s_firmware_checkready(struct ieee80211_hw *hw, + u8 loadfw_status) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rt_firmware *firmware = (struct rt_firmware *)rtlhal->pfirmware; + u32 tmpu4b; + u8 cpustatus = 0; + short pollingcnt = 1000; + bool rtstatus = true; + + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "LoadStaus(%d)\n", loadfw_status); + + firmware->fwstatus = (enum fw_status)loadfw_status; + + switch (loadfw_status) { + case FW_STATUS_LOAD_IMEM: + /* Polling IMEM code done. */ + do { + cpustatus = rtl_read_byte(rtlpriv, TCR); + if (cpustatus & IMEM_CODE_DONE) + break; + udelay(5); + } while (pollingcnt--); + + if (!(cpustatus & IMEM_CHK_RPT) || (pollingcnt <= 0)) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "FW_STATUS_LOAD_IMEM FAIL CPU, Status=%x\n", + cpustatus); + goto status_check_fail; + } + break; + + case FW_STATUS_LOAD_EMEM: + /* Check Put Code OK and Turn On CPU */ + /* Polling EMEM code done. */ + do { + cpustatus = rtl_read_byte(rtlpriv, TCR); + if (cpustatus & EMEM_CODE_DONE) + break; + udelay(5); + } while (pollingcnt--); + + if (!(cpustatus & EMEM_CHK_RPT) || (pollingcnt <= 0)) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "FW_STATUS_LOAD_EMEM FAIL CPU, Status=%x\n", + cpustatus); + goto status_check_fail; + } + + /* Turn On CPU */ + rtstatus = _rtl92s_firmware_enable_cpu(hw); + if (!rtstatus) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "Enable CPU fail!\n"); + goto status_check_fail; + } + break; + + case FW_STATUS_LOAD_DMEM: + /* Polling DMEM code done */ + do { + cpustatus = rtl_read_byte(rtlpriv, TCR); + if (cpustatus & DMEM_CODE_DONE) + break; + udelay(5); + } while (pollingcnt--); + + if (!(cpustatus & DMEM_CODE_DONE) || (pollingcnt <= 0)) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "Polling DMEM code done fail ! cpustatus(%#x)\n", + cpustatus); + goto status_check_fail; + } + + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "DMEM code download success, cpustatus(%#x)\n", + cpustatus); + + /* Prevent Delay too much and being scheduled out */ + /* Polling Load Firmware ready */ + pollingcnt = 2000; + do { + cpustatus = rtl_read_byte(rtlpriv, TCR); + if (cpustatus & FWRDY) + break; + udelay(40); + } while (pollingcnt--); + + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "Polling Load Firmware ready, cpustatus(%x)\n", + cpustatus); + + if (((cpustatus & LOAD_FW_READY) != LOAD_FW_READY) || + (pollingcnt <= 0)) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "Polling Load Firmware ready fail ! cpustatus(%x)\n", + cpustatus); + goto status_check_fail; + } + + /* If right here, we can set TCR/RCR to desired value */ + /* and config MAC lookback mode to normal mode */ + tmpu4b = rtl_read_dword(rtlpriv, TCR); + rtl_write_dword(rtlpriv, TCR, (tmpu4b & (~TCR_ICV))); + + tmpu4b = rtl_read_dword(rtlpriv, RCR); + rtl_write_dword(rtlpriv, RCR, (tmpu4b | RCR_APPFCS | + RCR_APP_ICV | RCR_APP_MIC)); + + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "Current RCR settings(%#x)\n", tmpu4b); + + /* Set to normal mode. */ + rtl_write_byte(rtlpriv, LBKMD_SEL, LBK_NORMAL); + break; + + default: + RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG, + "Unknown status check!\n"); + rtstatus = false; + break; + } + +status_check_fail: + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "loadfw_status(%d), rtstatus(%x)\n", + loadfw_status, rtstatus); + return rtstatus; +} + +int rtl92s_download_fw(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rt_firmware *firmware = NULL; + struct fw_hdr *pfwheader; + struct fw_priv *pfw_priv = NULL; + u8 *puc_mappedfile = NULL; + u32 ul_filelength = 0; + u8 fwhdr_size = RT_8192S_FIRMWARE_HDR_SIZE; + u8 fwstatus = FW_STATUS_INIT; + bool rtstatus = true; + + if (rtlpriv->max_fw_size == 0 || !rtlhal->pfirmware) + return 1; + + firmware = (struct rt_firmware *)rtlhal->pfirmware; + firmware->fwstatus = FW_STATUS_INIT; + + puc_mappedfile = firmware->sz_fw_tmpbuffer; + + /* 1. Retrieve FW header. */ + firmware->pfwheader = (struct fw_hdr *) puc_mappedfile; + pfwheader = firmware->pfwheader; + firmware->firmwareversion = byte(pfwheader->version, 0); + firmware->pfwheader->fwpriv.hci_sel = 1;/* pcie */ + + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "signature:%x, version:%x, size:%x, imemsize:%x, sram size:%x\n", + pfwheader->signature, + pfwheader->version, pfwheader->dmem_size, + pfwheader->img_imem_size, pfwheader->img_sram_size); + + /* 2. Retrieve IMEM image. */ + if ((pfwheader->img_imem_size == 0) || (pfwheader->img_imem_size > + sizeof(firmware->fw_imem))) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "memory for data image is less than IMEM required\n"); + goto fail; + } else { + puc_mappedfile += fwhdr_size; + + memcpy(firmware->fw_imem, puc_mappedfile, + pfwheader->img_imem_size); + firmware->fw_imem_len = pfwheader->img_imem_size; + } + + /* 3. Retriecve EMEM image. */ + if (pfwheader->img_sram_size > sizeof(firmware->fw_emem)) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "memory for data image is less than EMEM required\n"); + goto fail; + } else { + puc_mappedfile += firmware->fw_imem_len; + + memcpy(firmware->fw_emem, puc_mappedfile, + pfwheader->img_sram_size); + firmware->fw_emem_len = pfwheader->img_sram_size; + } + + /* 4. download fw now */ + fwstatus = _rtl92s_firmware_get_nextstatus(firmware->fwstatus); + while (fwstatus != FW_STATUS_READY) { + /* Image buffer redirection. */ + switch (fwstatus) { + case FW_STATUS_LOAD_IMEM: + puc_mappedfile = firmware->fw_imem; + ul_filelength = firmware->fw_imem_len; + break; + case FW_STATUS_LOAD_EMEM: + puc_mappedfile = firmware->fw_emem; + ul_filelength = firmware->fw_emem_len; + break; + case FW_STATUS_LOAD_DMEM: + /* Partial update the content of header private. */ + pfwheader = firmware->pfwheader; + pfw_priv = &pfwheader->fwpriv; + _rtl92s_firmwareheader_priveupdate(hw, pfw_priv); + puc_mappedfile = (u8 *)(firmware->pfwheader) + + RT_8192S_FIRMWARE_HDR_EXCLUDE_PRI_SIZE; + ul_filelength = fwhdr_size - + RT_8192S_FIRMWARE_HDR_EXCLUDE_PRI_SIZE; + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "Unexpected Download step!!\n"); + goto fail; + break; + } + + /* <2> Download image file */ + rtstatus = _rtl92s_firmware_downloadcode(hw, puc_mappedfile, + ul_filelength); + + if (!rtstatus) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "fail!\n"); + goto fail; + } + + /* <3> Check whether load FW process is ready */ + rtstatus = _rtl92s_firmware_checkready(hw, fwstatus); + if (!rtstatus) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "fail!\n"); + goto fail; + } + + fwstatus = _rtl92s_firmware_get_nextstatus(firmware->fwstatus); + } + + return rtstatus; +fail: + return 0; +} + +static u32 _rtl92s_fill_h2c_cmd(struct sk_buff *skb, u32 h2cbufferlen, + u32 cmd_num, u32 *pelement_id, u32 *pcmd_len, + u8 **pcmb_buffer, u8 *cmd_start_seq) +{ + u32 totallen = 0, len = 0, tx_desclen = 0; + u32 pre_continueoffset = 0; + u8 *ph2c_buffer; + u8 i = 0; + + do { + /* 8 - Byte aligment */ + len = H2C_TX_CMD_HDR_LEN + N_BYTE_ALIGMENT(pcmd_len[i], 8); + + /* Buffer length is not enough */ + if (h2cbufferlen < totallen + len + tx_desclen) + break; + + /* Clear content */ + ph2c_buffer = (u8 *)skb_put(skb, (u32)len); + memset((ph2c_buffer + totallen + tx_desclen), 0, len); + + /* CMD len */ + SET_BITS_TO_LE_4BYTE((ph2c_buffer + totallen + tx_desclen), + 0, 16, pcmd_len[i]); + + /* CMD ID */ + SET_BITS_TO_LE_4BYTE((ph2c_buffer + totallen + tx_desclen), + 16, 8, pelement_id[i]); + + /* CMD Sequence */ + *cmd_start_seq = *cmd_start_seq % 0x80; + SET_BITS_TO_LE_4BYTE((ph2c_buffer + totallen + tx_desclen), + 24, 7, *cmd_start_seq); + ++*cmd_start_seq; + + /* Copy memory */ + memcpy((ph2c_buffer + totallen + tx_desclen + + H2C_TX_CMD_HDR_LEN), pcmb_buffer[i], pcmd_len[i]); + + /* CMD continue */ + /* set the continue in prevoius cmd. */ + if (i < cmd_num - 1) + SET_BITS_TO_LE_4BYTE((ph2c_buffer + pre_continueoffset), + 31, 1, 1); + + pre_continueoffset = totallen; + + totallen += len; + } while (++i < cmd_num); + + return totallen; +} + +static u32 _rtl92s_get_h2c_cmdlen(u32 h2cbufferlen, u32 cmd_num, u32 *pcmd_len) +{ + u32 totallen = 0, len = 0, tx_desclen = 0; + u8 i = 0; + + do { + /* 8 - Byte aligment */ + len = H2C_TX_CMD_HDR_LEN + N_BYTE_ALIGMENT(pcmd_len[i], 8); + + /* Buffer length is not enough */ + if (h2cbufferlen < totallen + len + tx_desclen) + break; + + totallen += len; + } while (++i < cmd_num); + + return totallen + tx_desclen; +} + +static bool _rtl92s_firmware_set_h2c_cmd(struct ieee80211_hw *hw, u8 h2c_cmd, + u8 *pcmd_buffer) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_tcb_desc *cb_desc; + struct sk_buff *skb; + u32 element_id = 0; + u32 cmd_len = 0; + u32 len; + + switch (h2c_cmd) { + case FW_H2C_SETPWRMODE: + element_id = H2C_SETPWRMODE_CMD ; + cmd_len = sizeof(struct h2c_set_pwrmode_parm); + break; + case FW_H2C_JOINBSSRPT: + element_id = H2C_JOINBSSRPT_CMD; + cmd_len = sizeof(struct h2c_joinbss_rpt_parm); + break; + case FW_H2C_WOWLAN_UPDATE_GTK: + element_id = H2C_WOWLAN_UPDATE_GTK_CMD; + cmd_len = sizeof(struct h2c_wpa_two_way_parm); + break; + case FW_H2C_WOWLAN_UPDATE_IV: + element_id = H2C_WOWLAN_UPDATE_IV_CMD; + cmd_len = sizeof(unsigned long long); + break; + case FW_H2C_WOWLAN_OFFLOAD: + element_id = H2C_WOWLAN_FW_OFFLOAD; + cmd_len = sizeof(u8); + break; + default: + break; + } + + len = _rtl92s_get_h2c_cmdlen(MAX_TRANSMIT_BUFFER_SIZE, 1, &cmd_len); + skb = dev_alloc_skb(len); + if (!skb) + return false; + cb_desc = (struct rtl_tcb_desc *)(skb->cb); + cb_desc->queue_index = TXCMD_QUEUE; + cb_desc->cmd_or_init = DESC_PACKET_TYPE_NORMAL; + cb_desc->last_inipkt = false; + + _rtl92s_fill_h2c_cmd(skb, MAX_TRANSMIT_BUFFER_SIZE, 1, &element_id, + &cmd_len, &pcmd_buffer, &rtlhal->h2c_txcmd_seq); + _rtl92s_cmd_send_packet(hw, skb, false); + rtlpriv->cfg->ops->tx_polling(hw, TXCMD_QUEUE); + + return true; +} + +void rtl92s_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 Mode) +{ + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + struct h2c_set_pwrmode_parm pwrmode; + u16 max_wakeup_period = 0; + + pwrmode.mode = Mode; + pwrmode.flag_low_traffic_en = 0; + pwrmode.flag_lpnav_en = 0; + pwrmode.flag_rf_low_snr_en = 0; + pwrmode.flag_dps_en = 0; + pwrmode.bcn_rx_en = 0; + pwrmode.bcn_to = 0; + SET_BITS_TO_LE_2BYTE((u8 *)(&pwrmode) + 8, 0, 16, + mac->vif->bss_conf.beacon_int); + pwrmode.app_itv = 0; + pwrmode.awake_bcn_itvl = ppsc->reg_max_lps_awakeintvl; + pwrmode.smart_ps = 1; + pwrmode.bcn_pass_period = 10; + + /* Set beacon pass count */ + if (pwrmode.mode == FW_PS_MIN_MODE) + max_wakeup_period = mac->vif->bss_conf.beacon_int; + else if (pwrmode.mode == FW_PS_MAX_MODE) + max_wakeup_period = mac->vif->bss_conf.beacon_int * + mac->vif->bss_conf.dtim_period; + + if (max_wakeup_period >= 500) + pwrmode.bcn_pass_cnt = 1; + else if ((max_wakeup_period >= 300) && (max_wakeup_period < 500)) + pwrmode.bcn_pass_cnt = 2; + else if ((max_wakeup_period >= 200) && (max_wakeup_period < 300)) + pwrmode.bcn_pass_cnt = 3; + else if ((max_wakeup_period >= 20) && (max_wakeup_period < 200)) + pwrmode.bcn_pass_cnt = 5; + else + pwrmode.bcn_pass_cnt = 1; + + _rtl92s_firmware_set_h2c_cmd(hw, FW_H2C_SETPWRMODE, (u8 *)&pwrmode); + +} + +void rtl92s_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, + u8 mstatus, u8 ps_qosinfo) +{ + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct h2c_joinbss_rpt_parm joinbss_rpt; + + joinbss_rpt.opmode = mstatus; + joinbss_rpt.ps_qos_info = ps_qosinfo; + joinbss_rpt.bssid[0] = mac->bssid[0]; + joinbss_rpt.bssid[1] = mac->bssid[1]; + joinbss_rpt.bssid[2] = mac->bssid[2]; + joinbss_rpt.bssid[3] = mac->bssid[3]; + joinbss_rpt.bssid[4] = mac->bssid[4]; + joinbss_rpt.bssid[5] = mac->bssid[5]; + SET_BITS_TO_LE_2BYTE((u8 *)(&joinbss_rpt) + 8, 0, 16, + mac->vif->bss_conf.beacon_int); + SET_BITS_TO_LE_2BYTE((u8 *)(&joinbss_rpt) + 10, 0, 16, mac->assoc_id); + + _rtl92s_firmware_set_h2c_cmd(hw, FW_H2C_JOINBSSRPT, (u8 *)&joinbss_rpt); +} + diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/fw.h b/drivers/net/wireless/rtlwifi/rtl8192se/fw.h new file mode 100644 index 00000000..b4afff62 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192se/fw.h @@ -0,0 +1,376 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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 __REALTEK_FIRMWARE92S_H__ +#define __REALTEK_FIRMWARE92S_H__ + +#define RTL8190_MAX_FIRMWARE_CODE_SIZE 64000 +#define RTL8190_MAX_RAW_FIRMWARE_CODE_SIZE 90000 +#define RTL8190_CPU_START_OFFSET 0x80 +/* Firmware Local buffer size. 64k */ +#define MAX_FIRMWARE_CODE_SIZE 0xFF00 + +#define RT_8192S_FIRMWARE_HDR_SIZE 80 +#define RT_8192S_FIRMWARE_HDR_EXCLUDE_PRI_SIZE 32 + +/* support till 64 bit bus width OS */ +#define MAX_DEV_ADDR_SIZE 8 +#define MAX_FIRMWARE_INFORMATION_SIZE 32 +#define MAX_802_11_HEADER_LENGTH (40 + \ + MAX_FIRMWARE_INFORMATION_SIZE) +#define ENCRYPTION_MAX_OVERHEAD 128 +#define MAX_FRAGMENT_COUNT 8 +#define MAX_TRANSMIT_BUFFER_SIZE (1600 + \ + (MAX_802_11_HEADER_LENGTH + \ + ENCRYPTION_MAX_OVERHEAD) *\ + MAX_FRAGMENT_COUNT) + +#define H2C_TX_CMD_HDR_LEN 8 + +/* The following DM control code are for Reg0x364, */ +#define FW_DIG_ENABLE_CTL BIT(0) +#define FW_HIGH_PWR_ENABLE_CTL BIT(1) +#define FW_SS_CTL BIT(2) +#define FW_RA_INIT_CTL BIT(3) +#define FW_RA_BG_CTL BIT(4) +#define FW_RA_N_CTL BIT(5) +#define FW_PWR_TRK_CTL BIT(6) +#define FW_IQK_CTL BIT(7) +#define FW_FA_CTL BIT(8) +#define FW_DRIVER_CTRL_DM_CTL BIT(9) +#define FW_PAPE_CTL_BY_SW_HW BIT(10) +#define FW_DISABLE_ALL_DM 0 +#define FW_PWR_TRK_PARAM_CLR 0x0000ffff +#define FW_RA_PARAM_CLR 0xffff0000 + +enum desc_packet_type { + DESC_PACKET_TYPE_INIT = 0, + DESC_PACKET_TYPE_NORMAL = 1, +}; + +/* 8-bytes alignment required */ +struct fw_priv { + /* --- long word 0 ---- */ + /* 0x12: CE product, 0x92: IT product */ + u8 signature_0; + /* 0x87: CE product, 0x81: IT product */ + u8 signature_1; + /* 0x81: PCI-AP, 01:PCIe, 02: 92S-U, + * 0x82: USB-AP, 0x12: 72S-U, 03:SDIO */ + u8 hci_sel; + /* the same value as reigster value */ + u8 chip_version; + /* customer ID low byte */ + u8 customer_id_0; + /* customer ID high byte */ + u8 customer_id_1; + /* 0x11: 1T1R, 0x12: 1T2R, + * 0x92: 1T2R turbo, 0x22: 2T2R */ + u8 rf_config; + /* 4: 4EP, 6: 6EP, 11: 11EP */ + u8 usb_ep_num; + + /* --- long word 1 ---- */ + /* regulatory class bit map 0 */ + u8 regulatory_class_0; + /* regulatory class bit map 1 */ + u8 regulatory_class_1; + /* regulatory class bit map 2 */ + u8 regulatory_class_2; + /* regulatory class bit map 3 */ + u8 regulatory_class_3; + /* 0:SWSI, 1:HWSI, 2:HWPI */ + u8 rfintfs; + u8 def_nettype; + u8 rsvd010; + u8 rsvd011; + + /* --- long word 2 ---- */ + /* 0x00: normal, 0x03: MACLBK, 0x01: PHYLBK */ + u8 lbk_mode; + /* 1: for MP use, 0: for normal + * driver (to be discussed) */ + u8 mp_mode; + u8 rsvd020; + u8 rsvd021; + u8 rsvd022; + u8 rsvd023; + u8 rsvd024; + u8 rsvd025; + + /* --- long word 3 ---- */ + /* QoS enable */ + u8 qos_en; + /* 40MHz BW enable */ + /* 4181 convert AMSDU to AMPDU, 0: disable */ + u8 bw_40mhz_en; + u8 amsdu2ampdu_en; + /* 11n AMPDU enable */ + u8 ampdu_en; + /* FW offloads, 0: driver handles */ + u8 rate_control_offload; + /* FW offloads, 0: driver handles */ + u8 aggregation_offload; + u8 rsvd030; + u8 rsvd031; + + /* --- long word 4 ---- */ + /* 1. FW offloads, 0: driver handles */ + u8 beacon_offload; + /* 2. FW offloads, 0: driver handles */ + u8 mlme_offload; + /* 3. FW offloads, 0: driver handles */ + u8 hwpc_offload; + /* 4. FW offloads, 0: driver handles */ + u8 tcp_checksum_offload; + /* 5. FW offloads, 0: driver handles */ + u8 tcp_offload; + /* 6. FW offloads, 0: driver handles */ + u8 ps_control_offload; + /* 7. FW offloads, 0: driver handles */ + u8 wwlan_offload; + u8 rsvd040; + + /* --- long word 5 ---- */ + /* tcp tx packet length low byte */ + u8 tcp_tx_frame_len_L; + /* tcp tx packet length high byte */ + u8 tcp_tx_frame_len_H; + /* tcp rx packet length low byte */ + u8 tcp_rx_frame_len_L; + /* tcp rx packet length high byte */ + u8 tcp_rx_frame_len_H; + u8 rsvd050; + u8 rsvd051; + u8 rsvd052; + u8 rsvd053; +}; + +/* 8-byte alinment required */ +struct fw_hdr { + + /* --- LONG WORD 0 ---- */ + u16 signature; + /* 0x8000 ~ 0x8FFF for FPGA version, + * 0x0000 ~ 0x7FFF for ASIC version, */ + u16 version; + /* define the size of boot loader */ + u32 dmem_size; + + + /* --- LONG WORD 1 ---- */ + /* define the size of FW in IMEM */ + u32 img_imem_size; + /* define the size of FW in SRAM */ + u32 img_sram_size; + + /* --- LONG WORD 2 ---- */ + /* define the size of DMEM variable */ + u32 fw_priv_size; + u32 rsvd0; + + /* --- LONG WORD 3 ---- */ + u32 rsvd1; + u32 rsvd2; + + struct fw_priv fwpriv; + +} ; + +enum fw_status { + FW_STATUS_INIT = 0, + FW_STATUS_LOAD_IMEM = 1, + FW_STATUS_LOAD_EMEM = 2, + FW_STATUS_LOAD_DMEM = 3, + FW_STATUS_READY = 4, +}; + +struct rt_firmware { + struct fw_hdr *pfwheader; + enum fw_status fwstatus; + u16 firmwareversion; + u8 fw_imem[RTL8190_MAX_FIRMWARE_CODE_SIZE]; + u8 fw_emem[RTL8190_MAX_FIRMWARE_CODE_SIZE]; + u32 fw_imem_len; + u32 fw_emem_len; + u8 sz_fw_tmpbuffer[RTL8190_MAX_RAW_FIRMWARE_CODE_SIZE]; + u32 sz_fw_tmpbufferlen; + u16 cmdpacket_fragthresold; +}; + +struct h2c_set_pwrmode_parm { + u8 mode; + u8 flag_low_traffic_en; + u8 flag_lpnav_en; + u8 flag_rf_low_snr_en; + /* 1: dps, 0: 32k */ + u8 flag_dps_en; + u8 bcn_rx_en; + u8 bcn_pass_cnt; + /* beacon TO (ms). ¡§=0¡¨ no limit. */ + u8 bcn_to; + u16 bcn_itv; + /* only for VOIP mode. */ + u8 app_itv; + u8 awake_bcn_itvl; + u8 smart_ps; + /* unit: 100 ms */ + u8 bcn_pass_period; +}; + +struct h2c_joinbss_rpt_parm { + u8 opmode; + u8 ps_qos_info; + u8 bssid[6]; + u16 bcnitv; + u16 aid; +} ; + +struct h2c_wpa_ptk { + /* EAPOL-Key Key Confirmation Key (KCK) */ + u8 kck[16]; + /* EAPOL-Key Key Encryption Key (KEK) */ + u8 kek[16]; + /* Temporal Key 1 (TK1) */ + u8 tk1[16]; + union { + /* Temporal Key 2 (TK2) */ + u8 tk2[16]; + struct { + u8 tx_mic_key[8]; + u8 rx_mic_key[8]; + } athu; + } u; +}; + +struct h2c_wpa_two_way_parm { + /* algorithm TKIP or AES */ + u8 pairwise_en_alg; + u8 group_en_alg; + struct h2c_wpa_ptk wpa_ptk_value; +} ; + +enum h2c_cmd { + FW_H2C_SETPWRMODE = 0, + FW_H2C_JOINBSSRPT = 1, + FW_H2C_WOWLAN_UPDATE_GTK = 2, + FW_H2C_WOWLAN_UPDATE_IV = 3, + FW_H2C_WOWLAN_OFFLOAD = 4, +}; + +enum fw_h2c_cmd { + H2C_READ_MACREG_CMD, /*0*/ + H2C_WRITE_MACREG_CMD, + H2C_READBB_CMD, + H2C_WRITEBB_CMD, + H2C_READRF_CMD, + H2C_WRITERF_CMD, /*5*/ + H2C_READ_EEPROM_CMD, + H2C_WRITE_EEPROM_CMD, + H2C_READ_EFUSE_CMD, + H2C_WRITE_EFUSE_CMD, + H2C_READ_CAM_CMD, /*10*/ + H2C_WRITE_CAM_CMD, + H2C_SETBCNITV_CMD, + H2C_SETMBIDCFG_CMD, + H2C_JOINBSS_CMD, + H2C_DISCONNECT_CMD, /*15*/ + H2C_CREATEBSS_CMD, + H2C_SETOPMode_CMD, + H2C_SITESURVEY_CMD, + H2C_SETAUTH_CMD, + H2C_SETKEY_CMD, /*20*/ + H2C_SETSTAKEY_CMD, + H2C_SETASSOCSTA_CMD, + H2C_DELASSOCSTA_CMD, + H2C_SETSTAPWRSTATE_CMD, + H2C_SETBASICRATE_CMD, /*25*/ + H2C_GETBASICRATE_CMD, + H2C_SETDATARATE_CMD, + H2C_GETDATARATE_CMD, + H2C_SETPHYINFO_CMD, + H2C_GETPHYINFO_CMD, /*30*/ + H2C_SETPHY_CMD, + H2C_GETPHY_CMD, + H2C_READRSSI_CMD, + H2C_READGAIN_CMD, + H2C_SETATIM_CMD, /*35*/ + H2C_SETPWRMODE_CMD, + H2C_JOINBSSRPT_CMD, + H2C_SETRATABLE_CMD, + H2C_GETRATABLE_CMD, + H2C_GETCCXREPORT_CMD, /*40*/ + H2C_GETDTMREPORT_CMD, + H2C_GETTXRATESTATICS_CMD, + H2C_SETUSBSUSPEND_CMD, + H2C_SETH2CLBK_CMD, + H2C_TMP1, /*45*/ + H2C_WOWLAN_UPDATE_GTK_CMD, + H2C_WOWLAN_FW_OFFLOAD, + H2C_TMP2, + H2C_TMP3, + H2C_WOWLAN_UPDATE_IV_CMD, /*50*/ + H2C_TMP4, + MAX_H2CCMD /*52*/ +}; + +/* The following macros are used for FW + * CMD map and parameter updated. */ +#define FW_CMD_IO_CLR(rtlpriv, _Bit) \ + do { \ + udelay(1000); \ + rtlpriv->rtlhal.fwcmd_iomap &= (~_Bit); \ + } while (0); + +#define FW_CMD_IO_UPDATE(rtlpriv, _val) \ + rtlpriv->rtlhal.fwcmd_iomap = _val; + +#define FW_CMD_IO_SET(rtlpriv, _val) \ + do { \ + rtl_write_word(rtlpriv, LBUS_MON_ADDR, (u16)_val); \ + FW_CMD_IO_UPDATE(rtlpriv, _val); \ + } while (0); + +#define FW_CMD_PARA_SET(rtlpriv, _val) \ + do { \ + rtl_write_dword(rtlpriv, LBUS_ADDR_MASK, _val); \ + rtlpriv->rtlhal.fwcmd_ioparam = _val; \ + } while (0); + +#define FW_CMD_IO_QUERY(rtlpriv) \ + (u16)(rtlpriv->rtlhal.fwcmd_iomap) +#define FW_CMD_IO_PARA_QUERY(rtlpriv) \ + ((u32)(rtlpriv->rtlhal.fwcmd_ioparam)) + +int rtl92s_download_fw(struct ieee80211_hw *hw); +void rtl92s_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode); +void rtl92s_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, + u8 mstatus, u8 ps_qosinfo); + +#endif + diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/hw.c b/drivers/net/wireless/rtlwifi/rtl8192se/hw.c new file mode 100644 index 00000000..b141c35b --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192se/hw.c @@ -0,0 +1,2506 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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> + * + *****************************************************************************/ + +#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" + +void rtl92se_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_FW_PSMODE_STATUS: { + *((bool *) (val)) = ppsc->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, (TSFR + 4)); + *ptsf_low = rtl_read_dword(rtlpriv, TSFR); + + *((u64 *) (val)) = tsf; + + break; + } + case HW_VAR_MRC: { + *((bool *)(val)) = rtlpriv->dm.current_mrc_switch; + break; + } + default: { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "switch case not processed\n"); + break; + } + } +} + +void rtl92se_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_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + + switch (variable) { + case HW_VAR_ETHER_ADDR:{ + rtl_write_dword(rtlpriv, IDR0, ((u32 *)(val))[0]); + rtl_write_word(rtlpriv, IDR4, ((u16 *)(val + 4))[0]); + break; + } + case HW_VAR_BASIC_RATE:{ + u16 rate_cfg = ((u16 *) val)[0]; + u8 rate_index = 0; + + if (rtlhal->version == VERSION_8192S_ACUT) + rate_cfg = rate_cfg & 0x150; + else + rate_cfg = rate_cfg & 0x15f; + + rate_cfg |= 0x01; + + rtl_write_byte(rtlpriv, RRSR, rate_cfg & 0xff); + rtl_write_byte(rtlpriv, RRSR + 1, + (rate_cfg >> 8) & 0xff); + + while (rate_cfg > 0x1) { + rate_cfg = (rate_cfg >> 1); + rate_index++; + } + rtl_write_byte(rtlpriv, INIRTSMCS_SEL, rate_index); + + break; + } + case HW_VAR_BSSID:{ + rtl_write_dword(rtlpriv, BSSIDR, ((u32 *)(val))[0]); + rtl_write_word(rtlpriv, BSSIDR + 4, + ((u16 *)(val + 4))[0]); + break; + } + case HW_VAR_SIFS:{ + rtl_write_byte(rtlpriv, SIFS_OFDM, val[0]); + rtl_write_byte(rtlpriv, SIFS_OFDM + 1, val[1]); + break; + } + case HW_VAR_SLOT_TIME:{ + u8 e_aci; + + RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD, + "HW_VAR_SLOT_TIME %x\n", val[0]); + + rtl_write_byte(rtlpriv, SLOT_TIME, 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 = (mac->cur_40_prime_sc) << 5; + if (short_preamble) + reg_tmp |= 0x80; + + rtl_write_byte(rtlpriv, RRSR + 2, reg_tmp); + break; + } + case HW_VAR_AMPDU_MIN_SPACE:{ + u8 min_spacing_to_set; + u8 sec_min_space; + + min_spacing_to_set = *((u8 *)val); + if (min_spacing_to_set <= 7) { + if (rtlpriv->sec.pairwise_enc_algorithm == + NO_ENCRYPTION) + sec_min_space = 0; + else + sec_min_space = 1; + + if (min_spacing_to_set < sec_min_space) + min_spacing_to_set = sec_min_space; + if (min_spacing_to_set > 5) + min_spacing_to_set = 5; + + mac->min_space_cfg = + ((mac->min_space_cfg & 0xf8) | + min_spacing_to_set); + + *val = min_spacing_to_set; + + RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD, + "Set HW_VAR_AMPDU_MIN_SPACE: %#x\n", + mac->min_space_cfg); + + rtl_write_byte(rtlpriv, AMPDU_MIN_SPACE, + mac->min_space_cfg); + } + break; + } + case HW_VAR_SHORTGI_DENSITY:{ + u8 density_to_set; + + density_to_set = *((u8 *) val); + mac->min_space_cfg = rtlpriv->rtlhal.minspace_cfg; + mac->min_space_cfg |= (density_to_set << 3); + + RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD, + "Set HW_VAR_SHORTGI_DENSITY: %#x\n", + mac->min_space_cfg); + + rtl_write_byte(rtlpriv, AMPDU_MIN_SPACE, + mac->min_space_cfg); + + break; + } + case HW_VAR_AMPDU_FACTOR:{ + u8 factor_toset; + u8 regtoset; + u8 factorlevel[18] = { + 2, 4, 4, 7, 7, 13, 13, + 13, 2, 7, 7, 13, 13, + 15, 15, 15, 15, 0}; + u8 index = 0; + + factor_toset = *((u8 *) val); + if (factor_toset <= 3) { + factor_toset = (1 << (factor_toset + 2)); + if (factor_toset > 0xf) + factor_toset = 0xf; + + for (index = 0; index < 17; index++) { + if (factorlevel[index] > factor_toset) + factorlevel[index] = + factor_toset; + } + + for (index = 0; index < 8; index++) { + regtoset = ((factorlevel[index * 2]) | + (factorlevel[index * + 2 + 1] << 4)); + rtl_write_byte(rtlpriv, + AGGLEN_LMT_L + index, + regtoset); + } + + regtoset = ((factorlevel[16]) | + (factorlevel[17] << 4)); + rtl_write_byte(rtlpriv, AGGLEN_LMT_H, regtoset); + + RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD, + "Set HW_VAR_AMPDU_FACTOR: %#x\n", + factor_toset); + } + break; + } + case HW_VAR_AC_PARAM:{ + u8 e_aci = *((u8 *) val); + rtl92s_dm_init_edca_turbo(hw); + + 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 *p_aci_aifsn = (union aci_aifsn *)(&( + mac->ac[0].aifs)); + u8 acm = p_aci_aifsn->f.acm; + u8 acm_ctrl = rtl_read_byte(rtlpriv, 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(rtlpriv, 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(rtlpriv, COMP_ERR, DBG_EMERG, + "switch case not processed\n"); + break; + } + } + + RT_TRACE(rtlpriv, COMP_QOS, DBG_TRACE, + "HW_VAR_ACM_CTRL Write 0x%X\n", acm_ctrl); + rtl_write_byte(rtlpriv, AcmHwCtrl, acm_ctrl); + break; + } + case HW_VAR_RCR:{ + rtl_write_dword(rtlpriv, 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, RETRY_LIMIT, + retry_limit << RETRY_LIMIT_SHORT_SHIFT | + retry_limit << RETRY_LIMIT_LONG_SHIFT); + break; + } + case HW_VAR_DUAL_TSF_RST: { + break; + } + case HW_VAR_EFUSE_BYTES: { + rtlefuse->efuse_usedbytes = *((u16 *) val); + break; + } + case HW_VAR_EFUSE_USAGE: { + rtlefuse->efuse_usedpercentage = *((u8 *) val); + break; + } + case HW_VAR_IO_CMD: { + break; + } + case HW_VAR_WPA_CONFIG: { + rtl_write_byte(rtlpriv, REG_SECR, *((u8 *) val)); + break; + } + case HW_VAR_SET_RPWM:{ + break; + } + case HW_VAR_H2C_FW_PWRMODE:{ + break; + } + case HW_VAR_FW_PSMODE_STATUS: { + ppsc->fw_current_inpsmode = *((bool *) val); + break; + } + case HW_VAR_H2C_FW_JOINBSSRPT:{ + break; + } + case HW_VAR_AID:{ + break; + } + case HW_VAR_CORRECT_TSF:{ + break; + } + case HW_VAR_MRC: { + bool bmrc_toset = *((bool *)val); + u8 u1bdata = 0; + + if (bmrc_toset) { + rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, + MASKBYTE0, 0x33); + u1bdata = (u8)rtl_get_bbreg(hw, + ROFDM1_TRXPATHENABLE, + MASKBYTE0); + rtl_set_bbreg(hw, ROFDM1_TRXPATHENABLE, + MASKBYTE0, + ((u1bdata & 0xf0) | 0x03)); + u1bdata = (u8)rtl_get_bbreg(hw, + ROFDM0_TRXPATHENABLE, + MASKBYTE1); + rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, + MASKBYTE1, + (u1bdata | 0x04)); + + /* Update current settings. */ + rtlpriv->dm.current_mrc_switch = bmrc_toset; + } else { + rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, + MASKBYTE0, 0x13); + u1bdata = (u8)rtl_get_bbreg(hw, + ROFDM1_TRXPATHENABLE, + MASKBYTE0); + rtl_set_bbreg(hw, ROFDM1_TRXPATHENABLE, + MASKBYTE0, + ((u1bdata & 0xf0) | 0x01)); + u1bdata = (u8)rtl_get_bbreg(hw, + ROFDM0_TRXPATHENABLE, + MASKBYTE1); + rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, + MASKBYTE1, (u1bdata & 0xfb)); + + /* Update current settings. */ + rtlpriv->dm.current_mrc_switch = bmrc_toset; + } + + break; + } + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "switch case not processed\n"); + break; + } + +} + +void rtl92se_enable_hw_security_config(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 sec_reg_value = 0x0; + + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "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(rtlpriv, COMP_SEC, DBG_DMESG, + "not open hw encryption\n"); + return; + } + + sec_reg_value = SCR_TXENCENABLE | SCR_RXENCENABLE; + + if (rtlpriv->sec.use_defaultkey) { + sec_reg_value |= SCR_TXUSEDK; + sec_reg_value |= SCR_RXUSEDK; + } + + RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, "The SECR-value %x\n", + sec_reg_value); + + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_WPA_CONFIG, &sec_reg_value); + +} + +static u8 _rtl92ce_halset_sysclk(struct ieee80211_hw *hw, u8 data) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 waitcount = 100; + bool bresult = false; + u8 tmpvalue; + + rtl_write_byte(rtlpriv, SYS_CLKR + 1, data); + + /* Wait the MAC synchronized. */ + udelay(400); + + /* Check if it is set ready. */ + tmpvalue = rtl_read_byte(rtlpriv, SYS_CLKR + 1); + bresult = ((tmpvalue & BIT(7)) == (data & BIT(7))); + + if ((data & (BIT(6) | BIT(7))) == false) { + waitcount = 100; + tmpvalue = 0; + + while (1) { + waitcount--; + + tmpvalue = rtl_read_byte(rtlpriv, SYS_CLKR + 1); + if ((tmpvalue & BIT(6))) + break; + + pr_err("wait for BIT(6) return value %x\n", tmpvalue); + if (waitcount == 0) + break; + + udelay(10); + } + + if (waitcount == 0) + bresult = false; + else + bresult = true; + } + + return bresult; +} + +void rtl8192se_gpiobit3_cfg_inputmode(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 u1tmp; + + /* The following config GPIO function */ + rtl_write_byte(rtlpriv, MAC_PINMUX_CFG, (GPIOMUX_EN | GPIOSEL_GPIO)); + u1tmp = rtl_read_byte(rtlpriv, GPIO_IO_SEL); + + /* config GPIO3 to input */ + u1tmp &= HAL_8192S_HW_GPIO_OFF_MASK; + rtl_write_byte(rtlpriv, GPIO_IO_SEL, u1tmp); + +} + +static u8 _rtl92se_rf_onoff_detect(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 u1tmp; + u8 retval = ERFON; + + /* The following config GPIO function */ + rtl_write_byte(rtlpriv, MAC_PINMUX_CFG, (GPIOMUX_EN | GPIOSEL_GPIO)); + u1tmp = rtl_read_byte(rtlpriv, GPIO_IO_SEL); + + /* config GPIO3 to input */ + u1tmp &= HAL_8192S_HW_GPIO_OFF_MASK; + rtl_write_byte(rtlpriv, GPIO_IO_SEL, u1tmp); + + /* On some of the platform, driver cannot read correct + * value without delay between Write_GPIO_SEL and Read_GPIO_IN */ + mdelay(10); + + /* check GPIO3 */ + u1tmp = rtl_read_byte(rtlpriv, GPIO_IN_SE); + retval = (u1tmp & HAL_8192S_HW_GPIO_OFF_BIT) ? ERFON : ERFOFF; + + return retval; +} + +static void _rtl92se_macconfig_before_fwdownload(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + + u8 i; + u8 tmpu1b; + u16 tmpu2b; + u8 pollingcnt = 20; + + if (rtlpci->first_init) { + /* Reset PCIE Digital */ + tmpu1b = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1); + tmpu1b &= 0xFE; + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, tmpu1b); + udelay(1); + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, tmpu1b | BIT(0)); + } + + /* Switch to SW IO control */ + tmpu1b = rtl_read_byte(rtlpriv, (SYS_CLKR + 1)); + if (tmpu1b & BIT(7)) { + tmpu1b &= ~(BIT(6) | BIT(7)); + + /* Set failed, return to prevent hang. */ + if (!_rtl92ce_halset_sysclk(hw, tmpu1b)) + return; + } + + rtl_write_byte(rtlpriv, AFE_PLL_CTRL, 0x0); + udelay(50); + rtl_write_byte(rtlpriv, LDOA15_CTRL, 0x34); + udelay(50); + + /* Clear FW RPWM for FW control LPS.*/ + rtl_write_byte(rtlpriv, RPWM, 0x0); + + /* Reset MAC-IO and CPU and Core Digital BIT(10)/11/15 */ + tmpu1b = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1); + tmpu1b &= 0x73; + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, tmpu1b); + /* wait for BIT 10/11/15 to pull high automatically!! */ + mdelay(1); + + rtl_write_byte(rtlpriv, CMDR, 0); + rtl_write_byte(rtlpriv, TCR, 0); + + /* Data sheet not define 0x562!!! Copy from WMAC!!!!! */ + tmpu1b = rtl_read_byte(rtlpriv, 0x562); + tmpu1b |= 0x08; + rtl_write_byte(rtlpriv, 0x562, tmpu1b); + tmpu1b &= ~(BIT(3)); + rtl_write_byte(rtlpriv, 0x562, tmpu1b); + + /* Enable AFE clock source */ + tmpu1b = rtl_read_byte(rtlpriv, AFE_XTAL_CTRL); + rtl_write_byte(rtlpriv, AFE_XTAL_CTRL, (tmpu1b | 0x01)); + /* Delay 1.5ms */ + mdelay(2); + tmpu1b = rtl_read_byte(rtlpriv, AFE_XTAL_CTRL + 1); + rtl_write_byte(rtlpriv, AFE_XTAL_CTRL + 1, (tmpu1b & 0xfb)); + + /* Enable AFE Macro Block's Bandgap */ + tmpu1b = rtl_read_byte(rtlpriv, AFE_MISC); + rtl_write_byte(rtlpriv, AFE_MISC, (tmpu1b | BIT(0))); + mdelay(1); + + /* Enable AFE Mbias */ + tmpu1b = rtl_read_byte(rtlpriv, AFE_MISC); + rtl_write_byte(rtlpriv, AFE_MISC, (tmpu1b | 0x02)); + mdelay(1); + + /* Enable LDOA15 block */ + tmpu1b = rtl_read_byte(rtlpriv, LDOA15_CTRL); + rtl_write_byte(rtlpriv, LDOA15_CTRL, (tmpu1b | BIT(0))); + + /* Set Digital Vdd to Retention isolation Path. */ + tmpu2b = rtl_read_word(rtlpriv, REG_SYS_ISO_CTRL); + rtl_write_word(rtlpriv, REG_SYS_ISO_CTRL, (tmpu2b | BIT(11))); + + /* For warm reboot NIC disappera bug. */ + tmpu2b = rtl_read_word(rtlpriv, REG_SYS_FUNC_EN); + rtl_write_word(rtlpriv, REG_SYS_FUNC_EN, (tmpu2b | BIT(13))); + + rtl_write_byte(rtlpriv, REG_SYS_ISO_CTRL + 1, 0x68); + + /* Enable AFE PLL Macro Block */ + /* We need to delay 100u before enabling PLL. */ + udelay(200); + tmpu1b = rtl_read_byte(rtlpriv, AFE_PLL_CTRL); + rtl_write_byte(rtlpriv, AFE_PLL_CTRL, (tmpu1b | BIT(0) | BIT(4))); + + /* for divider reset */ + udelay(100); + rtl_write_byte(rtlpriv, AFE_PLL_CTRL, (tmpu1b | BIT(0) | + BIT(4) | BIT(6))); + udelay(10); + rtl_write_byte(rtlpriv, AFE_PLL_CTRL, (tmpu1b | BIT(0) | BIT(4))); + udelay(10); + + /* Enable MAC 80MHZ clock */ + tmpu1b = rtl_read_byte(rtlpriv, AFE_PLL_CTRL + 1); + rtl_write_byte(rtlpriv, AFE_PLL_CTRL + 1, (tmpu1b | BIT(0))); + mdelay(1); + + /* Release isolation AFE PLL & MD */ + rtl_write_byte(rtlpriv, REG_SYS_ISO_CTRL, 0xA6); + + /* Enable MAC clock */ + tmpu2b = rtl_read_word(rtlpriv, SYS_CLKR); + rtl_write_word(rtlpriv, SYS_CLKR, (tmpu2b | BIT(12) | BIT(11))); + + /* Enable Core digital and enable IOREG R/W */ + tmpu2b = rtl_read_word(rtlpriv, REG_SYS_FUNC_EN); + rtl_write_word(rtlpriv, REG_SYS_FUNC_EN, (tmpu2b | BIT(11))); + + tmpu1b = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1); + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, tmpu1b & ~(BIT(7))); + + /* enable REG_EN */ + rtl_write_word(rtlpriv, REG_SYS_FUNC_EN, (tmpu2b | BIT(11) | BIT(15))); + + /* Switch the control path. */ + tmpu2b = rtl_read_word(rtlpriv, SYS_CLKR); + rtl_write_word(rtlpriv, SYS_CLKR, (tmpu2b & (~BIT(2)))); + + tmpu1b = rtl_read_byte(rtlpriv, (SYS_CLKR + 1)); + tmpu1b = ((tmpu1b | BIT(7)) & (~BIT(6))); + if (!_rtl92ce_halset_sysclk(hw, tmpu1b)) + return; /* Set failed, return to prevent hang. */ + + rtl_write_word(rtlpriv, CMDR, 0x07FC); + + /* MH We must enable the section of code to prevent load IMEM fail. */ + /* Load MAC register from WMAc temporarily We simulate macreg. */ + /* txt HW will provide MAC txt later */ + rtl_write_byte(rtlpriv, 0x6, 0x30); + rtl_write_byte(rtlpriv, 0x49, 0xf0); + + rtl_write_byte(rtlpriv, 0x4b, 0x81); + + rtl_write_byte(rtlpriv, 0xb5, 0x21); + + rtl_write_byte(rtlpriv, 0xdc, 0xff); + rtl_write_byte(rtlpriv, 0xdd, 0xff); + rtl_write_byte(rtlpriv, 0xde, 0xff); + rtl_write_byte(rtlpriv, 0xdf, 0xff); + + rtl_write_byte(rtlpriv, 0x11a, 0x00); + rtl_write_byte(rtlpriv, 0x11b, 0x00); + + for (i = 0; i < 32; i++) + rtl_write_byte(rtlpriv, INIMCS_SEL + i, 0x1b); + + rtl_write_byte(rtlpriv, 0x236, 0xff); + + rtl_write_byte(rtlpriv, 0x503, 0x22); + + if (ppsc->support_aspm && !ppsc->support_backdoor) + rtl_write_byte(rtlpriv, 0x560, 0x40); + else + rtl_write_byte(rtlpriv, 0x560, 0x00); + + rtl_write_byte(rtlpriv, DBG_PORT, 0x91); + + /* Set RX Desc Address */ + rtl_write_dword(rtlpriv, RDQDA, rtlpci->rx_ring[RX_MPDU_QUEUE].dma); + rtl_write_dword(rtlpriv, RCDA, rtlpci->rx_ring[RX_CMD_QUEUE].dma); + + /* Set TX Desc Address */ + rtl_write_dword(rtlpriv, TBKDA, rtlpci->tx_ring[BK_QUEUE].dma); + rtl_write_dword(rtlpriv, TBEDA, rtlpci->tx_ring[BE_QUEUE].dma); + rtl_write_dword(rtlpriv, TVIDA, rtlpci->tx_ring[VI_QUEUE].dma); + rtl_write_dword(rtlpriv, TVODA, rtlpci->tx_ring[VO_QUEUE].dma); + rtl_write_dword(rtlpriv, TBDA, rtlpci->tx_ring[BEACON_QUEUE].dma); + rtl_write_dword(rtlpriv, TCDA, rtlpci->tx_ring[TXCMD_QUEUE].dma); + rtl_write_dword(rtlpriv, TMDA, rtlpci->tx_ring[MGNT_QUEUE].dma); + rtl_write_dword(rtlpriv, THPDA, rtlpci->tx_ring[HIGH_QUEUE].dma); + rtl_write_dword(rtlpriv, HDA, rtlpci->tx_ring[HCCA_QUEUE].dma); + + rtl_write_word(rtlpriv, CMDR, 0x37FC); + + /* To make sure that TxDMA can ready to download FW. */ + /* We should reset TxDMA if IMEM RPT was not ready. */ + do { + tmpu1b = rtl_read_byte(rtlpriv, TCR); + if ((tmpu1b & TXDMA_INIT_VALUE) == TXDMA_INIT_VALUE) + break; + + udelay(5); + } while (pollingcnt--); + + if (pollingcnt <= 0) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "Polling TXDMA_INIT_VALUE timeout!! Current TCR(%#x)\n", + tmpu1b); + tmpu1b = rtl_read_byte(rtlpriv, CMDR); + rtl_write_byte(rtlpriv, CMDR, tmpu1b & (~TXDMA_EN)); + udelay(2); + /* Reset TxDMA */ + rtl_write_byte(rtlpriv, CMDR, tmpu1b | TXDMA_EN); + } + + /* After MACIO reset,we must refresh LED state. */ + if ((ppsc->rfoff_reason == RF_CHANGE_BY_IPS) || + (ppsc->rfoff_reason == 0)) { + struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); + struct rtl_led *pLed0 = &(pcipriv->ledctl.sw_led0); + enum rf_pwrstate rfpwr_state_toset; + rfpwr_state_toset = _rtl92se_rf_onoff_detect(hw); + + if (rfpwr_state_toset == ERFON) + rtl92se_sw_led_on(hw, pLed0); + } +} + +static void _rtl92se_macconfig_after_fwdownload(struct ieee80211_hw *hw) +{ + 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)); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + u8 i; + u16 tmpu2b; + + /* 1. System Configure Register (Offset: 0x0000 - 0x003F) */ + + /* 2. Command Control Register (Offset: 0x0040 - 0x004F) */ + /* Turn on 0x40 Command register */ + rtl_write_word(rtlpriv, CMDR, (BBRSTN | BB_GLB_RSTN | + SCHEDULE_EN | MACRXEN | MACTXEN | DDMA_EN | FW2HW_EN | + RXDMA_EN | TXDMA_EN | HCI_RXDMA_EN | HCI_TXDMA_EN)); + + /* Set TCR TX DMA pre 2 FULL enable bit */ + rtl_write_dword(rtlpriv, TCR, rtl_read_dword(rtlpriv, TCR) | + TXDMAPRE2FULL); + + /* Set RCR */ + rtl_write_dword(rtlpriv, RCR, rtlpci->receive_config); + + /* 3. MACID Setting Register (Offset: 0x0050 - 0x007F) */ + + /* 4. Timing Control Register (Offset: 0x0080 - 0x009F) */ + /* Set CCK/OFDM SIFS */ + /* CCK SIFS shall always be 10us. */ + rtl_write_word(rtlpriv, SIFS_CCK, 0x0a0a); + rtl_write_word(rtlpriv, SIFS_OFDM, 0x1010); + + /* Set AckTimeout */ + rtl_write_byte(rtlpriv, ACK_TIMEOUT, 0x40); + + /* Beacon related */ + rtl_write_word(rtlpriv, BCN_INTERVAL, 100); + rtl_write_word(rtlpriv, ATIMWND, 2); + + /* 5. FIFO Control Register (Offset: 0x00A0 - 0x015F) */ + /* 5.1 Initialize Number of Reserved Pages in Firmware Queue */ + /* Firmware allocate now, associate with FW internal setting.!!! */ + + /* 5.2 Setting TX/RX page size 0/1/2/3/4=64/128/256/512/1024 */ + /* 5.3 Set driver info, we only accept PHY status now. */ + /* 5.4 Set RXDMA arbitration to control RXDMA/MAC/FW R/W for RXFIFO */ + rtl_write_byte(rtlpriv, RXDMA, rtl_read_byte(rtlpriv, RXDMA) | BIT(6)); + + /* 6. Adaptive Control Register (Offset: 0x0160 - 0x01CF) */ + /* Set RRSR to all legacy rate and HT rate + * CCK rate is supported by default. + * CCK rate will be filtered out only when associated + * AP does not support it. + * Only enable ACK rate to OFDM 24M + * Disable RRSR for CCK rate in A-Cut */ + + if (rtlhal->version == VERSION_8192S_ACUT) + rtl_write_byte(rtlpriv, RRSR, 0xf0); + else if (rtlhal->version == VERSION_8192S_BCUT) + rtl_write_byte(rtlpriv, RRSR, 0xff); + rtl_write_byte(rtlpriv, RRSR + 1, 0x01); + rtl_write_byte(rtlpriv, RRSR + 2, 0x00); + + /* A-Cut IC do not support CCK rate. We forbid ARFR to */ + /* fallback to CCK rate */ + for (i = 0; i < 8; i++) { + /*Disable RRSR for CCK rate in A-Cut */ + if (rtlhal->version == VERSION_8192S_ACUT) + rtl_write_dword(rtlpriv, ARFR0 + i * 4, 0x1f0ff0f0); + } + + /* Different rate use different AMPDU size */ + /* MCS32/ MCS15_SG use max AMPDU size 15*2=30K */ + rtl_write_byte(rtlpriv, AGGLEN_LMT_H, 0x0f); + /* MCS0/1/2/3 use max AMPDU size 4*2=8K */ + rtl_write_word(rtlpriv, AGGLEN_LMT_L, 0x7442); + /* MCS4/5 use max AMPDU size 8*2=16K 6/7 use 10*2=20K */ + rtl_write_word(rtlpriv, AGGLEN_LMT_L + 2, 0xddd7); + /* MCS8/9 use max AMPDU size 8*2=16K 10/11 use 10*2=20K */ + rtl_write_word(rtlpriv, AGGLEN_LMT_L + 4, 0xd772); + /* MCS12/13/14/15 use max AMPDU size 15*2=30K */ + rtl_write_word(rtlpriv, AGGLEN_LMT_L + 6, 0xfffd); + + /* Set Data / Response auto rate fallack retry count */ + rtl_write_dword(rtlpriv, DARFRC, 0x04010000); + rtl_write_dword(rtlpriv, DARFRC + 4, 0x09070605); + rtl_write_dword(rtlpriv, RARFRC, 0x04010000); + rtl_write_dword(rtlpriv, RARFRC + 4, 0x09070605); + + /* 7. EDCA Setting Register (Offset: 0x01D0 - 0x01FF) */ + /* Set all rate to support SG */ + rtl_write_word(rtlpriv, SG_RATE, 0xFFFF); + + /* 8. WMAC, BA, and CCX related Register (Offset: 0x0200 - 0x023F) */ + /* Set NAV protection length */ + rtl_write_word(rtlpriv, NAV_PROT_LEN, 0x0080); + /* CF-END Threshold */ + rtl_write_byte(rtlpriv, CFEND_TH, 0xFF); + /* Set AMPDU minimum space */ + rtl_write_byte(rtlpriv, AMPDU_MIN_SPACE, 0x07); + /* Set TXOP stall control for several queue/HI/BCN/MGT/ */ + rtl_write_byte(rtlpriv, TXOP_STALL_CTRL, 0x00); + + /* 9. Security Control Register (Offset: 0x0240 - 0x025F) */ + /* 10. Power Save Control Register (Offset: 0x0260 - 0x02DF) */ + /* 11. General Purpose Register (Offset: 0x02E0 - 0x02FF) */ + /* 12. Host Interrupt Status Register (Offset: 0x0300 - 0x030F) */ + /* 13. Test Mode and Debug Control Register (Offset: 0x0310 - 0x034F) */ + + /* 14. Set driver info, we only accept PHY status now. */ + rtl_write_byte(rtlpriv, RXDRVINFO_SZ, 4); + + /* 15. For EEPROM R/W Workaround */ + /* 16. For EFUSE to share REG_SYS_FUNC_EN with EEPROM!!! */ + tmpu2b = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN); + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, tmpu2b | BIT(13)); + tmpu2b = rtl_read_byte(rtlpriv, REG_SYS_ISO_CTRL); + rtl_write_byte(rtlpriv, REG_SYS_ISO_CTRL, tmpu2b & (~BIT(8))); + + /* 17. For EFUSE */ + /* We may R/W EFUSE in EEPROM mode */ + if (rtlefuse->epromtype == EEPROM_BOOT_EFUSE) { + u8 tempval; + + tempval = rtl_read_byte(rtlpriv, REG_SYS_ISO_CTRL + 1); + tempval &= 0xFE; + rtl_write_byte(rtlpriv, REG_SYS_ISO_CTRL + 1, tempval); + + /* Change Program timing */ + rtl_write_byte(rtlpriv, REG_EFUSE_CTRL + 3, 0x72); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "EFUSE CONFIG OK\n"); + } + + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "OK\n"); + +} + +static void _rtl92se_hw_configure(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + + u8 reg_bw_opmode = 0; + u32 reg_rrsr = 0; + u8 regtmp = 0; + + reg_bw_opmode = BW_OPMODE_20MHZ; + reg_rrsr = RATE_ALL_CCK | RATE_ALL_OFDM_AG; + + regtmp = rtl_read_byte(rtlpriv, INIRTSMCS_SEL); + reg_rrsr = ((reg_rrsr & 0x000fffff) << 8) | regtmp; + rtl_write_dword(rtlpriv, INIRTSMCS_SEL, reg_rrsr); + rtl_write_byte(rtlpriv, BW_OPMODE, reg_bw_opmode); + + /* Set Retry Limit here */ + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RETRY_LIMIT, + (u8 *)(&rtlpci->shortretry_limit)); + + rtl_write_byte(rtlpriv, MLT, 0x8f); + + /* For Min Spacing configuration. */ + switch (rtlphy->rf_type) { + case RF_1T2R: + case RF_1T1R: + rtlhal->minspace_cfg = (MAX_MSS_DENSITY_1T << 3); + break; + case RF_2T2R: + case RF_2T2R_GREEN: + rtlhal->minspace_cfg = (MAX_MSS_DENSITY_2T << 3); + break; + } + rtl_write_byte(rtlpriv, AMPDU_MIN_SPACE, rtlhal->minspace_cfg); +} + +int rtl92se_hw_init(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_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + u8 tmp_byte = 0; + + bool rtstatus = true; + u8 tmp_u1b; + int err = false; + u8 i; + int wdcapra_add[] = { + EDCAPARA_BE, EDCAPARA_BK, + EDCAPARA_VI, EDCAPARA_VO}; + u8 secr_value = 0x0; + + rtlpci->being_init_adapter = true; + + rtlpriv->intf_ops->disable_aspm(hw); + + /* 1. MAC Initialize */ + /* Before FW download, we have to set some MAC register */ + _rtl92se_macconfig_before_fwdownload(hw); + + rtlhal->version = (enum version_8192s)((rtl_read_dword(rtlpriv, + PMC_FSM) >> 16) & 0xF); + + rtl8192se_gpiobit3_cfg_inputmode(hw); + + /* 2. download firmware */ + rtstatus = rtl92s_download_fw(hw); + if (!rtstatus) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, + "Failed to download FW. Init HW without FW now... " + "Please copy FW into /lib/firmware/rtlwifi\n"); + return 1; + } + + /* After FW download, we have to reset MAC register */ + _rtl92se_macconfig_after_fwdownload(hw); + + /*Retrieve default FW Cmd IO map. */ + rtlhal->fwcmd_iomap = rtl_read_word(rtlpriv, LBUS_MON_ADDR); + rtlhal->fwcmd_ioparam = rtl_read_dword(rtlpriv, LBUS_ADDR_MASK); + + /* 3. Initialize MAC/PHY Config by MACPHY_reg.txt */ + if (!rtl92s_phy_mac_config(hw)) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "MAC Config failed\n"); + return rtstatus; + } + + /* Make sure BB/RF write OK. We should prevent enter IPS. radio off. */ + /* We must set flag avoid BB/RF config period later!! */ + rtl_write_dword(rtlpriv, CMDR, 0x37FC); + + /* 4. Initialize BB After MAC Config PHY_reg.txt, AGC_Tab.txt */ + if (!rtl92s_phy_bb_config(hw)) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG, "BB Config failed\n"); + return rtstatus; + } + + /* 5. Initiailze RF RAIO_A.txt RF RAIO_B.txt */ + /* Before initalizing RF. We can not use FW to do RF-R/W. */ + + rtlphy->rf_mode = RF_OP_BY_SW_3WIRE; + + /* RF Power Save */ +#if 0 + /* H/W or S/W RF OFF before sleep. */ + if (rtlpriv->psc.rfoff_reason > RF_CHANGE_BY_PS) { + u32 rfoffreason = rtlpriv->psc.rfoff_reason; + + rtlpriv->psc.rfoff_reason = RF_CHANGE_BY_INIT; + rtlpriv->psc.rfpwr_state = ERFON; + /* FIXME: check spinlocks if this block is uncommented */ + rtl_ps_set_rf_state(hw, ERFOFF, rfoffreason); + } else { + /* gpio radio on/off is out of adapter start */ + if (rtlpriv->psc.hwradiooff == false) { + rtlpriv->psc.rfpwr_state = ERFON; + rtlpriv->psc.rfoff_reason = 0; + } + } +#endif + + /* Before RF-R/W we must execute the IO from Scott's suggestion. */ + rtl_write_byte(rtlpriv, AFE_XTAL_CTRL + 1, 0xDB); + if (rtlhal->version == VERSION_8192S_ACUT) + rtl_write_byte(rtlpriv, SPS1_CTRL + 3, 0x07); + else + rtl_write_byte(rtlpriv, RF_CTRL, 0x07); + + if (!rtl92s_phy_rf_config(hw)) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "RF Config failed\n"); + return rtstatus; + } + + /* After read predefined TXT, we must set BB/MAC/RF + * register as our requirement */ + + rtlphy->rfreg_chnlval[0] = rtl92s_phy_query_rf_reg(hw, + (enum radio_path)0, + RF_CHNLBW, + RFREG_OFFSET_MASK); + rtlphy->rfreg_chnlval[1] = rtl92s_phy_query_rf_reg(hw, + (enum radio_path)1, + RF_CHNLBW, + RFREG_OFFSET_MASK); + + /*---- Set CCK and OFDM Block "ON"----*/ + rtl_set_bbreg(hw, RFPGA0_RFMOD, BCCKEN, 0x1); + rtl_set_bbreg(hw, RFPGA0_RFMOD, BOFDMEN, 0x1); + + /*3 Set Hardware(Do nothing now) */ + _rtl92se_hw_configure(hw); + + /* Read EEPROM TX power index and PHY_REG_PG.txt to capture correct */ + /* TX power index for different rate set. */ + /* Get original hw reg values */ + rtl92s_phy_get_hw_reg_originalvalue(hw); + /* Write correct tx power index */ + rtl92s_phy_set_txpower(hw, rtlphy->current_channel); + + /* We must set MAC address after firmware download. */ + for (i = 0; i < 6; i++) + rtl_write_byte(rtlpriv, MACIDR0 + i, rtlefuse->dev_addr[i]); + + /* EEPROM R/W workaround */ + tmp_u1b = rtl_read_byte(rtlpriv, MAC_PINMUX_CFG); + rtl_write_byte(rtlpriv, MAC_PINMUX_CFG, tmp_u1b & (~BIT(3))); + + rtl_write_byte(rtlpriv, 0x4d, 0x0); + + if (hal_get_firmwareversion(rtlpriv) >= 0x49) { + tmp_byte = rtl_read_byte(rtlpriv, FW_RSVD_PG_CRTL) & (~BIT(4)); + tmp_byte = tmp_byte | BIT(5); + rtl_write_byte(rtlpriv, FW_RSVD_PG_CRTL, tmp_byte); + rtl_write_dword(rtlpriv, TXDESC_MSK, 0xFFFFCFFF); + } + + /* We enable high power and RA related mechanism after NIC + * initialized. */ + rtl92s_phy_set_fw_cmd(hw, FW_CMD_RA_INIT); + + /* Add to prevent ASPM bug. */ + /* Always enable hst and NIC clock request. */ + rtl92s_phy_switch_ephy_parameter(hw); + + /* Security related + * 1. Clear all H/W keys. + * 2. Enable H/W encryption/decryption. */ + rtl_cam_reset_all_entry(hw); + secr_value |= SCR_TXENCENABLE; + secr_value |= SCR_RXENCENABLE; + secr_value |= SCR_NOSKMC; + rtl_write_byte(rtlpriv, REG_SECR, secr_value); + + for (i = 0; i < 4; i++) + rtl_write_dword(rtlpriv, wdcapra_add[i], 0x5e4322); + + if (rtlphy->rf_type == RF_1T2R) { + bool mrc2set = true; + /* Turn on B-Path */ + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_MRC, (u8 *)&mrc2set); + } + + rtlpriv->cfg->ops->led_control(hw, LED_CTL_POWER_ON); + rtl92s_dm_init(hw); + rtlpci->being_init_adapter = false; + + return err; +} + +void rtl92se_set_mac_addr(struct rtl_io *io, const u8 * addr) +{ +} + +void rtl92se_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) { + reg_rcr |= (RCR_CBSSID); + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR, (u8 *)(®_rcr)); + } else if (!check_bssid) { + reg_rcr &= (~RCR_CBSSID); + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR, (u8 *)(®_rcr)); + } + +} + +static int _rtl92se_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); + u32 temp; + bt_msr &= ~MSR_LINK_MASK; + + switch (type) { + case NL80211_IFTYPE_UNSPECIFIED: + bt_msr |= (MSR_LINK_NONE << MSR_LINK_SHIFT); + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + "Set Network type to NO LINK!\n"); + break; + case NL80211_IFTYPE_ADHOC: + bt_msr |= (MSR_LINK_ADHOC << MSR_LINK_SHIFT); + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + "Set Network type to Ad Hoc!\n"); + break; + case NL80211_IFTYPE_STATION: + bt_msr |= (MSR_LINK_MANAGED << MSR_LINK_SHIFT); + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + "Set Network type to STA!\n"); + break; + case NL80211_IFTYPE_AP: + bt_msr |= (MSR_LINK_MASTER << MSR_LINK_SHIFT); + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + "Set Network type to AP!\n"); + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "Network type %d not supported!\n", type); + return 1; + break; + + } + + rtl_write_byte(rtlpriv, (MSR), bt_msr); + + temp = rtl_read_dword(rtlpriv, TCR); + rtl_write_dword(rtlpriv, TCR, temp & (~BIT(8))); + rtl_write_dword(rtlpriv, TCR, temp | BIT(8)); + + + return 0; +} + +/* HW_VAR_MEDIA_STATUS & HW_VAR_CECHK_BSSID */ +int rtl92se_set_network_type(struct ieee80211_hw *hw, enum nl80211_iftype type) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + if (_rtl92se_set_media_status(hw, type)) + return -EOPNOTSUPP; + + if (rtlpriv->mac80211.link_state == MAC80211_LINKED) { + if (type != NL80211_IFTYPE_AP) + rtl92se_set_check_bssid(hw, true); + } else { + rtl92se_set_check_bssid(hw, false); + } + + return 0; +} + +/* don't set REG_EDCA_BE_PARAM here because mac80211 will send pkt when scan */ +void rtl92se_set_qos(struct ieee80211_hw *hw, int aci) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + rtl92s_dm_init_edca_turbo(hw); + + switch (aci) { + case AC1_BK: + rtl_write_dword(rtlpriv, EDCAPARA_BK, 0xa44f); + break; + case AC0_BE: + /* rtl_write_dword(rtlpriv, EDCAPARA_BE, u4b_ac_param); */ + break; + case AC2_VI: + rtl_write_dword(rtlpriv, EDCAPARA_VI, 0x5e4322); + break; + case AC3_VO: + rtl_write_dword(rtlpriv, EDCAPARA_VO, 0x2f3222); + break; + default: + RT_ASSERT(false, "invalid aci: %d !\n", aci); + break; + } +} + +void rtl92se_enable_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, INTA_MASK, rtlpci->irq_mask[0]); + /* Support Bit 32-37(Assign as Bit 0-5) interrupt setting now */ + rtl_write_dword(rtlpriv, INTA_MASK + 4, rtlpci->irq_mask[1] & 0x3F); +} + +void rtl92se_disable_interrupt(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv; + struct rtl_pci *rtlpci; + + rtlpriv = rtl_priv(hw); + /* if firmware not available, no interrupts */ + if (!rtlpriv || !rtlpriv->max_fw_size) + return; + rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + rtl_write_dword(rtlpriv, INTA_MASK, 0); + rtl_write_dword(rtlpriv, INTA_MASK + 4, 0); + + synchronize_irq(rtlpci->pdev->irq); +} + + +static u8 _rtl92s_set_sysclk(struct ieee80211_hw *hw, u8 data) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 waitcnt = 100; + bool result = false; + u8 tmp; + + rtl_write_byte(rtlpriv, SYS_CLKR + 1, data); + + /* Wait the MAC synchronized. */ + udelay(400); + + /* Check if it is set ready. */ + tmp = rtl_read_byte(rtlpriv, SYS_CLKR + 1); + result = ((tmp & BIT(7)) == (data & BIT(7))); + + if ((data & (BIT(6) | BIT(7))) == false) { + waitcnt = 100; + tmp = 0; + + while (1) { + waitcnt--; + tmp = rtl_read_byte(rtlpriv, SYS_CLKR + 1); + + if ((tmp & BIT(6))) + break; + + pr_err("wait for BIT(6) return value %x\n", tmp); + + if (waitcnt == 0) + break; + udelay(10); + } + + if (waitcnt == 0) + result = false; + else + result = true; + } + + return result; +} + +static void _rtl92s_phy_set_rfhalt(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)); + u8 u1btmp; + + if (rtlhal->driver_going2unload) + rtl_write_byte(rtlpriv, 0x560, 0x0); + + /* Power save for BB/RF */ + u1btmp = rtl_read_byte(rtlpriv, LDOV12D_CTRL); + u1btmp |= BIT(0); + rtl_write_byte(rtlpriv, LDOV12D_CTRL, u1btmp); + rtl_write_byte(rtlpriv, SPS1_CTRL, 0x0); + rtl_write_byte(rtlpriv, TXPAUSE, 0xFF); + rtl_write_word(rtlpriv, CMDR, 0x57FC); + udelay(100); + rtl_write_word(rtlpriv, CMDR, 0x77FC); + rtl_write_byte(rtlpriv, PHY_CCA, 0x0); + udelay(10); + rtl_write_word(rtlpriv, CMDR, 0x37FC); + udelay(10); + rtl_write_word(rtlpriv, CMDR, 0x77FC); + udelay(10); + rtl_write_word(rtlpriv, CMDR, 0x57FC); + rtl_write_word(rtlpriv, CMDR, 0x0000); + + if (rtlhal->driver_going2unload) { + u1btmp = rtl_read_byte(rtlpriv, (REG_SYS_FUNC_EN + 1)); + u1btmp &= ~(BIT(0)); + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, u1btmp); + } + + u1btmp = rtl_read_byte(rtlpriv, (SYS_CLKR + 1)); + + /* Add description. After switch control path. register + * after page1 will be invisible. We can not do any IO + * for register>0x40. After resume&MACIO reset, we need + * to remember previous reg content. */ + if (u1btmp & BIT(7)) { + u1btmp &= ~(BIT(6) | BIT(7)); + if (!_rtl92s_set_sysclk(hw, u1btmp)) { + pr_err("Switch ctrl path fail\n"); + return; + } + } + + /* Power save for MAC */ + if (ppsc->rfoff_reason == RF_CHANGE_BY_IPS && + !rtlhal->driver_going2unload) { + /* enable LED function */ + rtl_write_byte(rtlpriv, 0x03, 0xF9); + /* SW/HW radio off or halt adapter!! For example S3/S4 */ + } else { + /* LED function disable. Power range is about 8mA now. */ + /* if write 0xF1 disconnet_pci power + * ifconfig wlan0 down power are both high 35:70 */ + /* if write oxF9 disconnet_pci power + * ifconfig wlan0 down power are both low 12:45*/ + rtl_write_byte(rtlpriv, 0x03, 0xF9); + } + + rtl_write_byte(rtlpriv, SYS_CLKR + 1, 0x70); + rtl_write_byte(rtlpriv, AFE_PLL_CTRL + 1, 0x68); + rtl_write_byte(rtlpriv, AFE_PLL_CTRL, 0x00); + rtl_write_byte(rtlpriv, LDOA15_CTRL, 0x34); + rtl_write_byte(rtlpriv, AFE_XTAL_CTRL, 0x0E); + RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC); + +} + +static void _rtl92se_gen_refreshledstate(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); + struct rtl_led *pLed0 = &(pcipriv->ledctl.sw_led0); + + if (rtlpci->up_first_time == 1) + return; + + if (rtlpriv->psc.rfoff_reason == RF_CHANGE_BY_IPS) + rtl92se_sw_led_on(hw, pLed0); + else + rtl92se_sw_led_off(hw, pLed0); +} + + +static void _rtl92se_power_domain_init(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u16 tmpu2b; + u8 tmpu1b; + + rtlpriv->psc.pwrdomain_protect = true; + + tmpu1b = rtl_read_byte(rtlpriv, (SYS_CLKR + 1)); + if (tmpu1b & BIT(7)) { + tmpu1b &= ~(BIT(6) | BIT(7)); + if (!_rtl92s_set_sysclk(hw, tmpu1b)) { + rtlpriv->psc.pwrdomain_protect = false; + return; + } + } + + rtl_write_byte(rtlpriv, AFE_PLL_CTRL, 0x0); + rtl_write_byte(rtlpriv, LDOA15_CTRL, 0x34); + + /* Reset MAC-IO and CPU and Core Digital BIT10/11/15 */ + tmpu1b = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1); + + /* If IPS we need to turn LED on. So we not + * not disable BIT 3/7 of reg3. */ + if (rtlpriv->psc.rfoff_reason & (RF_CHANGE_BY_IPS | RF_CHANGE_BY_HW)) + tmpu1b &= 0xFB; + else + tmpu1b &= 0x73; + + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, tmpu1b); + /* wait for BIT 10/11/15 to pull high automatically!! */ + mdelay(1); + + rtl_write_byte(rtlpriv, CMDR, 0); + rtl_write_byte(rtlpriv, TCR, 0); + + /* Data sheet not define 0x562!!! Copy from WMAC!!!!! */ + tmpu1b = rtl_read_byte(rtlpriv, 0x562); + tmpu1b |= 0x08; + rtl_write_byte(rtlpriv, 0x562, tmpu1b); + tmpu1b &= ~(BIT(3)); + rtl_write_byte(rtlpriv, 0x562, tmpu1b); + + /* Enable AFE clock source */ + tmpu1b = rtl_read_byte(rtlpriv, AFE_XTAL_CTRL); + rtl_write_byte(rtlpriv, AFE_XTAL_CTRL, (tmpu1b | 0x01)); + /* Delay 1.5ms */ + udelay(1500); + tmpu1b = rtl_read_byte(rtlpriv, AFE_XTAL_CTRL + 1); + rtl_write_byte(rtlpriv, AFE_XTAL_CTRL + 1, (tmpu1b & 0xfb)); + + /* Enable AFE Macro Block's Bandgap */ + tmpu1b = rtl_read_byte(rtlpriv, AFE_MISC); + rtl_write_byte(rtlpriv, AFE_MISC, (tmpu1b | BIT(0))); + mdelay(1); + + /* Enable AFE Mbias */ + tmpu1b = rtl_read_byte(rtlpriv, AFE_MISC); + rtl_write_byte(rtlpriv, AFE_MISC, (tmpu1b | 0x02)); + mdelay(1); + + /* Enable LDOA15 block */ + tmpu1b = rtl_read_byte(rtlpriv, LDOA15_CTRL); + rtl_write_byte(rtlpriv, LDOA15_CTRL, (tmpu1b | BIT(0))); + + /* Set Digital Vdd to Retention isolation Path. */ + tmpu2b = rtl_read_word(rtlpriv, REG_SYS_ISO_CTRL); + rtl_write_word(rtlpriv, REG_SYS_ISO_CTRL, (tmpu2b | BIT(11))); + + + /* For warm reboot NIC disappera bug. */ + tmpu2b = rtl_read_word(rtlpriv, REG_SYS_FUNC_EN); + rtl_write_word(rtlpriv, REG_SYS_FUNC_EN, (tmpu2b | BIT(13))); + + rtl_write_byte(rtlpriv, REG_SYS_ISO_CTRL + 1, 0x68); + + /* Enable AFE PLL Macro Block */ + tmpu1b = rtl_read_byte(rtlpriv, AFE_PLL_CTRL); + rtl_write_byte(rtlpriv, AFE_PLL_CTRL, (tmpu1b | BIT(0) | BIT(4))); + /* Enable MAC 80MHZ clock */ + tmpu1b = rtl_read_byte(rtlpriv, AFE_PLL_CTRL + 1); + rtl_write_byte(rtlpriv, AFE_PLL_CTRL + 1, (tmpu1b | BIT(0))); + mdelay(1); + + /* Release isolation AFE PLL & MD */ + rtl_write_byte(rtlpriv, REG_SYS_ISO_CTRL, 0xA6); + + /* Enable MAC clock */ + tmpu2b = rtl_read_word(rtlpriv, SYS_CLKR); + rtl_write_word(rtlpriv, SYS_CLKR, (tmpu2b | BIT(12) | BIT(11))); + + /* Enable Core digital and enable IOREG R/W */ + tmpu2b = rtl_read_word(rtlpriv, REG_SYS_FUNC_EN); + rtl_write_word(rtlpriv, REG_SYS_FUNC_EN, (tmpu2b | BIT(11))); + /* enable REG_EN */ + rtl_write_word(rtlpriv, REG_SYS_FUNC_EN, (tmpu2b | BIT(11) | BIT(15))); + + /* Switch the control path. */ + tmpu2b = rtl_read_word(rtlpriv, SYS_CLKR); + rtl_write_word(rtlpriv, SYS_CLKR, (tmpu2b & (~BIT(2)))); + + tmpu1b = rtl_read_byte(rtlpriv, (SYS_CLKR + 1)); + tmpu1b = ((tmpu1b | BIT(7)) & (~BIT(6))); + if (!_rtl92s_set_sysclk(hw, tmpu1b)) { + rtlpriv->psc.pwrdomain_protect = false; + return; + } + + rtl_write_word(rtlpriv, CMDR, 0x37FC); + + /* After MACIO reset,we must refresh LED state. */ + _rtl92se_gen_refreshledstate(hw); + + rtlpriv->psc.pwrdomain_protect = false; +} + +void rtl92se_card_disable(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_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + enum nl80211_iftype opmode; + u8 wait = 30; + + rtlpriv->intf_ops->enable_aspm(hw); + + if (rtlpci->driver_is_goingto_unload || + ppsc->rfoff_reason > RF_CHANGE_BY_PS) + rtlpriv->cfg->ops->led_control(hw, LED_CTL_POWER_OFF); + + /* we should chnge GPIO to input mode + * this will drop away current about 25mA*/ + rtl8192se_gpiobit3_cfg_inputmode(hw); + + /* this is very important for ips power save */ + while (wait-- >= 10 && rtlpriv->psc.pwrdomain_protect) { + if (rtlpriv->psc.pwrdomain_protect) + mdelay(20); + else + break; + } + + mac->link_state = MAC80211_NOLINK; + opmode = NL80211_IFTYPE_UNSPECIFIED; + _rtl92se_set_media_status(hw, opmode); + + _rtl92s_phy_set_rfhalt(hw); + udelay(100); +} + +void rtl92se_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, ISR + 4) & rtlpci->irq_mask[1]; + rtl_write_dword(rtlpriv, ISR + 4, *p_intb); +} + +void rtl92se_set_beacon_related_registers(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + u16 bcntime_cfg = 0; + u16 bcn_cw = 6, bcn_ifs = 0xf; + u16 atim_window = 2; + + /* ATIM Window (in unit of TU). */ + rtl_write_word(rtlpriv, ATIMWND, atim_window); + + /* Beacon interval (in unit of TU). */ + rtl_write_word(rtlpriv, BCN_INTERVAL, mac->beacon_interval); + + /* DrvErlyInt (in unit of TU). (Time to send + * interrupt to notify driver to change + * beacon content) */ + rtl_write_word(rtlpriv, BCN_DRV_EARLY_INT, 10 << 4); + + /* BcnDMATIM(in unit of us). Indicates the + * time before TBTT to perform beacon queue DMA */ + rtl_write_word(rtlpriv, BCN_DMATIME, 256); + + /* Force beacon frame transmission even + * after receiving beacon frame from + * other ad hoc STA */ + rtl_write_byte(rtlpriv, BCN_ERR_THRESH, 100); + + /* Beacon Time Configuration */ + if (mac->opmode == NL80211_IFTYPE_ADHOC) + bcntime_cfg |= (bcn_cw << BCN_TCFG_CW_SHIFT); + + /* TODO: bcn_ifs may required to be changed on ASIC */ + bcntime_cfg |= bcn_ifs << BCN_TCFG_IFS; + + /*for beacon changed */ + rtl92s_phy_set_beacon_hwreg(hw, mac->beacon_interval); +} + +void rtl92se_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; + + /* Beacon interval (in unit of TU). */ + rtl_write_word(rtlpriv, BCN_INTERVAL, bcn_interval); + /* 2008.10.24 added by tynli for beacon changed. */ + rtl92s_phy_set_beacon_hwreg(hw, bcn_interval); +} + +void rtl92se_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(rtlpriv, 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); + + rtl92se_disable_interrupt(hw); + rtl92se_enable_interrupt(hw); +} + +static void _rtl8192se_get_IC_Inferiority(struct ieee80211_hw *hw) +{ + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u8 efuse_id; + + rtlhal->ic_class = IC_INFERIORITY_A; + + /* Only retrieving while using EFUSE. */ + if ((rtlefuse->epromtype == EEPROM_BOOT_EFUSE) && + !rtlefuse->autoload_failflag) { + efuse_id = efuse_read_1byte(hw, EFUSE_IC_ID_OFFSET); + + if (efuse_id == 0xfe) + rtlhal->ic_class = IC_INFERIORITY_B; + } +} + +static void _rtl92se_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_phy *rtlphy = &(rtlpriv->phy); + u16 i, usvalue; + u16 eeprom_id; + u8 tempval; + u8 hwinfo[HWSET_MAX_SIZE_92S]; + u8 rf_path, index; + + if (rtlefuse->epromtype == EEPROM_93C46) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "RTL819X Not boot from eeprom, check it !!\n"); + } else if (rtlefuse->epromtype == EEPROM_BOOT_EFUSE) { + rtl_efuse_shadow_map_update(hw); + + memcpy((void *)hwinfo, (void *) + &rtlefuse->efuse_map[EFUSE_INIT_MAP][0], + HWSET_MAX_SIZE_92S); + } + + RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_DMESG, "MAP", + hwinfo, HWSET_MAX_SIZE_92S); + + eeprom_id = *((u16 *)&hwinfo[0]); + if (eeprom_id != RTL8190_EEPROM_ID) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, + "EEPROM ID(%#x) is invalid!!\n", eeprom_id); + rtlefuse->autoload_failflag = true; + } else { + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "Autoload OK\n"); + rtlefuse->autoload_failflag = false; + } + + if (rtlefuse->autoload_failflag) + return; + + _rtl8192se_get_IC_Inferiority(hw); + + /* Read IC Version && Channel Plan */ + /* VID, DID SE 0xA-D */ + 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]; + rtlefuse->eeprom_version = *(u16 *)&hwinfo[EEPROM_VERSION]; + + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "EEPROMId = 0x%4x\n", eeprom_id); + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "EEPROM VID = 0x%4x\n", rtlefuse->eeprom_vid); + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "EEPROM DID = 0x%4x\n", rtlefuse->eeprom_did); + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "EEPROM SVID = 0x%4x\n", rtlefuse->eeprom_svid); + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "EEPROM SMID = 0x%4x\n", rtlefuse->eeprom_smid); + + for (i = 0; i < 6; i += 2) { + usvalue = *(u16 *)&hwinfo[EEPROM_MAC_ADDR + i]; + *((u16 *) (&rtlefuse->dev_addr[i])) = usvalue; + } + + for (i = 0; i < 6; i++) + rtl_write_byte(rtlpriv, MACIDR0 + i, rtlefuse->dev_addr[i]); + + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "%pM\n", rtlefuse->dev_addr); + + /* Get Tx Power Level by Channel */ + /* Read Tx power of Channel 1 ~ 14 from EEPROM. */ + /* 92S suupport RF A & B */ + for (rf_path = 0; rf_path < 2; rf_path++) { + for (i = 0; i < 3; i++) { + /* Read CCK RF A & B Tx power */ + rtlefuse->eeprom_chnlarea_txpwr_cck[rf_path][i] = + hwinfo[EEPROM_TXPOWERBASE + rf_path * 3 + i]; + + /* Read OFDM RF A & B Tx power for 1T */ + rtlefuse->eeprom_chnlarea_txpwr_ht40_1s[rf_path][i] = + hwinfo[EEPROM_TXPOWERBASE + 6 + rf_path * 3 + i]; + + /* Read OFDM RF A & B Tx power for 2T */ + rtlefuse->eeprom_chnlarea_txpwr_ht40_2sdiif[rf_path][i] + = hwinfo[EEPROM_TXPOWERBASE + 12 + + rf_path * 3 + i]; + } + } + + for (rf_path = 0; rf_path < 2; rf_path++) + for (i = 0; i < 3; i++) + RTPRINT(rtlpriv, FINIT, INIT_EEPROM, + "RF(%d) EEPROM CCK Area(%d) = 0x%x\n", + rf_path, i, + rtlefuse->eeprom_chnlarea_txpwr_cck + [rf_path][i]); + for (rf_path = 0; rf_path < 2; rf_path++) + for (i = 0; i < 3; i++) + RTPRINT(rtlpriv, FINIT, INIT_EEPROM, + "RF(%d) EEPROM HT40 1S Area(%d) = 0x%x\n", + rf_path, i, + rtlefuse->eeprom_chnlarea_txpwr_ht40_1s + [rf_path][i]); + for (rf_path = 0; rf_path < 2; rf_path++) + for (i = 0; i < 3; i++) + RTPRINT(rtlpriv, FINIT, INIT_EEPROM, + "RF(%d) EEPROM HT40 2S Diff Area(%d) = 0x%x\n", + rf_path, i, + rtlefuse->eeprom_chnlarea_txpwr_ht40_2sdiif + [rf_path][i]); + + for (rf_path = 0; rf_path < 2; rf_path++) { + + /* Assign dedicated channel tx power */ + for (i = 0; i < 14; i++) { + /* channel 1~3 use the same Tx Power Level. */ + if (i < 3) + index = 0; + /* Channel 4-8 */ + else if (i < 8) + index = 1; + /* Channel 9-14 */ + else + index = 2; + + /* Record A & B CCK /OFDM - 1T/2T Channel area + * tx power */ + rtlefuse->txpwrlevel_cck[rf_path][i] = + rtlefuse->eeprom_chnlarea_txpwr_cck + [rf_path][index]; + rtlefuse->txpwrlevel_ht40_1s[rf_path][i] = + rtlefuse->eeprom_chnlarea_txpwr_ht40_1s + [rf_path][index]; + rtlefuse->txpwrlevel_ht40_2s[rf_path][i] = + rtlefuse->eeprom_chnlarea_txpwr_ht40_2sdiif + [rf_path][index]; + } + + for (i = 0; i < 14; i++) { + RTPRINT(rtlpriv, FINIT, INIT_TxPower, + "RF(%d)-Ch(%d) [CCK / HT40_1S / HT40_2S] = [0x%x / 0x%x / 0x%x]\n", + rf_path, i, + rtlefuse->txpwrlevel_cck[rf_path][i], + rtlefuse->txpwrlevel_ht40_1s[rf_path][i], + rtlefuse->txpwrlevel_ht40_2s[rf_path][i]); + } + } + + for (rf_path = 0; rf_path < 2; rf_path++) { + for (i = 0; i < 3; i++) { + /* Read Power diff limit. */ + rtlefuse->eeprom_pwrgroup[rf_path][i] = + hwinfo[EEPROM_TXPWRGROUP + rf_path * 3 + i]; + } + } + + for (rf_path = 0; rf_path < 2; rf_path++) { + /* Fill Pwr group */ + for (i = 0; i < 14; i++) { + /* Chanel 1-3 */ + if (i < 3) + index = 0; + /* Channel 4-8 */ + else if (i < 8) + index = 1; + /* Channel 9-13 */ + else + index = 2; + + rtlefuse->pwrgroup_ht20[rf_path][i] = + (rtlefuse->eeprom_pwrgroup[rf_path][index] & + 0xf); + rtlefuse->pwrgroup_ht40[rf_path][i] = + ((rtlefuse->eeprom_pwrgroup[rf_path][index] & + 0xf0) >> 4); + + RTPRINT(rtlpriv, FINIT, INIT_TxPower, + "RF-%d pwrgroup_ht20[%d] = 0x%x\n", + rf_path, i, + rtlefuse->pwrgroup_ht20[rf_path][i]); + RTPRINT(rtlpriv, FINIT, INIT_TxPower, + "RF-%d pwrgroup_ht40[%d] = 0x%x\n", + rf_path, i, + rtlefuse->pwrgroup_ht40[rf_path][i]); + } + } + + for (i = 0; i < 14; i++) { + /* Read tx power difference between HT OFDM 20/40 MHZ */ + /* channel 1-3 */ + if (i < 3) + index = 0; + /* Channel 4-8 */ + else if (i < 8) + index = 1; + /* Channel 9-14 */ + else + index = 2; + + tempval = (*(u8 *)&hwinfo[EEPROM_TX_PWR_HT20_DIFF + + index]) & 0xff; + rtlefuse->txpwr_ht20diff[RF90_PATH_A][i] = (tempval & 0xF); + rtlefuse->txpwr_ht20diff[RF90_PATH_B][i] = + ((tempval >> 4) & 0xF); + + /* Read OFDM<->HT tx power diff */ + /* Channel 1-3 */ + if (i < 3) + index = 0; + /* Channel 4-8 */ + else if (i < 8) + index = 0x11; + /* Channel 9-14 */ + else + index = 1; + + tempval = (*(u8 *)&hwinfo[EEPROM_TX_PWR_OFDM_DIFF + index]) + & 0xff; + rtlefuse->txpwr_legacyhtdiff[RF90_PATH_A][i] = + (tempval & 0xF); + rtlefuse->txpwr_legacyhtdiff[RF90_PATH_B][i] = + ((tempval >> 4) & 0xF); + + tempval = (*(u8 *)&hwinfo[TX_PWR_SAFETY_CHK]); + rtlefuse->txpwr_safetyflag = (tempval & 0x01); + } + + rtlefuse->eeprom_regulatory = 0; + if (rtlefuse->eeprom_version >= 2) { + /* BIT(0)~2 */ + if (rtlefuse->eeprom_version >= 4) + rtlefuse->eeprom_regulatory = + (hwinfo[EEPROM_REGULATORY] & 0x7); + else /* BIT(0) */ + rtlefuse->eeprom_regulatory = + (hwinfo[EEPROM_REGULATORY] & 0x1); + } + RTPRINT(rtlpriv, FINIT, INIT_TxPower, + "eeprom_regulatory = 0x%x\n", rtlefuse->eeprom_regulatory); + + for (i = 0; i < 14; i++) + RTPRINT(rtlpriv, FINIT, INIT_TxPower, + "RF-A Ht20 to HT40 Diff[%d] = 0x%x\n", + i, rtlefuse->txpwr_ht20diff[RF90_PATH_A][i]); + for (i = 0; i < 14; i++) + RTPRINT(rtlpriv, FINIT, INIT_TxPower, + "RF-A Legacy to Ht40 Diff[%d] = 0x%x\n", + i, rtlefuse->txpwr_legacyhtdiff[RF90_PATH_A][i]); + for (i = 0; i < 14; i++) + RTPRINT(rtlpriv, FINIT, INIT_TxPower, + "RF-B Ht20 to HT40 Diff[%d] = 0x%x\n", + i, rtlefuse->txpwr_ht20diff[RF90_PATH_B][i]); + for (i = 0; i < 14; i++) + RTPRINT(rtlpriv, FINIT, INIT_TxPower, + "RF-B Legacy to HT40 Diff[%d] = 0x%x\n", + i, rtlefuse->txpwr_legacyhtdiff[RF90_PATH_B][i]); + + RTPRINT(rtlpriv, FINIT, INIT_TxPower, + "TxPwrSafetyFlag = %d\n", rtlefuse->txpwr_safetyflag); + + /* Read RF-indication and Tx Power gain + * index diff of legacy to HT OFDM rate. */ + tempval = (*(u8 *)&hwinfo[EEPROM_RFIND_POWERDIFF]) & 0xff; + rtlefuse->eeprom_txpowerdiff = tempval; + rtlefuse->legacy_httxpowerdiff = + rtlefuse->txpwr_legacyhtdiff[RF90_PATH_A][0]; + + RTPRINT(rtlpriv, FINIT, INIT_TxPower, + "TxPowerDiff = %#x\n", rtlefuse->eeprom_txpowerdiff); + + /* Get TSSI value for each path. */ + usvalue = *(u16 *)&hwinfo[EEPROM_TSSI_A]; + rtlefuse->eeprom_tssi[RF90_PATH_A] = (u8)((usvalue & 0xff00) >> 8); + usvalue = *(u8 *)&hwinfo[EEPROM_TSSI_B]; + rtlefuse->eeprom_tssi[RF90_PATH_B] = (u8)(usvalue & 0xff); + + RTPRINT(rtlpriv, FINIT, INIT_TxPower, "TSSI_A = 0x%x, TSSI_B = 0x%x\n", + rtlefuse->eeprom_tssi[RF90_PATH_A], + rtlefuse->eeprom_tssi[RF90_PATH_B]); + + /* Read antenna tx power offset of B/C/D to A from EEPROM */ + /* and read ThermalMeter from EEPROM */ + tempval = *(u8 *)&hwinfo[EEPROM_THERMALMETER]; + rtlefuse->eeprom_thermalmeter = tempval; + RTPRINT(rtlpriv, FINIT, INIT_TxPower, + "thermalmeter = 0x%x\n", rtlefuse->eeprom_thermalmeter); + + /* ThermalMeter, BIT(0)~3 for RFIC1, BIT(4)~7 for RFIC2 */ + rtlefuse->thermalmeter[0] = (rtlefuse->eeprom_thermalmeter & 0x1f); + rtlefuse->tssi_13dbm = rtlefuse->eeprom_thermalmeter * 100; + + /* Read CrystalCap from EEPROM */ + tempval = (*(u8 *)&hwinfo[EEPROM_CRYSTALCAP]) >> 4; + rtlefuse->eeprom_crystalcap = tempval; + /* CrystalCap, BIT(12)~15 */ + rtlefuse->crystalcap = rtlefuse->eeprom_crystalcap; + + /* Read IC Version && Channel Plan */ + /* Version ID, Channel plan */ + rtlefuse->eeprom_channelplan = *(u8 *)&hwinfo[EEPROM_CHANNELPLAN]; + rtlefuse->txpwr_fromeprom = true; + RTPRINT(rtlpriv, FINIT, INIT_TxPower, + "EEPROM ChannelPlan = 0x%4x\n", rtlefuse->eeprom_channelplan); + + /* Read Customer ID or Board Type!!! */ + tempval = *(u8 *)&hwinfo[EEPROM_BOARDTYPE]; + /* Change RF type definition */ + if (tempval == 0) + rtlphy->rf_type = RF_2T2R; + else if (tempval == 1) + rtlphy->rf_type = RF_1T2R; + else if (tempval == 2) + rtlphy->rf_type = RF_1T2R; + else if (tempval == 3) + rtlphy->rf_type = RF_1T1R; + + /* 1T2R but 1SS (1x1 receive combining) */ + rtlefuse->b1x1_recvcombine = false; + if (rtlphy->rf_type == RF_1T2R) { + tempval = rtl_read_byte(rtlpriv, 0x07); + if (!(tempval & BIT(0))) { + rtlefuse->b1x1_recvcombine = true; + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "RF_TYPE=1T2R but only 1SS\n"); + } + } + rtlefuse->b1ss_support = rtlefuse->b1x1_recvcombine; + rtlefuse->eeprom_oemid = *(u8 *)&hwinfo[EEPROM_CUSTOMID]; + + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "EEPROM Customer ID: 0x%2x", + rtlefuse->eeprom_oemid); + + /* set channel paln to world wide 13 */ + rtlefuse->channel_plan = COUNTRY_CODE_WORLD_WIDE_13; +} + +void rtl92se_read_eeprom_info(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + u8 tmp_u1b = 0; + + tmp_u1b = rtl_read_byte(rtlpriv, EPROM_CMD); + + if (tmp_u1b & BIT(4)) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "Boot from EEPROM\n"); + rtlefuse->epromtype = EEPROM_93C46; + } else { + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "Boot from EFUSE\n"); + rtlefuse->epromtype = EEPROM_BOOT_EFUSE; + } + + if (tmp_u1b & BIT(5)) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "Autoload OK\n"); + rtlefuse->autoload_failflag = false; + _rtl92se_read_adapter_info(hw); + } else { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Autoload ERR!!\n"); + rtlefuse->autoload_failflag = true; + } +} + +static void rtl92se_update_hal_rate_table(struct ieee80211_hw *hw, + struct ieee80211_sta *sta) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u32 ratr_value; + u8 ratr_index = 0; + u8 nmode = mac->ht_enable; + u8 mimo_ps = IEEE80211_SMPS_OFF; + u16 shortgi_rate = 0; + u32 tmp_ratr_value = 0; + u8 curtxbw_40mhz = mac->bw_40; + u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ? + 1 : 0; + u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ? + 1 : 0; + enum wireless_mode wirelessmode = mac->mode; + + if (rtlhal->current_bandtype == BAND_ON_5G) + ratr_value = sta->supp_rates[1] << 4; + else + ratr_value = sta->supp_rates[0]; + ratr_value |= (sta->ht_cap.mcs.rx_mask[1] << 20 | + sta->ht_cap.mcs.rx_mask[0] << 12); + switch (wirelessmode) { + case WIRELESS_MODE_B: + ratr_value &= 0x0000000D; + break; + case WIRELESS_MODE_G: + ratr_value &= 0x00000FF5; + break; + case WIRELESS_MODE_N_24G: + case WIRELESS_MODE_N_5G: + nmode = 1; + if (mimo_ps == IEEE80211_SMPS_STATIC) { + ratr_value &= 0x0007F005; + } else { + u32 ratr_mask; + + if (get_rf_type(rtlphy) == RF_1T2R || + get_rf_type(rtlphy) == RF_1T1R) { + if (curtxbw_40mhz) + ratr_mask = 0x000ff015; + else + ratr_mask = 0x000ff005; + } else { + if (curtxbw_40mhz) + ratr_mask = 0x0f0ff015; + else + ratr_mask = 0x0f0ff005; + } + + ratr_value &= ratr_mask; + } + break; + default: + if (rtlphy->rf_type == RF_1T2R) + ratr_value &= 0x000ff0ff; + else + ratr_value &= 0x0f0ff0ff; + + break; + } + + if (rtlpriv->rtlhal.version >= VERSION_8192S_BCUT) + ratr_value &= 0x0FFFFFFF; + else if (rtlpriv->rtlhal.version == VERSION_8192S_ACUT) + ratr_value &= 0x0FFFFFF0; + + if (nmode && ((curtxbw_40mhz && + curshortgi_40mhz) || (!curtxbw_40mhz && + curshortgi_20mhz))) { + + ratr_value |= 0x10000000; + tmp_ratr_value = (ratr_value >> 12); + + for (shortgi_rate = 15; shortgi_rate > 0; shortgi_rate--) { + if ((1 << shortgi_rate) & tmp_ratr_value) + break; + } + + shortgi_rate = (shortgi_rate << 12) | (shortgi_rate << 8) | + (shortgi_rate << 4) | (shortgi_rate); + + rtl_write_byte(rtlpriv, SG_RATE, shortgi_rate); + } + + rtl_write_dword(rtlpriv, ARFR0 + ratr_index * 4, ratr_value); + if (ratr_value & 0xfffff000) + rtl92s_phy_set_fw_cmd(hw, FW_CMD_RA_REFRESH_N); + else + rtl92s_phy_set_fw_cmd(hw, FW_CMD_RA_REFRESH_BG); + + RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG, "%x\n", + rtl_read_dword(rtlpriv, ARFR0)); +} + +static void rtl92se_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_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_sta_info *sta_entry = NULL; + u32 ratr_bitmap; + u8 ratr_index = 0; + u8 curtxbw_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) + ? 1 : 0; + u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ? + 1 : 0; + u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ? + 1 : 0; + enum wireless_mode wirelessmode = 0; + bool shortgi = false; + u32 ratr_value = 0; + u8 shortgi_rate = 0; + u32 mask = 0; + u32 band = 0; + bool bmulticast = false; + 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) + curtxbw_40mhz = mac->bw_40; + else if (mac->opmode == NL80211_IFTYPE_AP || + mac->opmode == NL80211_IFTYPE_ADHOC) + macid = sta->aid + 1; + + if (rtlhal->current_bandtype == BAND_ON_5G) + ratr_bitmap = sta->supp_rates[1] << 4; + else + ratr_bitmap = sta->supp_rates[0]; + ratr_bitmap |= (sta->ht_cap.mcs.rx_mask[1] << 20 | + sta->ht_cap.mcs.rx_mask[0] << 12); + switch (wirelessmode) { + case WIRELESS_MODE_B: + band |= WIRELESS_11B; + ratr_index = RATR_INX_WIRELESS_B; + if (ratr_bitmap & 0x0000000c) + ratr_bitmap &= 0x0000000d; + else + ratr_bitmap &= 0x0000000f; + break; + case WIRELESS_MODE_G: + band |= (WIRELESS_11G | WIRELESS_11B); + 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_A: + band |= WIRELESS_11A; + ratr_index = RATR_INX_WIRELESS_A; + ratr_bitmap &= 0x00000ff0; + break; + case WIRELESS_MODE_N_24G: + case WIRELESS_MODE_N_5G: + band |= (WIRELESS_11N | WIRELESS_11G | WIRELESS_11B); + ratr_index = RATR_INX_WIRELESS_NGB; + + if (mimo_ps == IEEE80211_SMPS_STATIC) { + if (rssi_level == 1) + ratr_bitmap &= 0x00070000; + else if (rssi_level == 2) + ratr_bitmap &= 0x0007f000; + else + ratr_bitmap &= 0x0007f005; + } else { + if (rtlphy->rf_type == RF_1T2R || + rtlphy->rf_type == RF_1T1R) { + if (rssi_level == 1) { + ratr_bitmap &= 0x000f0000; + } else if (rssi_level == 3) { + ratr_bitmap &= 0x000fc000; + } else if (rssi_level == 5) { + ratr_bitmap &= 0x000ff000; + } else { + if (curtxbw_40mhz) + ratr_bitmap &= 0x000ff015; + else + ratr_bitmap &= 0x000ff005; + } + } else { + if (rssi_level == 1) { + ratr_bitmap &= 0x0f8f0000; + } else if (rssi_level == 3) { + ratr_bitmap &= 0x0f8fc000; + } else if (rssi_level == 5) { + ratr_bitmap &= 0x0f8ff000; + } else { + if (curtxbw_40mhz) + ratr_bitmap &= 0x0f8ff015; + else + ratr_bitmap &= 0x0f8ff005; + } + } + } + + if ((curtxbw_40mhz && curshortgi_40mhz) || + (!curtxbw_40mhz && curshortgi_20mhz)) { + if (macid == 0) + shortgi = true; + else if (macid == 1) + shortgi = false; + } + break; + default: + band |= (WIRELESS_11N | WIRELESS_11G | WIRELESS_11B); + ratr_index = RATR_INX_WIRELESS_NGB; + + if (rtlphy->rf_type == RF_1T2R) + ratr_bitmap &= 0x000ff0ff; + else + ratr_bitmap &= 0x0f8ff0ff; + break; + } + + if (rtlpriv->rtlhal.version >= VERSION_8192S_BCUT) + ratr_bitmap &= 0x0FFFFFFF; + else if (rtlpriv->rtlhal.version == VERSION_8192S_ACUT) + ratr_bitmap &= 0x0FFFFFF0; + + if (shortgi) { + ratr_bitmap |= 0x10000000; + /* Get MAX MCS available. */ + ratr_value = (ratr_bitmap >> 12); + for (shortgi_rate = 15; shortgi_rate > 0; shortgi_rate--) { + if ((1 << shortgi_rate) & ratr_value) + break; + } + + shortgi_rate = (shortgi_rate << 12) | (shortgi_rate << 8) | + (shortgi_rate << 4) | (shortgi_rate); + rtl_write_byte(rtlpriv, SG_RATE, shortgi_rate); + } + + mask |= (bmulticast ? 1 : 0) << 9 | (macid & 0x1f) << 4 | (band & 0xf); + + RT_TRACE(rtlpriv, COMP_RATR, DBG_TRACE, "mask = %x, bitmap = %x\n", + mask, ratr_bitmap); + rtl_write_dword(rtlpriv, 0x2c4, ratr_bitmap); + rtl_write_dword(rtlpriv, WFM5, (FW_RA_UPDATE_MASK | (mask << 8))); + + if (macid != 0) + sta_entry->ratr_index = ratr_index; +} + +void rtl92se_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.useramask) + rtl92se_update_hal_rate_mask(hw, sta, rssi_level); + else + rtl92se_update_hal_rate_table(hw, sta); +} + +void rtl92se_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); + sifs_timer = 0x0e0e; + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SIFS, (u8 *)&sifs_timer); + +} + +/* this ifunction is for RFKILL, it's different with windows, + * because UI will disable wireless when GPIO Radio Off. + * And here we not check or Disable/Enable ASPM like windows*/ +bool rtl92se_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 *valid) +{ + 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)); + enum rf_pwrstate rfpwr_toset /*, cur_rfstate */; + unsigned long flag = 0; + bool actuallyset = false; + bool turnonbypowerdomain = false; + + /* just 8191se can check gpio before firstup, 92c/92d have fixed it */ + if ((rtlpci->up_first_time == 1) || (rtlpci->being_init_adapter)) + return false; + + if (ppsc->swrf_processing) + return false; + + spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flag); + if (ppsc->rfchange_inprogress) { + spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag); + return false; + } else { + ppsc->rfchange_inprogress = true; + spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag); + } + + /* cur_rfstate = ppsc->rfpwr_state;*/ + + /* because after _rtl92s_phy_set_rfhalt, all power + * closed, so we must open some power for GPIO check, + * or we will always check GPIO RFOFF here, + * And we should close power after GPIO check */ + if (RT_IN_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC)) { + _rtl92se_power_domain_init(hw); + turnonbypowerdomain = true; + } + + rfpwr_toset = _rtl92se_rf_onoff_detect(hw); + + if ((ppsc->hwradiooff) && (rfpwr_toset == ERFON)) { + RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG, + "RFKILL-HW Radio ON, RF ON\n"); + + rfpwr_toset = ERFON; + ppsc->hwradiooff = false; + actuallyset = true; + } else if ((!ppsc->hwradiooff) && (rfpwr_toset == ERFOFF)) { + RT_TRACE(rtlpriv, COMP_RF, + DBG_DMESG, "RFKILL-HW Radio OFF, RF OFF\n"); + + rfpwr_toset = ERFOFF; + ppsc->hwradiooff = true; + actuallyset = true; + } + + if (actuallyset) { + spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flag); + ppsc->rfchange_inprogress = false; + spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag); + + /* this not include ifconfig wlan0 down case */ + /* } else if (rfpwr_toset == ERFOFF || cur_rfstate == ERFOFF) { */ + } else { + /* because power_domain_init may be happen when + * _rtl92s_phy_set_rfhalt, this will open some powers + * and cause current increasing about 40 mA for ips, + * rfoff and ifconfig down, so we set + * _rtl92s_phy_set_rfhalt again here */ + if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_HALT_NIC && + turnonbypowerdomain) { + _rtl92s_phy_set_rfhalt(hw); + RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC); + } + + spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flag); + ppsc->rfchange_inprogress = false; + spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag); + } + + *valid = 1; + return !ppsc->hwradiooff; + +} + +/* Is_wepkey just used for WEP used as group & pairwise key + * if pairwise is AES ang group is WEP Is_wepkey == false.*/ +void rtl92se_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(rtlpriv, COMP_SEC, DBG_DMESG, "clear_all\n"); + + for (idx = 0; idx < clear_number; idx++) { + rtl_cam_mark_invalid(hw, cam_offset + idx); + 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(rtlpriv, COMP_ERR, DBG_EMERG, + "switch case not processed\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) { + entry_id = rtl_cam_get_free_entry(hw, + p_macaddr); + if (entry_id >= TOTAL_CAM_ENTRY) { + RT_TRACE(rtlpriv, + 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(rtlpriv, COMP_SEC, DBG_DMESG, + "delete one entry, entry_id is %d\n", + entry_id); + if (mac->opmode == NL80211_IFTYPE_AP) + rtl_cam_del_entry(hw, p_macaddr); + rtl_cam_delete_one_entry(hw, p_macaddr, entry_id); + } else { + RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, + "The insert KEY length is %d\n", + rtlpriv->sec.key_len[PAIRWISE_KEYIDX]); + RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, + "The insert KEY is %x %x\n", + rtlpriv->sec.key_buf[0][0], + rtlpriv->sec.key_buf[0][1]); + + RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, + "add one entry\n"); + if (is_pairwise) { + RT_PRINT_DATA(rtlpriv, COMP_SEC, DBG_LOUD, + "Pairwise Key content", + rtlpriv->sec.pairwise_key, + rtlpriv->sec. + key_len[PAIRWISE_KEYIDX]); + + RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, + "set Pairwise key\n"); + + 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(rtlpriv, COMP_SEC, DBG_DMESG, + "set group key\n"); + + if (mac->opmode == NL80211_IFTYPE_ADHOC) { + 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]); + } + + rtl_cam_add_one_entry(hw, macaddr, key_index, + entry_id, enc_algo, + CAM_CONFIG_NO_USEDK, + rtlpriv->sec.key_buf[entry_id]); + } + + } + } +} + +void rtl92se_suspend(struct ieee80211_hw *hw) +{ + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + + rtlpci->up_first_time = true; +} + +void rtl92se_resume(struct ieee80211_hw *hw) +{ + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + u32 val; + + pci_read_config_dword(rtlpci->pdev, 0x40, &val); + if ((val & 0x0000ff00) != 0) + pci_write_config_dword(rtlpci->pdev, 0x40, + val & 0xffff00ff); +} diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/hw.h b/drivers/net/wireless/rtlwifi/rtl8192se/hw.h new file mode 100644 index 00000000..1886c264 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192se/hw.h @@ -0,0 +1,79 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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 __REALTEK_PCI92SE_HW_H__ +#define __REALTEK_PCI92SE_HW_H__ + +#define MSR_LINK_MANAGED 2 +#define MSR_LINK_NONE 0 +#define MSR_LINK_SHIFT 0 +#define MSR_LINK_ADHOC 1 +#define MSR_LINK_MASTER 3 + +enum WIRELESS_NETWORK_TYPE { + WIRELESS_11B = 1, + WIRELESS_11G = 2, + WIRELESS_11A = 4, + WIRELESS_11N = 8 +}; + +void rtl92se_get_hw_reg(struct ieee80211_hw *hw, + u8 variable, u8 *val); +void rtl92se_read_eeprom_info(struct ieee80211_hw *hw); +void rtl92se_interrupt_recognized(struct ieee80211_hw *hw, + u32 *inta, u32 *intb); +int rtl92se_hw_init(struct ieee80211_hw *hw); +void rtl92se_card_disable(struct ieee80211_hw *hw); +void rtl92se_enable_interrupt(struct ieee80211_hw *hw); +void rtl92se_disable_interrupt(struct ieee80211_hw *hw); +int rtl92se_set_network_type(struct ieee80211_hw *hw, + enum nl80211_iftype type); +void rtl92se_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid); +void rtl92se_set_mac_addr(struct rtl_io *io, const u8 * addr); +void rtl92se_set_qos(struct ieee80211_hw *hw, int aci); +void rtl92se_set_beacon_related_registers(struct ieee80211_hw *hw); +void rtl92se_set_beacon_interval(struct ieee80211_hw *hw); +void rtl92se_update_interrupt_mask(struct ieee80211_hw *hw, + u32 add_msr, u32 rm_msr); +void rtl92se_set_hw_reg(struct ieee80211_hw *hw, u8 variable, + u8 *val); +void rtl92se_update_hal_rate_tbl(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, u8 rssi_level); +void rtl92se_update_channel_access_setting(struct ieee80211_hw *hw); +bool rtl92se_gpio_radio_on_off_checking(struct ieee80211_hw *hw, + u8 *valid); +void rtl8192se_gpiobit3_cfg_inputmode(struct ieee80211_hw *hw); +void rtl92se_enable_hw_security_config(struct ieee80211_hw *hw); +void rtl92se_set_key(struct ieee80211_hw *hw, + u32 key_index, u8 *macaddr, bool is_group, + u8 enc_algo, bool is_wepkey, bool clear_all); +void rtl92se_suspend(struct ieee80211_hw *hw); +void rtl92se_resume(struct ieee80211_hw *hw); + +#endif + diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/led.c b/drivers/net/wireless/rtlwifi/rtl8192se/led.c new file mode 100644 index 00000000..44949b5c --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192se/led.c @@ -0,0 +1,151 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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> + * + *****************************************************************************/ + +#include "../wifi.h" +#include "../pci.h" +#include "reg.h" +#include "led.h" + +static void _rtl92se_init_led(struct ieee80211_hw *hw, + struct rtl_led *pled, enum rtl_led_pin ledpin) +{ + pled->hw = hw; + pled->ledpin = ledpin; + pled->ledon = false; +} + +void rtl92se_init_sw_leds(struct ieee80211_hw *hw) +{ + struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); + _rtl92se_init_led(hw, &(pcipriv->ledctl.sw_led0), LED_PIN_LED0); + _rtl92se_init_led(hw, &(pcipriv->ledctl.sw_led1), LED_PIN_LED1); +} + +void rtl92se_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled) +{ + u8 ledcfg; + struct rtl_priv *rtlpriv = rtl_priv(hw); + + RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD, "LedAddr:%X ledpin=%d\n", + LEDCFG, pled->ledpin); + + ledcfg = rtl_read_byte(rtlpriv, LEDCFG); + + switch (pled->ledpin) { + case LED_PIN_GPIO0: + break; + case LED_PIN_LED0: + rtl_write_byte(rtlpriv, LEDCFG, ledcfg & 0xf0); + break; + case LED_PIN_LED1: + rtl_write_byte(rtlpriv, LEDCFG, ledcfg & 0x0f); + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "switch case not processed\n"); + break; + } + pled->ledon = true; +} + +void rtl92se_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled) +{ + struct rtl_priv *rtlpriv; + struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); + u8 ledcfg; + + rtlpriv = rtl_priv(hw); + if (!rtlpriv || rtlpriv->max_fw_size) + return; + RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD, "LedAddr:%X ledpin=%d\n", + LEDCFG, pled->ledpin); + + ledcfg = rtl_read_byte(rtlpriv, LEDCFG); + + switch (pled->ledpin) { + case LED_PIN_GPIO0: + break; + case LED_PIN_LED0: + ledcfg &= 0xf0; + if (pcipriv->ledctl.led_opendrain) + rtl_write_byte(rtlpriv, LEDCFG, (ledcfg | BIT(1))); + else + rtl_write_byte(rtlpriv, LEDCFG, (ledcfg | BIT(3))); + break; + case LED_PIN_LED1: + ledcfg &= 0x0f; + rtl_write_byte(rtlpriv, LEDCFG, (ledcfg | BIT(3))); + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "switch case not processed\n"); + break; + } + pled->ledon = false; +} + +static void _rtl92se_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: + rtl92se_sw_led_on(hw, pLed0); + break; + case LED_CTL_POWER_OFF: + rtl92se_sw_led_off(hw, pLed0); + break; + default: + break; + } +} + +void rtl92se_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(rtlpriv, COMP_LED, DBG_LOUD, "ledaction %d\n", ledaction); + + _rtl92se_sw_led_control(hw, ledaction); +} + diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/led.h b/drivers/net/wireless/rtlwifi/rtl8192se/led.h new file mode 100644 index 00000000..2182dbeb --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192se/led.h @@ -0,0 +1,37 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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 __REALTEK_PCI92SE_LED_H__ +#define __REALTEK_PCI92SE_LED_H__ + +void rtl92se_init_sw_leds(struct ieee80211_hw *hw); +void rtl92se_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled); +void rtl92se_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled); +void rtl92se_led_control(struct ieee80211_hw *hw, enum led_ctl_mode ledaction); + +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/phy.c b/drivers/net/wireless/rtlwifi/rtl8192se/phy.c new file mode 100644 index 00000000..4a499928 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192se/phy.c @@ -0,0 +1,1718 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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> + * + *****************************************************************************/ + +#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 "fw.h" +#include "hw.h" +#include "table.h" + +static u32 _rtl92s_phy_calculate_bit_shift(u32 bitmask) +{ + u32 i; + + for (i = 0; i <= 31; i++) { + if (((bitmask >> i) & 0x1) == 1) + break; + } + + return i; +} + +u32 rtl92s_phy_query_bb_reg(struct ieee80211_hw *hw, u32 regaddr, u32 bitmask) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 returnvalue = 0, originalvalue, bitshift; + + RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, "regaddr(%#x), bitmask(%#x)\n", + regaddr, bitmask); + + originalvalue = rtl_read_dword(rtlpriv, regaddr); + bitshift = _rtl92s_phy_calculate_bit_shift(bitmask); + returnvalue = (originalvalue & bitmask) >> bitshift; + + RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, "BBR MASK=0x%x Addr[0x%x]=0x%x\n", + bitmask, regaddr, originalvalue); + + return returnvalue; + +} + +void rtl92s_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(rtlpriv, COMP_RF, DBG_TRACE, + "regaddr(%#x), bitmask(%#x), data(%#x)\n", + regaddr, bitmask, data); + + if (bitmask != MASKDWORD) { + originalvalue = rtl_read_dword(rtlpriv, regaddr); + bitshift = _rtl92s_phy_calculate_bit_shift(bitmask); + data = ((originalvalue & (~bitmask)) | (data << bitshift)); + } + + rtl_write_dword(rtlpriv, regaddr, data); + + RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, + "regaddr(%#x), bitmask(%#x), data(%#x)\n", + regaddr, bitmask, data); + +} + +static u32 _rtl92s_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 = 0; + + offset &= 0x3f; + newoffset = offset; + + 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 & (~BLSSI_READADDRESS)) | (newoffset << 23) | + BLSSI_READEDGE; + + rtl_set_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, MASKDWORD, + tmplong & (~BLSSI_READEDGE)); + + mdelay(1); + + rtl_set_bbreg(hw, pphyreg->rfhssi_para2, MASKDWORD, tmplong2); + mdelay(1); + + rtl_set_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, MASKDWORD, tmplong | + BLSSI_READEDGE); + 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, + BLSSI_READBACK_DATA); + else + retvalue = rtl_get_bbreg(hw, pphyreg->rflssi_readback, + BLSSI_READBACK_DATA); + + retvalue = rtl_get_bbreg(hw, pphyreg->rflssi_readback, + BLSSI_READBACK_DATA); + + RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, "RFR-%d Addr[0x%x]=0x%x\n", + rfpath, pphyreg->rflssi_readback, retvalue); + + return retvalue; + +} + +static void _rtl92s_phy_rf_serial_write(struct ieee80211_hw *hw, + enum radio_path rfpath, u32 offset, + u32 data) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct bb_reg_def *pphyreg = &rtlphy->phyreg_def[rfpath]; + u32 data_and_addr = 0; + u32 newoffset; + + offset &= 0x3f; + newoffset = offset; + + data_and_addr = ((newoffset << 20) | (data & 0x000fffff)) & 0x0fffffff; + rtl_set_bbreg(hw, pphyreg->rf3wire_offset, MASKDWORD, data_and_addr); + + RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, "RFW-%d Addr[0x%x]=0x%x\n", + rfpath, pphyreg->rf3wire_offset, data_and_addr); +} + + +u32 rtl92s_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; + + RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, + "regaddr(%#x), rfpath(%#x), bitmask(%#x)\n", + regaddr, rfpath, bitmask); + + spin_lock(&rtlpriv->locks.rf_lock); + + original_value = _rtl92s_phy_rf_serial_read(hw, rfpath, regaddr); + + bitshift = _rtl92s_phy_calculate_bit_shift(bitmask); + readback_value = (original_value & bitmask) >> bitshift; + + spin_unlock(&rtlpriv->locks.rf_lock); + + RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, + "regaddr(%#x), rfpath(%#x), bitmask(%#x), original_value(%#x)\n", + regaddr, rfpath, bitmask, original_value); + + return readback_value; +} + +void rtl92s_phy_set_rf_reg(struct ieee80211_hw *hw, enum radio_path rfpath, + u32 regaddr, u32 bitmask, u32 data) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + u32 original_value, bitshift; + + if (!((rtlphy->rf_pathmap >> rfpath) & 0x1)) + return; + + RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, + "regaddr(%#x), bitmask(%#x), data(%#x), rfpath(%#x)\n", + regaddr, bitmask, data, rfpath); + + spin_lock(&rtlpriv->locks.rf_lock); + + if (bitmask != RFREG_OFFSET_MASK) { + original_value = _rtl92s_phy_rf_serial_read(hw, rfpath, + regaddr); + bitshift = _rtl92s_phy_calculate_bit_shift(bitmask); + data = ((original_value & (~bitmask)) | (data << bitshift)); + } + + _rtl92s_phy_rf_serial_write(hw, rfpath, regaddr, data); + + spin_unlock(&rtlpriv->locks.rf_lock); + + RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, + "regaddr(%#x), bitmask(%#x), data(%#x), rfpath(%#x)\n", + regaddr, bitmask, data, rfpath); + +} + +void rtl92s_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)); + + if (!is_hal_stop(rtlhal)) { + switch (operation) { + case SCAN_OPT_BACKUP: + rtl92s_phy_set_fw_cmd(hw, FW_CMD_PAUSE_DM_BY_SCAN); + break; + case SCAN_OPT_RESTORE: + rtl92s_phy_set_fw_cmd(hw, FW_CMD_RESUME_DM_BY_SCAN); + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "Unknown operation\n"); + break; + } + } +} + +void rtl92s_phy_set_bw_mode(struct ieee80211_hw *hw, + enum nl80211_channel_type ch_type) +{ + 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; + + RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE, "Switch to %s bandwidth\n", + rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20 ? + "20MHz" : "40MHz"); + + if (rtlphy->set_bwmode_inprogress) + return; + if (is_hal_stop(rtlhal)) + return; + + rtlphy->set_bwmode_inprogress = true; + + reg_bw_opmode = rtl_read_byte(rtlpriv, BW_OPMODE); + /* dummy read */ + rtl_read_byte(rtlpriv, RRSR + 2); + + switch (rtlphy->current_chan_bw) { + case HT_CHANNEL_WIDTH_20: + reg_bw_opmode |= BW_OPMODE_20MHZ; + rtl_write_byte(rtlpriv, BW_OPMODE, reg_bw_opmode); + break; + case HT_CHANNEL_WIDTH_20_40: + reg_bw_opmode &= ~BW_OPMODE_20MHZ; + rtl_write_byte(rtlpriv, BW_OPMODE, reg_bw_opmode); + break; + default: + RT_TRACE(rtlpriv, 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); + + if (rtlhal->version >= VERSION_8192S_BCUT) + rtl_write_byte(rtlpriv, RFPGA0_ANALOGPARAMETER2, 0x58); + 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); + + if (rtlhal->version >= VERSION_8192S_BCUT) + rtl_write_byte(rtlpriv, RFPGA0_ANALOGPARAMETER2, 0x18); + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "unknown bandwidth: %#X\n", rtlphy->current_chan_bw); + break; + } + + rtl92s_phy_rf6052_set_bandwidth(hw, rtlphy->current_chan_bw); + rtlphy->set_bwmode_inprogress = false; + RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE, "<==\n"); +} + +static bool _rtl92s_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 bool _rtl92s_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; + _rtl92s_phy_set_sw_chnl_cmdarray(precommoncmd, precommoncmdcnt++, + MAX_PRECMD_CNT, CMDID_SET_TXPOWEROWER_LEVEL, 0, 0, 0); + _rtl92s_phy_set_sw_chnl_cmdarray(precommoncmd, precommoncmdcnt++, + MAX_PRECMD_CNT, CMDID_END, 0, 0, 0); + + postcommoncmdcnt = 0; + + _rtl92s_phy_set_sw_chnl_cmdarray(postcommoncmd, postcommoncmdcnt++, + MAX_POSTCMD_CNT, CMDID_END, 0, 0, 0); + + rfdependcmdcnt = 0; + + RT_ASSERT((channel >= 1 && channel <= 14), + "invalid channel for Zebra: %d\n", channel); + + _rtl92s_phy_set_sw_chnl_cmdarray(rfdependcmd, rfdependcmdcnt++, + MAX_RFDEPENDCMD_CNT, CMDID_RF_WRITEREG, + RF_CHNLBW, channel, 10); + + _rtl92s_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; + } + + if (currentcmd->cmdid == CMDID_END) { + if ((*stage) == 2) { + return true; + } else { + (*stage)++; + (*step) = 0; + continue; + } + } + + switch (currentcmd->cmdid) { + case CMDID_SET_TXPOWEROWER_LEVEL: + rtl92s_phy_set_txpower(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] & + 0xfffffc00) | currentcmd->para2); + rtl_set_rfreg(hw, (enum radio_path)rfpath, + currentcmd->para1, + RFREG_OFFSET_MASK, + rtlphy->rfreg_chnlval[rfpath]); + } + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "switch case not processed\n"); + break; + } + + break; + } while (true); + + (*delay) = currentcmd->msdelay; + (*step)++; + return false; +} + +u8 rtl92s_phy_sw_chnl(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; + bool ret; + + RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE, "switch to channel%d\n", + rtlphy->current_channel); + + if (rtlphy->sw_chnl_inprogress) + return 0; + + if (rtlphy->set_bwmode_inprogress) + return 0; + + if (is_hal_stop(rtlhal)) + return 0; + + rtlphy->sw_chnl_inprogress = true; + rtlphy->sw_chnl_stage = 0; + rtlphy->sw_chnl_step = 0; + + do { + if (!rtlphy->sw_chnl_inprogress) + break; + + ret = _rtl92s_phy_sw_chnl_step_by_step(hw, + rtlphy->current_channel, + &rtlphy->sw_chnl_stage, + &rtlphy->sw_chnl_step, &delay); + if (!ret) { + if (delay > 0) + mdelay(delay); + else + continue; + } else { + rtlphy->sw_chnl_inprogress = false; + } + break; + } while (true); + + rtlphy->sw_chnl_inprogress = false; + + RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE, "<==\n"); + + return 1; +} + +static void _rtl92se_phy_set_rf_sleep(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 u1btmp; + + u1btmp = rtl_read_byte(rtlpriv, LDOV12D_CTRL); + u1btmp |= BIT(0); + + rtl_write_byte(rtlpriv, LDOV12D_CTRL, u1btmp); + rtl_write_byte(rtlpriv, SPS1_CTRL, 0x0); + rtl_write_byte(rtlpriv, TXPAUSE, 0xFF); + rtl_write_word(rtlpriv, CMDR, 0x57FC); + udelay(100); + + rtl_write_word(rtlpriv, CMDR, 0x77FC); + rtl_write_byte(rtlpriv, PHY_CCA, 0x0); + udelay(10); + + rtl_write_word(rtlpriv, CMDR, 0x37FC); + udelay(10); + + rtl_write_word(rtlpriv, CMDR, 0x77FC); + udelay(10); + + rtl_write_word(rtlpriv, CMDR, 0x57FC); + + /* we should chnge GPIO to input mode + * this will drop away current about 25mA*/ + rtl8192se_gpiobit3_cfg_inputmode(hw); +} + +bool rtl92s_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; + + if (rfpwr_state == ppsc->rfpwr_state) + return false; + + switch (rfpwr_state) { + case ERFON:{ + if ((ppsc->rfpwr_state == ERFOFF) && + RT_IN_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC)) { + + bool rtstatus; + u32 InitializeCount = 0; + do { + InitializeCount++; + RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG, + "IPS Set eRf nic enable\n"); + rtstatus = rtl_ps_enable_nic(hw); + } while (!rtstatus && (InitializeCount < 10)); + + RT_CLEAR_PS_LEVEL(ppsc, + RT_RF_OFF_LEVL_HALT_NIC); + } else { + RT_TRACE(rtlpriv, COMP_POWER, DBG_DMESG, + "awake, sleeped:%d ms state_inap:%x\n", + jiffies_to_msecs(jiffies - + ppsc-> + last_sleep_jiffies), + rtlpriv->psc.state_inap); + ppsc->last_awake_jiffies = jiffies; + rtl_write_word(rtlpriv, CMDR, 0x37FC); + rtl_write_byte(rtlpriv, TXPAUSE, 0x00); + rtl_write_byte(rtlpriv, PHY_CCA, 0x3); + } + + 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:{ + if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_HALT_NIC) { + RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG, + "IPS Set eRf nic disable\n"); + 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) + return false; + + 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 == BEACON_QUEUE) { + queue_id++; + continue; + } else { + RT_TRACE(rtlpriv, 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(rtlpriv, COMP_ERR, DBG_WARNING, + "ERFOFF: %d times TcbBusyQueue[%d] = %d !\n", + MAX_DOZE_WAITING_TIMES_9x, + queue_id, + skb_queue_len(&ring->queue)); + break; + } + } + + RT_TRACE(rtlpriv, COMP_POWER, DBG_DMESG, + "Set ERFSLEEP awaked:%d ms\n", + jiffies_to_msecs(jiffies - + ppsc->last_awake_jiffies)); + + RT_TRACE(rtlpriv, COMP_POWER, DBG_DMESG, + "sleep awaked:%d ms state_inap:%x\n", + jiffies_to_msecs(jiffies - + ppsc->last_awake_jiffies), + rtlpriv->psc.state_inap); + ppsc->last_sleep_jiffies = jiffies; + _rtl92se_phy_set_rf_sleep(hw); + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "switch case not processed\n"); + bresult = false; + break; + } + + if (bresult) + ppsc->rfpwr_state = rfpwr_state; + + return bresult; +} + +static bool _rtl92s_phy_config_rfpa_bias_current(struct ieee80211_hw *hw, + enum radio_path rfpath) +{ + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + bool rtstatus = true; + u32 tmpval = 0; + + /* If inferiority IC, we have to increase the PA bias current */ + if (rtlhal->ic_class != IC_INFERIORITY_A) { + tmpval = rtl92s_phy_query_rf_reg(hw, rfpath, RF_IPA, 0xf); + rtl92s_phy_set_rf_reg(hw, rfpath, RF_IPA, 0xf, tmpval + 1); + } + + return rtstatus; +} + +static void _rtl92s_store_pwrindex_diffrate_offset(struct ieee80211_hw *hw, + u32 reg_addr, u32 bitmask, u32 data) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + int index; + + if (reg_addr == RTXAGC_RATE18_06) + index = 0; + else if (reg_addr == RTXAGC_RATE54_24) + index = 1; + else if (reg_addr == RTXAGC_CCK_MCS32) + index = 6; + else if (reg_addr == RTXAGC_MCS03_MCS00) + index = 2; + else if (reg_addr == RTXAGC_MCS07_MCS04) + index = 3; + else if (reg_addr == RTXAGC_MCS11_MCS08) + index = 4; + else if (reg_addr == RTXAGC_MCS15_MCS12) + index = 5; + else + return; + + rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][index] = data; + if (index == 5) + rtlphy->pwrgroup_cnt++; +} + +static void _rtl92s_phy_init_register_definition(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + + /*RF Interface Sowrtware Control */ + 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_C].rfintfs = RFPGA0_XCD_RFINTERFACESW; + rtlphy->phyreg_def[RF90_PATH_D].rfintfs = RFPGA0_XCD_RFINTERFACESW; + + /* RF Interface Readback Value */ + rtlphy->phyreg_def[RF90_PATH_A].rfintfi = RFPGA0_XAB_RFINTERFACERB; + rtlphy->phyreg_def[RF90_PATH_B].rfintfi = RFPGA0_XAB_RFINTERFACERB; + rtlphy->phyreg_def[RF90_PATH_C].rfintfi = RFPGA0_XCD_RFINTERFACERB; + rtlphy->phyreg_def[RF90_PATH_D].rfintfi = RFPGA0_XCD_RFINTERFACERB; + + /* RF Interface Output (and Enable) */ + 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_C].rfintfo = RFPGA0_XC_RFINTERFACEOE; + rtlphy->phyreg_def[RF90_PATH_D].rfintfo = RFPGA0_XD_RFINTERFACEOE; + + /* RF Interface (Output and) Enable */ + 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_C].rfintfe = RFPGA0_XC_RFINTERFACEOE; + rtlphy->phyreg_def[RF90_PATH_D].rfintfe = RFPGA0_XD_RFINTERFACEOE; + + /* Addr of LSSI. Wirte RF register by driver */ + 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_C].rf3wire_offset = + RFPGA0_XC_LSSIPARAMETER; + rtlphy->phyreg_def[RF90_PATH_D].rf3wire_offset = + RFPGA0_XD_LSSIPARAMETER; + + /* RF parameter */ + rtlphy->phyreg_def[RF90_PATH_A].rflssi_select = RFPGA0_XAB_RFPARAMETER; + rtlphy->phyreg_def[RF90_PATH_B].rflssi_select = RFPGA0_XAB_RFPARAMETER; + rtlphy->phyreg_def[RF90_PATH_C].rflssi_select = RFPGA0_XCD_RFPARAMETER; + rtlphy->phyreg_def[RF90_PATH_D].rflssi_select = RFPGA0_XCD_RFPARAMETER; + + /* Tx AGC Gain Stage (same for all path. Should we remove this?) */ + rtlphy->phyreg_def[RF90_PATH_A].rftxgain_stage = RFPGA0_TXGAINSTAGE; + rtlphy->phyreg_def[RF90_PATH_B].rftxgain_stage = RFPGA0_TXGAINSTAGE; + rtlphy->phyreg_def[RF90_PATH_C].rftxgain_stage = RFPGA0_TXGAINSTAGE; + rtlphy->phyreg_def[RF90_PATH_D].rftxgain_stage = RFPGA0_TXGAINSTAGE; + + /* Tranceiver A~D HSSI Parameter-1 */ + rtlphy->phyreg_def[RF90_PATH_A].rfhssi_para1 = RFPGA0_XA_HSSIPARAMETER1; + rtlphy->phyreg_def[RF90_PATH_B].rfhssi_para1 = RFPGA0_XB_HSSIPARAMETER1; + rtlphy->phyreg_def[RF90_PATH_C].rfhssi_para1 = RFPGA0_XC_HSSIPARAMETER1; + rtlphy->phyreg_def[RF90_PATH_D].rfhssi_para1 = RFPGA0_XD_HSSIPARAMETER1; + + /* Tranceiver A~D HSSI Parameter-2 */ + 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_C].rfhssi_para2 = RFPGA0_XC_HSSIPARAMETER2; + rtlphy->phyreg_def[RF90_PATH_D].rfhssi_para2 = RFPGA0_XD_HSSIPARAMETER2; + + /* RF switch Control */ + rtlphy->phyreg_def[RF90_PATH_A].rfswitch_control = + RFPGA0_XAB_SWITCHCONTROL; + rtlphy->phyreg_def[RF90_PATH_B].rfswitch_control = + RFPGA0_XAB_SWITCHCONTROL; + rtlphy->phyreg_def[RF90_PATH_C].rfswitch_control = + RFPGA0_XCD_SWITCHCONTROL; + rtlphy->phyreg_def[RF90_PATH_D].rfswitch_control = + RFPGA0_XCD_SWITCHCONTROL; + + /* AGC control 1 */ + rtlphy->phyreg_def[RF90_PATH_A].rfagc_control1 = ROFDM0_XAAGCCORE1; + rtlphy->phyreg_def[RF90_PATH_B].rfagc_control1 = ROFDM0_XBAGCCORE1; + rtlphy->phyreg_def[RF90_PATH_C].rfagc_control1 = ROFDM0_XCAGCCORE1; + rtlphy->phyreg_def[RF90_PATH_D].rfagc_control1 = ROFDM0_XDAGCCORE1; + + /* AGC control 2 */ + rtlphy->phyreg_def[RF90_PATH_A].rfagc_control2 = ROFDM0_XAAGCCORE2; + rtlphy->phyreg_def[RF90_PATH_B].rfagc_control2 = ROFDM0_XBAGCCORE2; + rtlphy->phyreg_def[RF90_PATH_C].rfagc_control2 = ROFDM0_XCAGCCORE2; + rtlphy->phyreg_def[RF90_PATH_D].rfagc_control2 = ROFDM0_XDAGCCORE2; + + /* RX AFE control 1 */ + rtlphy->phyreg_def[RF90_PATH_A].rfrxiq_imbalance = + ROFDM0_XARXIQIMBALANCE; + rtlphy->phyreg_def[RF90_PATH_B].rfrxiq_imbalance = + ROFDM0_XBRXIQIMBALANCE; + rtlphy->phyreg_def[RF90_PATH_C].rfrxiq_imbalance = + ROFDM0_XCRXIQIMBALANCE; + rtlphy->phyreg_def[RF90_PATH_D].rfrxiq_imbalance = + ROFDM0_XDRXIQIMBALANCE; + + /* RX AFE control 1 */ + rtlphy->phyreg_def[RF90_PATH_A].rfrx_afe = ROFDM0_XARXAFE; + rtlphy->phyreg_def[RF90_PATH_B].rfrx_afe = ROFDM0_XBRXAFE; + rtlphy->phyreg_def[RF90_PATH_C].rfrx_afe = ROFDM0_XCRXAFE; + rtlphy->phyreg_def[RF90_PATH_D].rfrx_afe = ROFDM0_XDRXAFE; + + /* Tx AFE control 1 */ + rtlphy->phyreg_def[RF90_PATH_A].rftxiq_imbalance = + ROFDM0_XATXIQIMBALANCE; + rtlphy->phyreg_def[RF90_PATH_B].rftxiq_imbalance = + ROFDM0_XBTXIQIMBALANCE; + rtlphy->phyreg_def[RF90_PATH_C].rftxiq_imbalance = + ROFDM0_XCTXIQIMBALANCE; + rtlphy->phyreg_def[RF90_PATH_D].rftxiq_imbalance = + ROFDM0_XDTXIQIMBALANCE; + + /* Tx AFE control 2 */ + rtlphy->phyreg_def[RF90_PATH_A].rftx_afe = ROFDM0_XATXAFE; + rtlphy->phyreg_def[RF90_PATH_B].rftx_afe = ROFDM0_XBTXAFE; + rtlphy->phyreg_def[RF90_PATH_C].rftx_afe = ROFDM0_XCTXAFE; + rtlphy->phyreg_def[RF90_PATH_D].rftx_afe = ROFDM0_XDTXAFE; + + /* Tranceiver LSSI Readback */ + 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_C].rflssi_readback = + RFPGA0_XC_LSSIREADBACK; + rtlphy->phyreg_def[RF90_PATH_D].rflssi_readback = + RFPGA0_XD_LSSIREADBACK; + + /* Tranceiver LSSI Readback PI mode */ + rtlphy->phyreg_def[RF90_PATH_A].rflssi_readbackpi = + TRANSCEIVERA_HSPI_READBACK; + rtlphy->phyreg_def[RF90_PATH_B].rflssi_readbackpi = + TRANSCEIVERB_HSPI_READBACK; +} + + +static bool _rtl92s_phy_config_bb(struct ieee80211_hw *hw, u8 configtype) +{ + int i; + u32 *phy_reg_table; + u32 *agc_table; + u16 phy_reg_len, agc_len; + + agc_len = AGCTAB_ARRAYLENGTH; + agc_table = rtl8192seagctab_array; + /* Default RF_type: 2T2R */ + phy_reg_len = PHY_REG_2T2RARRAYLENGTH; + phy_reg_table = rtl8192sephy_reg_2t2rarray; + + if (configtype == BASEBAND_CONFIG_PHY_REG) { + for (i = 0; i < phy_reg_len; i = i + 2) { + if (phy_reg_table[i] == 0xfe) + mdelay(50); + else if (phy_reg_table[i] == 0xfd) + mdelay(5); + else if (phy_reg_table[i] == 0xfc) + mdelay(1); + else if (phy_reg_table[i] == 0xfb) + udelay(50); + else if (phy_reg_table[i] == 0xfa) + udelay(5); + else if (phy_reg_table[i] == 0xf9) + udelay(1); + + /* Add delay for ECS T20 & LG malow platform, */ + udelay(1); + + rtl92s_phy_set_bb_reg(hw, phy_reg_table[i], MASKDWORD, + phy_reg_table[i + 1]); + } + } else if (configtype == BASEBAND_CONFIG_AGC_TAB) { + for (i = 0; i < agc_len; i = i + 2) { + rtl92s_phy_set_bb_reg(hw, agc_table[i], MASKDWORD, + agc_table[i + 1]); + + /* Add delay for ECS T20 & LG malow platform */ + udelay(1); + } + } + + return true; +} + +static bool _rtl92s_phy_set_bb_to_diff_rf(struct ieee80211_hw *hw, + u8 configtype) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + u32 *phy_regarray2xtxr_table; + u16 phy_regarray2xtxr_len; + int i; + + if (rtlphy->rf_type == RF_1T1R) { + phy_regarray2xtxr_table = rtl8192sephy_changeto_1t1rarray; + phy_regarray2xtxr_len = PHY_CHANGETO_1T1RARRAYLENGTH; + } else if (rtlphy->rf_type == RF_1T2R) { + phy_regarray2xtxr_table = rtl8192sephy_changeto_1t2rarray; + phy_regarray2xtxr_len = PHY_CHANGETO_1T2RARRAYLENGTH; + } else { + return false; + } + + if (configtype == BASEBAND_CONFIG_PHY_REG) { + for (i = 0; i < phy_regarray2xtxr_len; i = i + 3) { + if (phy_regarray2xtxr_table[i] == 0xfe) + mdelay(50); + else if (phy_regarray2xtxr_table[i] == 0xfd) + mdelay(5); + else if (phy_regarray2xtxr_table[i] == 0xfc) + mdelay(1); + else if (phy_regarray2xtxr_table[i] == 0xfb) + udelay(50); + else if (phy_regarray2xtxr_table[i] == 0xfa) + udelay(5); + else if (phy_regarray2xtxr_table[i] == 0xf9) + udelay(1); + + rtl92s_phy_set_bb_reg(hw, phy_regarray2xtxr_table[i], + phy_regarray2xtxr_table[i + 1], + phy_regarray2xtxr_table[i + 2]); + } + } + + return true; +} + +static bool _rtl92s_phy_config_bb_with_pg(struct ieee80211_hw *hw, + u8 configtype) +{ + int i; + u32 *phy_table_pg; + u16 phy_pg_len; + + phy_pg_len = PHY_REG_ARRAY_PGLENGTH; + phy_table_pg = rtl8192sephy_reg_array_pg; + + if (configtype == BASEBAND_CONFIG_PHY_REG) { + for (i = 0; i < phy_pg_len; i = i + 3) { + if (phy_table_pg[i] == 0xfe) + mdelay(50); + else if (phy_table_pg[i] == 0xfd) + mdelay(5); + else if (phy_table_pg[i] == 0xfc) + mdelay(1); + else if (phy_table_pg[i] == 0xfb) + udelay(50); + else if (phy_table_pg[i] == 0xfa) + udelay(5); + else if (phy_table_pg[i] == 0xf9) + udelay(1); + + _rtl92s_store_pwrindex_diffrate_offset(hw, + phy_table_pg[i], + phy_table_pg[i + 1], + phy_table_pg[i + 2]); + rtl92s_phy_set_bb_reg(hw, phy_table_pg[i], + phy_table_pg[i + 1], + phy_table_pg[i + 2]); + } + } + + return true; +} + +static bool _rtl92s_phy_bb_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 = true; + + /* 1. Read PHY_REG.TXT BB INIT!! */ + /* We will separate as 1T1R/1T2R/1T2R_GREEN/2T2R */ + if (rtlphy->rf_type == RF_1T2R || rtlphy->rf_type == RF_2T2R || + rtlphy->rf_type == RF_1T1R || rtlphy->rf_type == RF_2T2R_GREEN) { + rtstatus = _rtl92s_phy_config_bb(hw, BASEBAND_CONFIG_PHY_REG); + + if (rtlphy->rf_type != RF_2T2R && + rtlphy->rf_type != RF_2T2R_GREEN) + /* so we should reconfig BB reg with the right + * PHY parameters. */ + rtstatus = _rtl92s_phy_set_bb_to_diff_rf(hw, + BASEBAND_CONFIG_PHY_REG); + } else { + rtstatus = false; + } + + if (!rtstatus) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG, + "Write BB Reg Fail!!\n"); + goto phy_BB8190_Config_ParaFile_Fail; + } + + /* 2. If EEPROM or EFUSE autoload OK, We must config by + * PHY_REG_PG.txt */ + if (rtlefuse->autoload_failflag == false) { + rtlphy->pwrgroup_cnt = 0; + + rtstatus = _rtl92s_phy_config_bb_with_pg(hw, + BASEBAND_CONFIG_PHY_REG); + } + if (!rtstatus) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG, + "_rtl92s_phy_bb_config_parafile(): BB_PG Reg Fail!!\n"); + goto phy_BB8190_Config_ParaFile_Fail; + } + + /* 3. BB AGC table Initialization */ + rtstatus = _rtl92s_phy_config_bb(hw, BASEBAND_CONFIG_AGC_TAB); + + if (!rtstatus) { + pr_err("%s(): AGC Table Fail\n", __func__); + goto phy_BB8190_Config_ParaFile_Fail; + } + + /* Check if the CCK HighPower is turned ON. */ + /* This is used to calculate PWDB. */ + rtlphy->cck_high_power = (bool)(rtl92s_phy_query_bb_reg(hw, + RFPGA0_XA_HSSIPARAMETER2, 0x200)); + +phy_BB8190_Config_ParaFile_Fail: + return rtstatus; +} + +u8 rtl92s_phy_config_rf(struct ieee80211_hw *hw, enum radio_path rfpath) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + int i; + bool rtstatus = true; + u32 *radio_a_table; + u32 *radio_b_table; + u16 radio_a_tblen, radio_b_tblen; + + radio_a_tblen = RADIOA_1T_ARRAYLENGTH; + radio_a_table = rtl8192seradioa_1t_array; + + /* Using Green mode array table for RF_2T2R_GREEN */ + if (rtlphy->rf_type == RF_2T2R_GREEN) { + radio_b_table = rtl8192seradiob_gm_array; + radio_b_tblen = RADIOB_GM_ARRAYLENGTH; + } else { + radio_b_table = rtl8192seradiob_array; + radio_b_tblen = RADIOB_ARRAYLENGTH; + } + + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "Radio No %x\n", rfpath); + rtstatus = true; + + switch (rfpath) { + case RF90_PATH_A: + for (i = 0; i < radio_a_tblen; i = i + 2) { + if (radio_a_table[i] == 0xfe) + /* Delay specific ms. Only RF configuration + * requires delay. */ + mdelay(50); + else if (radio_a_table[i] == 0xfd) + mdelay(5); + else if (radio_a_table[i] == 0xfc) + mdelay(1); + else if (radio_a_table[i] == 0xfb) + udelay(50); + else if (radio_a_table[i] == 0xfa) + udelay(5); + else if (radio_a_table[i] == 0xf9) + udelay(1); + else + rtl92s_phy_set_rf_reg(hw, rfpath, + radio_a_table[i], + MASK20BITS, + radio_a_table[i + 1]); + + /* Add delay for ECS T20 & LG malow platform */ + udelay(1); + } + + /* PA Bias current for inferiority IC */ + _rtl92s_phy_config_rfpa_bias_current(hw, rfpath); + break; + case RF90_PATH_B: + for (i = 0; i < radio_b_tblen; i = i + 2) { + if (radio_b_table[i] == 0xfe) + /* Delay specific ms. Only RF configuration + * requires delay.*/ + mdelay(50); + else if (radio_b_table[i] == 0xfd) + mdelay(5); + else if (radio_b_table[i] == 0xfc) + mdelay(1); + else if (radio_b_table[i] == 0xfb) + udelay(50); + else if (radio_b_table[i] == 0xfa) + udelay(5); + else if (radio_b_table[i] == 0xf9) + udelay(1); + else + rtl92s_phy_set_rf_reg(hw, rfpath, + radio_b_table[i], + MASK20BITS, + radio_b_table[i + 1]); + + /* Add delay for ECS T20 & LG malow platform */ + udelay(1); + } + break; + case RF90_PATH_C: + ; + break; + case RF90_PATH_D: + ; + break; + default: + break; + } + + return rtstatus; +} + + +bool rtl92s_phy_mac_config(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 i; + u32 arraylength; + u32 *ptraArray; + + arraylength = MAC_2T_ARRAYLENGTH; + ptraArray = rtl8192semac_2t_array; + + for (i = 0; i < arraylength; i = i + 2) + rtl_write_byte(rtlpriv, ptraArray[i], (u8)ptraArray[i + 1]); + + return true; +} + + +bool rtl92s_phy_bb_config(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + bool rtstatus = true; + u8 pathmap, index, rf_num = 0; + u8 path1, path2; + + _rtl92s_phy_init_register_definition(hw); + + /* Config BB and AGC */ + rtstatus = _rtl92s_phy_bb_config_parafile(hw); + + + /* Check BB/RF confiuration setting. */ + /* We only need to configure RF which is turned on. */ + path1 = (u8)(rtl92s_phy_query_bb_reg(hw, RFPGA0_TXINFO, 0xf)); + mdelay(10); + path2 = (u8)(rtl92s_phy_query_bb_reg(hw, ROFDM0_TRXPATHENABLE, 0xf)); + pathmap = path1 | path2; + + rtlphy->rf_pathmap = pathmap; + for (index = 0; index < 4; index++) { + if ((pathmap >> index) & 0x1) + rf_num++; + } + + if ((rtlphy->rf_type == RF_1T1R && rf_num != 1) || + (rtlphy->rf_type == RF_1T2R && rf_num != 2) || + (rtlphy->rf_type == RF_2T2R && rf_num != 2) || + (rtlphy->rf_type == RF_2T2R_GREEN && rf_num != 2)) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG, + "RF_Type(%x) does not match RF_Num(%x)!!\n", + rtlphy->rf_type, rf_num); + RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG, + "path1 0x%x, path2 0x%x, pathmap 0x%x\n", + path1, path2, pathmap); + } + + return rtstatus; +} + +bool rtl92s_phy_rf_config(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + + /* Initialize general global value */ + if (rtlphy->rf_type == RF_1T1R) + rtlphy->num_total_rfpath = 1; + else + rtlphy->num_total_rfpath = 2; + + /* Config BB and RF */ + return rtl92s_phy_rf6052_config(hw); +} + +void rtl92s_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + + /* read rx initial gain */ + rtlphy->default_initialgain[0] = rtl_get_bbreg(hw, + ROFDM0_XAAGCCORE1, MASKBYTE0); + rtlphy->default_initialgain[1] = rtl_get_bbreg(hw, + ROFDM0_XBAGCCORE1, MASKBYTE0); + rtlphy->default_initialgain[2] = rtl_get_bbreg(hw, + ROFDM0_XCAGCCORE1, MASKBYTE0); + rtlphy->default_initialgain[3] = rtl_get_bbreg(hw, + ROFDM0_XDAGCCORE1, MASKBYTE0); + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "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]); + + /* read framesync */ + rtlphy->framesync = rtl_get_bbreg(hw, ROFDM0_RXDETECTOR3, MASKBYTE0); + rtlphy->framesync_c34 = rtl_get_bbreg(hw, ROFDM0_RXDETECTOR2, + MASKDWORD); + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "Default framesync (0x%x) = 0x%x\n", + ROFDM0_RXDETECTOR3, rtlphy->framesync); + +} + +static void _rtl92s_phy_get_txpower_index(struct ieee80211_hw *hw, u8 channel, + u8 *cckpowerlevel, u8 *ofdmpowerLevel) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + u8 index = (channel - 1); + + /* 1. CCK */ + /* RF-A */ + cckpowerlevel[0] = rtlefuse->txpwrlevel_cck[0][index]; + /* RF-B */ + cckpowerlevel[1] = rtlefuse->txpwrlevel_cck[1][index]; + + /* 2. OFDM for 1T or 2T */ + if (rtlphy->rf_type == RF_1T2R || rtlphy->rf_type == RF_1T1R) { + /* Read HT 40 OFDM TX power */ + ofdmpowerLevel[0] = rtlefuse->txpwrlevel_ht40_1s[0][index]; + ofdmpowerLevel[1] = rtlefuse->txpwrlevel_ht40_1s[1][index]; + } else if (rtlphy->rf_type == RF_2T2R) { + /* Read HT 40 OFDM TX power */ + ofdmpowerLevel[0] = rtlefuse->txpwrlevel_ht40_2s[0][index]; + ofdmpowerLevel[1] = rtlefuse->txpwrlevel_ht40_2s[1][index]; + } +} + +static void _rtl92s_phy_ccxpower_indexcheck(struct ieee80211_hw *hw, + u8 channel, u8 *cckpowerlevel, u8 *ofdmpowerlevel) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + + rtlphy->cur_cck_txpwridx = cckpowerlevel[0]; + rtlphy->cur_ofdm24g_txpwridx = ofdmpowerlevel[0]; +} + +void rtl92s_phy_set_txpower(struct ieee80211_hw *hw, u8 channel) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + /* [0]:RF-A, [1]:RF-B */ + u8 cckpowerlevel[2], ofdmpowerLevel[2]; + + if (!rtlefuse->txpwr_fromeprom) + return; + + /* Mainly we use RF-A Tx Power to write the Tx Power registers, + * but the RF-B Tx Power must be calculated by the antenna diff. + * So we have to rewrite Antenna gain offset register here. + * Please refer to BB register 0x80c + * 1. For CCK. + * 2. For OFDM 1T or 2T */ + _rtl92s_phy_get_txpower_index(hw, channel, &cckpowerlevel[0], + &ofdmpowerLevel[0]); + + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + "Channel-%d, cckPowerLevel (A / B) = 0x%x / 0x%x, ofdmPowerLevel (A / B) = 0x%x / 0x%x\n", + channel, cckpowerlevel[0], cckpowerlevel[1], + ofdmpowerLevel[0], ofdmpowerLevel[1]); + + _rtl92s_phy_ccxpower_indexcheck(hw, channel, &cckpowerlevel[0], + &ofdmpowerLevel[0]); + + rtl92s_phy_rf6052_set_ccktxpower(hw, cckpowerlevel[0]); + rtl92s_phy_rf6052_set_ofdmtxpower(hw, &ofdmpowerLevel[0], channel); + +} + +void rtl92s_phy_chk_fwcmd_iodone(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u16 pollingcnt = 10000; + u32 tmpvalue; + + /* Make sure that CMD IO has be accepted by FW. */ + do { + udelay(10); + + tmpvalue = rtl_read_dword(rtlpriv, WFM5); + if (tmpvalue == 0) + break; + } while (--pollingcnt); + + if (pollingcnt == 0) + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Set FW Cmd fail!!\n"); +} + + +static void _rtl92s_phy_set_fwcmd_io(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 input, current_aid = 0; + + if (is_hal_stop(rtlhal)) + return; + + /* We re-map RA related CMD IO to combinational ones */ + /* if FW version is v.52 or later. */ + switch (rtlhal->current_fwcmd_io) { + case FW_CMD_RA_REFRESH_N: + rtlhal->current_fwcmd_io = FW_CMD_RA_REFRESH_N_COMB; + break; + case FW_CMD_RA_REFRESH_BG: + rtlhal->current_fwcmd_io = FW_CMD_RA_REFRESH_BG_COMB; + break; + default: + break; + } + + switch (rtlhal->current_fwcmd_io) { + case FW_CMD_RA_RESET: + RT_TRACE(rtlpriv, COMP_CMD, DBG_DMESG, "FW_CMD_RA_RESET\n"); + rtl_write_dword(rtlpriv, WFM5, FW_RA_RESET); + rtl92s_phy_chk_fwcmd_iodone(hw); + break; + case FW_CMD_RA_ACTIVE: + RT_TRACE(rtlpriv, COMP_CMD, DBG_DMESG, "FW_CMD_RA_ACTIVE\n"); + rtl_write_dword(rtlpriv, WFM5, FW_RA_ACTIVE); + rtl92s_phy_chk_fwcmd_iodone(hw); + break; + case FW_CMD_RA_REFRESH_N: + RT_TRACE(rtlpriv, COMP_CMD, DBG_DMESG, "FW_CMD_RA_REFRESH_N\n"); + input = FW_RA_REFRESH; + rtl_write_dword(rtlpriv, WFM5, input); + rtl92s_phy_chk_fwcmd_iodone(hw); + rtl_write_dword(rtlpriv, WFM5, FW_RA_ENABLE_RSSI_MASK); + rtl92s_phy_chk_fwcmd_iodone(hw); + break; + case FW_CMD_RA_REFRESH_BG: + RT_TRACE(rtlpriv, COMP_CMD, DBG_DMESG, + "FW_CMD_RA_REFRESH_BG\n"); + rtl_write_dword(rtlpriv, WFM5, FW_RA_REFRESH); + rtl92s_phy_chk_fwcmd_iodone(hw); + rtl_write_dword(rtlpriv, WFM5, FW_RA_DISABLE_RSSI_MASK); + rtl92s_phy_chk_fwcmd_iodone(hw); + break; + case FW_CMD_RA_REFRESH_N_COMB: + RT_TRACE(rtlpriv, COMP_CMD, DBG_DMESG, + "FW_CMD_RA_REFRESH_N_COMB\n"); + input = FW_RA_IOT_N_COMB; + rtl_write_dword(rtlpriv, WFM5, input); + rtl92s_phy_chk_fwcmd_iodone(hw); + break; + case FW_CMD_RA_REFRESH_BG_COMB: + RT_TRACE(rtlpriv, COMP_CMD, DBG_DMESG, + "FW_CMD_RA_REFRESH_BG_COMB\n"); + input = FW_RA_IOT_BG_COMB; + rtl_write_dword(rtlpriv, WFM5, input); + rtl92s_phy_chk_fwcmd_iodone(hw); + break; + case FW_CMD_IQK_ENABLE: + RT_TRACE(rtlpriv, COMP_CMD, DBG_DMESG, "FW_CMD_IQK_ENABLE\n"); + rtl_write_dword(rtlpriv, WFM5, FW_IQK_ENABLE); + rtl92s_phy_chk_fwcmd_iodone(hw); + break; + case FW_CMD_PAUSE_DM_BY_SCAN: + /* Lower initial gain */ + rtl_set_bbreg(hw, ROFDM0_XAAGCCORE1, MASKBYTE0, 0x17); + rtl_set_bbreg(hw, ROFDM0_XBAGCCORE1, MASKBYTE0, 0x17); + /* CCA threshold */ + rtl_set_bbreg(hw, RCCK0_CCA, MASKBYTE2, 0x40); + break; + case FW_CMD_RESUME_DM_BY_SCAN: + /* CCA threshold */ + rtl_set_bbreg(hw, RCCK0_CCA, MASKBYTE2, 0xcd); + rtl92s_phy_set_txpower(hw, rtlphy->current_channel); + break; + case FW_CMD_HIGH_PWR_DISABLE: + if (rtlpriv->dm.dm_flag & HAL_DM_HIPWR_DISABLE) + break; + + /* Lower initial gain */ + rtl_set_bbreg(hw, ROFDM0_XAAGCCORE1, MASKBYTE0, 0x17); + rtl_set_bbreg(hw, ROFDM0_XBAGCCORE1, MASKBYTE0, 0x17); + /* CCA threshold */ + rtl_set_bbreg(hw, RCCK0_CCA, MASKBYTE2, 0x40); + break; + case FW_CMD_HIGH_PWR_ENABLE: + if ((rtlpriv->dm.dm_flag & HAL_DM_HIPWR_DISABLE) || + rtlpriv->dm.dynamic_txpower_enable) + break; + + /* CCA threshold */ + rtl_set_bbreg(hw, RCCK0_CCA, MASKBYTE2, 0xcd); + break; + case FW_CMD_LPS_ENTER: + RT_TRACE(rtlpriv, COMP_CMD, DBG_DMESG, "FW_CMD_LPS_ENTER\n"); + current_aid = rtlpriv->mac80211.assoc_id; + rtl_write_dword(rtlpriv, WFM5, (FW_LPS_ENTER | + ((current_aid | 0xc000) << 8))); + rtl92s_phy_chk_fwcmd_iodone(hw); + /* FW set TXOP disable here, so disable EDCA + * turbo mode until driver leave LPS */ + break; + case FW_CMD_LPS_LEAVE: + RT_TRACE(rtlpriv, COMP_CMD, DBG_DMESG, "FW_CMD_LPS_LEAVE\n"); + rtl_write_dword(rtlpriv, WFM5, FW_LPS_LEAVE); + rtl92s_phy_chk_fwcmd_iodone(hw); + break; + case FW_CMD_ADD_A2_ENTRY: + RT_TRACE(rtlpriv, COMP_CMD, DBG_DMESG, "FW_CMD_ADD_A2_ENTRY\n"); + rtl_write_dword(rtlpriv, WFM5, FW_ADD_A2_ENTRY); + rtl92s_phy_chk_fwcmd_iodone(hw); + break; + case FW_CMD_CTRL_DM_BY_DRIVER: + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, + "FW_CMD_CTRL_DM_BY_DRIVER\n"); + rtl_write_dword(rtlpriv, WFM5, FW_CTRL_DM_BY_DRIVER); + rtl92s_phy_chk_fwcmd_iodone(hw); + break; + + default: + break; + } + + rtl92s_phy_chk_fwcmd_iodone(hw); + + /* Clear FW CMD operation flag. */ + rtlhal->set_fwcmd_inprogress = false; +} + +bool rtl92s_phy_set_fw_cmd(struct ieee80211_hw *hw, enum fwcmd_iotype fw_cmdio) +{ + 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)); + u32 fw_param = FW_CMD_IO_PARA_QUERY(rtlpriv); + u16 fw_cmdmap = FW_CMD_IO_QUERY(rtlpriv); + bool bPostProcessing = false; + + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, + "Set FW Cmd(%#x), set_fwcmd_inprogress(%d)\n", + fw_cmdio, rtlhal->set_fwcmd_inprogress); + + do { + /* We re-map to combined FW CMD ones if firmware version */ + /* is v.53 or later. */ + switch (fw_cmdio) { + case FW_CMD_RA_REFRESH_N: + fw_cmdio = FW_CMD_RA_REFRESH_N_COMB; + break; + case FW_CMD_RA_REFRESH_BG: + fw_cmdio = FW_CMD_RA_REFRESH_BG_COMB; + break; + default: + break; + } + + /* If firmware version is v.62 or later, + * use FW_CMD_IO_SET for FW_CMD_CTRL_DM_BY_DRIVER */ + if (hal_get_firmwareversion(rtlpriv) >= 0x3E) { + if (fw_cmdio == FW_CMD_CTRL_DM_BY_DRIVER) + fw_cmdio = FW_CMD_CTRL_DM_BY_DRIVER_NEW; + } + + + /* We shall revise all FW Cmd IO into Reg0x364 + * DM map table in the future. */ + switch (fw_cmdio) { + case FW_CMD_RA_INIT: + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "RA init!!\n"); + fw_cmdmap |= FW_RA_INIT_CTL; + FW_CMD_IO_SET(rtlpriv, fw_cmdmap); + /* Clear control flag to sync with FW. */ + FW_CMD_IO_CLR(rtlpriv, FW_RA_INIT_CTL); + break; + case FW_CMD_DIG_DISABLE: + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, + "Set DIG disable!!\n"); + fw_cmdmap &= ~FW_DIG_ENABLE_CTL; + FW_CMD_IO_SET(rtlpriv, fw_cmdmap); + break; + case FW_CMD_DIG_ENABLE: + case FW_CMD_DIG_RESUME: + if (!(rtlpriv->dm.dm_flag & HAL_DM_DIG_DISABLE)) { + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, + "Set DIG enable or resume!!\n"); + fw_cmdmap |= (FW_DIG_ENABLE_CTL | FW_SS_CTL); + FW_CMD_IO_SET(rtlpriv, fw_cmdmap); + } + break; + case FW_CMD_DIG_HALT: + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, + "Set DIG halt!!\n"); + fw_cmdmap &= ~(FW_DIG_ENABLE_CTL | FW_SS_CTL); + FW_CMD_IO_SET(rtlpriv, fw_cmdmap); + break; + case FW_CMD_TXPWR_TRACK_THERMAL: { + u8 thermalval = 0; + fw_cmdmap |= FW_PWR_TRK_CTL; + + /* Clear FW parameter in terms of thermal parts. */ + fw_param &= FW_PWR_TRK_PARAM_CLR; + + thermalval = rtlpriv->dm.thermalvalue; + fw_param |= ((thermalval << 24) | + (rtlefuse->thermalmeter[0] << 16)); + + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, + "Set TxPwr tracking!! FwCmdMap(%#x), FwParam(%#x)\n", + fw_cmdmap, fw_param); + + FW_CMD_PARA_SET(rtlpriv, fw_param); + FW_CMD_IO_SET(rtlpriv, fw_cmdmap); + + /* Clear control flag to sync with FW. */ + FW_CMD_IO_CLR(rtlpriv, FW_PWR_TRK_CTL); + } + break; + /* The following FW CMDs are only compatible to + * v.53 or later. */ + case FW_CMD_RA_REFRESH_N_COMB: + fw_cmdmap |= FW_RA_N_CTL; + + /* Clear RA BG mode control. */ + fw_cmdmap &= ~(FW_RA_BG_CTL | FW_RA_INIT_CTL); + + /* Clear FW parameter in terms of RA parts. */ + fw_param &= FW_RA_PARAM_CLR; + + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, + "[FW CMD] [New Version] Set RA/IOT Comb in n mode!! FwCmdMap(%#x), FwParam(%#x)\n", + fw_cmdmap, fw_param); + + FW_CMD_PARA_SET(rtlpriv, fw_param); + FW_CMD_IO_SET(rtlpriv, fw_cmdmap); + + /* Clear control flag to sync with FW. */ + FW_CMD_IO_CLR(rtlpriv, FW_RA_N_CTL); + break; + case FW_CMD_RA_REFRESH_BG_COMB: + fw_cmdmap |= FW_RA_BG_CTL; + + /* Clear RA n-mode control. */ + fw_cmdmap &= ~(FW_RA_N_CTL | FW_RA_INIT_CTL); + /* Clear FW parameter in terms of RA parts. */ + fw_param &= FW_RA_PARAM_CLR; + + FW_CMD_PARA_SET(rtlpriv, fw_param); + FW_CMD_IO_SET(rtlpriv, fw_cmdmap); + + /* Clear control flag to sync with FW. */ + FW_CMD_IO_CLR(rtlpriv, FW_RA_BG_CTL); + break; + case FW_CMD_IQK_ENABLE: + fw_cmdmap |= FW_IQK_CTL; + FW_CMD_IO_SET(rtlpriv, fw_cmdmap); + /* Clear control flag to sync with FW. */ + FW_CMD_IO_CLR(rtlpriv, FW_IQK_CTL); + break; + /* The following FW CMD is compatible to v.62 or later. */ + case FW_CMD_CTRL_DM_BY_DRIVER_NEW: + fw_cmdmap |= FW_DRIVER_CTRL_DM_CTL; + FW_CMD_IO_SET(rtlpriv, fw_cmdmap); + break; + /* The followed FW Cmds needs post-processing later. */ + case FW_CMD_RESUME_DM_BY_SCAN: + fw_cmdmap |= (FW_DIG_ENABLE_CTL | + FW_HIGH_PWR_ENABLE_CTL | + FW_SS_CTL); + + if (rtlpriv->dm.dm_flag & HAL_DM_DIG_DISABLE || + !digtable.dig_enable_flag) + fw_cmdmap &= ~FW_DIG_ENABLE_CTL; + + if ((rtlpriv->dm.dm_flag & HAL_DM_HIPWR_DISABLE) || + rtlpriv->dm.dynamic_txpower_enable) + fw_cmdmap &= ~FW_HIGH_PWR_ENABLE_CTL; + + if ((digtable.dig_ext_port_stage == + DIG_EXT_PORT_STAGE_0) || + (digtable.dig_ext_port_stage == + DIG_EXT_PORT_STAGE_1)) + fw_cmdmap &= ~FW_DIG_ENABLE_CTL; + + FW_CMD_IO_SET(rtlpriv, fw_cmdmap); + bPostProcessing = true; + break; + case FW_CMD_PAUSE_DM_BY_SCAN: + fw_cmdmap &= ~(FW_DIG_ENABLE_CTL | + FW_HIGH_PWR_ENABLE_CTL | + FW_SS_CTL); + FW_CMD_IO_SET(rtlpriv, fw_cmdmap); + bPostProcessing = true; + break; + case FW_CMD_HIGH_PWR_DISABLE: + fw_cmdmap &= ~FW_HIGH_PWR_ENABLE_CTL; + FW_CMD_IO_SET(rtlpriv, fw_cmdmap); + bPostProcessing = true; + break; + case FW_CMD_HIGH_PWR_ENABLE: + if (!(rtlpriv->dm.dm_flag & HAL_DM_HIPWR_DISABLE) && + !rtlpriv->dm.dynamic_txpower_enable) { + fw_cmdmap |= (FW_HIGH_PWR_ENABLE_CTL | + FW_SS_CTL); + FW_CMD_IO_SET(rtlpriv, fw_cmdmap); + bPostProcessing = true; + } + break; + case FW_CMD_DIG_MODE_FA: + fw_cmdmap |= FW_FA_CTL; + FW_CMD_IO_SET(rtlpriv, fw_cmdmap); + break; + case FW_CMD_DIG_MODE_SS: + fw_cmdmap &= ~FW_FA_CTL; + FW_CMD_IO_SET(rtlpriv, fw_cmdmap); + break; + case FW_CMD_PAPE_CONTROL: + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, + "[FW CMD] Set PAPE Control\n"); + fw_cmdmap &= ~FW_PAPE_CTL_BY_SW_HW; + + FW_CMD_IO_SET(rtlpriv, fw_cmdmap); + break; + default: + /* Pass to original FW CMD processing callback + * routine. */ + bPostProcessing = true; + break; + } + } while (false); + + /* We shall post processing these FW CMD if + * variable bPostProcessing is set. */ + if (bPostProcessing && !rtlhal->set_fwcmd_inprogress) { + rtlhal->set_fwcmd_inprogress = true; + /* Update current FW Cmd for callback use. */ + rtlhal->current_fwcmd_io = fw_cmdio; + } else { + return false; + } + + _rtl92s_phy_set_fwcmd_io(hw); + return true; +} + +static void _rtl92s_phy_check_ephy_switchready(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 delay = 100; + u8 regu1; + + regu1 = rtl_read_byte(rtlpriv, 0x554); + while ((regu1 & BIT(5)) && (delay > 0)) { + regu1 = rtl_read_byte(rtlpriv, 0x554); + delay--; + /* We delay only 50us to prevent + * being scheduled out. */ + udelay(50); + } +} + +void rtl92s_phy_switch_ephy_parameter(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + + /* The way to be capable to switch clock request + * when the PG setting does not support clock request. + * This is the backdoor solution to switch clock + * request before ASPM or D3. */ + rtl_write_dword(rtlpriv, 0x540, 0x73c11); + rtl_write_dword(rtlpriv, 0x548, 0x2407c); + + /* Switch EPHY parameter!!!! */ + rtl_write_word(rtlpriv, 0x550, 0x1000); + rtl_write_byte(rtlpriv, 0x554, 0x20); + _rtl92s_phy_check_ephy_switchready(hw); + + rtl_write_word(rtlpriv, 0x550, 0xa0eb); + rtl_write_byte(rtlpriv, 0x554, 0x3e); + _rtl92s_phy_check_ephy_switchready(hw); + + rtl_write_word(rtlpriv, 0x550, 0xff80); + rtl_write_byte(rtlpriv, 0x554, 0x39); + _rtl92s_phy_check_ephy_switchready(hw); + + /* Delay L1 enter time */ + if (ppsc->support_aspm && !ppsc->support_backdoor) + rtl_write_byte(rtlpriv, 0x560, 0x40); + else + rtl_write_byte(rtlpriv, 0x560, 0x00); + +} + +void rtl92s_phy_set_beacon_hwreg(struct ieee80211_hw *hw, u16 BeaconInterval) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + rtl_write_dword(rtlpriv, WFM5, 0xF1000000 | (BeaconInterval << 8)); +} diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/phy.h b/drivers/net/wireless/rtlwifi/rtl8192se/phy.h new file mode 100644 index 00000000..ac038777 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192se/phy.h @@ -0,0 +1,101 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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 __RTL92S_PHY_H__ +#define __RTL92S_PHY_H__ + +#define MAX_TXPWR_IDX_NMODE_92S 63 +#define MAX_DOZE_WAITING_TIMES_9x 64 + +/* Channel switch:The size of + * command tables for switch channel */ +#define MAX_PRECMD_CNT 16 +#define MAX_RFDEPENDCMD_CNT 16 +#define MAX_POSTCMD_CNT 16 + +#define RF90_PATH_MAX 4 + +enum version_8192s { + VERSION_8192S_ACUT, + VERSION_8192S_BCUT, + VERSION_8192S_CCUT +}; + +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 { + /* Radio Path A */ + BASEBAND_CONFIG_PHY_REG = 0, + /* Radio Path B */ + BASEBAND_CONFIG_AGC_TAB = 1, +}; + +#define hal_get_firmwareversion(rtlpriv) \ + (((struct rt_firmware *)(rtlpriv->rtlhal.pfirmware))->firmwareversion) + +u32 rtl92s_phy_query_bb_reg(struct ieee80211_hw *hw, u32 regaddr, u32 bitmask); +void rtl92s_phy_set_bb_reg(struct ieee80211_hw *hw, u32 regaddr, u32 bitmask, + u32 data); +void rtl92s_phy_scan_operation_backup(struct ieee80211_hw *hw, u8 operation); +u32 rtl92s_phy_query_rf_reg(struct ieee80211_hw *hw, enum radio_path rfpath, + u32 regaddr, u32 bitmask); +void rtl92s_phy_set_rf_reg(struct ieee80211_hw *hw, enum radio_path rfpath, + u32 regaddr, u32 bitmask, u32 data); +void rtl92s_phy_set_bw_mode(struct ieee80211_hw *hw, + enum nl80211_channel_type ch_type); +u8 rtl92s_phy_sw_chnl(struct ieee80211_hw *hw); +bool rtl92s_phy_set_rf_power_state(struct ieee80211_hw *hw, + enum rf_pwrstate rfpower_state); +bool rtl92s_phy_mac_config(struct ieee80211_hw *hw); +void rtl92s_phy_switch_ephy_parameter(struct ieee80211_hw *hw); +bool rtl92s_phy_bb_config(struct ieee80211_hw *hw); +bool rtl92s_phy_rf_config(struct ieee80211_hw *hw); +void rtl92s_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw); +void rtl92s_phy_set_txpower(struct ieee80211_hw *hw, u8 channel); +bool rtl92s_phy_set_fw_cmd(struct ieee80211_hw *hw, enum fwcmd_iotype fwcmd_io); +void rtl92s_phy_chk_fwcmd_iodone(struct ieee80211_hw *hw); +void rtl92s_phy_set_beacon_hwreg(struct ieee80211_hw *hw, u16 beaconinterval); +u8 rtl92s_phy_config_rf(struct ieee80211_hw *hw, enum radio_path rfpath) ; + +#endif + diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/reg.h b/drivers/net/wireless/rtlwifi/rtl8192se/reg.h new file mode 100644 index 00000000..84d11817 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192se/reg.h @@ -0,0 +1,1185 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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 __REALTEK_92S_REG_H__ +#define __REALTEK_92S_REG_H__ + +/* 1. System Configuration Registers */ +#define REG_SYS_ISO_CTRL 0x0000 +#define REG_SYS_FUNC_EN 0x0002 +#define PMC_FSM 0x0004 +#define SYS_CLKR 0x0008 +#define EPROM_CMD 0x000A +#define EE_VPD 0x000C +#define AFE_MISC 0x0010 +#define SPS0_CTRL 0x0011 +#define SPS1_CTRL 0x0018 +#define RF_CTRL 0x001F +#define LDOA15_CTRL 0x0020 +#define LDOV12D_CTRL 0x0021 +#define LDOHCI12_CTRL 0x0022 +#define LDO_USB_SDIO 0x0023 +#define LPLDO_CTRL 0x0024 +#define AFE_XTAL_CTRL 0x0026 +#define AFE_PLL_CTRL 0x0028 +#define REG_EFUSE_CTRL 0x0030 +#define REG_EFUSE_TEST 0x0034 +#define PWR_DATA 0x0038 +#define DBG_PORT 0x003A +#define DPS_TIMER 0x003C +#define RCLK_MON 0x003E + +/* 2. Command Control Registers */ +#define CMDR 0x0040 +#define TXPAUSE 0x0042 +#define LBKMD_SEL 0x0043 +#define TCR 0x0044 +#define RCR 0x0048 +#define MSR 0x004C +#define SYSF_CFG 0x004D +#define RX_PKY_LIMIT 0x004E +#define MBIDCTRL 0x004F + +/* 3. MACID Setting Registers */ +#define MACIDR 0x0050 +#define MACIDR0 0x0050 +#define MACIDR4 0x0054 +#define BSSIDR 0x0058 +#define HWVID 0x005E +#define MAR 0x0060 +#define MBIDCAMCONTENT 0x0068 +#define MBIDCAMCFG 0x0070 +#define BUILDTIME 0x0074 +#define BUILDUSER 0x0078 + +#define IDR0 MACIDR0 +#define IDR4 MACIDR4 + +/* 4. Timing Control Registers */ +#define TSFR 0x0080 +#define SLOT_TIME 0x0089 +#define USTIME 0x008A +#define SIFS_CCK 0x008C +#define SIFS_OFDM 0x008E +#define PIFS_TIME 0x0090 +#define ACK_TIMEOUT 0x0091 +#define EIFSTR 0x0092 +#define BCN_INTERVAL 0x0094 +#define ATIMWND 0x0096 +#define BCN_DRV_EARLY_INT 0x0098 +#define BCN_DMATIME 0x009A +#define BCN_ERR_THRESH 0x009C +#define MLT 0x009D +#define RSVD_MAC_TUNE_US 0x009E + +/* 5. FIFO Control Registers */ +#define RQPN 0x00A0 +#define RQPN1 0x00A0 +#define RQPN2 0x00A1 +#define RQPN3 0x00A2 +#define RQPN4 0x00A3 +#define RQPN5 0x00A4 +#define RQPN6 0x00A5 +#define RQPN7 0x00A6 +#define RQPN8 0x00A7 +#define RQPN9 0x00A8 +#define RQPN10 0x00A9 +#define LD_RQPN 0x00AB +#define RXFF_BNDY 0x00AC +#define RXRPT_BNDY 0x00B0 +#define TXPKTBUF_PGBNDY 0x00B4 +#define PBP 0x00B5 +#define RXDRVINFO_SZ 0x00B6 +#define TXFF_STATUS 0x00B7 +#define RXFF_STATUS 0x00B8 +#define TXFF_EMPTY_TH 0x00B9 +#define SDIO_RX_BLKSZ 0x00BC +#define RXDMA 0x00BD +#define RXPKT_NUM 0x00BE +#define C2HCMD_UDT_SIZE 0x00C0 +#define C2HCMD_UDT_ADDR 0x00C2 +#define FIFOPAGE1 0x00C4 +#define FIFOPAGE2 0x00C8 +#define FIFOPAGE3 0x00CC +#define FIFOPAGE4 0x00D0 +#define FIFOPAGE5 0x00D4 +#define FW_RSVD_PG_CRTL 0x00D8 +#define RXDMA_AGG_PG_TH 0x00D9 +#define TXDESC_MSK 0x00DC +#define TXRPTFF_RDPTR 0x00E0 +#define TXRPTFF_WTPTR 0x00E4 +#define C2HFF_RDPTR 0x00E8 +#define C2HFF_WTPTR 0x00EC +#define RXFF0_RDPTR 0x00F0 +#define RXFF0_WTPTR 0x00F4 +#define RXFF1_RDPTR 0x00F8 +#define RXFF1_WTPTR 0x00FC +#define RXRPT0_RDPTR 0x0100 +#define RXRPT0_WTPTR 0x0104 +#define RXRPT1_RDPTR 0x0108 +#define RXRPT1_WTPTR 0x010C +#define RX0_UDT_SIZE 0x0110 +#define RX1PKTNUM 0x0114 +#define RXFILTERMAP 0x0116 +#define RXFILTERMAP_GP1 0x0118 +#define RXFILTERMAP_GP2 0x011A +#define RXFILTERMAP_GP3 0x011C +#define BCNQ_CTRL 0x0120 +#define MGTQ_CTRL 0x0124 +#define HIQ_CTRL 0x0128 +#define VOTID7_CTRL 0x012c +#define VOTID6_CTRL 0x0130 +#define VITID5_CTRL 0x0134 +#define VITID4_CTRL 0x0138 +#define BETID3_CTRL 0x013c +#define BETID0_CTRL 0x0140 +#define BKTID2_CTRL 0x0144 +#define BKTID1_CTRL 0x0148 +#define CMDQ_CTRL 0x014c +#define TXPKT_NUM_CTRL 0x0150 +#define TXQ_PGADD 0x0152 +#define TXFF_PG_NUM 0x0154 +#define TRXDMA_STATUS 0x0156 + +/* 6. Adaptive Control Registers */ +#define INIMCS_SEL 0x0160 +#define TX_RATE_REG INIMCS_SEL +#define INIRTSMCS_SEL 0x0180 +#define RRSR 0x0181 +#define ARFR0 0x0184 +#define ARFR1 0x0188 +#define ARFR2 0x018C +#define ARFR3 0x0190 +#define ARFR4 0x0194 +#define ARFR5 0x0198 +#define ARFR6 0x019C +#define ARFR7 0x01A0 +#define AGGLEN_LMT_H 0x01A7 +#define AGGLEN_LMT_L 0x01A8 +#define DARFRC 0x01B0 +#define RARFRC 0x01B8 +#define MCS_TXAGC 0x01C0 +#define CCK_TXAGC 0x01C8 + +/* 7. EDCA Setting Registers */ +#define EDCAPARA_VO 0x01D0 +#define EDCAPARA_VI 0x01D4 +#define EDCAPARA_BE 0x01D8 +#define EDCAPARA_BK 0x01DC +#define BCNTCFG 0x01E0 +#define CWRR 0x01E2 +#define ACMAVG 0x01E4 +#define AcmHwCtrl 0x01E7 +#define VO_ADMTM 0x01E8 +#define VI_ADMTM 0x01EC +#define BE_ADMTM 0x01F0 +#define RETRY_LIMIT 0x01F4 +#define SG_RATE 0x01F6 + +/* 8. WMAC, BA and CCX related Register. */ +#define NAV_CTRL 0x0200 +#define BW_OPMODE 0x0203 +#define BACAMCMD 0x0204 +#define BACAMCONTENT 0x0208 + +/* the 0x2xx register WMAC definition */ +#define LBDLY 0x0210 +#define FWDLY 0x0211 +#define HWPC_RX_CTRL 0x0218 +#define MQIR 0x0220 +#define MAIR 0x0222 +#define MSIR 0x0224 +#define CLM_RESULT 0x0227 +#define NHM_RPI_CNT 0x0228 +#define RXERR_RPT 0x0230 +#define NAV_PROT_LEN 0x0234 +#define CFEND_TH 0x0236 +#define AMPDU_MIN_SPACE 0x0237 +#define TXOP_STALL_CTRL 0x0238 + +/* 9. Security Control Registers */ +#define REG_RWCAM 0x0240 +#define REG_WCAMI 0x0244 +#define REG_RCAMO 0x0248 +#define REG_CAMDBG 0x024C +#define REG_SECR 0x0250 + +/* 10. Power Save Control Registers */ +#define WOW_CTRL 0x0260 +#define PSSTATUS 0x0261 +#define PSSWITCH 0x0262 +#define MIMOPS_WAIT_PERIOD 0x0263 +#define LPNAV_CTRL 0x0264 +#define WFM0 0x0270 +#define WFM1 0x0280 +#define WFM2 0x0290 +#define WFM3 0x02A0 +#define WFM4 0x02B0 +#define WFM5 0x02C0 +#define WFCRC 0x02D0 +#define FW_RPT_REG 0x02c4 + +/* 11. General Purpose Registers */ +#define PSTIME 0x02E0 +#define TIMER0 0x02E4 +#define TIMER1 0x02E8 +#define GPIO_IN_SE 0x02EC +#define GPIO_IO_SEL 0x02EE +#define MAC_PINMUX_CFG 0x02F1 +#define LEDCFG 0x02F2 +#define PHY_REG 0x02F3 +#define PHY_REG_DATA 0x02F4 +#define REG_EFUSE_CLK 0x02F8 + +/* 12. Host Interrupt Status Registers */ +#define INTA_MASK 0x0300 +#define ISR 0x0308 + +/* 13. Test Mode and Debug Control Registers */ +#define DBG_PORT_SWITCH 0x003A +#define BIST 0x0310 +#define DBS 0x0314 +#define CPUINST 0x0318 +#define CPUCAUSE 0x031C +#define LBUS_ERR_ADDR 0x0320 +#define LBUS_ERR_CMD 0x0324 +#define LBUS_ERR_DATA_L 0x0328 +#define LBUS_ERR_DATA_H 0x032C +#define LX_EXCEPTION_ADDR 0x0330 +#define WDG_CTRL 0x0334 +#define INTMTU 0x0338 +#define INTM 0x033A +#define FDLOCKTURN0 0x033C +#define FDLOCKTURN1 0x033D +#define TRXPKTBUF_DBG_DATA 0x0340 +#define TRXPKTBUF_DBG_CTRL 0x0348 +#define DPLL 0x034A +#define CBUS_ERR_ADDR 0x0350 +#define CBUS_ERR_CMD 0x0354 +#define CBUS_ERR_DATA_L 0x0358 +#define CBUS_ERR_DATA_H 0x035C +#define USB_SIE_INTF_ADDR 0x0360 +#define USB_SIE_INTF_WD 0x0361 +#define USB_SIE_INTF_RD 0x0362 +#define USB_SIE_INTF_CTRL 0x0363 +#define LBUS_MON_ADDR 0x0364 +#define LBUS_ADDR_MASK 0x0368 + +/* Boundary is 0x37F */ + +/* 14. PCIE config register */ +#define TP_POLL 0x0500 +#define PM_CTRL 0x0502 +#define PCIF 0x0503 + +#define THPDA 0x0514 +#define TMDA 0x0518 +#define TCDA 0x051C +#define HDA 0x0520 +#define TVODA 0x0524 +#define TVIDA 0x0528 +#define TBEDA 0x052C +#define TBKDA 0x0530 +#define TBDA 0x0534 +#define RCDA 0x0538 +#define RDQDA 0x053C +#define DBI_WDATA 0x0540 +#define DBI_RDATA 0x0544 +#define DBI_CTRL 0x0548 +#define MDIO_DATA 0x0550 +#define MDIO_CTRL 0x0554 +#define PCI_RPWM 0x0561 +#define PCI_CPWM 0x0563 + +/* Config register (Offset 0x800-) */ +#define PHY_CCA 0x803 + +/* Min Spacing related settings. */ +#define MAX_MSS_DENSITY_2T 0x13 +#define MAX_MSS_DENSITY_1T 0x0A + +/* Rx DMA Control related settings */ +#define RXDMA_AGG_EN BIT(7) + +#define RPWM PCI_RPWM + +/* Regsiter Bit and Content definition */ + +#define ISO_MD2PP BIT(0) +#define ISO_PA2PCIE BIT(3) +#define ISO_PLL2MD BIT(4) +#define ISO_PWC_DV2RP BIT(11) +#define ISO_PWC_RV2RP BIT(12) + + +#define FEN_MREGEN BIT(15) +#define FEN_DCORE BIT(11) +#define FEN_CPUEN BIT(10) + +#define PAD_HWPD_IDN BIT(22) + +#define SYS_CLKSEL_80M BIT(0) +#define SYS_PS_CLKSEL BIT(1) +#define SYS_CPU_CLKSEL BIT(2) +#define SYS_MAC_CLK_EN BIT(11) +#define SYS_SWHW_SEL BIT(14) +#define SYS_FWHW_SEL BIT(15) + +#define CmdEEPROM_En BIT(5) +#define CmdEERPOMSEL BIT(4) +#define Cmd9346CR_9356SEL BIT(4) + +#define AFE_MBEN BIT(1) +#define AFE_BGEN BIT(0) + +#define SPS1_SWEN BIT(1) +#define SPS1_LDEN BIT(0) + +#define RF_EN BIT(0) +#define RF_RSTB BIT(1) +#define RF_SDMRSTB BIT(2) + +#define LDA15_EN BIT(0) + +#define LDV12_EN BIT(0) +#define LDV12_SDBY BIT(1) + +#define XTAL_GATE_AFE BIT(10) + +#define APLL_EN BIT(0) + +#define AFR_CardBEn BIT(0) +#define AFR_CLKRUN_SEL BIT(1) +#define AFR_FuncRegEn BIT(2) + +#define APSDOFF_STATUS BIT(15) +#define APSDOFF BIT(14) +#define BBRSTN BIT(13) +#define BB_GLB_RSTN BIT(12) +#define SCHEDULE_EN BIT(10) +#define MACRXEN BIT(9) +#define MACTXEN BIT(8) +#define DDMA_EN BIT(7) +#define FW2HW_EN BIT(6) +#define RXDMA_EN BIT(5) +#define TXDMA_EN BIT(4) +#define HCI_RXDMA_EN BIT(3) +#define HCI_TXDMA_EN BIT(2) + +#define StopHCCA BIT(6) +#define StopHigh BIT(5) +#define StopMgt BIT(4) +#define StopVO BIT(3) +#define StopVI BIT(2) +#define StopBE BIT(1) +#define StopBK BIT(0) + +#define LBK_NORMAL 0x00 +#define LBK_MAC_LB (BIT(0) | BIT(1) | BIT(3)) +#define LBK_MAC_DLB (BIT(0) | BIT(1)) +#define LBK_DMA_LB (BIT(0) | BIT(1) | BIT(2)) + +#define TCP_OFDL_EN BIT(25) +#define HWPC_TX_EN BIT(24) +#define TXDMAPRE2FULL BIT(23) +#define DISCW BIT(20) +#define TCRICV BIT(19) +#define CfendForm BIT(17) +#define TCRCRC BIT(16) +#define FAKE_IMEM_EN BIT(15) +#define TSFRST BIT(9) +#define TSFEN BIT(8) +#define FWALLRDY (BIT(0) | BIT(1) | BIT(2) | \ + BIT(3) | BIT(4) | BIT(5) | \ + BIT(6) | BIT(7)) +#define FWRDY BIT(7) +#define BASECHG BIT(6) +#define IMEM BIT(5) +#define DMEM_CODE_DONE BIT(4) +#define EXT_IMEM_CHK_RPT BIT(3) +#define EXT_IMEM_CODE_DONE BIT(2) +#define IMEM_CHK_RPT BIT(1) +#define IMEM_CODE_DONE BIT(0) +#define IMEM_CODE_DONE BIT(0) +#define IMEM_CHK_RPT BIT(1) +#define EMEM_CODE_DONE BIT(2) +#define EMEM_CHK_RPT BIT(3) +#define DMEM_CODE_DONE BIT(4) +#define IMEM_RDY BIT(5) +#define BASECHG BIT(6) +#define FWRDY BIT(7) +#define LOAD_FW_READY (IMEM_CODE_DONE | \ + IMEM_CHK_RPT | \ + EMEM_CODE_DONE | \ + EMEM_CHK_RPT | \ + DMEM_CODE_DONE | \ + IMEM_RDY | \ + BASECHG | \ + FWRDY) +#define TCR_TSFEN BIT(8) +#define TCR_TSFRST BIT(9) +#define TCR_FAKE_IMEM_EN BIT(15) +#define TCR_CRC BIT(16) +#define TCR_ICV BIT(19) +#define TCR_DISCW BIT(20) +#define TCR_HWPC_TX_EN BIT(24) +#define TCR_TCP_OFDL_EN BIT(25) +#define TXDMA_INIT_VALUE (IMEM_CHK_RPT | \ + EXT_IMEM_CHK_RPT) + +#define RCR_APPFCS BIT(31) +#define RCR_DIS_ENC_2BYTE BIT(30) +#define RCR_DIS_AES_2BYTE BIT(29) +#define RCR_HTC_LOC_CTRL BIT(28) +#define RCR_ENMBID BIT(27) +#define RCR_RX_TCPOFDL_EN BIT(26) +#define RCR_APP_PHYST_RXFF BIT(25) +#define RCR_APP_PHYST_STAFF BIT(24) +#define RCR_CBSSID BIT(23) +#define RCR_APWRMGT BIT(22) +#define RCR_ADD3 BIT(21) +#define RCR_AMF BIT(20) +#define RCR_ACF BIT(19) +#define RCR_ADF BIT(18) +#define RCR_APP_MIC BIT(17) +#define RCR_APP_ICV BIT(16) +#define RCR_RXFTH BIT(13) +#define RCR_AICV BIT(12) +#define RCR_RXDESC_LK_EN BIT(11) +#define RCR_APP_BA_SSN BIT(6) +#define RCR_ACRC32 BIT(5) +#define RCR_RXSHFT_EN 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 MSR_LINK_MASK ((1 << 0) | (1 << 1)) +#define MSR_LINK_MANAGED 2 +#define MSR_LINK_NONE 0 +#define MSR_LINK_SHIFT 0 +#define MSR_LINK_ADHOC 1 +#define MSR_LINK_MASTER 3 +#define MSR_NOLINK 0x00 +#define MSR_ADHOC 0x01 +#define MSR_INFRA 0x02 +#define MSR_AP 0x03 + +#define ENUART BIT(7) +#define ENJTAG BIT(3) +#define BTMODE (BIT(2) | BIT(1)) +#define ENBT BIT(0) + +#define ENMBID BIT(7) +#define BCNUM (BIT(6) | BIT(5) | BIT(4)) + +#define USTIME_EDCA 0xFF00 +#define USTIME_TSF 0x00FF + +#define SIFS_TRX 0xFF00 +#define SIFS_CTX 0x00FF + +#define ENSWBCN BIT(15) +#define DRVERLY_TU 0x0FF0 +#define DRVERLY_US 0x000F +#define BCN_TCFG_CW_SHIFT 8 +#define BCN_TCFG_IFS 0 + +#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_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 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 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 RETRY_LIMIT_SHORT_SHIFT 8 +#define RETRY_LIMIT_LONG_SHIFT 0 + +#define NAV_UPPER_EN BIT(16) +#define NAV_UPPER 0xFF00 +#define NAV_RTSRST 0xFF + +#define BW_OPMODE_20MHZ BIT(2) +#define BW_OPMODE_5G BIT(1) +#define BW_OPMODE_11J BIT(0) + +#define RXERR_RPT_RST BIT(27) +#define RXERR_OFDM_PPDU 0 +#define RXERR_OFDM_FALSE_ALARM 1 +#define RXERR_OFDM_MPDU_OK 2 +#define RXERR_OFDM_MPDU_FAIL 3 +#define RXERR_CCK_PPDU 4 +#define RXERR_CCK_FALSE_ALARM 5 +#define RXERR_CCK_MPDU_OK 6 +#define RXERR_CCK_MPDU_FAIL 7 +#define RXERR_HT_PPDU 8 +#define RXERR_HT_FALSE_ALARM 9 +#define RXERR_HT_MPDU_TOTAL 10 +#define RXERR_HT_MPDU_OK 11 +#define RXERR_HT_MPDU_FAIL 12 +#define RXERR_RX_FULL_DROP 15 + +#define SCR_TXUSEDK BIT(0) +#define SCR_RXUSEDK BIT(1) +#define SCR_TXENCENABLE BIT(2) +#define SCR_RXENCENABLE BIT(3) +#define SCR_SKBYA2 BIT(4) +#define SCR_NOSKMC BIT(5) + +#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 WOW_PMEN BIT(0) +#define WOW_WOMEN BIT(1) +#define WOW_MAGIC BIT(2) +#define WOW_UWF BIT(3) + +#define GPIOMUX_EN BIT(3) +#define GPIOSEL_GPIO 0 +#define GPIOSEL_PHYDBG 1 +#define GPIOSEL_BT 2 +#define GPIOSEL_WLANDBG 3 +#define GPIOSEL_GPIO_MASK (~(BIT(0)|BIT(1))) + +#define HST_RDBUSY BIT(0) +#define CPU_WTBUSY BIT(1) + +#define IMR8190_DISABLED 0x0 +#define IMR_CPUERR BIT(5) +#define IMR_ATIMEND BIT(4) +#define IMR_TBDOK BIT(3) +#define IMR_TBDER BIT(2) +#define IMR_BCNDMAINT8 BIT(1) +#define IMR_BCNDMAINT7 BIT(0) +#define IMR_BCNDMAINT6 BIT(31) +#define IMR_BCNDMAINT5 BIT(30) +#define IMR_BCNDMAINT4 BIT(29) +#define IMR_BCNDMAINT3 BIT(28) +#define IMR_BCNDMAINT2 BIT(27) +#define IMR_BCNDMAINT1 BIT(26) +#define IMR_BCNDOK8 BIT(25) +#define IMR_BCNDOK7 BIT(24) +#define IMR_BCNDOK6 BIT(23) +#define IMR_BCNDOK5 BIT(22) +#define IMR_BCNDOK4 BIT(21) +#define IMR_BCNDOK3 BIT(20) +#define IMR_BCNDOK2 BIT(19) +#define IMR_BCNDOK1 BIT(18) +#define IMR_TIMEOUT2 BIT(17) +#define IMR_TIMEOUT1 BIT(16) +#define IMR_TXFOVW BIT(15) +#define IMR_PSTIMEOUT BIT(14) +#define IMR_BCNINT BIT(13) +#define IMR_RXFOVW BIT(12) +#define IMR_RDU BIT(11) +#define IMR_RXCMDOK BIT(10) +#define IMR_BDOK BIT(9) +#define IMR_HIGHDOK BIT(8) +#define IMR_COMDOK BIT(7) +#define IMR_MGNTDOK BIT(6) +#define IMR_HCCADOK BIT(5) +#define IMR_BKDOK BIT(4) +#define IMR_BEDOK BIT(3) +#define IMR_VIDOK BIT(2) +#define IMR_VODOK BIT(1) +#define IMR_ROK BIT(0) + +#define TPPOLL_BKQ BIT(0) +#define TPPOLL_BEQ BIT(1) +#define TPPOLL_VIQ BIT(2) +#define TPPOLL_VOQ BIT(3) +#define TPPOLL_BQ BIT(4) +#define TPPOLL_CQ BIT(5) +#define TPPOLL_MQ BIT(6) +#define TPPOLL_HQ BIT(7) +#define TPPOLL_HCCAQ BIT(8) +#define TPPOLL_STOPBK BIT(9) +#define TPPOLL_STOPBE BIT(10) +#define TPPOLL_STOPVI BIT(11) +#define TPPOLL_STOPVO BIT(12) +#define TPPOLL_STOPMGT BIT(13) +#define TPPOLL_STOPHIGH BIT(14) +#define TPPOLL_STOPHCCA BIT(15) +#define TPPOLL_SHIFT 8 + +#define CCX_CMD_CLM_ENABLE BIT(0) +#define CCX_CMD_NHM_ENABLE BIT(1) +#define CCX_CMD_FUNCTION_ENABLE BIT(8) +#define CCX_CMD_IGNORE_CCA BIT(9) +#define CCX_CMD_IGNORE_TXON BIT(10) +#define CCX_CLM_RESULT_READY BIT(16) +#define CCX_NHM_RESULT_READY BIT(16) +#define CCX_CMD_RESET 0x0 + + +#define HWSET_MAX_SIZE_92S 128 +#define EFUSE_MAX_SECTION 16 +#define EFUSE_REAL_CONTENT_LEN 512 +#define EFUSE_OOB_PROTECT_BYTES 15 + +#define RTL8190_EEPROM_ID 0x8129 +#define EEPROM_HPON 0x02 +#define EEPROM_CLK 0x06 +#define EEPROM_TESTR 0x08 + +#define EEPROM_VID 0x0A +#define EEPROM_DID 0x0C +#define EEPROM_SVID 0x0E +#define EEPROM_SMID 0x10 + +#define EEPROM_MAC_ADDR 0x12 +#define EEPROM_NODE_ADDRESS_BYTE_0 0x12 + +#define EEPROM_PWDIFF 0x54 + +#define EEPROM_TXPOWERBASE 0x50 +#define EEPROM_TX_PWR_INDEX_RANGE 28 + +#define EEPROM_TX_PWR_HT20_DIFF 0x62 +#define DEFAULT_HT20_TXPWR_DIFF 2 +#define EEPROM_TX_PWR_OFDM_DIFF 0x65 + +#define EEPROM_TXPWRGROUP 0x67 +#define EEPROM_REGULATORY 0x6D + +#define TX_PWR_SAFETY_CHK 0x6D +#define EEPROM_TXPWINDEX_CCK_24G 0x5D +#define EEPROM_TXPWINDEX_OFDM_24G 0x6B +#define EEPROM_HT2T_CH1_A 0x6c +#define EEPROM_HT2T_CH7_A 0x6d +#define EEPROM_HT2T_CH13_A 0x6e +#define EEPROM_HT2T_CH1_B 0x6f +#define EEPROM_HT2T_CH7_B 0x70 +#define EEPROM_HT2T_CH13_B 0x71 + +#define EEPROM_TSSI_A 0x74 +#define EEPROM_TSSI_B 0x75 + +#define EEPROM_RFIND_POWERDIFF 0x76 +#define EEPROM_DEFAULT_LEGACYHTTXPOWERDIFF 0x3 + +#define EEPROM_THERMALMETER 0x77 +#define EEPROM_BLUETOOTH_COEXIST 0x78 +#define EEPROM_BLUETOOTH_TYPE 0x4f + +#define EEPROM_OPTIONAL 0x78 +#define EEPROM_WOWLAN 0x78 + +#define EEPROM_CRYSTALCAP 0x79 +#define EEPROM_CHANNELPLAN 0x7B +#define EEPROM_VERSION 0x7C +#define EEPROM_CUSTOMID 0x7A +#define EEPROM_BOARDTYPE 0x7E + +#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 FW_DIG_DISABLE 0xfd00cc00 +#define FW_DIG_ENABLE 0xfd000000 +#define FW_DIG_HALT 0xfd000001 +#define FW_DIG_RESUME 0xfd000002 +#define FW_HIGH_PWR_DISABLE 0xfd000008 +#define FW_HIGH_PWR_ENABLE 0xfd000009 +#define FW_ADD_A2_ENTRY 0xfd000016 +#define FW_TXPWR_TRACK_ENABLE 0xfd000017 +#define FW_TXPWR_TRACK_DISABLE 0xfd000018 +#define FW_TXPWR_TRACK_THERMAL 0xfd000019 +#define FW_TXANT_SWITCH_ENABLE 0xfd000023 +#define FW_TXANT_SWITCH_DISABLE 0xfd000024 +#define FW_RA_INIT 0xfd000026 +#define FW_CTRL_DM_BY_DRIVER 0Xfd00002a +#define FW_RA_IOT_BG_COMB 0xfd000030 +#define FW_RA_IOT_N_COMB 0xfd000031 +#define FW_RA_REFRESH 0xfd0000a0 +#define FW_RA_UPDATE_MASK 0xfd0000a2 +#define FW_RA_DISABLE 0xfd0000a4 +#define FW_RA_ACTIVE 0xfd0000a6 +#define FW_RA_DISABLE_RSSI_MASK 0xfd0000ac +#define FW_RA_ENABLE_RSSI_MASK 0xfd0000ad +#define FW_RA_RESET 0xfd0000af +#define FW_DM_DISABLE 0xfd00aa00 +#define FW_IQK_ENABLE 0xf0000020 +#define FW_IQK_SUCCESS 0x0000dddd +#define FW_IQK_FAIL 0x0000ffff +#define FW_OP_FAILURE 0xffffffff +#define FW_TX_FEEDBACK_NONE 0xfb000000 +#define FW_TX_FEEDBACK_DTM_ENABLE (FW_TX_FEEDBACK_NONE | 0x1) +#define FW_TX_FEEDBACK_CCX_ENABL (FW_TX_FEEDBACK_NONE | 0x2) +#define FW_BB_RESET_ENABLE 0xff00000d +#define FW_BB_RESET_DISABLE 0xff00000e +#define FW_CCA_CHK_ENABLE 0xff000011 +#define FW_CCK_RESET_CNT 0xff000013 +#define FW_LPS_ENTER 0xfe000010 +#define FW_LPS_LEAVE 0xfe000011 +#define FW_INDIRECT_READ 0xf2000000 +#define FW_INDIRECT_WRITE 0xf2000001 +#define FW_CHAN_SET 0xf3000001 + +#define RFPC 0x5F +#define RCR_9356SEL BIT(6) +#define TCR_LRL_OFFSET 0 +#define TCR_SRL_OFFSET 8 +#define TCR_MXDMA_OFFSET 21 +#define TCR_SAT BIT(24) +#define RCR_MXDMA_OFFSET 8 +#define RCR_FIFO_OFFSET 13 +#define RCR_OnlyErlPkt BIT(31) +#define CWR 0xDC +#define RETRYCTR 0xDE + +#define CPU_GEN_SYSTEM_RESET 0x00000001 + +#define CCX_COMMAND_REG 0x890 +#define CLM_PERIOD_REG 0x894 +#define NHM_PERIOD_REG 0x896 + +#define NHM_THRESHOLD0 0x898 +#define NHM_THRESHOLD1 0x899 +#define NHM_THRESHOLD2 0x89A +#define NHM_THRESHOLD3 0x89B +#define NHM_THRESHOLD4 0x89C +#define NHM_THRESHOLD5 0x89D +#define NHM_THRESHOLD6 0x89E +#define CLM_RESULT_REG 0x8D0 +#define NHM_RESULT_REG 0x8D4 +#define NHM_RPI_COUNTER0 0x8D8 +#define NHM_RPI_COUNTER1 0x8D9 +#define NHM_RPI_COUNTER2 0x8DA +#define NHM_RPI_COUNTER3 0x8DB +#define NHM_RPI_COUNTER4 0x8DC +#define NHM_RPI_COUNTER5 0x8DD +#define NHM_RPI_COUNTER6 0x8DE +#define NHM_RPI_COUNTER7 0x8DF + +#define HAL_8192S_HW_GPIO_OFF_BIT BIT(3) +#define HAL_8192S_HW_GPIO_OFF_MASK 0xF7 +#define HAL_8192S_HW_GPIO_WPS_BIT BIT(4) + +#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_TXPACKETNNM 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_TXDATATYPE 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 RF_BB_CMD_ADDR 0x02c0 +#define RF_BB_CMD_DATA 0x02c4 + +#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_XC_HSSIPARAMETER1 0x830 +#define RFPGA0_XC_HSSIPARAMETER2 0x834 +#define RFPGA0_XD_HSSIPARAMETER1 0x838 +#define RFPGA0_XD_HSSIPARAMETER2 0x83c +#define RFPGA0_XA_LSSIPARAMETER 0x840 +#define RFPGA0_XB_LSSIPARAMETER 0x844 +#define RFPGA0_XC_LSSIPARAMETER 0x848 +#define RFPGA0_XD_LSSIPARAMETER 0x84c + +#define RFPGA0_RFWAKEUP_PARAMETER 0x850 +#define RFPGA0_RFSLEEPUP_PARAMETER 0x854 + +#define RFPGA0_XAB_SWITCHCONTROL 0x858 +#define RFPGA0_XCD_SWITCHCONTROL 0x85c + +#define RFPGA0_XA_RFINTERFACEOE 0x860 +#define RFPGA0_XB_RFINTERFACEOE 0x864 +#define RFPGA0_XC_RFINTERFACEOE 0x868 +#define RFPGA0_XD_RFINTERFACEOE 0x86c + +#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 TRANSCEIVERA_HSPI_READBACK 0x8b8 +#define TRANSCEIVERB_HSPI_READBACK 0x8bc +#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 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_XCRXIQIMBALANCE 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_CFO_AND_DAGC 0xc44 +#define ROFDM0_CCADROP_THRESHOLD 0xc48 +#define ROFDM0_ECCA_THRESHOLD 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_RXHP_PARAMETER 0xce0 +#define ROFDM0_TXPSEUDO_NOISE_WGT 0xce4 +#define ROFDM0_FRAME_SYNC 0xcf0 +#define ROFDM0_DFSREPORT 0xcf4 +#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 ROFDM1_LSTF 0xd00 +#define ROFDM1_TRXPATHENABLE 0xd04 + +#define ROFDM1_CFO 0xd08 +#define ROFDM1_CSI1 0xd10 +#define ROFDM1_SBD 0xd14 +#define ROFDM1_CSI2 0xd18 +#define ROFDM1_CFOTRACKING 0xd2c +#define ROFDM1_TRXMESAURE1 0xd34 +#define ROFDM1_INTF_DET 0xd3c +#define ROFDM1_PSEUDO_NOISESTATEAB 0xd50 +#define ROFDM1_PSEUDO_NOISESTATECD 0xd54 +#define ROFDM1_RX_PSEUDO_NOISE_WGT 0xd58 + +#define ROFDM_PHYCOUNTER1 0xda0 +#define ROFDM_PHYCOUNTER2 0xda4 +#define ROFDM_PHYCOUNTER3 0xda8 + +#define ROFDM_SHORT_CFOAB 0xdac +#define ROFDM_SHORT_CFOCD 0xdb0 +#define ROFDM_LONG_CFOAB 0xdb4 +#define ROFDM_LONG_CFOCD 0xdb8 +#define ROFDM_TAIL_CFOAB 0xdbc +#define ROFDM_TAIL_CFOCD 0xdc0 +#define ROFDM_PW_MEASURE1 0xdc4 +#define ROFDM_PW_MEASURE2 0xdc8 +#define ROFDM_BW_REPORT 0xdcc +#define ROFDM_AGC_REPORT 0xdd0 +#define ROFDM_RXSNR 0xdd4 +#define ROFDM_RXEVMCSI 0xdd8 +#define ROFDM_SIG_REPORT 0xddc + + +#define RTXAGC_RATE18_06 0xe00 +#define RTXAGC_RATE54_24 0xe04 +#define RTXAGC_CCK_MCS32 0xe08 +#define RTXAGC_MCS03_MCS00 0xe10 +#define RTXAGC_MCS07_MCS04 0xe14 +#define RTXAGC_MCS11_MCS08 0xe18 +#define RTXAGC_MCS15_MCS12 0xe1c + + +#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 RF_CHANNEL 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 0x24 +#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 BRFMOD 0x1 +#define BCCKEN 0x1000000 +#define BOFDMEN 0x2000000 + +#define BXBTXAGC 0xf00 +#define BXCTXAGC 0xf000 +#define BXDTXAGC 0xf0000 + +#define B3WIRE_DATALENGTH 0x800 +#define B3WIRE_ADDRESSLENGTH 0x400 + +#define BRFSI_RFENV 0x10 + +#define BLSSI_READADDRESS 0x7f800000 +#define BLSSI_READEDGE 0x80000000 +#define BLSSI_READBACK_DATA 0xfffff + +#define BADCLKPHASE 0x4000000 + +#define BCCK_SIDEBAND 0x10 + +#define BTX_AGCRATECCK 0x7f00 + +#define MASKBYTE0 0xff +#define MASKBYTE1 0xff00 +#define MASKBYTE2 0xff0000 +#define MASKBYTE3 0xff000000 +#define MASKHWORD 0xffff0000 +#define MASKLWORD 0x0000ffff +#define MASKDWORD 0xffffffff + +#define MAKS12BITS 0xfffff +#define MASK20BITS 0xfffff +#define RFREG_OFFSET_MASK 0xfffff + +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/rf.c b/drivers/net/wireless/rtlwifi/rtl8192se/rf.c new file mode 100644 index 00000000..08c2f562 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192se/rf.c @@ -0,0 +1,538 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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> + * + *****************************************************************************/ + +#include "../wifi.h" +#include "reg.h" +#include "def.h" +#include "phy.h" +#include "rf.h" +#include "dm.h" + + +static void _rtl92s_get_powerbase(struct ieee80211_hw *hw, u8 *p_pwrlevel, + u8 chnl, u32 *ofdmbase, u32 *mcsbase, + u8 *p_final_pwridx) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + u32 pwrbase0, pwrbase1; + u8 legacy_pwrdiff = 0, ht20_pwrdiff = 0; + u8 i, pwrlevel[4]; + + for (i = 0; i < 2; i++) + pwrlevel[i] = p_pwrlevel[i]; + + /* We only care about the path A for legacy. */ + if (rtlefuse->eeprom_version < 2) { + pwrbase0 = pwrlevel[0] + (rtlefuse->legacy_httxpowerdiff & 0xf); + } else if (rtlefuse->eeprom_version >= 2) { + legacy_pwrdiff = rtlefuse->txpwr_legacyhtdiff + [RF90_PATH_A][chnl - 1]; + + /* For legacy OFDM, tx pwr always > HT OFDM pwr. + * We do not care Path B + * legacy OFDM pwr diff. NO BB register + * to notify HW. */ + pwrbase0 = pwrlevel[0] + legacy_pwrdiff; + } + + pwrbase0 = (pwrbase0 << 24) | (pwrbase0 << 16) | (pwrbase0 << 8) | + pwrbase0; + *ofdmbase = pwrbase0; + + /* MCS rates */ + if (rtlefuse->eeprom_version >= 2) { + /* Check HT20 to HT40 diff */ + if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20) { + for (i = 0; i < 2; i++) { + /* rf-A, rf-B */ + /* HT 20<->40 pwr diff */ + ht20_pwrdiff = rtlefuse->txpwr_ht20diff + [i][chnl - 1]; + + if (ht20_pwrdiff < 8) /* 0~+7 */ + pwrlevel[i] += ht20_pwrdiff; + else /* index8-15=-8~-1 */ + pwrlevel[i] -= (16 - ht20_pwrdiff); + } + } + } + + /* use index of rf-A */ + pwrbase1 = pwrlevel[0]; + pwrbase1 = (pwrbase1 << 24) | (pwrbase1 << 16) | (pwrbase1 << 8) | + pwrbase1; + *mcsbase = pwrbase1; + + /* The following is for Antenna + * diff from Ant-B to Ant-A */ + p_final_pwridx[0] = pwrlevel[0]; + p_final_pwridx[1] = pwrlevel[1]; + + switch (rtlefuse->eeprom_regulatory) { + case 3: + /* The following is for calculation + * of the power diff for Ant-B to Ant-A. */ + if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) { + p_final_pwridx[0] += rtlefuse->pwrgroup_ht40 + [RF90_PATH_A][ + chnl - 1]; + p_final_pwridx[1] += rtlefuse->pwrgroup_ht40 + [RF90_PATH_B][ + chnl - 1]; + } else { + p_final_pwridx[0] += rtlefuse->pwrgroup_ht20 + [RF90_PATH_A][ + chnl - 1]; + p_final_pwridx[1] += rtlefuse->pwrgroup_ht20 + [RF90_PATH_B][ + chnl - 1]; + } + break; + default: + break; + } + + if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) { + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + "40MHz finalpwr_idx (A / B) = 0x%x / 0x%x\n", + p_final_pwridx[0], p_final_pwridx[1]); + } else { + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + "20MHz finalpwr_idx (A / B) = 0x%x / 0x%x\n", + p_final_pwridx[0], p_final_pwridx[1]); + } +} + +static void _rtl92s_set_antennadiff(struct ieee80211_hw *hw, + u8 *p_final_pwridx) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + char ant_pwr_diff = 0; + u32 u4reg_val = 0; + + if (rtlphy->rf_type == RF_2T2R) { + ant_pwr_diff = p_final_pwridx[1] - p_final_pwridx[0]; + + /* range is from 7~-8, + * index = 0x0~0xf */ + if (ant_pwr_diff > 7) + ant_pwr_diff = 7; + if (ant_pwr_diff < -8) + ant_pwr_diff = -8; + + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + "Antenna Diff from RF-B to RF-A = %d (0x%x)\n", + ant_pwr_diff, ant_pwr_diff & 0xf); + + ant_pwr_diff &= 0xf; + } + + /* Antenna TX power difference */ + rtlefuse->antenna_txpwdiff[2] = 0;/* RF-D, don't care */ + rtlefuse->antenna_txpwdiff[1] = 0;/* RF-C, don't care */ + rtlefuse->antenna_txpwdiff[0] = (u8)(ant_pwr_diff); /* RF-B */ + + u4reg_val = rtlefuse->antenna_txpwdiff[2] << 8 | + rtlefuse->antenna_txpwdiff[1] << 4 | + rtlefuse->antenna_txpwdiff[0]; + + rtl_set_bbreg(hw, RFPGA0_TXGAINSTAGE, (BXBTXAGC | BXCTXAGC | BXDTXAGC), + u4reg_val); + + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, "Write BCD-Diff(0x%x) = 0x%x\n", + RFPGA0_TXGAINSTAGE, u4reg_val); +} + +static void _rtl92s_get_txpower_writeval_byregulatory(struct ieee80211_hw *hw, + u8 chnl, u8 index, + u32 pwrbase0, + u32 pwrbase1, + u32 *p_outwrite_val) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + u8 i, chnlgroup, pwrdiff_limit[4]; + u32 writeval, customer_limit; + + /* Index 0 & 1= legacy OFDM, 2-5=HT_MCS rate */ + switch (rtlefuse->eeprom_regulatory) { + case 0: + /* Realtek better performance increase power diff + * defined by Realtek for large power */ + chnlgroup = 0; + + writeval = rtlphy->mcs_txpwrlevel_origoffset + [chnlgroup][index] + + ((index < 2) ? pwrbase0 : pwrbase1); + + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + "RTK better performance, writeval = 0x%x\n", writeval); + break; + case 1: + /* Realtek regulatory increase power diff defined + * by Realtek for regulatory */ + if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) { + writeval = ((index < 2) ? pwrbase0 : pwrbase1); + + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + "Realtek regulatory, 40MHz, writeval = 0x%x\n", + writeval); + } else { + if (rtlphy->pwrgroup_cnt == 1) + chnlgroup = 0; + + if (rtlphy->pwrgroup_cnt >= 3) { + if (chnl <= 3) + chnlgroup = 0; + else if (chnl >= 4 && chnl <= 8) + chnlgroup = 1; + else if (chnl > 8) + chnlgroup = 2; + if (rtlphy->pwrgroup_cnt == 4) + chnlgroup++; + } + + writeval = rtlphy->mcs_txpwrlevel_origoffset + [chnlgroup][index] + + ((index < 2) ? + pwrbase0 : pwrbase1); + + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + "Realtek regulatory, 20MHz, writeval = 0x%x\n", + writeval); + } + break; + case 2: + /* Better regulatory don't increase any power diff */ + writeval = ((index < 2) ? pwrbase0 : pwrbase1); + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + "Better regulatory, writeval = 0x%x\n", writeval); + break; + case 3: + /* Customer defined power diff. increase power diff + defined by customer. */ + chnlgroup = 0; + + if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) { + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + "customer's limit, 40MHz = 0x%x\n", + rtlefuse->pwrgroup_ht40 + [RF90_PATH_A][chnl - 1]); + } else { + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + "customer's limit, 20MHz = 0x%x\n", + rtlefuse->pwrgroup_ht20 + [RF90_PATH_A][chnl - 1]); + } + + for (i = 0; i < 4; i++) { + pwrdiff_limit[i] = + (u8)((rtlphy->mcs_txpwrlevel_origoffset + [chnlgroup][index] & (0x7f << (i * 8))) + >> (i * 8)); + + if (rtlphy->current_chan_bw == + HT_CHANNEL_WIDTH_20_40) { + if (pwrdiff_limit[i] > + rtlefuse->pwrgroup_ht40 + [RF90_PATH_A][chnl - 1]) { + pwrdiff_limit[i] = + rtlefuse->pwrgroup_ht20 + [RF90_PATH_A][chnl - 1]; + } + } else { + if (pwrdiff_limit[i] > + rtlefuse->pwrgroup_ht20 + [RF90_PATH_A][chnl - 1]) { + pwrdiff_limit[i] = + rtlefuse->pwrgroup_ht20 + [RF90_PATH_A][chnl - 1]; + } + } + } + + customer_limit = (pwrdiff_limit[3] << 24) | + (pwrdiff_limit[2] << 16) | + (pwrdiff_limit[1] << 8) | + (pwrdiff_limit[0]); + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + "Customer's limit = 0x%x\n", customer_limit); + + writeval = customer_limit + ((index < 2) ? + pwrbase0 : pwrbase1); + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + "Customer, writeval = 0x%x\n", writeval); + break; + default: + chnlgroup = 0; + writeval = rtlphy->mcs_txpwrlevel_origoffset[chnlgroup][index] + + ((index < 2) ? pwrbase0 : pwrbase1); + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + "RTK better performance, writeval = 0x%x\n", writeval); + break; + } + + if (rtlpriv->dm.dynamic_txhighpower_lvl == TX_HIGH_PWR_LEVEL_LEVEL1) + writeval = 0x10101010; + else if (rtlpriv->dm.dynamic_txhighpower_lvl == + TX_HIGH_PWR_LEVEL_LEVEL2) + writeval = 0x0; + + *p_outwrite_val = writeval; + +} + +static void _rtl92s_write_ofdm_powerreg(struct ieee80211_hw *hw, + u8 index, u32 val) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + u16 regoffset[6] = {0xe00, 0xe04, 0xe10, 0xe14, 0xe18, 0xe1c}; + u8 i, rfa_pwr[4]; + u8 rfa_lower_bound = 0, rfa_upper_bound = 0, rf_pwr_diff = 0; + u32 writeval = val; + + /* If path A and Path B coexist, we must limit Path A tx power. + * Protect Path B pwr over or under flow. We need to calculate + * upper and lower bound of path A tx power. */ + if (rtlphy->rf_type == RF_2T2R) { + rf_pwr_diff = rtlefuse->antenna_txpwdiff[0]; + + /* Diff=-8~-1 */ + if (rf_pwr_diff >= 8) { + /* Prevent underflow!! */ + rfa_lower_bound = 0x10 - rf_pwr_diff; + /* if (rf_pwr_diff >= 0) Diff = 0-7 */ + } else { + rfa_upper_bound = RF6052_MAX_TX_PWR - rf_pwr_diff; + } + } + + for (i = 0; i < 4; i++) { + rfa_pwr[i] = (u8)((writeval & (0x7f << (i * 8))) >> (i * 8)); + if (rfa_pwr[i] > RF6052_MAX_TX_PWR) + rfa_pwr[i] = RF6052_MAX_TX_PWR; + + /* If path A and Path B coexist, we must limit Path A tx power. + * Protect Path B pwr over or under flow. We need to calculate + * upper and lower bound of path A tx power. */ + if (rtlphy->rf_type == RF_2T2R) { + /* Diff=-8~-1 */ + if (rf_pwr_diff >= 8) { + /* Prevent underflow!! */ + if (rfa_pwr[i] < rfa_lower_bound) + rfa_pwr[i] = rfa_lower_bound; + /* Diff = 0-7 */ + } else if (rf_pwr_diff >= 1) { + /* Prevent overflow */ + if (rfa_pwr[i] > rfa_upper_bound) + rfa_pwr[i] = rfa_upper_bound; + } + } + + } + + writeval = (rfa_pwr[3] << 24) | (rfa_pwr[2] << 16) | (rfa_pwr[1] << 8) | + rfa_pwr[0]; + + rtl_set_bbreg(hw, regoffset[index], 0x7f7f7f7f, writeval); +} + +void rtl92s_phy_rf6052_set_ofdmtxpower(struct ieee80211_hw *hw, + u8 *p_pwrlevel, u8 chnl) +{ + u32 writeval, pwrbase0, pwrbase1; + u8 index = 0; + u8 finalpwr_idx[4]; + + _rtl92s_get_powerbase(hw, p_pwrlevel, chnl, &pwrbase0, &pwrbase1, + &finalpwr_idx[0]); + _rtl92s_set_antennadiff(hw, &finalpwr_idx[0]); + + for (index = 0; index < 6; index++) { + _rtl92s_get_txpower_writeval_byregulatory(hw, chnl, index, + pwrbase0, pwrbase1, &writeval); + + _rtl92s_write_ofdm_powerreg(hw, index, writeval); + } +} + +void rtl92s_phy_rf6052_set_ccktxpower(struct ieee80211_hw *hw, u8 pwrlevel) +{ + 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)); + u32 txagc = 0; + bool dont_inc_cck_or_turboscanoff = false; + + if (((rtlefuse->eeprom_version >= 2) && + (rtlefuse->txpwr_safetyflag == 1)) || + ((rtlefuse->eeprom_version >= 2) && + (rtlefuse->eeprom_regulatory != 0))) + dont_inc_cck_or_turboscanoff = true; + + if (mac->act_scanning) { + txagc = 0x3f; + if (dont_inc_cck_or_turboscanoff) + txagc = pwrlevel; + } else { + txagc = pwrlevel; + + if (rtlpriv->dm.dynamic_txhighpower_lvl == + TX_HIGH_PWR_LEVEL_LEVEL1) + txagc = 0x10; + else if (rtlpriv->dm.dynamic_txhighpower_lvl == + TX_HIGH_PWR_LEVEL_LEVEL2) + txagc = 0x0; + } + + if (txagc > RF6052_MAX_TX_PWR) + txagc = RF6052_MAX_TX_PWR; + + rtl_set_bbreg(hw, RTXAGC_CCK_MCS32, BTX_AGCRATECCK, txagc); + +} + +bool rtl92s_phy_rf6052_config(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + u32 u4reg_val = 0; + u8 rfpath; + bool rtstatus = true; + struct bb_reg_def *pphyreg; + + /* Initialize RF */ + for (rfpath = 0; rfpath < rtlphy->num_total_rfpath; rfpath++) { + + pphyreg = &rtlphy->phyreg_def[rfpath]; + + /* Store original RFENV control type */ + switch (rfpath) { + case RF90_PATH_A: + case RF90_PATH_C: + u4reg_val = rtl92s_phy_query_bb_reg(hw, + pphyreg->rfintfs, + BRFSI_RFENV); + break; + case RF90_PATH_B: + case RF90_PATH_D: + u4reg_val = rtl92s_phy_query_bb_reg(hw, + pphyreg->rfintfs, + BRFSI_RFENV << 16); + break; + } + + /* Set RF_ENV enable */ + rtl92s_phy_set_bb_reg(hw, pphyreg->rfintfe, + BRFSI_RFENV << 16, 0x1); + + /* Set RF_ENV output high */ + rtl92s_phy_set_bb_reg(hw, pphyreg->rfintfo, BRFSI_RFENV, 0x1); + + /* Set bit number of Address and Data for RF register */ + rtl92s_phy_set_bb_reg(hw, pphyreg->rfhssi_para2, + B3WIRE_ADDRESSLENGTH, 0x0); + rtl92s_phy_set_bb_reg(hw, pphyreg->rfhssi_para2, + B3WIRE_DATALENGTH, 0x0); + + /* Initialize RF fom connfiguration file */ + switch (rfpath) { + case RF90_PATH_A: + rtstatus = rtl92s_phy_config_rf(hw, + (enum radio_path)rfpath); + break; + case RF90_PATH_B: + rtstatus = rtl92s_phy_config_rf(hw, + (enum radio_path)rfpath); + break; + case RF90_PATH_C: + break; + case RF90_PATH_D: + break; + } + + /* Restore RFENV control type */ + switch (rfpath) { + case RF90_PATH_A: + case RF90_PATH_C: + rtl92s_phy_set_bb_reg(hw, pphyreg->rfintfs, BRFSI_RFENV, + u4reg_val); + break; + case RF90_PATH_B: + case RF90_PATH_D: + rtl92s_phy_set_bb_reg(hw, pphyreg->rfintfs, + BRFSI_RFENV << 16, + u4reg_val); + break; + } + + if (!rtstatus) { + pr_err("Radio[%d] Fail!!\n", rfpath); + goto fail; + } + + } + + return rtstatus; + +fail: + return rtstatus; +} + +void rtl92s_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) | 0x0400); + rtl_set_rfreg(hw, RF90_PATH_A, 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)); + rtl_set_rfreg(hw, RF90_PATH_A, RF_CHNLBW, RFREG_OFFSET_MASK, + rtlphy->rfreg_chnlval[0]); + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "unknown bandwidth: %#X\n", bandwidth); + break; + } +} diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/rf.h b/drivers/net/wireless/rtlwifi/rtl8192se/rf.h new file mode 100644 index 00000000..8a29eb94 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192se/rf.h @@ -0,0 +1,43 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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 __INC_RTL92S_RF_H +#define __INC_RTL92S_RF_H + +#define RF6052_MAX_TX_PWR 0x3F + +void rtl92s_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw, + u8 bandwidth); +bool rtl92s_phy_rf6052_config(struct ieee80211_hw *hw) ; +void rtl92s_phy_rf6052_set_ccktxpower(struct ieee80211_hw *hw, + u8 powerlevel); +void rtl92s_phy_rf6052_set_ofdmtxpower(struct ieee80211_hw *hw, + u8 *p_pwrlevel, u8 chnl); + +#endif + diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/sw.c b/drivers/net/wireless/rtlwifi/rtl8192se/sw.c new file mode 100644 index 00000000..f1b36005 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192se/sw.c @@ -0,0 +1,470 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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> + * + *****************************************************************************/ + +#include "../wifi.h" +#include "../core.h" +#include "../pci.h" +#include "../base.h" +#include "../pci.h" +#include "reg.h" +#include "def.h" +#include "phy.h" +#include "dm.h" +#include "fw.h" +#include "hw.h" +#include "sw.h" +#include "trx.h" +#include "led.h" + +#include <linux/module.h> + +static void rtl92s_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 = 2; + + /*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 = 2; + + /* + * 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 = 2; +} + +static void rtl92se_fw_cb(const struct firmware *firmware, void *context) +{ + struct ieee80211_hw *hw = context; + struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(pcipriv); + struct rt_firmware *pfirmware = NULL; + int err; + + RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD, + "Firmware callback routine entered!\n"); + complete(&rtlpriv->firmware_loading_complete); + if (!firmware) { + pr_err("Firmware %s not available\n", rtlpriv->cfg->fw_name); + rtlpriv->max_fw_size = 0; + return; + } + if (firmware->size > rtlpriv->max_fw_size) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "Firmware is too big!\n"); + rtlpriv->max_fw_size = 0; + release_firmware(firmware); + return; + } + pfirmware = (struct rt_firmware *)rtlpriv->rtlhal.pfirmware; + memcpy(pfirmware->sz_fw_tmpbuffer, firmware->data, firmware->size); + pfirmware->sz_fw_tmpbufferlen = firmware->size; + release_firmware(firmware); + + err = ieee80211_register_hw(hw); + if (err) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "Can't register mac80211 hw\n"); + return; + } else { + rtlpriv->mac80211.mac80211_registered = 1; + } + rtlpci->irq_alloc = 1; + set_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status); + + /*init rfkill */ + rtl_init_rfkill(hw); +} + +static int rtl92s_init_sw_vars(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + int err = 0; + u16 earlyrxthreshold = 7; + + rtlpriv->dm.dm_initialgain_enable = true; + rtlpriv->dm.dm_flag = 0; + rtlpriv->dm.disable_framebursting = false; + rtlpriv->dm.thermalvalue = 0; + rtlpriv->dm.useramask = true; + + /* compatible 5G band 91se just 2.4G band & smsp */ + rtlpriv->rtlhal.current_bandtype = BAND_ON_2_4G; + rtlpriv->rtlhal.bandset = BAND_ON_2_4G; + rtlpriv->rtlhal.macphymode = SINGLEMAC_SINGLEPHY; + + rtlpci->transmit_config = 0; + + rtlpci->receive_config = + RCR_APPFCS | + RCR_APWRMGT | + /*RCR_ADD3 |*/ + RCR_AMF | + RCR_ADF | + RCR_APP_MIC | + RCR_APP_ICV | + RCR_AICV | + /* Accept ICV error, CRC32 Error */ + RCR_ACRC32 | + RCR_AB | + /* Accept Broadcast, Multicast */ + RCR_AM | + /* Accept Physical match */ + RCR_APM | + /* Accept Destination Address packets */ + /*RCR_AAP |*/ + RCR_APP_PHYST_STAFF | + /* Accept PHY status */ + RCR_APP_PHYST_RXFF | + (earlyrxthreshold << RCR_FIFO_OFFSET); + + rtlpci->irq_mask[0] = (u32) + (IMR_ROK | + IMR_VODOK | + IMR_VIDOK | + IMR_BEDOK | + IMR_BKDOK | + IMR_HCCADOK | + IMR_MGNTDOK | + IMR_COMDOK | + IMR_HIGHDOK | + IMR_BDOK | + IMR_RXCMDOK | + /*IMR_TIMEOUT0 |*/ + IMR_RDU | + IMR_RXFOVW | + IMR_BCNINT + /*| IMR_TXFOVW*/ + /*| IMR_TBDOK | + IMR_TBDER*/); + + rtlpci->irq_mask[1] = (u32) 0; + + rtlpci->shortretry_limit = 0x30; + rtlpci->longretry_limit = 0x30; + + rtlpci->first_init = true; + + /* for debug level */ + rtlpriv->dbg.global_debuglevel = rtlpriv->cfg->mod_params->debug; + /* for LPS & IPS */ + rtlpriv->psc.inactiveps = rtlpriv->cfg->mod_params->inactiveps; + rtlpriv->psc.swctrl_lps = rtlpriv->cfg->mod_params->swctrl_lps; + rtlpriv->psc.fwctrl_lps = rtlpriv->cfg->mod_params->fwctrl_lps; + if (!rtlpriv->psc.inactiveps) + pr_info("Power Save off (module option)\n"); + if (!rtlpriv->psc.fwctrl_lps) + pr_info("FW Power Save off (module option)\n"); + rtlpriv->psc.reg_fwctrl_lps = 3; + rtlpriv->psc.reg_max_lps_awakeintvl = 5; + /* for ASPM, you can close aspm through + * set const_support_pciaspm = 0 */ + rtl92s_init_aspm_vars(hw); + + if (rtlpriv->psc.reg_fwctrl_lps == 1) + rtlpriv->psc.fwctrl_psmode = FW_PS_MIN_MODE; + else if (rtlpriv->psc.reg_fwctrl_lps == 2) + rtlpriv->psc.fwctrl_psmode = FW_PS_MAX_MODE; + else if (rtlpriv->psc.reg_fwctrl_lps == 3) + rtlpriv->psc.fwctrl_psmode = FW_PS_DTIM_MODE; + + /* for firmware buf */ + rtlpriv->rtlhal.pfirmware = vzalloc(sizeof(struct rt_firmware)); + if (!rtlpriv->rtlhal.pfirmware) + return 1; + + rtlpriv->max_fw_size = RTL8190_MAX_RAW_FIRMWARE_CODE_SIZE; + + pr_info("Driver for Realtek RTL8192SE/RTL8191SE\n" + "Loading firmware %s\n", rtlpriv->cfg->fw_name); + /* request fw */ + err = request_firmware_nowait(THIS_MODULE, 1, rtlpriv->cfg->fw_name, + rtlpriv->io.dev, GFP_KERNEL, hw, + rtl92se_fw_cb); + if (err) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "Failed to request firmware!\n"); + return 1; + } + + return err; +} + +static void rtl92s_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; + } +} + +static struct rtl_hal_ops rtl8192se_hal_ops = { + .init_sw_vars = rtl92s_init_sw_vars, + .deinit_sw_vars = rtl92s_deinit_sw_vars, + .read_eeprom_info = rtl92se_read_eeprom_info, + .interrupt_recognized = rtl92se_interrupt_recognized, + .hw_init = rtl92se_hw_init, + .hw_disable = rtl92se_card_disable, + .hw_suspend = rtl92se_suspend, + .hw_resume = rtl92se_resume, + .enable_interrupt = rtl92se_enable_interrupt, + .disable_interrupt = rtl92se_disable_interrupt, + .set_network_type = rtl92se_set_network_type, + .set_chk_bssid = rtl92se_set_check_bssid, + .set_qos = rtl92se_set_qos, + .set_bcn_reg = rtl92se_set_beacon_related_registers, + .set_bcn_intv = rtl92se_set_beacon_interval, + .update_interrupt_mask = rtl92se_update_interrupt_mask, + .get_hw_reg = rtl92se_get_hw_reg, + .set_hw_reg = rtl92se_set_hw_reg, + .update_rate_tbl = rtl92se_update_hal_rate_tbl, + .fill_tx_desc = rtl92se_tx_fill_desc, + .fill_tx_cmddesc = rtl92se_tx_fill_cmddesc, + .query_rx_desc = rtl92se_rx_query_desc, + .set_channel_access = rtl92se_update_channel_access_setting, + .radio_onoff_checking = rtl92se_gpio_radio_on_off_checking, + .set_bw_mode = rtl92s_phy_set_bw_mode, + .switch_channel = rtl92s_phy_sw_chnl, + .dm_watchdog = rtl92s_dm_watchdog, + .scan_operation_backup = rtl92s_phy_scan_operation_backup, + .set_rf_power_state = rtl92s_phy_set_rf_power_state, + .led_control = rtl92se_led_control, + .set_desc = rtl92se_set_desc, + .get_desc = rtl92se_get_desc, + .tx_polling = rtl92se_tx_polling, + .enable_hw_sec = rtl92se_enable_hw_security_config, + .set_key = rtl92se_set_key, + .init_sw_leds = rtl92se_init_sw_leds, + .get_bbreg = rtl92s_phy_query_bb_reg, + .set_bbreg = rtl92s_phy_set_bb_reg, + .get_rfreg = rtl92s_phy_query_rf_reg, + .set_rfreg = rtl92s_phy_set_rf_reg, +}; + +static struct rtl_mod_params rtl92se_mod_params = { + .sw_crypto = false, + .inactiveps = true, + .swctrl_lps = true, + .fwctrl_lps = false, + .debug = DBG_EMERG, +}; + +/* Because memory R/W bursting will cause system hang/crash + * for 92se, so we don't read back after every write action */ +static struct rtl_hal_cfg rtl92se_hal_cfg = { + .bar_id = 1, + .write_readback = false, + .name = "rtl92s_pci", + .fw_name = "rtlwifi/rtl8192sefw.bin", + .ops = &rtl8192se_hal_ops, + .mod_params = &rtl92se_mod_params, + + .maps[SYS_ISO_CTRL] = REG_SYS_ISO_CTRL, + .maps[SYS_FUNC_EN] = REG_SYS_FUNC_EN, + .maps[SYS_CLK] = SYS_CLKR, + .maps[MAC_RCR_AM] = RCR_AM, + .maps[MAC_RCR_AB] = RCR_AB, + .maps[MAC_RCR_ACRC32] = RCR_ACRC32, + .maps[MAC_RCR_ACF] = RCR_ACF, + .maps[MAC_RCR_AAP] = RCR_AAP, + + .maps[EFUSE_TEST] = REG_EFUSE_TEST, + .maps[EFUSE_CTRL] = REG_EFUSE_CTRL, + .maps[EFUSE_CLK] = REG_EFUSE_CLK, + .maps[EFUSE_CLK_CTRL] = REG_EFUSE_CTRL, + .maps[EFUSE_PWC_EV12V] = 0, /* nouse for 8192se */ + .maps[EFUSE_FEN_ELDR] = 0, /* nouse for 8192se */ + .maps[EFUSE_LOADER_CLK_EN] = 0,/* nouse for 8192se */ + .maps[EFUSE_ANA8M] = EFUSE_ANA8M, + .maps[EFUSE_HWSET_MAX_SIZE] = HWSET_MAX_SIZE_92S, + .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_RWCAM, + .maps[WCAMI] = REG_WCAMI, + .maps[RCAMO] = REG_RCAMO, + .maps[CAMDBG] = REG_CAMDBG, + .maps[SECR] = REG_SECR, + .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, + .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_BCNINT, + .maps[RTL_IMR_RXFOVW] = IMR_RXFOVW, + .maps[RTL_IMR_RDU] = IMR_RDU, + .maps[RTL_IMR_ATIMEND] = IMR_ATIMEND, + .maps[RTL_IMR_BDOK] = IMR_BDOK, + .maps[RTL_IMR_MGNTDOK] = IMR_MGNTDOK, + .maps[RTL_IMR_TBDER] = IMR_TBDER, + .maps[RTL_IMR_HIGHDOK] = IMR_HIGHDOK, + .maps[RTL_IMR_COMDOK] = IMR_COMDOK, + .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_BCNINT | IMR_TBDOK | IMR_TBDER), + + .maps[RTL_RC_CCK_RATE1M] = DESC92_RATE1M, + .maps[RTL_RC_CCK_RATE2M] = DESC92_RATE2M, + .maps[RTL_RC_CCK_RATE5_5M] = DESC92_RATE5_5M, + .maps[RTL_RC_CCK_RATE11M] = DESC92_RATE11M, + .maps[RTL_RC_OFDM_RATE6M] = DESC92_RATE6M, + .maps[RTL_RC_OFDM_RATE9M] = DESC92_RATE9M, + .maps[RTL_RC_OFDM_RATE12M] = DESC92_RATE12M, + .maps[RTL_RC_OFDM_RATE18M] = DESC92_RATE18M, + .maps[RTL_RC_OFDM_RATE24M] = DESC92_RATE24M, + .maps[RTL_RC_OFDM_RATE36M] = DESC92_RATE36M, + .maps[RTL_RC_OFDM_RATE48M] = DESC92_RATE48M, + .maps[RTL_RC_OFDM_RATE54M] = DESC92_RATE54M, + + .maps[RTL_RC_HT_RATEMCS7] = DESC92_RATEMCS7, + .maps[RTL_RC_HT_RATEMCS15] = DESC92_RATEMCS15, +}; + +static struct pci_device_id rtl92se_pci_ids[] __devinitdata = { + {RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8192, rtl92se_hal_cfg)}, + {RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8171, rtl92se_hal_cfg)}, + {RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8172, rtl92se_hal_cfg)}, + {RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8173, rtl92se_hal_cfg)}, + {RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8174, rtl92se_hal_cfg)}, + {}, +}; + +MODULE_DEVICE_TABLE(pci, rtl92se_pci_ids); + +MODULE_AUTHOR("lizhaoming <chaoming_li@realsil.com.cn>"); +MODULE_AUTHOR("Realtek WlanFAE <wlanfae@realtek.com>"); +MODULE_AUTHOR("Larry Finger <Larry.Finger@lwfinger.net>"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Realtek 8192S/8191S 802.11n PCI wireless"); +MODULE_FIRMWARE("rtlwifi/rtl8192sefw.bin"); + +module_param_named(swenc, rtl92se_mod_params.sw_crypto, bool, 0444); +module_param_named(debug, rtl92se_mod_params.debug, int, 0444); +module_param_named(ips, rtl92se_mod_params.inactiveps, bool, 0444); +module_param_named(swlps, rtl92se_mod_params.swctrl_lps, bool, 0444); +module_param_named(fwlps, rtl92se_mod_params.fwctrl_lps, bool, 0444); +MODULE_PARM_DESC(swenc, "Set to 1 for software crypto (default 0)\n"); +MODULE_PARM_DESC(ips, "Set to 0 to not use link power save (default 1)\n"); +MODULE_PARM_DESC(swlps, "Set to 1 to use SW control power save (default 0)\n"); +MODULE_PARM_DESC(fwlps, "Set to 1 to use FW control power save (default 1)\n"); +MODULE_PARM_DESC(debug, "Set debug level (0-5) (default 0)"); + +static const struct dev_pm_ops rtlwifi_pm_ops = { + .suspend = rtl_pci_suspend, + .resume = rtl_pci_resume, + .freeze = rtl_pci_suspend, + .thaw = rtl_pci_resume, + .poweroff = rtl_pci_suspend, + .restore = rtl_pci_resume, +}; + +static struct pci_driver rtl92se_driver = { + .name = KBUILD_MODNAME, + .id_table = rtl92se_pci_ids, + .probe = rtl_pci_probe, + .remove = rtl_pci_disconnect, + .driver.pm = &rtlwifi_pm_ops, +}; + +static int __init rtl92se_module_init(void) +{ + int ret = 0; + + ret = pci_register_driver(&rtl92se_driver); + if (ret) + RT_ASSERT(false, "No device found\n"); + + return ret; +} + +static void __exit rtl92se_module_exit(void) +{ + pci_unregister_driver(&rtl92se_driver); +} + +module_init(rtl92se_module_init); +module_exit(rtl92se_module_exit); diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/sw.h b/drivers/net/wireless/rtlwifi/rtl8192se/sw.h new file mode 100644 index 00000000..2eb88862 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192se/sw.h @@ -0,0 +1,36 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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. + * + *****************************************************************************/ +#ifndef __REALTEK_PCI92SE_SW_H__ +#define __REALTEK_PCI92SE_SW_H__ + +#define EFUSE_MAX_SECTION 16 + +int rtl92se_init_sw(struct ieee80211_hw *hw); +void rtl92se_deinit_sw(struct ieee80211_hw *hw); +void rtl92se_init_var_map(struct ieee80211_hw *hw); + +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/table.c b/drivers/net/wireless/rtlwifi/rtl8192se/table.c new file mode 100644 index 00000000..f1a73f75 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192se/table.c @@ -0,0 +1,634 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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> + * + * Created on 2010/ 5/18, 1:41 + *****************************************************************************/ + +#include "table.h" + +u32 rtl8192sephy_reg_2t2rarray[PHY_REG_2T2RARRAYLENGTH] = { + 0x01c, 0x07000000, + 0x800, 0x00040000, + 0x804, 0x00008003, + 0x808, 0x0000fc00, + 0x80c, 0x0000000a, + 0x810, 0x10005088, + 0x814, 0x020c3d10, + 0x818, 0x00200185, + 0x81c, 0x00000000, + 0x820, 0x01000000, + 0x824, 0x00390004, + 0x828, 0x01000000, + 0x82c, 0x00390004, + 0x830, 0x00000004, + 0x834, 0x00690200, + 0x838, 0x00000004, + 0x83c, 0x00690200, + 0x840, 0x00010000, + 0x844, 0x00010000, + 0x848, 0x00000000, + 0x84c, 0x00000000, + 0x850, 0x00000000, + 0x854, 0x00000000, + 0x858, 0x48484848, + 0x85c, 0x65a965a9, + 0x860, 0x0f7f0130, + 0x864, 0x0f7f0130, + 0x868, 0x0f7f0130, + 0x86c, 0x0f7f0130, + 0x870, 0x03000700, + 0x874, 0x03000300, + 0x878, 0x00020002, + 0x87c, 0x004f0201, + 0x880, 0xa8300ac1, + 0x884, 0x00000058, + 0x888, 0x00000008, + 0x88c, 0x00000004, + 0x890, 0x00000000, + 0x894, 0xfffffffe, + 0x898, 0x40302010, + 0x89c, 0x00706050, + 0x8b0, 0x00000000, + 0x8e0, 0x00000000, + 0x8e4, 0x00000000, + 0xe00, 0x30333333, + 0xe04, 0x2a2d2e2f, + 0xe08, 0x00003232, + 0xe10, 0x30333333, + 0xe14, 0x2a2d2e2f, + 0xe18, 0x30333333, + 0xe1c, 0x2a2d2e2f, + 0xe30, 0x01007c00, + 0xe34, 0x01004800, + 0xe38, 0x1000dc1f, + 0xe3c, 0x10008c1f, + 0xe40, 0x021400a0, + 0xe44, 0x281600a0, + 0xe48, 0xf8000001, + 0xe4c, 0x00002910, + 0xe50, 0x01007c00, + 0xe54, 0x01004800, + 0xe58, 0x1000dc1f, + 0xe5c, 0x10008c1f, + 0xe60, 0x021400a0, + 0xe64, 0x281600a0, + 0xe6c, 0x00002910, + 0xe70, 0x31ed92fb, + 0xe74, 0x361536fb, + 0xe78, 0x361536fb, + 0xe7c, 0x361536fb, + 0xe80, 0x361536fb, + 0xe84, 0x000d92fb, + 0xe88, 0x000d92fb, + 0xe8c, 0x31ed92fb, + 0xed0, 0x31ed92fb, + 0xed4, 0x31ed92fb, + 0xed8, 0x000d92fb, + 0xedc, 0x000d92fb, + 0xee0, 0x000d92fb, + 0xee4, 0x015e5448, + 0xee8, 0x21555448, + 0x900, 0x00000000, + 0x904, 0x00000023, + 0x908, 0x00000000, + 0x90c, 0x01121313, + 0xa00, 0x00d047c8, + 0xa04, 0x80ff0008, + 0xa08, 0x8ccd8300, + 0xa0c, 0x2e62120f, + 0xa10, 0x9500bb78, + 0xa14, 0x11144028, + 0xa18, 0x00881117, + 0xa1c, 0x89140f00, + 0xa20, 0x1a1b0000, + 0xa24, 0x090e1317, + 0xa28, 0x00000204, + 0xa2c, 0x10d30000, + 0xc00, 0x40071d40, + 0xc04, 0x00a05633, + 0xc08, 0x000000e4, + 0xc0c, 0x6c6c6c6c, + 0xc10, 0x08800000, + 0xc14, 0x40000100, + 0xc18, 0x08000000, + 0xc1c, 0x40000100, + 0xc20, 0x08000000, + 0xc24, 0x40000100, + 0xc28, 0x08000000, + 0xc2c, 0x40000100, + 0xc30, 0x6de9ac44, + 0xc34, 0x469652cf, + 0xc38, 0x49795994, + 0xc3c, 0x0a979764, + 0xc40, 0x1f7c403f, + 0xc44, 0x000100b7, + 0xc48, 0xec020000, + 0xc4c, 0x007f037f, + 0xc50, 0x69543420, + 0xc54, 0x433c0094, + 0xc58, 0x69543420, + 0xc5c, 0x433c0094, + 0xc60, 0x69543420, + 0xc64, 0x433c0094, + 0xc68, 0x69543420, + 0xc6c, 0x433c0094, + 0xc70, 0x2c7f000d, + 0xc74, 0x0186155b, + 0xc78, 0x0000001f, + 0xc7c, 0x00b91612, + 0xc80, 0x40000100, + 0xc84, 0x20f60000, + 0xc88, 0x20000080, + 0xc8c, 0x20200000, + 0xc90, 0x40000100, + 0xc94, 0x00000000, + 0xc98, 0x40000100, + 0xc9c, 0x00000000, + 0xca0, 0x00492492, + 0xca4, 0x00000000, + 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, 0x00000000, + 0xce8, 0x37644302, + 0xcec, 0x2f97d40c, + 0xd00, 0x00000750, + 0xd04, 0x00000403, + 0xd08, 0x0000907f, + 0xd0c, 0x00000001, + 0xd10, 0xa0633333, + 0xd14, 0x33333c63, + 0xd18, 0x6a8f5b6b, + 0xd1c, 0x00000000, + 0xd20, 0x00000000, + 0xd24, 0x00000000, + 0xd28, 0x00000000, + 0xd2c, 0xcc979975, + 0xd30, 0x00000000, + 0xd34, 0x00000000, + 0xd38, 0x00000000, + 0xd3c, 0x00027293, + 0xd40, 0x00000000, + 0xd44, 0x00000000, + 0xd48, 0x00000000, + 0xd50, 0x6437140a, + 0xd54, 0x024dbd02, + 0xd58, 0x00000000, + 0xd5c, 0x30032064, + 0xd60, 0x4653de68, + 0xd64, 0x00518a3c, + 0xd68, 0x00002101, + 0xf14, 0x00000003, + 0xf4c, 0x00000000, + 0xf00, 0x00000300, +}; + +u32 rtl8192sephy_changeto_1t1rarray[PHY_CHANGETO_1T1RARRAYLENGTH] = { + 0x844, 0xffffffff, 0x00010000, + 0x804, 0x0000000f, 0x00000001, + 0x824, 0x00f0000f, 0x00300004, + 0x82c, 0x00f0000f, 0x00100002, + 0x870, 0x04000000, 0x00000001, + 0x864, 0x00000400, 0x00000000, + 0x878, 0x000f000f, 0x00000002, + 0xe74, 0x0f000000, 0x00000002, + 0xe78, 0x0f000000, 0x00000002, + 0xe7c, 0x0f000000, 0x00000002, + 0xe80, 0x0f000000, 0x00000002, + 0x90c, 0x000000ff, 0x00000011, + 0xc04, 0x000000ff, 0x00000011, + 0xd04, 0x0000000f, 0x00000001, + 0x1f4, 0xffff0000, 0x00007777, + 0x234, 0xf8000000, 0x0000000a, +}; + +u32 rtl8192sephy_changeto_1t2rarray[PHY_CHANGETO_1T2RARRAYLENGTH] = { + 0x804, 0x0000000f, 0x00000003, + 0x824, 0x00f0000f, 0x00300004, + 0x82c, 0x00f0000f, 0x00300002, + 0x870, 0x04000000, 0x00000001, + 0x864, 0x00000400, 0x00000000, + 0x878, 0x000f000f, 0x00000002, + 0xe74, 0x0f000000, 0x00000002, + 0xe78, 0x0f000000, 0x00000002, + 0xe7c, 0x0f000000, 0x00000002, + 0xe80, 0x0f000000, 0x00000002, + 0x90c, 0x000000ff, 0x00000011, + 0xc04, 0x000000ff, 0x00000033, + 0xd04, 0x0000000f, 0x00000003, + 0x1f4, 0xffff0000, 0x00007777, + 0x234, 0xf8000000, 0x0000000a, +}; + +u32 rtl8192sephy_reg_array_pg[PHY_REG_ARRAY_PGLENGTH] = { + 0xe00, 0xffffffff, 0x06090909, + 0xe04, 0xffffffff, 0x00030406, + 0xe08, 0x0000ff00, 0x00000000, + 0xe10, 0xffffffff, 0x0a0c0d0e, + 0xe14, 0xffffffff, 0x04070809, + 0xe18, 0xffffffff, 0x0a0c0d0e, + 0xe1c, 0xffffffff, 0x04070809, + 0xe00, 0xffffffff, 0x04040404, + 0xe04, 0xffffffff, 0x00020204, + 0xe08, 0x0000ff00, 0x00000000, + 0xe10, 0xffffffff, 0x02040404, + 0xe14, 0xffffffff, 0x00000002, + 0xe18, 0xffffffff, 0x02040404, + 0xe1c, 0xffffffff, 0x00000002, + 0xe00, 0xffffffff, 0x04040404, + 0xe04, 0xffffffff, 0x00020204, + 0xe08, 0x0000ff00, 0x00000000, + 0xe10, 0xffffffff, 0x02040404, + 0xe14, 0xffffffff, 0x00000002, + 0xe18, 0xffffffff, 0x02040404, + 0xe1c, 0xffffffff, 0x00000002, + 0xe00, 0xffffffff, 0x02020202, + 0xe04, 0xffffffff, 0x00020202, + 0xe08, 0x0000ff00, 0x00000000, + 0xe10, 0xffffffff, 0x02020202, + 0xe14, 0xffffffff, 0x00000002, + 0xe18, 0xffffffff, 0x02020202, + 0xe1c, 0xffffffff, 0x00000002, +}; + +u32 rtl8192seradioa_1t_array[RADIOA_1T_ARRAYLENGTH] = { + 0x000, 0x00030159, + 0x001, 0x00030250, + 0x002, 0x00010000, + 0x010, 0x0008000f, + 0x011, 0x000231fc, + 0x010, 0x000c000f, + 0x011, 0x0003f9f8, + 0x010, 0x0002000f, + 0x011, 0x00020101, + 0x014, 0x0001093e, + 0x014, 0x0009093e, + 0x015, 0x0000f8f4, + 0x017, 0x000f6500, + 0x01a, 0x00013056, + 0x01b, 0x00060000, + 0x01c, 0x00000300, + 0x01e, 0x00031059, + 0x021, 0x00054000, + 0x022, 0x0000083c, + 0x023, 0x00001558, + 0x024, 0x00000060, + 0x025, 0x00022583, + 0x026, 0x0000f200, + 0x027, 0x000eacf1, + 0x028, 0x0009bd54, + 0x029, 0x00004582, + 0x02a, 0x00000001, + 0x02b, 0x00021334, + 0x02a, 0x00000000, + 0x02b, 0x0000000a, + 0x02a, 0x00000001, + 0x02b, 0x00000808, + 0x02b, 0x00053333, + 0x02c, 0x0000000c, + 0x02a, 0x00000002, + 0x02b, 0x00000808, + 0x02b, 0x0005b333, + 0x02c, 0x0000000d, + 0x02a, 0x00000003, + 0x02b, 0x00000808, + 0x02b, 0x00063333, + 0x02c, 0x0000000d, + 0x02a, 0x00000004, + 0x02b, 0x00000808, + 0x02b, 0x0006b333, + 0x02c, 0x0000000d, + 0x02a, 0x00000005, + 0x02b, 0x00000709, + 0x02b, 0x00053333, + 0x02c, 0x0000000d, + 0x02a, 0x00000006, + 0x02b, 0x00000709, + 0x02b, 0x0005b333, + 0x02c, 0x0000000d, + 0x02a, 0x00000007, + 0x02b, 0x00000709, + 0x02b, 0x00063333, + 0x02c, 0x0000000d, + 0x02a, 0x00000008, + 0x02b, 0x00000709, + 0x02b, 0x0006b333, + 0x02c, 0x0000000d, + 0x02a, 0x00000009, + 0x02b, 0x0000060a, + 0x02b, 0x00053333, + 0x02c, 0x0000000d, + 0x02a, 0x0000000a, + 0x02b, 0x0000060a, + 0x02b, 0x0005b333, + 0x02c, 0x0000000d, + 0x02a, 0x0000000b, + 0x02b, 0x0000060a, + 0x02b, 0x00063333, + 0x02c, 0x0000000d, + 0x02a, 0x0000000c, + 0x02b, 0x0000060a, + 0x02b, 0x0006b333, + 0x02c, 0x0000000d, + 0x02a, 0x0000000d, + 0x02b, 0x0000050b, + 0x02b, 0x00053333, + 0x02c, 0x0000000d, + 0x02a, 0x0000000e, + 0x02b, 0x0000050b, + 0x02b, 0x00066623, + 0x02c, 0x0000001a, + 0x02a, 0x000e4000, + 0x030, 0x00020000, + 0x031, 0x000b9631, + 0x032, 0x0000130d, + 0x033, 0x00000187, + 0x013, 0x00019e6c, + 0x013, 0x00015e94, + 0x000, 0x00010159, + 0x018, 0x0000f401, + 0x0fe, 0x00000000, + 0x01e, 0x0003105b, + 0x0fe, 0x00000000, + 0x000, 0x00030159, + 0x010, 0x0004000f, + 0x011, 0x000203f9, +}; + +u32 rtl8192seradiob_array[RADIOB_ARRAYLENGTH] = { + 0x000, 0x00030159, + 0x001, 0x00001041, + 0x002, 0x00011000, + 0x005, 0x00080fc0, + 0x007, 0x000fc803, + 0x013, 0x00017cb0, + 0x013, 0x00011cc0, + 0x013, 0x0000dc60, + 0x013, 0x00008c60, + 0x013, 0x00004450, + 0x013, 0x00000020, +}; + +u32 rtl8192seradiob_gm_array[RADIOB_GM_ARRAYLENGTH] = { + 0x000, 0x00030159, + 0x001, 0x00001041, + 0x002, 0x00011000, + 0x005, 0x00080fc0, + 0x007, 0x000fc803, +}; + +u32 rtl8192semac_2t_array[MAC_2T_ARRAYLENGTH] = { + 0x020, 0x00000035, + 0x048, 0x0000000e, + 0x049, 0x000000f0, + 0x04a, 0x00000077, + 0x04b, 0x00000083, + 0x0b5, 0x00000021, + 0x0dc, 0x000000ff, + 0x0dd, 0x000000ff, + 0x0de, 0x000000ff, + 0x0df, 0x000000ff, + 0x116, 0x00000000, + 0x117, 0x00000000, + 0x118, 0x00000000, + 0x119, 0x00000000, + 0x11a, 0x00000000, + 0x11b, 0x00000000, + 0x11c, 0x00000000, + 0x11d, 0x00000000, + 0x160, 0x0000000b, + 0x161, 0x0000000b, + 0x162, 0x0000000b, + 0x163, 0x0000000b, + 0x164, 0x0000000b, + 0x165, 0x0000000b, + 0x166, 0x0000000b, + 0x167, 0x0000000b, + 0x168, 0x0000000b, + 0x169, 0x0000000b, + 0x16a, 0x0000000b, + 0x16b, 0x0000000b, + 0x16c, 0x0000000b, + 0x16d, 0x0000000b, + 0x16e, 0x0000000b, + 0x16f, 0x0000000b, + 0x170, 0x0000000b, + 0x171, 0x0000000b, + 0x172, 0x0000000b, + 0x173, 0x0000000b, + 0x174, 0x0000000b, + 0x175, 0x0000000b, + 0x176, 0x0000000b, + 0x177, 0x0000000b, + 0x178, 0x0000000b, + 0x179, 0x0000000b, + 0x17a, 0x0000000b, + 0x17b, 0x0000000b, + 0x17c, 0x0000000b, + 0x17d, 0x0000000b, + 0x17e, 0x0000000b, + 0x17f, 0x0000000b, + 0x236, 0x0000000c, + 0x503, 0x00000022, + 0x560, 0x00000000, +}; + +u32 rtl8192seagctab_array[AGCTAB_ARRAYLENGTH] = { + 0xc78, 0x7f000001, + 0xc78, 0x7f010001, + 0xc78, 0x7e020001, + 0xc78, 0x7d030001, + 0xc78, 0x7c040001, + 0xc78, 0x7b050001, + 0xc78, 0x7a060001, + 0xc78, 0x79070001, + 0xc78, 0x78080001, + 0xc78, 0x77090001, + 0xc78, 0x760a0001, + 0xc78, 0x750b0001, + 0xc78, 0x740c0001, + 0xc78, 0x730d0001, + 0xc78, 0x720e0001, + 0xc78, 0x710f0001, + 0xc78, 0x70100001, + 0xc78, 0x6f110001, + 0xc78, 0x6f120001, + 0xc78, 0x6e130001, + 0xc78, 0x6d140001, + 0xc78, 0x6d150001, + 0xc78, 0x6c160001, + 0xc78, 0x6b170001, + 0xc78, 0x6a180001, + 0xc78, 0x6a190001, + 0xc78, 0x691a0001, + 0xc78, 0x681b0001, + 0xc78, 0x671c0001, + 0xc78, 0x661d0001, + 0xc78, 0x651e0001, + 0xc78, 0x641f0001, + 0xc78, 0x63200001, + 0xc78, 0x4c210001, + 0xc78, 0x4b220001, + 0xc78, 0x4a230001, + 0xc78, 0x49240001, + 0xc78, 0x48250001, + 0xc78, 0x47260001, + 0xc78, 0x46270001, + 0xc78, 0x45280001, + 0xc78, 0x44290001, + 0xc78, 0x2c2a0001, + 0xc78, 0x2b2b0001, + 0xc78, 0x2a2c0001, + 0xc78, 0x292d0001, + 0xc78, 0x282e0001, + 0xc78, 0x272f0001, + 0xc78, 0x26300001, + 0xc78, 0x25310001, + 0xc78, 0x24320001, + 0xc78, 0x23330001, + 0xc78, 0x22340001, + 0xc78, 0x09350001, + 0xc78, 0x08360001, + 0xc78, 0x07370001, + 0xc78, 0x06380001, + 0xc78, 0x05390001, + 0xc78, 0x043a0001, + 0xc78, 0x033b0001, + 0xc78, 0x023c0001, + 0xc78, 0x013d0001, + 0xc78, 0x003e0001, + 0xc78, 0x003f0001, + 0xc78, 0x7f400001, + 0xc78, 0x7f410001, + 0xc78, 0x7e420001, + 0xc78, 0x7d430001, + 0xc78, 0x7c440001, + 0xc78, 0x7b450001, + 0xc78, 0x7a460001, + 0xc78, 0x79470001, + 0xc78, 0x78480001, + 0xc78, 0x77490001, + 0xc78, 0x764a0001, + 0xc78, 0x754b0001, + 0xc78, 0x744c0001, + 0xc78, 0x734d0001, + 0xc78, 0x724e0001, + 0xc78, 0x714f0001, + 0xc78, 0x70500001, + 0xc78, 0x6f510001, + 0xc78, 0x6f520001, + 0xc78, 0x6e530001, + 0xc78, 0x6d540001, + 0xc78, 0x6d550001, + 0xc78, 0x6c560001, + 0xc78, 0x6b570001, + 0xc78, 0x6a580001, + 0xc78, 0x6a590001, + 0xc78, 0x695a0001, + 0xc78, 0x685b0001, + 0xc78, 0x675c0001, + 0xc78, 0x665d0001, + 0xc78, 0x655e0001, + 0xc78, 0x645f0001, + 0xc78, 0x63600001, + 0xc78, 0x4c610001, + 0xc78, 0x4b620001, + 0xc78, 0x4a630001, + 0xc78, 0x49640001, + 0xc78, 0x48650001, + 0xc78, 0x47660001, + 0xc78, 0x46670001, + 0xc78, 0x45680001, + 0xc78, 0x44690001, + 0xc78, 0x2c6a0001, + 0xc78, 0x2b6b0001, + 0xc78, 0x2a6c0001, + 0xc78, 0x296d0001, + 0xc78, 0x286e0001, + 0xc78, 0x276f0001, + 0xc78, 0x26700001, + 0xc78, 0x25710001, + 0xc78, 0x24720001, + 0xc78, 0x23730001, + 0xc78, 0x22740001, + 0xc78, 0x09750001, + 0xc78, 0x08760001, + 0xc78, 0x07770001, + 0xc78, 0x06780001, + 0xc78, 0x05790001, + 0xc78, 0x047a0001, + 0xc78, 0x037b0001, + 0xc78, 0x027c0001, + 0xc78, 0x017d0001, + 0xc78, 0x007e0001, + 0xc78, 0x007f0001, + 0xc78, 0x3000001e, + 0xc78, 0x3001001e, + 0xc78, 0x3002001e, + 0xc78, 0x3003001e, + 0xc78, 0x3004001e, + 0xc78, 0x3405001e, + 0xc78, 0x3806001e, + 0xc78, 0x3e07001e, + 0xc78, 0x3e08001e, + 0xc78, 0x4409001e, + 0xc78, 0x460a001e, + 0xc78, 0x480b001e, + 0xc78, 0x480c001e, + 0xc78, 0x4e0d001e, + 0xc78, 0x560e001e, + 0xc78, 0x5a0f001e, + 0xc78, 0x5e10001e, + 0xc78, 0x6211001e, + 0xc78, 0x6c12001e, + 0xc78, 0x7213001e, + 0xc78, 0x7214001e, + 0xc78, 0x7215001e, + 0xc78, 0x7216001e, + 0xc78, 0x7217001e, + 0xc78, 0x7218001e, + 0xc78, 0x7219001e, + 0xc78, 0x721a001e, + 0xc78, 0x721b001e, + 0xc78, 0x721c001e, + 0xc78, 0x721d001e, + 0xc78, 0x721e001e, + 0xc78, 0x721f001e, +}; + diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/table.h b/drivers/net/wireless/rtlwifi/rtl8192se/table.h new file mode 100644 index 00000000..2feb73b7 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192se/table.h @@ -0,0 +1,49 @@ +/****************************************************************************** + * Copyright(c) 2008 - 2012 Realtek Corporation. All rights reserved. + * + * 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> + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + ******************************************************************************/ +#ifndef __INC_HAL8192SE_FW_IMG_H +#define __INC_HAL8192SE_FW_IMG_H + +#include <linux/types.h> + +/*Created on 2010/ 4/12, 5:56*/ + +#define PHY_REG_2T2RARRAYLENGTH 372 +extern u32 rtl8192sephy_reg_2t2rarray[PHY_REG_2T2RARRAYLENGTH]; +#define PHY_CHANGETO_1T1RARRAYLENGTH 48 +extern u32 rtl8192sephy_changeto_1t1rarray[PHY_CHANGETO_1T1RARRAYLENGTH]; +#define PHY_CHANGETO_1T2RARRAYLENGTH 45 +extern u32 rtl8192sephy_changeto_1t2rarray[PHY_CHANGETO_1T2RARRAYLENGTH]; +#define PHY_REG_ARRAY_PGLENGTH 84 +extern u32 rtl8192sephy_reg_array_pg[PHY_REG_ARRAY_PGLENGTH]; +#define RADIOA_1T_ARRAYLENGTH 202 +extern u32 rtl8192seradioa_1t_array[RADIOA_1T_ARRAYLENGTH]; +#define RADIOB_ARRAYLENGTH 22 +extern u32 rtl8192seradiob_array[RADIOB_ARRAYLENGTH]; +#define RADIOB_GM_ARRAYLENGTH 10 +extern u32 rtl8192seradiob_gm_array[RADIOB_GM_ARRAYLENGTH]; +#define MAC_2T_ARRAYLENGTH 106 +extern u32 rtl8192semac_2t_array[MAC_2T_ARRAYLENGTH]; +#define AGCTAB_ARRAYLENGTH 320 +extern u32 rtl8192seagctab_array[AGCTAB_ARRAYLENGTH]; + +#endif + diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/trx.c b/drivers/net/wireless/rtlwifi/rtl8192se/trx.c new file mode 100644 index 00000000..2fd3d13b --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192se/trx.c @@ -0,0 +1,891 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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> + * + *****************************************************************************/ + +#include "../wifi.h" +#include "../pci.h" +#include "../base.h" +#include "reg.h" +#include "def.h" +#include "phy.h" +#include "fw.h" +#include "trx.h" +#include "led.h" + +static u8 _rtl92se_map_hwqueue_to_fwqueue(struct sk_buff *skb, u8 skb_queue) +{ + __le16 fc = rtl_get_fc(skb); + + if (unlikely(ieee80211_is_beacon(fc))) + return QSLT_BEACON; + if (ieee80211_is_mgmt(fc)) + return QSLT_MGNT; + if (ieee80211_is_nullfunc(fc)) + return QSLT_HIGH; + + return skb->priority; +} + +static u8 _rtl92s_query_rxpwrpercentage(char antpower) +{ + if ((antpower <= -100) || (antpower >= 20)) + return 0; + else if (antpower >= 0) + return 100; + else + return 100 + antpower; +} + +static u8 _rtl92s_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; +} + +static long _rtl92se_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; +} + +static long _rtl92se_signal_scale_mapping(struct ieee80211_hw *hw, + long currsig) +{ + long retsig = 0; + + /* Step 1. Scale mapping. */ + if (currsig > 47) + retsig = 100; + else if (currsig > 14 && currsig <= 47) + retsig = 100 - ((47 - currsig) * 3) / 2; + else if (currsig > 2 && currsig <= 14) + retsig = 48 - ((14 - currsig) * 15) / 7; + else if (currsig >= 0) + retsig = currsig * 9 + 1; + + return retsig; +} + + +static void _rtl92se_query_rxphystatus(struct ieee80211_hw *hw, + struct rtl_stats *pstats, u8 *pdesc, + struct rx_fwinfo *p_drvinfo, + bool packet_match_bssid, + bool packet_toself, + bool packet_beacon) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct phy_sts_cck_8192s_t *cck_buf; + s8 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 in_powersavemode = false; + bool is_cck = pstats->is_cck; + + pstats->packet_matchbssid = packet_match_bssid; + pstats->packet_toself = packet_toself; + pstats->packet_beacon = packet_beacon; + pstats->rx_mimo_signalquality[0] = -1; + pstats->rx_mimo_signalquality[1] = -1; + + if (is_cck) { + u8 report, cck_highpwr; + cck_buf = (struct phy_sts_cck_8192s_t *)p_drvinfo; + + if (!in_powersavemode) + cck_highpwr = (u8) rtl_get_bbreg(hw, + RFPGA0_XA_HSSIPARAMETER2, + 0x200); + else + cck_highpwr = false; + + if (!cck_highpwr) { + u8 cck_agc_rpt = cck_buf->cck_agc_rpt; + report = cck_buf->cck_agc_rpt & 0xc0; + report = report >> 6; + switch (report) { + case 0x3: + rx_pwr_all = -40 - (cck_agc_rpt & 0x3e); + break; + case 0x2: + rx_pwr_all = -20 - (cck_agc_rpt & 0x3e); + break; + case 0x1: + rx_pwr_all = -2 - (cck_agc_rpt & 0x3e); + break; + case 0x0: + rx_pwr_all = 14 - (cck_agc_rpt & 0x3e); + break; + } + } else { + u8 cck_agc_rpt = cck_buf->cck_agc_rpt; + report = p_drvinfo->cfosho[0] & 0x60; + report = report >> 5; + switch (report) { + case 0x3: + rx_pwr_all = -40 - ((cck_agc_rpt & 0x1f) << 1); + break; + case 0x2: + rx_pwr_all = -20 - ((cck_agc_rpt & 0x1f) << 1); + break; + case 0x1: + rx_pwr_all = -2 - ((cck_agc_rpt & 0x1f) << 1); + break; + case 0x0: + rx_pwr_all = 14 - ((cck_agc_rpt & 0x1f) << 1); + break; + } + } + + pwdb_all = _rtl92s_query_rxpwrpercentage(rx_pwr_all); + + /* CCK gain is smaller than OFDM/MCS gain, */ + /* so we add gain diff by experiences, the val is 6 */ + pwdb_all += 6; + if (pwdb_all > 100) + pwdb_all = 100; + /* modify the offset to make the same gain index with OFDM. */ + if (pwdb_all > 34 && pwdb_all <= 42) + pwdb_all -= 2; + else if (pwdb_all > 26 && pwdb_all <= 34) + pwdb_all -= 6; + else if (pwdb_all > 14 && pwdb_all <= 26) + pwdb_all -= 8; + else if (pwdb_all > 4 && pwdb_all <= 14) + pwdb_all -= 4; + + pstats->rx_pwdb_all = pwdb_all; + pstats->recvsignalpower = rx_pwr_all; + + if (packet_match_bssid) { + u8 sq; + if (pstats->rx_pwdb_all > 40) { + sq = 100; + } else { + sq = cck_buf->sq_rpt; + if (sq > 64) + sq = 0; + else if (sq < 20) + sq = 100; + else + sq = ((64 - sq) * 100) / 44; + } + + pstats->signalquality = sq; + pstats->rx_mimo_signalquality[0] = sq; + pstats->rx_mimo_signalquality[1] = -1; + } + } else { + rtlpriv->dm.rfpath_rxenable[0] = + rtlpriv->dm.rfpath_rxenable[1] = true; + for (i = RF90_PATH_A; i < RF90_PATH_MAX; i++) { + if (rtlpriv->dm.rfpath_rxenable[i]) + rf_rx_num++; + + rx_pwr[i] = ((p_drvinfo->gain_trsw[i] & + 0x3f) * 2) - 110; + rssi = _rtl92s_query_rxpwrpercentage(rx_pwr[i]); + total_rssi += rssi; + rtlpriv->stats.rx_snr_db[i] = + (long)(p_drvinfo->rxsnr[i] / 2); + + if (packet_match_bssid) + pstats->rx_mimo_signalstrength[i] = (u8) rssi; + } + + rx_pwr_all = ((p_drvinfo->pwdb_all >> 1) & 0x7f) - 110; + pwdb_all = _rtl92s_query_rxpwrpercentage(rx_pwr_all); + pstats->rx_pwdb_all = pwdb_all; + pstats->rxpower = rx_pwr_all; + pstats->recvsignalpower = rx_pwr_all; + + if (pstats->is_ht && pstats->rate >= DESC92_RATEMCS8 && + pstats->rate <= DESC92_RATEMCS15) + max_spatial_stream = 2; + else + max_spatial_stream = 1; + + for (i = 0; i < max_spatial_stream; i++) { + evm = _rtl92s_evm_db_to_percentage(p_drvinfo->rxevm[i]); + + if (packet_match_bssid) { + if (i == 0) + pstats->signalquality = (u8)(evm & + 0xff); + pstats->rx_mimo_signalquality[i] = + (u8) (evm & 0xff); + } + } + } + + if (is_cck) + pstats->signalstrength = (u8)(_rtl92se_signal_scale_mapping(hw, + pwdb_all)); + else if (rf_rx_num != 0) + pstats->signalstrength = (u8) (_rtl92se_signal_scale_mapping(hw, + total_rssi /= rf_rx_num)); +} + +static void _rtl92se_process_ui_rssi(struct ieee80211_hw *hw, + struct rtl_stats *pstats) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + u8 rfpath; + u32 last_rssi, tmpval; + + if (pstats->packet_toself || pstats->packet_beacon) { + 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 += pstats->signalstrength; + rtlpriv->stats.ui_rssi.elements[rtlpriv->stats.ui_rssi.index++] + = pstats->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 = _rtl92se_translate_todbm(hw, + (u8) tmpval); + pstats->rssi = rtlpriv->stats.signal_strength; + } + + if (!pstats->is_cck && pstats->packet_toself) { + 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] = + pstats->rx_mimo_signalstrength[rfpath]; + + } + + if (pstats->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)) + + (pstats->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)) + + (pstats->rx_mimo_signalstrength[rfpath])) / + (RX_SMOOTH_FACTOR); + } + + } + } +} + +static void _rtl92se_update_rxsignalstatistics(struct ieee80211_hw *hw, + struct rtl_stats *pstats) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + int weighting = 0; + + if (rtlpriv->stats.recv_signal_power == 0) + rtlpriv->stats.recv_signal_power = pstats->recvsignalpower; + + if (pstats->recvsignalpower > rtlpriv->stats.recv_signal_power) + weighting = 5; + else if (pstats->recvsignalpower < rtlpriv->stats.recv_signal_power) + weighting = (-5); + + rtlpriv->stats.recv_signal_power = (rtlpriv->stats.recv_signal_power * 5 + + pstats->recvsignalpower + + weighting) / 6; +} + +static void _rtl92se_process_pwdb(struct ieee80211_hw *hw, + struct rtl_stats *pstats) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + long undec_sm_pwdb = 0; + + if (mac->opmode == NL80211_IFTYPE_ADHOC) { + return; + } else { + undec_sm_pwdb = + rtlpriv->dm.undecorated_smoothed_pwdb; + } + + if (pstats->packet_toself || pstats->packet_beacon) { + if (undec_sm_pwdb < 0) + undec_sm_pwdb = pstats->rx_pwdb_all; + + if (pstats->rx_pwdb_all > (u32) undec_sm_pwdb) { + undec_sm_pwdb = + (((undec_sm_pwdb) * + (RX_SMOOTH_FACTOR - 1)) + + (pstats->rx_pwdb_all)) / (RX_SMOOTH_FACTOR); + + undec_sm_pwdb = undec_sm_pwdb + 1; + } else { + undec_sm_pwdb = (((undec_sm_pwdb) * + (RX_SMOOTH_FACTOR - 1)) + (pstats->rx_pwdb_all)) / + (RX_SMOOTH_FACTOR); + } + + rtlpriv->dm.undecorated_smoothed_pwdb = undec_sm_pwdb; + _rtl92se_update_rxsignalstatistics(hw, pstats); + } +} + +static void rtl_92s_process_streams(struct ieee80211_hw *hw, + struct rtl_stats *pstats) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 stream; + + for (stream = 0; stream < 2; stream++) { + if (pstats->rx_mimo_signalquality[stream] != -1) { + if (rtlpriv->stats.rx_evm_percentage[stream] == 0) { + rtlpriv->stats.rx_evm_percentage[stream] = + pstats->rx_mimo_signalquality[stream]; + } + + rtlpriv->stats.rx_evm_percentage[stream] = + ((rtlpriv->stats.rx_evm_percentage[stream] * + (RX_SMOOTH_FACTOR - 1)) + + (pstats->rx_mimo_signalquality[stream] * + 1)) / (RX_SMOOTH_FACTOR); + } + } +} + +static void _rtl92se_process_ui_link_quality(struct ieee80211_hw *hw, + struct rtl_stats *pstats) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 last_evm = 0, tmpval; + + if (pstats->signalquality != 0) { + if (pstats->packet_toself || pstats->packet_beacon) { + + 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 += + pstats->signalquality; + rtlpriv->stats.ui_link_quality.elements[ + rtlpriv->stats.ui_link_quality.index++] = + pstats->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; + + rtl_92s_process_streams(hw, pstats); + + } + } +} + +static void _rtl92se_process_phyinfo(struct ieee80211_hw *hw, + u8 *buffer, + struct rtl_stats *pcurrent_stats) +{ + + if (!pcurrent_stats->packet_matchbssid && + !pcurrent_stats->packet_beacon) + return; + + _rtl92se_process_ui_rssi(hw, pcurrent_stats); + _rtl92se_process_pwdb(hw, pcurrent_stats); + _rtl92se_process_ui_link_quality(hw, pcurrent_stats); +} + +static void _rtl92se_translate_rx_signal_stuff(struct ieee80211_hw *hw, + struct sk_buff *skb, struct rtl_stats *pstats, + 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; + __le16 fc; + u16 type, cfc; + bool packet_matchbssid, packet_toself, packet_beacon; + + tmp_buf = skb->data + pstats->rx_drvinfo_size + pstats->rx_bufshift; + + hdr = (struct ieee80211_hdr *)tmp_buf; + fc = hdr->frame_control; + cfc = le16_to_cpu(fc); + type = WLAN_FC_GET_TYPE(fc); + praddr = hdr->addr1; + + packet_matchbssid = ((IEEE80211_FTYPE_CTL != type) && + (!compare_ether_addr(mac->bssid, (cfc & IEEE80211_FCTL_TODS) ? + hdr->addr1 : (cfc & IEEE80211_FCTL_FROMDS) ? + hdr->addr2 : hdr->addr3)) && (!pstats->hwerror) && + (!pstats->crc) && (!pstats->icv)); + + packet_toself = packet_matchbssid && + (!compare_ether_addr(praddr, rtlefuse->dev_addr)); + + if (ieee80211_is_beacon(fc)) + packet_beacon = true; + + _rtl92se_query_rxphystatus(hw, pstats, pdesc, p_drvinfo, + packet_matchbssid, packet_toself, packet_beacon); + _rtl92se_process_phyinfo(hw, tmp_buf, pstats); +} + +bool rtl92se_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *stats, + struct ieee80211_rx_status *rx_status, u8 *pdesc, + struct sk_buff *skb) +{ + struct rx_fwinfo *p_drvinfo; + u32 phystatus = (u32)GET_RX_STATUS_DESC_PHY_STATUS(pdesc); + struct ieee80211_hdr *hdr; + bool first_ampdu = false; + + stats->length = (u16)GET_RX_STATUS_DESC_PKT_LEN(pdesc); + stats->rx_drvinfo_size = (u8)GET_RX_STATUS_DESC_DRVINFO_SIZE(pdesc) * 8; + stats->rx_bufshift = (u8)(GET_RX_STATUS_DESC_SHIFT(pdesc) & 0x03); + stats->icv = (u16)GET_RX_STATUS_DESC_ICV(pdesc); + stats->crc = (u16)GET_RX_STATUS_DESC_CRC32(pdesc); + stats->hwerror = (u16)(stats->crc | stats->icv); + stats->decrypted = !GET_RX_STATUS_DESC_SWDEC(pdesc); + + stats->rate = (u8)GET_RX_STATUS_DESC_RX_MCS(pdesc); + stats->shortpreamble = (u16)GET_RX_STATUS_DESC_SPLCP(pdesc); + stats->isampdu = (bool)(GET_RX_STATUS_DESC_PAGGR(pdesc) == 1); + stats->isfirst_ampdu = (bool) ((GET_RX_STATUS_DESC_PAGGR(pdesc) == 1) + && (GET_RX_STATUS_DESC_FAGGR(pdesc) == 1)); + stats->timestamp_low = GET_RX_STATUS_DESC_TSFL(pdesc); + stats->rx_is40Mhzpacket = (bool)GET_RX_STATUS_DESC_BW(pdesc); + stats->is_ht = (bool)GET_RX_STATUS_DESC_RX_HT(pdesc); + stats->is_cck = SE_RX_HAL_IS_CCK_RATE(pdesc); + + if (stats->hwerror) + return false; + + rx_status->freq = hw->conf.channel->center_freq; + rx_status->band = hw->conf.channel->band; + + hdr = (struct ieee80211_hdr *)(skb->data + stats->rx_drvinfo_size + + stats->rx_bufshift); + + if (stats->crc) + rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; + + if (stats->rx_is40Mhzpacket) + rx_status->flag |= RX_FLAG_40MHZ; + + if (stats->is_ht) + rx_status->flag |= RX_FLAG_HT; + + rx_status->flag |= RX_FLAG_MACTIME_MPDU; + + /* hw will set stats->decrypted true, if it finds the + * frame is open data frame or mgmt frame, + * hw will not decrypt robust managment frame + * for IEEE80211w but still set stats->decrypted + * true, so here we should set it back to undecrypted + * for IEEE80211w frame, and mac80211 sw will help + * to decrypt it */ + if (stats->decrypted) { + 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; + } + + rx_status->rate_idx = rtlwifi_rate_mapping(hw, + stats->is_ht, stats->rate, first_ampdu); + + rx_status->mactime = stats->timestamp_low; + if (phystatus) { + p_drvinfo = (struct rx_fwinfo *)(skb->data + + stats->rx_bufshift); + _rtl92se_translate_rx_signal_stuff(hw, skb, stats, pdesc, + p_drvinfo); + } + + /*rx_status->qual = stats->signal; */ + rx_status->signal = stats->rssi + 10; + /*rx_status->noise = -stats->noise; */ + + return true; +} + +void rtl92se_tx_fill_desc(struct ieee80211_hw *hw, + struct ieee80211_hdr *hdr, u8 *pdesc_tx, + struct ieee80211_tx_info *info, 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(rtl_priv(hw)); + struct ieee80211_sta *sta = info->control.sta; + u8 *pdesc = (u8 *) pdesc_tx; + u16 seq_number; + __le16 fc = hdr->frame_control; + u8 reserved_macid = 0; + u8 fw_qsel = _rtl92se_map_hwqueue_to_fwqueue(skb, hw_queue); + bool firstseg = (!(hdr->seq_ctrl & cpu_to_le16(IEEE80211_SCTL_FRAG))); + bool lastseg = (!(hdr->frame_control & + cpu_to_le16(IEEE80211_FCTL_MOREFRAGS))); + dma_addr_t mapping = pci_map_single(rtlpci->pdev, skb->data, skb->len, + PCI_DMA_TODEVICE); + u8 bw_40 = 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; + + rtl_get_tcb_desc(hw, info, sta, skb, ptcb_desc); + + CLEAR_PCI_TX_DESC_CONTENT(pdesc, TX_DESC_SIZE_RTL8192S); + + if (firstseg) { + if (rtlpriv->dm.useramask) { + /* set txdesc macId */ + if (ptcb_desc->mac_id < 32) { + SET_TX_DESC_MACID(pdesc, ptcb_desc->mac_id); + reserved_macid |= ptcb_desc->mac_id; + } + } + SET_TX_DESC_RSVD_MACID(pdesc, reserved_macid); + + SET_TX_DESC_TXHT(pdesc, ((ptcb_desc->hw_rate >= + DESC92_RATEMCS0) ? 1 : 0)); + + if (rtlhal->version == VERSION_8192S_ACUT) { + if (ptcb_desc->hw_rate == DESC92_RATE1M || + ptcb_desc->hw_rate == DESC92_RATE2M || + ptcb_desc->hw_rate == DESC92_RATE5_5M || + ptcb_desc->hw_rate == DESC92_RATE11M) { + ptcb_desc->hw_rate = DESC92_RATE12M; + } + } + + SET_TX_DESC_TX_RATE(pdesc, ptcb_desc->hw_rate); + + if (ptcb_desc->use_shortgi || ptcb_desc->use_shortpreamble) + SET_TX_DESC_TX_SHORT(pdesc, 0); + + /* Aggregation related */ + if (info->flags & IEEE80211_TX_CTL_AMPDU) + SET_TX_DESC_AGG_ENABLE(pdesc, 1); + + /* For AMPDU, we must insert SSN into TX_DESC */ + SET_TX_DESC_SEQ(pdesc, seq_number); + + /* Protection mode related */ + /* For 92S, if RTS/CTS are set, HW will execute RTS. */ + /* We choose only one protection mode to execute */ + SET_TX_DESC_RTS_ENABLE(pdesc, ((ptcb_desc->rts_enable && + !ptcb_desc->cts_enable) ? 1 : 0)); + SET_TX_DESC_CTS_ENABLE(pdesc, ((ptcb_desc->cts_enable) ? + 1 : 0)); + SET_TX_DESC_RTS_STBC(pdesc, ((ptcb_desc->rts_stbc) ? 1 : 0)); + + SET_TX_DESC_RTS_RATE(pdesc, ptcb_desc->rts_rate); + SET_TX_DESC_RTS_BANDWIDTH(pdesc, 0); + SET_TX_DESC_RTS_SUB_CARRIER(pdesc, ptcb_desc->rts_sc); + SET_TX_DESC_RTS_SHORT(pdesc, ((ptcb_desc->rts_rate <= + DESC92_RATE54M) ? + (ptcb_desc->rts_use_shortpreamble ? 1 : 0) + : (ptcb_desc->rts_use_shortgi ? 1 : 0))); + + + /* Set Bandwidth and sub-channel settings. */ + if (bw_40) { + if (ptcb_desc->packet_bw) { + SET_TX_DESC_TX_BANDWIDTH(pdesc, 1); + /* use duplicated mode */ + SET_TX_DESC_TX_SUB_CARRIER(pdesc, 0); + } else { + SET_TX_DESC_TX_BANDWIDTH(pdesc, 0); + SET_TX_DESC_TX_SUB_CARRIER(pdesc, + mac->cur_40_prime_sc); + } + } else { + SET_TX_DESC_TX_BANDWIDTH(pdesc, 0); + SET_TX_DESC_TX_SUB_CARRIER(pdesc, 0); + } + + /* 3 Fill necessary field in First Descriptor */ + /*DWORD 0*/ + SET_TX_DESC_LINIP(pdesc, 0); + SET_TX_DESC_OFFSET(pdesc, 32); + SET_TX_DESC_PKT_SIZE(pdesc, (u16) skb->len); + + /*DWORD 1*/ + SET_TX_DESC_RA_BRSR_ID(pdesc, ptcb_desc->ratr_index); + + /* Fill security related */ + if (info->control.hw_key) { + struct ieee80211_key_conf *keyconf; + + keyconf = info->control.hw_key; + switch (keyconf->cipher) { + case WLAN_CIPHER_SUITE_WEP40: + case WLAN_CIPHER_SUITE_WEP104: + SET_TX_DESC_SEC_TYPE(pdesc, 0x1); + break; + case WLAN_CIPHER_SUITE_TKIP: + SET_TX_DESC_SEC_TYPE(pdesc, 0x2); + break; + case WLAN_CIPHER_SUITE_CCMP: + SET_TX_DESC_SEC_TYPE(pdesc, 0x3); + break; + default: + SET_TX_DESC_SEC_TYPE(pdesc, 0x0); + break; + + } + } + + /* Set Packet ID */ + SET_TX_DESC_PACKET_ID(pdesc, 0); + + /* We will assign magement queue to BK. */ + SET_TX_DESC_QUEUE_SEL(pdesc, fw_qsel); + + /* Alwasy enable all rate fallback range */ + SET_TX_DESC_DATA_RATE_FB_LIMIT(pdesc, 0x1F); + + /* Fix: I don't kown why hw use 6.5M to tx when set it */ + SET_TX_DESC_USER_RATE(pdesc, + ptcb_desc->use_driver_rate ? 1 : 0); + + /* Set NON_QOS bit. */ + if (!ieee80211_is_data_qos(fc)) + SET_TX_DESC_NON_QOS(pdesc, 1); + + } + + /* Fill fields that are required to be initialized + * in all of the descriptors */ + /*DWORD 0 */ + SET_TX_DESC_FIRST_SEG(pdesc, (firstseg ? 1 : 0)); + SET_TX_DESC_LAST_SEG(pdesc, (lastseg ? 1 : 0)); + + /* DWORD 7 */ + SET_TX_DESC_TX_BUFFER_SIZE(pdesc, (u16) skb->len); + + /* DOWRD 8 */ + SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, cpu_to_le32(mapping)); + + RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE, "\n"); +} + +void rtl92se_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc, + bool firstseg, bool lastseg, struct sk_buff *skb) +{ + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_tcb_desc *tcb_desc = (struct rtl_tcb_desc *)(skb->cb); + + dma_addr_t mapping = pci_map_single(rtlpci->pdev, skb->data, skb->len, + PCI_DMA_TODEVICE); + + /* Clear all status */ + CLEAR_PCI_TX_DESC_CONTENT(pdesc, TX_CMDDESC_SIZE_RTL8192S); + + /* This bit indicate this packet is used for FW download. */ + if (tcb_desc->cmd_or_init == DESC_PACKET_TYPE_INIT) { + /* For firmware downlaod we only need to set LINIP */ + SET_TX_DESC_LINIP(pdesc, tcb_desc->last_inipkt); + + /* 92SE must set as 1 for firmware download HW DMA error */ + SET_TX_DESC_FIRST_SEG(pdesc, 1); + SET_TX_DESC_LAST_SEG(pdesc, 1); + + /* 92SE need not to set TX packet size when firmware download */ + SET_TX_DESC_PKT_SIZE(pdesc, (u16)(skb->len)); + SET_TX_DESC_TX_BUFFER_SIZE(pdesc, (u16)(skb->len)); + SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, cpu_to_le32(mapping)); + + wmb(); + SET_TX_DESC_OWN(pdesc, 1); + } else { /* H2C Command Desc format (Host TXCMD) */ + /* 92SE must set as 1 for firmware download HW DMA error */ + SET_TX_DESC_FIRST_SEG(pdesc, 1); + SET_TX_DESC_LAST_SEG(pdesc, 1); + + SET_TX_DESC_OFFSET(pdesc, 0x20); + + /* Buffer size + command header */ + SET_TX_DESC_PKT_SIZE(pdesc, (u16)(skb->len)); + /* Fixed queue of H2C command */ + SET_TX_DESC_QUEUE_SEL(pdesc, 0x13); + + SET_BITS_TO_LE_4BYTE(skb->data, 24, 7, rtlhal->h2c_txcmd_seq); + + SET_TX_DESC_TX_BUFFER_SIZE(pdesc, (u16)(skb->len)); + SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, cpu_to_le32(mapping)); + + wmb(); + SET_TX_DESC_OWN(pdesc, 1); + + } +} + +void rtl92se_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val) +{ + if (istx) { + switch (desc_name) { + case HW_DESC_OWN: + wmb(); + SET_TX_DESC_OWN(pdesc, 1); + break; + case HW_DESC_TX_NEXTDESC_ADDR: + SET_TX_DESC_NEXT_DESC_ADDRESS(pdesc, *(u32 *) val); + break; + default: + RT_ASSERT(false, "ERR txdesc :%d not process\n", + desc_name); + break; + } + } else { + switch (desc_name) { + case HW_DESC_RXOWN: + wmb(); + SET_RX_STATUS_DESC_OWN(pdesc, 1); + break; + case HW_DESC_RXBUFF_ADDR: + SET_RX_STATUS__DESC_BUFF_ADDR(pdesc, *(u32 *) val); + break; + case HW_DESC_RXPKT_LEN: + SET_RX_STATUS_DESC_PKT_LEN(pdesc, *(u32 *) val); + break; + case HW_DESC_RXERO: + SET_RX_STATUS_DESC_EOR(pdesc, 1); + break; + default: + RT_ASSERT(false, "ERR rxdesc :%d not process\n", + desc_name); + break; + } + } +} + +u32 rtl92se_get_desc(u8 *desc, bool istx, u8 desc_name) +{ + u32 ret = 0; + + if (istx) { + switch (desc_name) { + case HW_DESC_OWN: + ret = GET_TX_DESC_OWN(desc); + break; + case HW_DESC_TXBUFF_ADDR: + ret = GET_TX_DESC_TX_BUFFER_ADDRESS(desc); + 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_STATUS_DESC_OWN(desc); + break; + case HW_DESC_RXPKT_LEN: + ret = GET_RX_STATUS_DESC_PKT_LEN(desc); + break; + default: + RT_ASSERT(false, "ERR rxdesc :%d not process\n", + desc_name); + break; + } + } + return ret; +} + +void rtl92se_tx_polling(struct ieee80211_hw *hw, u8 hw_queue) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + rtl_write_word(rtlpriv, TP_POLL, BIT(0) << (hw_queue)); +} diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/trx.h b/drivers/net/wireless/rtlwifi/rtl8192se/trx.h new file mode 100644 index 00000000..011e7b06 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192se/trx.h @@ -0,0 +1,45 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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 __REALTEK_PCI92SE_TRX_H__ +#define __REALTEK_PCI92SE_TRX_H__ + +void rtl92se_tx_fill_desc(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, + u8 *pdesc, struct ieee80211_tx_info *info, + struct sk_buff *skb, u8 hw_queue, + struct rtl_tcb_desc *ptcb_desc); +void rtl92se_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc, bool firstseg, + bool lastseg, struct sk_buff *skb); +bool rtl92se_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *stats, + struct ieee80211_rx_status *rx_status, u8 *pdesc, + struct sk_buff *skb); +void rtl92se_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val); +u32 rtl92se_get_desc(u8 *pdesc, bool istx, u8 desc_name); +void rtl92se_tx_polling(struct ieee80211_hw *hw, u8 hw_queue); + +#endif diff --git a/drivers/net/wireless/rtlwifi/usb.c b/drivers/net/wireless/rtlwifi/usb.c new file mode 100644 index 00000000..a6049d7d --- /dev/null +++ b/drivers/net/wireless/rtlwifi/usb.c @@ -0,0 +1,1045 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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. + * + * 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. + * + *****************************************************************************/ + +#include "wifi.h" +#include "core.h" +#include "usb.h" +#include "base.h" +#include "ps.h" +#include "rtl8192c/fw_common.h" +#include <linux/export.h> + +#define REALTEK_USB_VENQT_READ 0xC0 +#define REALTEK_USB_VENQT_WRITE 0x40 +#define REALTEK_USB_VENQT_CMD_REQ 0x05 +#define REALTEK_USB_VENQT_CMD_IDX 0x00 + +#define MAX_USBCTRL_VENDORREQ_TIMES 10 + +static void usbctrl_async_callback(struct urb *urb) +{ + if (urb) + kfree(urb->context); +} + +static int _usbctrl_vendorreq_async_write(struct usb_device *udev, u8 request, + u16 value, u16 index, void *pdata, + u16 len) +{ + int rc; + unsigned int pipe; + u8 reqtype; + struct usb_ctrlrequest *dr; + struct urb *urb; + struct rtl819x_async_write_data { + u8 data[REALTEK_USB_VENQT_MAX_BUF_SIZE]; + struct usb_ctrlrequest dr; + } *buf; + + pipe = usb_sndctrlpipe(udev, 0); /* write_out */ + reqtype = REALTEK_USB_VENQT_WRITE; + + buf = kmalloc(sizeof(*buf), GFP_ATOMIC); + if (!buf) + return -ENOMEM; + + urb = usb_alloc_urb(0, GFP_ATOMIC); + if (!urb) { + kfree(buf); + return -ENOMEM; + } + + dr = &buf->dr; + + dr->bRequestType = reqtype; + dr->bRequest = request; + dr->wValue = cpu_to_le16(value); + dr->wIndex = cpu_to_le16(index); + dr->wLength = cpu_to_le16(len); + /* data are already in little-endian order */ + memcpy(buf, pdata, len); + usb_fill_control_urb(urb, udev, pipe, + (unsigned char *)dr, buf, len, + usbctrl_async_callback, buf); + rc = usb_submit_urb(urb, GFP_ATOMIC); + if (rc < 0) + kfree(buf); + usb_free_urb(urb); + return rc; +} + +static int _usbctrl_vendorreq_sync_read(struct usb_device *udev, u8 request, + u16 value, u16 index, void *pdata, + u16 len) +{ + unsigned int pipe; + int status; + u8 reqtype; + int vendorreq_times = 0; + static int count; + + pipe = usb_rcvctrlpipe(udev, 0); /* read_in */ + reqtype = REALTEK_USB_VENQT_READ; + + do { + status = usb_control_msg(udev, pipe, request, reqtype, value, + index, pdata, len, 0); /*max. timeout*/ + if (status < 0) { + /* firmware download is checksumed, don't retry */ + if ((value >= FW_8192C_START_ADDRESS && + value <= FW_8192C_END_ADDRESS)) + break; + } else { + break; + } + } while (++vendorreq_times < MAX_USBCTRL_VENDORREQ_TIMES); + + if (status < 0 && count++ < 4) + pr_err("reg 0x%x, usbctrl_vendorreq TimeOut! status:0x%x value=0x%x\n", + value, status, le32_to_cpu(*(u32 *)pdata)); + return status; +} + +static u32 _usb_read_sync(struct rtl_priv *rtlpriv, u32 addr, u16 len) +{ + struct device *dev = rtlpriv->io.dev; + struct usb_device *udev = to_usb_device(dev); + u8 request; + u16 wvalue; + u16 index; + __le32 *data = &rtlpriv->usb_data[rtlpriv->usb_data_index]; + + request = REALTEK_USB_VENQT_CMD_REQ; + index = REALTEK_USB_VENQT_CMD_IDX; /* n/a */ + + wvalue = (u16)addr; + _usbctrl_vendorreq_sync_read(udev, request, wvalue, index, data, len); + if (++rtlpriv->usb_data_index >= RTL_USB_MAX_RX_COUNT) + rtlpriv->usb_data_index = 0; + return le32_to_cpu(*data); +} + +static u8 _usb_read8_sync(struct rtl_priv *rtlpriv, u32 addr) +{ + return (u8)_usb_read_sync(rtlpriv, addr, 1); +} + +static u16 _usb_read16_sync(struct rtl_priv *rtlpriv, u32 addr) +{ + return (u16)_usb_read_sync(rtlpriv, addr, 2); +} + +static u32 _usb_read32_sync(struct rtl_priv *rtlpriv, u32 addr) +{ + return _usb_read_sync(rtlpriv, addr, 4); +} + +static void _usb_write_async(struct usb_device *udev, u32 addr, u32 val, + u16 len) +{ + u8 request; + u16 wvalue; + u16 index; + __le32 data; + + request = REALTEK_USB_VENQT_CMD_REQ; + index = REALTEK_USB_VENQT_CMD_IDX; /* n/a */ + wvalue = (u16)(addr&0x0000ffff); + data = cpu_to_le32(val); + _usbctrl_vendorreq_async_write(udev, request, wvalue, index, &data, + len); +} + +static void _usb_write8_async(struct rtl_priv *rtlpriv, u32 addr, u8 val) +{ + struct device *dev = rtlpriv->io.dev; + + _usb_write_async(to_usb_device(dev), addr, val, 1); +} + +static void _usb_write16_async(struct rtl_priv *rtlpriv, u32 addr, u16 val) +{ + struct device *dev = rtlpriv->io.dev; + + _usb_write_async(to_usb_device(dev), addr, val, 2); +} + +static void _usb_write32_async(struct rtl_priv *rtlpriv, u32 addr, u32 val) +{ + struct device *dev = rtlpriv->io.dev; + + _usb_write_async(to_usb_device(dev), addr, val, 4); +} + +static void _usb_writeN_sync(struct rtl_priv *rtlpriv, u32 addr, void *data, + u16 len) +{ + struct device *dev = rtlpriv->io.dev; + struct usb_device *udev = to_usb_device(dev); + u8 request = REALTEK_USB_VENQT_CMD_REQ; + u8 reqtype = REALTEK_USB_VENQT_WRITE; + u16 wvalue; + u16 index = REALTEK_USB_VENQT_CMD_IDX; + int pipe = usb_sndctrlpipe(udev, 0); /* write_out */ + u8 *buffer; + dma_addr_t dma_addr; + + wvalue = (u16)(addr&0x0000ffff); + buffer = usb_alloc_coherent(udev, (size_t)len, GFP_ATOMIC, &dma_addr); + if (!buffer) + return; + memcpy(buffer, data, len); + usb_control_msg(udev, pipe, request, reqtype, wvalue, + index, buffer, len, 50); + + usb_free_coherent(udev, (size_t)len, buffer, dma_addr); +} + +static void _rtl_usb_io_handler_init(struct device *dev, + struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtlpriv->io.dev = dev; + mutex_init(&rtlpriv->io.bb_mutex); + rtlpriv->io.write8_async = _usb_write8_async; + rtlpriv->io.write16_async = _usb_write16_async; + rtlpriv->io.write32_async = _usb_write32_async; + rtlpriv->io.read8_sync = _usb_read8_sync; + rtlpriv->io.read16_sync = _usb_read16_sync; + rtlpriv->io.read32_sync = _usb_read32_sync; + rtlpriv->io.writeN_sync = _usb_writeN_sync; +} + +static void _rtl_usb_io_handler_release(struct ieee80211_hw *hw) +{ + struct rtl_priv __maybe_unused *rtlpriv = rtl_priv(hw); + + mutex_destroy(&rtlpriv->io.bb_mutex); +} + +/** + * + * Default aggregation handler. Do nothing and just return the oldest skb. + */ +static struct sk_buff *_none_usb_tx_aggregate_hdl(struct ieee80211_hw *hw, + struct sk_buff_head *list) +{ + return skb_dequeue(list); +} + +#define IS_HIGH_SPEED_USB(udev) \ + ((USB_SPEED_HIGH == (udev)->speed) ? true : false) + +static int _rtl_usb_init_tx(struct ieee80211_hw *hw) +{ + u32 i; + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw)); + + rtlusb->max_bulk_out_size = IS_HIGH_SPEED_USB(rtlusb->udev) + ? USB_HIGH_SPEED_BULK_SIZE + : USB_FULL_SPEED_BULK_SIZE; + + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "USB Max Bulk-out Size=%d\n", + rtlusb->max_bulk_out_size); + + for (i = 0; i < __RTL_TXQ_NUM; i++) { + u32 ep_num = rtlusb->ep_map.ep_mapping[i]; + if (!ep_num) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "Invalid endpoint map setting!\n"); + return -EINVAL; + } + } + + rtlusb->usb_tx_post_hdl = + rtlpriv->cfg->usb_interface_cfg->usb_tx_post_hdl; + rtlusb->usb_tx_cleanup = + rtlpriv->cfg->usb_interface_cfg->usb_tx_cleanup; + rtlusb->usb_tx_aggregate_hdl = + (rtlpriv->cfg->usb_interface_cfg->usb_tx_aggregate_hdl) + ? rtlpriv->cfg->usb_interface_cfg->usb_tx_aggregate_hdl + : &_none_usb_tx_aggregate_hdl; + + init_usb_anchor(&rtlusb->tx_submitted); + for (i = 0; i < RTL_USB_MAX_EP_NUM; i++) { + skb_queue_head_init(&rtlusb->tx_skb_queue[i]); + init_usb_anchor(&rtlusb->tx_pending[i]); + } + return 0; +} + +static int _rtl_usb_init_rx(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_usb_priv *usb_priv = rtl_usbpriv(hw); + struct rtl_usb *rtlusb = rtl_usbdev(usb_priv); + + rtlusb->rx_max_size = rtlpriv->cfg->usb_interface_cfg->rx_max_size; + rtlusb->rx_urb_num = rtlpriv->cfg->usb_interface_cfg->rx_urb_num; + rtlusb->in_ep = rtlpriv->cfg->usb_interface_cfg->in_ep_num; + rtlusb->usb_rx_hdl = rtlpriv->cfg->usb_interface_cfg->usb_rx_hdl; + rtlusb->usb_rx_segregate_hdl = + rtlpriv->cfg->usb_interface_cfg->usb_rx_segregate_hdl; + + pr_info("rx_max_size %d, rx_urb_num %d, in_ep %d\n", + rtlusb->rx_max_size, rtlusb->rx_urb_num, rtlusb->in_ep); + init_usb_anchor(&rtlusb->rx_submitted); + return 0; +} + +static int _rtl_usb_init(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_usb_priv *usb_priv = rtl_usbpriv(hw); + struct rtl_usb *rtlusb = rtl_usbdev(usb_priv); + int err; + u8 epidx; + struct usb_interface *usb_intf = rtlusb->intf; + u8 epnums = usb_intf->cur_altsetting->desc.bNumEndpoints; + + rtlusb->out_ep_nums = rtlusb->in_ep_nums = 0; + for (epidx = 0; epidx < epnums; epidx++) { + struct usb_endpoint_descriptor *pep_desc; + pep_desc = &usb_intf->cur_altsetting->endpoint[epidx].desc; + + if (usb_endpoint_dir_in(pep_desc)) + rtlusb->in_ep_nums++; + else if (usb_endpoint_dir_out(pep_desc)) + rtlusb->out_ep_nums++; + + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "USB EP(0x%02x), MaxPacketSize=%d, Interval=%d\n", + pep_desc->bEndpointAddress, pep_desc->wMaxPacketSize, + pep_desc->bInterval); + } + if (rtlusb->in_ep_nums < rtlpriv->cfg->usb_interface_cfg->in_ep_num) { + pr_err("Too few input end points found\n"); + return -EINVAL; + } + if (rtlusb->out_ep_nums == 0) { + pr_err("No output end points found\n"); + return -EINVAL; + } + /* usb endpoint mapping */ + err = rtlpriv->cfg->usb_interface_cfg->usb_endpoint_mapping(hw); + rtlusb->usb_mq_to_hwq = rtlpriv->cfg->usb_interface_cfg->usb_mq_to_hwq; + _rtl_usb_init_tx(hw); + _rtl_usb_init_rx(hw); + return err; +} + +static void rtl_usb_init_sw(struct ieee80211_hw *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)); + struct rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw)); + + rtlhal->hw = hw; + ppsc->inactiveps = false; + ppsc->leisure_ps = false; + ppsc->fwctrl_lps = false; + ppsc->reg_fwctrl_lps = 3; + ppsc->reg_max_lps_awakeintvl = 5; + ppsc->fwctrl_psmode = FW_PS_DTIM_MODE; + + /* 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 */ + rtlusb->acm_method = eAcmWay2_SW; + + /* IRQ */ + /* HIMR - turn all on */ + rtlusb->irq_mask[0] = 0xFFFFFFFF; + /* HIMR_EX - turn all on */ + rtlusb->irq_mask[1] = 0xFFFFFFFF; + rtlusb->disableHWSM = true; +} + +#define __RADIO_TAP_SIZE_RSV 32 + +static void _rtl_rx_completed(struct urb *urb); + +static struct sk_buff *_rtl_prep_rx_urb(struct ieee80211_hw *hw, + struct rtl_usb *rtlusb, + struct urb *urb, + gfp_t gfp_mask) +{ + struct sk_buff *skb; + struct rtl_priv *rtlpriv = rtl_priv(hw); + + skb = __dev_alloc_skb((rtlusb->rx_max_size + __RADIO_TAP_SIZE_RSV), + gfp_mask); + if (!skb) { + RT_TRACE(rtlpriv, COMP_USB, DBG_EMERG, + "Failed to __dev_alloc_skb!!\n"); + return ERR_PTR(-ENOMEM); + } + + /* reserve some space for mac80211's radiotap */ + skb_reserve(skb, __RADIO_TAP_SIZE_RSV); + usb_fill_bulk_urb(urb, rtlusb->udev, + usb_rcvbulkpipe(rtlusb->udev, rtlusb->in_ep), + skb->data, min(skb_tailroom(skb), + (int)rtlusb->rx_max_size), + _rtl_rx_completed, skb); + + _rtl_install_trx_info(rtlusb, skb, rtlusb->in_ep); + return skb; +} + +#undef __RADIO_TAP_SIZE_RSV + +static void _rtl_usb_rx_process_agg(struct ieee80211_hw *hw, + struct sk_buff *skb) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 *rxdesc = skb->data; + struct ieee80211_hdr *hdr; + bool unicast = false; + __le16 fc; + struct ieee80211_rx_status rx_status = {0}; + struct rtl_stats stats = { + .signal = 0, + .noise = -98, + .rate = 0, + }; + + skb_pull(skb, RTL_RX_DESC_SIZE); + rtlpriv->cfg->ops->query_rx_desc(hw, &stats, &rx_status, rxdesc, skb); + skb_pull(skb, (stats.rx_drvinfo_size + stats.rx_bufshift)); + hdr = (struct ieee80211_hdr *)(skb->data); + fc = hdr->frame_control; + if (!stats.crc) { + 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; + } + + rtl_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 void _rtl_usb_rx_process_noagg(struct ieee80211_hw *hw, + struct sk_buff *skb) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 *rxdesc = skb->data; + struct ieee80211_hdr *hdr; + bool unicast = false; + __le16 fc; + struct ieee80211_rx_status rx_status = {0}; + struct rtl_stats stats = { + .signal = 0, + .noise = -98, + .rate = 0, + }; + + skb_pull(skb, RTL_RX_DESC_SIZE); + rtlpriv->cfg->ops->query_rx_desc(hw, &stats, &rx_status, rxdesc, skb); + skb_pull(skb, (stats.rx_drvinfo_size + stats.rx_bufshift)); + hdr = (struct ieee80211_hdr *)(skb->data); + fc = hdr->frame_control; + if (!stats.crc) { + 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; + } + + rtl_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++; + } + if (likely(rtl_action_proc(hw, skb, false))) { + struct sk_buff *uskb = NULL; + u8 *pdata; + + uskb = dev_alloc_skb(skb->len + 128); + if (uskb) { /* drop packet on allocation failure */ + memcpy(IEEE80211_SKB_RXCB(uskb), &rx_status, + sizeof(rx_status)); + pdata = (u8 *)skb_put(uskb, skb->len); + memcpy(pdata, skb->data, skb->len); + ieee80211_rx_irqsafe(hw, uskb); + } + dev_kfree_skb_any(skb); + } else { + dev_kfree_skb_any(skb); + } + } +} + +static void _rtl_rx_pre_process(struct ieee80211_hw *hw, struct sk_buff *skb) +{ + struct sk_buff *_skb; + struct sk_buff_head rx_queue; + struct rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw)); + + skb_queue_head_init(&rx_queue); + if (rtlusb->usb_rx_segregate_hdl) + rtlusb->usb_rx_segregate_hdl(hw, skb, &rx_queue); + WARN_ON(skb_queue_empty(&rx_queue)); + while (!skb_queue_empty(&rx_queue)) { + _skb = skb_dequeue(&rx_queue); + _rtl_usb_rx_process_agg(hw, skb); + ieee80211_rx_irqsafe(hw, skb); + } +} + +static void _rtl_rx_completed(struct urb *_urb) +{ + struct sk_buff *skb = (struct sk_buff *)_urb->context; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct rtl_usb *rtlusb = (struct rtl_usb *)info->rate_driver_data[0]; + struct ieee80211_hw *hw = usb_get_intfdata(rtlusb->intf); + struct rtl_priv *rtlpriv = rtl_priv(hw); + int err = 0; + + if (unlikely(IS_USB_STOP(rtlusb))) + goto free; + + if (likely(0 == _urb->status)) { + /* If this code were moved to work queue, would CPU + * utilization be improved? NOTE: We shall allocate another skb + * and reuse the original one. + */ + skb_put(skb, _urb->actual_length); + + if (likely(!rtlusb->usb_rx_segregate_hdl)) { + struct sk_buff *_skb; + _rtl_usb_rx_process_noagg(hw, skb); + _skb = _rtl_prep_rx_urb(hw, rtlusb, _urb, GFP_ATOMIC); + if (IS_ERR(_skb)) { + err = PTR_ERR(_skb); + RT_TRACE(rtlpriv, COMP_USB, DBG_EMERG, + "Can't allocate skb for bulk IN!\n"); + return; + } + skb = _skb; + } else{ + /* TO DO */ + _rtl_rx_pre_process(hw, skb); + pr_err("rx agg not supported\n"); + } + goto resubmit; + } + + switch (_urb->status) { + /* disconnect */ + case -ENOENT: + case -ECONNRESET: + case -ENODEV: + case -ESHUTDOWN: + goto free; + default: + break; + } + +resubmit: + skb_reset_tail_pointer(skb); + skb_trim(skb, 0); + + usb_anchor_urb(_urb, &rtlusb->rx_submitted); + err = usb_submit_urb(_urb, GFP_ATOMIC); + if (unlikely(err)) { + usb_unanchor_urb(_urb); + goto free; + } + return; + +free: + dev_kfree_skb_irq(skb); +} + +static int _rtl_usb_receive(struct ieee80211_hw *hw) +{ + struct urb *urb; + struct sk_buff *skb; + int err; + int i; + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw)); + + WARN_ON(0 == rtlusb->rx_urb_num); + /* 1600 == 1514 + max WLAN header + rtk info */ + WARN_ON(rtlusb->rx_max_size < 1600); + + for (i = 0; i < rtlusb->rx_urb_num; i++) { + err = -ENOMEM; + urb = usb_alloc_urb(0, GFP_KERNEL); + if (!urb) { + RT_TRACE(rtlpriv, COMP_USB, DBG_EMERG, + "Failed to alloc URB!!\n"); + goto err_out; + } + + skb = _rtl_prep_rx_urb(hw, rtlusb, urb, GFP_KERNEL); + if (IS_ERR(skb)) { + RT_TRACE(rtlpriv, COMP_USB, DBG_EMERG, + "Failed to prep_rx_urb!!\n"); + err = PTR_ERR(skb); + goto err_out; + } + + usb_anchor_urb(urb, &rtlusb->rx_submitted); + err = usb_submit_urb(urb, GFP_KERNEL); + if (err) + goto err_out; + usb_free_urb(urb); + } + return 0; + +err_out: + usb_kill_anchored_urbs(&rtlusb->rx_submitted); + return err; +} + +static int rtl_usb_start(struct ieee80211_hw *hw) +{ + int err; + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw)); + + err = rtlpriv->cfg->ops->hw_init(hw); + if (!err) { + rtl_init_rx_config(hw); + + /* Enable software */ + SET_USB_START(rtlusb); + /* should after adapter start and interrupt enable. */ + set_hal_start(rtlhal); + + /* Start bulk IN */ + _rtl_usb_receive(hw); + } + + return err; +} +/** + * + * + */ + +/*======================= tx =========================================*/ +static void rtl_usb_cleanup(struct ieee80211_hw *hw) +{ + u32 i; + struct sk_buff *_skb; + struct rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw)); + struct ieee80211_tx_info *txinfo; + + SET_USB_STOP(rtlusb); + + /* clean up rx stuff. */ + usb_kill_anchored_urbs(&rtlusb->rx_submitted); + + /* clean up tx stuff */ + for (i = 0; i < RTL_USB_MAX_EP_NUM; i++) { + while ((_skb = skb_dequeue(&rtlusb->tx_skb_queue[i]))) { + rtlusb->usb_tx_cleanup(hw, _skb); + txinfo = IEEE80211_SKB_CB(_skb); + ieee80211_tx_info_clear_status(txinfo); + txinfo->flags |= IEEE80211_TX_STAT_ACK; + ieee80211_tx_status_irqsafe(hw, _skb); + } + usb_kill_anchored_urbs(&rtlusb->tx_pending[i]); + } + usb_kill_anchored_urbs(&rtlusb->tx_submitted); +} + +/** + * + * We may add some struct into struct rtl_usb later. Do deinit here. + * + */ +static void rtl_usb_deinit(struct ieee80211_hw *hw) +{ + rtl_usb_cleanup(hw); +} + +static void rtl_usb_stop(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw)); + + /* should after adapter start and interrupt enable. */ + set_hal_stop(rtlhal); + /* Enable software */ + SET_USB_STOP(rtlusb); + rtl_usb_deinit(hw); + rtlpriv->cfg->ops->hw_disable(hw); +} + +static void _rtl_submit_tx_urb(struct ieee80211_hw *hw, struct urb *_urb) +{ + int err; + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw)); + + usb_anchor_urb(_urb, &rtlusb->tx_submitted); + err = usb_submit_urb(_urb, GFP_ATOMIC); + if (err < 0) { + struct sk_buff *skb; + + RT_TRACE(rtlpriv, COMP_USB, DBG_EMERG, + "Failed to submit urb\n"); + usb_unanchor_urb(_urb); + skb = (struct sk_buff *)_urb->context; + kfree_skb(skb); + } + usb_free_urb(_urb); +} + +static int _usb_tx_post(struct ieee80211_hw *hw, struct urb *urb, + struct sk_buff *skb) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw)); + struct ieee80211_tx_info *txinfo; + + rtlusb->usb_tx_post_hdl(hw, urb, skb); + skb_pull(skb, RTL_TX_HEADER_SIZE); + txinfo = IEEE80211_SKB_CB(skb); + ieee80211_tx_info_clear_status(txinfo); + txinfo->flags |= IEEE80211_TX_STAT_ACK; + + if (urb->status) { + RT_TRACE(rtlpriv, COMP_USB, DBG_EMERG, + "Urb has error status 0x%X\n", urb->status); + goto out; + } + /* TODO: statistics */ +out: + ieee80211_tx_status_irqsafe(hw, skb); + return urb->status; +} + +static void _rtl_tx_complete(struct urb *urb) +{ + struct sk_buff *skb = (struct sk_buff *)urb->context; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct rtl_usb *rtlusb = (struct rtl_usb *)info->rate_driver_data[0]; + struct ieee80211_hw *hw = usb_get_intfdata(rtlusb->intf); + int err; + + if (unlikely(IS_USB_STOP(rtlusb))) + return; + err = _usb_tx_post(hw, urb, skb); + if (err) { + /* Ignore error and keep issuiing other urbs */ + return; + } +} + +static struct urb *_rtl_usb_tx_urb_setup(struct ieee80211_hw *hw, + struct sk_buff *skb, u32 ep_num) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw)); + struct urb *_urb; + + WARN_ON(NULL == skb); + _urb = usb_alloc_urb(0, GFP_ATOMIC); + if (!_urb) { + RT_TRACE(rtlpriv, COMP_USB, DBG_EMERG, + "Can't allocate URB for bulk out!\n"); + kfree_skb(skb); + return NULL; + } + _rtl_install_trx_info(rtlusb, skb, ep_num); + usb_fill_bulk_urb(_urb, rtlusb->udev, usb_sndbulkpipe(rtlusb->udev, + ep_num), skb->data, skb->len, _rtl_tx_complete, skb); + _urb->transfer_flags |= URB_ZERO_PACKET; + return _urb; +} + +static void _rtl_usb_transmit(struct ieee80211_hw *hw, struct sk_buff *skb, + enum rtl_txq qnum) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw)); + u32 ep_num; + struct urb *_urb = NULL; + struct sk_buff *_skb = NULL; + struct sk_buff_head *skb_list; + struct usb_anchor *urb_list; + + WARN_ON(NULL == rtlusb->usb_tx_aggregate_hdl); + if (unlikely(IS_USB_STOP(rtlusb))) { + RT_TRACE(rtlpriv, COMP_USB, DBG_EMERG, + "USB device is stopping...\n"); + kfree_skb(skb); + return; + } + ep_num = rtlusb->ep_map.ep_mapping[qnum]; + skb_list = &rtlusb->tx_skb_queue[ep_num]; + _skb = skb; + _urb = _rtl_usb_tx_urb_setup(hw, _skb, ep_num); + if (unlikely(!_urb)) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "Can't allocate urb. Drop skb!\n"); + return; + } + urb_list = &rtlusb->tx_pending[ep_num]; + _rtl_submit_tx_urb(hw, _urb); +} + +static void _rtl_usb_tx_preprocess(struct ieee80211_hw *hw, struct sk_buff *skb, + u16 hw_queue) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct rtl_tx_desc *pdesc = NULL; + struct rtl_tcb_desc tcb_desc; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data); + __le16 fc = hdr->frame_control; + u8 *pda_addr = hdr->addr1; + /* ssn */ + u8 *qc = NULL; + u8 tid = 0; + u16 seq_number = 0; + + memset(&tcb_desc, 0, sizeof(struct rtl_tcb_desc)); + if (ieee80211_is_auth(fc)) { + RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG, "MAC80211_LINKING\n"); + rtl_ips_nic_on(hw); + } + + 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); + } + + rtl_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; + if (ieee80211_is_data_qos(fc)) { + qc = ieee80211_get_qos_ctl(hdr); + tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; + seq_number = (le16_to_cpu(hdr->seq_ctrl) & + IEEE80211_SCTL_SEQ) >> 4; + seq_number += 1; + seq_number <<= 4; + } + rtlpriv->cfg->ops->fill_tx_desc(hw, hdr, (u8 *)pdesc, info, skb, + hw_queue, &tcb_desc); + if (!ieee80211_has_morefrags(hdr->frame_control)) { + if (qc) + mac->tids[tid].seq_number = seq_number; + } + if (ieee80211_is_data(fc)) + rtlpriv->cfg->ops->led_control(hw, LED_CTL_TX); +} + +static int rtl_usb_tx(struct ieee80211_hw *hw, struct sk_buff *skb, + struct rtl_tcb_desc *dummy) +{ + struct rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw)); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data); + __le16 fc = hdr->frame_control; + u16 hw_queue; + + if (unlikely(is_hal_stop(rtlhal))) + goto err_free; + hw_queue = rtlusb->usb_mq_to_hwq(fc, skb_get_queue_mapping(skb)); + _rtl_usb_tx_preprocess(hw, skb, hw_queue); + _rtl_usb_transmit(hw, skb, hw_queue); + return NETDEV_TX_OK; + +err_free: + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; +} + +static bool rtl_usb_tx_chk_waitq_insert(struct ieee80211_hw *hw, + struct sk_buff *skb) +{ + return false; +} + +static struct rtl_intf_ops rtl_usb_ops = { + .adapter_start = rtl_usb_start, + .adapter_stop = rtl_usb_stop, + .adapter_tx = rtl_usb_tx, + .waitq_insert = rtl_usb_tx_chk_waitq_insert, +}; + +int __devinit rtl_usb_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + int err; + struct ieee80211_hw *hw = NULL; + struct rtl_priv *rtlpriv = NULL; + struct usb_device *udev; + struct rtl_usb_priv *usb_priv; + + hw = ieee80211_alloc_hw(sizeof(struct rtl_priv) + + sizeof(struct rtl_usb_priv), &rtl_ops); + if (!hw) { + RT_ASSERT(false, "ieee80211 alloc failed\n"); + return -ENOMEM; + } + rtlpriv = hw->priv; + rtlpriv->usb_data = kzalloc(RTL_USB_MAX_RX_COUNT * sizeof(u32), + GFP_KERNEL); + if (!rtlpriv->usb_data) + return -ENOMEM; + rtlpriv->usb_data_index = 0; + init_completion(&rtlpriv->firmware_loading_complete); + SET_IEEE80211_DEV(hw, &intf->dev); + udev = interface_to_usbdev(intf); + usb_get_dev(udev); + usb_priv = rtl_usbpriv(hw); + memset(usb_priv, 0, sizeof(*usb_priv)); + usb_priv->dev.intf = intf; + usb_priv->dev.udev = udev; + usb_set_intfdata(intf, hw); + /* init cfg & intf_ops */ + rtlpriv->rtlhal.interface = INTF_USB; + rtlpriv->cfg = (struct rtl_hal_cfg *)(id->driver_info); + rtlpriv->intf_ops = &rtl_usb_ops; + rtl_dbgp_flag_init(hw); + /* Init IO handler */ + _rtl_usb_io_handler_init(&udev->dev, hw); + rtlpriv->cfg->ops->read_chip_version(hw); + /*like read eeprom and so on */ + rtlpriv->cfg->ops->read_eeprom_info(hw); + err = _rtl_usb_init(hw); + if (err) + goto error_out; + rtl_usb_init_sw(hw); + /* Init mac80211 sw */ + err = rtl_init_core(hw); + if (err) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "Can't allocate sw for mac80211\n"); + goto error_out; + } + if (rtlpriv->cfg->ops->init_sw_vars(hw)) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Can't init_sw_vars\n"); + goto error_out; + } + rtlpriv->cfg->ops->init_sw_leds(hw); + + return 0; +error_out: + rtl_deinit_core(hw); + _rtl_usb_io_handler_release(hw); + usb_put_dev(udev); + complete(&rtlpriv->firmware_loading_complete); + return -ENODEV; +} +EXPORT_SYMBOL(rtl_usb_probe); + +void rtl_usb_disconnect(struct usb_interface *intf) +{ + struct ieee80211_hw *hw = usb_get_intfdata(intf); + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *rtlmac = rtl_mac(rtl_priv(hw)); + struct rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw)); + + if (unlikely(!rtlpriv)) + return; + + /* just in case driver is removed before firmware callback */ + wait_for_completion(&rtlpriv->firmware_loading_complete); + /*ieee80211_unregister_hw will call ops_stop */ + if (rtlmac->mac80211_registered == 1) { + ieee80211_unregister_hw(hw); + rtlmac->mac80211_registered = 0; + } else { + rtl_deinit_deferred_work(hw); + rtlpriv->intf_ops->adapter_stop(hw); + } + /*deinit rfkill */ + /* rtl_deinit_rfkill(hw); */ + rtl_usb_deinit(hw); + rtl_deinit_core(hw); + kfree(rtlpriv->usb_data); + rtlpriv->cfg->ops->deinit_sw_leds(hw); + rtlpriv->cfg->ops->deinit_sw_vars(hw); + _rtl_usb_io_handler_release(hw); + usb_put_dev(rtlusb->udev); + usb_set_intfdata(intf, NULL); + ieee80211_free_hw(hw); +} +EXPORT_SYMBOL(rtl_usb_disconnect); + +int rtl_usb_suspend(struct usb_interface *pusb_intf, pm_message_t message) +{ + return 0; +} +EXPORT_SYMBOL(rtl_usb_suspend); + +int rtl_usb_resume(struct usb_interface *pusb_intf) +{ + return 0; +} +EXPORT_SYMBOL(rtl_usb_resume); diff --git a/drivers/net/wireless/rtlwifi/usb.h b/drivers/net/wireless/rtlwifi/usb.h new file mode 100644 index 00000000..43846b32 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/usb.h @@ -0,0 +1,165 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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. + * + * 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. + * + *****************************************************************************/ + +#ifndef __RTL_USB_H__ +#define __RTL_USB_H__ + +#include <linux/skbuff.h> + +#define RTL_RX_DESC_SIZE 24 + +#define RTL_USB_DEVICE(vend, prod, cfg) \ + .match_flags = USB_DEVICE_ID_MATCH_DEVICE, \ + .idVendor = (vend), \ + .idProduct = (prod), \ + .driver_info = (kernel_ulong_t)&(cfg) + +#define USB_HIGH_SPEED_BULK_SIZE 512 +#define USB_FULL_SPEED_BULK_SIZE 64 + + +#define RTL_USB_MAX_TXQ_NUM 4 /* max tx queue */ +#define RTL_USB_MAX_EP_NUM 6 /* max ep number */ +#define RTL_USB_MAX_TX_URBS_NUM 8 + +enum rtl_txq { + /* These definitions shall be consistent with value + * returned by skb_get_queue_mapping + *------------------------------------*/ + RTL_TXQ_BK, + RTL_TXQ_BE, + RTL_TXQ_VI, + RTL_TXQ_VO, + /*------------------------------------*/ + RTL_TXQ_BCN, + RTL_TXQ_MGT, + RTL_TXQ_HI, + + /* Must be last */ + __RTL_TXQ_NUM, +}; + +struct rtl_ep_map { + u32 ep_mapping[__RTL_TXQ_NUM]; +}; + +struct _trx_info { + struct rtl_usb *rtlusb; + u32 ep_num; +}; + +static inline void _rtl_install_trx_info(struct rtl_usb *rtlusb, + struct sk_buff *skb, + u32 ep_num) +{ + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + info->rate_driver_data[0] = rtlusb; + info->rate_driver_data[1] = (void *)(__kernel_size_t)ep_num; +} + + +/* Add suspend/resume later */ +enum rtl_usb_state { + USB_STATE_STOP = 0, + USB_STATE_START = 1, +}; + +#define IS_USB_STOP(rtlusb_ptr) (USB_STATE_STOP == (rtlusb_ptr)->state) +#define IS_USB_START(rtlusb_ptr) (USB_STATE_START == (rtlusb_ptr)->state) +#define SET_USB_STOP(rtlusb_ptr) \ + do { \ + (rtlusb_ptr)->state = USB_STATE_STOP; \ + } while (0) + +#define SET_USB_START(rtlusb_ptr) \ + do { \ + (rtlusb_ptr)->state = USB_STATE_START; \ + } while (0) + +struct rtl_usb { + struct usb_device *udev; + struct usb_interface *intf; + enum rtl_usb_state state; + + /* Bcn control register setting */ + u32 reg_bcn_ctrl_val; + /* for 88/92cu card disable */ + u8 disableHWSM; + /*QOS & EDCA */ + enum acm_method acm_method; + /* irq . HIMR,HIMR_EX */ + u32 irq_mask[2]; + bool irq_enabled; + + u16 (*usb_mq_to_hwq)(__le16 fc, u16 mac80211_queue_index); + + /* Tx */ + u8 out_ep_nums ; + u8 out_queue_sel; + struct rtl_ep_map ep_map; + + u32 max_bulk_out_size; + u32 tx_submitted_urbs; + struct sk_buff_head tx_skb_queue[RTL_USB_MAX_EP_NUM]; + + struct usb_anchor tx_pending[RTL_USB_MAX_EP_NUM]; + struct usb_anchor tx_submitted; + + struct sk_buff *(*usb_tx_aggregate_hdl)(struct ieee80211_hw *, + struct sk_buff_head *); + int (*usb_tx_post_hdl)(struct ieee80211_hw *, + struct urb *, struct sk_buff *); + void (*usb_tx_cleanup)(struct ieee80211_hw *, struct sk_buff *); + + /* Rx */ + u8 in_ep_nums ; + u32 in_ep; /* Bulk IN endpoint number */ + u32 rx_max_size; /* Bulk IN max buffer size */ + u32 rx_urb_num; /* How many Bulk INs are submitted to host. */ + struct usb_anchor rx_submitted; + void (*usb_rx_segregate_hdl)(struct ieee80211_hw *, struct sk_buff *, + struct sk_buff_head *); + void (*usb_rx_hdl)(struct ieee80211_hw *, struct sk_buff *); +}; + +struct rtl_usb_priv { + struct rtl_usb dev; + struct rtl_led_ctl ledctl; +}; + +#define rtl_usbpriv(hw) (((struct rtl_usb_priv *)(rtl_priv(hw))->priv)) +#define rtl_usbdev(usbpriv) (&((usbpriv)->dev)) + + + +int __devinit rtl_usb_probe(struct usb_interface *intf, + const struct usb_device_id *id); +void rtl_usb_disconnect(struct usb_interface *intf); +int rtl_usb_suspend(struct usb_interface *pusb_intf, pm_message_t message); +int rtl_usb_resume(struct usb_interface *pusb_intf); + +#endif diff --git a/drivers/net/wireless/rtlwifi/wifi.h b/drivers/net/wireless/rtlwifi/wifi.h new file mode 100644 index 00000000..28ebc692 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/wifi.h @@ -0,0 +1,2041 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 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 __RTL_WIFI_H__ +#define __RTL_WIFI_H__ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/sched.h> +#include <linux/firmware.h> +#include <linux/etherdevice.h> +#include <linux/vmalloc.h> +#include <linux/usb.h> +#include <net/mac80211.h> +#include <linux/completion.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 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 REALTEK_USB_VENQT_MAX_BUF_SIZE 254 +#define RTL_USB_MAX_RX_COUNT 100 +#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 no */ +#define CHANNEL_GROUP_MAX (3 + 9) /* ch1~3, 4~9, 10~14 = 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 MAX_TID_COUNT 9 + +/* for early mode */ +#define FCS_LEN 4 +#define EM_HDR_LEN 8 +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 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_RTL8723E, + HARDWARE_TYPE_RTL8723U, + + /* keep it last */ + HARDWARE_TYPE_NUM +}; + +#define IS_HARDWARE_TYPE_8192SU(rtlhal) \ + (rtlhal->hw_type == HARDWARE_TYPE_RTL8192SU) +#define IS_HARDWARE_TYPE_8192SE(rtlhal) \ + (rtlhal->hw_type == HARDWARE_TYPE_RTL8192SE) +#define IS_HARDWARE_TYPE_8192CE(rtlhal) \ + (rtlhal->hw_type == HARDWARE_TYPE_RTL8192CE) +#define IS_HARDWARE_TYPE_8192CU(rtlhal) \ + (rtlhal->hw_type == HARDWARE_TYPE_RTL8192CU) +#define IS_HARDWARE_TYPE_8192DE(rtlhal) \ + (rtlhal->hw_type == HARDWARE_TYPE_RTL8192DE) +#define IS_HARDWARE_TYPE_8192DU(rtlhal) \ + (rtlhal->hw_type == HARDWARE_TYPE_RTL8192DU) +#define IS_HARDWARE_TYPE_8723E(rtlhal) \ + (rtlhal->hw_type == HARDWARE_TYPE_RTL8723E) +#define IS_HARDWARE_TYPE_8723U(rtlhal) \ + (rtlhal->hw_type == HARDWARE_TYPE_RTL8723U) +#define IS_HARDWARE_TYPE_8192S(rtlhal) \ +(IS_HARDWARE_TYPE_8192SE(rtlhal) || IS_HARDWARE_TYPE_8192SU(rtlhal)) +#define IS_HARDWARE_TYPE_8192C(rtlhal) \ +(IS_HARDWARE_TYPE_8192CE(rtlhal) || IS_HARDWARE_TYPE_8192CU(rtlhal)) +#define IS_HARDWARE_TYPE_8192D(rtlhal) \ +(IS_HARDWARE_TYPE_8192DE(rtlhal) || IS_HARDWARE_TYPE_8192DU(rtlhal)) +#define IS_HARDWARE_TYPE_8723(rtlhal) \ +(IS_HARDWARE_TYPE_8723E(rtlhal) || IS_HARDWARE_TYPE_8723U(rtlhal)) +#define IS_HARDWARE_TYPE_8723U(rtlhal) \ + (rtlhal->hw_type == HARDWARE_TYPE_RTL8723U) + +#define RX_HAL_IS_CCK_RATE(_pdesc)\ + (_pdesc->rxmcs == DESC92_RATE1M || \ + _pdesc->rxmcs == DESC92_RATE2M || \ + _pdesc->rxmcs == DESC92_RATE5_5M || \ + _pdesc->rxmcs == DESC92_RATE11M) + +enum scan_operation_backup_opt { + SCAN_OPT_BACKUP = 0, + 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_DM_BY_SCAN = 0, + IO_CMD_RESUME_DM_BY_SCAN = 1, +}; + +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_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_FW_PSMODE_STATUS, + 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, + + HW_VAR_MRC, + + HW_VAR_MGT_FILTER, + HW_VAR_CTRL_FILTER, + HW_VAR_DATA_FILTER, +}; + +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, +}; + +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, +}; + +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, +}; + +/* 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, +}; + +enum rtl_hal_state { + _HAL_STATE_STOP = 0, + _HAL_STATE_START = 1, +}; + +enum rtl_desc92_rate { + DESC92_RATE1M = 0x00, + DESC92_RATE2M = 0x01, + DESC92_RATE5_5M = 0x02, + DESC92_RATE11M = 0x03, + + DESC92_RATE6M = 0x04, + DESC92_RATE9M = 0x05, + DESC92_RATE12M = 0x06, + DESC92_RATE18M = 0x07, + DESC92_RATE24M = 0x08, + DESC92_RATE36M = 0x09, + DESC92_RATE48M = 0x0a, + DESC92_RATE54M = 0x0b, + + DESC92_RATEMCS0 = 0x0c, + DESC92_RATEMCS1 = 0x0d, + DESC92_RATEMCS2 = 0x0e, + DESC92_RATEMCS3 = 0x0f, + DESC92_RATEMCS4 = 0x10, + DESC92_RATEMCS5 = 0x11, + DESC92_RATEMCS6 = 0x12, + DESC92_RATEMCS7 = 0x13, + DESC92_RATEMCS8 = 0x14, + DESC92_RATEMCS9 = 0x15, + DESC92_RATEMCS10 = 0x16, + DESC92_RATEMCS11 = 0x17, + DESC92_RATEMCS12 = 0x18, + DESC92_RATEMCS13 = 0x19, + DESC92_RATEMCS14 = 0x1a, + DESC92_RATEMCS15 = 0x1b, + DESC92_RATEMCS15_SG = 0x1c, + DESC92_RATEMCS32 = 0x20, +}; + +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, + + /*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, + + /*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_IBSS_INT_MASKS, /*(RTL_IMR_BcnInt | RTL_IMR_TBDOK | + * RTL_IMR_TBDER) */ + + /*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, + + /*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 +}; + +#define IS_WIRELESS_MODE_A(wirelessmode) \ + (wirelessmode == WIRELESS_MODE_A) +#define IS_WIRELESS_MODE_B(wirelessmode) \ + (wirelessmode == WIRELESS_MODE_B) +#define IS_WIRELESS_MODE_G(wirelessmode) \ + (wirelessmode == WIRELESS_MODE_G) +#define IS_WIRELESS_MODE_N_24G(wirelessmode) \ + (wirelessmode == WIRELESS_MODE_N_24G) +#define IS_WIRELESS_MODE_N_5G(wirelessmode) \ + (wirelessmode == WIRELESS_MODE_N_5G) + +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_A = 8, +}; + +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, +}; + +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 ledon; +}; + +struct rtl_led_ctl { + bool led_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 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; +}; + +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; + + /*Transformed, in dbm. Beautified signal + strength for UI, not correct. */ + long signal_strength; + + u8 rx_rssi_percentage[4]; + u8 rx_evm_percentage[2]; + + 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_ra40m; + u32 low_rssi_thresh_for_ra40M; + u8 low2high_rssi_thresh_for_ra20m; + u32 low_rssi_thresh_for_ra20M; + 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; +}; + +struct regd_pair_mapping { + u16 reg_dmnenum; + u16 reg_5ghz_ctl; + u16 reg_2ghz_ctl; +}; + +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 */ +}; + +#define IQK_MATRIX_REG_NUM 8 +#define IQK_MATRIX_SETTINGS_NUM (1 + 24 + 21) +struct iqk_matrix_regs { + bool iqk_done; + long value[1][IQK_MATRIX_REG_NUM]; +}; + +struct phy_parameters { + u16 length; + u32 *pdata; +}; + +enum hw_param_tab_index { + PHY_REG_2T, + PHY_REG_1T, + PHY_REG_PG, + RADIOA_2T, + RADIOB_2T, + RADIOA_1T, + RADIOB_1T, + MAC_REG, + AGCTAB_2T, + AGCTAB_1T, + MAX_TAB +}; + +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; + + /* 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]; + + /* Dual mac */ + bool need_iqk; + struct iqk_matrix_regs iqk_matrix_regsetting[IQK_MATRIX_SETTINGS_NUM]; + + bool rfpi_enable; + + u8 pwrgroup_cnt; + u8 cck_high_power; + /* MAX_PG_GROUP groups of pwr diff by rates */ + u32 mcs_txpwrlevel_origoffset[MAX_PG_GROUP][16]; + u8 default_initialgain[4]; + + /* the current Tx power level */ + u8 cur_cck_txpwridx; + u8 cur_ofdm24g_txpwridx; + + u32 rfreg_chnlval[2]; + bool apk_done; + u32 reg_rf3c[2]; /* pathA / pathB */ + + /* bfsync */ + u8 framesync; + u32 framesync_c34; + + u8 num_total_rfpath; + struct phy_parameters hwparam_tables[MAX_TAB]; + u16 rf_pathmap; +}; + +#define MAX_TID_COUNT 9 +#define RTL_AGG_STOP 0 +#define RTL_AGG_PROGRESS 1 +#define RTL_AGG_START 2 +#define RTL_AGG_OPERATIONAL 3 +#define RTL_AGG_OFF 0 +#define RTL_AGG_ON 1 +#define RTL_AGG_EMPTYING_HW_QUEUE_ADDBA 2 +#define RTL_AGG_EMPTYING_HW_QUEUE_DELBA 3 + +struct rtl_ht_agg { + u16 txq_id; + u16 wait_for_ba; + u16 start_idx; + u64 bitmap; + u32 rate_n_flags; + u8 agg_state; +}; + +struct rtl_tid_data { + u16 seq_number; + struct rtl_ht_agg agg; +}; + +struct rtl_sta_info { + u8 ratr_index; + u8 wireless_mode; + u8 mimo_ps; + struct rtl_tid_data tids[MAX_TID_COUNT]; +} __packed; + +struct rtl_priv; +struct rtl_io { + struct device *dev; + struct mutex bb_mutex; + + /*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); + void (*writeN_sync) (struct rtl_priv *rtlpriv, u32 addr, void *buf, + u16 len); + + 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 */ + struct rtl_tid_data tids[MAX_TID_COUNT]; + enum rtl_link_state link_state; + + int n_channels; + int n_bitrates; + + bool offchan_delay; + + /*filters */ + u32 rx_conf; + u16 rx_mgt_filter; + u16 rx_ctrl_filter; + u16 rx_data_filter; + + bool act_scanning; + u8 cnt_after_linked; + + /* early mode */ + /* skb wait queue */ + struct sk_buff_head skb_waitq[MAX_TID_COUNT]; + u8 earlymode_threshold; + + /*RDG*/ + bool rdg_en; + + /*AP*/ + u8 bssid[6]; + u32 vendor; + u8 mcs[16]; /* 16 bytes mcs for HT rates. */ + u32 basic_rates; /* b/g rates */ + u8 ht_enable; + u8 sgi_40; + u8 sgi_20; + 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; + u64 tsf; + u8 retry_short; + u8 retry_long; + u16 assoc_id; + + /*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; + + 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 */ + + /*firmware */ + u32 fwsize; + u8 *pfirmware; + u16 fw_version; + u16 fw_subversion; + bool h2c_setinprogress; + u8 last_hmeboxnum; + /*Reserve page start offset except beacon in TxQ. */ + u8 fw_rsvdpage_startoffset; + u8 h2c_txcmd_seq; + + /* FW Cmd IO related */ + u16 fwcmd_iomap; + u32 fwcmd_ioparam; + bool set_fwcmd_inprogress; + u8 current_fwcmd_io; + + /**/ + bool driver_going2unload; + + /*AMPDU init min space*/ + u8 minspace_cfg; /*For Min spacing configurations */ + + /* Dual 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 DualMac S3S4 */ + u8 macphyctl_reg; + bool earlymode_enable; + /* Dual 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 load_imrandiqk_setting_for2g; + + bool disable_amsdu_8k; +}; + +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_dm { + /*PHY status for Dynamic Management */ + long entry_min_undecoratedsmoothed_pwdb; + long undecorated_smoothed_pwdb; /*out dm */ + long entry_max_undecoratedsmoothed_pwdb; + bool dm_initialgain_enable; + bool dynamic_txpower_enable; + bool current_turbo_edca; + bool is_any_nonbepkts; /*out dm */ + bool is_cur_rdlstate; + bool txpower_trackinginit; + bool disable_framebursting; + bool cck_inch14; + bool txpower_tracking; + bool useramask; + bool rfpath_rxenable[4]; + bool inform_fw_driverctrldm; + bool current_mrc_switch; + u8 txpowercount; + + u8 thermalvalue_rxgain; + u8 thermalvalue_iqk; + u8 thermalvalue_lck; + u8 thermalvalue; + u8 last_dtp_lvl; + u8 thermalvalue_avg[AVG_THERMAL_NUM]; + u8 thermalvalue_avg_index; + bool done_txpower; + u8 dynamic_txhighpower_lvl; /*Tx high power level */ + u8 dm_flag; /*Indicate each dynamic mechanism's status. */ + u8 dm_type; + u8 txpower_track_control; + bool interrupt_migration; + bool disable_tx_int; + char ofdm_index[2]; + char cck_index; +}; + +#define EFUSE_MAX_LOGICAL_SIZE 256 + +struct rtl_efuse { + bool autoLoad_ok; + bool bootfromefuse; + u16 max_physical_size; + + u8 efuse_map[2][EFUSE_MAX_LOGICAL_SIZE]; + u16 efuse_usedbytes; + u8 efuse_usedpercentage; +#ifdef EFUSE_REPG_WORKAROUND + bool efuse_re_pg_sec1flag; + u8 efuse_re_pg_data[8]; +#endif + + 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 board_type; + u8 external_pa; + + u8 dev_addr[6]; + + bool 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 txpwrlevel_cck[2][CHANNEL_MAX_NUMBER_2G]; + u8 txpwrlevel_ht40_1s[2][CHANNEL_MAX_NUMBER]; /*For HT 40MHZ pwr */ + u8 txpwrlevel_ht40_2s[2][CHANNEL_MAX_NUMBER]; /*For HT 40MHZ pwr */ + + 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]; + + char txpwr_ht20diff[2][CHANNEL_MAX_NUMBER]; /*HT 20<->40 Pwr diff */ + /*For HT<->legacy pwr diff*/ + u8 txpwr_legacyhtdiff[2][CHANNEL_MAX_NUMBER]; + 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, 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 apk_thermalmeterignore; + + bool b1x1_recvcombine; + bool b1ss_support; + + /*channel plan */ + u8 channel_plan; +}; + +struct rtl_ps_ctl { + bool pwrdomain_protect; + bool in_powersavemode; + bool rfchange_inprogress; + bool swrf_processing; + bool hwradiooff; + + /* + * just for PCIE ASPM + * If it supports ASPM, Offset[560h] = 0x40, + * otherwise Offset[560h] = 0x00. + * */ + bool support_aspm; + + bool support_backdoor; + + /*for LPS */ + enum rt_psmode dot11_psmode; /*Power save mode configured. */ + bool swctrl_lps; + bool leisure_ps; + bool fwctrl_lps; + u8 fwctrl_psmode; + /*For Fw control LPS mode */ + u8 reg_fwctrl_lps; + /*Record Fw PS mode status. */ + bool fw_current_inpsmode; + u8 reg_max_lps_awakeintvl; + bool report_linked; + + /*for IPS */ + bool inactiveps; + + u32 rfoff_reason; + + /*RF OFF Level */ + u32 cur_ps_level; + u32 reg_rfps_level; + + /*just for PCIE ASPM */ + u8 const_amdpci_aspm; + bool pwrdown_mode; + + 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; +}; + +struct rtl_stats { + u32 mac_time[2]; + s8 rssi; + u8 signal; + u8 noise; + u16 rate; /*in 100 kbps */ + 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 hwerror:1; + u16 crc:1; + u16 icv:1; + u16 shortpreamble:1; + u16 antenna:1; + u16 decrypted:1; + u16 wakeup:1; + u32 timestamp_low; + u32 timestamp_high; + + u8 rx_drvinfo_size; + u8 rx_bufshift; + bool isampdu; + bool isfirst_ampdu; + bool rx_is40Mhzpacket; + u32 rx_pwdb_all; + u8 rx_mimo_signalstrength[4]; /*in 0~100 index */ + s8 rx_mimo_signalquality[2]; + bool packet_matchbssid; + bool is_cck; + bool is_ht; + bool packet_toself; + bool packet_beacon; /*for rssi */ + char cck_adc_pwdb[4]; /*for rx path selection */ +}; + +struct rt_link_detect { + u32 num_tx_in4period[4]; + u32 num_rx_in4period[4]; + + u32 num_tx_inperiod; + u32 num_rx_inperiod; + + bool busytraffic; + bool higher_busytraffic; + bool 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:1; + u8 multicast:1; + u8 broadcast:1; + + u8 rts_stbc:1; + u8 rts_enable:1; + u8 cts_enable:1; + u8 rts_use_shortpreamble:1; + u8 rts_use_shortgi:1; + u8 rts_sc:1; + u8 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 last_inipkt:1; + u8 cmd_or_init:1; + u8 queue_index; + + /* early mode */ + u8 empkt_num; + /* The max value by HW */ + u32 empkt_len[5]; +}; + +struct rtl_hal_ops { + int (*init_sw_vars) (struct ieee80211_hw *hw); + void (*deinit_sw_vars) (struct ieee80211_hw *hw); + void (*read_chip_version)(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 (*update_rate_mask) (struct ieee80211_hw *hw, u8 rssi_level); + void (*fill_tx_desc) (struct ieee80211_hw *hw, + struct ieee80211_hdr *hdr, u8 *pdesc_tx, + struct ieee80211_tx_info *info, + struct sk_buff *skb, u8 hw_queue, + struct rtl_tcb_desc *ptcb_desc); + void (*fill_fake_txdesc) (struct ieee80211_hw *hw, u8 *pDesc, + u32 buffer_len, bool bIsPsPoll); + void (*fill_tx_cmddesc) (struct ieee80211_hw *hw, u8 *pdesc, + bool firstseg, bool lastseg, + struct sk_buff *skb); + bool (*cmd_send_packet)(struct ieee80211_hw *hw, struct sk_buff *skb); + bool (*query_rx_desc) (struct ieee80211_hw *hw, + struct rtl_stats *stats, + 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) (u8 *pdesc, bool istx, u8 desc_name, u8 *val); + u32 (*get_desc) (u8 *pdesc, bool istx, u8 desc_name); + 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 *macaddr, bool is_group, u8 enc_algo, + bool is_wepkey, bool clear_all); + void (*init_sw_leds) (struct ieee80211_hw *hw); + void (*deinit_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 (*linked_set_reg) (struct ieee80211_hw *hw); + bool (*phy_rf6052_config) (struct ieee80211_hw *hw); + void (*phy_rf6052_set_cck_txpower) (struct ieee80211_hw *hw, + u8 *powerlevel); + void (*phy_rf6052_set_ofdm_txpower) (struct ieee80211_hw *hw, + u8 *ppowerlevel, u8 channel); + bool (*config_bb_with_headerfile) (struct ieee80211_hw *hw, + u8 configtype); + bool (*config_bb_with_pgheaderfile) (struct ieee80211_hw *hw, + u8 configtype); + void (*phy_lc_calibrate) (struct ieee80211_hw *hw, bool is2t); + void (*phy_set_bw_mode_callback) (struct ieee80211_hw *hw); + void (*dm_dynamic_txpower) (struct ieee80211_hw *hw); +}; + +struct rtl_intf_ops { + /*com */ + void (*read_efuse_byte)(struct ieee80211_hw *hw, u16 _offset, u8 *pbuf); + int (*adapter_start) (struct ieee80211_hw *hw); + void (*adapter_stop) (struct ieee80211_hw *hw); + + int (*adapter_tx) (struct ieee80211_hw *hw, struct sk_buff *skb, + struct rtl_tcb_desc *ptcb_desc); + void (*flush)(struct ieee80211_hw *hw, bool drop); + int (*reset_trx_ring) (struct ieee80211_hw *hw); + bool (*waitq_insert) (struct ieee80211_hw *hw, 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 inactiveps; + + /* default: 1 = using linked sw power save */ + bool swctrl_lps; + + /* default: 1 = using linked fw power save */ + bool fwctrl_lps; +}; + +struct rtl_hal_usbint_cfg { + /* data - rx */ + u32 in_ep_num; + u32 rx_urb_num; + u32 rx_max_size; + + /* op - rx */ + void (*usb_rx_hdl)(struct ieee80211_hw *, struct sk_buff *); + void (*usb_rx_segregate_hdl)(struct ieee80211_hw *, struct sk_buff *, + struct sk_buff_head *); + + /* tx */ + void (*usb_tx_cleanup)(struct ieee80211_hw *, struct sk_buff *); + int (*usb_tx_post_hdl)(struct ieee80211_hw *, struct urb *, + struct sk_buff *); + struct sk_buff *(*usb_tx_aggregate_hdl)(struct ieee80211_hw *, + struct sk_buff_head *); + + /* endpoint mapping */ + int (*usb_endpoint_mapping)(struct ieee80211_hw *hw); + u16 (*usb_mq_to_hwq)(__le16 fc, u16 mac80211_queue_index); +}; + +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; + struct rtl_hal_usbint_cfg *usb_interface_cfg; + + /*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; + struct mutex ps_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 waitq_lock; + + /*Dual mac*/ + spinlock_t cck_and_rw_pagea_lock; +}; + +struct rtl_works { + struct ieee80211_hw *hw; + + /*timer */ + struct timer_list watchdog_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 work_struct lps_leave_work; +}; + +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]; +}; + +struct rtl_priv { + struct completion firmware_loading_complete; + 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 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; + int max_fw_size; + + /* + *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; + + /* data buffer pointer for USB reads */ + __le32 *usb_data; + int usb_data_index; + + /*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)) + + +/*************************************** + Bluetooth Co-existence 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, +}; + +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 init_set; + bool bt_busy_traffic; + bool bt_traffic_mode_set; + bool bt_non_traffic_mode_set; + + bool fw_coexist_all_off; + bool sw_coexist_all_off; + u32 current_state; + u32 previous_state; + u8 bt_pre_rssi_state; + + u8 reg_bt_iso; + u8 reg_bt_sco; + +}; + + +/**************************************** + 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(*((u16 *)(_ptr))) +#define READEF4BYTE(_ptr) \ + EF4BYTE(*((u32 *)(_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) \ + (*((u16 *)(_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(*((u32 *)(__pstart)))) +#define LE_P2BYTE_TO_HOST_2BYTE(__pstart) \ + (EF2BYTE(*((u16 *)(__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)) = EF4BYTE \ + ( \ + 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)) = EF2BYTE \ + ( \ + 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_cpu(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]) + +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 *)(hw)->priv)->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 *get_sta(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + const u8 *bssid) +{ + return ieee80211_find_sta(vif, bssid); +} + +#endif |