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