From 57f0f512b273f60d52568b8c6b77e17f5636edc0 Mon Sep 17 00:00:00 2001 From: André Fabian Silva Delgado Date: Wed, 5 Aug 2015 17:04:01 -0300 Subject: Initial import --- drivers/staging/rtl8188eu/hal/rf.c | 318 +++++++++++++++++++++++++++++++++++++ 1 file changed, 318 insertions(+) create mode 100644 drivers/staging/rtl8188eu/hal/rf.c (limited to 'drivers/staging/rtl8188eu/hal/rf.c') diff --git a/drivers/staging/rtl8188eu/hal/rf.c b/drivers/staging/rtl8188eu/hal/rf.c new file mode 100644 index 000000000..097092772 --- /dev/null +++ b/drivers/staging/rtl8188eu/hal/rf.c @@ -0,0 +1,318 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * 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 + * + ******************************************************************************/ + +#include +#include +#include +#include +#include + +void rtl88eu_phy_rf6052_set_bandwidth(struct adapter *adapt, + enum ht_channel_width bandwidth) +{ + struct hal_data_8188e *hal_data = GET_HAL_DATA(adapt); + + switch (bandwidth) { + case HT_CHANNEL_WIDTH_20: + hal_data->RfRegChnlVal[0] = ((hal_data->RfRegChnlVal[0] & + 0xfffff3ff) | BIT(10) | BIT(11)); + phy_set_rf_reg(adapt, RF_PATH_A, RF_CHNLBW, bRFRegOffsetMask, + hal_data->RfRegChnlVal[0]); + break; + case HT_CHANNEL_WIDTH_40: + hal_data->RfRegChnlVal[0] = ((hal_data->RfRegChnlVal[0] & + 0xfffff3ff) | BIT(10)); + phy_set_rf_reg(adapt, RF_PATH_A, RF_CHNLBW, bRFRegOffsetMask, + hal_data->RfRegChnlVal[0]); + break; + default: + break; + } +} + +void rtl88eu_phy_rf6052_set_cck_txpower(struct adapter *adapt, u8 *powerlevel) +{ + struct hal_data_8188e *hal_data = GET_HAL_DATA(adapt); + struct dm_priv *pdmpriv = &hal_data->dmpriv; + struct mlme_ext_priv *pmlmeext = &adapt->mlmeextpriv; + u32 tx_agc[2] = {0, 0}, tmpval = 0, pwrtrac_value; + u8 idx1, idx2; + u8 *ptr; + u8 direction; + + + if (pmlmeext->sitesurvey_res.state == SCAN_PROCESS) { + tx_agc[RF_PATH_A] = 0x3f3f3f3f; + tx_agc[RF_PATH_B] = 0x3f3f3f3f; + for (idx1 = RF_PATH_A; idx1 <= RF_PATH_B; idx1++) { + tx_agc[idx1] = powerlevel[idx1] | + (powerlevel[idx1]<<8) | + (powerlevel[idx1]<<16) | + (powerlevel[idx1]<<24); + if (tx_agc[idx1] > 0x20 && hal_data->ExternalPA) + tx_agc[idx1] = 0x20; + } + } else { + if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_Level1) { + tx_agc[RF_PATH_A] = 0x10101010; + tx_agc[RF_PATH_B] = 0x10101010; + } else if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_Level2) { + tx_agc[RF_PATH_A] = 0x00000000; + tx_agc[RF_PATH_B] = 0x00000000; + } else { + for (idx1 = RF_PATH_A; idx1 <= RF_PATH_B; idx1++) { + tx_agc[idx1] = powerlevel[idx1] | + (powerlevel[idx1]<<8) | + (powerlevel[idx1]<<16) | + (powerlevel[idx1]<<24); + } + if (hal_data->EEPROMRegulatory == 0) { + tmpval = hal_data->MCSTxPowerLevelOriginalOffset[0][6] + + (hal_data->MCSTxPowerLevelOriginalOffset[0][7]<<8); + tx_agc[RF_PATH_A] += tmpval; + + tmpval = hal_data->MCSTxPowerLevelOriginalOffset[0][14] + + (hal_data->MCSTxPowerLevelOriginalOffset[0][15]<<24); + tx_agc[RF_PATH_B] += tmpval; + } + } + } + for (idx1 = RF_PATH_A; idx1 <= RF_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++; + } + } + rtl88eu_dm_txpower_track_adjust(&hal_data->odmpriv, 1, &direction, + &pwrtrac_value); + + if (direction == 1) { + /* Increase TX power */ + tx_agc[0] += pwrtrac_value; + tx_agc[1] += pwrtrac_value; + } else if (direction == 2) { + /* Decrease TX power */ + tx_agc[0] -= pwrtrac_value; + tx_agc[1] -= pwrtrac_value; + } + + /* rf-A cck tx power */ + tmpval = tx_agc[RF_PATH_A]&0xff; + phy_set_bb_reg(adapt, rTxAGC_A_CCK1_Mcs32, bMaskByte1, tmpval); + tmpval = tx_agc[RF_PATH_A]>>8; + phy_set_bb_reg(adapt, rTxAGC_B_CCK11_A_CCK2_11, 0xffffff00, tmpval); + + /* rf-B cck tx power */ + tmpval = tx_agc[RF_PATH_B]>>24; + phy_set_bb_reg(adapt, rTxAGC_B_CCK11_A_CCK2_11, bMaskByte0, tmpval); + tmpval = tx_agc[RF_PATH_B]&0x00ffffff; + phy_set_bb_reg(adapt, rTxAGC_B_CCK1_55_Mcs32, 0xffffff00, tmpval); +} + +/* powerbase0 for OFDM rates */ +/* powerbase1 for HT MCS rates */ +static void getpowerbase88e(struct adapter *adapt, u8 *pwr_level_ofdm, + u8 *pwr_level_bw20, u8 *pwr_level_bw40, + u8 channel, u32 *ofdmbase, u32 *mcs_base) +{ + struct hal_data_8188e *hal_data = GET_HAL_DATA(adapt); + u32 powerbase0, powerbase1; + u8 i, powerlevel[2]; + + for (i = 0; i < 2; i++) { + powerbase0 = pwr_level_ofdm[i]; + + powerbase0 = (powerbase0<<24) | (powerbase0<<16) | + (powerbase0<<8) | powerbase0; + *(ofdmbase+i) = powerbase0; + } + for (i = 0; i < hal_data->NumTotalRFPath; i++) { + /* Check HT20 to HT40 diff */ + if (hal_data->CurrentChannelBW == HT_CHANNEL_WIDTH_20) + powerlevel[i] = pwr_level_bw20[i]; + else + powerlevel[i] = pwr_level_bw40[i]; + powerbase1 = powerlevel[i]; + powerbase1 = (powerbase1<<24) | (powerbase1<<16) | + (powerbase1<<8) | powerbase1; + *(mcs_base+i) = powerbase1; + } +} +static void get_rx_power_val_by_reg(struct adapter *adapt, u8 channel, + u8 index, u32 *powerbase0, u32 *powerbase1, + u32 *out_val) +{ + struct hal_data_8188e *hal_data = GET_HAL_DATA(adapt); + struct dm_priv *pdmpriv = &hal_data->dmpriv; + u8 i, chnlGroup = 0, pwr_diff_limit[4], customer_pwr_limit; + s8 pwr_diff = 0; + u32 write_val, customer_limit, rf; + u8 regulatory = hal_data->EEPROMRegulatory; + + /* Index 0 & 1= legacy OFDM, 2-5=HT_MCS rate */ + + for (rf = 0; rf < 2; rf++) { + u8 j = index + (rf ? 8 : 0); + + switch (regulatory) { + case 0: + chnlGroup = 0; + write_val = hal_data->MCSTxPowerLevelOriginalOffset[chnlGroup][index+(rf ? 8 : 0)] + + ((index < 2) ? powerbase0[rf] : powerbase1[rf]); + break; + case 1: /* Realtek regulatory */ + /* increase power diff defined by Realtek for regulatory */ + if (hal_data->pwrGroupCnt == 1) + chnlGroup = 0; + if (hal_data->pwrGroupCnt >= hal_data->PGMaxGroup) { + if (channel < 3) + chnlGroup = 0; + else if (channel < 6) + chnlGroup = 1; + else if (channel < 9) + chnlGroup = 2; + else if (channel < 12) + chnlGroup = 3; + else if (channel < 14) + chnlGroup = 4; + else if (channel == 14) + chnlGroup = 5; + } + write_val = hal_data->MCSTxPowerLevelOriginalOffset[chnlGroup][index+(rf ? 8 : 0)] + + ((index < 2) ? powerbase0[rf] : powerbase1[rf]); + break; + case 2: /* Better regulatory */ + /* don't increase any power diff */ + write_val = (index < 2) ? powerbase0[rf] : powerbase1[rf]; + break; + case 3: /* Customer defined power diff. */ + /* increase power diff defined by customer. */ + chnlGroup = 0; + + if (index < 2) + pwr_diff = hal_data->TxPwrLegacyHtDiff[rf][channel-1]; + else if (hal_data->CurrentChannelBW == HT_CHANNEL_WIDTH_20) + pwr_diff = hal_data->TxPwrHt20Diff[rf][channel-1]; + + if (hal_data->CurrentChannelBW == HT_CHANNEL_WIDTH_40) + customer_pwr_limit = hal_data->PwrGroupHT40[rf][channel-1]; + else + customer_pwr_limit = hal_data->PwrGroupHT20[rf][channel-1]; + + if (pwr_diff >= customer_pwr_limit) + pwr_diff = 0; + else + pwr_diff = customer_pwr_limit - pwr_diff; + + for (i = 0; i < 4; i++) { + pwr_diff_limit[i] = (u8)((hal_data->MCSTxPowerLevelOriginalOffset[chnlGroup][j] & + (0x7f << (i * 8))) >> (i * 8)); + + if (pwr_diff_limit[i] > pwr_diff) + pwr_diff_limit[i] = pwr_diff; + } + customer_limit = (pwr_diff_limit[3]<<24) | + (pwr_diff_limit[2]<<16) | + (pwr_diff_limit[1]<<8) | + (pwr_diff_limit[0]); + write_val = customer_limit + ((index < 2) ? powerbase0[rf] : powerbase1[rf]); + break; + default: + chnlGroup = 0; + write_val = hal_data->MCSTxPowerLevelOriginalOffset[chnlGroup][j] + + ((index < 2) ? powerbase0[rf] : powerbase1[rf]); + break; + } +/* 20100427 Joseph: Driver dynamic Tx power shall not affect Tx power. It shall be determined by power training mechanism. */ +/* Currently, we cannot fully disable driver dynamic tx power mechanism because it is referenced by BT coexist mechanism. */ +/* In the future, two mechanism shall be separated from each other and maintained independently. Thanks for Lanhsin's reminder. */ + /* 92d do not need this */ + if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_Level1) + write_val = 0x14141414; + else if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_Level2) + write_val = 0x00000000; + + *(out_val+rf) = write_val; + } +} + +static void write_ofdm_pwr_reg(struct adapter *adapt, u8 index, u32 *pvalue) +{ + 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 write_val; + u16 regoffset; + + for (rf = 0; rf < 2; rf++) { + write_val = pvalue[rf]; + for (i = 0; i < 4; i++) { + pwr_val[i] = (u8)((write_val & (0x7f<<(i*8)))>>(i*8)); + if (pwr_val[i] > RF6052_MAX_TX_PWR) + pwr_val[i] = RF6052_MAX_TX_PWR; + } + write_val = (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]; + + phy_set_bb_reg(adapt, regoffset, bMaskDWord, write_val); + } +} + +void rtl88eu_phy_rf6052_set_ofdm_txpower(struct adapter *adapt, + u8 *pwr_level_ofdm, + u8 *pwr_level_bw20, + u8 *pwr_level_bw40, u8 channel) +{ + struct hal_data_8188e *hal_data = GET_HAL_DATA(adapt); + u32 write_val[2], powerbase0[2], powerbase1[2], pwrtrac_value; + u8 direction; + u8 index = 0; + + getpowerbase88e(adapt, pwr_level_ofdm, pwr_level_bw20, pwr_level_bw40, + channel, &powerbase0[0], &powerbase1[0]); + + rtl88eu_dm_txpower_track_adjust(&hal_data->odmpriv, 0, &direction, + &pwrtrac_value); + + for (index = 0; index < 6; index++) { + get_rx_power_val_by_reg(adapt, channel, index, + &powerbase0[0], &powerbase1[0], + &write_val[0]); + + if (direction == 1) { + write_val[0] += pwrtrac_value; + write_val[1] += pwrtrac_value; + } else if (direction == 2) { + write_val[0] -= pwrtrac_value; + write_val[1] -= pwrtrac_value; + } + write_ofdm_pwr_reg(adapt, index, &write_val[0]); + } +} -- cgit v1.2.3-54-g00ecf