Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6
[pandora-kernel.git] / drivers / net / wireless / ath9k / calib.c
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
22 static 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
31 static 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_NF_CAL,
35                         "%s: noise floor value detected (%d) is "
36                         "lower than what we think is a "
37                         "reasonable value (%d)\n",
38                         __func__, nf, ATH9K_NF_TOO_LOW);
39                 return false;
40         }
41         return true;
42 }
43
44 static 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
67 static 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
94 static 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_NF_CAL,
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_NF_CAL,
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_NF_CAL,
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_NF_CAL,
165                         "NF calibrated [ext] [chain 2] is %d\n", nf);
166                 nfarray[5] = nf;
167         }
168 }
169
170 static 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 = (int16_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 = (int16_t)ath9k_hw_get_eeprom(ah, EEP_NFTHRESH_2);
187                 break;
188         default:
189                 DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
190                         "%s: invalid channel flags 0x%x\n", __func__,
191                         chan->channelFlags);
192                 return false;
193         }
194
195         return true;
196 }
197
198 static void ath9k_hw_setup_calibration(struct ath_hal *ah,
199                                        struct hal_cal_list *currCal)
200 {
201         REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(0),
202                       AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX,
203                       currCal->calData->calCountMax);
204
205         switch (currCal->calData->calType) {
206         case IQ_MISMATCH_CAL:
207                 REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_IQ);
208                 DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
209                         "%s: starting IQ Mismatch Calibration\n",
210                         __func__);
211                 break;
212         case ADC_GAIN_CAL:
213                 REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_GAIN);
214                 DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
215                         "%s: starting ADC Gain Calibration\n", __func__);
216                 break;
217         case ADC_DC_CAL:
218                 REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_PER);
219                 DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
220                         "%s: starting ADC DC Calibration\n", __func__);
221                 break;
222         case ADC_DC_INIT_CAL:
223                 REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_INIT);
224                 DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
225                         "%s: starting Init ADC DC Calibration\n",
226                         __func__);
227                 break;
228         }
229
230         REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4(0),
231                     AR_PHY_TIMING_CTRL4_DO_CAL);
232 }
233
234 static void ath9k_hw_reset_calibration(struct ath_hal *ah,
235                                        struct hal_cal_list *currCal)
236 {
237         struct ath_hal_5416 *ahp = AH5416(ah);
238         int i;
239
240         ath9k_hw_setup_calibration(ah, currCal);
241
242         currCal->calState = CAL_RUNNING;
243
244         for (i = 0; i < AR5416_MAX_CHAINS; i++) {
245                 ahp->ah_Meas0.sign[i] = 0;
246                 ahp->ah_Meas1.sign[i] = 0;
247                 ahp->ah_Meas2.sign[i] = 0;
248                 ahp->ah_Meas3.sign[i] = 0;
249         }
250
251         ahp->ah_CalSamples = 0;
252 }
253
254 static void ath9k_hw_per_calibration(struct ath_hal *ah,
255                                      struct ath9k_channel *ichan,
256                                      u8 rxchainmask,
257                                      struct hal_cal_list *currCal,
258                                      bool *isCalDone)
259 {
260         struct ath_hal_5416 *ahp = AH5416(ah);
261
262         *isCalDone = false;
263
264         if (currCal->calState == CAL_RUNNING) {
265                 if (!(REG_READ(ah, AR_PHY_TIMING_CTRL4(0)) &
266                       AR_PHY_TIMING_CTRL4_DO_CAL)) {
267
268                         currCal->calData->calCollect(ah);
269                         ahp->ah_CalSamples++;
270
271                         if (ahp->ah_CalSamples >= currCal->calData->calNumSamples) {
272                                 int i, numChains = 0;
273                                 for (i = 0; i < AR5416_MAX_CHAINS; i++) {
274                                         if (rxchainmask & (1 << i))
275                                                 numChains++;
276                                 }
277
278                                 currCal->calData->calPostProc(ah, numChains);
279                                 ichan->CalValid |= currCal->calData->calType;
280                                 currCal->calState = CAL_DONE;
281                                 *isCalDone = true;
282                         } else {
283                                 ath9k_hw_setup_calibration(ah, currCal);
284                         }
285                 }
286         } else if (!(ichan->CalValid & currCal->calData->calType)) {
287                 ath9k_hw_reset_calibration(ah, currCal);
288         }
289 }
290
291 static bool ath9k_hw_iscal_supported(struct ath_hal *ah,
292                                      struct ath9k_channel *chan,
293                                      enum hal_cal_types calType)
294 {
295         struct ath_hal_5416 *ahp = AH5416(ah);
296         bool retval = false;
297
298         switch (calType & ahp->ah_suppCals) {
299         case IQ_MISMATCH_CAL:
300                 if (!IS_CHAN_B(chan))
301                         retval = true;
302                 break;
303         case ADC_GAIN_CAL:
304         case ADC_DC_CAL:
305                 if (!IS_CHAN_B(chan)
306                     && !(IS_CHAN_2GHZ(chan) && IS_CHAN_HT20(chan)))
307                         retval = true;
308                 break;
309         }
310
311         return retval;
312 }
313
314 static void ath9k_hw_iqcal_collect(struct ath_hal *ah)
315 {
316         struct ath_hal_5416 *ahp = AH5416(ah);
317         int i;
318
319         for (i = 0; i < AR5416_MAX_CHAINS; i++) {
320                 ahp->ah_totalPowerMeasI[i] +=
321                         REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
322                 ahp->ah_totalPowerMeasQ[i] +=
323                         REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
324                 ahp->ah_totalIqCorrMeas[i] +=
325                         (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
326                 DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
327                         "%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n",
328                         ahp->ah_CalSamples, i, ahp->ah_totalPowerMeasI[i],
329                         ahp->ah_totalPowerMeasQ[i],
330                         ahp->ah_totalIqCorrMeas[i]);
331         }
332 }
333
334 static void ath9k_hw_adc_gaincal_collect(struct ath_hal *ah)
335 {
336         struct ath_hal_5416 *ahp = AH5416(ah);
337         int i;
338
339         for (i = 0; i < AR5416_MAX_CHAINS; i++) {
340                 ahp->ah_totalAdcIOddPhase[i] +=
341                         REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
342                 ahp->ah_totalAdcIEvenPhase[i] +=
343                         REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
344                 ahp->ah_totalAdcQOddPhase[i] +=
345                         REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
346                 ahp->ah_totalAdcQEvenPhase[i] +=
347                         REG_READ(ah, AR_PHY_CAL_MEAS_3(i));
348
349                 DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
350                         "%d: Chn %d oddi=0x%08x; eveni=0x%08x; "
351                         "oddq=0x%08x; evenq=0x%08x;\n",
352                         ahp->ah_CalSamples, i,
353                         ahp->ah_totalAdcIOddPhase[i],
354                         ahp->ah_totalAdcIEvenPhase[i],
355                         ahp->ah_totalAdcQOddPhase[i],
356                         ahp->ah_totalAdcQEvenPhase[i]);
357         }
358 }
359
360 static void ath9k_hw_adc_dccal_collect(struct ath_hal *ah)
361 {
362         struct ath_hal_5416 *ahp = AH5416(ah);
363         int i;
364
365         for (i = 0; i < AR5416_MAX_CHAINS; i++) {
366                 ahp->ah_totalAdcDcOffsetIOddPhase[i] +=
367                         (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
368                 ahp->ah_totalAdcDcOffsetIEvenPhase[i] +=
369                         (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
370                 ahp->ah_totalAdcDcOffsetQOddPhase[i] +=
371                         (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
372                 ahp->ah_totalAdcDcOffsetQEvenPhase[i] +=
373                         (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_3(i));
374
375                 DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
376                         "%d: Chn %d oddi=0x%08x; eveni=0x%08x; "
377                         "oddq=0x%08x; evenq=0x%08x;\n",
378                         ahp->ah_CalSamples, i,
379                         ahp->ah_totalAdcDcOffsetIOddPhase[i],
380                         ahp->ah_totalAdcDcOffsetIEvenPhase[i],
381                         ahp->ah_totalAdcDcOffsetQOddPhase[i],
382                         ahp->ah_totalAdcDcOffsetQEvenPhase[i]);
383         }
384 }
385
386 static void ath9k_hw_iqcalibrate(struct ath_hal *ah, u8 numChains)
387 {
388         struct ath_hal_5416 *ahp = AH5416(ah);
389         u32 powerMeasQ, powerMeasI, iqCorrMeas;
390         u32 qCoffDenom, iCoffDenom;
391         int32_t qCoff, iCoff;
392         int iqCorrNeg, i;
393
394         for (i = 0; i < numChains; i++) {
395                 powerMeasI = ahp->ah_totalPowerMeasI[i];
396                 powerMeasQ = ahp->ah_totalPowerMeasQ[i];
397                 iqCorrMeas = ahp->ah_totalIqCorrMeas[i];
398
399                 DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
400                         "Starting IQ Cal and Correction for Chain %d\n",
401                         i);
402
403                 DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
404                         "Orignal: Chn %diq_corr_meas = 0x%08x\n",
405                         i, ahp->ah_totalIqCorrMeas[i]);
406
407                 iqCorrNeg = 0;
408
409                 if (iqCorrMeas > 0x80000000) {
410                         iqCorrMeas = (0xffffffff - iqCorrMeas) + 1;
411                         iqCorrNeg = 1;
412                 }
413
414                 DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
415                         "Chn %d pwr_meas_i = 0x%08x\n", i, powerMeasI);
416                 DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
417                         "Chn %d pwr_meas_q = 0x%08x\n", i, powerMeasQ);
418                 DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, "iqCorrNeg is 0x%08x\n",
419                         iqCorrNeg);
420
421                 iCoffDenom = (powerMeasI / 2 + powerMeasQ / 2) / 128;
422                 qCoffDenom = powerMeasQ / 64;
423
424                 if (powerMeasQ != 0) {
425                         iCoff = iqCorrMeas / iCoffDenom;
426                         qCoff = powerMeasI / qCoffDenom - 64;
427                         DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
428                                 "Chn %d iCoff = 0x%08x\n", i, iCoff);
429                         DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
430                                 "Chn %d qCoff = 0x%08x\n", i, qCoff);
431
432                         iCoff = iCoff & 0x3f;
433                         DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
434                                 "New: Chn %d iCoff = 0x%08x\n", i, iCoff);
435                         if (iqCorrNeg == 0x0)
436                                 iCoff = 0x40 - iCoff;
437
438                         if (qCoff > 15)
439                                 qCoff = 15;
440                         else if (qCoff <= -16)
441                                 qCoff = 16;
442
443                         DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
444                                 "Chn %d : iCoff = 0x%x  qCoff = 0x%x\n",
445                                 i, iCoff, qCoff);
446
447                         REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(i),
448                                       AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF,
449                                       iCoff);
450                         REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(i),
451                                       AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF,
452                                       qCoff);
453                         DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
454                                 "IQ Cal and Correction done for Chain %d\n",
455                                 i);
456                 }
457         }
458
459         REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4(0),
460                     AR_PHY_TIMING_CTRL4_IQCORR_ENABLE);
461 }
462
463 static void ath9k_hw_adc_gaincal_calibrate(struct ath_hal *ah, u8 numChains)
464 {
465         struct ath_hal_5416 *ahp = AH5416(ah);
466         u32 iOddMeasOffset, iEvenMeasOffset, qOddMeasOffset, qEvenMeasOffset;
467         u32 qGainMismatch, iGainMismatch, val, i;
468
469         for (i = 0; i < numChains; i++) {
470                 iOddMeasOffset = ahp->ah_totalAdcIOddPhase[i];
471                 iEvenMeasOffset = ahp->ah_totalAdcIEvenPhase[i];
472                 qOddMeasOffset = ahp->ah_totalAdcQOddPhase[i];
473                 qEvenMeasOffset = ahp->ah_totalAdcQEvenPhase[i];
474
475                 DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
476                         "Starting ADC Gain Cal for Chain %d\n", i);
477
478                 DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
479                         "Chn %d pwr_meas_odd_i = 0x%08x\n", i,
480                         iOddMeasOffset);
481                 DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
482                         "Chn %d pwr_meas_even_i = 0x%08x\n", i,
483                         iEvenMeasOffset);
484                 DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
485                         "Chn %d pwr_meas_odd_q = 0x%08x\n", i,
486                         qOddMeasOffset);
487                 DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
488                         "Chn %d pwr_meas_even_q = 0x%08x\n", i,
489                         qEvenMeasOffset);
490
491                 if (iOddMeasOffset != 0 && qEvenMeasOffset != 0) {
492                         iGainMismatch =
493                                 ((iEvenMeasOffset * 32) /
494                                  iOddMeasOffset) & 0x3f;
495                         qGainMismatch =
496                                 ((qOddMeasOffset * 32) /
497                                  qEvenMeasOffset) & 0x3f;
498
499                         DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
500                                 "Chn %d gain_mismatch_i = 0x%08x\n", i,
501                                 iGainMismatch);
502                         DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
503                                 "Chn %d gain_mismatch_q = 0x%08x\n", i,
504                                 qGainMismatch);
505
506                         val = REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i));
507                         val &= 0xfffff000;
508                         val |= (qGainMismatch) | (iGainMismatch << 6);
509                         REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val);
510
511                         DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
512                                 "ADC Gain Cal done for Chain %d\n", i);
513                 }
514         }
515
516         REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0),
517                   REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0)) |
518                   AR_PHY_NEW_ADC_GAIN_CORR_ENABLE);
519 }
520
521 static void ath9k_hw_adc_dccal_calibrate(struct ath_hal *ah, u8 numChains)
522 {
523         struct ath_hal_5416 *ahp = AH5416(ah);
524         u32 iOddMeasOffset, iEvenMeasOffset, val, i;
525         int32_t qOddMeasOffset, qEvenMeasOffset, qDcMismatch, iDcMismatch;
526         const struct hal_percal_data *calData =
527                 ahp->ah_cal_list_curr->calData;
528         u32 numSamples =
529                 (1 << (calData->calCountMax + 5)) * calData->calNumSamples;
530
531         for (i = 0; i < numChains; i++) {
532                 iOddMeasOffset = ahp->ah_totalAdcDcOffsetIOddPhase[i];
533                 iEvenMeasOffset = ahp->ah_totalAdcDcOffsetIEvenPhase[i];
534                 qOddMeasOffset = ahp->ah_totalAdcDcOffsetQOddPhase[i];
535                 qEvenMeasOffset = ahp->ah_totalAdcDcOffsetQEvenPhase[i];
536
537                 DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
538                         "Starting ADC DC Offset Cal for Chain %d\n", i);
539
540                 DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
541                         "Chn %d pwr_meas_odd_i = %d\n", i,
542                         iOddMeasOffset);
543                 DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
544                         "Chn %d pwr_meas_even_i = %d\n", i,
545                         iEvenMeasOffset);
546                 DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
547                         "Chn %d pwr_meas_odd_q = %d\n", i,
548                         qOddMeasOffset);
549                 DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
550                         "Chn %d pwr_meas_even_q = %d\n", i,
551                         qEvenMeasOffset);
552
553                 iDcMismatch = (((iEvenMeasOffset - iOddMeasOffset) * 2) /
554                                numSamples) & 0x1ff;
555                 qDcMismatch = (((qOddMeasOffset - qEvenMeasOffset) * 2) /
556                                numSamples) & 0x1ff;
557
558                 DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
559                         "Chn %d dc_offset_mismatch_i = 0x%08x\n", i,
560                         iDcMismatch);
561                 DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
562                         "Chn %d dc_offset_mismatch_q = 0x%08x\n", i,
563                         qDcMismatch);
564
565                 val = REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i));
566                 val &= 0xc0000fff;
567                 val |= (qDcMismatch << 12) | (iDcMismatch << 21);
568                 REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val);
569
570                 DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
571                         "ADC DC Offset Cal done for Chain %d\n", i);
572         }
573
574         REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0),
575                   REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0)) |
576                   AR_PHY_NEW_ADC_DC_OFFSET_CORR_ENABLE);
577 }
578
579 void ath9k_hw_reset_calvalid(struct ath_hal *ah, struct ath9k_channel *chan,
580                              bool *isCalDone)
581 {
582         struct ath_hal_5416 *ahp = AH5416(ah);
583         struct ath9k_channel *ichan =
584                 ath9k_regd_check_channel(ah, chan);
585         struct hal_cal_list *currCal = ahp->ah_cal_list_curr;
586
587         *isCalDone = true;
588
589         if (!AR_SREV_9100(ah) && !AR_SREV_9160_10_OR_LATER(ah))
590                 return;
591
592         if (currCal == NULL)
593                 return;
594
595         if (ichan == NULL) {
596                 DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
597                         "%s: invalid channel %u/0x%x; no mapping\n",
598                         __func__, chan->channel, chan->channelFlags);
599                 return;
600         }
601
602
603         if (currCal->calState != CAL_DONE) {
604                 DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
605                         "%s: Calibration state incorrect, %d\n",
606                         __func__, currCal->calState);
607                 return;
608         }
609
610
611         if (!ath9k_hw_iscal_supported(ah, chan, currCal->calData->calType))
612                 return;
613
614         DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
615                 "%s: Resetting Cal %d state for channel %u/0x%x\n",
616                 __func__, currCal->calData->calType, chan->channel,
617                 chan->channelFlags);
618
619         ichan->CalValid &= ~currCal->calData->calType;
620         currCal->calState = CAL_WAITING;
621
622         *isCalDone = false;
623 }
624
625 void ath9k_hw_start_nfcal(struct ath_hal *ah)
626 {
627         REG_SET_BIT(ah, AR_PHY_AGC_CONTROL,
628                     AR_PHY_AGC_CONTROL_ENABLE_NF);
629         REG_SET_BIT(ah, AR_PHY_AGC_CONTROL,
630                     AR_PHY_AGC_CONTROL_NO_UPDATE_NF);
631         REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
632 }
633
634 void ath9k_hw_loadnf(struct ath_hal *ah, struct ath9k_channel *chan)
635 {
636         struct ath9k_nfcal_hist *h;
637         int i, j;
638         int32_t val;
639         const u32 ar5416_cca_regs[6] = {
640                 AR_PHY_CCA,
641                 AR_PHY_CH1_CCA,
642                 AR_PHY_CH2_CCA,
643                 AR_PHY_EXT_CCA,
644                 AR_PHY_CH1_EXT_CCA,
645                 AR_PHY_CH2_EXT_CCA
646         };
647         u8 chainmask;
648
649         if (AR_SREV_9280(ah))
650                 chainmask = 0x1B;
651         else
652                 chainmask = 0x3F;
653
654 #ifdef ATH_NF_PER_CHAN
655         h = chan->nfCalHist;
656 #else
657         h = ah->nfCalHist;
658 #endif
659
660         for (i = 0; i < NUM_NF_READINGS; i++) {
661                 if (chainmask & (1 << i)) {
662                         val = REG_READ(ah, ar5416_cca_regs[i]);
663                         val &= 0xFFFFFE00;
664                         val |= (((u32) (h[i].privNF) << 1) & 0x1ff);
665                         REG_WRITE(ah, ar5416_cca_regs[i], val);
666                 }
667         }
668
669         REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
670                     AR_PHY_AGC_CONTROL_ENABLE_NF);
671         REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
672                     AR_PHY_AGC_CONTROL_NO_UPDATE_NF);
673         REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
674
675         for (j = 0; j < 1000; j++) {
676                 if ((REG_READ(ah, AR_PHY_AGC_CONTROL) &
677                      AR_PHY_AGC_CONTROL_NF) == 0)
678                         break;
679                 udelay(10);
680         }
681
682         for (i = 0; i < NUM_NF_READINGS; i++) {
683                 if (chainmask & (1 << i)) {
684                         val = REG_READ(ah, ar5416_cca_regs[i]);
685                         val &= 0xFFFFFE00;
686                         val |= (((u32) (-50) << 1) & 0x1ff);
687                         REG_WRITE(ah, ar5416_cca_regs[i], val);
688                 }
689         }
690 }
691
692 int16_t ath9k_hw_getnf(struct ath_hal *ah,
693                        struct ath9k_channel *chan)
694 {
695         int16_t nf, nfThresh;
696         int16_t nfarray[NUM_NF_READINGS] = { 0 };
697         struct ath9k_nfcal_hist *h;
698         u8 chainmask;
699
700         if (AR_SREV_9280(ah))
701                 chainmask = 0x1B;
702         else
703                 chainmask = 0x3F;
704
705         chan->channelFlags &= (~CHANNEL_CW_INT);
706         if (REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) {
707                 DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
708                         "%s: NF did not complete in calibration window\n",
709                         __func__);
710                 nf = 0;
711                 chan->rawNoiseFloor = nf;
712                 return chan->rawNoiseFloor;
713         } else {
714                 ath9k_hw_do_getnf(ah, nfarray);
715                 nf = nfarray[0];
716                 if (getNoiseFloorThresh(ah, chan, &nfThresh)
717                     && nf > nfThresh) {
718                         DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
719                                 "%s: noise floor failed detected; "
720                                 "detected %d, threshold %d\n", __func__,
721                                 nf, nfThresh);
722                         chan->channelFlags |= CHANNEL_CW_INT;
723                 }
724         }
725
726 #ifdef ATH_NF_PER_CHAN
727         h = chan->nfCalHist;
728 #else
729         h = ah->nfCalHist;
730 #endif
731
732         ath9k_hw_update_nfcal_hist_buffer(h, nfarray);
733         chan->rawNoiseFloor = h[0].privNF;
734
735         return chan->rawNoiseFloor;
736 }
737
738 void ath9k_init_nfcal_hist_buffer(struct ath_hal *ah)
739 {
740         int i, j;
741
742         for (i = 0; i < NUM_NF_READINGS; i++) {
743                 ah->nfCalHist[i].currIndex = 0;
744                 ah->nfCalHist[i].privNF = AR_PHY_CCA_MAX_GOOD_VALUE;
745                 ah->nfCalHist[i].invalidNFcount =
746                         AR_PHY_CCA_FILTERWINDOW_LENGTH;
747                 for (j = 0; j < ATH9K_NF_CAL_HIST_MAX; j++) {
748                         ah->nfCalHist[i].nfCalBuffer[j] =
749                                 AR_PHY_CCA_MAX_GOOD_VALUE;
750                 }
751         }
752         return;
753 }
754
755 s16 ath9k_hw_getchan_noise(struct ath_hal *ah, struct ath9k_channel *chan)
756 {
757         struct ath9k_channel *ichan;
758         s16 nf;
759
760         ichan = ath9k_regd_check_channel(ah, chan);
761         if (ichan == NULL) {
762                 DPRINTF(ah->ah_sc, ATH_DBG_NF_CAL,
763                         "%s: invalid channel %u/0x%x; no mapping\n",
764                         __func__, chan->channel, chan->channelFlags);
765                 return ATH_DEFAULT_NOISE_FLOOR;
766         }
767         if (ichan->rawNoiseFloor == 0) {
768                 enum wireless_mode mode = ath9k_hw_chan2wmode(ah, chan);
769                 nf = NOISE_FLOOR[mode];
770         } else
771                 nf = ichan->rawNoiseFloor;
772
773         if (!ath9k_hw_nf_in_range(ah, nf))
774                 nf = ATH_DEFAULT_NOISE_FLOOR;
775
776         return nf;
777 }
778
779 bool ath9k_hw_calibrate(struct ath_hal *ah, struct ath9k_channel *chan,
780                         u8 rxchainmask, bool longcal,
781                         bool *isCalDone)
782 {
783         struct ath_hal_5416 *ahp = AH5416(ah);
784         struct hal_cal_list *currCal = ahp->ah_cal_list_curr;
785         struct ath9k_channel *ichan = ath9k_regd_check_channel(ah, chan);
786
787         *isCalDone = true;
788
789         if (ichan == NULL) {
790                 DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
791                         "%s: invalid channel %u/0x%x; no mapping\n",
792                         __func__, chan->channel, chan->channelFlags);
793                 return false;
794         }
795
796         if (currCal &&
797             (currCal->calState == CAL_RUNNING ||
798              currCal->calState == CAL_WAITING)) {
799                 ath9k_hw_per_calibration(ah, ichan, rxchainmask, currCal,
800                                          isCalDone);
801                 if (*isCalDone) {
802                         ahp->ah_cal_list_curr = currCal = currCal->calNext;
803
804                         if (currCal->calState == CAL_WAITING) {
805                                 *isCalDone = false;
806                                 ath9k_hw_reset_calibration(ah, currCal);
807                         }
808                 }
809         }
810
811         if (longcal) {
812                 ath9k_hw_getnf(ah, ichan);
813                 ath9k_hw_loadnf(ah, ah->ah_curchan);
814                 ath9k_hw_start_nfcal(ah);
815
816                 if ((ichan->channelFlags & CHANNEL_CW_INT) != 0) {
817                         chan->channelFlags |= CHANNEL_CW_INT;
818                         ichan->channelFlags &= ~CHANNEL_CW_INT;
819                 }
820         }
821
822         return true;
823 }
824
825 bool ath9k_hw_init_cal(struct ath_hal *ah,
826                        struct ath9k_channel *chan)
827 {
828         struct ath_hal_5416 *ahp = AH5416(ah);
829         struct ath9k_channel *ichan = ath9k_regd_check_channel(ah, chan);
830
831         REG_WRITE(ah, AR_PHY_AGC_CONTROL,
832                   REG_READ(ah, AR_PHY_AGC_CONTROL) |
833                   AR_PHY_AGC_CONTROL_CAL);
834
835         if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 0)) {
836                 DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
837                         "%s: offset calibration failed to complete in 1ms; "
838                         "noisy environment?\n", __func__);
839                 return false;
840         }
841
842         REG_WRITE(ah, AR_PHY_AGC_CONTROL,
843                   REG_READ(ah, AR_PHY_AGC_CONTROL) |
844                   AR_PHY_AGC_CONTROL_NF);
845
846         ahp->ah_cal_list = ahp->ah_cal_list_last = ahp->ah_cal_list_curr = NULL;
847
848         if (AR_SREV_9100(ah) || AR_SREV_9160_10_OR_LATER(ah)) {
849                 if (ath9k_hw_iscal_supported(ah, chan, ADC_GAIN_CAL)) {
850                         INIT_CAL(&ahp->ah_adcGainCalData);
851                         INSERT_CAL(ahp, &ahp->ah_adcGainCalData);
852                         DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
853                                 "%s: enabling ADC Gain Calibration.\n",
854                                 __func__);
855                 }
856                 if (ath9k_hw_iscal_supported(ah, chan, ADC_DC_CAL)) {
857                         INIT_CAL(&ahp->ah_adcDcCalData);
858                         INSERT_CAL(ahp, &ahp->ah_adcDcCalData);
859                         DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
860                                 "%s: enabling ADC DC Calibration.\n",
861                                 __func__);
862                 }
863                 if (ath9k_hw_iscal_supported(ah, chan, IQ_MISMATCH_CAL)) {
864                         INIT_CAL(&ahp->ah_iqCalData);
865                         INSERT_CAL(ahp, &ahp->ah_iqCalData);
866                         DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
867                                 "%s: enabling IQ Calibration.\n",
868                                 __func__);
869                 }
870
871                 ahp->ah_cal_list_curr = ahp->ah_cal_list;
872
873                 if (ahp->ah_cal_list_curr)
874                         ath9k_hw_reset_calibration(ah, ahp->ah_cal_list_curr);
875         }
876
877         ichan->CalValid = 0;
878
879         return true;
880 }
881
882 const struct hal_percal_data iq_cal_multi_sample = {
883         IQ_MISMATCH_CAL,
884         MAX_CAL_SAMPLES,
885         PER_MIN_LOG_COUNT,
886         ath9k_hw_iqcal_collect,
887         ath9k_hw_iqcalibrate
888 };
889 const struct hal_percal_data iq_cal_single_sample = {
890         IQ_MISMATCH_CAL,
891         MIN_CAL_SAMPLES,
892         PER_MAX_LOG_COUNT,
893         ath9k_hw_iqcal_collect,
894         ath9k_hw_iqcalibrate
895 };
896 const struct hal_percal_data adc_gain_cal_multi_sample = {
897         ADC_GAIN_CAL,
898         MAX_CAL_SAMPLES,
899         PER_MIN_LOG_COUNT,
900         ath9k_hw_adc_gaincal_collect,
901         ath9k_hw_adc_gaincal_calibrate
902 };
903 const struct hal_percal_data adc_gain_cal_single_sample = {
904         ADC_GAIN_CAL,
905         MIN_CAL_SAMPLES,
906         PER_MAX_LOG_COUNT,
907         ath9k_hw_adc_gaincal_collect,
908         ath9k_hw_adc_gaincal_calibrate
909 };
910 const struct hal_percal_data adc_dc_cal_multi_sample = {
911         ADC_DC_CAL,
912         MAX_CAL_SAMPLES,
913         PER_MIN_LOG_COUNT,
914         ath9k_hw_adc_dccal_collect,
915         ath9k_hw_adc_dccal_calibrate
916 };
917 const struct hal_percal_data adc_dc_cal_single_sample = {
918         ADC_DC_CAL,
919         MIN_CAL_SAMPLES,
920         PER_MAX_LOG_COUNT,
921         ath9k_hw_adc_dccal_collect,
922         ath9k_hw_adc_dccal_calibrate
923 };
924 const struct hal_percal_data adc_init_dc_cal = {
925         ADC_DC_INIT_CAL,
926         MIN_CAL_SAMPLES,
927         INIT_LOG_COUNT,
928         ath9k_hw_adc_dccal_collect,
929         ath9k_hw_adc_dccal_calibrate
930 };