360 lines · c
1// SPDX-License-Identifier: GPL-2.02/* Copyright(c) 2009-2012 Realtek Corporation.*/3 4#include "../wifi.h"5#include "def.h"6#include "reg.h"7#include "phy_common.h"8#include "rf_common.h"9 10void rtl92d_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw, u8 bandwidth)11{12 struct rtl_priv *rtlpriv = rtl_priv(hw);13 struct rtl_phy *rtlphy = &rtlpriv->phy;14 u8 rfpath;15 16 switch (bandwidth) {17 case HT_CHANNEL_WIDTH_20:18 for (rfpath = 0; rfpath < rtlphy->num_total_rfpath; rfpath++) {19 rtlphy->rfreg_chnlval[rfpath] &= 0xfffff3ff;20 rtlphy->rfreg_chnlval[rfpath] |= 0x0400;21 22 rtl_set_rfreg(hw, rfpath, RF_CHNLBW,23 BIT(10) | BIT(11), 0x01);24 25 rtl_dbg(rtlpriv, COMP_RF, DBG_LOUD,26 "20M RF 0x18 = 0x%x\n",27 rtlphy->rfreg_chnlval[rfpath]);28 }29 30 break;31 case HT_CHANNEL_WIDTH_20_40:32 for (rfpath = 0; rfpath < rtlphy->num_total_rfpath; rfpath++) {33 rtlphy->rfreg_chnlval[rfpath] &= 0xfffff3ff;34 35 rtl_set_rfreg(hw, rfpath, RF_CHNLBW,36 BIT(10) | BIT(11), 0x00);37 38 rtl_dbg(rtlpriv, COMP_RF, DBG_LOUD,39 "40M RF 0x18 = 0x%x\n",40 rtlphy->rfreg_chnlval[rfpath]);41 }42 break;43 default:44 pr_err("unknown bandwidth: %#X\n", bandwidth);45 break;46 }47}48EXPORT_SYMBOL_GPL(rtl92d_phy_rf6052_set_bandwidth);49 50void rtl92d_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw,51 u8 *ppowerlevel)52{53 struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));54 struct rtl_mac *mac = rtl_mac(rtl_priv(hw));55 struct rtl_priv *rtlpriv = rtl_priv(hw);56 struct rtl_phy *rtlphy = &rtlpriv->phy;57 u32 tx_agc[2] = {0, 0}, tmpval;58 bool turbo_scanoff = false;59 u8 idx1, idx2;60 u8 *ptr;61 62 if (rtlefuse->eeprom_regulatory != 0)63 turbo_scanoff = true;64 if (mac->act_scanning) {65 tx_agc[RF90_PATH_A] = 0x3f3f3f3f;66 tx_agc[RF90_PATH_B] = 0x3f3f3f3f;67 if (turbo_scanoff) {68 for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B; idx1++) {69 tx_agc[idx1] = ppowerlevel[idx1] |70 (ppowerlevel[idx1] << 8) |71 (ppowerlevel[idx1] << 16) |72 (ppowerlevel[idx1] << 24);73 }74 }75 } else {76 for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B; idx1++) {77 tx_agc[idx1] = ppowerlevel[idx1] |78 (ppowerlevel[idx1] << 8) |79 (ppowerlevel[idx1] << 16) |80 (ppowerlevel[idx1] << 24);81 }82 if (rtlefuse->eeprom_regulatory == 0) {83 tmpval = (rtlphy->mcs_offset[0][6]) +84 (rtlphy->mcs_offset[0][7] << 8);85 tx_agc[RF90_PATH_A] += tmpval;86 tmpval = (rtlphy->mcs_offset[0][14]) +87 (rtlphy->mcs_offset[0][15] << 24);88 tx_agc[RF90_PATH_B] += tmpval;89 }90 }91 92 for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B; idx1++) {93 ptr = (u8 *)(&tx_agc[idx1]);94 for (idx2 = 0; idx2 < 4; idx2++) {95 if (*ptr > RF6052_MAX_TX_PWR)96 *ptr = RF6052_MAX_TX_PWR;97 ptr++;98 }99 }100 101 tmpval = tx_agc[RF90_PATH_A] & 0xff;102 rtl_set_bbreg(hw, RTXAGC_A_CCK1_MCS32, MASKBYTE1, tmpval);103 RTPRINT(rtlpriv, FPHY, PHY_TXPWR,104 "CCK PWR 1M (rf-A) = 0x%x (reg 0x%x)\n",105 tmpval, RTXAGC_A_CCK1_MCS32);106 tmpval = tx_agc[RF90_PATH_A] >> 8;107 rtl_set_bbreg(hw, RTXAGC_B_CCK11_A_CCK2_11, 0xffffff00, tmpval);108 RTPRINT(rtlpriv, FPHY, PHY_TXPWR,109 "CCK PWR 2~11M (rf-A) = 0x%x (reg 0x%x)\n",110 tmpval, RTXAGC_B_CCK11_A_CCK2_11);111 tmpval = tx_agc[RF90_PATH_B] >> 24;112 rtl_set_bbreg(hw, RTXAGC_B_CCK11_A_CCK2_11, MASKBYTE0, tmpval);113 RTPRINT(rtlpriv, FPHY, PHY_TXPWR,114 "CCK PWR 11M (rf-B) = 0x%x (reg 0x%x)\n",115 tmpval, RTXAGC_B_CCK11_A_CCK2_11);116 tmpval = tx_agc[RF90_PATH_B] & 0x00ffffff;117 rtl_set_bbreg(hw, RTXAGC_B_CCK1_55_MCS32, 0xffffff00, tmpval);118 RTPRINT(rtlpriv, FPHY, PHY_TXPWR,119 "CCK PWR 1~5.5M (rf-B) = 0x%x (reg 0x%x)\n",120 tmpval, RTXAGC_B_CCK1_55_MCS32);121}122EXPORT_SYMBOL_GPL(rtl92d_phy_rf6052_set_cck_txpower);123 124static void _rtl92d_phy_get_power_base(struct ieee80211_hw *hw,125 u8 *ppowerlevel, u8 channel,126 u32 *ofdmbase, u32 *mcsbase)127{128 struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));129 struct rtl_priv *rtlpriv = rtl_priv(hw);130 struct rtl_phy *rtlphy = &rtlpriv->phy;131 u32 powerbase0, powerbase1;132 u8 legacy_pwrdiff, ht20_pwrdiff;133 u8 i, powerlevel[2];134 135 for (i = 0; i < 2; i++) {136 powerlevel[i] = ppowerlevel[i];137 legacy_pwrdiff = rtlefuse->txpwr_legacyhtdiff[i][channel - 1];138 powerbase0 = powerlevel[i] + legacy_pwrdiff;139 powerbase0 = (powerbase0 << 24) | (powerbase0 << 16) |140 (powerbase0 << 8) | powerbase0;141 *(ofdmbase + i) = powerbase0;142 RTPRINT(rtlpriv, FPHY, PHY_TXPWR,143 " [OFDM power base index rf(%c) = 0x%x]\n",144 i == 0 ? 'A' : 'B', *(ofdmbase + i));145 }146 147 for (i = 0; i < 2; i++) {148 if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20) {149 ht20_pwrdiff = rtlefuse->txpwr_ht20diff[i][channel - 1];150 powerlevel[i] += ht20_pwrdiff;151 }152 powerbase1 = powerlevel[i];153 powerbase1 = (powerbase1 << 24) | (powerbase1 << 16) |154 (powerbase1 << 8) | powerbase1;155 *(mcsbase + i) = powerbase1;156 RTPRINT(rtlpriv, FPHY, PHY_TXPWR,157 " [MCS power base index rf(%c) = 0x%x]\n",158 i == 0 ? 'A' : 'B', *(mcsbase + i));159 }160}161 162static void _rtl92d_get_pwr_diff_limit(struct ieee80211_hw *hw, u8 channel,163 u8 index, u8 rf, u8 pwr_diff_limit[4])164{165 struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));166 struct rtl_priv *rtlpriv = rtl_priv(hw);167 struct rtl_phy *rtlphy = &rtlpriv->phy;168 u32 mcs_offset;169 u8 limit;170 int i;171 172 mcs_offset = rtlphy->mcs_offset[0][index + (rf ? 8 : 0)];173 174 for (i = 0; i < 4; i++) {175 pwr_diff_limit[i] = (mcs_offset >> (i * 8)) & 0x7f;176 177 if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40)178 limit = rtlefuse->pwrgroup_ht40[rf][channel - 1];179 else180 limit = rtlefuse->pwrgroup_ht20[rf][channel - 1];181 182 if (pwr_diff_limit[i] > limit)183 pwr_diff_limit[i] = limit;184 }185}186 187static void _rtl92d_get_txpower_writeval_by_regulatory(struct ieee80211_hw *hw,188 u8 channel, u8 index,189 u32 *powerbase0,190 u32 *powerbase1,191 u32 *p_outwriteval)192{193 struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));194 struct rtl_priv *rtlpriv = rtl_priv(hw);195 struct rtl_phy *rtlphy = &rtlpriv->phy;196 u32 writeval = 0, customer_limit, rf;197 u8 chnlgroup = 0, pwr_diff_limit[4];198 199 for (rf = 0; rf < 2; rf++) {200 switch (rtlefuse->eeprom_regulatory) {201 case 0:202 writeval = rtlphy->mcs_offset[0][index + (rf ? 8 : 0)];203 204 RTPRINT(rtlpriv, FPHY, PHY_TXPWR,205 "RTK better performance\n");206 break;207 case 1:208 if (rtlphy->pwrgroup_cnt == 1)209 chnlgroup = 0;210 211 if (rtlphy->pwrgroup_cnt < MAX_PG_GROUP)212 break;213 214 chnlgroup = rtl92d_phy_get_chnlgroup_bypg(channel - 1);215 if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20)216 chnlgroup++;217 else218 chnlgroup += 4;219 220 writeval = rtlphy->mcs_offset221 [chnlgroup][index + (rf ? 8 : 0)];222 223 RTPRINT(rtlpriv, FPHY, PHY_TXPWR,224 "Realtek regulatory, 20MHz\n");225 break;226 case 2:227 writeval = 0;228 229 RTPRINT(rtlpriv, FPHY, PHY_TXPWR, "Better regulatory\n");230 break;231 case 3:232 if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) {233 RTPRINT(rtlpriv, FPHY, PHY_TXPWR,234 "customer's limit, 40MHz rf(%c) = 0x%x\n",235 rf == 0 ? 'A' : 'B',236 rtlefuse->pwrgroup_ht40[rf][channel - 1]);237 } else {238 RTPRINT(rtlpriv, FPHY, PHY_TXPWR,239 "customer's limit, 20MHz rf(%c) = 0x%x\n",240 rf == 0 ? 'A' : 'B',241 rtlefuse->pwrgroup_ht20[rf][channel - 1]);242 }243 244 _rtl92d_get_pwr_diff_limit(hw, channel, index, rf,245 pwr_diff_limit);246 247 customer_limit = (pwr_diff_limit[3] << 24) |248 (pwr_diff_limit[2] << 16) |249 (pwr_diff_limit[1] << 8) |250 (pwr_diff_limit[0]);251 252 RTPRINT(rtlpriv, FPHY, PHY_TXPWR,253 "Customer's limit rf(%c) = 0x%x\n",254 rf == 0 ? 'A' : 'B', customer_limit);255 256 writeval = customer_limit;257 258 RTPRINT(rtlpriv, FPHY, PHY_TXPWR, "Customer\n");259 break;260 default:261 writeval = rtlphy->mcs_offset[0][index + (rf ? 8 : 0)];262 263 RTPRINT(rtlpriv, FPHY, PHY_TXPWR,264 "RTK better performance\n");265 break;266 }267 268 if (index < 2)269 writeval += powerbase0[rf];270 else271 writeval += powerbase1[rf];272 273 RTPRINT(rtlpriv, FPHY, PHY_TXPWR, "writeval rf(%c)= 0x%x\n",274 rf == 0 ? 'A' : 'B', writeval);275 276 *(p_outwriteval + rf) = writeval;277 }278}279 280static void _rtl92d_write_ofdm_power_reg(struct ieee80211_hw *hw,281 u8 index, u32 *pvalue)282{283 struct rtl_priv *rtlpriv = rtl_priv(hw);284 struct rtl_phy *rtlphy = &rtlpriv->phy;285 static const u16 regoffset_a[6] = {286 RTXAGC_A_RATE18_06, RTXAGC_A_RATE54_24,287 RTXAGC_A_MCS03_MCS00, RTXAGC_A_MCS07_MCS04,288 RTXAGC_A_MCS11_MCS08, RTXAGC_A_MCS15_MCS12289 };290 static const u16 regoffset_b[6] = {291 RTXAGC_B_RATE18_06, RTXAGC_B_RATE54_24,292 RTXAGC_B_MCS03_MCS00, RTXAGC_B_MCS07_MCS04,293 RTXAGC_B_MCS11_MCS08, RTXAGC_B_MCS15_MCS12294 };295 u8 i, rf, pwr_val[4];296 u32 writeval;297 u16 regoffset;298 299 for (rf = 0; rf < 2; rf++) {300 writeval = pvalue[rf];301 for (i = 0; i < 4; i++) {302 pwr_val[i] = (u8)((writeval & (0x7f <<303 (i * 8))) >> (i * 8));304 if (pwr_val[i] > RF6052_MAX_TX_PWR)305 pwr_val[i] = RF6052_MAX_TX_PWR;306 }307 writeval = (pwr_val[3] << 24) | (pwr_val[2] << 16) |308 (pwr_val[1] << 8) | pwr_val[0];309 if (rf == 0)310 regoffset = regoffset_a[index];311 else312 regoffset = regoffset_b[index];313 rtl_set_bbreg(hw, regoffset, MASKDWORD, writeval);314 RTPRINT(rtlpriv, FPHY, PHY_TXPWR,315 "Set 0x%x = %08x\n", regoffset, writeval);316 if (((get_rf_type(rtlphy) == RF_2T2R) &&317 (regoffset == RTXAGC_A_MCS15_MCS12 ||318 regoffset == RTXAGC_B_MCS15_MCS12)) ||319 ((get_rf_type(rtlphy) != RF_2T2R) &&320 (regoffset == RTXAGC_A_MCS07_MCS04 ||321 regoffset == RTXAGC_B_MCS07_MCS04))) {322 writeval = pwr_val[3];323 if (regoffset == RTXAGC_A_MCS15_MCS12 ||324 regoffset == RTXAGC_A_MCS07_MCS04)325 regoffset = 0xc90;326 if (regoffset == RTXAGC_B_MCS15_MCS12 ||327 regoffset == RTXAGC_B_MCS07_MCS04)328 regoffset = 0xc98;329 for (i = 0; i < 3; i++) {330 if (i != 2)331 writeval = (writeval > 8) ?332 (writeval - 8) : 0;333 else334 writeval = (writeval > 6) ?335 (writeval - 6) : 0;336 rtl_write_byte(rtlpriv, (u32)(regoffset + i),337 (u8)writeval);338 }339 }340 }341}342 343void rtl92d_phy_rf6052_set_ofdm_txpower(struct ieee80211_hw *hw,344 u8 *ppowerlevel, u8 channel)345{346 u32 writeval[2], powerbase0[2], powerbase1[2];347 u8 index;348 349 _rtl92d_phy_get_power_base(hw, ppowerlevel, channel,350 &powerbase0[0], &powerbase1[0]);351 for (index = 0; index < 6; index++) {352 _rtl92d_get_txpower_writeval_by_regulatory(hw, channel, index,353 &powerbase0[0],354 &powerbase1[0],355 &writeval[0]);356 _rtl92d_write_ofdm_power_reg(hw, index, &writeval[0]);357 }358}359EXPORT_SYMBOL_GPL(rtl92d_phy_rf6052_set_ofdm_txpower);360