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