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