linux/drivers/staging/rtl8188eu/hal/rf.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/******************************************************************************
   3 *
   4 * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
   5 *
   6 ******************************************************************************/
   7
   8#include <osdep_service.h>
   9#include <drv_types.h>
  10#include <phy.h>
  11#include <rf.h>
  12#include <rtl8188e_hal.h>
  13
  14void rtl88eu_phy_rf6052_set_bandwidth(struct adapter *adapt,
  15                                      enum ht_channel_width bandwidth)
  16{
  17        struct hal_data_8188e *hal_data = adapt->HalData;
  18
  19        switch (bandwidth) {
  20        case HT_CHANNEL_WIDTH_20:
  21                hal_data->RfRegChnlVal[0] = ((hal_data->RfRegChnlVal[0] &
  22                                              0xfffff3ff) | BIT(10) | BIT(11));
  23                phy_set_rf_reg(adapt, RF_PATH_A, RF_CHNLBW, bRFRegOffsetMask,
  24                               hal_data->RfRegChnlVal[0]);
  25                break;
  26        case HT_CHANNEL_WIDTH_40:
  27                hal_data->RfRegChnlVal[0] = ((hal_data->RfRegChnlVal[0] &
  28                                              0xfffff3ff) | BIT(10));
  29                phy_set_rf_reg(adapt, RF_PATH_A, RF_CHNLBW, bRFRegOffsetMask,
  30                               hal_data->RfRegChnlVal[0]);
  31                break;
  32        default:
  33                break;
  34        }
  35}
  36
  37void rtl88eu_phy_rf6052_set_cck_txpower(struct adapter *adapt, u8 *powerlevel)
  38{
  39        struct hal_data_8188e *hal_data = adapt->HalData;
  40        struct dm_priv *pdmpriv = &hal_data->dmpriv;
  41        struct mlme_ext_priv *pmlmeext = &adapt->mlmeextpriv;
  42        u32 tx_agc[2] = {0, 0}, tmpval = 0, pwrtrac_value;
  43        u8 idx1, idx2;
  44        u8 *ptr;
  45        u8 direction;
  46
  47        if (pmlmeext->sitesurvey_res.state == SCAN_PROCESS) {
  48                tx_agc[RF_PATH_A] = 0x3f3f3f3f;
  49                tx_agc[RF_PATH_B] = 0x3f3f3f3f;
  50                for (idx1 = RF_PATH_A; idx1 <= RF_PATH_B; idx1++) {
  51                        tx_agc[idx1] = powerlevel[idx1] |
  52                                      (powerlevel[idx1] << 8) |
  53                                      (powerlevel[idx1] << 16) |
  54                                      (powerlevel[idx1] << 24);
  55                }
  56        } else {
  57                if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_Level1) {
  58                        tx_agc[RF_PATH_A] = 0x10101010;
  59                        tx_agc[RF_PATH_B] = 0x10101010;
  60                } else if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_Level2) {
  61                        tx_agc[RF_PATH_A] = 0x00000000;
  62                        tx_agc[RF_PATH_B] = 0x00000000;
  63                } else {
  64                        for (idx1 = RF_PATH_A; idx1 <= RF_PATH_B; idx1++) {
  65                                tx_agc[idx1] = powerlevel[idx1] |
  66                                               (powerlevel[idx1] << 8) |
  67                                               (powerlevel[idx1] << 16) |
  68                                               (powerlevel[idx1] << 24);
  69                        }
  70                        if (hal_data->EEPROMRegulatory == 0) {
  71                                tmpval = hal_data->MCSTxPowerLevelOriginalOffset[0][6] +
  72                                         (hal_data->MCSTxPowerLevelOriginalOffset[0][7] << 8);
  73                                tx_agc[RF_PATH_A] += tmpval;
  74
  75                                tmpval = hal_data->MCSTxPowerLevelOriginalOffset[0][14] +
  76                                         (hal_data->MCSTxPowerLevelOriginalOffset[0][15] << 24);
  77                                tx_agc[RF_PATH_B] += tmpval;
  78                        }
  79                }
  80        }
  81        for (idx1 = RF_PATH_A; idx1 <= RF_PATH_B; idx1++) {
  82                ptr = (u8 *)(&tx_agc[idx1]);
  83                for (idx2 = 0; idx2 < 4; idx2++) {
  84                        if (*ptr > RF6052_MAX_TX_PWR)
  85                                *ptr = RF6052_MAX_TX_PWR;
  86                        ptr++;
  87                }
  88        }
  89        rtl88eu_dm_txpower_track_adjust(&hal_data->odmpriv, 1, &direction,
  90                                        &pwrtrac_value);
  91
  92        if (direction == 1) {
  93                /*  Increase TX power */
  94                tx_agc[0] += pwrtrac_value;
  95                tx_agc[1] += pwrtrac_value;
  96        } else if (direction == 2) {
  97                /*  Decrease TX power */
  98                tx_agc[0] -=  pwrtrac_value;
  99                tx_agc[1] -=  pwrtrac_value;
 100        }
 101
 102        /*  rf-A cck tx power */
 103        tmpval = tx_agc[RF_PATH_A] & 0xff;
 104        phy_set_bb_reg(adapt, rTxAGC_A_CCK1_Mcs32, bMaskByte1, tmpval);
 105        tmpval = tx_agc[RF_PATH_A] >> 8;
 106        phy_set_bb_reg(adapt, rTxAGC_B_CCK11_A_CCK2_11, 0xffffff00, tmpval);
 107
 108        /*  rf-B cck tx power */
 109        tmpval = tx_agc[RF_PATH_B] >> 24;
 110        phy_set_bb_reg(adapt, rTxAGC_B_CCK11_A_CCK2_11, bMaskByte0, tmpval);
 111        tmpval = tx_agc[RF_PATH_B] & 0x00ffffff;
 112        phy_set_bb_reg(adapt, rTxAGC_B_CCK1_55_Mcs32, 0xffffff00, tmpval);
 113}
 114
 115/*  powerbase0 for OFDM rates */
 116/*  powerbase1 for HT MCS rates */
 117static void getpowerbase88e(struct adapter *adapt, u8 *pwr_level_ofdm,
 118                            u8 *pwr_level_bw20, u8 *pwr_level_bw40,
 119                            u8 channel, u32 *ofdmbase, u32 *mcs_base)
 120{
 121        u32 powerbase0, powerbase1;
 122        u8 i, powerlevel[2];
 123
 124        for (i = 0; i < 2; i++) {
 125                powerbase0 = pwr_level_ofdm[i];
 126
 127                powerbase0 = (powerbase0 << 24) | (powerbase0 << 16) |
 128                             (powerbase0 << 8) | powerbase0;
 129                *(ofdmbase + i) = powerbase0;
 130        }
 131        /* Check HT20 to HT40 diff */
 132        if (adapt->HalData->CurrentChannelBW == HT_CHANNEL_WIDTH_20)
 133                powerlevel[0] = pwr_level_bw20[0];
 134        else
 135                powerlevel[0] = pwr_level_bw40[0];
 136        powerbase1 = powerlevel[0];
 137        powerbase1 = (powerbase1 << 24) | (powerbase1 << 16) |
 138                     (powerbase1 << 8) | powerbase1;
 139        *mcs_base = powerbase1;
 140}
 141
 142static void get_rx_power_val_by_reg(struct adapter *adapt, u8 channel,
 143                                    u8 index, u32 *powerbase0, u32 *powerbase1,
 144                                    u32 *out_val)
 145{
 146        struct hal_data_8188e *hal_data = adapt->HalData;
 147        struct dm_priv  *pdmpriv = &hal_data->dmpriv;
 148        u8 i, chnlGroup = 0, pwr_diff_limit[4], customer_pwr_limit;
 149        s8 pwr_diff = 0;
 150        u32 write_val, customer_limit, rf;
 151        u8 regulatory = hal_data->EEPROMRegulatory;
 152
 153        /*  Index 0 & 1= legacy OFDM, 2-5=HT_MCS rate */
 154
 155        for (rf = 0; rf < 2; rf++) {
 156                u8 j = index + (rf ? 8 : 0);
 157
 158                switch (regulatory) {
 159                case 0:
 160                        chnlGroup = 0;
 161                        write_val = hal_data->MCSTxPowerLevelOriginalOffset[chnlGroup][index + (rf ? 8 : 0)] +
 162                                ((index < 2) ? powerbase0[rf] : powerbase1[rf]);
 163                        break;
 164                case 1: /*  Realtek regulatory */
 165                        /*  increase power diff defined by Realtek for regulatory */
 166                        if (hal_data->pwrGroupCnt == 1)
 167                                chnlGroup = 0;
 168                        if (hal_data->pwrGroupCnt >= hal_data->PGMaxGroup)
 169                                Hal_GetChnlGroup88E(channel, &chnlGroup);
 170
 171                        write_val = hal_data->MCSTxPowerLevelOriginalOffset[chnlGroup][index + (rf ? 8 : 0)] +
 172                                        ((index < 2) ? powerbase0[rf] : powerbase1[rf]);
 173                        break;
 174                case 2: /*  Better regulatory */
 175                                /*  don't increase any power diff */
 176                        write_val = (index < 2) ? powerbase0[rf] : powerbase1[rf];
 177                        break;
 178                case 3: /*  Customer defined power diff. */
 179                                /*  increase power diff defined by customer. */
 180                        chnlGroup = 0;
 181
 182                        if (index < 2)
 183                                pwr_diff = hal_data->TxPwrLegacyHtDiff[rf][channel - 1];
 184                        else if (hal_data->CurrentChannelBW == HT_CHANNEL_WIDTH_20)
 185                                pwr_diff = hal_data->TxPwrHt20Diff[rf][channel - 1];
 186
 187                        if (hal_data->CurrentChannelBW == HT_CHANNEL_WIDTH_40)
 188                                customer_pwr_limit = hal_data->PwrGroupHT40[rf][channel - 1];
 189                        else
 190                                customer_pwr_limit = hal_data->PwrGroupHT20[rf][channel - 1];
 191
 192                        if (pwr_diff >= customer_pwr_limit)
 193                                pwr_diff = 0;
 194                        else
 195                                pwr_diff = customer_pwr_limit - pwr_diff;
 196
 197                        for (i = 0; i < 4; i++) {
 198                                pwr_diff_limit[i] = (u8)((hal_data->MCSTxPowerLevelOriginalOffset[chnlGroup][j] &
 199                                                         (0x7f << (i * 8))) >> (i * 8));
 200
 201                                if (pwr_diff_limit[i] > pwr_diff)
 202                                        pwr_diff_limit[i] = pwr_diff;
 203                        }
 204                        customer_limit = (pwr_diff_limit[3] << 24) |
 205                                         (pwr_diff_limit[2] << 16) |
 206                                         (pwr_diff_limit[1] << 8) |
 207                                         (pwr_diff_limit[0]);
 208                        write_val = customer_limit + ((index < 2) ? powerbase0[rf] : powerbase1[rf]);
 209                        break;
 210                default:
 211                        chnlGroup = 0;
 212                        write_val = hal_data->MCSTxPowerLevelOriginalOffset[chnlGroup][j] +
 213                                        ((index < 2) ? powerbase0[rf] : powerbase1[rf]);
 214                        break;
 215                }
 216/*  20100427 Joseph: Driver dynamic Tx power shall not affect Tx power. It shall be determined by power training mechanism. */
 217/*  Currently, we cannot fully disable driver dynamic tx power mechanism because it is referenced by BT coexist mechanism. */
 218/*  In the future, two mechanism shall be separated from each other and maintained independently. Thanks for Lanhsin's reminder. */
 219                /* 92d do not need this */
 220                if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_Level1)
 221                        write_val = 0x14141414;
 222                else if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_Level2)
 223                        write_val = 0x00000000;
 224
 225                *(out_val + rf) = write_val;
 226        }
 227}
 228
 229static void write_ofdm_pwr_reg(struct adapter *adapt, u8 index, u32 *pvalue)
 230{
 231        u16 regoffset_a[6] = { rTxAGC_A_Rate18_06, rTxAGC_A_Rate54_24,
 232                               rTxAGC_A_Mcs03_Mcs00, rTxAGC_A_Mcs07_Mcs04,
 233                               rTxAGC_A_Mcs11_Mcs08, rTxAGC_A_Mcs15_Mcs12 };
 234        u16 regoffset_b[6] = { rTxAGC_B_Rate18_06, rTxAGC_B_Rate54_24,
 235                               rTxAGC_B_Mcs03_Mcs00, rTxAGC_B_Mcs07_Mcs04,
 236                               rTxAGC_B_Mcs11_Mcs08, rTxAGC_B_Mcs15_Mcs12 };
 237        u8 i, rf, pwr_val[4];
 238        u32 write_val;
 239        u16 regoffset;
 240
 241        for (rf = 0; rf < 2; rf++) {
 242                write_val = pvalue[rf];
 243                for (i = 0; i < 4; i++) {
 244                        pwr_val[i] = (u8)((write_val & (0x7f << (i * 8))) >> (i * 8));
 245                        if (pwr_val[i]  > RF6052_MAX_TX_PWR)
 246                                pwr_val[i]  = RF6052_MAX_TX_PWR;
 247                }
 248                write_val = (pwr_val[3] << 24) | (pwr_val[2] << 16) |
 249                            (pwr_val[1] << 8) | pwr_val[0];
 250
 251                if (rf == 0)
 252                        regoffset = regoffset_a[index];
 253                else
 254                        regoffset = regoffset_b[index];
 255
 256                phy_set_bb_reg(adapt, regoffset, bMaskDWord, write_val);
 257        }
 258}
 259
 260void rtl88eu_phy_rf6052_set_ofdm_txpower(struct adapter *adapt,
 261                                         u8 *pwr_level_ofdm,
 262                                         u8 *pwr_level_bw20,
 263                                         u8 *pwr_level_bw40, u8 channel)
 264{
 265        u32 write_val[2], powerbase0[2], powerbase1[2], pwrtrac_value;
 266        u8 direction;
 267        u8 index = 0;
 268
 269        getpowerbase88e(adapt, pwr_level_ofdm, pwr_level_bw20, pwr_level_bw40,
 270                        channel, &powerbase0[0], &powerbase1[0]);
 271
 272        rtl88eu_dm_txpower_track_adjust(&adapt->HalData->odmpriv, 0,
 273                                        &direction, &pwrtrac_value);
 274
 275        for (index = 0; index < 6; index++) {
 276                get_rx_power_val_by_reg(adapt, channel, index,
 277                                        &powerbase0[0], &powerbase1[0],
 278                                        &write_val[0]);
 279
 280                if (direction == 1) {
 281                        write_val[0] += pwrtrac_value;
 282                        write_val[1] += pwrtrac_value;
 283                } else if (direction == 2) {
 284                        write_val[0] -= pwrtrac_value;
 285                        write_val[1] -= pwrtrac_value;
 286                }
 287                write_ofdm_pwr_reg(adapt, index, &write_val[0]);
 288        }
 289}
 290