Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wirel...
[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_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
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_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
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 = (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
197 static 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
231 static 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
251 static 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
288 static 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
311 static 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
331 static 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
357 static 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
383 static 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
460 static 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
518 static 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
576 void 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
622 void 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
631 void 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
689 int16_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
734 void 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
751 s16 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
775 bool 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
821 bool ath9k_hw_init_cal(struct ath_hal *ah,
822                        struct ath9k_channel *chan)
823 {
824         struct ath_hal_5416 *ahp = AH5416(ah);
825         struct ath9k_channel *ichan = ath9k_regd_check_channel(ah, chan);
826
827         REG_WRITE(ah, AR_PHY_AGC_CONTROL,
828                   REG_READ(ah, AR_PHY_AGC_CONTROL) |
829                   AR_PHY_AGC_CONTROL_CAL);
830
831         if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 0)) {
832                 DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
833                         "offset calibration failed to complete in 1ms; "
834                         "noisy environment?\n");
835                 return false;
836         }
837
838         REG_WRITE(ah, AR_PHY_AGC_CONTROL,
839                   REG_READ(ah, AR_PHY_AGC_CONTROL) |
840                   AR_PHY_AGC_CONTROL_NF);
841
842         ahp->ah_cal_list = ahp->ah_cal_list_last = ahp->ah_cal_list_curr = NULL;
843
844         if (AR_SREV_9100(ah) || AR_SREV_9160_10_OR_LATER(ah)) {
845                 if (ath9k_hw_iscal_supported(ah, chan, ADC_GAIN_CAL)) {
846                         INIT_CAL(&ahp->ah_adcGainCalData);
847                         INSERT_CAL(ahp, &ahp->ah_adcGainCalData);
848                         DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
849                                 "enabling ADC Gain Calibration.\n");
850                 }
851                 if (ath9k_hw_iscal_supported(ah, chan, ADC_DC_CAL)) {
852                         INIT_CAL(&ahp->ah_adcDcCalData);
853                         INSERT_CAL(ahp, &ahp->ah_adcDcCalData);
854                         DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
855                                 "enabling ADC DC Calibration.\n");
856                 }
857                 if (ath9k_hw_iscal_supported(ah, chan, IQ_MISMATCH_CAL)) {
858                         INIT_CAL(&ahp->ah_iqCalData);
859                         INSERT_CAL(ahp, &ahp->ah_iqCalData);
860                         DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
861                                 "enabling IQ Calibration.\n");
862                 }
863
864                 ahp->ah_cal_list_curr = ahp->ah_cal_list;
865
866                 if (ahp->ah_cal_list_curr)
867                         ath9k_hw_reset_calibration(ah, ahp->ah_cal_list_curr);
868         }
869
870         ichan->CalValid = 0;
871
872         return true;
873 }
874
875 const struct hal_percal_data iq_cal_multi_sample = {
876         IQ_MISMATCH_CAL,
877         MAX_CAL_SAMPLES,
878         PER_MIN_LOG_COUNT,
879         ath9k_hw_iqcal_collect,
880         ath9k_hw_iqcalibrate
881 };
882 const struct hal_percal_data iq_cal_single_sample = {
883         IQ_MISMATCH_CAL,
884         MIN_CAL_SAMPLES,
885         PER_MAX_LOG_COUNT,
886         ath9k_hw_iqcal_collect,
887         ath9k_hw_iqcalibrate
888 };
889 const struct hal_percal_data adc_gain_cal_multi_sample = {
890         ADC_GAIN_CAL,
891         MAX_CAL_SAMPLES,
892         PER_MIN_LOG_COUNT,
893         ath9k_hw_adc_gaincal_collect,
894         ath9k_hw_adc_gaincal_calibrate
895 };
896 const struct hal_percal_data adc_gain_cal_single_sample = {
897         ADC_GAIN_CAL,
898         MIN_CAL_SAMPLES,
899         PER_MAX_LOG_COUNT,
900         ath9k_hw_adc_gaincal_collect,
901         ath9k_hw_adc_gaincal_calibrate
902 };
903 const struct hal_percal_data adc_dc_cal_multi_sample = {
904         ADC_DC_CAL,
905         MAX_CAL_SAMPLES,
906         PER_MIN_LOG_COUNT,
907         ath9k_hw_adc_dccal_collect,
908         ath9k_hw_adc_dccal_calibrate
909 };
910 const struct hal_percal_data adc_dc_cal_single_sample = {
911         ADC_DC_CAL,
912         MIN_CAL_SAMPLES,
913         PER_MAX_LOG_COUNT,
914         ath9k_hw_adc_dccal_collect,
915         ath9k_hw_adc_dccal_calibrate
916 };
917 const struct hal_percal_data adc_init_dc_cal = {
918         ADC_DC_INIT_CAL,
919         MIN_CAL_SAMPLES,
920         INIT_LOG_COUNT,
921         ath9k_hw_adc_dccal_collect,
922         ath9k_hw_adc_dccal_calibrate
923 };