1 /****************************************************************************** 2 * 3 * Copyright(c) 2009-2012 Realtek Corporation. 4 * 5 * This program is free software; you can redistribute it and/or modify it 6 * under the terms of version 2 of the GNU General Public License as 7 * published by the Free Software Foundation. 8 * 9 * This program is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 12 * more details. 13 * 14 * You should have received a copy of the GNU General Public License along with 15 * this program; if not, write to the Free Software Foundation, Inc., 16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA 17 * 18 * The full GNU General Public License is included in this distribution in the 19 * file called LICENSE. 20 * 21 * Contact Information: 22 * wlanfae <wlanfae@realtek.com> 23 * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, 24 * Hsinchu 300, Taiwan. 25 * 26 * Larry Finger <Larry.Finger@lwfinger.net> 27 * 28 *****************************************************************************/ 29 30 #include "../wifi.h" 31 #include "reg.h" 32 #include "def.h" 33 #include "phy.h" 34 #include "rf.h" 35 #include "dm.h" 36 37 38 static void _rtl92s_get_powerbase(struct ieee80211_hw *hw, u8 *p_pwrlevel, 39 u8 chnl, u32 *ofdmbase, u32 *mcsbase, 40 u8 *p_final_pwridx) 41 { 42 struct rtl_priv *rtlpriv = rtl_priv(hw); 43 struct rtl_phy *rtlphy = &(rtlpriv->phy); 44 struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); 45 u32 pwrbase0, pwrbase1; 46 u8 legacy_pwrdiff = 0, ht20_pwrdiff = 0; 47 u8 i, pwrlevel[4]; 48 49 for (i = 0; i < 2; i++) 50 pwrlevel[i] = p_pwrlevel[i]; 51 52 /* We only care about the path A for legacy. */ 53 if (rtlefuse->eeprom_version < 2) { 54 pwrbase0 = pwrlevel[0] + (rtlefuse->legacy_httxpowerdiff & 0xf); 55 } else { 56 legacy_pwrdiff = rtlefuse->txpwr_legacyhtdiff 57 [RF90_PATH_A][chnl - 1]; 58 59 /* For legacy OFDM, tx pwr always > HT OFDM pwr. 60 * We do not care Path B 61 * legacy OFDM pwr diff. NO BB register 62 * to notify HW. */ 63 pwrbase0 = pwrlevel[0] + legacy_pwrdiff; 64 } 65 66 pwrbase0 = (pwrbase0 << 24) | (pwrbase0 << 16) | (pwrbase0 << 8) | 67 pwrbase0; 68 *ofdmbase = pwrbase0; 69 70 /* MCS rates */ 71 if (rtlefuse->eeprom_version >= 2) { 72 /* Check HT20 to HT40 diff */ 73 if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20) { 74 for (i = 0; i < 2; i++) { 75 /* rf-A, rf-B */ 76 /* HT 20<->40 pwr diff */ 77 ht20_pwrdiff = rtlefuse->txpwr_ht20diff 78 [i][chnl - 1]; 79 80 if (ht20_pwrdiff < 8) /* 0~+7 */ 81 pwrlevel[i] += ht20_pwrdiff; 82 else /* index8-15=-8~-1 */ 83 pwrlevel[i] -= (16 - ht20_pwrdiff); 84 } 85 } 86 } 87 88 /* use index of rf-A */ 89 pwrbase1 = pwrlevel[0]; 90 pwrbase1 = (pwrbase1 << 24) | (pwrbase1 << 16) | (pwrbase1 << 8) | 91 pwrbase1; 92 *mcsbase = pwrbase1; 93 94 /* The following is for Antenna 95 * diff from Ant-B to Ant-A */ 96 p_final_pwridx[0] = pwrlevel[0]; 97 p_final_pwridx[1] = pwrlevel[1]; 98 99 switch (rtlefuse->eeprom_regulatory) { 100 case 3: 101 /* The following is for calculation 102 * of the power diff for Ant-B to Ant-A. */ 103 if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) { 104 p_final_pwridx[0] += rtlefuse->pwrgroup_ht40 105 [RF90_PATH_A][ 106 chnl - 1]; 107 p_final_pwridx[1] += rtlefuse->pwrgroup_ht40 108 [RF90_PATH_B][ 109 chnl - 1]; 110 } else { 111 p_final_pwridx[0] += rtlefuse->pwrgroup_ht20 112 [RF90_PATH_A][ 113 chnl - 1]; 114 p_final_pwridx[1] += rtlefuse->pwrgroup_ht20 115 [RF90_PATH_B][ 116 chnl - 1]; 117 } 118 break; 119 default: 120 break; 121 } 122 123 if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) { 124 RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, 125 "40MHz finalpwr_idx (A / B) = 0x%x / 0x%x\n", 126 p_final_pwridx[0], p_final_pwridx[1]); 127 } else { 128 RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, 129 "20MHz finalpwr_idx (A / B) = 0x%x / 0x%x\n", 130 p_final_pwridx[0], p_final_pwridx[1]); 131 } 132 } 133 134 static void _rtl92s_set_antennadiff(struct ieee80211_hw *hw, 135 u8 *p_final_pwridx) 136 { 137 struct rtl_priv *rtlpriv = rtl_priv(hw); 138 struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); 139 struct rtl_phy *rtlphy = &(rtlpriv->phy); 140 char ant_pwr_diff = 0; 141 u32 u4reg_val = 0; 142 143 if (rtlphy->rf_type == RF_2T2R) { 144 ant_pwr_diff = p_final_pwridx[1] - p_final_pwridx[0]; 145 146 /* range is from 7~-8, 147 * index = 0x0~0xf */ 148 if (ant_pwr_diff > 7) 149 ant_pwr_diff = 7; 150 if (ant_pwr_diff < -8) 151 ant_pwr_diff = -8; 152 153 RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, 154 "Antenna Diff from RF-B to RF-A = %d (0x%x)\n", 155 ant_pwr_diff, ant_pwr_diff & 0xf); 156 157 ant_pwr_diff &= 0xf; 158 } 159 160 /* Antenna TX power difference */ 161 rtlefuse->antenna_txpwdiff[2] = 0;/* RF-D, don't care */ 162 rtlefuse->antenna_txpwdiff[1] = 0;/* RF-C, don't care */ 163 rtlefuse->antenna_txpwdiff[0] = (u8)(ant_pwr_diff); /* RF-B */ 164 165 u4reg_val = rtlefuse->antenna_txpwdiff[2] << 8 | 166 rtlefuse->antenna_txpwdiff[1] << 4 | 167 rtlefuse->antenna_txpwdiff[0]; 168 169 rtl_set_bbreg(hw, RFPGA0_TXGAINSTAGE, (BXBTXAGC | BXCTXAGC | BXDTXAGC), 170 u4reg_val); 171 172 RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, "Write BCD-Diff(0x%x) = 0x%x\n", 173 RFPGA0_TXGAINSTAGE, u4reg_val); 174 } 175 176 static void _rtl92s_get_txpower_writeval_byregulatory(struct ieee80211_hw *hw, 177 u8 chnl, u8 index, 178 u32 pwrbase0, 179 u32 pwrbase1, 180 u32 *p_outwrite_val) 181 { 182 struct rtl_priv *rtlpriv = rtl_priv(hw); 183 struct rtl_phy *rtlphy = &(rtlpriv->phy); 184 struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); 185 u8 i, chnlgroup, pwrdiff_limit[4]; 186 u32 writeval, customer_limit; 187 188 /* Index 0 & 1= legacy OFDM, 2-5=HT_MCS rate */ 189 switch (rtlefuse->eeprom_regulatory) { 190 case 0: 191 /* Realtek better performance increase power diff 192 * defined by Realtek for large power */ 193 chnlgroup = 0; 194 195 writeval = rtlphy->mcs_offset[chnlgroup][index] + 196 ((index < 2) ? pwrbase0 : pwrbase1); 197 198 RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, 199 "RTK better performance, writeval = 0x%x\n", writeval); 200 break; 201 case 1: 202 /* Realtek regulatory increase power diff defined 203 * by Realtek for regulatory */ 204 if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) { 205 writeval = ((index < 2) ? pwrbase0 : pwrbase1); 206 207 RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, 208 "Realtek regulatory, 40MHz, writeval = 0x%x\n", 209 writeval); 210 } else { 211 chnlgroup = 0; 212 213 if (rtlphy->pwrgroup_cnt >= 3) { 214 if (chnl <= 3) 215 chnlgroup = 0; 216 else if (chnl >= 4 && chnl <= 8) 217 chnlgroup = 1; 218 else if (chnl > 8) 219 chnlgroup = 2; 220 if (rtlphy->pwrgroup_cnt == 4) 221 chnlgroup++; 222 } 223 224 writeval = rtlphy->mcs_offset[chnlgroup][index] 225 + ((index < 2) ? 226 pwrbase0 : pwrbase1); 227 228 RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, 229 "Realtek regulatory, 20MHz, writeval = 0x%x\n", 230 writeval); 231 } 232 break; 233 case 2: 234 /* Better regulatory don't increase any power diff */ 235 writeval = ((index < 2) ? pwrbase0 : pwrbase1); 236 RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, 237 "Better regulatory, writeval = 0x%x\n", writeval); 238 break; 239 case 3: 240 /* Customer defined power diff. increase power diff 241 defined by customer. */ 242 chnlgroup = 0; 243 244 if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) { 245 RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, 246 "customer's limit, 40MHz = 0x%x\n", 247 rtlefuse->pwrgroup_ht40 248 [RF90_PATH_A][chnl - 1]); 249 } else { 250 RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, 251 "customer's limit, 20MHz = 0x%x\n", 252 rtlefuse->pwrgroup_ht20 253 [RF90_PATH_A][chnl - 1]); 254 } 255 256 for (i = 0; i < 4; i++) { 257 pwrdiff_limit[i] = (u8)((rtlphy->mcs_offset 258 [chnlgroup][index] & (0x7f << (i * 8))) 259 >> (i * 8)); 260 261 if (rtlphy->current_chan_bw == 262 HT_CHANNEL_WIDTH_20_40) { 263 if (pwrdiff_limit[i] > 264 rtlefuse->pwrgroup_ht40 265 [RF90_PATH_A][chnl - 1]) { 266 pwrdiff_limit[i] = 267 rtlefuse->pwrgroup_ht40 268 [RF90_PATH_A][chnl - 1]; 269 } 270 } else { 271 if (pwrdiff_limit[i] > 272 rtlefuse->pwrgroup_ht20 273 [RF90_PATH_A][chnl - 1]) { 274 pwrdiff_limit[i] = 275 rtlefuse->pwrgroup_ht20 276 [RF90_PATH_A][chnl - 1]; 277 } 278 } 279 } 280 281 customer_limit = (pwrdiff_limit[3] << 24) | 282 (pwrdiff_limit[2] << 16) | 283 (pwrdiff_limit[1] << 8) | 284 (pwrdiff_limit[0]); 285 RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, 286 "Customer's limit = 0x%x\n", customer_limit); 287 288 writeval = customer_limit + ((index < 2) ? 289 pwrbase0 : pwrbase1); 290 RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, 291 "Customer, writeval = 0x%x\n", writeval); 292 break; 293 default: 294 chnlgroup = 0; 295 writeval = rtlphy->mcs_offset[chnlgroup][index] + 296 ((index < 2) ? pwrbase0 : pwrbase1); 297 RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, 298 "RTK better performance, writeval = 0x%x\n", writeval); 299 break; 300 } 301 302 if (rtlpriv->dm.dynamic_txhighpower_lvl == TX_HIGH_PWR_LEVEL_LEVEL1) 303 writeval = 0x10101010; 304 else if (rtlpriv->dm.dynamic_txhighpower_lvl == 305 TX_HIGH_PWR_LEVEL_LEVEL2) 306 writeval = 0x0; 307 308 *p_outwrite_val = writeval; 309 310 } 311 312 static void _rtl92s_write_ofdm_powerreg(struct ieee80211_hw *hw, 313 u8 index, u32 val) 314 { 315 struct rtl_priv *rtlpriv = rtl_priv(hw); 316 struct rtl_phy *rtlphy = &(rtlpriv->phy); 317 struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); 318 u16 regoffset[6] = {0xe00, 0xe04, 0xe10, 0xe14, 0xe18, 0xe1c}; 319 u8 i, rfa_pwr[4]; 320 u8 rfa_lower_bound = 0, rfa_upper_bound = 0, rf_pwr_diff = 0; 321 u32 writeval = val; 322 323 /* If path A and Path B coexist, we must limit Path A tx power. 324 * Protect Path B pwr over or under flow. We need to calculate 325 * upper and lower bound of path A tx power. */ 326 if (rtlphy->rf_type == RF_2T2R) { 327 rf_pwr_diff = rtlefuse->antenna_txpwdiff[0]; 328 329 /* Diff=-8~-1 */ 330 if (rf_pwr_diff >= 8) { 331 /* Prevent underflow!! */ 332 rfa_lower_bound = 0x10 - rf_pwr_diff; 333 /* if (rf_pwr_diff >= 0) Diff = 0-7 */ 334 } else { 335 rfa_upper_bound = RF6052_MAX_TX_PWR - rf_pwr_diff; 336 } 337 } 338 339 for (i = 0; i < 4; i++) { 340 rfa_pwr[i] = (u8)((writeval & (0x7f << (i * 8))) >> (i * 8)); 341 if (rfa_pwr[i] > RF6052_MAX_TX_PWR) 342 rfa_pwr[i] = RF6052_MAX_TX_PWR; 343 344 /* If path A and Path B coexist, we must limit Path A tx power. 345 * Protect Path B pwr over or under flow. We need to calculate 346 * upper and lower bound of path A tx power. */ 347 if (rtlphy->rf_type == RF_2T2R) { 348 /* Diff=-8~-1 */ 349 if (rf_pwr_diff >= 8) { 350 /* Prevent underflow!! */ 351 if (rfa_pwr[i] < rfa_lower_bound) 352 rfa_pwr[i] = rfa_lower_bound; 353 /* Diff = 0-7 */ 354 } else if (rf_pwr_diff >= 1) { 355 /* Prevent overflow */ 356 if (rfa_pwr[i] > rfa_upper_bound) 357 rfa_pwr[i] = rfa_upper_bound; 358 } 359 } 360 361 } 362 363 writeval = (rfa_pwr[3] << 24) | (rfa_pwr[2] << 16) | (rfa_pwr[1] << 8) | 364 rfa_pwr[0]; 365 366 rtl_set_bbreg(hw, regoffset[index], 0x7f7f7f7f, writeval); 367 } 368 369 void rtl92s_phy_rf6052_set_ofdmtxpower(struct ieee80211_hw *hw, 370 u8 *p_pwrlevel, u8 chnl) 371 { 372 u32 writeval, pwrbase0, pwrbase1; 373 u8 index = 0; 374 u8 finalpwr_idx[4]; 375 376 _rtl92s_get_powerbase(hw, p_pwrlevel, chnl, &pwrbase0, &pwrbase1, 377 &finalpwr_idx[0]); 378 _rtl92s_set_antennadiff(hw, &finalpwr_idx[0]); 379 380 for (index = 0; index < 6; index++) { 381 _rtl92s_get_txpower_writeval_byregulatory(hw, chnl, index, 382 pwrbase0, pwrbase1, &writeval); 383 384 _rtl92s_write_ofdm_powerreg(hw, index, writeval); 385 } 386 } 387 388 void rtl92s_phy_rf6052_set_ccktxpower(struct ieee80211_hw *hw, u8 pwrlevel) 389 { 390 struct rtl_priv *rtlpriv = rtl_priv(hw); 391 struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); 392 struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); 393 u32 txagc = 0; 394 bool dont_inc_cck_or_turboscanoff = false; 395 396 if (((rtlefuse->eeprom_version >= 2) && 397 (rtlefuse->txpwr_safetyflag == 1)) || 398 ((rtlefuse->eeprom_version >= 2) && 399 (rtlefuse->eeprom_regulatory != 0))) 400 dont_inc_cck_or_turboscanoff = true; 401 402 if (mac->act_scanning) { 403 txagc = 0x3f; 404 if (dont_inc_cck_or_turboscanoff) 405 txagc = pwrlevel; 406 } else { 407 txagc = pwrlevel; 408 409 if (rtlpriv->dm.dynamic_txhighpower_lvl == 410 TX_HIGH_PWR_LEVEL_LEVEL1) 411 txagc = 0x10; 412 else if (rtlpriv->dm.dynamic_txhighpower_lvl == 413 TX_HIGH_PWR_LEVEL_LEVEL2) 414 txagc = 0x0; 415 } 416 417 if (txagc > RF6052_MAX_TX_PWR) 418 txagc = RF6052_MAX_TX_PWR; 419 420 rtl_set_bbreg(hw, RTXAGC_CCK_MCS32, BTX_AGCRATECCK, txagc); 421 422 } 423 424 bool rtl92s_phy_rf6052_config(struct ieee80211_hw *hw) 425 { 426 struct rtl_priv *rtlpriv = rtl_priv(hw); 427 struct rtl_phy *rtlphy = &(rtlpriv->phy); 428 u32 u4reg_val = 0; 429 u8 rfpath; 430 bool rtstatus = true; 431 struct bb_reg_def *pphyreg; 432 433 /* Initialize RF */ 434 for (rfpath = 0; rfpath < rtlphy->num_total_rfpath; rfpath++) { 435 436 pphyreg = &rtlphy->phyreg_def[rfpath]; 437 438 /* Store original RFENV control type */ 439 switch (rfpath) { 440 case RF90_PATH_A: 441 case RF90_PATH_C: 442 u4reg_val = rtl92s_phy_query_bb_reg(hw, 443 pphyreg->rfintfs, 444 BRFSI_RFENV); 445 break; 446 case RF90_PATH_B: 447 case RF90_PATH_D: 448 u4reg_val = rtl92s_phy_query_bb_reg(hw, 449 pphyreg->rfintfs, 450 BRFSI_RFENV << 16); 451 break; 452 } 453 454 /* Set RF_ENV enable */ 455 rtl92s_phy_set_bb_reg(hw, pphyreg->rfintfe, 456 BRFSI_RFENV << 16, 0x1); 457 458 /* Set RF_ENV output high */ 459 rtl92s_phy_set_bb_reg(hw, pphyreg->rfintfo, BRFSI_RFENV, 0x1); 460 461 /* Set bit number of Address and Data for RF register */ 462 rtl92s_phy_set_bb_reg(hw, pphyreg->rfhssi_para2, 463 B3WIRE_ADDRESSLENGTH, 0x0); 464 rtl92s_phy_set_bb_reg(hw, pphyreg->rfhssi_para2, 465 B3WIRE_DATALENGTH, 0x0); 466 467 /* Initialize RF fom connfiguration file */ 468 switch (rfpath) { 469 case RF90_PATH_A: 470 rtstatus = rtl92s_phy_config_rf(hw, 471 (enum radio_path)rfpath); 472 break; 473 case RF90_PATH_B: 474 rtstatus = rtl92s_phy_config_rf(hw, 475 (enum radio_path)rfpath); 476 break; 477 case RF90_PATH_C: 478 break; 479 case RF90_PATH_D: 480 break; 481 } 482 483 /* Restore RFENV control type */ 484 switch (rfpath) { 485 case RF90_PATH_A: 486 case RF90_PATH_C: 487 rtl92s_phy_set_bb_reg(hw, pphyreg->rfintfs, BRFSI_RFENV, 488 u4reg_val); 489 break; 490 case RF90_PATH_B: 491 case RF90_PATH_D: 492 rtl92s_phy_set_bb_reg(hw, pphyreg->rfintfs, 493 BRFSI_RFENV << 16, 494 u4reg_val); 495 break; 496 } 497 498 if (!rtstatus) { 499 pr_err("Radio[%d] Fail!!\n", rfpath); 500 goto fail; 501 } 502 503 } 504 505 return rtstatus; 506 507 fail: 508 return rtstatus; 509 } 510 511 void rtl92s_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw, u8 bandwidth) 512 { 513 struct rtl_priv *rtlpriv = rtl_priv(hw); 514 struct rtl_phy *rtlphy = &(rtlpriv->phy); 515 516 switch (bandwidth) { 517 case HT_CHANNEL_WIDTH_20: 518 rtlphy->rfreg_chnlval[0] = ((rtlphy->rfreg_chnlval[0] & 519 0xfffff3ff) | 0x0400); 520 rtl_set_rfreg(hw, RF90_PATH_A, RF_CHNLBW, RFREG_OFFSET_MASK, 521 rtlphy->rfreg_chnlval[0]); 522 break; 523 case HT_CHANNEL_WIDTH_20_40: 524 rtlphy->rfreg_chnlval[0] = ((rtlphy->rfreg_chnlval[0] & 525 0xfffff3ff)); 526 rtl_set_rfreg(hw, RF90_PATH_A, RF_CHNLBW, RFREG_OFFSET_MASK, 527 rtlphy->rfreg_chnlval[0]); 528 break; 529 default: 530 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, 531 "unknown bandwidth: %#X\n", bandwidth); 532 break; 533 } 534 } 535