875 lines
25 KiB
C
Executable File
875 lines
25 KiB
C
Executable File
/******************************************************************************
|
|
*
|
|
* Copyright(c) 2007 - 2016 Realtek Corporation.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
* under the terms of version 2 of the GNU General Public License as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
* more details.
|
|
*
|
|
* The full GNU General Public License is included in this distribution in the
|
|
* file called LICENSE.
|
|
*
|
|
* Contact Information:
|
|
* wlanfae <wlanfae@realtek.com>
|
|
* Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
|
|
* Hsinchu 300, Taiwan.
|
|
*
|
|
* Larry Finger <Larry.Finger@lwfinger.net>
|
|
*
|
|
*****************************************************************************/
|
|
#include "mp_precomp.h"
|
|
#include "phydm_precomp.h"
|
|
#include <linux/module.h>
|
|
|
|
static int _rtl_phydm_init_com_info(struct rtl_priv *rtlpriv,
|
|
enum odm_ic_type ic_type,
|
|
struct rtl_phydm_params *params)
|
|
{
|
|
struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv);
|
|
struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
|
|
struct rtl_phy *rtlphy = &rtlpriv->phy;
|
|
struct rtl_mac *mac = rtl_mac(rtlpriv);
|
|
struct rtl_ps_ctl *ppsc = rtl_psc(rtlpriv);
|
|
struct rtl_efuse *rtlefuse = rtl_efuse(rtlpriv);
|
|
u8 odm_board_type = ODM_BOARD_DEFAULT;
|
|
u32 support_ability;
|
|
int i;
|
|
|
|
dm->adapter = (void *)rtlpriv;
|
|
|
|
odm_cmn_info_init(dm, ODM_CMNINFO_PLATFORM, ODM_CE);
|
|
|
|
odm_cmn_info_init(dm, ODM_CMNINFO_IC_TYPE, ic_type);
|
|
|
|
odm_cmn_info_init(dm, ODM_CMNINFO_INTERFACE, ODM_ITRF_PCIE);
|
|
|
|
odm_cmn_info_init(dm, ODM_CMNINFO_MP_TEST_CHIP, params->mp_chip);
|
|
|
|
odm_cmn_info_init(dm, ODM_CMNINFO_PATCH_ID, rtlhal->oem_id);
|
|
|
|
odm_cmn_info_init(dm, ODM_CMNINFO_BWIFI_TEST, 1);
|
|
|
|
if (rtlphy->rf_type == RF_1T1R)
|
|
odm_cmn_info_init(dm, ODM_CMNINFO_RF_TYPE, ODM_1T1R);
|
|
else if (rtlphy->rf_type == RF_1T2R)
|
|
odm_cmn_info_init(dm, ODM_CMNINFO_RF_TYPE, ODM_1T2R);
|
|
else if (rtlphy->rf_type == RF_2T2R)
|
|
odm_cmn_info_init(dm, ODM_CMNINFO_RF_TYPE, ODM_2T2R);
|
|
else if (rtlphy->rf_type == RF_2T2R_GREEN)
|
|
odm_cmn_info_init(dm, ODM_CMNINFO_RF_TYPE, ODM_2T2R_GREEN);
|
|
else if (rtlphy->rf_type == RF_2T3R)
|
|
odm_cmn_info_init(dm, ODM_CMNINFO_RF_TYPE, ODM_2T3R);
|
|
else if (rtlphy->rf_type == RF_2T4R)
|
|
odm_cmn_info_init(dm, ODM_CMNINFO_RF_TYPE, ODM_2T4R);
|
|
else if (rtlphy->rf_type == RF_3T3R)
|
|
odm_cmn_info_init(dm, ODM_CMNINFO_RF_TYPE, ODM_3T3R);
|
|
else if (rtlphy->rf_type == RF_3T4R)
|
|
odm_cmn_info_init(dm, ODM_CMNINFO_RF_TYPE, ODM_3T4R);
|
|
else if (rtlphy->rf_type == RF_4T4R)
|
|
odm_cmn_info_init(dm, ODM_CMNINFO_RF_TYPE, ODM_4T4R);
|
|
else
|
|
odm_cmn_info_init(dm, ODM_CMNINFO_RF_TYPE, ODM_XTXR);
|
|
|
|
/* 1 ======= BoardType: ODM_CMNINFO_BOARD_TYPE ======= */
|
|
if (rtlhal->external_lna_2g != 0) {
|
|
odm_board_type |= ODM_BOARD_EXT_LNA;
|
|
odm_cmn_info_init(dm, ODM_CMNINFO_EXT_LNA, 1);
|
|
}
|
|
if (rtlhal->external_lna_5g != 0) {
|
|
odm_board_type |= ODM_BOARD_EXT_LNA_5G;
|
|
odm_cmn_info_init(dm, ODM_CMNINFO_5G_EXT_LNA, 1);
|
|
}
|
|
if (rtlhal->external_pa_2g != 0) {
|
|
odm_board_type |= ODM_BOARD_EXT_PA;
|
|
odm_cmn_info_init(dm, ODM_CMNINFO_EXT_PA, 1);
|
|
}
|
|
if (rtlhal->external_pa_5g != 0) {
|
|
odm_board_type |= ODM_BOARD_EXT_PA_5G;
|
|
odm_cmn_info_init(dm, ODM_CMNINFO_5G_EXT_PA, 1);
|
|
}
|
|
if (rtlpriv->cfg->ops->get_btc_status())
|
|
odm_board_type |= ODM_BOARD_BT;
|
|
|
|
odm_cmn_info_init(dm, ODM_CMNINFO_BOARD_TYPE, odm_board_type);
|
|
/* 1 ============== End of BoardType ============== */
|
|
|
|
odm_cmn_info_init(dm, ODM_CMNINFO_GPA, rtlhal->type_gpa);
|
|
odm_cmn_info_init(dm, ODM_CMNINFO_APA, rtlhal->type_apa);
|
|
odm_cmn_info_init(dm, ODM_CMNINFO_GLNA, rtlhal->type_glna);
|
|
odm_cmn_info_init(dm, ODM_CMNINFO_ALNA, rtlhal->type_alna);
|
|
|
|
odm_cmn_info_init(dm, ODM_CMNINFO_RFE_TYPE, rtlhal->rfe_type);
|
|
|
|
odm_cmn_info_init(dm, ODM_CMNINFO_EXT_TRSW, 0);
|
|
|
|
/*Add by YuChen for kfree init*/
|
|
odm_cmn_info_init(dm, ODM_CMNINFO_REGRFKFREEENABLE, 2);
|
|
odm_cmn_info_init(dm, ODM_CMNINFO_RFKFREEENABLE, 0);
|
|
|
|
/*Antenna diversity relative parameters*/
|
|
odm_cmn_info_hook(dm, ODM_CMNINFO_ANT_DIV,
|
|
&rtlefuse->antenna_div_cfg);
|
|
odm_cmn_info_init(dm, ODM_CMNINFO_RF_ANTENNA_TYPE,
|
|
rtlefuse->antenna_div_type);
|
|
odm_cmn_info_init(dm, ODM_CMNINFO_BE_FIX_TX_ANT, 0);
|
|
odm_cmn_info_init(dm, ODM_CMNINFO_WITH_EXT_ANTENNA_SWITCH, 0);
|
|
|
|
/* (8822B) efuse 0x3D7 & 0x3D8 for TX PA bias */
|
|
odm_cmn_info_init(dm, ODM_CMNINFO_EFUSE0X3D7, params->efuse0x3d7);
|
|
odm_cmn_info_init(dm, ODM_CMNINFO_EFUSE0X3D8, params->efuse0x3d8);
|
|
|
|
/*Add by YuChen for adaptivity init*/
|
|
odm_cmn_info_hook(dm, ODM_CMNINFO_ADAPTIVITY,
|
|
&rtlpriv->phydm.adaptivity_en);
|
|
phydm_adaptivity_info_init(dm, PHYDM_ADAPINFO_CARRIER_SENSE_ENABLE,
|
|
false);
|
|
phydm_adaptivity_info_init(dm, PHYDM_ADAPINFO_DCBACKOFF, 0);
|
|
phydm_adaptivity_info_init(dm, PHYDM_ADAPINFO_DYNAMICLINKADAPTIVITY,
|
|
false);
|
|
phydm_adaptivity_info_init(dm, PHYDM_ADAPINFO_TH_L2H_INI, 0);
|
|
phydm_adaptivity_info_init(dm, PHYDM_ADAPINFO_TH_EDCCA_HL_DIFF, 0);
|
|
|
|
odm_cmn_info_init(dm, ODM_CMNINFO_IQKFWOFFLOAD, 0);
|
|
|
|
/* Pointer reference */
|
|
odm_cmn_info_hook(dm, ODM_CMNINFO_TX_UNI,
|
|
&rtlpriv->stats.txbytesunicast);
|
|
odm_cmn_info_hook(dm, ODM_CMNINFO_RX_UNI,
|
|
&rtlpriv->stats.rxbytesunicast);
|
|
odm_cmn_info_hook(dm, ODM_CMNINFO_BAND, &rtlhal->current_bandtype);
|
|
odm_cmn_info_hook(dm, ODM_CMNINFO_FORCED_RATE,
|
|
&rtlpriv->phydm.forced_data_rate);
|
|
odm_cmn_info_hook(dm, ODM_CMNINFO_FORCED_IGI_LB,
|
|
&rtlpriv->phydm.forced_igi_lb);
|
|
|
|
odm_cmn_info_hook(dm, ODM_CMNINFO_SEC_CHNL_OFFSET,
|
|
&mac->cur_40_prime_sc);
|
|
odm_cmn_info_hook(dm, ODM_CMNINFO_BW, &rtlphy->current_chan_bw);
|
|
odm_cmn_info_hook(dm, ODM_CMNINFO_CHNL, &rtlphy->current_channel);
|
|
|
|
odm_cmn_info_hook(dm, ODM_CMNINFO_SCAN, &mac->act_scanning);
|
|
odm_cmn_info_hook(dm, ODM_CMNINFO_POWER_SAVING,
|
|
&ppsc->dot11_psmode); /* may add new boolean flag */
|
|
/*Add by Yuchen for phydm beamforming*/
|
|
odm_cmn_info_hook(dm, ODM_CMNINFO_TX_TP,
|
|
&rtlpriv->stats.txbytesunicast_inperiod_tp);
|
|
odm_cmn_info_hook(dm, ODM_CMNINFO_RX_TP,
|
|
&rtlpriv->stats.rxbytesunicast_inperiod_tp);
|
|
odm_cmn_info_hook(dm, ODM_CMNINFO_ANT_TEST,
|
|
&rtlpriv->phydm.antenna_test);
|
|
for (i = 0; i < ODM_ASSOCIATE_ENTRY_NUM; i++)
|
|
odm_cmn_info_ptr_array_hook(dm, ODM_CMNINFO_STA_STATUS, i,
|
|
NULL);
|
|
|
|
phydm_init_debug_setting(dm);
|
|
|
|
odm_cmn_info_init(dm, ODM_CMNINFO_FAB_VER, params->fab_ver);
|
|
odm_cmn_info_init(dm, ODM_CMNINFO_CUT_VER, params->cut_ver);
|
|
|
|
/* after ifup, ability is updated again */
|
|
support_ability = ODM_RF_CALIBRATION | ODM_RF_TX_PWR_TRACK;
|
|
odm_cmn_info_update(dm, ODM_CMNINFO_ABILITY, support_ability);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int rtl_phydm_init_priv(struct rtl_priv *rtlpriv,
|
|
struct rtl_phydm_params *params)
|
|
{
|
|
struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv);
|
|
enum odm_ic_type ic;
|
|
|
|
if (IS_HARDWARE_TYPE_8822B(rtlpriv))
|
|
ic = ODM_RTL8822B;
|
|
else
|
|
return 0;
|
|
|
|
rtlpriv->phydm.internal =
|
|
kzalloc(sizeof(struct phy_dm_struct), GFP_KERNEL);
|
|
|
|
_rtl_phydm_init_com_info(rtlpriv, ic, params);
|
|
|
|
odm_init_all_timers(dm);
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int rtl_phydm_deinit_priv(struct rtl_priv *rtlpriv)
|
|
{
|
|
struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv);
|
|
|
|
odm_cancel_all_timers(dm);
|
|
|
|
kfree(rtlpriv->phydm.internal);
|
|
rtlpriv->phydm.internal = NULL;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static bool rtl_phydm_load_txpower_by_rate(struct rtl_priv *rtlpriv)
|
|
{
|
|
struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv);
|
|
enum hal_status status;
|
|
|
|
status = odm_config_bb_with_header_file(dm, CONFIG_BB_PHY_REG_PG);
|
|
if (status != HAL_STATUS_SUCCESS)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool rtl_phydm_load_txpower_limit(struct rtl_priv *rtlpriv)
|
|
{
|
|
struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv);
|
|
enum hal_status status;
|
|
|
|
if (IS_HARDWARE_TYPE_8822B(rtlpriv)) {
|
|
odm_read_and_config_mp_8822b_txpwr_lmt(dm);
|
|
} else {
|
|
status = odm_config_rf_with_header_file(dm, CONFIG_RF_TXPWR_LMT,
|
|
0);
|
|
if (status != HAL_STATUS_SUCCESS)
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static int rtl_phydm_init_dm(struct rtl_priv *rtlpriv)
|
|
{
|
|
struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv);
|
|
u32 support_ability = 0;
|
|
|
|
/* clang-format off */
|
|
support_ability = 0
|
|
| ODM_BB_DIG
|
|
| ODM_BB_RA_MASK
|
|
| ODM_BB_DYNAMIC_TXPWR
|
|
| ODM_BB_FA_CNT
|
|
| ODM_BB_RSSI_MONITOR
|
|
| ODM_BB_CCK_PD
|
|
/* | ODM_BB_PWR_SAVE*/
|
|
| ODM_BB_CFO_TRACKING
|
|
| ODM_MAC_EDCA_TURBO
|
|
| ODM_RF_TX_PWR_TRACK
|
|
| ODM_RF_CALIBRATION
|
|
| ODM_BB_NHM_CNT
|
|
/* | ODM_BB_PWR_TRAIN*/
|
|
;
|
|
/* clang-format on */
|
|
|
|
odm_cmn_info_update(dm, ODM_CMNINFO_ABILITY, support_ability);
|
|
|
|
odm_dm_init(dm);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int rtl_phydm_deinit_dm(struct rtl_priv *rtlpriv)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static int rtl_phydm_reset_dm(struct rtl_priv *rtlpriv)
|
|
{
|
|
struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv);
|
|
|
|
odm_dm_reset(dm);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static bool rtl_phydm_parameter_init(struct rtl_priv *rtlpriv, bool post)
|
|
{
|
|
struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv);
|
|
|
|
if (IS_HARDWARE_TYPE_8822B(rtlpriv))
|
|
return config_phydm_parameter_init(dm, post ? ODM_POST_SETTING :
|
|
ODM_PRE_SETTING);
|
|
|
|
return false;
|
|
}
|
|
|
|
static bool rtl_phydm_phy_bb_config(struct rtl_priv *rtlpriv)
|
|
{
|
|
struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv);
|
|
enum hal_status status;
|
|
|
|
status = odm_config_bb_with_header_file(dm, CONFIG_BB_PHY_REG);
|
|
if (status != HAL_STATUS_SUCCESS)
|
|
return false;
|
|
|
|
status = odm_config_bb_with_header_file(dm, CONFIG_BB_AGC_TAB);
|
|
if (status != HAL_STATUS_SUCCESS)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool rtl_phydm_phy_rf_config(struct rtl_priv *rtlpriv)
|
|
{
|
|
struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv);
|
|
struct rtl_phy *rtlphy = &rtlpriv->phy;
|
|
enum hal_status status;
|
|
enum odm_rf_radio_path rfpath;
|
|
|
|
for (rfpath = 0; rfpath < rtlphy->num_total_rfpath; rfpath++) {
|
|
status = odm_config_rf_with_header_file(dm, CONFIG_RF_RADIO,
|
|
rfpath);
|
|
if (status != HAL_STATUS_SUCCESS)
|
|
return false;
|
|
}
|
|
|
|
status = odm_config_rf_with_tx_pwr_track_header_file(dm);
|
|
if (status != HAL_STATUS_SUCCESS)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool rtl_phydm_phy_mac_config(struct rtl_priv *rtlpriv)
|
|
{
|
|
struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv);
|
|
enum hal_status status;
|
|
|
|
status = odm_config_mac_with_header_file(dm);
|
|
if (status != HAL_STATUS_SUCCESS)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool rtl_phydm_trx_mode(struct rtl_priv *rtlpriv,
|
|
enum radio_mask tx_path, enum radio_mask rx_path,
|
|
bool is_tx2_path)
|
|
{
|
|
struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv);
|
|
|
|
if (IS_HARDWARE_TYPE_8822B(rtlpriv))
|
|
return config_phydm_trx_mode_8822b(dm,
|
|
(enum odm_rf_path)tx_path,
|
|
(enum odm_rf_path)rx_path,
|
|
is_tx2_path);
|
|
|
|
return false;
|
|
}
|
|
|
|
static bool rtl_phydm_watchdog(struct rtl_priv *rtlpriv)
|
|
{
|
|
struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv);
|
|
struct rtl_mac *mac = rtl_mac(rtlpriv);
|
|
struct rtl_ps_ctl *ppsc = rtl_psc(rtlpriv);
|
|
bool fw_current_inpsmode = false;
|
|
bool fw_ps_awake = true;
|
|
u8 is_linked = false;
|
|
u8 bsta_state = false;
|
|
u8 is_bt_enabled = false;
|
|
|
|
/* check whether do watchdog */
|
|
rtlpriv->cfg->ops->get_hw_reg(rtlpriv->hw, HW_VAR_FW_PSMODE_STATUS,
|
|
(u8 *)(&fw_current_inpsmode));
|
|
rtlpriv->cfg->ops->get_hw_reg(rtlpriv->hw, HW_VAR_FWLPS_RF_ON,
|
|
(u8 *)(&fw_ps_awake));
|
|
if (ppsc->p2p_ps_info.p2p_ps_mode)
|
|
fw_ps_awake = false;
|
|
|
|
if ((ppsc->rfpwr_state == ERFON) &&
|
|
((!fw_current_inpsmode) && fw_ps_awake) &&
|
|
(!ppsc->rfchange_inprogress))
|
|
;
|
|
else
|
|
return false;
|
|
|
|
/* update common info before doing watchdog */
|
|
if (mac->link_state >= MAC80211_LINKED) {
|
|
is_linked = true;
|
|
if (mac->vif && mac->vif->type == NL80211_IFTYPE_STATION)
|
|
bsta_state = true;
|
|
}
|
|
|
|
if (rtlpriv->cfg->ops->get_btc_status())
|
|
is_bt_enabled = !rtlpriv->btcoexist.btc_ops->btc_is_bt_disabled(
|
|
rtlpriv);
|
|
|
|
odm_cmn_info_update(dm, ODM_CMNINFO_LINK, is_linked);
|
|
odm_cmn_info_update(dm, ODM_CMNINFO_STATION_STATE, bsta_state);
|
|
odm_cmn_info_update(dm, ODM_CMNINFO_BT_ENABLED, is_bt_enabled);
|
|
|
|
/* do watchdog */
|
|
odm_dm_watchdog(dm);
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool rtl_phydm_switch_band(struct rtl_priv *rtlpriv, u8 central_ch)
|
|
{
|
|
struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv);
|
|
|
|
if (IS_HARDWARE_TYPE_8822B(rtlpriv))
|
|
return config_phydm_switch_band_8822b(dm, central_ch);
|
|
|
|
return false;
|
|
}
|
|
|
|
static bool rtl_phydm_switch_channel(struct rtl_priv *rtlpriv, u8 central_ch)
|
|
{
|
|
struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv);
|
|
|
|
if (IS_HARDWARE_TYPE_8822B(rtlpriv))
|
|
return config_phydm_switch_channel_8822b(dm, central_ch);
|
|
|
|
return false;
|
|
}
|
|
|
|
static bool rtl_phydm_switch_bandwidth(struct rtl_priv *rtlpriv,
|
|
u8 primary_ch_idx,
|
|
enum ht_channel_width bandwidth)
|
|
{
|
|
struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv);
|
|
enum odm_bw odm_bw = (enum odm_bw)bandwidth;
|
|
|
|
if (IS_HARDWARE_TYPE_8822B(rtlpriv))
|
|
return config_phydm_switch_bandwidth_8822b(dm, primary_ch_idx,
|
|
odm_bw);
|
|
|
|
return false;
|
|
}
|
|
|
|
static bool rtl_phydm_iq_calibrate(struct rtl_priv *rtlpriv)
|
|
{
|
|
struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv);
|
|
|
|
if (IS_HARDWARE_TYPE_8822B(rtlpriv))
|
|
phy_iq_calibrate_8822b(dm, false);
|
|
else
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool rtl_phydm_clear_txpowertracking_state(struct rtl_priv *rtlpriv)
|
|
{
|
|
struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv);
|
|
|
|
odm_clear_txpowertracking_state(dm);
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool rtl_phydm_pause_dig(struct rtl_priv *rtlpriv, bool pause)
|
|
{
|
|
struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv);
|
|
|
|
if (pause)
|
|
odm_pause_dig(dm, PHYDM_PAUSE, PHYDM_PAUSE_LEVEL_0, 0x1e);
|
|
else /* resume */
|
|
odm_pause_dig(dm, PHYDM_RESUME, PHYDM_PAUSE_LEVEL_0, 0xff);
|
|
|
|
return true;
|
|
}
|
|
|
|
static u32 rtl_phydm_read_rf_reg(struct rtl_priv *rtlpriv,
|
|
enum radio_path rfpath, u32 addr, u32 mask)
|
|
{
|
|
struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv);
|
|
enum odm_rf_radio_path odm_rfpath = (enum odm_rf_radio_path)rfpath;
|
|
|
|
if (IS_HARDWARE_TYPE_8822B(rtlpriv))
|
|
return config_phydm_read_rf_reg_8822b(dm, odm_rfpath, addr,
|
|
mask);
|
|
|
|
return -1;
|
|
}
|
|
|
|
static bool rtl_phydm_write_rf_reg(struct rtl_priv *rtlpriv,
|
|
enum radio_path rfpath, u32 addr, u32 mask,
|
|
u32 data)
|
|
{
|
|
struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv);
|
|
enum odm_rf_radio_path odm_rfpath = (enum odm_rf_radio_path)rfpath;
|
|
|
|
if (IS_HARDWARE_TYPE_8822B(rtlpriv))
|
|
return config_phydm_write_rf_reg_8822b(dm, odm_rfpath, addr,
|
|
mask, data);
|
|
|
|
return false;
|
|
}
|
|
|
|
static u8 rtl_phydm_read_txagc(struct rtl_priv *rtlpriv, enum radio_path rfpath,
|
|
u8 hw_rate)
|
|
{
|
|
struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv);
|
|
enum odm_rf_radio_path odm_rfpath = (enum odm_rf_radio_path)rfpath;
|
|
|
|
if (IS_HARDWARE_TYPE_8822B(rtlpriv))
|
|
return config_phydm_read_txagc_8822b(dm, odm_rfpath, hw_rate);
|
|
|
|
return -1;
|
|
}
|
|
|
|
static bool rtl_phydm_write_txagc(struct rtl_priv *rtlpriv, u32 power_index,
|
|
enum radio_path rfpath, u8 hw_rate)
|
|
{
|
|
struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv);
|
|
enum odm_rf_radio_path odm_rfpath = (enum odm_rf_radio_path)rfpath;
|
|
|
|
if (IS_HARDWARE_TYPE_8822B(rtlpriv))
|
|
return config_phydm_write_txagc_8822b(dm, power_index,
|
|
odm_rfpath, hw_rate);
|
|
|
|
return false;
|
|
}
|
|
|
|
static bool rtl_phydm_c2h_content_parsing(struct rtl_priv *rtlpriv, u8 cmd_id,
|
|
u8 cmd_len, u8 *content)
|
|
{
|
|
struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv);
|
|
|
|
if (phydm_c2H_content_parsing(dm, cmd_id, cmd_len, content))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
static bool rtl_phydm_query_phy_status(struct rtl_priv *rtlpriv, u8 *phystrpt,
|
|
struct ieee80211_hdr *hdr,
|
|
struct rtl_stats *pstatus)
|
|
{
|
|
/* NOTE: phystrpt may be NULL, and need to fill default value */
|
|
|
|
struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv);
|
|
struct rtl_efuse *rtlefuse = rtl_efuse(rtlpriv);
|
|
struct rtl_mac *mac = rtl_mac(rtlpriv);
|
|
struct dm_per_pkt_info pktinfo; /* input of pydm */
|
|
struct dm_phy_status_info phy_info; /* output of phydm */
|
|
__le16 fc = hdr->frame_control;
|
|
|
|
/* fill driver pstatus */
|
|
ether_addr_copy(pstatus->psaddr, ieee80211_get_SA(hdr));
|
|
|
|
/* fill pktinfo */
|
|
memset(&pktinfo, 0, sizeof(pktinfo));
|
|
|
|
pktinfo.data_rate = pstatus->rate;
|
|
|
|
if (rtlpriv->mac80211.opmode == NL80211_IFTYPE_STATION) {
|
|
pktinfo.station_id = 0;
|
|
} else {
|
|
/* TODO: use rtl_find_sta() to find ID */
|
|
pktinfo.station_id = 0xFF;
|
|
}
|
|
|
|
pktinfo.is_packet_match_bssid =
|
|
(!ieee80211_is_ctl(fc) &&
|
|
(ether_addr_equal(mac->bssid,
|
|
ieee80211_has_tods(fc) ?
|
|
hdr->addr1 :
|
|
ieee80211_has_fromds(fc) ?
|
|
hdr->addr2 :
|
|
hdr->addr3)) &&
|
|
(!pstatus->hwerror) && (!pstatus->crc) && (!pstatus->icv));
|
|
pktinfo.is_packet_to_self =
|
|
pktinfo.is_packet_match_bssid &&
|
|
(ether_addr_equal(hdr->addr1, rtlefuse->dev_addr));
|
|
pktinfo.is_to_self = (!pstatus->icv) && (!pstatus->crc) &&
|
|
(ether_addr_equal(hdr->addr1, rtlefuse->dev_addr));
|
|
pktinfo.is_packet_beacon = (ieee80211_is_beacon(fc) ? true : false);
|
|
|
|
/* query phy status */
|
|
if (phystrpt)
|
|
odm_phy_status_query(dm, &phy_info, phystrpt, &pktinfo);
|
|
else
|
|
memset(&phy_info, 0, sizeof(phy_info));
|
|
|
|
/* copy phy_info from phydm to driver */
|
|
pstatus->rx_pwdb_all = phy_info.rx_pwdb_all;
|
|
pstatus->bt_rx_rssi_percentage = phy_info.bt_rx_rssi_percentage;
|
|
pstatus->recvsignalpower = phy_info.recv_signal_power;
|
|
pstatus->signalquality = phy_info.signal_quality;
|
|
pstatus->rx_mimo_signalquality[0] = phy_info.rx_mimo_signal_quality[0];
|
|
pstatus->rx_mimo_signalquality[1] = phy_info.rx_mimo_signal_quality[1];
|
|
pstatus->rx_packet_bw =
|
|
phy_info.band_width; /* HT_CHANNEL_WIDTH_20 <- ODM_BW20M */
|
|
|
|
/* fill driver pstatus */
|
|
pstatus->packet_matchbssid = pktinfo.is_packet_match_bssid;
|
|
pstatus->packet_toself = pktinfo.is_packet_to_self;
|
|
pstatus->packet_beacon = pktinfo.is_packet_beacon;
|
|
|
|
return true;
|
|
}
|
|
|
|
static u8 rtl_phydm_rate_id_mapping(struct rtl_priv *rtlpriv,
|
|
enum wireless_mode wireless_mode,
|
|
enum rf_type rf_type,
|
|
enum ht_channel_width bw)
|
|
{
|
|
struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv);
|
|
|
|
return phydm_rate_id_mapping(dm, wireless_mode, rf_type, bw);
|
|
}
|
|
|
|
static bool rtl_phydm_get_ra_bitmap(struct rtl_priv *rtlpriv,
|
|
enum wireless_mode wireless_mode,
|
|
enum rf_type rf_type,
|
|
enum ht_channel_width bw,
|
|
u8 tx_rate_level, /* 0~6 */
|
|
u32 *tx_bitmap_msb,
|
|
u32 *tx_bitmap_lsb)
|
|
{
|
|
struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv);
|
|
const u8 mimo_ps_enable = 0;
|
|
const u8 disable_cck_rate = 0;
|
|
|
|
phydm_update_hal_ra_mask(dm, wireless_mode, rf_type, bw, mimo_ps_enable,
|
|
disable_cck_rate, tx_bitmap_msb, tx_bitmap_lsb,
|
|
tx_rate_level);
|
|
|
|
return true;
|
|
}
|
|
|
|
static u8 _rtl_phydm_get_macid(struct rtl_priv *rtlpriv,
|
|
struct ieee80211_sta *sta)
|
|
{
|
|
struct rtl_mac *mac = rtl_mac(rtlpriv);
|
|
|
|
if (mac->opmode == NL80211_IFTYPE_STATION ||
|
|
mac->opmode == NL80211_IFTYPE_MESH_POINT) {
|
|
return 0;
|
|
} else if (mac->opmode == NL80211_IFTYPE_AP ||
|
|
mac->opmode == NL80211_IFTYPE_ADHOC)
|
|
return sta->aid + 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static bool rtl_phydm_add_sta(struct rtl_priv *rtlpriv,
|
|
struct ieee80211_sta *sta)
|
|
{
|
|
struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv);
|
|
struct rtl_sta_info *sta_entry = (struct rtl_sta_info *)sta->drv_priv;
|
|
u8 mac_id = _rtl_phydm_get_macid(rtlpriv, sta);
|
|
|
|
odm_cmn_info_ptr_array_hook(dm, ODM_CMNINFO_STA_STATUS, mac_id,
|
|
sta_entry);
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool rtl_phydm_del_sta(struct rtl_priv *rtlpriv,
|
|
struct ieee80211_sta *sta)
|
|
{
|
|
struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv);
|
|
u8 mac_id = _rtl_phydm_get_macid(rtlpriv, sta);
|
|
|
|
odm_cmn_info_ptr_array_hook(dm, ODM_CMNINFO_STA_STATUS, mac_id, NULL);
|
|
|
|
return true;
|
|
}
|
|
|
|
static u32 rtl_phydm_get_version(struct rtl_priv *rtlpriv)
|
|
{
|
|
u32 ver = 0;
|
|
|
|
if (IS_HARDWARE_TYPE_8822B(rtlpriv))
|
|
ver = RELEASE_VERSION_8822B;
|
|
|
|
return ver;
|
|
}
|
|
|
|
static bool rtl_phydm_modify_ra_pcr_threshold(struct rtl_priv *rtlpriv,
|
|
u8 ra_offset_direction,
|
|
u8 ra_threshold_offset)
|
|
{
|
|
struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv);
|
|
|
|
phydm_modify_RA_PCR_threshold(dm, ra_offset_direction,
|
|
ra_threshold_offset);
|
|
|
|
return true;
|
|
}
|
|
|
|
static u32 rtl_phydm_query_counter(struct rtl_priv *rtlpriv,
|
|
const char *info_type)
|
|
{
|
|
struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv);
|
|
static const struct query_entry {
|
|
const char *query_name;
|
|
enum phydm_info_query query_id;
|
|
} query_table[] = {
|
|
#define QUERY_ENTRY(name) {#name, name}
|
|
QUERY_ENTRY(PHYDM_INFO_FA_OFDM),
|
|
QUERY_ENTRY(PHYDM_INFO_FA_CCK),
|
|
QUERY_ENTRY(PHYDM_INFO_CCA_OFDM),
|
|
QUERY_ENTRY(PHYDM_INFO_CCA_CCK),
|
|
QUERY_ENTRY(PHYDM_INFO_CRC32_OK_CCK),
|
|
QUERY_ENTRY(PHYDM_INFO_CRC32_OK_LEGACY),
|
|
QUERY_ENTRY(PHYDM_INFO_CRC32_OK_HT),
|
|
QUERY_ENTRY(PHYDM_INFO_CRC32_OK_VHT),
|
|
QUERY_ENTRY(PHYDM_INFO_CRC32_ERROR_CCK),
|
|
QUERY_ENTRY(PHYDM_INFO_CRC32_ERROR_LEGACY),
|
|
QUERY_ENTRY(PHYDM_INFO_CRC32_ERROR_HT),
|
|
QUERY_ENTRY(PHYDM_INFO_CRC32_ERROR_VHT),
|
|
};
|
|
#define QUERY_TABLE_SIZE ARRAY_SIZE(query_table)
|
|
|
|
int i;
|
|
const struct query_entry *entry;
|
|
|
|
if (!strcmp(info_type, "IQK_TOTAL"))
|
|
return dm->n_iqk_cnt;
|
|
|
|
if (!strcmp(info_type, "IQK_OK"))
|
|
return dm->n_iqk_ok_cnt;
|
|
|
|
if (!strcmp(info_type, "IQK_FAIL"))
|
|
return dm->n_iqk_fail_cnt;
|
|
|
|
for (i = 0; i < QUERY_TABLE_SIZE; i++) {
|
|
entry = &query_table[i];
|
|
|
|
if (!strcmp(info_type, entry->query_name))
|
|
return phydm_cmn_info_query(dm, entry->query_id);
|
|
}
|
|
|
|
pr_err("Unrecognized info_type:%s!!!!:\n", info_type);
|
|
|
|
return 0xDEADDEAD;
|
|
}
|
|
|
|
static bool rtl_phydm_debug_cmd(struct rtl_priv *rtlpriv, char *in, u32 in_len,
|
|
char *out, u32 out_len)
|
|
{
|
|
struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv);
|
|
|
|
phydm_cmd(dm, in, in_len, 1, out, out_len);
|
|
|
|
return true;
|
|
}
|
|
|
|
static struct rtl_phydm_ops rtl_phydm_operation = {
|
|
/* init/deinit priv */
|
|
.phydm_init_priv = rtl_phydm_init_priv,
|
|
.phydm_deinit_priv = rtl_phydm_deinit_priv,
|
|
.phydm_load_txpower_by_rate = rtl_phydm_load_txpower_by_rate,
|
|
.phydm_load_txpower_limit = rtl_phydm_load_txpower_limit,
|
|
|
|
/* init hw */
|
|
.phydm_init_dm = rtl_phydm_init_dm,
|
|
.phydm_deinit_dm = rtl_phydm_deinit_dm,
|
|
.phydm_reset_dm = rtl_phydm_reset_dm,
|
|
.phydm_parameter_init = rtl_phydm_parameter_init,
|
|
.phydm_phy_bb_config = rtl_phydm_phy_bb_config,
|
|
.phydm_phy_rf_config = rtl_phydm_phy_rf_config,
|
|
.phydm_phy_mac_config = rtl_phydm_phy_mac_config,
|
|
.phydm_trx_mode = rtl_phydm_trx_mode,
|
|
|
|
/* watchdog */
|
|
.phydm_watchdog = rtl_phydm_watchdog,
|
|
|
|
/* channel */
|
|
.phydm_switch_band = rtl_phydm_switch_band,
|
|
.phydm_switch_channel = rtl_phydm_switch_channel,
|
|
.phydm_switch_bandwidth = rtl_phydm_switch_bandwidth,
|
|
.phydm_iq_calibrate = rtl_phydm_iq_calibrate,
|
|
.phydm_clear_txpowertracking_state =
|
|
rtl_phydm_clear_txpowertracking_state,
|
|
.phydm_pause_dig = rtl_phydm_pause_dig,
|
|
|
|
/* read/write reg */
|
|
.phydm_read_rf_reg = rtl_phydm_read_rf_reg,
|
|
.phydm_write_rf_reg = rtl_phydm_write_rf_reg,
|
|
.phydm_read_txagc = rtl_phydm_read_txagc,
|
|
.phydm_write_txagc = rtl_phydm_write_txagc,
|
|
|
|
/* RX */
|
|
.phydm_c2h_content_parsing = rtl_phydm_c2h_content_parsing,
|
|
.phydm_query_phy_status = rtl_phydm_query_phy_status,
|
|
|
|
/* TX */
|
|
.phydm_rate_id_mapping = rtl_phydm_rate_id_mapping,
|
|
.phydm_get_ra_bitmap = rtl_phydm_get_ra_bitmap,
|
|
|
|
/* STA */
|
|
.phydm_add_sta = rtl_phydm_add_sta,
|
|
.phydm_del_sta = rtl_phydm_del_sta,
|
|
|
|
/* BTC */
|
|
.phydm_get_version = rtl_phydm_get_version,
|
|
.phydm_modify_ra_pcr_threshold = rtl_phydm_modify_ra_pcr_threshold,
|
|
.phydm_query_counter = rtl_phydm_query_counter,
|
|
|
|
/* debug */
|
|
.phydm_debug_cmd = rtl_phydm_debug_cmd,
|
|
};
|
|
|
|
struct rtl_phydm_ops *rtl_phydm_get_ops_pointer(void)
|
|
{
|
|
return &rtl_phydm_operation;
|
|
}
|
|
EXPORT_SYMBOL(rtl_phydm_get_ops_pointer);
|
|
|
|
/* ********************************************************
|
|
* Define phydm callout function in below
|
|
* ********************************************************
|
|
*/
|
|
|
|
u8 phy_get_tx_power_index(void *adapter, u8 rf_path, u8 rate,
|
|
enum ht_channel_width bandwidth, u8 channel)
|
|
{
|
|
/* rate: DESC_RATE1M */
|
|
struct rtl_priv *rtlpriv = (struct rtl_priv *)adapter;
|
|
|
|
return rtlpriv->cfg->ops->get_txpower_index(rtlpriv->hw, rf_path, rate,
|
|
bandwidth, channel);
|
|
}
|
|
|
|
void phy_set_tx_power_index_by_rs(void *adapter, u8 ch, u8 path, u8 rs)
|
|
{
|
|
struct rtl_priv *rtlpriv = (struct rtl_priv *)adapter;
|
|
|
|
return rtlpriv->cfg->ops->set_tx_power_index_by_rs(rtlpriv->hw, ch,
|
|
path, rs);
|
|
}
|
|
|
|
void phy_store_tx_power_by_rate(void *adapter, u32 band, u32 rfpath, u32 txnum,
|
|
u32 regaddr, u32 bitmask, u32 data)
|
|
{
|
|
struct rtl_priv *rtlpriv = (struct rtl_priv *)adapter;
|
|
|
|
rtlpriv->cfg->ops->store_tx_power_by_rate(
|
|
rtlpriv->hw, band, rfpath, txnum, regaddr, bitmask, data);
|
|
}
|
|
|
|
void phy_set_tx_power_limit(void *dm, u8 *regulation, u8 *band, u8 *bandwidth,
|
|
u8 *rate_section, u8 *rf_path, u8 *channel,
|
|
u8 *power_limit)
|
|
{
|
|
struct rtl_priv *rtlpriv =
|
|
(struct rtl_priv *)((struct phy_dm_struct *)dm)->adapter;
|
|
|
|
rtlpriv->cfg->ops->phy_set_txpower_limit(rtlpriv->hw, regulation, band,
|
|
bandwidth, rate_section,
|
|
rf_path, channel, power_limit);
|
|
}
|
|
|
|
void rtl_hal_update_ra_mask(void *adapter, struct rtl_sta_info *psta,
|
|
u8 rssi_level)
|
|
{
|
|
struct rtl_priv *rtlpriv = (struct rtl_priv *)adapter;
|
|
struct ieee80211_sta *sta =
|
|
container_of((void *)psta, struct ieee80211_sta, drv_priv);
|
|
|
|
rtlpriv->cfg->ops->update_rate_tbl(rtlpriv->hw, sta, rssi_level, false);
|
|
}
|
|
|
|
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");
|