Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /* Copyright(c) 2009-2012  Realtek Corporation.*/
0003 
0004 #include "../wifi.h"
0005 #include "reg.h"
0006 #include "def.h"
0007 #include "phy.h"
0008 #include "rf.h"
0009 #include "dm.h"
0010 
0011 
0012 static void _rtl92s_get_powerbase(struct ieee80211_hw *hw, u8 *p_pwrlevel,
0013                   u8 chnl, u32 *ofdmbase, u32 *mcsbase,
0014                   u8 *p_final_pwridx)
0015 {
0016     struct rtl_priv *rtlpriv = rtl_priv(hw);
0017     struct rtl_phy *rtlphy = &(rtlpriv->phy);
0018     struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
0019     u32 pwrbase0, pwrbase1;
0020     u8 legacy_pwrdiff = 0, ht20_pwrdiff = 0;
0021     u8 i, pwrlevel[4];
0022 
0023     for (i = 0; i < 2; i++)
0024         pwrlevel[i] = p_pwrlevel[i];
0025 
0026     /* We only care about the path A for legacy. */
0027     if (rtlefuse->eeprom_version < 2) {
0028         pwrbase0 = pwrlevel[0] + (rtlefuse->legacy_ht_txpowerdiff & 0xf);
0029     } else {
0030         legacy_pwrdiff = rtlefuse->txpwr_legacyhtdiff
0031                         [RF90_PATH_A][chnl - 1];
0032 
0033         /* For legacy OFDM, tx pwr always > HT OFDM pwr.
0034          * We do not care Path B
0035          * legacy OFDM pwr diff. NO BB register
0036          * to notify HW. */
0037         pwrbase0 = pwrlevel[0] + legacy_pwrdiff;
0038     }
0039 
0040     pwrbase0 = (pwrbase0 << 24) | (pwrbase0 << 16) | (pwrbase0 << 8) |
0041             pwrbase0;
0042     *ofdmbase = pwrbase0;
0043 
0044     /* MCS rates */
0045     if (rtlefuse->eeprom_version >= 2) {
0046         /* Check HT20 to HT40 diff  */
0047         if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20) {
0048             for (i = 0; i < 2; i++) {
0049                 /* rf-A, rf-B */
0050                 /* HT 20<->40 pwr diff */
0051                 ht20_pwrdiff = rtlefuse->txpwr_ht20diff
0052                             [i][chnl - 1];
0053 
0054                 if (ht20_pwrdiff < 8) /* 0~+7 */
0055                     pwrlevel[i] += ht20_pwrdiff;
0056                 else /* index8-15=-8~-1 */
0057                     pwrlevel[i] -= (16 - ht20_pwrdiff);
0058             }
0059         }
0060     }
0061 
0062     /* use index of rf-A */
0063     pwrbase1 = pwrlevel[0];
0064     pwrbase1 = (pwrbase1 << 24) | (pwrbase1 << 16) | (pwrbase1 << 8) |
0065                 pwrbase1;
0066     *mcsbase = pwrbase1;
0067 
0068     /* The following is for Antenna
0069      * diff from Ant-B to Ant-A */
0070     p_final_pwridx[0] = pwrlevel[0];
0071     p_final_pwridx[1] = pwrlevel[1];
0072 
0073     switch (rtlefuse->eeprom_regulatory) {
0074     case 3:
0075         /* The following is for calculation
0076          * of the power diff for Ant-B to Ant-A. */
0077         if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) {
0078             p_final_pwridx[0] += rtlefuse->pwrgroup_ht40
0079                         [RF90_PATH_A][
0080                         chnl - 1];
0081             p_final_pwridx[1] += rtlefuse->pwrgroup_ht40
0082                         [RF90_PATH_B][
0083                         chnl - 1];
0084         } else {
0085             p_final_pwridx[0] += rtlefuse->pwrgroup_ht20
0086                         [RF90_PATH_A][
0087                         chnl - 1];
0088             p_final_pwridx[1] += rtlefuse->pwrgroup_ht20
0089                         [RF90_PATH_B][
0090                         chnl - 1];
0091         }
0092         break;
0093     default:
0094         break;
0095     }
0096 
0097     if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) {
0098         rtl_dbg(rtlpriv, COMP_POWER, DBG_LOUD,
0099             "40MHz finalpwr_idx (A / B) = 0x%x / 0x%x\n",
0100             p_final_pwridx[0], p_final_pwridx[1]);
0101     } else {
0102         rtl_dbg(rtlpriv, COMP_POWER, DBG_LOUD,
0103             "20MHz finalpwr_idx (A / B) = 0x%x / 0x%x\n",
0104             p_final_pwridx[0], p_final_pwridx[1]);
0105     }
0106 }
0107 
0108 static void _rtl92s_set_antennadiff(struct ieee80211_hw *hw,
0109                     u8 *p_final_pwridx)
0110 {
0111     struct rtl_priv *rtlpriv = rtl_priv(hw);
0112     struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
0113     struct rtl_phy *rtlphy = &(rtlpriv->phy);
0114     s8 ant_pwr_diff = 0;
0115     u32 u4reg_val = 0;
0116 
0117     if (rtlphy->rf_type == RF_2T2R) {
0118         ant_pwr_diff = p_final_pwridx[1] - p_final_pwridx[0];
0119 
0120         /* range is from 7~-8,
0121          * index = 0x0~0xf */
0122         if (ant_pwr_diff > 7)
0123             ant_pwr_diff = 7;
0124         if (ant_pwr_diff < -8)
0125             ant_pwr_diff = -8;
0126 
0127         rtl_dbg(rtlpriv, COMP_POWER, DBG_LOUD,
0128             "Antenna Diff from RF-B to RF-A = %d (0x%x)\n",
0129             ant_pwr_diff, ant_pwr_diff & 0xf);
0130 
0131         ant_pwr_diff &= 0xf;
0132     }
0133 
0134     /* Antenna TX power difference */
0135     rtlefuse->antenna_txpwdiff[2] = 0;/* RF-D, don't care */
0136     rtlefuse->antenna_txpwdiff[1] = 0;/* RF-C, don't care */
0137     rtlefuse->antenna_txpwdiff[0] = (u8)(ant_pwr_diff); /* RF-B */
0138 
0139     u4reg_val = rtlefuse->antenna_txpwdiff[2] << 8 |
0140                 rtlefuse->antenna_txpwdiff[1] << 4 |
0141                 rtlefuse->antenna_txpwdiff[0];
0142 
0143     rtl_set_bbreg(hw, RFPGA0_TXGAINSTAGE, (BXBTXAGC | BXCTXAGC | BXDTXAGC),
0144               u4reg_val);
0145 
0146     rtl_dbg(rtlpriv, COMP_POWER, DBG_LOUD, "Write BCD-Diff(0x%x) = 0x%x\n",
0147         RFPGA0_TXGAINSTAGE, u4reg_val);
0148 }
0149 
0150 static void _rtl92s_get_txpower_writeval_byregulatory(struct ieee80211_hw *hw,
0151                               u8 chnl, u8 index,
0152                               u32 pwrbase0,
0153                               u32 pwrbase1,
0154                               u32 *p_outwrite_val)
0155 {
0156     struct rtl_priv *rtlpriv = rtl_priv(hw);
0157     struct rtl_phy *rtlphy = &(rtlpriv->phy);
0158     struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
0159     u8 i, chnlgroup, pwrdiff_limit[4];
0160     u32 writeval, customer_limit;
0161 
0162     /* Index 0 & 1= legacy OFDM, 2-5=HT_MCS rate */
0163     switch (rtlefuse->eeprom_regulatory) {
0164     case 0:
0165         /* Realtek better performance increase power diff
0166          * defined by Realtek for large power */
0167         chnlgroup = 0;
0168 
0169         writeval = rtlphy->mcs_offset[chnlgroup][index] +
0170                 ((index < 2) ? pwrbase0 : pwrbase1);
0171 
0172         rtl_dbg(rtlpriv, COMP_POWER, DBG_LOUD,
0173             "RTK better performance, writeval = 0x%x\n", writeval);
0174         break;
0175     case 1:
0176         /* Realtek regulatory increase power diff defined
0177          * by Realtek for regulatory */
0178         if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) {
0179             writeval = ((index < 2) ? pwrbase0 : pwrbase1);
0180 
0181             rtl_dbg(rtlpriv, COMP_POWER, DBG_LOUD,
0182                 "Realtek regulatory, 40MHz, writeval = 0x%x\n",
0183                 writeval);
0184         } else {
0185             chnlgroup = 0;
0186 
0187             if (rtlphy->pwrgroup_cnt >= 3) {
0188                 if (chnl <= 3)
0189                     chnlgroup = 0;
0190                 else if (chnl >= 4 && chnl <= 8)
0191                     chnlgroup = 1;
0192                 else if (chnl > 8)
0193                     chnlgroup = 2;
0194                 if (rtlphy->pwrgroup_cnt == 4)
0195                     chnlgroup++;
0196             }
0197 
0198             writeval = rtlphy->mcs_offset[chnlgroup][index]
0199                     + ((index < 2) ?
0200                     pwrbase0 : pwrbase1);
0201 
0202             rtl_dbg(rtlpriv, COMP_POWER, DBG_LOUD,
0203                 "Realtek regulatory, 20MHz, writeval = 0x%x\n",
0204                 writeval);
0205         }
0206         break;
0207     case 2:
0208         /* Better regulatory don't increase any power diff */
0209         writeval = ((index < 2) ? pwrbase0 : pwrbase1);
0210         rtl_dbg(rtlpriv, COMP_POWER, DBG_LOUD,
0211             "Better regulatory, writeval = 0x%x\n", writeval);
0212         break;
0213     case 3:
0214         /* Customer defined power diff. increase power diff
0215           defined by customer. */
0216         chnlgroup = 0;
0217 
0218         if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) {
0219             rtl_dbg(rtlpriv, COMP_POWER, DBG_LOUD,
0220                 "customer's limit, 40MHz = 0x%x\n",
0221                 rtlefuse->pwrgroup_ht40
0222                 [RF90_PATH_A][chnl - 1]);
0223         } else {
0224             rtl_dbg(rtlpriv, COMP_POWER, DBG_LOUD,
0225                 "customer's limit, 20MHz = 0x%x\n",
0226                 rtlefuse->pwrgroup_ht20
0227                 [RF90_PATH_A][chnl - 1]);
0228         }
0229 
0230         for (i = 0; i < 4; i++) {
0231             pwrdiff_limit[i] = (u8)((rtlphy->mcs_offset
0232                 [chnlgroup][index] & (0x7f << (i * 8)))
0233                 >> (i * 8));
0234 
0235             if (rtlphy->current_chan_bw ==
0236                 HT_CHANNEL_WIDTH_20_40) {
0237                 if (pwrdiff_limit[i] >
0238                     rtlefuse->pwrgroup_ht40
0239                     [RF90_PATH_A][chnl - 1]) {
0240                     pwrdiff_limit[i] =
0241                       rtlefuse->pwrgroup_ht40
0242                       [RF90_PATH_A][chnl - 1];
0243                 }
0244             } else {
0245                 if (pwrdiff_limit[i] >
0246                     rtlefuse->pwrgroup_ht20
0247                     [RF90_PATH_A][chnl - 1]) {
0248                     pwrdiff_limit[i] =
0249                         rtlefuse->pwrgroup_ht20
0250                         [RF90_PATH_A][chnl - 1];
0251                 }
0252             }
0253         }
0254 
0255         customer_limit = (pwrdiff_limit[3] << 24) |
0256                 (pwrdiff_limit[2] << 16) |
0257                 (pwrdiff_limit[1] << 8) |
0258                 (pwrdiff_limit[0]);
0259         rtl_dbg(rtlpriv, COMP_POWER, DBG_LOUD,
0260             "Customer's limit = 0x%x\n", customer_limit);
0261 
0262         writeval = customer_limit + ((index < 2) ?
0263                          pwrbase0 : pwrbase1);
0264         rtl_dbg(rtlpriv, COMP_POWER, DBG_LOUD,
0265             "Customer, writeval = 0x%x\n", writeval);
0266         break;
0267     default:
0268         chnlgroup = 0;
0269         writeval = rtlphy->mcs_offset[chnlgroup][index] +
0270                 ((index < 2) ? pwrbase0 : pwrbase1);
0271         rtl_dbg(rtlpriv, COMP_POWER, DBG_LOUD,
0272             "RTK better performance, writeval = 0x%x\n", writeval);
0273         break;
0274     }
0275 
0276     if (rtlpriv->dm.dynamic_txhighpower_lvl == TX_HIGH_PWR_LEVEL_LEVEL1)
0277         writeval = 0x10101010;
0278     else if (rtlpriv->dm.dynamic_txhighpower_lvl ==
0279          TX_HIGH_PWR_LEVEL_LEVEL2)
0280         writeval = 0x0;
0281 
0282     *p_outwrite_val = writeval;
0283 
0284 }
0285 
0286 static void _rtl92s_write_ofdm_powerreg(struct ieee80211_hw *hw,
0287                     u8 index, u32 val)
0288 {
0289     struct rtl_priv *rtlpriv = rtl_priv(hw);
0290     struct rtl_phy *rtlphy = &(rtlpriv->phy);
0291     struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
0292     u16 regoffset[6] = {0xe00, 0xe04, 0xe10, 0xe14, 0xe18, 0xe1c};
0293     u8 i, rfa_pwr[4];
0294     u8 rfa_lower_bound = 0, rfa_upper_bound = 0, rf_pwr_diff = 0;
0295     u32 writeval = val;
0296 
0297     /* If path A and Path B coexist, we must limit Path A tx power.
0298      * Protect Path B pwr over or under flow. We need to calculate
0299      * upper and lower bound of path A tx power. */
0300     if (rtlphy->rf_type == RF_2T2R) {
0301         rf_pwr_diff = rtlefuse->antenna_txpwdiff[0];
0302 
0303         /* Diff=-8~-1 */
0304         if (rf_pwr_diff >= 8) {
0305             /* Prevent underflow!! */
0306             rfa_lower_bound = 0x10 - rf_pwr_diff;
0307         /* if (rf_pwr_diff >= 0) Diff = 0-7 */
0308         } else {
0309             rfa_upper_bound = RF6052_MAX_TX_PWR - rf_pwr_diff;
0310         }
0311     }
0312 
0313     for (i = 0; i < 4; i++) {
0314         rfa_pwr[i] = (u8)((writeval & (0x7f << (i * 8))) >> (i * 8));
0315         if (rfa_pwr[i]  > RF6052_MAX_TX_PWR)
0316             rfa_pwr[i]  = RF6052_MAX_TX_PWR;
0317 
0318         /* If path A and Path B coexist, we must limit Path A tx power.
0319          * Protect Path B pwr over or under flow. We need to calculate
0320          * upper and lower bound of path A tx power. */
0321         if (rtlphy->rf_type == RF_2T2R) {
0322             /* Diff=-8~-1 */
0323             if (rf_pwr_diff >= 8) {
0324                 /* Prevent underflow!! */
0325                 if (rfa_pwr[i] < rfa_lower_bound)
0326                     rfa_pwr[i] = rfa_lower_bound;
0327             /* Diff = 0-7 */
0328             } else if (rf_pwr_diff >= 1) {
0329                 /* Prevent overflow */
0330                 if (rfa_pwr[i] > rfa_upper_bound)
0331                     rfa_pwr[i] = rfa_upper_bound;
0332             }
0333         }
0334 
0335     }
0336 
0337     writeval = (rfa_pwr[3] << 24) | (rfa_pwr[2] << 16) | (rfa_pwr[1] << 8) |
0338                 rfa_pwr[0];
0339 
0340     rtl_set_bbreg(hw, regoffset[index], 0x7f7f7f7f, writeval);
0341 }
0342 
0343 void rtl92s_phy_rf6052_set_ofdmtxpower(struct ieee80211_hw *hw,
0344                        u8 *p_pwrlevel, u8 chnl)
0345 {
0346     u32 writeval, pwrbase0, pwrbase1;
0347     u8 index = 0;
0348     u8 finalpwr_idx[4];
0349 
0350     _rtl92s_get_powerbase(hw, p_pwrlevel, chnl, &pwrbase0, &pwrbase1,
0351             &finalpwr_idx[0]);
0352     _rtl92s_set_antennadiff(hw, &finalpwr_idx[0]);
0353 
0354     for (index = 0; index < 6; index++) {
0355         _rtl92s_get_txpower_writeval_byregulatory(hw, chnl, index,
0356                 pwrbase0, pwrbase1, &writeval);
0357 
0358         _rtl92s_write_ofdm_powerreg(hw, index, writeval);
0359     }
0360 }
0361 
0362 void rtl92s_phy_rf6052_set_ccktxpower(struct ieee80211_hw *hw, u8 pwrlevel)
0363 {
0364     struct rtl_priv *rtlpriv = rtl_priv(hw);
0365     struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
0366     struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
0367     u32 txagc = 0;
0368     bool dont_inc_cck_or_turboscanoff = false;
0369 
0370     if (((rtlefuse->eeprom_version >= 2) &&
0371           (rtlefuse->txpwr_safetyflag == 1)) ||
0372           ((rtlefuse->eeprom_version >= 2) &&
0373           (rtlefuse->eeprom_regulatory != 0)))
0374         dont_inc_cck_or_turboscanoff = true;
0375 
0376     if (mac->act_scanning) {
0377         txagc = 0x3f;
0378         if (dont_inc_cck_or_turboscanoff)
0379             txagc = pwrlevel;
0380     } else {
0381         txagc = pwrlevel;
0382 
0383         if (rtlpriv->dm.dynamic_txhighpower_lvl ==
0384             TX_HIGH_PWR_LEVEL_LEVEL1)
0385             txagc = 0x10;
0386         else if (rtlpriv->dm.dynamic_txhighpower_lvl ==
0387             TX_HIGH_PWR_LEVEL_LEVEL2)
0388             txagc = 0x0;
0389     }
0390 
0391     if (txagc > RF6052_MAX_TX_PWR)
0392         txagc = RF6052_MAX_TX_PWR;
0393 
0394     rtl_set_bbreg(hw, RTXAGC_CCK_MCS32, BTX_AGCRATECCK, txagc);
0395 
0396 }
0397 
0398 bool rtl92s_phy_rf6052_config(struct ieee80211_hw *hw)
0399 {
0400     struct rtl_priv *rtlpriv = rtl_priv(hw);
0401     struct rtl_phy *rtlphy = &(rtlpriv->phy);
0402     u32 u4reg_val = 0;
0403     u8 rfpath;
0404     bool rtstatus = true;
0405     struct bb_reg_def *pphyreg;
0406 
0407     /* Initialize RF */
0408     for (rfpath = 0; rfpath < rtlphy->num_total_rfpath; rfpath++) {
0409 
0410         pphyreg = &rtlphy->phyreg_def[rfpath];
0411 
0412         /* Store original RFENV control type */
0413         switch (rfpath) {
0414         case RF90_PATH_A:
0415         case RF90_PATH_C:
0416             u4reg_val = rtl92s_phy_query_bb_reg(hw,
0417                                 pphyreg->rfintfs,
0418                                 BRFSI_RFENV);
0419             break;
0420         case RF90_PATH_B:
0421         case RF90_PATH_D:
0422             u4reg_val = rtl92s_phy_query_bb_reg(hw,
0423                                 pphyreg->rfintfs,
0424                                 BRFSI_RFENV << 16);
0425             break;
0426         }
0427 
0428         /* Set RF_ENV enable */
0429         rtl92s_phy_set_bb_reg(hw, pphyreg->rfintfe,
0430                       BRFSI_RFENV << 16, 0x1);
0431 
0432         /* Set RF_ENV output high */
0433         rtl92s_phy_set_bb_reg(hw, pphyreg->rfintfo, BRFSI_RFENV, 0x1);
0434 
0435         /* Set bit number of Address and Data for RF register */
0436         rtl92s_phy_set_bb_reg(hw, pphyreg->rfhssi_para2,
0437                 B3WIRE_ADDRESSLENGTH, 0x0);
0438         rtl92s_phy_set_bb_reg(hw, pphyreg->rfhssi_para2,
0439                 B3WIRE_DATALENGTH, 0x0);
0440 
0441         /* Initialize RF fom connfiguration file */
0442         switch (rfpath) {
0443         case RF90_PATH_A:
0444             rtstatus = rtl92s_phy_config_rf(hw,
0445                         (enum radio_path)rfpath);
0446             break;
0447         case RF90_PATH_B:
0448             rtstatus = rtl92s_phy_config_rf(hw,
0449                         (enum radio_path)rfpath);
0450             break;
0451         case RF90_PATH_C:
0452             break;
0453         case RF90_PATH_D:
0454             break;
0455         }
0456 
0457         /* Restore RFENV control type */
0458         switch (rfpath) {
0459         case RF90_PATH_A:
0460         case RF90_PATH_C:
0461             rtl92s_phy_set_bb_reg(hw, pphyreg->rfintfs, BRFSI_RFENV,
0462                           u4reg_val);
0463             break;
0464         case RF90_PATH_B:
0465         case RF90_PATH_D:
0466             rtl92s_phy_set_bb_reg(hw, pphyreg->rfintfs,
0467                           BRFSI_RFENV << 16,
0468                           u4reg_val);
0469             break;
0470         }
0471 
0472         if (!rtstatus) {
0473             pr_err("Radio[%d] Fail!!\n", rfpath);
0474             goto fail;
0475         }
0476 
0477     }
0478 
0479     return rtstatus;
0480 
0481 fail:
0482     return rtstatus;
0483 }
0484 
0485 void rtl92s_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw, u8 bandwidth)
0486 {
0487     struct rtl_priv *rtlpriv = rtl_priv(hw);
0488     struct rtl_phy *rtlphy = &(rtlpriv->phy);
0489 
0490     switch (bandwidth) {
0491     case HT_CHANNEL_WIDTH_20:
0492         rtlphy->rfreg_chnlval[0] = ((rtlphy->rfreg_chnlval[0] &
0493                        0xfffff3ff) | 0x0400);
0494         rtl_set_rfreg(hw, RF90_PATH_A, RF_CHNLBW, RFREG_OFFSET_MASK,
0495                     rtlphy->rfreg_chnlval[0]);
0496         break;
0497     case HT_CHANNEL_WIDTH_20_40:
0498         rtlphy->rfreg_chnlval[0] = ((rtlphy->rfreg_chnlval[0] &
0499                         0xfffff3ff));
0500         rtl_set_rfreg(hw, RF90_PATH_A, RF_CHNLBW, RFREG_OFFSET_MASK,
0501                     rtlphy->rfreg_chnlval[0]);
0502         break;
0503     default:
0504         pr_err("unknown bandwidth: %#X\n", bandwidth);
0505         break;
0506     }
0507 }