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