1 /****************************************************************************** 2 * 3 * Copyright(c) 2009-2010 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 _rtl8821ae_phy_rf6052_config_parafile(struct ieee80211_hw *hw); 34 35 void rtl8821ae_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw, u8 bandwidth) 36 { 37 struct rtl_priv *rtlpriv = rtl_priv(hw); 38 39 switch (bandwidth) { 40 case HT_CHANNEL_WIDTH_20: 41 rtl_set_rfreg(hw, RF90_PATH_A, RF_CHNLBW, BIT(11)|BIT(10), 3); 42 rtl_set_rfreg(hw, RF90_PATH_B, RF_CHNLBW, BIT(11)|BIT(10), 3); 43 break; 44 case HT_CHANNEL_WIDTH_20_40: 45 rtl_set_rfreg(hw, RF90_PATH_A, RF_CHNLBW, BIT(11)|BIT(10), 1); 46 rtl_set_rfreg(hw, RF90_PATH_B, RF_CHNLBW, BIT(11)|BIT(10), 1); 47 break; 48 case HT_CHANNEL_WIDTH_80: 49 rtl_set_rfreg(hw, RF90_PATH_A, RF_CHNLBW, BIT(11)|BIT(10), 0); 50 rtl_set_rfreg(hw, RF90_PATH_B, RF_CHNLBW, BIT(11)|BIT(10), 0); 51 break; 52 default: 53 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, 54 "unknown bandwidth: %#X\n", bandwidth); 55 break; 56 } 57 } 58 59 void rtl8821ae_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) { 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; 82 idx1 <= RF90_PATH_B; 83 idx1++) { 84 tx_agc[idx1] = ppowerlevel[idx1] | 85 (ppowerlevel[idx1] << 8) | 86 (ppowerlevel[idx1] << 16) | 87 (ppowerlevel[idx1] << 24); 88 } 89 } 90 } else { 91 for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B; idx1++) { 92 tx_agc[idx1] = ppowerlevel[idx1] | 93 (ppowerlevel[idx1] << 8) | 94 (ppowerlevel[idx1] << 16) | 95 (ppowerlevel[idx1] << 24); 96 } 97 98 if (rtlefuse->eeprom_regulatory == 0) { 99 tmpval = 100 (rtlphy->mcs_txpwrlevel_origoffset[0][6]) + 101 (rtlphy->mcs_txpwrlevel_origoffset[0][7] << 102 8); 103 tx_agc[RF90_PATH_A] += tmpval; 104 105 tmpval = (rtlphy->mcs_txpwrlevel_origoffset[0][14]) + 106 (rtlphy->mcs_txpwrlevel_origoffset[0][15] << 107 24); 108 tx_agc[RF90_PATH_B] += tmpval; 109 } 110 } 111 112 for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B; idx1++) { 113 ptr = (u8 *)(&tx_agc[idx1]); 114 for (idx2 = 0; idx2 < 4; idx2++) { 115 if (*ptr > RF6052_MAX_TX_PWR) 116 *ptr = RF6052_MAX_TX_PWR; 117 ptr++; 118 } 119 } 120 rtl8821ae_dm_txpower_track_adjust(hw, 1, &direction, &pwrtrac_value); 121 if (direction == 1) { 122 tx_agc[0] += pwrtrac_value; 123 tx_agc[1] += pwrtrac_value; 124 } else if (direction == 2) { 125 tx_agc[0] -= pwrtrac_value; 126 tx_agc[1] -= pwrtrac_value; 127 } 128 tmpval = tx_agc[RF90_PATH_A]; 129 rtl_set_bbreg(hw, RTXAGC_A_CCK11_CCK1, MASKDWORD, tmpval); 130 131 RTPRINT(rtlpriv, FPHY, PHY_TXPWR, 132 "CCK PWR 1~11M (rf-A) = 0x%x (reg 0x%x)\n", tmpval, 133 RTXAGC_A_CCK11_CCK1); 134 135 tmpval = tx_agc[RF90_PATH_B]; 136 rtl_set_bbreg(hw, RTXAGC_B_CCK11_CCK1, MASKDWORD, tmpval); 137 138 RTPRINT(rtlpriv, FPHY, PHY_TXPWR, 139 "CCK PWR 11M (rf-B) = 0x%x (reg 0x%x)\n", tmpval, 140 RTXAGC_B_CCK11_CCK1); 141 } 142 143 static void rtl8821ae_phy_get_power_base(struct ieee80211_hw *hw, 144 u8 *ppowerlevel_ofdm, 145 u8 *ppowerlevel_bw20, 146 u8 *ppowerlevel_bw40, u8 channel, 147 u32 *ofdmbase, u32 *mcsbase) 148 { 149 struct rtl_priv *rtlpriv = rtl_priv(hw); 150 struct rtl_phy *rtlphy = &rtlpriv->phy; 151 u32 powerbase0, powerbase1; 152 u8 i, powerlevel[2]; 153 154 for (i = 0; i < 2; i++) { 155 powerbase0 = ppowerlevel_ofdm[i]; 156 157 powerbase0 = (powerbase0 << 24) | (powerbase0 << 16) | 158 (powerbase0 << 8) | powerbase0; 159 *(ofdmbase + i) = powerbase0; 160 RTPRINT(rtlpriv, FPHY, PHY_TXPWR, 161 " [OFDM power base index rf(%c) = 0x%x]\n", 162 ((i == 0) ? 'A' : 'B'), *(ofdmbase + i)); 163 } 164 165 for (i = 0; i < 2; i++) { 166 if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20) 167 powerlevel[i] = ppowerlevel_bw20[i]; 168 else 169 powerlevel[i] = ppowerlevel_bw40[i]; 170 171 powerbase1 = powerlevel[i]; 172 powerbase1 = (powerbase1 << 24) | 173 (powerbase1 << 16) | (powerbase1 << 8) | powerbase1; 174 175 *(mcsbase + i) = powerbase1; 176 177 RTPRINT(rtlpriv, FPHY, PHY_TXPWR, 178 " [MCS power base index rf(%c) = 0x%x]\n", 179 ((i == 0) ? 'A' : 'B'), *(mcsbase + i)); 180 } 181 } 182 183 static void get_txpower_writeval_by_regulatory(struct ieee80211_hw *hw, 184 u8 channel, u8 index, 185 u32 *powerbase0, 186 u32 *powerbase1, 187 u32 *p_outwriteval) 188 { 189 struct rtl_priv *rtlpriv = rtl_priv(hw); 190 struct rtl_phy *rtlphy = &rtlpriv->phy; 191 struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); 192 u8 i, chnlgroup = 0, pwr_diff_limit[4], pwr_diff = 0, customer_pwr_diff; 193 u32 writeval, customer_limit, rf; 194 195 for (rf = 0; rf < 2; rf++) { 196 switch (rtlefuse->eeprom_regulatory) { 197 case 0: 198 chnlgroup = 0; 199 200 writeval = 201 rtlphy->mcs_txpwrlevel_origoffset[chnlgroup][index + 202 (rf ? 8 : 0)] 203 + ((index < 2) ? powerbase0[rf] : powerbase1[rf]); 204 205 RTPRINT(rtlpriv, FPHY, PHY_TXPWR, 206 "RTK better performance, writeval(%c) = 0x%x\n", 207 ((rf == 0) ? 'A' : 'B'), writeval); 208 break; 209 case 1: 210 if (rtlphy->pwrgroup_cnt == 1) { 211 chnlgroup = 0; 212 } else { 213 if (channel < 3) 214 chnlgroup = 0; 215 else if (channel < 6) 216 chnlgroup = 1; 217 else if (channel < 9) 218 chnlgroup = 2; 219 else if (channel < 12) 220 chnlgroup = 3; 221 else if (channel < 14) 222 chnlgroup = 4; 223 else if (channel == 14) 224 chnlgroup = 5; 225 } 226 227 writeval = 228 rtlphy->mcs_txpwrlevel_origoffset[chnlgroup] 229 [index + (rf ? 8 : 0)] + ((index < 2) ? 230 powerbase0[rf] : 231 powerbase1[rf]); 232 233 RTPRINT(rtlpriv, FPHY, PHY_TXPWR, 234 "Realtek regulatory, 20MHz, writeval(%c) = 0x%x\n", 235 ((rf == 0) ? 'A' : 'B'), writeval); 236 237 break; 238 case 2: 239 writeval = 240 ((index < 2) ? powerbase0[rf] : powerbase1[rf]); 241 242 RTPRINT(rtlpriv, FPHY, PHY_TXPWR, 243 "Better regulatory, writeval(%c) = 0x%x\n", 244 ((rf == 0) ? 'A' : 'B'), writeval); 245 break; 246 case 3: 247 chnlgroup = 0; 248 249 if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) { 250 RTPRINT(rtlpriv, FPHY, PHY_TXPWR, 251 "customer's limit, 40MHz rf(%c) = 0x%x\n", 252 ((rf == 0) ? 'A' : 'B'), 253 rtlefuse->pwrgroup_ht40[rf][channel - 254 1]); 255 } else { 256 RTPRINT(rtlpriv, FPHY, PHY_TXPWR, 257 "customer's limit, 20MHz rf(%c) = 0x%x\n", 258 ((rf == 0) ? 'A' : 'B'), 259 rtlefuse->pwrgroup_ht20[rf][channel - 260 1]); 261 } 262 263 if (index < 2) 264 pwr_diff = rtlefuse->txpwr_legacyhtdiff[rf][channel-1]; 265 else if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20) 266 pwr_diff = 267 rtlefuse->txpwr_ht20diff[rf][channel-1]; 268 269 if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) 270 customer_pwr_diff = 271 rtlefuse->pwrgroup_ht40[rf][channel-1]; 272 else 273 customer_pwr_diff = 274 rtlefuse->pwrgroup_ht20[rf][channel-1]; 275 276 if (pwr_diff > customer_pwr_diff) 277 pwr_diff = 0; 278 else 279 pwr_diff = customer_pwr_diff - pwr_diff; 280 281 for (i = 0; i < 4; i++) { 282 pwr_diff_limit[i] = 283 (u8)((rtlphy->mcs_txpwrlevel_origoffset 284 [chnlgroup][index + (rf ? 8 : 0)] & 285 (0x7f << (i * 8))) >> (i * 8)); 286 287 if (pwr_diff_limit[i] > pwr_diff) 288 pwr_diff_limit[i] = pwr_diff; 289 } 290 291 customer_limit = (pwr_diff_limit[3] << 24) | 292 (pwr_diff_limit[2] << 16) | 293 (pwr_diff_limit[1] << 8) | (pwr_diff_limit[0]); 294 295 RTPRINT(rtlpriv, FPHY, PHY_TXPWR, 296 "Customer's limit rf(%c) = 0x%x\n", 297 ((rf == 0) ? 'A' : 'B'), customer_limit); 298 299 writeval = customer_limit + 300 ((index < 2) ? powerbase0[rf] : powerbase1[rf]); 301 302 RTPRINT(rtlpriv, FPHY, PHY_TXPWR, 303 "Customer, writeval rf(%c)= 0x%x\n", 304 ((rf == 0) ? 'A' : 'B'), writeval); 305 break; 306 default: 307 chnlgroup = 0; 308 writeval = 309 rtlphy->mcs_txpwrlevel_origoffset[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 _rtl8821ae_write_ofdm_power_reg(struct ieee80211_hw *hw, 329 u8 index, u32 *pvalue) 330 { 331 struct rtl_priv *rtlpriv = rtl_priv(hw); 332 u16 regoffset_a[6] = { 333 RTXAGC_A_OFDM18_OFDM6, RTXAGC_A_OFDM54_OFDM24, 334 RTXAGC_A_MCS03_MCS00, RTXAGC_A_MCS07_MCS04, 335 RTXAGC_A_MCS11_MCS08, RTXAGC_A_MCS15_MCS12 336 }; 337 u16 regoffset_b[6] = { 338 RTXAGC_B_OFDM18_OFDM6, RTXAGC_B_OFDM54_OFDM24, 339 RTXAGC_B_MCS03_MCS00, RTXAGC_B_MCS07_MCS04, 340 RTXAGC_B_MCS11_MCS08, RTXAGC_B_MCS15_MCS12 341 }; 342 u8 i, rf, pwr_val[4]; 343 u32 writeval; 344 u16 regoffset; 345 346 for (rf = 0; rf < 2; rf++) { 347 writeval = pvalue[rf]; 348 for (i = 0; i < 4; i++) { 349 pwr_val[i] = (u8)((writeval & (0x7f << 350 (i * 8))) >> (i * 8)); 351 352 if (pwr_val[i] > RF6052_MAX_TX_PWR) 353 pwr_val[i] = RF6052_MAX_TX_PWR; 354 } 355 writeval = (pwr_val[3] << 24) | (pwr_val[2] << 16) | 356 (pwr_val[1] << 8) | pwr_val[0]; 357 358 if (rf == 0) 359 regoffset = regoffset_a[index]; 360 else 361 regoffset = regoffset_b[index]; 362 rtl_set_bbreg(hw, regoffset, MASKDWORD, writeval); 363 364 RTPRINT(rtlpriv, FPHY, PHY_TXPWR, 365 "Set 0x%x = %08x\n", regoffset, writeval); 366 } 367 } 368 369 void rtl8821ae_phy_rf6052_set_ofdm_txpower(struct ieee80211_hw *hw, 370 u8 *ppowerlevel_ofdm, 371 u8 *ppowerlevel_bw20, 372 u8 *ppowerlevel_bw40, 373 u8 channel) 374 { 375 u32 writeval[2], powerbase0[2], powerbase1[2]; 376 u8 index; 377 u8 direction; 378 u32 pwrtrac_value; 379 380 rtl8821ae_phy_get_power_base(hw, ppowerlevel_ofdm, 381 ppowerlevel_bw20, 382 ppowerlevel_bw40, 383 channel, 384 &powerbase0[0], 385 &powerbase1[0]); 386 387 rtl8821ae_dm_txpower_track_adjust(hw, 1, &direction, &pwrtrac_value); 388 389 for (index = 0; index < 6; index++) { 390 get_txpower_writeval_by_regulatory(hw, channel, index, 391 &powerbase0[0], 392 &powerbase1[0], 393 &writeval[0]); 394 if (direction == 1) { 395 writeval[0] += pwrtrac_value; 396 writeval[1] += pwrtrac_value; 397 } else if (direction == 2) { 398 writeval[0] -= pwrtrac_value; 399 writeval[1] -= pwrtrac_value; 400 } 401 _rtl8821ae_write_ofdm_power_reg(hw, index, &writeval[0]); 402 } 403 } 404 405 bool rtl8821ae_phy_rf6052_config(struct ieee80211_hw *hw) 406 { 407 struct rtl_priv *rtlpriv = rtl_priv(hw); 408 struct rtl_phy *rtlphy = &rtlpriv->phy; 409 410 if (rtlphy->rf_type == RF_1T1R) 411 rtlphy->num_total_rfpath = 1; 412 else 413 rtlphy->num_total_rfpath = 2; 414 415 return _rtl8821ae_phy_rf6052_config_parafile(hw); 416 } 417 418 static bool _rtl8821ae_phy_rf6052_config_parafile(struct ieee80211_hw *hw) 419 { 420 struct rtl_priv *rtlpriv = rtl_priv(hw); 421 struct rtl_phy *rtlphy = &rtlpriv->phy; 422 struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); 423 u8 rfpath; 424 bool rtstatus = true; 425 426 for (rfpath = 0; rfpath < rtlphy->num_total_rfpath; rfpath++) { 427 switch (rfpath) { 428 case RF90_PATH_A: { 429 if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) 430 rtstatus = 431 rtl8812ae_phy_config_rf_with_headerfile(hw, 432 (enum radio_path)rfpath); 433 else 434 rtstatus = 435 rtl8821ae_phy_config_rf_with_headerfile(hw, 436 (enum radio_path)rfpath); 437 break; 438 } 439 case RF90_PATH_B: 440 if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) 441 rtstatus = 442 rtl8812ae_phy_config_rf_with_headerfile(hw, 443 (enum radio_path)rfpath); 444 else 445 rtstatus = 446 rtl8821ae_phy_config_rf_with_headerfile(hw, 447 (enum radio_path)rfpath); 448 break; 449 case RF90_PATH_C: 450 break; 451 case RF90_PATH_D: 452 break; 453 } 454 455 if (!rtstatus) { 456 RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, 457 "Radio[%d] Fail!!", rfpath); 458 return false; 459 } 460 } 461 462 /*put arrays in dm.c*/ 463 RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "\n"); 464 return rtstatus; 465 } 466