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