root/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/rf.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. rtl8821ae_phy_rf6052_set_bandwidth
  2. rtl8821ae_phy_rf6052_set_cck_txpower
  3. rtl8821ae_phy_get_power_base
  4. get_txpower_writeval_by_regulatory
  5. _rtl8821ae_write_ofdm_power_reg
  6. rtl8821ae_phy_rf6052_set_ofdm_txpower
  7. rtl8821ae_phy_rf6052_config
  8. _rtl8821ae_phy_rf6052_config_parafile

   1 // SPDX-License-Identifier: GPL-2.0
   2 /* Copyright(c) 2009-2010  Realtek Corporation.*/
   3 
   4 #include "../wifi.h"
   5 #include "reg.h"
   6 #include "def.h"
   7 #include "phy.h"
   8 #include "rf.h"
   9 #include "dm.h"
  10 
  11 static bool _rtl8821ae_phy_rf6052_config_parafile(struct ieee80211_hw *hw);
  12 
  13 void rtl8821ae_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw, u8 bandwidth)
  14 {
  15         switch (bandwidth) {
  16         case HT_CHANNEL_WIDTH_20:
  17                 rtl_set_rfreg(hw, RF90_PATH_A, RF_CHNLBW, BIT(11)|BIT(10), 3);
  18                 rtl_set_rfreg(hw, RF90_PATH_B, RF_CHNLBW, BIT(11)|BIT(10), 3);
  19                 break;
  20         case HT_CHANNEL_WIDTH_20_40:
  21                 rtl_set_rfreg(hw, RF90_PATH_A, RF_CHNLBW, BIT(11)|BIT(10), 1);
  22                 rtl_set_rfreg(hw, RF90_PATH_B, RF_CHNLBW, BIT(11)|BIT(10), 1);
  23                 break;
  24         case HT_CHANNEL_WIDTH_80:
  25                 rtl_set_rfreg(hw, RF90_PATH_A, RF_CHNLBW, BIT(11)|BIT(10), 0);
  26                 rtl_set_rfreg(hw, RF90_PATH_B, RF_CHNLBW, BIT(11)|BIT(10), 0);
  27                 break;
  28         default:
  29                 pr_err("unknown bandwidth: %#X\n", bandwidth);
  30                 break;
  31         }
  32 }
  33 
  34 void rtl8821ae_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw,
  35                                           u8 *ppowerlevel)
  36 {
  37         struct rtl_priv *rtlpriv = rtl_priv(hw);
  38         struct rtl_phy *rtlphy = &rtlpriv->phy;
  39         struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
  40         struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
  41         u32 tx_agc[2] = {0, 0}, tmpval;
  42         bool turbo_scanoff = false;
  43         u8 idx1, idx2;
  44         u8 *ptr;
  45         u8 direction;
  46         u32 pwrtrac_value;
  47 
  48         if (rtlefuse->eeprom_regulatory != 0)
  49                 turbo_scanoff = true;
  50 
  51         if (mac->act_scanning) {
  52                 tx_agc[RF90_PATH_A] = 0x3f3f3f3f;
  53                 tx_agc[RF90_PATH_B] = 0x3f3f3f3f;
  54 
  55                 if (turbo_scanoff) {
  56                         for (idx1 = RF90_PATH_A;
  57                                 idx1 <= RF90_PATH_B;
  58                                 idx1++) {
  59                                 tx_agc[idx1] = ppowerlevel[idx1] |
  60                                     (ppowerlevel[idx1] << 8) |
  61                                     (ppowerlevel[idx1] << 16) |
  62                                     (ppowerlevel[idx1] << 24);
  63                         }
  64                 }
  65         } else {
  66                 for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B; idx1++) {
  67                         tx_agc[idx1] = ppowerlevel[idx1] |
  68                             (ppowerlevel[idx1] << 8) |
  69                             (ppowerlevel[idx1] << 16) |
  70                             (ppowerlevel[idx1] << 24);
  71                 }
  72 
  73                 if (rtlefuse->eeprom_regulatory == 0) {
  74                         tmpval =
  75                             (rtlphy->mcs_txpwrlevel_origoffset[0][6]) +
  76                             (rtlphy->mcs_txpwrlevel_origoffset[0][7] <<
  77                              8);
  78                         tx_agc[RF90_PATH_A] += tmpval;
  79 
  80                         tmpval = (rtlphy->mcs_txpwrlevel_origoffset[0][14]) +
  81                             (rtlphy->mcs_txpwrlevel_origoffset[0][15] <<
  82                              24);
  83                         tx_agc[RF90_PATH_B] += tmpval;
  84                 }
  85         }
  86 
  87         for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B; idx1++) {
  88                 ptr = (u8 *)(&tx_agc[idx1]);
  89                 for (idx2 = 0; idx2 < 4; idx2++) {
  90                         if (*ptr > RF6052_MAX_TX_PWR)
  91                                 *ptr = RF6052_MAX_TX_PWR;
  92                         ptr++;
  93                 }
  94         }
  95         rtl8821ae_dm_txpower_track_adjust(hw, 1, &direction, &pwrtrac_value);
  96         if (direction == 1) {
  97                 tx_agc[0] += pwrtrac_value;
  98                 tx_agc[1] += pwrtrac_value;
  99         } else if (direction == 2) {
 100                 tx_agc[0] -= pwrtrac_value;
 101                 tx_agc[1] -= pwrtrac_value;
 102         }
 103         tmpval = tx_agc[RF90_PATH_A];
 104         rtl_set_bbreg(hw, RTXAGC_A_CCK11_CCK1, MASKDWORD, tmpval);
 105 
 106         RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
 107                 "CCK PWR 1~11M (rf-A) = 0x%x (reg 0x%x)\n", tmpval,
 108                  RTXAGC_A_CCK11_CCK1);
 109 
 110         tmpval = tx_agc[RF90_PATH_B];
 111         rtl_set_bbreg(hw, RTXAGC_B_CCK11_CCK1, MASKDWORD, tmpval);
 112 
 113         RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
 114                 "CCK PWR 11M (rf-B) = 0x%x (reg 0x%x)\n", tmpval,
 115                  RTXAGC_B_CCK11_CCK1);
 116 }
 117 
 118 static void rtl8821ae_phy_get_power_base(struct ieee80211_hw *hw,
 119                                          u8 *ppowerlevel_ofdm,
 120                                          u8 *ppowerlevel_bw20,
 121                                          u8 *ppowerlevel_bw40, u8 channel,
 122                                          u32 *ofdmbase, u32 *mcsbase)
 123 {
 124         struct rtl_priv *rtlpriv = rtl_priv(hw);
 125         struct rtl_phy *rtlphy = &rtlpriv->phy;
 126         u32 powerbase0, powerbase1;
 127         u8 i, powerlevel[2];
 128 
 129         for (i = 0; i < 2; i++) {
 130                 powerbase0 = ppowerlevel_ofdm[i];
 131 
 132                 powerbase0 = (powerbase0 << 24) | (powerbase0 << 16) |
 133                     (powerbase0 << 8) | powerbase0;
 134                 *(ofdmbase + i) = powerbase0;
 135                 RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
 136                         " [OFDM power base index rf(%c) = 0x%x]\n",
 137                          ((i == 0) ? 'A' : 'B'), *(ofdmbase + i));
 138         }
 139 
 140         for (i = 0; i < 2; i++) {
 141                 if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20)
 142                         powerlevel[i] = ppowerlevel_bw20[i];
 143                 else
 144                         powerlevel[i] = ppowerlevel_bw40[i];
 145 
 146                 powerbase1 = powerlevel[i];
 147                 powerbase1 = (powerbase1 << 24) |
 148                     (powerbase1 << 16) | (powerbase1 << 8) | powerbase1;
 149 
 150                 *(mcsbase + i) = powerbase1;
 151 
 152                 RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
 153                         " [MCS power base index rf(%c) = 0x%x]\n",
 154                          ((i == 0) ? 'A' : 'B'), *(mcsbase + i));
 155         }
 156 }
 157 
 158 static void get_txpower_writeval_by_regulatory(struct ieee80211_hw *hw,
 159                                                u8 channel, u8 index,
 160                                                u32 *powerbase0,
 161                                                u32 *powerbase1,
 162                                                u32 *p_outwriteval)
 163 {
 164         struct rtl_priv *rtlpriv = rtl_priv(hw);
 165         struct rtl_phy *rtlphy = &rtlpriv->phy;
 166         struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
 167         u8 i, chnlgroup = 0, pwr_diff_limit[4], pwr_diff = 0, customer_pwr_diff;
 168         u32 writeval, customer_limit, rf;
 169 
 170         for (rf = 0; rf < 2; rf++) {
 171                 switch (rtlefuse->eeprom_regulatory) {
 172                 case 0:
 173                         chnlgroup = 0;
 174 
 175                         writeval =
 176                             rtlphy->mcs_txpwrlevel_origoffset[chnlgroup][index +
 177                                                         (rf ? 8 : 0)]
 178                             + ((index < 2) ? powerbase0[rf] : powerbase1[rf]);
 179 
 180                         RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
 181                                 "RTK better performance, writeval(%c) = 0x%x\n",
 182                                  ((rf == 0) ? 'A' : 'B'), writeval);
 183                         break;
 184                 case 1:
 185                         if (rtlphy->pwrgroup_cnt == 1) {
 186                                 chnlgroup = 0;
 187                         } else {
 188                                 if (channel < 3)
 189                                         chnlgroup = 0;
 190                                 else if (channel < 6)
 191                                         chnlgroup = 1;
 192                                 else if (channel < 9)
 193                                         chnlgroup = 2;
 194                                 else if (channel < 12)
 195                                         chnlgroup = 3;
 196                                 else if (channel < 14)
 197                                         chnlgroup = 4;
 198                                 else if (channel == 14)
 199                                         chnlgroup = 5;
 200                         }
 201 
 202                         writeval =
 203                             rtlphy->mcs_txpwrlevel_origoffset[chnlgroup]
 204                             [index + (rf ? 8 : 0)] + ((index < 2) ?
 205                                                       powerbase0[rf] :
 206                                                       powerbase1[rf]);
 207 
 208                         RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
 209                                 "Realtek regulatory, 20MHz, writeval(%c) = 0x%x\n",
 210                                  ((rf == 0) ? 'A' : 'B'), writeval);
 211 
 212                         break;
 213                 case 2:
 214                         writeval =
 215                             ((index < 2) ? powerbase0[rf] : powerbase1[rf]);
 216 
 217                         RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
 218                                 "Better regulatory, writeval(%c) = 0x%x\n",
 219                                  ((rf == 0) ? 'A' : 'B'), writeval);
 220                         break;
 221                 case 3:
 222                         chnlgroup = 0;
 223 
 224                         if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) {
 225                                 RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
 226                                         "customer's limit, 40MHz rf(%c) = 0x%x\n",
 227                                          ((rf == 0) ? 'A' : 'B'),
 228                                          rtlefuse->pwrgroup_ht40[rf][channel -
 229                                                                      1]);
 230                         } else {
 231                                 RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
 232                                         "customer's limit, 20MHz rf(%c) = 0x%x\n",
 233                                          ((rf == 0) ? 'A' : 'B'),
 234                                          rtlefuse->pwrgroup_ht20[rf][channel -
 235                                                                      1]);
 236                         }
 237 
 238                         if (index < 2)
 239                                 pwr_diff = rtlefuse->txpwr_legacyhtdiff[rf][channel-1];
 240                         else if (rtlphy->current_chan_bw ==  HT_CHANNEL_WIDTH_20)
 241                                 pwr_diff =
 242                                   rtlefuse->txpwr_ht20diff[rf][channel-1];
 243 
 244                         if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40)
 245                                 customer_pwr_diff =
 246                                   rtlefuse->pwrgroup_ht40[rf][channel-1];
 247                         else
 248                                 customer_pwr_diff =
 249                                   rtlefuse->pwrgroup_ht20[rf][channel-1];
 250 
 251                         if (pwr_diff > customer_pwr_diff)
 252                                 pwr_diff = 0;
 253                         else
 254                                 pwr_diff = customer_pwr_diff - pwr_diff;
 255 
 256                         for (i = 0; i < 4; i++) {
 257                                 pwr_diff_limit[i] =
 258                                     (u8)((rtlphy->mcs_txpwrlevel_origoffset
 259                                     [chnlgroup][index + (rf ? 8 : 0)] &
 260                                     (0x7f << (i * 8))) >> (i * 8));
 261 
 262                                 if (pwr_diff_limit[i] > pwr_diff)
 263                                         pwr_diff_limit[i] = pwr_diff;
 264                         }
 265 
 266                         customer_limit = (pwr_diff_limit[3] << 24) |
 267                             (pwr_diff_limit[2] << 16) |
 268                             (pwr_diff_limit[1] << 8) | (pwr_diff_limit[0]);
 269 
 270                         RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
 271                                 "Customer's limit rf(%c) = 0x%x\n",
 272                                  ((rf == 0) ? 'A' : 'B'), customer_limit);
 273 
 274                         writeval = customer_limit +
 275                             ((index < 2) ? powerbase0[rf] : powerbase1[rf]);
 276 
 277                         RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
 278                                 "Customer, writeval rf(%c)= 0x%x\n",
 279                                  ((rf == 0) ? 'A' : 'B'), writeval);
 280                         break;
 281                 default:
 282                         chnlgroup = 0;
 283                         writeval =
 284                             rtlphy->mcs_txpwrlevel_origoffset[chnlgroup]
 285                             [index + (rf ? 8 : 0)]
 286                             + ((index < 2) ? powerbase0[rf] : powerbase1[rf]);
 287 
 288                         RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
 289                                 "RTK better performance, writeval rf(%c) = 0x%x\n",
 290                                  ((rf == 0) ? 'A' : 'B'), writeval);
 291                         break;
 292                 }
 293 
 294                 if (rtlpriv->dm.dynamic_txhighpower_lvl == TXHIGHPWRLEVEL_BT1)
 295                         writeval = writeval - 0x06060606;
 296                 else if (rtlpriv->dm.dynamic_txhighpower_lvl ==
 297                          TXHIGHPWRLEVEL_BT2)
 298                         writeval = writeval - 0x0c0c0c0c;
 299                 *(p_outwriteval + rf) = writeval;
 300         }
 301 }
 302 
 303 static void _rtl8821ae_write_ofdm_power_reg(struct ieee80211_hw *hw,
 304                                             u8 index, u32 *pvalue)
 305 {
 306         struct rtl_priv *rtlpriv = rtl_priv(hw);
 307         u16 regoffset_a[6] = {
 308                 RTXAGC_A_OFDM18_OFDM6, RTXAGC_A_OFDM54_OFDM24,
 309                 RTXAGC_A_MCS03_MCS00, RTXAGC_A_MCS07_MCS04,
 310                 RTXAGC_A_MCS11_MCS08, RTXAGC_A_MCS15_MCS12
 311         };
 312         u16 regoffset_b[6] = {
 313                 RTXAGC_B_OFDM18_OFDM6, RTXAGC_B_OFDM54_OFDM24,
 314                 RTXAGC_B_MCS03_MCS00, RTXAGC_B_MCS07_MCS04,
 315                 RTXAGC_B_MCS11_MCS08, RTXAGC_B_MCS15_MCS12
 316         };
 317         u8 i, rf, pwr_val[4];
 318         u32 writeval;
 319         u16 regoffset;
 320 
 321         for (rf = 0; rf < 2; rf++) {
 322                 writeval = pvalue[rf];
 323                 for (i = 0; i < 4; i++) {
 324                         pwr_val[i] = (u8)((writeval & (0x7f <<
 325                                                         (i * 8))) >> (i * 8));
 326 
 327                         if (pwr_val[i] > RF6052_MAX_TX_PWR)
 328                                 pwr_val[i] = RF6052_MAX_TX_PWR;
 329                 }
 330                 writeval = (pwr_val[3] << 24) | (pwr_val[2] << 16) |
 331                     (pwr_val[1] << 8) | pwr_val[0];
 332 
 333                 if (rf == 0)
 334                         regoffset = regoffset_a[index];
 335                 else
 336                         regoffset = regoffset_b[index];
 337                 rtl_set_bbreg(hw, regoffset, MASKDWORD, writeval);
 338 
 339                 RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
 340                         "Set 0x%x = %08x\n", regoffset, writeval);
 341         }
 342 }
 343 
 344 void rtl8821ae_phy_rf6052_set_ofdm_txpower(struct ieee80211_hw *hw,
 345                                            u8 *ppowerlevel_ofdm,
 346                                            u8 *ppowerlevel_bw20,
 347                                            u8 *ppowerlevel_bw40,
 348                                            u8 channel)
 349 {
 350         u32 writeval[2], powerbase0[2], powerbase1[2];
 351         u8 index;
 352         u8 direction;
 353         u32 pwrtrac_value;
 354 
 355         rtl8821ae_phy_get_power_base(hw, ppowerlevel_ofdm,
 356                                      ppowerlevel_bw20,
 357                                      ppowerlevel_bw40,
 358                                      channel,
 359                                      &powerbase0[0],
 360                                      &powerbase1[0]);
 361 
 362         rtl8821ae_dm_txpower_track_adjust(hw, 1, &direction, &pwrtrac_value);
 363 
 364         for (index = 0; index < 6; index++) {
 365                 get_txpower_writeval_by_regulatory(hw, channel, index,
 366                                                    &powerbase0[0],
 367                                                    &powerbase1[0],
 368                                                    &writeval[0]);
 369                 if (direction == 1) {
 370                         writeval[0] += pwrtrac_value;
 371                         writeval[1] += pwrtrac_value;
 372                 } else if (direction == 2) {
 373                         writeval[0] -= pwrtrac_value;
 374                         writeval[1] -= pwrtrac_value;
 375                 }
 376                 _rtl8821ae_write_ofdm_power_reg(hw, index, &writeval[0]);
 377         }
 378 }
 379 
 380 bool rtl8821ae_phy_rf6052_config(struct ieee80211_hw *hw)
 381 {
 382         struct rtl_priv *rtlpriv = rtl_priv(hw);
 383         struct rtl_phy *rtlphy = &rtlpriv->phy;
 384 
 385         if (rtlphy->rf_type == RF_1T1R)
 386                 rtlphy->num_total_rfpath = 1;
 387         else
 388                 rtlphy->num_total_rfpath = 2;
 389 
 390         return _rtl8821ae_phy_rf6052_config_parafile(hw);
 391 }
 392 
 393 static bool _rtl8821ae_phy_rf6052_config_parafile(struct ieee80211_hw *hw)
 394 {
 395         struct rtl_priv *rtlpriv = rtl_priv(hw);
 396         struct rtl_phy *rtlphy = &rtlpriv->phy;
 397         struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
 398         u8 rfpath;
 399         bool rtstatus = true;
 400 
 401         for (rfpath = 0; rfpath < rtlphy->num_total_rfpath; rfpath++) {
 402                 switch (rfpath) {
 403                 case RF90_PATH_A: {
 404                         if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE)
 405                                 rtstatus =
 406                                   rtl8812ae_phy_config_rf_with_headerfile(hw,
 407                                                         (enum radio_path)rfpath);
 408                         else
 409                                 rtstatus =
 410                                   rtl8821ae_phy_config_rf_with_headerfile(hw,
 411                                                         (enum radio_path)rfpath);
 412                         break;
 413                         }
 414                 case RF90_PATH_B:
 415                         if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE)
 416                                 rtstatus =
 417                                   rtl8812ae_phy_config_rf_with_headerfile(hw,
 418                                                         (enum radio_path)rfpath);
 419                         else
 420                                 rtstatus =
 421                                   rtl8821ae_phy_config_rf_with_headerfile(hw,
 422                                                         (enum radio_path)rfpath);
 423                         break;
 424                 case RF90_PATH_C:
 425                         break;
 426                 case RF90_PATH_D:
 427                         break;
 428                 }
 429 
 430                 if (!rtstatus) {
 431                         RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
 432                                  "Radio[%d] Fail!!\n", rfpath);
 433                         return false;
 434                 }
 435         }
 436 
 437         /*put arrays in dm.c*/
 438         RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "\n");
 439         return rtstatus;
 440 }

/* [<][>][^][v][top][bottom][index][help] */