linux/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/rf.c
<<
>>
Prefs
   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
  11static bool _rtl8821ae_phy_rf6052_config_parafile(struct ieee80211_hw *hw);
  12
  13void 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
  34void 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
 118static 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
 158static 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
 303static 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
 344void 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
 380bool 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
 393static 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                        rtl_dbg(rtlpriv, COMP_INIT, DBG_TRACE,
 432                                "Radio[%d] Fail!!\n", rfpath);
 433                        return false;
 434                }
 435        }
 436
 437        /*put arrays in dm.c*/
 438        rtl_dbg(rtlpriv, COMP_INIT, DBG_TRACE, "\n");
 439        return rtstatus;
 440}
 441