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}
 141static void get_rx_power_val_by_reg(struct adapter *adapt, u8 channel,
 142                                    u8 index, u32 *powerbase0, u32 *powerbase1,
 143                                    u32 *out_val)
 144{
 145        struct hal_data_8188e *hal_data = adapt->HalData;
 146        struct dm_priv  *pdmpriv = &hal_data->dmpriv;
 147        u8 i, chnlGroup = 0, pwr_diff_limit[4], customer_pwr_limit;
 148        s8 pwr_diff = 0;
 149        u32 write_val, customer_limit, rf;
 150        u8 regulatory = hal_data->EEPROMRegulatory;
 151
 152        /*  Index 0 & 1= legacy OFDM, 2-5=HT_MCS rate */
 153
 154        for (rf = 0; rf < 2; rf++) {
 155                u8 j = index + (rf ? 8 : 0);
 156
 157                switch (regulatory) {
 158                case 0:
 159                        chnlGroup = 0;
 160                        write_val = hal_data->MCSTxPowerLevelOriginalOffset[chnlGroup][index+(rf ? 8 : 0)] +
 161                                ((index < 2) ? powerbase0[rf] : powerbase1[rf]);
 162                        break;
 163                case 1: /*  Realtek regulatory */
 164                        /*  increase power diff defined by Realtek for regulatory */
 165                        if (hal_data->pwrGroupCnt == 1)
 166                                chnlGroup = 0;
 167                        if (hal_data->pwrGroupCnt >= hal_data->PGMaxGroup) {
 168                                if (channel < 3)
 169                                        chnlGroup = 0;
 170                                else if (channel < 6)
 171                                        chnlGroup = 1;
 172                                else if (channel < 9)
 173                                        chnlGroup = 2;
 174                                else if (channel < 12)
 175                                        chnlGroup = 3;
 176                                else if (channel < 14)
 177                                        chnlGroup = 4;
 178                                else if (channel == 14)
 179                                        chnlGroup = 5;
 180                        }
 181                        write_val = hal_data->MCSTxPowerLevelOriginalOffset[chnlGroup][index+(rf ? 8 : 0)] +
 182                                        ((index < 2) ? powerbase0[rf] : powerbase1[rf]);
 183                        break;
 184                case 2: /*  Better regulatory */
 185                                /*  don't increase any power diff */
 186                        write_val = (index < 2) ? powerbase0[rf] : powerbase1[rf];
 187                        break;
 188                case 3: /*  Customer defined power diff. */
 189                                /*  increase power diff defined by customer. */
 190                        chnlGroup = 0;
 191
 192                        if (index < 2)
 193                                pwr_diff = hal_data->TxPwrLegacyHtDiff[rf][channel-1];
 194                        else if (hal_data->CurrentChannelBW == HT_CHANNEL_WIDTH_20)
 195                                pwr_diff = hal_data->TxPwrHt20Diff[rf][channel-1];
 196
 197                        if (hal_data->CurrentChannelBW == HT_CHANNEL_WIDTH_40)
 198                                customer_pwr_limit = hal_data->PwrGroupHT40[rf][channel-1];
 199                        else
 200                                customer_pwr_limit = hal_data->PwrGroupHT20[rf][channel-1];
 201
 202                        if (pwr_diff >= customer_pwr_limit)
 203                                pwr_diff = 0;
 204                        else
 205                                pwr_diff = customer_pwr_limit - pwr_diff;
 206
 207                        for (i = 0; i < 4; i++) {
 208                                pwr_diff_limit[i] = (u8)((hal_data->MCSTxPowerLevelOriginalOffset[chnlGroup][j] &
 209                                                         (0x7f << (i * 8))) >> (i * 8));
 210
 211                                if (pwr_diff_limit[i] > pwr_diff)
 212                                        pwr_diff_limit[i] = pwr_diff;
 213                        }
 214                        customer_limit = (pwr_diff_limit[3]<<24) |
 215                                         (pwr_diff_limit[2]<<16) |
 216                                         (pwr_diff_limit[1]<<8) |
 217                                         (pwr_diff_limit[0]);
 218                        write_val = customer_limit + ((index < 2) ? powerbase0[rf] : powerbase1[rf]);
 219                        break;
 220                default:
 221                        chnlGroup = 0;
 222                        write_val = hal_data->MCSTxPowerLevelOriginalOffset[chnlGroup][j] +
 223                                        ((index < 2) ? powerbase0[rf] : powerbase1[rf]);
 224                        break;
 225                }
 226/*  20100427 Joseph: Driver dynamic Tx power shall not affect Tx power. It shall be determined by power training mechanism. */
 227/*  Currently, we cannot fully disable driver dynamic tx power mechanism because it is referenced by BT coexist mechanism. */
 228/*  In the future, two mechanism shall be separated from each other and maintained independently. Thanks for Lanhsin's reminder. */
 229                /* 92d do not need this */
 230                if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_Level1)
 231                        write_val = 0x14141414;
 232                else if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_Level2)
 233                        write_val = 0x00000000;
 234
 235                *(out_val+rf) = write_val;
 236        }
 237}
 238
 239static void write_ofdm_pwr_reg(struct adapter *adapt, u8 index, u32 *pvalue)
 240{
 241        u16 regoffset_a[6] = { rTxAGC_A_Rate18_06, rTxAGC_A_Rate54_24,
 242                               rTxAGC_A_Mcs03_Mcs00, rTxAGC_A_Mcs07_Mcs04,
 243                               rTxAGC_A_Mcs11_Mcs08, rTxAGC_A_Mcs15_Mcs12 };
 244        u16 regoffset_b[6] = { rTxAGC_B_Rate18_06, rTxAGC_B_Rate54_24,
 245                               rTxAGC_B_Mcs03_Mcs00, rTxAGC_B_Mcs07_Mcs04,
 246                               rTxAGC_B_Mcs11_Mcs08, rTxAGC_B_Mcs15_Mcs12 };
 247        u8 i, rf, pwr_val[4];
 248        u32 write_val;
 249        u16 regoffset;
 250
 251        for (rf = 0; rf < 2; rf++) {
 252                write_val = pvalue[rf];
 253                for (i = 0; i < 4; i++) {
 254                        pwr_val[i] = (u8)((write_val & (0x7f<<(i*8)))>>(i*8));
 255                        if (pwr_val[i]  > RF6052_MAX_TX_PWR)
 256                                pwr_val[i]  = RF6052_MAX_TX_PWR;
 257                }
 258                write_val = (pwr_val[3]<<24) | (pwr_val[2]<<16) |
 259                            (pwr_val[1]<<8) | pwr_val[0];
 260
 261                if (rf == 0)
 262                        regoffset = regoffset_a[index];
 263                else
 264                        regoffset = regoffset_b[index];
 265
 266                phy_set_bb_reg(adapt, regoffset, bMaskDWord, write_val);
 267        }
 268}
 269
 270void rtl88eu_phy_rf6052_set_ofdm_txpower(struct adapter *adapt,
 271                                         u8 *pwr_level_ofdm,
 272                                         u8 *pwr_level_bw20,
 273                                         u8 *pwr_level_bw40, u8 channel)
 274{
 275        u32 write_val[2], powerbase0[2], powerbase1[2], pwrtrac_value;
 276        u8 direction;
 277        u8 index = 0;
 278
 279        getpowerbase88e(adapt, pwr_level_ofdm, pwr_level_bw20, pwr_level_bw40,
 280                        channel, &powerbase0[0], &powerbase1[0]);
 281
 282        rtl88eu_dm_txpower_track_adjust(&adapt->HalData->odmpriv, 0,
 283                                        &direction, &pwrtrac_value);
 284
 285        for (index = 0; index < 6; index++) {
 286                get_rx_power_val_by_reg(adapt, channel, index,
 287                                        &powerbase0[0], &powerbase1[0],
 288                                        &write_val[0]);
 289
 290                if (direction == 1) {
 291                        write_val[0] += pwrtrac_value;
 292                        write_val[1] += pwrtrac_value;
 293                } else if (direction == 2) {
 294                        write_val[0] -= pwrtrac_value;
 295                        write_val[1] -= pwrtrac_value;
 296                }
 297                write_ofdm_pwr_reg(adapt, index, &write_val[0]);
 298        }
 299}
 300