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