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