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