2 * Copyright (c) 2008 Atheros Communications Inc.
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.
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.
22 static const int16_t NOISE_FLOOR
[] = { -96, -93, -98, -96, -93, -96 };
24 /* We can tune this as we go by monitoring really low values */
25 #define ATH9K_NF_TOO_LOW -60
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 */
31 static bool ath9k_hw_nf_in_range(struct ath_hal
*ah
, s16 nf
)
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
);
44 static int16_t ath9k_hw_get_nf_hist_mid(int16_t *nfCalBuffer
)
47 int16_t sort
[ATH9K_NF_CAL_HIST_MAX
];
50 for (i
= 0; i
< ATH9K_NF_CAL_HIST_MAX
; i
++)
51 sort
[i
] = nfCalBuffer
[i
];
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]) {
57 sort
[j
] = sort
[j
- 1];
62 nfval
= sort
[(ATH9K_NF_CAL_HIST_MAX
- 1) >> 1];
67 static void ath9k_hw_update_nfcal_hist_buffer(struct ath9k_nfcal_hist
*h
,
72 for (i
= 0; i
< NUM_NF_READINGS
; i
++) {
73 h
[i
].nfCalBuffer
[h
[i
].currIndex
] = nfarray
[i
];
75 if (++h
[i
].currIndex
>= ATH9K_NF_CAL_HIST_MAX
)
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
;
83 h
[i
].invalidNFcount
--;
84 h
[i
].privNF
= nfarray
[i
];
88 ath9k_hw_get_nf_hist_mid(h
[i
].nfCalBuffer
);
94 static void ath9k_hw_do_getnf(struct ath_hal
*ah
,
95 int16_t nfarray
[NUM_NF_READINGS
])
99 if (AR_SREV_9280_10_OR_LATER(ah
))
100 nf
= MS(REG_READ(ah
, AR_PHY_CCA
), AR9280_PHY_MINCCA_PWR
);
102 nf
= MS(REG_READ(ah
, AR_PHY_CCA
), AR_PHY_MINCCA_PWR
);
105 nf
= 0 - ((nf
^ 0x1ff) + 1);
106 DPRINTF(ah
->ah_sc
, ATH_DBG_CALIBRATE
,
107 "NF calibrated [ctl] [chain 0] is %d\n", nf
);
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
);
114 nf
= MS(REG_READ(ah
, AR_PHY_CH1_CCA
),
115 AR_PHY_CH1_MINCCA_PWR
);
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
);
123 if (!AR_SREV_9280(ah
)) {
124 nf
= MS(REG_READ(ah
, AR_PHY_CH2_CCA
),
125 AR_PHY_CH2_MINCCA_PWR
);
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
);
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
);
137 nf
= MS(REG_READ(ah
, AR_PHY_EXT_CCA
),
138 AR_PHY_EXT_MINCCA_PWR
);
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
);
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
);
150 nf
= MS(REG_READ(ah
, AR_PHY_CH1_EXT_CCA
),
151 AR_PHY_CH1_EXT_MINCCA_PWR
);
154 nf
= 0 - ((nf
^ 0x1ff) + 1);
155 DPRINTF(ah
->ah_sc
, ATH_DBG_CALIBRATE
,
156 "NF calibrated [ext] [chain 1] is %d\n", nf
);
159 if (!AR_SREV_9280(ah
)) {
160 nf
= MS(REG_READ(ah
, AR_PHY_CH2_EXT_CCA
),
161 AR_PHY_CH2_EXT_MINCCA_PWR
);
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
);
170 static bool getNoiseFloorThresh(struct ath_hal
*ah
,
171 const struct ath9k_channel
*chan
,
174 switch (chan
->chanmode
) {
177 case CHANNEL_A_HT40PLUS
:
178 case CHANNEL_A_HT40MINUS
:
179 *nft
= (int8_t)ath9k_hw_get_eeprom(ah
, EEP_NFTHRESH_5
);
184 case CHANNEL_G_HT40PLUS
:
185 case CHANNEL_G_HT40MINUS
:
186 *nft
= (int8_t)ath9k_hw_get_eeprom(ah
, EEP_NFTHRESH_2
);
189 DPRINTF(ah
->ah_sc
, ATH_DBG_CHANNEL
,
190 "%s: invalid channel flags 0x%x\n", __func__
,
198 static void ath9k_hw_setup_calibration(struct ath_hal
*ah
,
199 struct hal_cal_list
*currCal
)
201 REG_RMW_FIELD(ah
, AR_PHY_TIMING_CTRL4(0),
202 AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX
,
203 currCal
->calData
->calCountMax
);
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",
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__
);
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__
);
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",
230 REG_SET_BIT(ah
, AR_PHY_TIMING_CTRL4(0),
231 AR_PHY_TIMING_CTRL4_DO_CAL
);
234 static void ath9k_hw_reset_calibration(struct ath_hal
*ah
,
235 struct hal_cal_list
*currCal
)
237 struct ath_hal_5416
*ahp
= AH5416(ah
);
240 ath9k_hw_setup_calibration(ah
, currCal
);
242 currCal
->calState
= CAL_RUNNING
;
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;
251 ahp
->ah_CalSamples
= 0;
254 static void ath9k_hw_per_calibration(struct ath_hal
*ah
,
255 struct ath9k_channel
*ichan
,
257 struct hal_cal_list
*currCal
,
260 struct ath_hal_5416
*ahp
= AH5416(ah
);
264 if (currCal
->calState
== CAL_RUNNING
) {
265 if (!(REG_READ(ah
, AR_PHY_TIMING_CTRL4(0)) &
266 AR_PHY_TIMING_CTRL4_DO_CAL
)) {
268 currCal
->calData
->calCollect(ah
);
269 ahp
->ah_CalSamples
++;
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
))
278 currCal
->calData
->calPostProc(ah
, numChains
);
279 ichan
->CalValid
|= currCal
->calData
->calType
;
280 currCal
->calState
= CAL_DONE
;
283 ath9k_hw_setup_calibration(ah
, currCal
);
286 } else if (!(ichan
->CalValid
& currCal
->calData
->calType
)) {
287 ath9k_hw_reset_calibration(ah
, currCal
);
291 static bool ath9k_hw_iscal_supported(struct ath_hal
*ah
,
292 struct ath9k_channel
*chan
,
293 enum hal_cal_types calType
)
295 struct ath_hal_5416
*ahp
= AH5416(ah
);
298 switch (calType
& ahp
->ah_suppCals
) {
299 case IQ_MISMATCH_CAL
:
300 if (!IS_CHAN_B(chan
))
306 && !(IS_CHAN_2GHZ(chan
) && IS_CHAN_HT20(chan
)))
314 static void ath9k_hw_iqcal_collect(struct ath_hal
*ah
)
316 struct ath_hal_5416
*ahp
= AH5416(ah
);
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
]);
334 static void ath9k_hw_adc_gaincal_collect(struct ath_hal
*ah
)
336 struct ath_hal_5416
*ahp
= AH5416(ah
);
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
));
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
]);
360 static void ath9k_hw_adc_dccal_collect(struct ath_hal
*ah
)
362 struct ath_hal_5416
*ahp
= AH5416(ah
);
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
));
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
]);
386 static void ath9k_hw_iqcalibrate(struct ath_hal
*ah
, u8 numChains
)
388 struct ath_hal_5416
*ahp
= AH5416(ah
);
389 u32 powerMeasQ
, powerMeasI
, iqCorrMeas
;
390 u32 qCoffDenom
, iCoffDenom
;
391 int32_t qCoff
, iCoff
;
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
];
399 DPRINTF(ah
->ah_sc
, ATH_DBG_CALIBRATE
,
400 "Starting IQ Cal and Correction for Chain %d\n",
403 DPRINTF(ah
->ah_sc
, ATH_DBG_CALIBRATE
,
404 "Orignal: Chn %diq_corr_meas = 0x%08x\n",
405 i
, ahp
->ah_totalIqCorrMeas
[i
]);
409 if (iqCorrMeas
> 0x80000000) {
410 iqCorrMeas
= (0xffffffff - iqCorrMeas
) + 1;
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",
421 iCoffDenom
= (powerMeasI
/ 2 + powerMeasQ
/ 2) / 128;
422 qCoffDenom
= powerMeasQ
/ 64;
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
);
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
;
440 else if (qCoff
<= -16)
443 DPRINTF(ah
->ah_sc
, ATH_DBG_CALIBRATE
,
444 "Chn %d : iCoff = 0x%x qCoff = 0x%x\n",
447 REG_RMW_FIELD(ah
, AR_PHY_TIMING_CTRL4(i
),
448 AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF
,
450 REG_RMW_FIELD(ah
, AR_PHY_TIMING_CTRL4(i
),
451 AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF
,
453 DPRINTF(ah
->ah_sc
, ATH_DBG_CALIBRATE
,
454 "IQ Cal and Correction done for Chain %d\n",
459 REG_SET_BIT(ah
, AR_PHY_TIMING_CTRL4(0),
460 AR_PHY_TIMING_CTRL4_IQCORR_ENABLE
);
463 static void ath9k_hw_adc_gaincal_calibrate(struct ath_hal
*ah
, u8 numChains
)
465 struct ath_hal_5416
*ahp
= AH5416(ah
);
466 u32 iOddMeasOffset
, iEvenMeasOffset
, qOddMeasOffset
, qEvenMeasOffset
;
467 u32 qGainMismatch
, iGainMismatch
, val
, i
;
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
];
475 DPRINTF(ah
->ah_sc
, ATH_DBG_CALIBRATE
,
476 "Starting ADC Gain Cal for Chain %d\n", i
);
478 DPRINTF(ah
->ah_sc
, ATH_DBG_CALIBRATE
,
479 "Chn %d pwr_meas_odd_i = 0x%08x\n", i
,
481 DPRINTF(ah
->ah_sc
, ATH_DBG_CALIBRATE
,
482 "Chn %d pwr_meas_even_i = 0x%08x\n", i
,
484 DPRINTF(ah
->ah_sc
, ATH_DBG_CALIBRATE
,
485 "Chn %d pwr_meas_odd_q = 0x%08x\n", i
,
487 DPRINTF(ah
->ah_sc
, ATH_DBG_CALIBRATE
,
488 "Chn %d pwr_meas_even_q = 0x%08x\n", i
,
491 if (iOddMeasOffset
!= 0 && qEvenMeasOffset
!= 0) {
493 ((iEvenMeasOffset
* 32) /
494 iOddMeasOffset
) & 0x3f;
496 ((qOddMeasOffset
* 32) /
497 qEvenMeasOffset
) & 0x3f;
499 DPRINTF(ah
->ah_sc
, ATH_DBG_CALIBRATE
,
500 "Chn %d gain_mismatch_i = 0x%08x\n", i
,
502 DPRINTF(ah
->ah_sc
, ATH_DBG_CALIBRATE
,
503 "Chn %d gain_mismatch_q = 0x%08x\n", i
,
506 val
= REG_READ(ah
, AR_PHY_NEW_ADC_DC_GAIN_CORR(i
));
508 val
|= (qGainMismatch
) | (iGainMismatch
<< 6);
509 REG_WRITE(ah
, AR_PHY_NEW_ADC_DC_GAIN_CORR(i
), val
);
511 DPRINTF(ah
->ah_sc
, ATH_DBG_CALIBRATE
,
512 "ADC Gain Cal done for Chain %d\n", i
);
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
);
521 static void ath9k_hw_adc_dccal_calibrate(struct ath_hal
*ah
, u8 numChains
)
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
;
529 (1 << (calData
->calCountMax
+ 5)) * calData
->calNumSamples
;
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
];
537 DPRINTF(ah
->ah_sc
, ATH_DBG_CALIBRATE
,
538 "Starting ADC DC Offset Cal for Chain %d\n", i
);
540 DPRINTF(ah
->ah_sc
, ATH_DBG_CALIBRATE
,
541 "Chn %d pwr_meas_odd_i = %d\n", i
,
543 DPRINTF(ah
->ah_sc
, ATH_DBG_CALIBRATE
,
544 "Chn %d pwr_meas_even_i = %d\n", i
,
546 DPRINTF(ah
->ah_sc
, ATH_DBG_CALIBRATE
,
547 "Chn %d pwr_meas_odd_q = %d\n", i
,
549 DPRINTF(ah
->ah_sc
, ATH_DBG_CALIBRATE
,
550 "Chn %d pwr_meas_even_q = %d\n", i
,
553 iDcMismatch
= (((iEvenMeasOffset
- iOddMeasOffset
) * 2) /
555 qDcMismatch
= (((qOddMeasOffset
- qEvenMeasOffset
) * 2) /
558 DPRINTF(ah
->ah_sc
, ATH_DBG_CALIBRATE
,
559 "Chn %d dc_offset_mismatch_i = 0x%08x\n", i
,
561 DPRINTF(ah
->ah_sc
, ATH_DBG_CALIBRATE
,
562 "Chn %d dc_offset_mismatch_q = 0x%08x\n", i
,
565 val
= REG_READ(ah
, AR_PHY_NEW_ADC_DC_GAIN_CORR(i
));
567 val
|= (qDcMismatch
<< 12) | (iDcMismatch
<< 21);
568 REG_WRITE(ah
, AR_PHY_NEW_ADC_DC_GAIN_CORR(i
), val
);
570 DPRINTF(ah
->ah_sc
, ATH_DBG_CALIBRATE
,
571 "ADC DC Offset Cal done for Chain %d\n", i
);
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
);
579 void ath9k_hw_reset_calvalid(struct ath_hal
*ah
, struct ath9k_channel
*chan
,
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
;
589 if (!AR_SREV_9100(ah
) && !AR_SREV_9160_10_OR_LATER(ah
))
596 DPRINTF(ah
->ah_sc
, ATH_DBG_CALIBRATE
,
597 "%s: invalid channel %u/0x%x; no mapping\n",
598 __func__
, chan
->channel
, chan
->channelFlags
);
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
);
611 if (!ath9k_hw_iscal_supported(ah
, chan
, currCal
->calData
->calType
))
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
,
619 ichan
->CalValid
&= ~currCal
->calData
->calType
;
620 currCal
->calState
= CAL_WAITING
;
625 void ath9k_hw_start_nfcal(struct ath_hal
*ah
)
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
);
634 void ath9k_hw_loadnf(struct ath_hal
*ah
, struct ath9k_channel
*chan
)
636 struct ath9k_nfcal_hist
*h
;
639 const u32 ar5416_cca_regs
[6] = {
649 if (AR_SREV_9280(ah
))
654 #ifdef ATH_NF_PER_CHAN
660 for (i
= 0; i
< NUM_NF_READINGS
; i
++) {
661 if (chainmask
& (1 << i
)) {
662 val
= REG_READ(ah
, ar5416_cca_regs
[i
]);
664 val
|= (((u32
) (h
[i
].privNF
) << 1) & 0x1ff);
665 REG_WRITE(ah
, ar5416_cca_regs
[i
], val
);
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
);
675 for (j
= 0; j
< 1000; j
++) {
676 if ((REG_READ(ah
, AR_PHY_AGC_CONTROL
) &
677 AR_PHY_AGC_CONTROL_NF
) == 0)
682 for (i
= 0; i
< NUM_NF_READINGS
; i
++) {
683 if (chainmask
& (1 << i
)) {
684 val
= REG_READ(ah
, ar5416_cca_regs
[i
]);
686 val
|= (((u32
) (-50) << 1) & 0x1ff);
687 REG_WRITE(ah
, ar5416_cca_regs
[i
], val
);
692 int16_t ath9k_hw_getnf(struct ath_hal
*ah
,
693 struct ath9k_channel
*chan
)
695 int16_t nf
, nfThresh
;
696 int16_t nfarray
[NUM_NF_READINGS
] = { 0 };
697 struct ath9k_nfcal_hist
*h
;
700 if (AR_SREV_9280(ah
))
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",
711 chan
->rawNoiseFloor
= nf
;
712 return chan
->rawNoiseFloor
;
714 ath9k_hw_do_getnf(ah
, nfarray
);
716 if (getNoiseFloorThresh(ah
, chan
, &nfThresh
)
718 DPRINTF(ah
->ah_sc
, ATH_DBG_CALIBRATE
,
719 "%s: noise floor failed detected; "
720 "detected %d, threshold %d\n", __func__
,
722 chan
->channelFlags
|= CHANNEL_CW_INT
;
726 #ifdef ATH_NF_PER_CHAN
732 ath9k_hw_update_nfcal_hist_buffer(h
, nfarray
);
733 chan
->rawNoiseFloor
= h
[0].privNF
;
735 return chan
->rawNoiseFloor
;
738 void ath9k_init_nfcal_hist_buffer(struct ath_hal
*ah
)
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
;
755 s16
ath9k_hw_getchan_noise(struct ath_hal
*ah
, struct ath9k_channel
*chan
)
757 struct ath9k_channel
*ichan
;
760 ichan
= ath9k_regd_check_channel(ah
, chan
);
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
;
767 if (ichan
->rawNoiseFloor
== 0) {
768 enum wireless_mode mode
= ath9k_hw_chan2wmode(ah
, chan
);
769 nf
= NOISE_FLOOR
[mode
];
771 nf
= ichan
->rawNoiseFloor
;
773 if (!ath9k_hw_nf_in_range(ah
, nf
))
774 nf
= ATH_DEFAULT_NOISE_FLOOR
;
779 bool ath9k_hw_calibrate(struct ath_hal
*ah
, struct ath9k_channel
*chan
,
780 u8 rxchainmask
, bool longcal
,
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
);
790 DPRINTF(ah
->ah_sc
, ATH_DBG_CHANNEL
,
791 "%s: invalid channel %u/0x%x; no mapping\n",
792 __func__
, chan
->channel
, chan
->channelFlags
);
797 (currCal
->calState
== CAL_RUNNING
||
798 currCal
->calState
== CAL_WAITING
)) {
799 ath9k_hw_per_calibration(ah
, ichan
, rxchainmask
, currCal
,
802 ahp
->ah_cal_list_curr
= currCal
= currCal
->calNext
;
804 if (currCal
->calState
== CAL_WAITING
) {
806 ath9k_hw_reset_calibration(ah
, currCal
);
812 ath9k_hw_getnf(ah
, ichan
);
813 ath9k_hw_loadnf(ah
, ah
->ah_curchan
);
814 ath9k_hw_start_nfcal(ah
);
816 if ((ichan
->channelFlags
& CHANNEL_CW_INT
) != 0) {
817 chan
->channelFlags
|= CHANNEL_CW_INT
;
818 ichan
->channelFlags
&= ~CHANNEL_CW_INT
;
825 bool ath9k_hw_init_cal(struct ath_hal
*ah
,
826 struct ath9k_channel
*chan
)
828 struct ath_hal_5416
*ahp
= AH5416(ah
);
829 struct ath9k_channel
*ichan
= ath9k_regd_check_channel(ah
, chan
);
831 REG_WRITE(ah
, AR_PHY_AGC_CONTROL
,
832 REG_READ(ah
, AR_PHY_AGC_CONTROL
) |
833 AR_PHY_AGC_CONTROL_CAL
);
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__
);
842 REG_WRITE(ah
, AR_PHY_AGC_CONTROL
,
843 REG_READ(ah
, AR_PHY_AGC_CONTROL
) |
844 AR_PHY_AGC_CONTROL_NF
);
846 ahp
->ah_cal_list
= ahp
->ah_cal_list_last
= ahp
->ah_cal_list_curr
= NULL
;
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",
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",
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",
871 ahp
->ah_cal_list_curr
= ahp
->ah_cal_list
;
873 if (ahp
->ah_cal_list_curr
)
874 ath9k_hw_reset_calibration(ah
, ahp
->ah_cal_list_curr
);
882 const struct hal_percal_data iq_cal_multi_sample
= {
886 ath9k_hw_iqcal_collect
,
889 const struct hal_percal_data iq_cal_single_sample
= {
893 ath9k_hw_iqcal_collect
,
896 const struct hal_percal_data adc_gain_cal_multi_sample
= {
900 ath9k_hw_adc_gaincal_collect
,
901 ath9k_hw_adc_gaincal_calibrate
903 const struct hal_percal_data adc_gain_cal_single_sample
= {
907 ath9k_hw_adc_gaincal_collect
,
908 ath9k_hw_adc_gaincal_calibrate
910 const struct hal_percal_data adc_dc_cal_multi_sample
= {
914 ath9k_hw_adc_dccal_collect
,
915 ath9k_hw_adc_dccal_calibrate
917 const struct hal_percal_data adc_dc_cal_single_sample
= {
921 ath9k_hw_adc_dccal_collect
,
922 ath9k_hw_adc_dccal_calibrate
924 const struct hal_percal_data adc_init_dc_cal
= {
928 ath9k_hw_adc_dccal_collect
,
929 ath9k_hw_adc_dccal_calibrate