1 1.1 alc /* 2 1.1 alc * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting 3 1.1 alc * Copyright (c) 2002-2008 Atheros Communications, Inc. 4 1.1 alc * 5 1.1 alc * Permission to use, copy, modify, and/or distribute this software for any 6 1.1 alc * purpose with or without fee is hereby granted, provided that the above 7 1.1 alc * copyright notice and this permission notice appear in all copies. 8 1.1 alc * 9 1.1 alc * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 1.1 alc * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 1.1 alc * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 1.1 alc * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 1.1 alc * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 1.1 alc * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 1.1 alc * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 1.1 alc * 17 1.2 cegger * $Id: ar5416_cal.c,v 1.2 2011/03/07 11:25:44 cegger Exp $ 18 1.1 alc */ 19 1.1 alc #include "opt_ah.h" 20 1.1 alc 21 1.1 alc #include "ah.h" 22 1.1 alc #include "ah_internal.h" 23 1.1 alc #include "ah_devid.h" 24 1.1 alc 25 1.1 alc #include "ah_eeprom_v14.h" 26 1.1 alc 27 1.2 cegger #include "ar5212/ar5212.h" /* for NF cal related declarations */ 28 1.2 cegger 29 1.1 alc #include "ar5416/ar5416.h" 30 1.1 alc #include "ar5416/ar5416reg.h" 31 1.1 alc #include "ar5416/ar5416phy.h" 32 1.1 alc 33 1.1 alc /* Owl specific stuff */ 34 1.1 alc #define NUM_NOISEFLOOR_READINGS 6 /* 3 chains * (ctl + ext) */ 35 1.1 alc 36 1.1 alc static void ar5416StartNFCal(struct ath_hal *ah); 37 1.1 alc static void ar5416LoadNF(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *); 38 1.1 alc static int16_t ar5416GetNf(struct ath_hal *, HAL_CHANNEL_INTERNAL *); 39 1.1 alc 40 1.1 alc /* 41 1.1 alc * Determine if calibration is supported by device and channel flags 42 1.1 alc */ 43 1.1 alc static OS_INLINE HAL_BOOL 44 1.1 alc ar5416IsCalSupp(struct ath_hal *ah, HAL_CHANNEL *chan, HAL_CAL_TYPE calType) 45 1.1 alc { 46 1.1 alc struct ar5416PerCal *cal = &AH5416(ah)->ah_cal; 47 1.1 alc 48 1.1 alc switch (calType & cal->suppCals) { 49 1.1 alc case IQ_MISMATCH_CAL: 50 1.1 alc /* Run IQ Mismatch for non-CCK only */ 51 1.1 alc return !IS_CHAN_B(chan); 52 1.1 alc case ADC_GAIN_CAL: 53 1.1 alc case ADC_DC_CAL: 54 1.1 alc /* Run ADC Gain Cal for non-CCK & non 2GHz-HT20 only */ 55 1.1 alc return !IS_CHAN_B(chan) && 56 1.1 alc !(IS_CHAN_2GHZ(chan) && IS_CHAN_HT20(chan)); 57 1.1 alc } 58 1.1 alc return AH_FALSE; 59 1.1 alc } 60 1.1 alc 61 1.1 alc /* 62 1.1 alc * Setup HW to collect samples used for current cal 63 1.1 alc */ 64 1.1 alc static void 65 1.1 alc ar5416SetupMeasurement(struct ath_hal *ah, HAL_CAL_LIST *currCal) 66 1.1 alc { 67 1.1 alc /* Start calibration w/ 2^(INIT_IQCAL_LOG_COUNT_MAX+1) samples */ 68 1.1 alc OS_REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4, 69 1.1 alc AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX, 70 1.1 alc currCal->calData->calCountMax); 71 1.1 alc 72 1.1 alc /* Select calibration to run */ 73 1.1 alc switch (currCal->calData->calType) { 74 1.1 alc case IQ_MISMATCH_CAL: 75 1.1 alc OS_REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_IQ); 76 1.1 alc HALDEBUG(ah, HAL_DEBUG_PERCAL, 77 1.1 alc "%s: start IQ Mismatch calibration\n", __func__); 78 1.1 alc break; 79 1.1 alc case ADC_GAIN_CAL: 80 1.1 alc OS_REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_GAIN); 81 1.1 alc HALDEBUG(ah, HAL_DEBUG_PERCAL, 82 1.1 alc "%s: start ADC Gain calibration\n", __func__); 83 1.1 alc break; 84 1.1 alc case ADC_DC_CAL: 85 1.1 alc OS_REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_PER); 86 1.1 alc HALDEBUG(ah, HAL_DEBUG_PERCAL, 87 1.1 alc "%s: start ADC DC calibration\n", __func__); 88 1.1 alc break; 89 1.1 alc case ADC_DC_INIT_CAL: 90 1.1 alc OS_REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_INIT); 91 1.1 alc HALDEBUG(ah, HAL_DEBUG_PERCAL, 92 1.1 alc "%s: start Init ADC DC calibration\n", __func__); 93 1.1 alc break; 94 1.1 alc } 95 1.1 alc /* Kick-off cal */ 96 1.1 alc OS_REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4, AR_PHY_TIMING_CTRL4_DO_CAL); 97 1.1 alc } 98 1.1 alc 99 1.1 alc /* 100 1.1 alc * Initialize shared data structures and prepare a cal to be run. 101 1.1 alc */ 102 1.1 alc static void 103 1.1 alc ar5416ResetMeasurement(struct ath_hal *ah, HAL_CAL_LIST *currCal) 104 1.1 alc { 105 1.1 alc struct ar5416PerCal *cal = &AH5416(ah)->ah_cal; 106 1.1 alc 107 1.1 alc /* Reset data structures shared between different calibrations */ 108 1.1 alc OS_MEMZERO(cal->caldata, sizeof(cal->caldata)); 109 1.1 alc cal->calSamples = 0; 110 1.1 alc 111 1.1 alc /* Setup HW for new calibration */ 112 1.1 alc ar5416SetupMeasurement(ah, currCal); 113 1.1 alc 114 1.1 alc /* Change SW state to RUNNING for this calibration */ 115 1.1 alc currCal->calState = CAL_RUNNING; 116 1.1 alc } 117 1.1 alc 118 1.1 alc #if 0 119 1.1 alc /* 120 1.1 alc * Run non-periodic calibrations. 121 1.1 alc */ 122 1.1 alc static HAL_BOOL 123 1.1 alc ar5416RunInitCals(struct ath_hal *ah, int init_cal_count) 124 1.1 alc { 125 1.1 alc struct ath_hal_5416 *ahp = AH5416(ah); 126 1.1 alc struct ar5416PerCal *cal = &AH5416(ah)->ah_cal; 127 1.1 alc HAL_CHANNEL_INTERNAL ichan; /* XXX bogus */ 128 1.1 alc HAL_CAL_LIST *curCal = ahp->ah_cal_curr; 129 1.1 alc HAL_BOOL isCalDone; 130 1.1 alc int i; 131 1.1 alc 132 1.1 alc if (curCal == AH_NULL) 133 1.1 alc return AH_FALSE; 134 1.1 alc 135 1.1 alc ichan.calValid = 0; 136 1.1 alc for (i = 0; i < init_cal_count; i++) { 137 1.1 alc /* Reset this Cal */ 138 1.1 alc ar5416ResetMeasurement(ah, curCal); 139 1.1 alc /* Poll for offset calibration complete */ 140 1.1 alc if (!ath_hal_wait(ah, AR_PHY_TIMING_CTRL4, AR_PHY_TIMING_CTRL4_DO_CAL, 0)) { 141 1.1 alc HALDEBUG(ah, HAL_DEBUG_ANY, 142 1.1 alc "%s: Cal %d failed to finish in 100ms.\n", 143 1.1 alc __func__, curCal->calData->calType); 144 1.1 alc /* Re-initialize list pointers for periodic cals */ 145 1.1 alc cal->cal_list = cal->cal_last = cal->cal_curr = AH_NULL; 146 1.1 alc return AH_FALSE; 147 1.1 alc } 148 1.1 alc /* Run this cal */ 149 1.1 alc ar5416DoCalibration(ah, &ichan, ahp->ah_rxchainmask, 150 1.1 alc curCal, &isCalDone); 151 1.1 alc if (!isCalDone) 152 1.1 alc HALDEBUG(ah, HAL_DEBUG_ANY, 153 1.1 alc "%s: init cal %d did not complete.\n", 154 1.1 alc __func__, curCal->calData->calType); 155 1.1 alc if (curCal->calNext != AH_NULL) 156 1.1 alc curCal = curCal->calNext; 157 1.1 alc } 158 1.1 alc 159 1.1 alc /* Re-initialize list pointers for periodic cals */ 160 1.1 alc cal->cal_list = cal->cal_last = cal->cal_curr = AH_NULL; 161 1.1 alc return AH_TRUE; 162 1.1 alc } 163 1.1 alc #endif 164 1.1 alc 165 1.1 alc /* 166 1.1 alc * Initialize Calibration infrastructure. 167 1.1 alc */ 168 1.1 alc HAL_BOOL 169 1.1 alc ar5416InitCal(struct ath_hal *ah, HAL_CHANNEL *chan) 170 1.1 alc { 171 1.1 alc struct ar5416PerCal *cal = &AH5416(ah)->ah_cal; 172 1.1 alc HAL_CHANNEL_INTERNAL *ichan; 173 1.1 alc 174 1.1 alc ichan = ath_hal_checkchannel(ah, chan); 175 1.1 alc HALASSERT(ichan != AH_NULL); 176 1.1 alc 177 1.1 alc if (AR_SREV_MERLIN_10_OR_LATER(ah)) { 178 1.1 alc /* Enable Rx Filter Cal */ 179 1.1 alc OS_REG_CLR_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC); 180 1.1 alc OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, 181 1.1 alc AR_PHY_AGC_CONTROL_FLTR_CAL); 182 1.1 alc 183 1.1 alc /* Clear the carrier leak cal bit */ 184 1.1 alc OS_REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE); 185 1.1 alc 186 1.1 alc /* kick off the cal */ 187 1.1 alc OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL); 188 1.1 alc 189 1.1 alc /* Poll for offset calibration complete */ 190 1.1 alc if (!ath_hal_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 0)) { 191 1.1 alc HALDEBUG(ah, HAL_DEBUG_ANY, 192 1.1 alc "%s: offset calibration failed to complete in 1ms; " 193 1.1 alc "noisy environment?\n", __func__); 194 1.1 alc return AH_FALSE; 195 1.1 alc } 196 1.1 alc 197 1.1 alc /* Set the cl cal bit and rerun the cal a 2nd time */ 198 1.1 alc /* Enable Rx Filter Cal */ 199 1.1 alc OS_REG_CLR_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC); 200 1.1 alc OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, 201 1.1 alc AR_PHY_AGC_CONTROL_FLTR_CAL); 202 1.1 alc 203 1.1 alc OS_REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE); 204 1.1 alc } 205 1.1 alc 206 1.1 alc /* Calibrate the AGC */ 207 1.1 alc OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL); 208 1.1 alc 209 1.1 alc /* Poll for offset calibration complete */ 210 1.1 alc if (!ath_hal_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 0)) { 211 1.1 alc HALDEBUG(ah, HAL_DEBUG_ANY, 212 1.1 alc "%s: offset calibration did not complete in 1ms; " 213 1.1 alc "noisy environment?\n", __func__); 214 1.1 alc return AH_FALSE; 215 1.1 alc } 216 1.1 alc 217 1.1 alc /* 218 1.1 alc * Do NF calibration after DC offset and other CALs. 219 1.1 alc * Per system engineers, noise floor value can sometimes be 20 dB 220 1.1 alc * higher than normal value if DC offset and noise floor cal are 221 1.1 alc * triggered at the same time. 222 1.1 alc */ 223 1.2 cegger /* XXX this actually kicks off a NF calibration -adrian */ 224 1.1 alc OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF); 225 1.2 cegger /* 226 1.2 cegger * Try to make sure the above NF cal completes, just so 227 1.2 cegger * it doesn't clash with subsequent percals - adrian 228 1.2 cegger */ 229 1.2 cegger if (!ar5212WaitNFCalComplete(ah, 10000)) { 230 1.2 cegger HALDEBUG(ah, HAL_DEBUG_ANY, "%s: initial NF calibration did " 231 1.2 cegger "not complete in time; noisy environment?\n", __func__); 232 1.2 cegger return AH_FALSE; 233 1.2 cegger } 234 1.1 alc 235 1.1 alc /* Initialize list pointers */ 236 1.1 alc cal->cal_list = cal->cal_last = cal->cal_curr = AH_NULL; 237 1.1 alc 238 1.1 alc /* 239 1.1 alc * Enable IQ, ADC Gain, ADC DC Offset Cals 240 1.1 alc */ 241 1.1 alc if (AR_SREV_SOWL_10_OR_LATER(ah)) { 242 1.1 alc /* Setup all non-periodic, init time only calibrations */ 243 1.1 alc /* XXX: Init DC Offset not working yet */ 244 1.1 alc #if 0 245 1.1 alc if (ar5416IsCalSupp(ah, chan, ADC_DC_INIT_CAL)) { 246 1.1 alc INIT_CAL(&cal->adcDcCalInitData); 247 1.1 alc INSERT_CAL(cal, &cal->adcDcCalInitData); 248 1.1 alc } 249 1.1 alc /* Initialize current pointer to first element in list */ 250 1.1 alc cal->cal_curr = cal->cal_list; 251 1.1 alc 252 1.1 alc if (cal->ah_cal_curr != AH_NULL && !ar5416RunInitCals(ah, 0)) 253 1.1 alc return AH_FALSE; 254 1.1 alc #endif 255 1.1 alc } 256 1.1 alc 257 1.1 alc /* If Cals are supported, add them to list via INIT/INSERT_CAL */ 258 1.1 alc if (ar5416IsCalSupp(ah, chan, ADC_GAIN_CAL)) { 259 1.1 alc INIT_CAL(&cal->adcGainCalData); 260 1.1 alc INSERT_CAL(cal, &cal->adcGainCalData); 261 1.1 alc HALDEBUG(ah, HAL_DEBUG_PERCAL, 262 1.1 alc "%s: enable ADC Gain Calibration.\n", __func__); 263 1.1 alc } 264 1.1 alc if (ar5416IsCalSupp(ah, chan, ADC_DC_CAL)) { 265 1.1 alc INIT_CAL(&cal->adcDcCalData); 266 1.1 alc INSERT_CAL(cal, &cal->adcDcCalData); 267 1.1 alc HALDEBUG(ah, HAL_DEBUG_PERCAL, 268 1.1 alc "%s: enable ADC DC Calibration.\n", __func__); 269 1.1 alc } 270 1.1 alc if (ar5416IsCalSupp(ah, chan, IQ_MISMATCH_CAL)) { 271 1.1 alc INIT_CAL(&cal->iqCalData); 272 1.1 alc INSERT_CAL(cal, &cal->iqCalData); 273 1.1 alc HALDEBUG(ah, HAL_DEBUG_PERCAL, 274 1.1 alc "%s: enable IQ Calibration.\n", __func__); 275 1.1 alc } 276 1.1 alc /* Initialize current pointer to first element in list */ 277 1.1 alc cal->cal_curr = cal->cal_list; 278 1.1 alc 279 1.1 alc /* Kick off measurements for the first cal */ 280 1.1 alc if (cal->cal_curr != AH_NULL) 281 1.1 alc ar5416ResetMeasurement(ah, cal->cal_curr); 282 1.1 alc 283 1.1 alc /* Mark all calibrations on this channel as being invalid */ 284 1.1 alc ichan->calValid = 0; 285 1.1 alc 286 1.1 alc return AH_TRUE; 287 1.1 alc } 288 1.1 alc 289 1.1 alc /* 290 1.1 alc * Entry point for upper layers to restart current cal. 291 1.1 alc * Reset the calibration valid bit in channel. 292 1.1 alc */ 293 1.1 alc HAL_BOOL 294 1.1 alc ar5416ResetCalValid(struct ath_hal *ah, HAL_CHANNEL *chan) 295 1.1 alc { 296 1.1 alc struct ar5416PerCal *cal = &AH5416(ah)->ah_cal; 297 1.1 alc HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan); 298 1.1 alc HAL_CAL_LIST *currCal = cal->cal_curr; 299 1.1 alc 300 1.1 alc if (!AR_SREV_SOWL_10_OR_LATER(ah)) 301 1.1 alc return AH_FALSE; 302 1.1 alc if (currCal == AH_NULL) 303 1.1 alc return AH_FALSE; 304 1.1 alc if (ichan == AH_NULL) { 305 1.1 alc HALDEBUG(ah, HAL_DEBUG_ANY, 306 1.1 alc "%s: invalid channel %u/0x%x; no mapping\n", 307 1.1 alc __func__, chan->channel, chan->channelFlags); 308 1.1 alc return AH_FALSE; 309 1.1 alc } 310 1.1 alc /* 311 1.1 alc * Expected that this calibration has run before, post-reset. 312 1.1 alc * Current state should be done 313 1.1 alc */ 314 1.1 alc if (currCal->calState != CAL_DONE) { 315 1.1 alc HALDEBUG(ah, HAL_DEBUG_ANY, 316 1.1 alc "%s: Calibration state incorrect, %d\n", 317 1.1 alc __func__, currCal->calState); 318 1.1 alc return AH_FALSE; 319 1.1 alc } 320 1.1 alc 321 1.1 alc /* Verify Cal is supported on this channel */ 322 1.1 alc if (!ar5416IsCalSupp(ah, chan, currCal->calData->calType)) 323 1.1 alc return AH_FALSE; 324 1.1 alc 325 1.1 alc HALDEBUG(ah, HAL_DEBUG_PERCAL, 326 1.1 alc "%s: Resetting Cal %d state for channel %u/0x%x\n", 327 1.1 alc __func__, currCal->calData->calType, chan->channel, 328 1.1 alc chan->channelFlags); 329 1.1 alc 330 1.1 alc /* Disable cal validity in channel */ 331 1.1 alc ichan->calValid &= ~currCal->calData->calType; 332 1.1 alc currCal->calState = CAL_WAITING; 333 1.1 alc 334 1.1 alc return AH_TRUE; 335 1.1 alc } 336 1.1 alc 337 1.1 alc /* 338 1.1 alc * Recalibrate the lower PHY chips to account for temperature/environment 339 1.1 alc * changes. 340 1.1 alc */ 341 1.1 alc static void 342 1.1 alc ar5416DoCalibration(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *ichan, 343 1.1 alc uint8_t rxchainmask, HAL_CAL_LIST *currCal, HAL_BOOL *isCalDone) 344 1.1 alc { 345 1.1 alc struct ar5416PerCal *cal = &AH5416(ah)->ah_cal; 346 1.1 alc 347 1.1 alc /* Cal is assumed not done until explicitly set below */ 348 1.1 alc *isCalDone = AH_FALSE; 349 1.1 alc 350 1.1 alc HALDEBUG(ah, HAL_DEBUG_PERCAL, 351 1.1 alc "%s: %s Calibration, state %d, calValid 0x%x\n", 352 1.1 alc __func__, currCal->calData->calName, currCal->calState, 353 1.1 alc ichan->calValid); 354 1.1 alc 355 1.1 alc /* Calibration in progress. */ 356 1.1 alc if (currCal->calState == CAL_RUNNING) { 357 1.1 alc /* Check to see if it has finished. */ 358 1.1 alc if (!(OS_REG_READ(ah, AR_PHY_TIMING_CTRL4) & AR_PHY_TIMING_CTRL4_DO_CAL)) { 359 1.1 alc HALDEBUG(ah, HAL_DEBUG_PERCAL, 360 1.1 alc "%s: sample %d of %d finished\n", 361 1.1 alc __func__, cal->calSamples, 362 1.1 alc currCal->calData->calNumSamples); 363 1.1 alc /* 364 1.1 alc * Collect measurements for active chains. 365 1.1 alc */ 366 1.1 alc currCal->calData->calCollect(ah); 367 1.1 alc if (++cal->calSamples >= currCal->calData->calNumSamples) { 368 1.1 alc int i, numChains = 0; 369 1.1 alc for (i = 0; i < AR5416_MAX_CHAINS; i++) { 370 1.1 alc if (rxchainmask & (1 << i)) 371 1.1 alc numChains++; 372 1.1 alc } 373 1.1 alc /* 374 1.1 alc * Process accumulated data 375 1.1 alc */ 376 1.1 alc currCal->calData->calPostProc(ah, numChains); 377 1.1 alc 378 1.1 alc /* Calibration has finished. */ 379 1.1 alc ichan->calValid |= currCal->calData->calType; 380 1.1 alc currCal->calState = CAL_DONE; 381 1.1 alc *isCalDone = AH_TRUE; 382 1.1 alc } else { 383 1.1 alc /* 384 1.1 alc * Set-up to collect of another sub-sample. 385 1.1 alc */ 386 1.1 alc ar5416SetupMeasurement(ah, currCal); 387 1.1 alc } 388 1.1 alc } 389 1.1 alc } else if (!(ichan->calValid & currCal->calData->calType)) { 390 1.1 alc /* If current cal is marked invalid in channel, kick it off */ 391 1.1 alc ar5416ResetMeasurement(ah, currCal); 392 1.1 alc } 393 1.1 alc } 394 1.1 alc 395 1.1 alc /* 396 1.1 alc * Internal interface to schedule periodic calibration work. 397 1.1 alc */ 398 1.1 alc HAL_BOOL 399 1.1 alc ar5416PerCalibrationN(struct ath_hal *ah, HAL_CHANNEL *chan, 400 1.1 alc u_int rxchainmask, HAL_BOOL longcal, HAL_BOOL *isCalDone) 401 1.1 alc { 402 1.1 alc struct ar5416PerCal *cal = &AH5416(ah)->ah_cal; 403 1.1 alc HAL_CAL_LIST *currCal = cal->cal_curr; 404 1.1 alc HAL_CHANNEL_INTERNAL *ichan; 405 1.1 alc 406 1.1 alc OS_MARK(ah, AH_MARK_PERCAL, chan->channel); 407 1.1 alc 408 1.1 alc *isCalDone = AH_TRUE; 409 1.1 alc 410 1.2 cegger /* 411 1.2 cegger * Since ath_hal calls the PerCal method with rxchainmask=0x1; 412 1.2 cegger * override it with the current chainmask. The upper levels currently 413 1.2 cegger * doesn't know about the chainmask. 414 1.2 cegger */ 415 1.2 cegger rxchainmask = AH5416(ah)->ah_rx_chainmask; 416 1.2 cegger 417 1.1 alc /* Invalid channel check */ 418 1.1 alc ichan = ath_hal_checkchannel(ah, chan); 419 1.1 alc if (ichan == AH_NULL) { 420 1.1 alc HALDEBUG(ah, HAL_DEBUG_ANY, 421 1.1 alc "%s: invalid channel %u/0x%x; no mapping\n", 422 1.1 alc __func__, chan->channel, chan->channelFlags); 423 1.1 alc return AH_FALSE; 424 1.1 alc } 425 1.1 alc 426 1.1 alc /* 427 1.1 alc * For given calibration: 428 1.1 alc * 1. Call generic cal routine 429 1.1 alc * 2. When this cal is done (isCalDone) if we have more cals waiting 430 1.1 alc * (eg after reset), mask this to upper layers by not propagating 431 1.1 alc * isCalDone if it is set to TRUE. 432 1.1 alc * Instead, change isCalDone to FALSE and setup the waiting cal(s) 433 1.1 alc * to be run. 434 1.1 alc */ 435 1.1 alc if (currCal != AH_NULL && 436 1.1 alc (currCal->calState == CAL_RUNNING || 437 1.1 alc currCal->calState == CAL_WAITING)) { 438 1.1 alc ar5416DoCalibration(ah, ichan, rxchainmask, currCal, isCalDone); 439 1.1 alc if (*isCalDone == AH_TRUE) { 440 1.1 alc cal->cal_curr = currCal = currCal->calNext; 441 1.1 alc if (currCal->calState == CAL_WAITING) { 442 1.1 alc *isCalDone = AH_FALSE; 443 1.1 alc ar5416ResetMeasurement(ah, currCal); 444 1.1 alc } 445 1.1 alc } 446 1.1 alc } 447 1.1 alc 448 1.1 alc /* Do NF cal only at longer intervals */ 449 1.1 alc if (longcal) { 450 1.1 alc /* 451 1.1 alc * Get the value from the previous NF cal 452 1.1 alc * and update the history buffer. 453 1.1 alc */ 454 1.1 alc ar5416GetNf(ah, ichan); 455 1.1 alc 456 1.1 alc /* 457 1.1 alc * Load the NF from history buffer of the current channel. 458 1.1 alc * NF is slow time-variant, so it is OK to use a 459 1.1 alc * historical value. 460 1.1 alc */ 461 1.1 alc ar5416LoadNF(ah, AH_PRIVATE(ah)->ah_curchan); 462 1.1 alc 463 1.1 alc /* start NF calibration, without updating BB NF register*/ 464 1.1 alc ar5416StartNFCal(ah); 465 1.1 alc } 466 1.1 alc return AH_TRUE; 467 1.1 alc } 468 1.1 alc 469 1.1 alc /* 470 1.1 alc * Recalibrate the lower PHY chips to account for temperature/environment 471 1.1 alc * changes. 472 1.1 alc */ 473 1.1 alc HAL_BOOL 474 1.1 alc ar5416PerCalibration(struct ath_hal *ah, HAL_CHANNEL *chan, HAL_BOOL *isIQdone) 475 1.1 alc { 476 1.1 alc struct ath_hal_5416 *ahp = AH5416(ah); 477 1.1 alc struct ar5416PerCal *cal = &AH5416(ah)->ah_cal; 478 1.1 alc HAL_CAL_LIST *curCal = cal->cal_curr; 479 1.1 alc 480 1.1 alc if (curCal != AH_NULL && curCal->calData->calType == IQ_MISMATCH_CAL) { 481 1.1 alc return ar5416PerCalibrationN(ah, chan, ahp->ah_rx_chainmask, 482 1.1 alc AH_TRUE, isIQdone); 483 1.1 alc } else { 484 1.1 alc HAL_BOOL isCalDone; 485 1.1 alc 486 1.1 alc *isIQdone = AH_FALSE; 487 1.1 alc return ar5416PerCalibrationN(ah, chan, ahp->ah_rx_chainmask, 488 1.1 alc AH_TRUE, &isCalDone); 489 1.1 alc } 490 1.1 alc } 491 1.1 alc 492 1.1 alc static HAL_BOOL 493 1.1 alc ar5416GetEepromNoiseFloorThresh(struct ath_hal *ah, 494 1.1 alc const HAL_CHANNEL_INTERNAL *chan, int16_t *nft) 495 1.1 alc { 496 1.1 alc switch (chan->channelFlags & CHANNEL_ALL_NOTURBO) { 497 1.1 alc case CHANNEL_A: 498 1.1 alc case CHANNEL_A_HT20: 499 1.1 alc case CHANNEL_A_HT40PLUS: 500 1.1 alc case CHANNEL_A_HT40MINUS: 501 1.1 alc ath_hal_eepromGet(ah, AR_EEP_NFTHRESH_5, nft); 502 1.1 alc break; 503 1.1 alc case CHANNEL_B: 504 1.1 alc case CHANNEL_G: 505 1.1 alc case CHANNEL_G_HT20: 506 1.1 alc case CHANNEL_G_HT40PLUS: 507 1.1 alc case CHANNEL_G_HT40MINUS: 508 1.1 alc ath_hal_eepromGet(ah, AR_EEP_NFTHRESH_2, nft); 509 1.1 alc break; 510 1.1 alc default: 511 1.1 alc HALDEBUG(ah, HAL_DEBUG_ANY, 512 1.1 alc "%s: invalid channel flags 0x%x\n", 513 1.1 alc __func__, chan->channelFlags); 514 1.1 alc return AH_FALSE; 515 1.1 alc } 516 1.1 alc return AH_TRUE; 517 1.1 alc } 518 1.1 alc 519 1.1 alc static void 520 1.1 alc ar5416StartNFCal(struct ath_hal *ah) 521 1.1 alc { 522 1.1 alc OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_ENABLE_NF); 523 1.1 alc OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NO_UPDATE_NF); 524 1.1 alc OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF); 525 1.1 alc } 526 1.1 alc 527 1.1 alc static void 528 1.1 alc ar5416LoadNF(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan) 529 1.1 alc { 530 1.1 alc static const uint32_t ar5416_cca_regs[] = { 531 1.1 alc AR_PHY_CCA, 532 1.1 alc AR_PHY_CH1_CCA, 533 1.1 alc AR_PHY_CH2_CCA, 534 1.1 alc AR_PHY_EXT_CCA, 535 1.1 alc AR_PHY_CH1_EXT_CCA, 536 1.1 alc AR_PHY_CH2_EXT_CCA 537 1.1 alc }; 538 1.1 alc struct ar5212NfCalHist *h; 539 1.2 cegger int i; 540 1.1 alc int32_t val; 541 1.1 alc uint8_t chainmask; 542 1.1 alc 543 1.1 alc /* 544 1.1 alc * Force NF calibration for all chains. 545 1.1 alc */ 546 1.1 alc if (AR_SREV_KITE(ah)) { 547 1.1 alc /* Kite has only one chain */ 548 1.1 alc chainmask = 0x9; 549 1.1 alc } else if (AR_SREV_MERLIN(ah)) { 550 1.1 alc /* Merlin has only two chains */ 551 1.1 alc chainmask = 0x1B; 552 1.1 alc } else { 553 1.1 alc chainmask = 0x3F; 554 1.1 alc } 555 1.1 alc 556 1.1 alc /* 557 1.1 alc * Write filtered NF values into maxCCApwr register parameter 558 1.1 alc * so we can load below. 559 1.1 alc */ 560 1.1 alc h = AH5416(ah)->ah_cal.nfCalHist; 561 1.1 alc for (i = 0; i < AR5416_NUM_NF_READINGS; i ++) 562 1.1 alc if (chainmask & (1 << i)) { 563 1.1 alc val = OS_REG_READ(ah, ar5416_cca_regs[i]); 564 1.1 alc val &= 0xFFFFFE00; 565 1.1 alc val |= (((uint32_t)(h[i].privNF) << 1) & 0x1ff); 566 1.1 alc OS_REG_WRITE(ah, ar5416_cca_regs[i], val); 567 1.1 alc } 568 1.1 alc 569 1.1 alc /* Load software filtered NF value into baseband internal minCCApwr variable. */ 570 1.1 alc OS_REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_ENABLE_NF); 571 1.1 alc OS_REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NO_UPDATE_NF); 572 1.1 alc OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF); 573 1.1 alc 574 1.1 alc /* Wait for load to complete, should be fast, a few 10s of us. */ 575 1.2 cegger if (! ar5212WaitNFCalComplete(ah, 10000)) { 576 1.2 cegger /* 577 1.2 cegger * We timed out waiting for the noisefloor to load, probably due 578 1.2 cegger * to an in-progress rx. Simply return here and allow the load 579 1.2 cegger * plenty of time to complete before the next calibration 580 1.2 cegger * interval. We need to avoid trying to load -50 (which happens 581 1.2 cegger * below) while the previous load is still in progress as this 582 1.2 cegger * can cause rx deafness. Instead by returning here, the 583 1.2 cegger * baseband nf cal will just be capped by our present 584 1.2 cegger * noisefloor until the next calibration timer. 585 1.2 cegger */ 586 1.2 cegger HALDEBUG(ah, HAL_DEBUG_ANY, "Timeout while waiting for nf " 587 1.2 cegger "to load: AR_PHY_AGC_CONTROL=0x%x\n", 588 1.2 cegger OS_REG_READ(ah, AR_PHY_AGC_CONTROL)); 589 1.2 cegger return; 590 1.1 alc } 591 1.1 alc 592 1.1 alc /* 593 1.1 alc * Restore maxCCAPower register parameter again so that we're not capped 594 1.1 alc * by the median we just loaded. This will be initial (and max) value 595 1.1 alc * of next noise floor calibration the baseband does. 596 1.1 alc */ 597 1.1 alc for (i = 0; i < AR5416_NUM_NF_READINGS; i ++) 598 1.1 alc if (chainmask & (1 << i)) { 599 1.1 alc val = OS_REG_READ(ah, ar5416_cca_regs[i]); 600 1.1 alc val &= 0xFFFFFE00; 601 1.1 alc val |= (((uint32_t)(-50) << 1) & 0x1ff); 602 1.1 alc OS_REG_WRITE(ah, ar5416_cca_regs[i], val); 603 1.1 alc } 604 1.1 alc } 605 1.1 alc 606 1.1 alc void 607 1.1 alc ar5416InitNfHistBuff(struct ar5212NfCalHist *h) 608 1.1 alc { 609 1.1 alc int i, j; 610 1.1 alc 611 1.1 alc for (i = 0; i < AR5416_NUM_NF_READINGS; i ++) { 612 1.1 alc h[i].currIndex = 0; 613 1.1 alc h[i].privNF = AR5416_CCA_MAX_GOOD_VALUE; 614 1.1 alc h[i].invalidNFcount = AR512_NF_CAL_HIST_MAX; 615 1.1 alc for (j = 0; j < AR512_NF_CAL_HIST_MAX; j ++) 616 1.1 alc h[i].nfCalBuffer[j] = AR5416_CCA_MAX_GOOD_VALUE; 617 1.1 alc } 618 1.1 alc } 619 1.1 alc 620 1.1 alc /* 621 1.1 alc * Update the noise floor buffer as a ring buffer 622 1.1 alc */ 623 1.1 alc static void 624 1.1 alc ar5416UpdateNFHistBuff(struct ar5212NfCalHist *h, int16_t *nfarray) 625 1.1 alc { 626 1.1 alc int i; 627 1.1 alc 628 1.1 alc for (i = 0; i < AR5416_NUM_NF_READINGS; i ++) { 629 1.1 alc h[i].nfCalBuffer[h[i].currIndex] = nfarray[i]; 630 1.1 alc 631 1.1 alc if (++h[i].currIndex >= AR512_NF_CAL_HIST_MAX) 632 1.1 alc h[i].currIndex = 0; 633 1.1 alc if (h[i].invalidNFcount > 0) { 634 1.1 alc if (nfarray[i] < AR5416_CCA_MIN_BAD_VALUE || 635 1.1 alc nfarray[i] > AR5416_CCA_MAX_HIGH_VALUE) { 636 1.1 alc h[i].invalidNFcount = AR512_NF_CAL_HIST_MAX; 637 1.1 alc } else { 638 1.1 alc h[i].invalidNFcount--; 639 1.1 alc h[i].privNF = nfarray[i]; 640 1.1 alc } 641 1.1 alc } else { 642 1.1 alc h[i].privNF = ar5212GetNfHistMid(h[i].nfCalBuffer); 643 1.1 alc } 644 1.1 alc } 645 1.1 alc } 646 1.1 alc 647 1.1 alc /* 648 1.1 alc * Read the NF and check it against the noise floor threshhold 649 1.1 alc */ 650 1.1 alc static int16_t 651 1.1 alc ar5416GetNf(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan) 652 1.1 alc { 653 1.1 alc int16_t nf, nfThresh; 654 1.1 alc 655 1.1 alc if (OS_REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) { 656 1.1 alc HALDEBUG(ah, HAL_DEBUG_ANY, 657 1.1 alc "%s: NF didn't complete in calibration window\n", __func__); 658 1.1 alc nf = 0; 659 1.1 alc } else { 660 1.1 alc /* Finished NF cal, check against threshold */ 661 1.1 alc int16_t nfarray[NUM_NOISEFLOOR_READINGS] = { 0 }; 662 1.1 alc 663 1.1 alc /* TODO - enhance for multiple chains and ext ch */ 664 1.1 alc ath_hal_getNoiseFloor(ah, nfarray); 665 1.1 alc nf = nfarray[0]; 666 1.1 alc if (ar5416GetEepromNoiseFloorThresh(ah, chan, &nfThresh)) { 667 1.1 alc if (nf > nfThresh) { 668 1.1 alc HALDEBUG(ah, HAL_DEBUG_ANY, 669 1.1 alc "%s: noise floor failed detected; " 670 1.1 alc "detected %d, threshold %d\n", __func__, 671 1.1 alc nf, nfThresh); 672 1.1 alc /* 673 1.1 alc * NB: Don't discriminate 2.4 vs 5Ghz, if this 674 1.1 alc * happens it indicates a problem regardless 675 1.1 alc * of the band. 676 1.1 alc */ 677 1.1 alc chan->channelFlags |= CHANNEL_CW_INT; 678 1.1 alc nf = 0; 679 1.1 alc } 680 1.1 alc } else { 681 1.1 alc nf = 0; 682 1.1 alc } 683 1.1 alc ar5416UpdateNFHistBuff(AH5416(ah)->ah_cal.nfCalHist, nfarray); 684 1.1 alc chan->rawNoiseFloor = nf; 685 1.1 alc } 686 1.1 alc return nf; 687 1.1 alc } 688