linux/drivers/net/wireless/realtek/rtlwifi/rtl8192se/rf.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/* Copyright(c) 2009-2012  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
  12static void _rtl92s_get_powerbase(struct ieee80211_hw *hw, u8 *p_pwrlevel,
  13                                  u8 chnl, u32 *ofdmbase, u32 *mcsbase,
  14                                  u8 *p_final_pwridx)
  15{
  16        struct rtl_priv *rtlpriv = rtl_priv(hw);
  17        struct rtl_phy *rtlphy = &(rtlpriv->phy);
  18        struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
  19        u32 pwrbase0, pwrbase1;
  20        u8 legacy_pwrdiff = 0, ht20_pwrdiff = 0;
  21        u8 i, pwrlevel[4];
  22
  23        for (i = 0; i < 2; i++)
  24                pwrlevel[i] = p_pwrlevel[i];
  25
  26        /* We only care about the path A for legacy. */
  27        if (rtlefuse->eeprom_version < 2) {
  28                pwrbase0 = pwrlevel[0] + (rtlefuse->legacy_ht_txpowerdiff & 0xf);
  29        } else {
  30                legacy_pwrdiff = rtlefuse->txpwr_legacyhtdiff
  31                                                [RF90_PATH_A][chnl - 1];
  32
  33                /* For legacy OFDM, tx pwr always > HT OFDM pwr.
  34                 * We do not care Path B
  35                 * legacy OFDM pwr diff. NO BB register
  36                 * to notify HW. */
  37                pwrbase0 = pwrlevel[0] + legacy_pwrdiff;
  38        }
  39
  40        pwrbase0 = (pwrbase0 << 24) | (pwrbase0 << 16) | (pwrbase0 << 8) |
  41                    pwrbase0;
  42        *ofdmbase = pwrbase0;
  43
  44        /* MCS rates */
  45        if (rtlefuse->eeprom_version >= 2) {
  46                /* Check HT20 to HT40 diff      */
  47                if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20) {
  48                        for (i = 0; i < 2; i++) {
  49                                /* rf-A, rf-B */
  50                                /* HT 20<->40 pwr diff */
  51                                ht20_pwrdiff = rtlefuse->txpwr_ht20diff
  52                                                        [i][chnl - 1];
  53
  54                                if (ht20_pwrdiff < 8) /* 0~+7 */
  55                                        pwrlevel[i] += ht20_pwrdiff;
  56                                else /* index8-15=-8~-1 */
  57                                        pwrlevel[i] -= (16 - ht20_pwrdiff);
  58                        }
  59                }
  60        }
  61
  62        /* use index of rf-A */
  63        pwrbase1 = pwrlevel[0];
  64        pwrbase1 = (pwrbase1 << 24) | (pwrbase1 << 16) | (pwrbase1 << 8) |
  65                                pwrbase1;
  66        *mcsbase = pwrbase1;
  67
  68        /* The following is for Antenna
  69         * diff from Ant-B to Ant-A */
  70        p_final_pwridx[0] = pwrlevel[0];
  71        p_final_pwridx[1] = pwrlevel[1];
  72
  73        switch (rtlefuse->eeprom_regulatory) {
  74        case 3:
  75                /* The following is for calculation
  76                 * of the power diff for Ant-B to Ant-A. */
  77                if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) {
  78                        p_final_pwridx[0] += rtlefuse->pwrgroup_ht40
  79                                                [RF90_PATH_A][
  80                                                chnl - 1];
  81                        p_final_pwridx[1] += rtlefuse->pwrgroup_ht40
  82                                                [RF90_PATH_B][
  83                                                chnl - 1];
  84                } else {
  85                        p_final_pwridx[0] += rtlefuse->pwrgroup_ht20
  86                                                [RF90_PATH_A][
  87                                                chnl - 1];
  88                        p_final_pwridx[1] += rtlefuse->pwrgroup_ht20
  89                                                [RF90_PATH_B][
  90                                                chnl - 1];
  91                }
  92                break;
  93        default:
  94                break;
  95        }
  96
  97        if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) {
  98                rtl_dbg(rtlpriv, COMP_POWER, DBG_LOUD,
  99                        "40MHz finalpwr_idx (A / B) = 0x%x / 0x%x\n",
 100                        p_final_pwridx[0], p_final_pwridx[1]);
 101        } else {
 102                rtl_dbg(rtlpriv, COMP_POWER, DBG_LOUD,
 103                        "20MHz finalpwr_idx (A / B) = 0x%x / 0x%x\n",
 104                        p_final_pwridx[0], p_final_pwridx[1]);
 105        }
 106}
 107
 108static void _rtl92s_set_antennadiff(struct ieee80211_hw *hw,
 109                                    u8 *p_final_pwridx)
 110{
 111        struct rtl_priv *rtlpriv = rtl_priv(hw);
 112        struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
 113        struct rtl_phy *rtlphy = &(rtlpriv->phy);
 114        s8 ant_pwr_diff = 0;
 115        u32     u4reg_val = 0;
 116
 117        if (rtlphy->rf_type == RF_2T2R) {
 118                ant_pwr_diff = p_final_pwridx[1] - p_final_pwridx[0];
 119
 120                /* range is from 7~-8,
 121                 * index = 0x0~0xf */
 122                if (ant_pwr_diff > 7)
 123                        ant_pwr_diff = 7;
 124                if (ant_pwr_diff < -8)
 125                        ant_pwr_diff = -8;
 126
 127                rtl_dbg(rtlpriv, COMP_POWER, DBG_LOUD,
 128                        "Antenna Diff from RF-B to RF-A = %d (0x%x)\n",
 129                        ant_pwr_diff, ant_pwr_diff & 0xf);
 130
 131                ant_pwr_diff &= 0xf;
 132        }
 133
 134        /* Antenna TX power difference */
 135        rtlefuse->antenna_txpwdiff[2] = 0;/* RF-D, don't care */
 136        rtlefuse->antenna_txpwdiff[1] = 0;/* RF-C, don't care */
 137        rtlefuse->antenna_txpwdiff[0] = (u8)(ant_pwr_diff);     /* RF-B */
 138
 139        u4reg_val = rtlefuse->antenna_txpwdiff[2] << 8 |
 140                                rtlefuse->antenna_txpwdiff[1] << 4 |
 141                                rtlefuse->antenna_txpwdiff[0];
 142
 143        rtl_set_bbreg(hw, RFPGA0_TXGAINSTAGE, (BXBTXAGC | BXCTXAGC | BXDTXAGC),
 144                      u4reg_val);
 145
 146        rtl_dbg(rtlpriv, COMP_POWER, DBG_LOUD, "Write BCD-Diff(0x%x) = 0x%x\n",
 147                RFPGA0_TXGAINSTAGE, u4reg_val);
 148}
 149
 150static void _rtl92s_get_txpower_writeval_byregulatory(struct ieee80211_hw *hw,
 151                                                      u8 chnl, u8 index,
 152                                                      u32 pwrbase0,
 153                                                      u32 pwrbase1,
 154                                                      u32 *p_outwrite_val)
 155{
 156        struct rtl_priv *rtlpriv = rtl_priv(hw);
 157        struct rtl_phy *rtlphy = &(rtlpriv->phy);
 158        struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
 159        u8 i, chnlgroup, pwrdiff_limit[4];
 160        u32 writeval, customer_limit;
 161
 162        /* Index 0 & 1= legacy OFDM, 2-5=HT_MCS rate */
 163        switch (rtlefuse->eeprom_regulatory) {
 164        case 0:
 165                /* Realtek better performance increase power diff
 166                 * defined by Realtek for large power */
 167                chnlgroup = 0;
 168
 169                writeval = rtlphy->mcs_offset[chnlgroup][index] +
 170                                ((index < 2) ? pwrbase0 : pwrbase1);
 171
 172                rtl_dbg(rtlpriv, COMP_POWER, DBG_LOUD,
 173                        "RTK better performance, writeval = 0x%x\n", writeval);
 174                break;
 175        case 1:
 176                /* Realtek regulatory increase power diff defined
 177                 * by Realtek for regulatory */
 178                if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) {
 179                        writeval = ((index < 2) ? pwrbase0 : pwrbase1);
 180
 181                        rtl_dbg(rtlpriv, COMP_POWER, DBG_LOUD,
 182                                "Realtek regulatory, 40MHz, writeval = 0x%x\n",
 183                                writeval);
 184                } else {
 185                        chnlgroup = 0;
 186
 187                        if (rtlphy->pwrgroup_cnt >= 3) {
 188                                if (chnl <= 3)
 189                                        chnlgroup = 0;
 190                                else if (chnl >= 4 && chnl <= 8)
 191                                        chnlgroup = 1;
 192                                else if (chnl > 8)
 193                                        chnlgroup = 2;
 194                                if (rtlphy->pwrgroup_cnt == 4)
 195                                        chnlgroup++;
 196                        }
 197
 198                        writeval = rtlphy->mcs_offset[chnlgroup][index]
 199                                        + ((index < 2) ?
 200                                        pwrbase0 : pwrbase1);
 201
 202                        rtl_dbg(rtlpriv, COMP_POWER, DBG_LOUD,
 203                                "Realtek regulatory, 20MHz, writeval = 0x%x\n",
 204                                writeval);
 205                }
 206                break;
 207        case 2:
 208                /* Better regulatory don't increase any power diff */
 209                writeval = ((index < 2) ? pwrbase0 : pwrbase1);
 210                rtl_dbg(rtlpriv, COMP_POWER, DBG_LOUD,
 211                        "Better regulatory, writeval = 0x%x\n", writeval);
 212                break;
 213        case 3:
 214                /* Customer defined power diff. increase power diff
 215                  defined by customer. */
 216                chnlgroup = 0;
 217
 218                if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) {
 219                        rtl_dbg(rtlpriv, COMP_POWER, DBG_LOUD,
 220                                "customer's limit, 40MHz = 0x%x\n",
 221                                rtlefuse->pwrgroup_ht40
 222                                [RF90_PATH_A][chnl - 1]);
 223                } else {
 224                        rtl_dbg(rtlpriv, COMP_POWER, DBG_LOUD,
 225                                "customer's limit, 20MHz = 0x%x\n",
 226                                rtlefuse->pwrgroup_ht20
 227                                [RF90_PATH_A][chnl - 1]);
 228                }
 229
 230                for (i = 0; i < 4; i++) {
 231                        pwrdiff_limit[i] = (u8)((rtlphy->mcs_offset
 232                                [chnlgroup][index] & (0x7f << (i * 8)))
 233                                >> (i * 8));
 234
 235                        if (rtlphy->current_chan_bw ==
 236                            HT_CHANNEL_WIDTH_20_40) {
 237                                if (pwrdiff_limit[i] >
 238                                    rtlefuse->pwrgroup_ht40
 239                                    [RF90_PATH_A][chnl - 1]) {
 240                                        pwrdiff_limit[i] =
 241                                          rtlefuse->pwrgroup_ht40
 242                                          [RF90_PATH_A][chnl - 1];
 243                                }
 244                        } else {
 245                                if (pwrdiff_limit[i] >
 246                                    rtlefuse->pwrgroup_ht20
 247                                    [RF90_PATH_A][chnl - 1]) {
 248                                        pwrdiff_limit[i] =
 249                                            rtlefuse->pwrgroup_ht20
 250                                            [RF90_PATH_A][chnl - 1];
 251                                }
 252                        }
 253                }
 254
 255                customer_limit = (pwrdiff_limit[3] << 24) |
 256                                (pwrdiff_limit[2] << 16) |
 257                                (pwrdiff_limit[1] << 8) |
 258                                (pwrdiff_limit[0]);
 259                rtl_dbg(rtlpriv, COMP_POWER, DBG_LOUD,
 260                        "Customer's limit = 0x%x\n", customer_limit);
 261
 262                writeval = customer_limit + ((index < 2) ?
 263                                             pwrbase0 : pwrbase1);
 264                rtl_dbg(rtlpriv, COMP_POWER, DBG_LOUD,
 265                        "Customer, writeval = 0x%x\n", writeval);
 266                break;
 267        default:
 268                chnlgroup = 0;
 269                writeval = rtlphy->mcs_offset[chnlgroup][index] +
 270                                ((index < 2) ? pwrbase0 : pwrbase1);
 271                rtl_dbg(rtlpriv, COMP_POWER, DBG_LOUD,
 272                        "RTK better performance, writeval = 0x%x\n", writeval);
 273                break;
 274        }
 275
 276        if (rtlpriv->dm.dynamic_txhighpower_lvl == TX_HIGH_PWR_LEVEL_LEVEL1)
 277                writeval = 0x10101010;
 278        else if (rtlpriv->dm.dynamic_txhighpower_lvl ==
 279                 TX_HIGH_PWR_LEVEL_LEVEL2)
 280                writeval = 0x0;
 281
 282        *p_outwrite_val = writeval;
 283
 284}
 285
 286static void _rtl92s_write_ofdm_powerreg(struct ieee80211_hw *hw,
 287                                        u8 index, u32 val)
 288{
 289        struct rtl_priv *rtlpriv = rtl_priv(hw);
 290        struct rtl_phy *rtlphy = &(rtlpriv->phy);
 291        struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
 292        u16 regoffset[6] = {0xe00, 0xe04, 0xe10, 0xe14, 0xe18, 0xe1c};
 293        u8 i, rfa_pwr[4];
 294        u8 rfa_lower_bound = 0, rfa_upper_bound = 0, rf_pwr_diff = 0;
 295        u32 writeval = val;
 296
 297        /* If path A and Path B coexist, we must limit Path A tx power.
 298         * Protect Path B pwr over or under flow. We need to calculate
 299         * upper and lower bound of path A tx power. */
 300        if (rtlphy->rf_type == RF_2T2R) {
 301                rf_pwr_diff = rtlefuse->antenna_txpwdiff[0];
 302
 303                /* Diff=-8~-1 */
 304                if (rf_pwr_diff >= 8) {
 305                        /* Prevent underflow!! */
 306                        rfa_lower_bound = 0x10 - rf_pwr_diff;
 307                /* if (rf_pwr_diff >= 0) Diff = 0-7 */
 308                } else {
 309                        rfa_upper_bound = RF6052_MAX_TX_PWR - rf_pwr_diff;
 310                }
 311        }
 312
 313        for (i = 0; i < 4; i++) {
 314                rfa_pwr[i] = (u8)((writeval & (0x7f << (i * 8))) >> (i * 8));
 315                if (rfa_pwr[i]  > RF6052_MAX_TX_PWR)
 316                        rfa_pwr[i]  = RF6052_MAX_TX_PWR;
 317
 318                /* If path A and Path B coexist, we must limit Path A tx power.
 319                 * Protect Path B pwr over or under flow. We need to calculate
 320                 * upper and lower bound of path A tx power. */
 321                if (rtlphy->rf_type == RF_2T2R) {
 322                        /* Diff=-8~-1 */
 323                        if (rf_pwr_diff >= 8) {
 324                                /* Prevent underflow!! */
 325                                if (rfa_pwr[i] < rfa_lower_bound)
 326                                        rfa_pwr[i] = rfa_lower_bound;
 327                        /* Diff = 0-7 */
 328                        } else if (rf_pwr_diff >= 1) {
 329                                /* Prevent overflow */
 330                                if (rfa_pwr[i] > rfa_upper_bound)
 331                                        rfa_pwr[i] = rfa_upper_bound;
 332                        }
 333                }
 334
 335        }
 336
 337        writeval = (rfa_pwr[3] << 24) | (rfa_pwr[2] << 16) | (rfa_pwr[1] << 8) |
 338                                rfa_pwr[0];
 339
 340        rtl_set_bbreg(hw, regoffset[index], 0x7f7f7f7f, writeval);
 341}
 342
 343void rtl92s_phy_rf6052_set_ofdmtxpower(struct ieee80211_hw *hw,
 344                                       u8 *p_pwrlevel, u8 chnl)
 345{
 346        u32 writeval, pwrbase0, pwrbase1;
 347        u8 index = 0;
 348        u8 finalpwr_idx[4];
 349
 350        _rtl92s_get_powerbase(hw, p_pwrlevel, chnl, &pwrbase0, &pwrbase1,
 351                        &finalpwr_idx[0]);
 352        _rtl92s_set_antennadiff(hw, &finalpwr_idx[0]);
 353
 354        for (index = 0; index < 6; index++) {
 355                _rtl92s_get_txpower_writeval_byregulatory(hw, chnl, index,
 356                                pwrbase0, pwrbase1, &writeval);
 357
 358                _rtl92s_write_ofdm_powerreg(hw, index, writeval);
 359        }
 360}
 361
 362void rtl92s_phy_rf6052_set_ccktxpower(struct ieee80211_hw *hw, u8 pwrlevel)
 363{
 364        struct rtl_priv *rtlpriv = rtl_priv(hw);
 365        struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
 366        struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
 367        u32 txagc = 0;
 368        bool dont_inc_cck_or_turboscanoff = false;
 369
 370        if (((rtlefuse->eeprom_version >= 2) &&
 371              (rtlefuse->txpwr_safetyflag == 1)) ||
 372              ((rtlefuse->eeprom_version >= 2) &&
 373              (rtlefuse->eeprom_regulatory != 0)))
 374                dont_inc_cck_or_turboscanoff = true;
 375
 376        if (mac->act_scanning) {
 377                txagc = 0x3f;
 378                if (dont_inc_cck_or_turboscanoff)
 379                        txagc = pwrlevel;
 380        } else {
 381                txagc = pwrlevel;
 382
 383                if (rtlpriv->dm.dynamic_txhighpower_lvl ==
 384                    TX_HIGH_PWR_LEVEL_LEVEL1)
 385                        txagc = 0x10;
 386                else if (rtlpriv->dm.dynamic_txhighpower_lvl ==
 387                        TX_HIGH_PWR_LEVEL_LEVEL2)
 388                        txagc = 0x0;
 389        }
 390
 391        if (txagc > RF6052_MAX_TX_PWR)
 392                txagc = RF6052_MAX_TX_PWR;
 393
 394        rtl_set_bbreg(hw, RTXAGC_CCK_MCS32, BTX_AGCRATECCK, txagc);
 395
 396}
 397
 398bool rtl92s_phy_rf6052_config(struct ieee80211_hw *hw)
 399{
 400        struct rtl_priv *rtlpriv = rtl_priv(hw);
 401        struct rtl_phy *rtlphy = &(rtlpriv->phy);
 402        u32 u4reg_val = 0;
 403        u8 rfpath;
 404        bool rtstatus = true;
 405        struct bb_reg_def *pphyreg;
 406
 407        /* Initialize RF */
 408        for (rfpath = 0; rfpath < rtlphy->num_total_rfpath; rfpath++) {
 409
 410                pphyreg = &rtlphy->phyreg_def[rfpath];
 411
 412                /* Store original RFENV control type */
 413                switch (rfpath) {
 414                case RF90_PATH_A:
 415                case RF90_PATH_C:
 416                        u4reg_val = rtl92s_phy_query_bb_reg(hw,
 417                                                            pphyreg->rfintfs,
 418                                                            BRFSI_RFENV);
 419                        break;
 420                case RF90_PATH_B:
 421                case RF90_PATH_D:
 422                        u4reg_val = rtl92s_phy_query_bb_reg(hw,
 423                                                            pphyreg->rfintfs,
 424                                                            BRFSI_RFENV << 16);
 425                        break;
 426                }
 427
 428                /* Set RF_ENV enable */
 429                rtl92s_phy_set_bb_reg(hw, pphyreg->rfintfe,
 430                                      BRFSI_RFENV << 16, 0x1);
 431
 432                /* Set RF_ENV output high */
 433                rtl92s_phy_set_bb_reg(hw, pphyreg->rfintfo, BRFSI_RFENV, 0x1);
 434
 435                /* Set bit number of Address and Data for RF register */
 436                rtl92s_phy_set_bb_reg(hw, pphyreg->rfhssi_para2,
 437                                B3WIRE_ADDRESSLENGTH, 0x0);
 438                rtl92s_phy_set_bb_reg(hw, pphyreg->rfhssi_para2,
 439                                B3WIRE_DATALENGTH, 0x0);
 440
 441                /* Initialize RF fom connfiguration file */
 442                switch (rfpath) {
 443                case RF90_PATH_A:
 444                        rtstatus = rtl92s_phy_config_rf(hw,
 445                                                (enum radio_path)rfpath);
 446                        break;
 447                case RF90_PATH_B:
 448                        rtstatus = rtl92s_phy_config_rf(hw,
 449                                                (enum radio_path)rfpath);
 450                        break;
 451                case RF90_PATH_C:
 452                        break;
 453                case RF90_PATH_D:
 454                        break;
 455                }
 456
 457                /* Restore RFENV control type */
 458                switch (rfpath) {
 459                case RF90_PATH_A:
 460                case RF90_PATH_C:
 461                        rtl92s_phy_set_bb_reg(hw, pphyreg->rfintfs, BRFSI_RFENV,
 462                                              u4reg_val);
 463                        break;
 464                case RF90_PATH_B:
 465                case RF90_PATH_D:
 466                        rtl92s_phy_set_bb_reg(hw, pphyreg->rfintfs,
 467                                              BRFSI_RFENV << 16,
 468                                              u4reg_val);
 469                        break;
 470                }
 471
 472                if (!rtstatus) {
 473                        pr_err("Radio[%d] Fail!!\n", rfpath);
 474                        goto fail;
 475                }
 476
 477        }
 478
 479        return rtstatus;
 480
 481fail:
 482        return rtstatus;
 483}
 484
 485void rtl92s_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw, u8 bandwidth)
 486{
 487        struct rtl_priv *rtlpriv = rtl_priv(hw);
 488        struct rtl_phy *rtlphy = &(rtlpriv->phy);
 489
 490        switch (bandwidth) {
 491        case HT_CHANNEL_WIDTH_20:
 492                rtlphy->rfreg_chnlval[0] = ((rtlphy->rfreg_chnlval[0] &
 493                                           0xfffff3ff) | 0x0400);
 494                rtl_set_rfreg(hw, RF90_PATH_A, RF_CHNLBW, RFREG_OFFSET_MASK,
 495                                        rtlphy->rfreg_chnlval[0]);
 496                break;
 497        case HT_CHANNEL_WIDTH_20_40:
 498                rtlphy->rfreg_chnlval[0] = ((rtlphy->rfreg_chnlval[0] &
 499                                            0xfffff3ff));
 500                rtl_set_rfreg(hw, RF90_PATH_A, RF_CHNLBW, RFREG_OFFSET_MASK,
 501                                        rtlphy->rfreg_chnlval[0]);
 502                break;
 503        default:
 504                pr_err("unknown bandwidth: %#X\n", bandwidth);
 505                break;
 506        }
 507}
 508