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