Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.29 1021 lines 28 kB view raw
1/* 2 * Copyright (c) 2008 Atheros Communications Inc. 3 * 4 * Permission to use, copy, modify, and/or distribute this software for any 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice appear in all copies. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 */ 16 17#include "core.h" 18#include "hw.h" 19#include "reg.h" 20#include "phy.h" 21 22static const int16_t NOISE_FLOOR[] = { -96, -93, -98, -96, -93, -96 }; 23 24/* We can tune this as we go by monitoring really low values */ 25#define ATH9K_NF_TOO_LOW -60 26 27/* AR5416 may return very high value (like -31 dBm), in those cases the nf 28 * is incorrect and we should use the static NF value. Later we can try to 29 * find out why they are reporting these values */ 30 31static bool ath9k_hw_nf_in_range(struct ath_hal *ah, s16 nf) 32{ 33 if (nf > ATH9K_NF_TOO_LOW) { 34 DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, 35 "noise floor value detected (%d) is " 36 "lower than what we think is a " 37 "reasonable value (%d)\n", 38 nf, ATH9K_NF_TOO_LOW); 39 return false; 40 } 41 return true; 42} 43 44static int16_t ath9k_hw_get_nf_hist_mid(int16_t *nfCalBuffer) 45{ 46 int16_t nfval; 47 int16_t sort[ATH9K_NF_CAL_HIST_MAX]; 48 int i, j; 49 50 for (i = 0; i < ATH9K_NF_CAL_HIST_MAX; i++) 51 sort[i] = nfCalBuffer[i]; 52 53 for (i = 0; i < ATH9K_NF_CAL_HIST_MAX - 1; i++) { 54 for (j = 1; j < ATH9K_NF_CAL_HIST_MAX - i; j++) { 55 if (sort[j] > sort[j - 1]) { 56 nfval = sort[j]; 57 sort[j] = sort[j - 1]; 58 sort[j - 1] = nfval; 59 } 60 } 61 } 62 nfval = sort[(ATH9K_NF_CAL_HIST_MAX - 1) >> 1]; 63 64 return nfval; 65} 66 67static void ath9k_hw_update_nfcal_hist_buffer(struct ath9k_nfcal_hist *h, 68 int16_t *nfarray) 69{ 70 int i; 71 72 for (i = 0; i < NUM_NF_READINGS; i++) { 73 h[i].nfCalBuffer[h[i].currIndex] = nfarray[i]; 74 75 if (++h[i].currIndex >= ATH9K_NF_CAL_HIST_MAX) 76 h[i].currIndex = 0; 77 78 if (h[i].invalidNFcount > 0) { 79 if (nfarray[i] < AR_PHY_CCA_MIN_BAD_VALUE || 80 nfarray[i] > AR_PHY_CCA_MAX_HIGH_VALUE) { 81 h[i].invalidNFcount = ATH9K_NF_CAL_HIST_MAX; 82 } else { 83 h[i].invalidNFcount--; 84 h[i].privNF = nfarray[i]; 85 } 86 } else { 87 h[i].privNF = 88 ath9k_hw_get_nf_hist_mid(h[i].nfCalBuffer); 89 } 90 } 91 return; 92} 93 94static void ath9k_hw_do_getnf(struct ath_hal *ah, 95 int16_t nfarray[NUM_NF_READINGS]) 96{ 97 int16_t nf; 98 99 if (AR_SREV_9280_10_OR_LATER(ah)) 100 nf = MS(REG_READ(ah, AR_PHY_CCA), AR9280_PHY_MINCCA_PWR); 101 else 102 nf = MS(REG_READ(ah, AR_PHY_CCA), AR_PHY_MINCCA_PWR); 103 104 if (nf & 0x100) 105 nf = 0 - ((nf ^ 0x1ff) + 1); 106 DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, 107 "NF calibrated [ctl] [chain 0] is %d\n", nf); 108 nfarray[0] = nf; 109 110 if (AR_SREV_9280_10_OR_LATER(ah)) 111 nf = MS(REG_READ(ah, AR_PHY_CH1_CCA), 112 AR9280_PHY_CH1_MINCCA_PWR); 113 else 114 nf = MS(REG_READ(ah, AR_PHY_CH1_CCA), 115 AR_PHY_CH1_MINCCA_PWR); 116 117 if (nf & 0x100) 118 nf = 0 - ((nf ^ 0x1ff) + 1); 119 DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, 120 "NF calibrated [ctl] [chain 1] is %d\n", nf); 121 nfarray[1] = nf; 122 123 if (!AR_SREV_9280(ah)) { 124 nf = MS(REG_READ(ah, AR_PHY_CH2_CCA), 125 AR_PHY_CH2_MINCCA_PWR); 126 if (nf & 0x100) 127 nf = 0 - ((nf ^ 0x1ff) + 1); 128 DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, 129 "NF calibrated [ctl] [chain 2] is %d\n", nf); 130 nfarray[2] = nf; 131 } 132 133 if (AR_SREV_9280_10_OR_LATER(ah)) 134 nf = MS(REG_READ(ah, AR_PHY_EXT_CCA), 135 AR9280_PHY_EXT_MINCCA_PWR); 136 else 137 nf = MS(REG_READ(ah, AR_PHY_EXT_CCA), 138 AR_PHY_EXT_MINCCA_PWR); 139 140 if (nf & 0x100) 141 nf = 0 - ((nf ^ 0x1ff) + 1); 142 DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, 143 "NF calibrated [ext] [chain 0] is %d\n", nf); 144 nfarray[3] = nf; 145 146 if (AR_SREV_9280_10_OR_LATER(ah)) 147 nf = MS(REG_READ(ah, AR_PHY_CH1_EXT_CCA), 148 AR9280_PHY_CH1_EXT_MINCCA_PWR); 149 else 150 nf = MS(REG_READ(ah, AR_PHY_CH1_EXT_CCA), 151 AR_PHY_CH1_EXT_MINCCA_PWR); 152 153 if (nf & 0x100) 154 nf = 0 - ((nf ^ 0x1ff) + 1); 155 DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, 156 "NF calibrated [ext] [chain 1] is %d\n", nf); 157 nfarray[4] = nf; 158 159 if (!AR_SREV_9280(ah)) { 160 nf = MS(REG_READ(ah, AR_PHY_CH2_EXT_CCA), 161 AR_PHY_CH2_EXT_MINCCA_PWR); 162 if (nf & 0x100) 163 nf = 0 - ((nf ^ 0x1ff) + 1); 164 DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, 165 "NF calibrated [ext] [chain 2] is %d\n", nf); 166 nfarray[5] = nf; 167 } 168} 169 170static bool getNoiseFloorThresh(struct ath_hal *ah, 171 const struct ath9k_channel *chan, 172 int16_t *nft) 173{ 174 switch (chan->chanmode) { 175 case CHANNEL_A: 176 case CHANNEL_A_HT20: 177 case CHANNEL_A_HT40PLUS: 178 case CHANNEL_A_HT40MINUS: 179 *nft = (int8_t)ath9k_hw_get_eeprom(ah, EEP_NFTHRESH_5); 180 break; 181 case CHANNEL_B: 182 case CHANNEL_G: 183 case CHANNEL_G_HT20: 184 case CHANNEL_G_HT40PLUS: 185 case CHANNEL_G_HT40MINUS: 186 *nft = (int8_t)ath9k_hw_get_eeprom(ah, EEP_NFTHRESH_2); 187 break; 188 default: 189 DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, 190 "invalid channel flags 0x%x\n", chan->channelFlags); 191 return false; 192 } 193 194 return true; 195} 196 197static void ath9k_hw_setup_calibration(struct ath_hal *ah, 198 struct hal_cal_list *currCal) 199{ 200 REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(0), 201 AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX, 202 currCal->calData->calCountMax); 203 204 switch (currCal->calData->calType) { 205 case IQ_MISMATCH_CAL: 206 REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_IQ); 207 DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, 208 "starting IQ Mismatch Calibration\n"); 209 break; 210 case ADC_GAIN_CAL: 211 REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_GAIN); 212 DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, 213 "starting ADC Gain Calibration\n"); 214 break; 215 case ADC_DC_CAL: 216 REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_PER); 217 DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, 218 "starting ADC DC Calibration\n"); 219 break; 220 case ADC_DC_INIT_CAL: 221 REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_INIT); 222 DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, 223 "starting Init ADC DC Calibration\n"); 224 break; 225 } 226 227 REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4(0), 228 AR_PHY_TIMING_CTRL4_DO_CAL); 229} 230 231static void ath9k_hw_reset_calibration(struct ath_hal *ah, 232 struct hal_cal_list *currCal) 233{ 234 struct ath_hal_5416 *ahp = AH5416(ah); 235 int i; 236 237 ath9k_hw_setup_calibration(ah, currCal); 238 239 currCal->calState = CAL_RUNNING; 240 241 for (i = 0; i < AR5416_MAX_CHAINS; i++) { 242 ahp->ah_Meas0.sign[i] = 0; 243 ahp->ah_Meas1.sign[i] = 0; 244 ahp->ah_Meas2.sign[i] = 0; 245 ahp->ah_Meas3.sign[i] = 0; 246 } 247 248 ahp->ah_CalSamples = 0; 249} 250 251static void ath9k_hw_per_calibration(struct ath_hal *ah, 252 struct ath9k_channel *ichan, 253 u8 rxchainmask, 254 struct hal_cal_list *currCal, 255 bool *isCalDone) 256{ 257 struct ath_hal_5416 *ahp = AH5416(ah); 258 259 *isCalDone = false; 260 261 if (currCal->calState == CAL_RUNNING) { 262 if (!(REG_READ(ah, AR_PHY_TIMING_CTRL4(0)) & 263 AR_PHY_TIMING_CTRL4_DO_CAL)) { 264 265 currCal->calData->calCollect(ah); 266 ahp->ah_CalSamples++; 267 268 if (ahp->ah_CalSamples >= currCal->calData->calNumSamples) { 269 int i, numChains = 0; 270 for (i = 0; i < AR5416_MAX_CHAINS; i++) { 271 if (rxchainmask & (1 << i)) 272 numChains++; 273 } 274 275 currCal->calData->calPostProc(ah, numChains); 276 ichan->CalValid |= currCal->calData->calType; 277 currCal->calState = CAL_DONE; 278 *isCalDone = true; 279 } else { 280 ath9k_hw_setup_calibration(ah, currCal); 281 } 282 } 283 } else if (!(ichan->CalValid & currCal->calData->calType)) { 284 ath9k_hw_reset_calibration(ah, currCal); 285 } 286} 287 288static bool ath9k_hw_iscal_supported(struct ath_hal *ah, 289 struct ath9k_channel *chan, 290 enum hal_cal_types calType) 291{ 292 struct ath_hal_5416 *ahp = AH5416(ah); 293 bool retval = false; 294 295 switch (calType & ahp->ah_suppCals) { 296 case IQ_MISMATCH_CAL: 297 if (!IS_CHAN_B(chan)) 298 retval = true; 299 break; 300 case ADC_GAIN_CAL: 301 case ADC_DC_CAL: 302 if (!IS_CHAN_B(chan) 303 && !(IS_CHAN_2GHZ(chan) && IS_CHAN_HT20(chan))) 304 retval = true; 305 break; 306 } 307 308 return retval; 309} 310 311static void ath9k_hw_iqcal_collect(struct ath_hal *ah) 312{ 313 struct ath_hal_5416 *ahp = AH5416(ah); 314 int i; 315 316 for (i = 0; i < AR5416_MAX_CHAINS; i++) { 317 ahp->ah_totalPowerMeasI[i] += 318 REG_READ(ah, AR_PHY_CAL_MEAS_0(i)); 319 ahp->ah_totalPowerMeasQ[i] += 320 REG_READ(ah, AR_PHY_CAL_MEAS_1(i)); 321 ahp->ah_totalIqCorrMeas[i] += 322 (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i)); 323 DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, 324 "%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n", 325 ahp->ah_CalSamples, i, ahp->ah_totalPowerMeasI[i], 326 ahp->ah_totalPowerMeasQ[i], 327 ahp->ah_totalIqCorrMeas[i]); 328 } 329} 330 331static void ath9k_hw_adc_gaincal_collect(struct ath_hal *ah) 332{ 333 struct ath_hal_5416 *ahp = AH5416(ah); 334 int i; 335 336 for (i = 0; i < AR5416_MAX_CHAINS; i++) { 337 ahp->ah_totalAdcIOddPhase[i] += 338 REG_READ(ah, AR_PHY_CAL_MEAS_0(i)); 339 ahp->ah_totalAdcIEvenPhase[i] += 340 REG_READ(ah, AR_PHY_CAL_MEAS_1(i)); 341 ahp->ah_totalAdcQOddPhase[i] += 342 REG_READ(ah, AR_PHY_CAL_MEAS_2(i)); 343 ahp->ah_totalAdcQEvenPhase[i] += 344 REG_READ(ah, AR_PHY_CAL_MEAS_3(i)); 345 346 DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, 347 "%d: Chn %d oddi=0x%08x; eveni=0x%08x; " 348 "oddq=0x%08x; evenq=0x%08x;\n", 349 ahp->ah_CalSamples, i, 350 ahp->ah_totalAdcIOddPhase[i], 351 ahp->ah_totalAdcIEvenPhase[i], 352 ahp->ah_totalAdcQOddPhase[i], 353 ahp->ah_totalAdcQEvenPhase[i]); 354 } 355} 356 357static void ath9k_hw_adc_dccal_collect(struct ath_hal *ah) 358{ 359 struct ath_hal_5416 *ahp = AH5416(ah); 360 int i; 361 362 for (i = 0; i < AR5416_MAX_CHAINS; i++) { 363 ahp->ah_totalAdcDcOffsetIOddPhase[i] += 364 (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_0(i)); 365 ahp->ah_totalAdcDcOffsetIEvenPhase[i] += 366 (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_1(i)); 367 ahp->ah_totalAdcDcOffsetQOddPhase[i] += 368 (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i)); 369 ahp->ah_totalAdcDcOffsetQEvenPhase[i] += 370 (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_3(i)); 371 372 DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, 373 "%d: Chn %d oddi=0x%08x; eveni=0x%08x; " 374 "oddq=0x%08x; evenq=0x%08x;\n", 375 ahp->ah_CalSamples, i, 376 ahp->ah_totalAdcDcOffsetIOddPhase[i], 377 ahp->ah_totalAdcDcOffsetIEvenPhase[i], 378 ahp->ah_totalAdcDcOffsetQOddPhase[i], 379 ahp->ah_totalAdcDcOffsetQEvenPhase[i]); 380 } 381} 382 383static void ath9k_hw_iqcalibrate(struct ath_hal *ah, u8 numChains) 384{ 385 struct ath_hal_5416 *ahp = AH5416(ah); 386 u32 powerMeasQ, powerMeasI, iqCorrMeas; 387 u32 qCoffDenom, iCoffDenom; 388 int32_t qCoff, iCoff; 389 int iqCorrNeg, i; 390 391 for (i = 0; i < numChains; i++) { 392 powerMeasI = ahp->ah_totalPowerMeasI[i]; 393 powerMeasQ = ahp->ah_totalPowerMeasQ[i]; 394 iqCorrMeas = ahp->ah_totalIqCorrMeas[i]; 395 396 DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, 397 "Starting IQ Cal and Correction for Chain %d\n", 398 i); 399 400 DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, 401 "Orignal: Chn %diq_corr_meas = 0x%08x\n", 402 i, ahp->ah_totalIqCorrMeas[i]); 403 404 iqCorrNeg = 0; 405 406 if (iqCorrMeas > 0x80000000) { 407 iqCorrMeas = (0xffffffff - iqCorrMeas) + 1; 408 iqCorrNeg = 1; 409 } 410 411 DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, 412 "Chn %d pwr_meas_i = 0x%08x\n", i, powerMeasI); 413 DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, 414 "Chn %d pwr_meas_q = 0x%08x\n", i, powerMeasQ); 415 DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, "iqCorrNeg is 0x%08x\n", 416 iqCorrNeg); 417 418 iCoffDenom = (powerMeasI / 2 + powerMeasQ / 2) / 128; 419 qCoffDenom = powerMeasQ / 64; 420 421 if (powerMeasQ != 0) { 422 iCoff = iqCorrMeas / iCoffDenom; 423 qCoff = powerMeasI / qCoffDenom - 64; 424 DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, 425 "Chn %d iCoff = 0x%08x\n", i, iCoff); 426 DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, 427 "Chn %d qCoff = 0x%08x\n", i, qCoff); 428 429 iCoff = iCoff & 0x3f; 430 DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, 431 "New: Chn %d iCoff = 0x%08x\n", i, iCoff); 432 if (iqCorrNeg == 0x0) 433 iCoff = 0x40 - iCoff; 434 435 if (qCoff > 15) 436 qCoff = 15; 437 else if (qCoff <= -16) 438 qCoff = 16; 439 440 DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, 441 "Chn %d : iCoff = 0x%x qCoff = 0x%x\n", 442 i, iCoff, qCoff); 443 444 REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(i), 445 AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF, 446 iCoff); 447 REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(i), 448 AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF, 449 qCoff); 450 DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, 451 "IQ Cal and Correction done for Chain %d\n", 452 i); 453 } 454 } 455 456 REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4(0), 457 AR_PHY_TIMING_CTRL4_IQCORR_ENABLE); 458} 459 460static void ath9k_hw_adc_gaincal_calibrate(struct ath_hal *ah, u8 numChains) 461{ 462 struct ath_hal_5416 *ahp = AH5416(ah); 463 u32 iOddMeasOffset, iEvenMeasOffset, qOddMeasOffset, qEvenMeasOffset; 464 u32 qGainMismatch, iGainMismatch, val, i; 465 466 for (i = 0; i < numChains; i++) { 467 iOddMeasOffset = ahp->ah_totalAdcIOddPhase[i]; 468 iEvenMeasOffset = ahp->ah_totalAdcIEvenPhase[i]; 469 qOddMeasOffset = ahp->ah_totalAdcQOddPhase[i]; 470 qEvenMeasOffset = ahp->ah_totalAdcQEvenPhase[i]; 471 472 DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, 473 "Starting ADC Gain Cal for Chain %d\n", i); 474 475 DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, 476 "Chn %d pwr_meas_odd_i = 0x%08x\n", i, 477 iOddMeasOffset); 478 DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, 479 "Chn %d pwr_meas_even_i = 0x%08x\n", i, 480 iEvenMeasOffset); 481 DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, 482 "Chn %d pwr_meas_odd_q = 0x%08x\n", i, 483 qOddMeasOffset); 484 DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, 485 "Chn %d pwr_meas_even_q = 0x%08x\n", i, 486 qEvenMeasOffset); 487 488 if (iOddMeasOffset != 0 && qEvenMeasOffset != 0) { 489 iGainMismatch = 490 ((iEvenMeasOffset * 32) / 491 iOddMeasOffset) & 0x3f; 492 qGainMismatch = 493 ((qOddMeasOffset * 32) / 494 qEvenMeasOffset) & 0x3f; 495 496 DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, 497 "Chn %d gain_mismatch_i = 0x%08x\n", i, 498 iGainMismatch); 499 DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, 500 "Chn %d gain_mismatch_q = 0x%08x\n", i, 501 qGainMismatch); 502 503 val = REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i)); 504 val &= 0xfffff000; 505 val |= (qGainMismatch) | (iGainMismatch << 6); 506 REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val); 507 508 DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, 509 "ADC Gain Cal done for Chain %d\n", i); 510 } 511 } 512 513 REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0), 514 REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0)) | 515 AR_PHY_NEW_ADC_GAIN_CORR_ENABLE); 516} 517 518static void ath9k_hw_adc_dccal_calibrate(struct ath_hal *ah, u8 numChains) 519{ 520 struct ath_hal_5416 *ahp = AH5416(ah); 521 u32 iOddMeasOffset, iEvenMeasOffset, val, i; 522 int32_t qOddMeasOffset, qEvenMeasOffset, qDcMismatch, iDcMismatch; 523 const struct hal_percal_data *calData = 524 ahp->ah_cal_list_curr->calData; 525 u32 numSamples = 526 (1 << (calData->calCountMax + 5)) * calData->calNumSamples; 527 528 for (i = 0; i < numChains; i++) { 529 iOddMeasOffset = ahp->ah_totalAdcDcOffsetIOddPhase[i]; 530 iEvenMeasOffset = ahp->ah_totalAdcDcOffsetIEvenPhase[i]; 531 qOddMeasOffset = ahp->ah_totalAdcDcOffsetQOddPhase[i]; 532 qEvenMeasOffset = ahp->ah_totalAdcDcOffsetQEvenPhase[i]; 533 534 DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, 535 "Starting ADC DC Offset Cal for Chain %d\n", i); 536 537 DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, 538 "Chn %d pwr_meas_odd_i = %d\n", i, 539 iOddMeasOffset); 540 DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, 541 "Chn %d pwr_meas_even_i = %d\n", i, 542 iEvenMeasOffset); 543 DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, 544 "Chn %d pwr_meas_odd_q = %d\n", i, 545 qOddMeasOffset); 546 DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, 547 "Chn %d pwr_meas_even_q = %d\n", i, 548 qEvenMeasOffset); 549 550 iDcMismatch = (((iEvenMeasOffset - iOddMeasOffset) * 2) / 551 numSamples) & 0x1ff; 552 qDcMismatch = (((qOddMeasOffset - qEvenMeasOffset) * 2) / 553 numSamples) & 0x1ff; 554 555 DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, 556 "Chn %d dc_offset_mismatch_i = 0x%08x\n", i, 557 iDcMismatch); 558 DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, 559 "Chn %d dc_offset_mismatch_q = 0x%08x\n", i, 560 qDcMismatch); 561 562 val = REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i)); 563 val &= 0xc0000fff; 564 val |= (qDcMismatch << 12) | (iDcMismatch << 21); 565 REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val); 566 567 DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, 568 "ADC DC Offset Cal done for Chain %d\n", i); 569 } 570 571 REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0), 572 REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0)) | 573 AR_PHY_NEW_ADC_DC_OFFSET_CORR_ENABLE); 574} 575 576void ath9k_hw_reset_calvalid(struct ath_hal *ah, struct ath9k_channel *chan, 577 bool *isCalDone) 578{ 579 struct ath_hal_5416 *ahp = AH5416(ah); 580 struct ath9k_channel *ichan = 581 ath9k_regd_check_channel(ah, chan); 582 struct hal_cal_list *currCal = ahp->ah_cal_list_curr; 583 584 *isCalDone = true; 585 586 if (!AR_SREV_9100(ah) && !AR_SREV_9160_10_OR_LATER(ah)) 587 return; 588 589 if (currCal == NULL) 590 return; 591 592 if (ichan == NULL) { 593 DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, 594 "invalid channel %u/0x%x; no mapping\n", 595 chan->channel, chan->channelFlags); 596 return; 597 } 598 599 600 if (currCal->calState != CAL_DONE) { 601 DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, 602 "Calibration state incorrect, %d\n", 603 currCal->calState); 604 return; 605 } 606 607 608 if (!ath9k_hw_iscal_supported(ah, chan, currCal->calData->calType)) 609 return; 610 611 DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, 612 "Resetting Cal %d state for channel %u/0x%x\n", 613 currCal->calData->calType, chan->channel, 614 chan->channelFlags); 615 616 ichan->CalValid &= ~currCal->calData->calType; 617 currCal->calState = CAL_WAITING; 618 619 *isCalDone = false; 620} 621 622void ath9k_hw_start_nfcal(struct ath_hal *ah) 623{ 624 REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, 625 AR_PHY_AGC_CONTROL_ENABLE_NF); 626 REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, 627 AR_PHY_AGC_CONTROL_NO_UPDATE_NF); 628 REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF); 629} 630 631void ath9k_hw_loadnf(struct ath_hal *ah, struct ath9k_channel *chan) 632{ 633 struct ath9k_nfcal_hist *h; 634 int i, j; 635 int32_t val; 636 const u32 ar5416_cca_regs[6] = { 637 AR_PHY_CCA, 638 AR_PHY_CH1_CCA, 639 AR_PHY_CH2_CCA, 640 AR_PHY_EXT_CCA, 641 AR_PHY_CH1_EXT_CCA, 642 AR_PHY_CH2_EXT_CCA 643 }; 644 u8 chainmask; 645 646 if (AR_SREV_9280(ah)) 647 chainmask = 0x1B; 648 else 649 chainmask = 0x3F; 650 651#ifdef ATH_NF_PER_CHAN 652 h = chan->nfCalHist; 653#else 654 h = ah->nfCalHist; 655#endif 656 657 for (i = 0; i < NUM_NF_READINGS; i++) { 658 if (chainmask & (1 << i)) { 659 val = REG_READ(ah, ar5416_cca_regs[i]); 660 val &= 0xFFFFFE00; 661 val |= (((u32) (h[i].privNF) << 1) & 0x1ff); 662 REG_WRITE(ah, ar5416_cca_regs[i], val); 663 } 664 } 665 666 REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, 667 AR_PHY_AGC_CONTROL_ENABLE_NF); 668 REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, 669 AR_PHY_AGC_CONTROL_NO_UPDATE_NF); 670 REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF); 671 672 for (j = 0; j < 1000; j++) { 673 if ((REG_READ(ah, AR_PHY_AGC_CONTROL) & 674 AR_PHY_AGC_CONTROL_NF) == 0) 675 break; 676 udelay(10); 677 } 678 679 for (i = 0; i < NUM_NF_READINGS; i++) { 680 if (chainmask & (1 << i)) { 681 val = REG_READ(ah, ar5416_cca_regs[i]); 682 val &= 0xFFFFFE00; 683 val |= (((u32) (-50) << 1) & 0x1ff); 684 REG_WRITE(ah, ar5416_cca_regs[i], val); 685 } 686 } 687} 688 689int16_t ath9k_hw_getnf(struct ath_hal *ah, 690 struct ath9k_channel *chan) 691{ 692 int16_t nf, nfThresh; 693 int16_t nfarray[NUM_NF_READINGS] = { 0 }; 694 struct ath9k_nfcal_hist *h; 695 u8 chainmask; 696 697 if (AR_SREV_9280(ah)) 698 chainmask = 0x1B; 699 else 700 chainmask = 0x3F; 701 702 chan->channelFlags &= (~CHANNEL_CW_INT); 703 if (REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) { 704 DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, 705 "NF did not complete in calibration window\n"); 706 nf = 0; 707 chan->rawNoiseFloor = nf; 708 return chan->rawNoiseFloor; 709 } else { 710 ath9k_hw_do_getnf(ah, nfarray); 711 nf = nfarray[0]; 712 if (getNoiseFloorThresh(ah, chan, &nfThresh) 713 && nf > nfThresh) { 714 DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, 715 "noise floor failed detected; " 716 "detected %d, threshold %d\n", 717 nf, nfThresh); 718 chan->channelFlags |= CHANNEL_CW_INT; 719 } 720 } 721 722#ifdef ATH_NF_PER_CHAN 723 h = chan->nfCalHist; 724#else 725 h = ah->nfCalHist; 726#endif 727 728 ath9k_hw_update_nfcal_hist_buffer(h, nfarray); 729 chan->rawNoiseFloor = h[0].privNF; 730 731 return chan->rawNoiseFloor; 732} 733 734void ath9k_init_nfcal_hist_buffer(struct ath_hal *ah) 735{ 736 int i, j; 737 738 for (i = 0; i < NUM_NF_READINGS; i++) { 739 ah->nfCalHist[i].currIndex = 0; 740 ah->nfCalHist[i].privNF = AR_PHY_CCA_MAX_GOOD_VALUE; 741 ah->nfCalHist[i].invalidNFcount = 742 AR_PHY_CCA_FILTERWINDOW_LENGTH; 743 for (j = 0; j < ATH9K_NF_CAL_HIST_MAX; j++) { 744 ah->nfCalHist[i].nfCalBuffer[j] = 745 AR_PHY_CCA_MAX_GOOD_VALUE; 746 } 747 } 748 return; 749} 750 751s16 ath9k_hw_getchan_noise(struct ath_hal *ah, struct ath9k_channel *chan) 752{ 753 struct ath9k_channel *ichan; 754 s16 nf; 755 756 ichan = ath9k_regd_check_channel(ah, chan); 757 if (ichan == NULL) { 758 DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, 759 "invalid channel %u/0x%x; no mapping\n", 760 chan->channel, chan->channelFlags); 761 return ATH_DEFAULT_NOISE_FLOOR; 762 } 763 if (ichan->rawNoiseFloor == 0) { 764 enum wireless_mode mode = ath9k_hw_chan2wmode(ah, chan); 765 nf = NOISE_FLOOR[mode]; 766 } else 767 nf = ichan->rawNoiseFloor; 768 769 if (!ath9k_hw_nf_in_range(ah, nf)) 770 nf = ATH_DEFAULT_NOISE_FLOOR; 771 772 return nf; 773} 774 775bool ath9k_hw_calibrate(struct ath_hal *ah, struct ath9k_channel *chan, 776 u8 rxchainmask, bool longcal, 777 bool *isCalDone) 778{ 779 struct ath_hal_5416 *ahp = AH5416(ah); 780 struct hal_cal_list *currCal = ahp->ah_cal_list_curr; 781 struct ath9k_channel *ichan = ath9k_regd_check_channel(ah, chan); 782 783 *isCalDone = true; 784 785 if (ichan == NULL) { 786 DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, 787 "invalid channel %u/0x%x; no mapping\n", 788 chan->channel, chan->channelFlags); 789 return false; 790 } 791 792 if (currCal && 793 (currCal->calState == CAL_RUNNING || 794 currCal->calState == CAL_WAITING)) { 795 ath9k_hw_per_calibration(ah, ichan, rxchainmask, currCal, 796 isCalDone); 797 if (*isCalDone) { 798 ahp->ah_cal_list_curr = currCal = currCal->calNext; 799 800 if (currCal->calState == CAL_WAITING) { 801 *isCalDone = false; 802 ath9k_hw_reset_calibration(ah, currCal); 803 } 804 } 805 } 806 807 if (longcal) { 808 ath9k_hw_getnf(ah, ichan); 809 ath9k_hw_loadnf(ah, ah->ah_curchan); 810 ath9k_hw_start_nfcal(ah); 811 812 if ((ichan->channelFlags & CHANNEL_CW_INT) != 0) { 813 chan->channelFlags |= CHANNEL_CW_INT; 814 ichan->channelFlags &= ~CHANNEL_CW_INT; 815 } 816 } 817 818 return true; 819} 820 821static inline void ath9k_hw_9285_pa_cal(struct ath_hal *ah) 822{ 823 824 u32 regVal; 825 int i, offset, offs_6_1, offs_0; 826 u32 ccomp_org, reg_field; 827 u32 regList[][2] = { 828 { 0x786c, 0 }, 829 { 0x7854, 0 }, 830 { 0x7820, 0 }, 831 { 0x7824, 0 }, 832 { 0x7868, 0 }, 833 { 0x783c, 0 }, 834 { 0x7838, 0 }, 835 }; 836 837 if (AR_SREV_9285_11(ah)) { 838 REG_WRITE(ah, AR9285_AN_TOP4, (AR9285_AN_TOP4_DEFAULT | 0x14)); 839 udelay(10); 840 } 841 842 for (i = 0; i < ARRAY_SIZE(regList); i++) 843 regList[i][1] = REG_READ(ah, regList[i][0]); 844 845 regVal = REG_READ(ah, 0x7834); 846 regVal &= (~(0x1)); 847 REG_WRITE(ah, 0x7834, regVal); 848 regVal = REG_READ(ah, 0x9808); 849 regVal |= (0x1 << 27); 850 REG_WRITE(ah, 0x9808, regVal); 851 852 REG_RMW_FIELD(ah, AR9285_AN_TOP3, AR9285_AN_TOP3_PWDDAC, 1); 853 REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDRXTXBB1, 1); 854 REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDV2I, 1); 855 REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDDACIF, 1); 856 REG_RMW_FIELD(ah, AR9285_AN_RF2G2, AR9285_AN_RF2G2_OFFCAL, 0); 857 REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PWDDB, 0); 858 REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_ENPACAL, 0); 859 REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV1, 1); 860 REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV2, 0); 861 REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPAOUT, 0); 862 REG_RMW_FIELD(ah, AR9285_AN_RF2G8, AR9285_AN_RF2G8_PADRVGN2TAB0, 7); 863 REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PADRVGN2TAB0, 0); 864 ccomp_org = MS(REG_READ(ah, AR9285_AN_RF2G6), AR9285_AN_RF2G6_CCOMP); 865 REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_CCOMP, 7); 866 867 REG_WRITE(ah, AR9285_AN_TOP2, 0xca0358a0); 868 udelay(30); 869 REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_OFFS, 0); 870 REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, 0); 871 872 for (i = 6; i > 0; i--) { 873 regVal = REG_READ(ah, 0x7834); 874 regVal |= (1 << (19 + i)); 875 REG_WRITE(ah, 0x7834, regVal); 876 udelay(1); 877 regVal = REG_READ(ah, 0x7834); 878 regVal &= (~(0x1 << (19 + i))); 879 reg_field = MS(REG_READ(ah, 0x7840), AR9285_AN_RXTXBB1_SPARE9); 880 regVal |= (reg_field << (19 + i)); 881 REG_WRITE(ah, 0x7834, regVal); 882 } 883 884 REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, 1); 885 udelay(1); 886 reg_field = MS(REG_READ(ah, AR9285_AN_RF2G9), AR9285_AN_RXTXBB1_SPARE9); 887 REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, reg_field); 888 offs_6_1 = MS(REG_READ(ah, AR9285_AN_RF2G6), AR9285_AN_RF2G6_OFFS); 889 offs_0 = MS(REG_READ(ah, AR9285_AN_RF2G3), AR9285_AN_RF2G3_PDVCCOMP); 890 891 offset = (offs_6_1<<1) | offs_0; 892 offset = offset - 0; 893 offs_6_1 = offset>>1; 894 offs_0 = offset & 1; 895 896 REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_OFFS, offs_6_1); 897 REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, offs_0); 898 899 regVal = REG_READ(ah, 0x7834); 900 regVal |= 0x1; 901 REG_WRITE(ah, 0x7834, regVal); 902 regVal = REG_READ(ah, 0x9808); 903 regVal &= (~(0x1 << 27)); 904 REG_WRITE(ah, 0x9808, regVal); 905 906 for (i = 0; i < ARRAY_SIZE(regList); i++) 907 REG_WRITE(ah, regList[i][0], regList[i][1]); 908 909 REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_CCOMP, ccomp_org); 910 911 if (AR_SREV_9285_11(ah)) 912 REG_WRITE(ah, AR9285_AN_TOP4, AR9285_AN_TOP4_DEFAULT); 913 914} 915 916bool ath9k_hw_init_cal(struct ath_hal *ah, 917 struct ath9k_channel *chan) 918{ 919 struct ath_hal_5416 *ahp = AH5416(ah); 920 struct ath9k_channel *ichan = ath9k_regd_check_channel(ah, chan); 921 922 REG_WRITE(ah, AR_PHY_AGC_CONTROL, 923 REG_READ(ah, AR_PHY_AGC_CONTROL) | 924 AR_PHY_AGC_CONTROL_CAL); 925 926 if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 0)) { 927 DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, 928 "offset calibration failed to complete in 1ms; " 929 "noisy environment?\n"); 930 return false; 931 } 932 933 if (AR_SREV_9285(ah) && AR_SREV_9285_11_OR_LATER(ah)) 934 ath9k_hw_9285_pa_cal(ah); 935 936 REG_WRITE(ah, AR_PHY_AGC_CONTROL, 937 REG_READ(ah, AR_PHY_AGC_CONTROL) | 938 AR_PHY_AGC_CONTROL_NF); 939 940 ahp->ah_cal_list = ahp->ah_cal_list_last = ahp->ah_cal_list_curr = NULL; 941 942 if (AR_SREV_9100(ah) || AR_SREV_9160_10_OR_LATER(ah)) { 943 if (ath9k_hw_iscal_supported(ah, chan, ADC_GAIN_CAL)) { 944 INIT_CAL(&ahp->ah_adcGainCalData); 945 INSERT_CAL(ahp, &ahp->ah_adcGainCalData); 946 DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, 947 "enabling ADC Gain Calibration.\n"); 948 } 949 if (ath9k_hw_iscal_supported(ah, chan, ADC_DC_CAL)) { 950 INIT_CAL(&ahp->ah_adcDcCalData); 951 INSERT_CAL(ahp, &ahp->ah_adcDcCalData); 952 DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, 953 "enabling ADC DC Calibration.\n"); 954 } 955 if (ath9k_hw_iscal_supported(ah, chan, IQ_MISMATCH_CAL)) { 956 INIT_CAL(&ahp->ah_iqCalData); 957 INSERT_CAL(ahp, &ahp->ah_iqCalData); 958 DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, 959 "enabling IQ Calibration.\n"); 960 } 961 962 ahp->ah_cal_list_curr = ahp->ah_cal_list; 963 964 if (ahp->ah_cal_list_curr) 965 ath9k_hw_reset_calibration(ah, ahp->ah_cal_list_curr); 966 } 967 968 ichan->CalValid = 0; 969 970 return true; 971} 972 973const struct hal_percal_data iq_cal_multi_sample = { 974 IQ_MISMATCH_CAL, 975 MAX_CAL_SAMPLES, 976 PER_MIN_LOG_COUNT, 977 ath9k_hw_iqcal_collect, 978 ath9k_hw_iqcalibrate 979}; 980const struct hal_percal_data iq_cal_single_sample = { 981 IQ_MISMATCH_CAL, 982 MIN_CAL_SAMPLES, 983 PER_MAX_LOG_COUNT, 984 ath9k_hw_iqcal_collect, 985 ath9k_hw_iqcalibrate 986}; 987const struct hal_percal_data adc_gain_cal_multi_sample = { 988 ADC_GAIN_CAL, 989 MAX_CAL_SAMPLES, 990 PER_MIN_LOG_COUNT, 991 ath9k_hw_adc_gaincal_collect, 992 ath9k_hw_adc_gaincal_calibrate 993}; 994const struct hal_percal_data adc_gain_cal_single_sample = { 995 ADC_GAIN_CAL, 996 MIN_CAL_SAMPLES, 997 PER_MAX_LOG_COUNT, 998 ath9k_hw_adc_gaincal_collect, 999 ath9k_hw_adc_gaincal_calibrate 1000}; 1001const struct hal_percal_data adc_dc_cal_multi_sample = { 1002 ADC_DC_CAL, 1003 MAX_CAL_SAMPLES, 1004 PER_MIN_LOG_COUNT, 1005 ath9k_hw_adc_dccal_collect, 1006 ath9k_hw_adc_dccal_calibrate 1007}; 1008const struct hal_percal_data adc_dc_cal_single_sample = { 1009 ADC_DC_CAL, 1010 MIN_CAL_SAMPLES, 1011 PER_MAX_LOG_COUNT, 1012 ath9k_hw_adc_dccal_collect, 1013 ath9k_hw_adc_dccal_calibrate 1014}; 1015const struct hal_percal_data adc_init_dc_cal = { 1016 ADC_DC_INIT_CAL, 1017 MIN_CAL_SAMPLES, 1018 INIT_LOG_COUNT, 1019 ath9k_hw_adc_dccal_collect, 1020 ath9k_hw_adc_dccal_calibrate 1021};