483 lines · c
1// SPDX-License-Identifier: GPL-2.02/* 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 11static bool _rtl92ce_phy_rf6052_config_parafile(struct ieee80211_hw *hw);12 13void rtl92ce_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw, u8 bandwidth)14{15 struct rtl_priv *rtlpriv = rtl_priv(hw);16 struct rtl_phy *rtlphy = &(rtlpriv->phy);17 18 switch (bandwidth) {19 case HT_CHANNEL_WIDTH_20:20 rtlphy->rfreg_chnlval[0] = ((rtlphy->rfreg_chnlval[0] &21 0xfffff3ff) | 0x0400);22 rtl_set_rfreg(hw, RF90_PATH_A, RF_CHNLBW, RFREG_OFFSET_MASK,23 rtlphy->rfreg_chnlval[0]);24 break;25 case HT_CHANNEL_WIDTH_20_40:26 rtlphy->rfreg_chnlval[0] = ((rtlphy->rfreg_chnlval[0] &27 0xfffff3ff));28 rtl_set_rfreg(hw, RF90_PATH_A, RF_CHNLBW, RFREG_OFFSET_MASK,29 rtlphy->rfreg_chnlval[0]);30 break;31 default:32 pr_err("unknown bandwidth: %#X\n", bandwidth);33 break;34 }35}36 37void rtl92ce_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw,38 u8 *ppowerlevel)39{40 struct rtl_priv *rtlpriv = rtl_priv(hw);41 struct rtl_phy *rtlphy = &(rtlpriv->phy);42 struct rtl_mac *mac = rtl_mac(rtl_priv(hw));43 struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));44 u32 tx_agc[2] = {0, 0}, tmpval;45 bool turbo_scanoff = false;46 u8 idx1, idx2;47 u8 *ptr;48 49 if (rtlefuse->eeprom_regulatory != 0)50 turbo_scanoff = true;51 52 if (mac->act_scanning) {53 tx_agc[RF90_PATH_A] = 0x3f3f3f3f;54 tx_agc[RF90_PATH_B] = 0x3f3f3f3f;55 56 if (turbo_scanoff) {57 for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B; idx1++) {58 tx_agc[idx1] = ppowerlevel[idx1] |59 (ppowerlevel[idx1] << 8) |60 (ppowerlevel[idx1] << 16) |61 (ppowerlevel[idx1] << 24);62 }63 }64 } else {65 for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B; idx1++) {66 tx_agc[idx1] = ppowerlevel[idx1] |67 (ppowerlevel[idx1] << 8) |68 (ppowerlevel[idx1] << 16) |69 (ppowerlevel[idx1] << 24);70 }71 72 if (rtlefuse->eeprom_regulatory == 0) {73 tmpval = (rtlphy->mcs_offset[0][6]) +74 (rtlphy->mcs_offset[0][7] << 8);75 tx_agc[RF90_PATH_A] += tmpval;76 77 tmpval = (rtlphy->mcs_offset[0][14]) +78 (rtlphy->mcs_offset[0][15] << 24);79 tx_agc[RF90_PATH_B] += tmpval;80 }81 }82 83 for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B; idx1++) {84 ptr = (u8 *) (&(tx_agc[idx1]));85 for (idx2 = 0; idx2 < 4; idx2++) {86 if (*ptr > RF6052_MAX_TX_PWR)87 *ptr = RF6052_MAX_TX_PWR;88 ptr++;89 }90 }91 92 tmpval = tx_agc[RF90_PATH_A] & 0xff;93 rtl_set_bbreg(hw, RTXAGC_A_CCK1_MCS32, MASKBYTE1, tmpval);94 95 RTPRINT(rtlpriv, FPHY, PHY_TXPWR,96 "CCK PWR 1M (rf-A) = 0x%x (reg 0x%x)\n",97 tmpval, RTXAGC_A_CCK1_MCS32);98 99 tmpval = tx_agc[RF90_PATH_A] >> 8;100 101 tmpval = tmpval & 0xff00ffff;102 103 rtl_set_bbreg(hw, RTXAGC_B_CCK11_A_CCK2_11, 0xffffff00, tmpval);104 105 RTPRINT(rtlpriv, FPHY, PHY_TXPWR,106 "CCK PWR 2~11M (rf-A) = 0x%x (reg 0x%x)\n",107 tmpval, RTXAGC_B_CCK11_A_CCK2_11);108 109 tmpval = tx_agc[RF90_PATH_B] >> 24;110 rtl_set_bbreg(hw, RTXAGC_B_CCK11_A_CCK2_11, MASKBYTE0, tmpval);111 112 RTPRINT(rtlpriv, FPHY, PHY_TXPWR,113 "CCK PWR 11M (rf-B) = 0x%x (reg 0x%x)\n",114 tmpval, RTXAGC_B_CCK11_A_CCK2_11);115 116 tmpval = tx_agc[RF90_PATH_B] & 0x00ffffff;117 rtl_set_bbreg(hw, RTXAGC_B_CCK1_55_MCS32, 0xffffff00, tmpval);118 119 RTPRINT(rtlpriv, FPHY, PHY_TXPWR,120 "CCK PWR 1~5.5M (rf-B) = 0x%x (reg 0x%x)\n",121 tmpval, RTXAGC_B_CCK1_55_MCS32);122}123 124static void rtl92c_phy_get_power_base(struct ieee80211_hw *hw,125 u8 *ppowerlevel, u8 channel,126 u32 *ofdmbase, u32 *mcsbase)127{128 struct rtl_priv *rtlpriv = rtl_priv(hw);129 struct rtl_phy *rtlphy = &(rtlpriv->phy);130 struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));131 u32 powerbase0, powerbase1;132 u8 legacy_pwrdiff, ht20_pwrdiff;133 u8 i, powerlevel[2];134 135 for (i = 0; i < 2; i++) {136 powerlevel[i] = ppowerlevel[i];137 legacy_pwrdiff = rtlefuse->txpwr_legacyhtdiff[i][channel - 1];138 powerbase0 = powerlevel[i] + legacy_pwrdiff;139 140 powerbase0 = (powerbase0 << 24) | (powerbase0 << 16) |141 (powerbase0 << 8) | powerbase0;142 *(ofdmbase + i) = powerbase0;143 RTPRINT(rtlpriv, FPHY, PHY_TXPWR,144 " [OFDM power base index rf(%c) = 0x%x]\n",145 i == 0 ? 'A' : 'B', *(ofdmbase + i));146 }147 148 for (i = 0; i < 2; i++) {149 if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20) {150 ht20_pwrdiff = rtlefuse->txpwr_ht20diff[i][channel - 1];151 powerlevel[i] += ht20_pwrdiff;152 }153 powerbase1 = powerlevel[i];154 powerbase1 = (powerbase1 << 24) |155 (powerbase1 << 16) | (powerbase1 << 8) | powerbase1;156 157 *(mcsbase + i) = powerbase1;158 159 RTPRINT(rtlpriv, FPHY, PHY_TXPWR,160 " [MCS power base index rf(%c) = 0x%x]\n",161 i == 0 ? 'A' : 'B', *(mcsbase + i));162 }163}164 165static void _rtl92c_get_txpower_writeval_by_regulatory(struct ieee80211_hw *hw,166 u8 channel, u8 index,167 u32 *powerbase0,168 u32 *powerbase1,169 u32 *p_outwriteval)170{171 struct rtl_priv *rtlpriv = rtl_priv(hw);172 struct rtl_phy *rtlphy = &(rtlpriv->phy);173 struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));174 u8 i, chnlgroup = 0, pwr_diff_limit[4];175 u32 writeval, customer_limit, rf;176 177 for (rf = 0; rf < 2; rf++) {178 switch (rtlefuse->eeprom_regulatory) {179 case 0:180 chnlgroup = 0;181 182 writeval = rtlphy->mcs_offset[chnlgroup][index +183 (rf ? 8 : 0)]184 + ((index < 2) ? powerbase0[rf] : powerbase1[rf]);185 186 RTPRINT(rtlpriv, FPHY, PHY_TXPWR,187 "RTK better performance, writeval(%c) = 0x%x\n",188 rf == 0 ? 'A' : 'B', writeval);189 break;190 case 1:191 if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) {192 writeval = ((index < 2) ? powerbase0[rf] :193 powerbase1[rf]);194 195 RTPRINT(rtlpriv, FPHY, PHY_TXPWR,196 "Realtek regulatory, 40MHz, writeval(%c) = 0x%x\n",197 rf == 0 ? 'A' : 'B', writeval);198 } else {199 if (rtlphy->pwrgroup_cnt == 1)200 chnlgroup = 0;201 if (rtlphy->pwrgroup_cnt >= 3) {202 if (channel <= 3)203 chnlgroup = 0;204 else if (channel >= 4 && channel <= 9)205 chnlgroup = 1;206 else if (channel > 9)207 chnlgroup = 2;208 if (rtlphy->pwrgroup_cnt == 4)209 chnlgroup++;210 }211 212 writeval = rtlphy->mcs_offset[chnlgroup]213 [index + (rf ? 8 : 0)] + ((index < 2) ?214 powerbase0[rf] :215 powerbase1[rf]);216 217 RTPRINT(rtlpriv, FPHY, PHY_TXPWR,218 "Realtek regulatory, 20MHz, writeval(%c) = 0x%x\n",219 rf == 0 ? 'A' : 'B', writeval);220 }221 break;222 case 2:223 writeval =224 ((index < 2) ? powerbase0[rf] : powerbase1[rf]);225 226 RTPRINT(rtlpriv, FPHY, PHY_TXPWR,227 "Better regulatory, writeval(%c) = 0x%x\n",228 rf == 0 ? 'A' : 'B', writeval);229 break;230 case 3:231 chnlgroup = 0;232 233 if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) {234 RTPRINT(rtlpriv, FPHY, PHY_TXPWR,235 "customer's limit, 40MHz rf(%c) = 0x%x\n",236 rf == 0 ? 'A' : 'B',237 rtlefuse->pwrgroup_ht40[rf][channel -238 1]);239 } else {240 RTPRINT(rtlpriv, FPHY, PHY_TXPWR,241 "customer's limit, 20MHz rf(%c) = 0x%x\n",242 rf == 0 ? 'A' : 'B',243 rtlefuse->pwrgroup_ht20[rf][channel -244 1]);245 }246 for (i = 0; i < 4; i++) {247 pwr_diff_limit[i] = (u8) ((rtlphy->mcs_offset248 [chnlgroup][index +249 (rf ? 8 : 0)] & (0x7f << (i * 8))) >>250 (i * 8));251 252 if (rtlphy->current_chan_bw ==253 HT_CHANNEL_WIDTH_20_40) {254 if (pwr_diff_limit[i] >255 rtlefuse->256 pwrgroup_ht40[rf][channel - 1])257 pwr_diff_limit[i] =258 rtlefuse->pwrgroup_ht40[rf]259 [channel - 1];260 } else {261 if (pwr_diff_limit[i] >262 rtlefuse->263 pwrgroup_ht20[rf][channel - 1])264 pwr_diff_limit[i] =265 rtlefuse->pwrgroup_ht20[rf]266 [channel - 1];267 }268 }269 270 customer_limit = (pwr_diff_limit[3] << 24) |271 (pwr_diff_limit[2] << 16) |272 (pwr_diff_limit[1] << 8) | (pwr_diff_limit[0]);273 274 RTPRINT(rtlpriv, FPHY, PHY_TXPWR,275 "Customer's limit rf(%c) = 0x%x\n",276 rf == 0 ? 'A' : 'B', customer_limit);277 278 writeval = customer_limit +279 ((index < 2) ? powerbase0[rf] : powerbase1[rf]);280 281 RTPRINT(rtlpriv, FPHY, PHY_TXPWR,282 "Customer, writeval rf(%c)= 0x%x\n",283 rf == 0 ? 'A' : 'B', writeval);284 break;285 default:286 chnlgroup = 0;287 writeval = rtlphy->mcs_offset[chnlgroup]288 [index + (rf ? 8 : 0)]289 + ((index < 2) ? powerbase0[rf] : powerbase1[rf]);290 291 RTPRINT(rtlpriv, FPHY, PHY_TXPWR,292 "RTK better performance, writeval rf(%c) = 0x%x\n",293 rf == 0 ? 'A' : 'B', writeval);294 break;295 }296 297 if (rtlpriv->dm.dynamic_txhighpower_lvl == TXHIGHPWRLEVEL_BT1)298 writeval = writeval - 0x06060606;299 else if (rtlpriv->dm.dynamic_txhighpower_lvl ==300 TXHIGHPWRLEVEL_BT2)301 writeval = writeval - 0x0c0c0c0c;302 *(p_outwriteval + rf) = writeval;303 }304}305 306static void _rtl92c_write_ofdm_power_reg(struct ieee80211_hw *hw,307 u8 index, u32 *value)308{309 struct rtl_priv *rtlpriv = rtl_priv(hw);310 struct rtl_phy *rtlphy = &(rtlpriv->phy);311 312 u16 regoffset_a[6] = {313 RTXAGC_A_RATE18_06, RTXAGC_A_RATE54_24,314 RTXAGC_A_MCS03_MCS00, RTXAGC_A_MCS07_MCS04,315 RTXAGC_A_MCS11_MCS08, RTXAGC_A_MCS15_MCS12316 };317 u16 regoffset_b[6] = {318 RTXAGC_B_RATE18_06, RTXAGC_B_RATE54_24,319 RTXAGC_B_MCS03_MCS00, RTXAGC_B_MCS07_MCS04,320 RTXAGC_B_MCS11_MCS08, RTXAGC_B_MCS15_MCS12321 };322 u8 i, rf, pwr_val[4];323 u32 writeval;324 u16 regoffset;325 326 for (rf = 0; rf < 2; rf++) {327 writeval = value[rf];328 for (i = 0; i < 4; i++) {329 pwr_val[i] = (u8)((writeval & (0x7f <<330 (i * 8))) >> (i * 8));331 332 if (pwr_val[i] > RF6052_MAX_TX_PWR)333 pwr_val[i] = RF6052_MAX_TX_PWR;334 }335 writeval = (pwr_val[3] << 24) | (pwr_val[2] << 16) |336 (pwr_val[1] << 8) | pwr_val[0];337 338 if (rf == 0)339 regoffset = regoffset_a[index];340 else341 regoffset = regoffset_b[index];342 rtl_set_bbreg(hw, regoffset, MASKDWORD, writeval);343 344 RTPRINT(rtlpriv, FPHY, PHY_TXPWR,345 "Set 0x%x = %08x\n", regoffset, writeval);346 347 if (((get_rf_type(rtlphy) == RF_2T2R) &&348 (regoffset == RTXAGC_A_MCS15_MCS12 ||349 regoffset == RTXAGC_B_MCS15_MCS12)) ||350 ((get_rf_type(rtlphy) != RF_2T2R) &&351 (regoffset == RTXAGC_A_MCS07_MCS04 ||352 regoffset == RTXAGC_B_MCS07_MCS04))) {353 354 writeval = pwr_val[3];355 if (regoffset == RTXAGC_A_MCS15_MCS12 ||356 regoffset == RTXAGC_A_MCS07_MCS04)357 regoffset = 0xc90;358 if (regoffset == RTXAGC_B_MCS15_MCS12 ||359 regoffset == RTXAGC_B_MCS07_MCS04)360 regoffset = 0xc98;361 362 for (i = 0; i < 3; i++) {363 writeval = (writeval > 6) ? (writeval - 6) : 0;364 rtl_write_byte(rtlpriv, (u32) (regoffset + i),365 (u8)writeval);366 }367 }368 }369}370 371void rtl92ce_phy_rf6052_set_ofdm_txpower(struct ieee80211_hw *hw,372 u8 *ppowerlevel, u8 channel)373{374 u32 writeval[2], powerbase0[2], powerbase1[2];375 u8 index;376 377 rtl92c_phy_get_power_base(hw, ppowerlevel,378 channel, &powerbase0[0], &powerbase1[0]);379 380 for (index = 0; index < 6; index++) {381 _rtl92c_get_txpower_writeval_by_regulatory(hw,382 channel, index,383 &powerbase0[0],384 &powerbase1[0],385 &writeval[0]);386 387 _rtl92c_write_ofdm_power_reg(hw, index, &writeval[0]);388 }389}390 391bool rtl92ce_phy_rf6052_config(struct ieee80211_hw *hw)392{393 struct rtl_priv *rtlpriv = rtl_priv(hw);394 struct rtl_phy *rtlphy = &(rtlpriv->phy);395 396 if (rtlphy->rf_type == RF_1T1R)397 rtlphy->num_total_rfpath = 1;398 else399 rtlphy->num_total_rfpath = 2;400 401 return _rtl92ce_phy_rf6052_config_parafile(hw);402 403}404 405static bool _rtl92ce_phy_rf6052_config_parafile(struct ieee80211_hw *hw)406{407 struct rtl_priv *rtlpriv = rtl_priv(hw);408 struct rtl_phy *rtlphy = &(rtlpriv->phy);409 u32 u4_regvalue = 0;410 u8 rfpath;411 bool rtstatus = true;412 struct bb_reg_def *pphyreg;413 414 for (rfpath = 0; rfpath < rtlphy->num_total_rfpath; rfpath++) {415 416 pphyreg = &rtlphy->phyreg_def[rfpath];417 418 switch (rfpath) {419 case RF90_PATH_A:420 case RF90_PATH_C:421 u4_regvalue = rtl_get_bbreg(hw, pphyreg->rfintfs,422 BRFSI_RFENV);423 break;424 case RF90_PATH_B:425 case RF90_PATH_D:426 u4_regvalue = rtl_get_bbreg(hw, pphyreg->rfintfs,427 BRFSI_RFENV << 16);428 break;429 }430 431 rtl_set_bbreg(hw, pphyreg->rfintfe, BRFSI_RFENV << 16, 0x1);432 udelay(1);433 434 rtl_set_bbreg(hw, pphyreg->rfintfo, BRFSI_RFENV, 0x1);435 udelay(1);436 437 rtl_set_bbreg(hw, pphyreg->rfhssi_para2,438 B3WIREADDREAALENGTH, 0x0);439 udelay(1);440 441 rtl_set_bbreg(hw, pphyreg->rfhssi_para2, B3WIREDATALENGTH, 0x0);442 udelay(1);443 444 switch (rfpath) {445 case RF90_PATH_A:446 rtstatus = rtl92c_phy_config_rf_with_headerfile(hw,447 (enum radio_path)rfpath);448 break;449 case RF90_PATH_B:450 rtstatus = rtl92c_phy_config_rf_with_headerfile(hw,451 (enum radio_path)rfpath);452 break;453 case RF90_PATH_C:454 break;455 case RF90_PATH_D:456 break;457 }458 459 switch (rfpath) {460 case RF90_PATH_A:461 case RF90_PATH_C:462 rtl_set_bbreg(hw, pphyreg->rfintfs,463 BRFSI_RFENV, u4_regvalue);464 break;465 case RF90_PATH_B:466 case RF90_PATH_D:467 rtl_set_bbreg(hw, pphyreg->rfintfs,468 BRFSI_RFENV << 16, u4_regvalue);469 break;470 }471 472 if (!rtstatus) {473 rtl_dbg(rtlpriv, COMP_INIT, DBG_TRACE,474 "Radio[%d] Fail!!\n", rfpath);475 return false;476 }477 478 }479 480 rtl_dbg(rtlpriv, COMP_INIT, DBG_TRACE, "<---\n");481 return rtstatus;482}483