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 * You should have received a copy of the GNU General Public License along with 15 * this program; if not, write to the Free Software Foundation, Inc., 16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA 17 * 18 * The full GNU General Public License is included in this distribution in the 19 * file called LICENSE. 20 * 21 * Contact Information: 22 * wlanfae <wlanfae@realtek.com> 23 * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, 24 * Hsinchu 300, Taiwan. 25 * 26 * Larry Finger <Larry.Finger@lwfinger.net> 27 * 28 *****************************************************************************/ 29 30#include "../wifi.h" 31#include "reg.h" 32#include "def.h" 33#include "phy.h" 34#include "rf.h" 35#include "dm.h" 36 37static bool _rtl92c_phy_rf6052_config_parafile(struct ieee80211_hw *hw); 38 39void rtl92cu_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw, u8 bandwidth) 40{ 41 struct rtl_priv *rtlpriv = rtl_priv(hw); 42 struct rtl_phy *rtlphy = &(rtlpriv->phy); 43 44 switch (bandwidth) { 45 case HT_CHANNEL_WIDTH_20: 46 rtlphy->rfreg_chnlval[0] = ((rtlphy->rfreg_chnlval[0] & 47 0xfffff3ff) | 0x0400); 48 rtl_set_rfreg(hw, RF90_PATH_A, RF_CHNLBW, RFREG_OFFSET_MASK, 49 rtlphy->rfreg_chnlval[0]); 50 break; 51 case HT_CHANNEL_WIDTH_20_40: 52 rtlphy->rfreg_chnlval[0] = ((rtlphy->rfreg_chnlval[0] & 53 0xfffff3ff)); 54 rtl_set_rfreg(hw, RF90_PATH_A, RF_CHNLBW, RFREG_OFFSET_MASK, 55 rtlphy->rfreg_chnlval[0]); 56 break; 57 default: 58 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, 59 "unknown bandwidth: %#X\n", bandwidth); 60 break; 61 } 62} 63 64void rtl92cu_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw, 65 u8 *ppowerlevel) 66{ 67 struct rtl_priv *rtlpriv = rtl_priv(hw); 68 struct rtl_phy *rtlphy = &(rtlpriv->phy); 69 struct rtl_hal *rtlhal = rtl_hal(rtlpriv); 70 struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); 71 struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); 72 u32 tx_agc[2] = { 0, 0 }, tmpval = 0; 73 bool turbo_scanoff = false; 74 u8 idx1, idx2; 75 u8 *ptr; 76 77 if (rtlhal->interface == INTF_PCI) { 78 if (rtlefuse->eeprom_regulatory != 0) 79 turbo_scanoff = true; 80 } else { 81 if ((rtlefuse->eeprom_regulatory != 0) || 82 (rtlefuse->external_pa)) 83 turbo_scanoff = true; 84 } 85 if (mac->act_scanning) { 86 tx_agc[RF90_PATH_A] = 0x3f3f3f3f; 87 tx_agc[RF90_PATH_B] = 0x3f3f3f3f; 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 if (rtlhal->interface == INTF_USB) { 94 if (tx_agc[idx1] > 0x20 && 95 rtlefuse->external_pa) 96 tx_agc[idx1] = 0x20; 97 } 98 } 99 } else { 100 if (rtlpriv->dm.dynamic_txhighpower_lvl == 101 TXHIGHPWRLEVEL_LEVEL1) { 102 tx_agc[RF90_PATH_A] = 0x10101010; 103 tx_agc[RF90_PATH_B] = 0x10101010; 104 } else if (rtlpriv->dm.dynamic_txhighpower_lvl == 105 TXHIGHPWRLEVEL_LEVEL2) { 106 tx_agc[RF90_PATH_A] = 0x00000000; 107 tx_agc[RF90_PATH_B] = 0x00000000; 108 } else { 109 for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B; idx1++) { 110 tx_agc[idx1] = ppowerlevel[idx1] | 111 (ppowerlevel[idx1] << 8) | 112 (ppowerlevel[idx1] << 16) | 113 (ppowerlevel[idx1] << 24); 114 } 115 if (rtlefuse->eeprom_regulatory == 0) { 116 tmpval = (rtlphy->mcs_offset[0][6]) + 117 (rtlphy->mcs_offset[0][7] << 8); 118 tx_agc[RF90_PATH_A] += tmpval; 119 tmpval = (rtlphy->mcs_offset[0][14]) + 120 (rtlphy->mcs_offset[0][15] << 24); 121 tx_agc[RF90_PATH_B] += tmpval; 122 } 123 } 124 } 125 for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B; idx1++) { 126 ptr = (u8 *) (&(tx_agc[idx1])); 127 for (idx2 = 0; idx2 < 4; idx2++) { 128 if (*ptr > RF6052_MAX_TX_PWR) 129 *ptr = RF6052_MAX_TX_PWR; 130 ptr++; 131 } 132 } 133 tmpval = tx_agc[RF90_PATH_A] & 0xff; 134 rtl_set_bbreg(hw, RTXAGC_A_CCK1_MCS32, MASKBYTE1, tmpval); 135 136 RTPRINT(rtlpriv, FPHY, PHY_TXPWR, 137 "CCK PWR 1M (rf-A) = 0x%x (reg 0x%x)\n", 138 tmpval, RTXAGC_A_CCK1_MCS32); 139 140 tmpval = tx_agc[RF90_PATH_A] >> 8; 141 if (mac->mode == WIRELESS_MODE_B) 142 tmpval = tmpval & 0xff00ffff; 143 rtl_set_bbreg(hw, RTXAGC_B_CCK11_A_CCK2_11, 0xffffff00, tmpval); 144 RTPRINT(rtlpriv, FPHY, PHY_TXPWR, 145 "CCK PWR 2~11M (rf-A) = 0x%x (reg 0x%x)\n", 146 tmpval, RTXAGC_B_CCK11_A_CCK2_11); 147 tmpval = tx_agc[RF90_PATH_B] >> 24; 148 rtl_set_bbreg(hw, RTXAGC_B_CCK11_A_CCK2_11, MASKBYTE0, tmpval); 149 RTPRINT(rtlpriv, FPHY, PHY_TXPWR, 150 "CCK PWR 11M (rf-B) = 0x%x (reg 0x%x)\n", 151 tmpval, RTXAGC_B_CCK11_A_CCK2_11); 152 tmpval = tx_agc[RF90_PATH_B] & 0x00ffffff; 153 rtl_set_bbreg(hw, RTXAGC_B_CCK1_55_MCS32, 0xffffff00, tmpval); 154 RTPRINT(rtlpriv, FPHY, PHY_TXPWR, 155 "CCK PWR 1~5.5M (rf-B) = 0x%x (reg 0x%x)\n", 156 tmpval, RTXAGC_B_CCK1_55_MCS32); 157} 158 159static void rtl92c_phy_get_power_base(struct ieee80211_hw *hw, 160 u8 *ppowerlevel, u8 channel, 161 u32 *ofdmbase, u32 *mcsbase) 162{ 163 struct rtl_priv *rtlpriv = rtl_priv(hw); 164 struct rtl_phy *rtlphy = &(rtlpriv->phy); 165 struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); 166 u32 powerBase0, powerBase1; 167 u8 legacy_pwrdiff = 0, ht20_pwrdiff = 0; 168 u8 i, powerlevel[2]; 169 170 for (i = 0; i < 2; i++) { 171 powerlevel[i] = ppowerlevel[i]; 172 legacy_pwrdiff = rtlefuse->txpwr_legacyhtdiff[i][channel - 1]; 173 powerBase0 = powerlevel[i] + legacy_pwrdiff; 174 powerBase0 = (powerBase0 << 24) | (powerBase0 << 16) | 175 (powerBase0 << 8) | powerBase0; 176 *(ofdmbase + i) = powerBase0; 177 RTPRINT(rtlpriv, FPHY, PHY_TXPWR, 178 " [OFDM power base index rf(%c) = 0x%x]\n", 179 i == 0 ? 'A' : 'B', *(ofdmbase + i)); 180 } 181 for (i = 0; i < 2; i++) { 182 if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20) { 183 ht20_pwrdiff = rtlefuse->txpwr_ht20diff[i][channel - 1]; 184 powerlevel[i] += ht20_pwrdiff; 185 } 186 powerBase1 = powerlevel[i]; 187 powerBase1 = (powerBase1 << 24) | 188 (powerBase1 << 16) | (powerBase1 << 8) | powerBase1; 189 *(mcsbase + i) = powerBase1; 190 RTPRINT(rtlpriv, FPHY, PHY_TXPWR, 191 " [MCS power base index rf(%c) = 0x%x]\n", 192 i == 0 ? 'A' : 'B', *(mcsbase + i)); 193 } 194} 195 196static void _rtl92c_get_txpower_writeval_by_regulatory(struct ieee80211_hw *hw, 197 u8 channel, u8 index, 198 u32 *powerBase0, 199 u32 *powerBase1, 200 u32 *p_outwriteval) 201{ 202 struct rtl_priv *rtlpriv = rtl_priv(hw); 203 struct rtl_phy *rtlphy = &(rtlpriv->phy); 204 struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); 205 u8 i, chnlgroup = 0, pwr_diff_limit[4]; 206 u32 writeVal, customer_limit, rf; 207 208 for (rf = 0; rf < 2; rf++) { 209 switch (rtlefuse->eeprom_regulatory) { 210 case 0: 211 chnlgroup = 0; 212 writeVal = rtlphy->mcs_offset 213 [chnlgroup][index + (rf ? 8 : 0)] 214 + ((index < 2) ? powerBase0[rf] : powerBase1[rf]); 215 RTPRINT(rtlpriv, FPHY, PHY_TXPWR, 216 "RTK better performance,writeVal(%c) = 0x%x\n", 217 rf == 0 ? 'A' : 'B', writeVal); 218 break; 219 case 1: 220 if (rtlphy->pwrgroup_cnt == 1) 221 chnlgroup = 0; 222 if (rtlphy->pwrgroup_cnt >= 3) { 223 if (channel <= 3) 224 chnlgroup = 0; 225 else if (channel >= 4 && channel <= 9) 226 chnlgroup = 1; 227 else if (channel > 9) 228 chnlgroup = 2; 229 if (rtlphy->current_chan_bw == 230 HT_CHANNEL_WIDTH_20) 231 chnlgroup++; 232 else 233 chnlgroup += 4; 234 } 235 writeVal = rtlphy->mcs_offset[chnlgroup][index + 236 (rf ? 8 : 0)] + 237 ((index < 2) ? powerBase0[rf] : 238 powerBase1[rf]); 239 RTPRINT(rtlpriv, FPHY, PHY_TXPWR, 240 "Realtek regulatory, 20MHz, writeVal(%c) = 0x%x\n", 241 rf == 0 ? 'A' : 'B', writeVal); 242 break; 243 case 2: 244 writeVal = ((index < 2) ? powerBase0[rf] : 245 powerBase1[rf]); 246 RTPRINT(rtlpriv, FPHY, PHY_TXPWR, 247 "Better regulatory,writeVal(%c) = 0x%x\n", 248 rf == 0 ? 'A' : 'B', writeVal); 249 break; 250 case 3: 251 chnlgroup = 0; 252 if (rtlphy->current_chan_bw == 253 HT_CHANNEL_WIDTH_20_40) { 254 RTPRINT(rtlpriv, FPHY, PHY_TXPWR, 255 "customer's limit, 40MHzrf(%c) = 0x%x\n", 256 rf == 0 ? 'A' : 'B', 257 rtlefuse->pwrgroup_ht40[rf] 258 [channel - 1]); 259 } else { 260 RTPRINT(rtlpriv, FPHY, PHY_TXPWR, 261 "customer's limit, 20MHz rf(%c) = 0x%x\n", 262 rf == 0 ? 'A' : 'B', 263 rtlefuse->pwrgroup_ht20[rf] 264 [channel - 1]); 265 } 266 for (i = 0; i < 4; i++) { 267 pwr_diff_limit[i] = (u8) ((rtlphy->mcs_offset 268 [chnlgroup][index + (rf ? 8 : 0)] 269 & (0x7f << (i * 8))) >> (i * 8)); 270 if (rtlphy->current_chan_bw == 271 HT_CHANNEL_WIDTH_20_40) { 272 if (pwr_diff_limit[i] > 273 rtlefuse->pwrgroup_ht40[rf] 274 [channel - 1]) 275 pwr_diff_limit[i] = rtlefuse-> 276 pwrgroup_ht40[rf] 277 [channel - 1]; 278 } else { 279 if (pwr_diff_limit[i] > 280 rtlefuse->pwrgroup_ht20[rf] 281 [channel - 1]) 282 pwr_diff_limit[i] = 283 rtlefuse->pwrgroup_ht20[rf] 284 [channel - 1]; 285 } 286 } 287 customer_limit = (pwr_diff_limit[3] << 24) | 288 (pwr_diff_limit[2] << 16) | 289 (pwr_diff_limit[1] << 8) | (pwr_diff_limit[0]); 290 RTPRINT(rtlpriv, FPHY, PHY_TXPWR, 291 "Customer's limit rf(%c) = 0x%x\n", 292 rf == 0 ? 'A' : 'B', customer_limit); 293 writeVal = customer_limit + ((index < 2) ? 294 powerBase0[rf] : powerBase1[rf]); 295 RTPRINT(rtlpriv, FPHY, PHY_TXPWR, 296 "Customer, writeVal rf(%c)= 0x%x\n", 297 rf == 0 ? 'A' : 'B', writeVal); 298 break; 299 default: 300 chnlgroup = 0; 301 writeVal = rtlphy->mcs_offset[chnlgroup] 302 [index + (rf ? 8 : 0)] + ((index < 2) ? 303 powerBase0[rf] : powerBase1[rf]); 304 RTPRINT(rtlpriv, FPHY, PHY_TXPWR, 305 "RTK better performance, writeValrf(%c) = 0x%x\n", 306 rf == 0 ? 'A' : 'B', writeVal); 307 break; 308 } 309 if (rtlpriv->dm.dynamic_txhighpower_lvl == 310 TXHIGHPWRLEVEL_LEVEL1) 311 writeVal = 0x14141414; 312 else if (rtlpriv->dm.dynamic_txhighpower_lvl == 313 TXHIGHPWRLEVEL_LEVEL2) 314 writeVal = 0x00000000; 315 if (rtlpriv->dm.dynamic_txhighpower_lvl == TXHIGHPWRLEVEL_BT1) 316 writeVal = writeVal - 0x06060606; 317 else if (rtlpriv->dm.dynamic_txhighpower_lvl == 318 TXHIGHPWRLEVEL_BT2) 319 writeVal = writeVal; 320 *(p_outwriteval + rf) = writeVal; 321 } 322} 323 324static void _rtl92c_write_ofdm_power_reg(struct ieee80211_hw *hw, 325 u8 index, u32 *pValue) 326{ 327 struct rtl_priv *rtlpriv = rtl_priv(hw); 328 struct rtl_phy *rtlphy = &(rtlpriv->phy); 329 u16 regoffset_a[6] = { 330 RTXAGC_A_RATE18_06, RTXAGC_A_RATE54_24, 331 RTXAGC_A_MCS03_MCS00, RTXAGC_A_MCS07_MCS04, 332 RTXAGC_A_MCS11_MCS08, RTXAGC_A_MCS15_MCS12 333 }; 334 u16 regoffset_b[6] = { 335 RTXAGC_B_RATE18_06, RTXAGC_B_RATE54_24, 336 RTXAGC_B_MCS03_MCS00, RTXAGC_B_MCS07_MCS04, 337 RTXAGC_B_MCS11_MCS08, RTXAGC_B_MCS15_MCS12 338 }; 339 u8 i, rf, pwr_val[4]; 340 u32 writeVal; 341 u16 regoffset; 342 343 for (rf = 0; rf < 2; rf++) { 344 writeVal = pValue[rf]; 345 for (i = 0; i < 4; i++) { 346 pwr_val[i] = (u8)((writeVal & (0x7f << (i * 8))) >> 347 (i * 8)); 348 if (pwr_val[i] > RF6052_MAX_TX_PWR) 349 pwr_val[i] = RF6052_MAX_TX_PWR; 350 } 351 writeVal = (pwr_val[3] << 24) | (pwr_val[2] << 16) | 352 (pwr_val[1] << 8) | pwr_val[0]; 353 if (rf == 0) 354 regoffset = regoffset_a[index]; 355 else 356 regoffset = regoffset_b[index]; 357 rtl_set_bbreg(hw, regoffset, MASKDWORD, writeVal); 358 RTPRINT(rtlpriv, FPHY, PHY_TXPWR, 359 "Set 0x%x = %08x\n", regoffset, writeVal); 360 if (((get_rf_type(rtlphy) == RF_2T2R) && 361 (regoffset == RTXAGC_A_MCS15_MCS12 || 362 regoffset == RTXAGC_B_MCS15_MCS12)) || 363 ((get_rf_type(rtlphy) != RF_2T2R) && 364 (regoffset == RTXAGC_A_MCS07_MCS04 || 365 regoffset == RTXAGC_B_MCS07_MCS04))) { 366 writeVal = pwr_val[3]; 367 if (regoffset == RTXAGC_A_MCS15_MCS12 || 368 regoffset == RTXAGC_A_MCS07_MCS04) 369 regoffset = 0xc90; 370 if (regoffset == RTXAGC_B_MCS15_MCS12 || 371 regoffset == RTXAGC_B_MCS07_MCS04) 372 regoffset = 0xc98; 373 for (i = 0; i < 3; i++) { 374 if (i != 2) 375 writeVal = (writeVal > 8) ? 376 (writeVal - 8) : 0; 377 else 378 writeVal = (writeVal > 6) ? 379 (writeVal - 6) : 0; 380 rtl_write_byte(rtlpriv, (u32)(regoffset + i), 381 (u8)writeVal); 382 } 383 } 384 } 385} 386 387void rtl92cu_phy_rf6052_set_ofdm_txpower(struct ieee80211_hw *hw, 388 u8 *ppowerlevel, u8 channel) 389{ 390 u32 writeVal[2], powerBase0[2], powerBase1[2]; 391 u8 index = 0; 392 393 rtl92c_phy_get_power_base(hw, ppowerlevel, 394 channel, &powerBase0[0], &powerBase1[0]); 395 for (index = 0; index < 6; index++) { 396 _rtl92c_get_txpower_writeval_by_regulatory(hw, 397 channel, index, 398 &powerBase0[0], 399 &powerBase1[0], 400 &writeVal[0]); 401 _rtl92c_write_ofdm_power_reg(hw, index, &writeVal[0]); 402 } 403} 404 405bool rtl92cu_phy_rf6052_config(struct ieee80211_hw *hw) 406{ 407 struct rtl_priv *rtlpriv = rtl_priv(hw); 408 struct rtl_phy *rtlphy = &(rtlpriv->phy); 409 bool rtstatus = true; 410 u8 b_reg_hwparafile = 1; 411 412 if (rtlphy->rf_type == RF_1T1R) 413 rtlphy->num_total_rfpath = 1; 414 else 415 rtlphy->num_total_rfpath = 2; 416 if (b_reg_hwparafile == 1) 417 rtstatus = _rtl92c_phy_rf6052_config_parafile(hw); 418 return rtstatus; 419} 420 421static bool _rtl92c_phy_rf6052_config_parafile(struct ieee80211_hw *hw) 422{ 423 struct rtl_priv *rtlpriv = rtl_priv(hw); 424 struct rtl_phy *rtlphy = &(rtlpriv->phy); 425 u32 u4_regvalue = 0; 426 u8 rfpath; 427 bool rtstatus = true; 428 struct bb_reg_def *pphyreg; 429 430 for (rfpath = 0; rfpath < rtlphy->num_total_rfpath; rfpath++) { 431 pphyreg = &rtlphy->phyreg_def[rfpath]; 432 switch (rfpath) { 433 case RF90_PATH_A: 434 case RF90_PATH_C: 435 u4_regvalue = rtl_get_bbreg(hw, pphyreg->rfintfs, 436 BRFSI_RFENV); 437 break; 438 case RF90_PATH_B: 439 case RF90_PATH_D: 440 u4_regvalue = rtl_get_bbreg(hw, pphyreg->rfintfs, 441 BRFSI_RFENV << 16); 442 break; 443 } 444 rtl_set_bbreg(hw, pphyreg->rfintfe, BRFSI_RFENV << 16, 0x1); 445 udelay(1); 446 rtl_set_bbreg(hw, pphyreg->rfintfo, BRFSI_RFENV, 0x1); 447 udelay(1); 448 rtl_set_bbreg(hw, pphyreg->rfhssi_para2, 449 B3WIREADDREAALENGTH, 0x0); 450 udelay(1); 451 rtl_set_bbreg(hw, pphyreg->rfhssi_para2, B3WIREDATALENGTH, 0x0); 452 udelay(1); 453 switch (rfpath) { 454 case RF90_PATH_A: 455 rtstatus = rtl92cu_phy_config_rf_with_headerfile(hw, 456 (enum radio_path) rfpath); 457 break; 458 case RF90_PATH_B: 459 rtstatus = rtl92cu_phy_config_rf_with_headerfile(hw, 460 (enum radio_path) rfpath); 461 break; 462 case RF90_PATH_C: 463 break; 464 case RF90_PATH_D: 465 break; 466 } 467 switch (rfpath) { 468 case RF90_PATH_A: 469 case RF90_PATH_C: 470 rtl_set_bbreg(hw, pphyreg->rfintfs, 471 BRFSI_RFENV, u4_regvalue); 472 break; 473 case RF90_PATH_B: 474 case RF90_PATH_D: 475 rtl_set_bbreg(hw, pphyreg->rfintfs, 476 BRFSI_RFENV << 16, u4_regvalue); 477 break; 478 } 479 if (!rtstatus) { 480 RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, 481 "Radio[%d] Fail!!", rfpath); 482 goto phy_rf_cfg_fail; 483 } 484 } 485 RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "<---\n"); 486 return rtstatus; 487phy_rf_cfg_fail: 488 return rtstatus; 489} 490