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