1/* 2 * Copyright (c) 2008-2009 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 "hw.h" 18#include "hw-ops.h" 19 20/* Common calibration code */ 21 22/* We can tune this as we go by monitoring really low values */ 23#define ATH9K_NF_TOO_LOW -60 24 25static int16_t ath9k_hw_get_nf_hist_mid(int16_t *nfCalBuffer) 26{ 27 int16_t nfval; 28 int16_t sort[ATH9K_NF_CAL_HIST_MAX]; 29 int i, j; 30 31 for (i = 0; i < ATH9K_NF_CAL_HIST_MAX; i++) 32 sort[i] = nfCalBuffer[i]; 33 34 for (i = 0; i < ATH9K_NF_CAL_HIST_MAX - 1; i++) { 35 for (j = 1; j < ATH9K_NF_CAL_HIST_MAX - i; j++) { 36 if (sort[j] > sort[j - 1]) { 37 nfval = sort[j]; 38 sort[j] = sort[j - 1]; 39 sort[j - 1] = nfval; 40 } 41 } 42 } 43 nfval = sort[(ATH9K_NF_CAL_HIST_MAX - 1) >> 1]; 44 45 return nfval; 46} 47 48static void ath9k_hw_update_nfcal_hist_buffer(struct ath9k_nfcal_hist *h, 49 int16_t *nfarray) 50{ 51 int i; 52 53 for (i = 0; i < NUM_NF_READINGS; i++) { 54 h[i].nfCalBuffer[h[i].currIndex] = nfarray[i]; 55 56 if (++h[i].currIndex >= ATH9K_NF_CAL_HIST_MAX) 57 h[i].currIndex = 0; 58 59 if (h[i].invalidNFcount > 0) { 60 h[i].invalidNFcount--; 61 h[i].privNF = nfarray[i]; 62 } else { 63 h[i].privNF = 64 ath9k_hw_get_nf_hist_mid(h[i].nfCalBuffer); 65 } 66 } 67} 68 69static bool ath9k_hw_get_nf_thresh(struct ath_hw *ah, 70 enum ieee80211_band band, 71 int16_t *nft) 72{ 73 switch (band) { 74 case IEEE80211_BAND_5GHZ: 75 *nft = (int8_t)ah->eep_ops->get_eeprom(ah, EEP_NFTHRESH_5); 76 break; 77 case IEEE80211_BAND_2GHZ: 78 *nft = (int8_t)ah->eep_ops->get_eeprom(ah, EEP_NFTHRESH_2); 79 break; 80 default: 81 BUG_ON(1); 82 return false; 83 } 84 85 return true; 86} 87 88void ath9k_hw_reset_calibration(struct ath_hw *ah, 89 struct ath9k_cal_list *currCal) 90{ 91 int i; 92 93 ath9k_hw_setup_calibration(ah, currCal); 94 95 currCal->calState = CAL_RUNNING; 96 97 for (i = 0; i < AR5416_MAX_CHAINS; i++) { 98 ah->meas0.sign[i] = 0; 99 ah->meas1.sign[i] = 0; 100 ah->meas2.sign[i] = 0; 101 ah->meas3.sign[i] = 0; 102 } 103 104 ah->cal_samples = 0; 105} 106 107static s16 ath9k_hw_get_default_nf(struct ath_hw *ah, 108 struct ath9k_channel *chan) 109{ 110 struct ath_nf_limits *limit; 111 112 if (!chan || IS_CHAN_2GHZ(chan)) 113 limit = &ah->nf_2g; 114 else 115 limit = &ah->nf_5g; 116 117 return limit->nominal; 118} 119 120/* This is done for the currently configured channel */ 121bool ath9k_hw_reset_calvalid(struct ath_hw *ah) 122{ 123 struct ath_common *common = ath9k_hw_common(ah); 124 struct ieee80211_conf *conf = &common->hw->conf; 125 struct ath9k_cal_list *currCal = ah->cal_list_curr; 126 127 if (!ah->caldata) 128 return true; 129 130 if (!AR_SREV_9100(ah) && !AR_SREV_9160_10_OR_LATER(ah)) 131 return true; 132 133 if (currCal == NULL) 134 return true; 135 136 if (currCal->calState != CAL_DONE) { 137 ath_print(common, ATH_DBG_CALIBRATE, 138 "Calibration state incorrect, %d\n", 139 currCal->calState); 140 return true; 141 } 142 143 if (!ath9k_hw_iscal_supported(ah, currCal->calData->calType)) 144 return true; 145 146 ath_print(common, ATH_DBG_CALIBRATE, 147 "Resetting Cal %d state for channel %u\n", 148 currCal->calData->calType, conf->channel->center_freq); 149 150 ah->caldata->CalValid &= ~currCal->calData->calType; 151 currCal->calState = CAL_WAITING; 152 153 return false; 154} 155EXPORT_SYMBOL(ath9k_hw_reset_calvalid); 156 157void ath9k_hw_start_nfcal(struct ath_hw *ah, bool update) 158{ 159 if (ah->caldata) 160 ah->caldata->nfcal_pending = true; 161 162 REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, 163 AR_PHY_AGC_CONTROL_ENABLE_NF); 164 165 if (update) 166 REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, 167 AR_PHY_AGC_CONTROL_NO_UPDATE_NF); 168 else 169 REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, 170 AR_PHY_AGC_CONTROL_NO_UPDATE_NF); 171 172 REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF); 173} 174 175void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan) 176{ 177 struct ath9k_nfcal_hist *h = NULL; 178 unsigned i, j; 179 int32_t val; 180 u8 chainmask = (ah->rxchainmask << 3) | ah->rxchainmask; 181 struct ath_common *common = ath9k_hw_common(ah); 182 s16 default_nf = ath9k_hw_get_default_nf(ah, chan); 183 184 if (ah->caldata) 185 h = ah->caldata->nfCalHist; 186 187 for (i = 0; i < NUM_NF_READINGS; i++) { 188 if (chainmask & (1 << i)) { 189 s16 nfval; 190 191 if (h) 192 nfval = h[i].privNF; 193 else 194 nfval = default_nf; 195 196 val = REG_READ(ah, ah->nf_regs[i]); 197 val &= 0xFFFFFE00; 198 val |= (((u32) nfval << 1) & 0x1ff); 199 REG_WRITE(ah, ah->nf_regs[i], val); 200 } 201 } 202 203 /* 204 * Load software filtered NF value into baseband internal minCCApwr 205 * variable. 206 */ 207 REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, 208 AR_PHY_AGC_CONTROL_ENABLE_NF); 209 REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, 210 AR_PHY_AGC_CONTROL_NO_UPDATE_NF); 211 REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF); 212 213 /* 214 * Wait for load to complete, should be fast, a few 10s of us. 215 * The max delay was changed from an original 250us to 10000us 216 * since 250us often results in NF load timeout and causes deaf 217 * condition during stress testing 12/12/2009 218 */ 219 for (j = 0; j < 1000; j++) { 220 if ((REG_READ(ah, AR_PHY_AGC_CONTROL) & 221 AR_PHY_AGC_CONTROL_NF) == 0) 222 break; 223 udelay(10); 224 } 225 226 /* 227 * We timed out waiting for the noisefloor to load, probably due to an 228 * in-progress rx. Simply return here and allow the load plenty of time 229 * to complete before the next calibration interval. We need to avoid 230 * trying to load -50 (which happens below) while the previous load is 231 * still in progress as this can cause rx deafness. Instead by returning 232 * here, the baseband nf cal will just be capped by our present 233 * noisefloor until the next calibration timer. 234 */ 235 if (j == 1000) { 236 ath_print(common, ATH_DBG_ANY, "Timeout while waiting for nf " 237 "to load: AR_PHY_AGC_CONTROL=0x%x\n", 238 REG_READ(ah, AR_PHY_AGC_CONTROL)); 239 return; 240 } 241 242 /* 243 * Restore maxCCAPower register parameter again so that we're not capped 244 * by the median we just loaded. This will be initial (and max) value 245 * of next noise floor calibration the baseband does. 246 */ 247 ENABLE_REGWRITE_BUFFER(ah); 248 for (i = 0; i < NUM_NF_READINGS; i++) { 249 if (chainmask & (1 << i)) { 250 val = REG_READ(ah, ah->nf_regs[i]); 251 val &= 0xFFFFFE00; 252 val |= (((u32) (-50) << 1) & 0x1ff); 253 REG_WRITE(ah, ah->nf_regs[i], val); 254 } 255 } 256 REGWRITE_BUFFER_FLUSH(ah); 257 DISABLE_REGWRITE_BUFFER(ah); 258} 259 260 261static void ath9k_hw_nf_sanitize(struct ath_hw *ah, s16 *nf) 262{ 263 struct ath_common *common = ath9k_hw_common(ah); 264 struct ath_nf_limits *limit; 265 int i; 266 267 if (IS_CHAN_2GHZ(ah->curchan)) 268 limit = &ah->nf_2g; 269 else 270 limit = &ah->nf_5g; 271 272 for (i = 0; i < NUM_NF_READINGS; i++) { 273 if (!nf[i]) 274 continue; 275 276 ath_print(common, ATH_DBG_CALIBRATE, 277 "NF calibrated [%s] [chain %d] is %d\n", 278 (i >= 3 ? "ext" : "ctl"), i % 3, nf[i]); 279 280 if (nf[i] > limit->max) { 281 ath_print(common, ATH_DBG_CALIBRATE, 282 "NF[%d] (%d) > MAX (%d), correcting to MAX", 283 i, nf[i], limit->max); 284 nf[i] = limit->max; 285 } else if (nf[i] < limit->min) { 286 ath_print(common, ATH_DBG_CALIBRATE, 287 "NF[%d] (%d) < MIN (%d), correcting to NOM", 288 i, nf[i], limit->min); 289 nf[i] = limit->nominal; 290 } 291 } 292} 293 294bool ath9k_hw_getnf(struct ath_hw *ah, struct ath9k_channel *chan) 295{ 296 struct ath_common *common = ath9k_hw_common(ah); 297 int16_t nf, nfThresh; 298 int16_t nfarray[NUM_NF_READINGS] = { 0 }; 299 struct ath9k_nfcal_hist *h; 300 struct ieee80211_channel *c = chan->chan; 301 struct ath9k_hw_cal_data *caldata = ah->caldata; 302 303 if (!caldata) 304 return false; 305 306 chan->channelFlags &= (~CHANNEL_CW_INT); 307 if (REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) { 308 ath_print(common, ATH_DBG_CALIBRATE, 309 "NF did not complete in calibration window\n"); 310 nf = 0; 311 caldata->rawNoiseFloor = nf; 312 return false; 313 } else { 314 ath9k_hw_do_getnf(ah, nfarray); 315 ath9k_hw_nf_sanitize(ah, nfarray); 316 nf = nfarray[0]; 317 if (ath9k_hw_get_nf_thresh(ah, c->band, &nfThresh) 318 && nf > nfThresh) { 319 ath_print(common, ATH_DBG_CALIBRATE, 320 "noise floor failed detected; " 321 "detected %d, threshold %d\n", 322 nf, nfThresh); 323 chan->channelFlags |= CHANNEL_CW_INT; 324 } 325 } 326 327 h = caldata->nfCalHist; 328 caldata->nfcal_pending = false; 329 ath9k_hw_update_nfcal_hist_buffer(h, nfarray); 330 caldata->rawNoiseFloor = h[0].privNF; 331 return true; 332} 333 334void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah, 335 struct ath9k_channel *chan) 336{ 337 struct ath9k_nfcal_hist *h; 338 s16 default_nf; 339 int i, j; 340 341 if (!ah->caldata) 342 return; 343 344 h = ah->caldata->nfCalHist; 345 default_nf = ath9k_hw_get_default_nf(ah, chan); 346 for (i = 0; i < NUM_NF_READINGS; i++) { 347 h[i].currIndex = 0; 348 h[i].privNF = default_nf; 349 h[i].invalidNFcount = AR_PHY_CCA_FILTERWINDOW_LENGTH; 350 for (j = 0; j < ATH9K_NF_CAL_HIST_MAX; j++) { 351 h[i].nfCalBuffer[j] = default_nf; 352 } 353 } 354} 355 356s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan) 357{ 358 if (!ah->caldata || !ah->caldata->rawNoiseFloor) 359 return ath9k_hw_get_default_nf(ah, chan); 360 361 return ah->caldata->rawNoiseFloor; 362} 363EXPORT_SYMBOL(ath9k_hw_getchan_noise); 364