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 12 static 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_httxpowerdiff & 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 RT_TRACE(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 RT_TRACE(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 108 static 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 RT_TRACE(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 RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, "Write BCD-Diff(0x%x) = 0x%x\n", 147 RFPGA0_TXGAINSTAGE, u4reg_val); 148 } 149 150 static 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 RT_TRACE(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 RT_TRACE(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 RT_TRACE(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 RT_TRACE(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 RT_TRACE(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 RT_TRACE(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 RT_TRACE(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 RT_TRACE(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 RT_TRACE(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 286 static 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 343 void 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 362 void 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 398 bool 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 481 fail: 482 return rtstatus; 483 } 484 485 void 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