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_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
);
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_CALIBRATE
,
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_CALIBRATE
,
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_CALIBRATE
,
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_CALIBRATE
,
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 "invalid channel flags 0x%x\n", chan
->channelFlags
);
197 static void ath9k_hw_setup_calibration(struct ath_hal
*ah
,
198 struct hal_cal_list
*currCal
)
200 REG_RMW_FIELD(ah
, AR_PHY_TIMING_CTRL4(0),
201 AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX
,
202 currCal
->calData
->calCountMax
);
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");
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");
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");
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");
227 REG_SET_BIT(ah
, AR_PHY_TIMING_CTRL4(0),
228 AR_PHY_TIMING_CTRL4_DO_CAL
);
231 static void ath9k_hw_reset_calibration(struct ath_hal
*ah
,
232 struct hal_cal_list
*currCal
)
234 struct ath_hal_5416
*ahp
= AH5416(ah
);
237 ath9k_hw_setup_calibration(ah
, currCal
);
239 currCal
->calState
= CAL_RUNNING
;
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;
248 ahp
->ah_CalSamples
= 0;
251 static void ath9k_hw_per_calibration(struct ath_hal
*ah
,
252 struct ath9k_channel
*ichan
,
254 struct hal_cal_list
*currCal
,
257 struct ath_hal_5416
*ahp
= AH5416(ah
);
261 if (currCal
->calState
== CAL_RUNNING
) {
262 if (!(REG_READ(ah
, AR_PHY_TIMING_CTRL4(0)) &
263 AR_PHY_TIMING_CTRL4_DO_CAL
)) {
265 currCal
->calData
->calCollect(ah
);
266 ahp
->ah_CalSamples
++;
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
))
275 currCal
->calData
->calPostProc(ah
, numChains
);
276 ichan
->CalValid
|= currCal
->calData
->calType
;
277 currCal
->calState
= CAL_DONE
;
280 ath9k_hw_setup_calibration(ah
, currCal
);
283 } else if (!(ichan
->CalValid
& currCal
->calData
->calType
)) {
284 ath9k_hw_reset_calibration(ah
, currCal
);
288 static bool ath9k_hw_iscal_supported(struct ath_hal
*ah
,
289 struct ath9k_channel
*chan
,
290 enum hal_cal_types calType
)
292 struct ath_hal_5416
*ahp
= AH5416(ah
);
295 switch (calType
& ahp
->ah_suppCals
) {
296 case IQ_MISMATCH_CAL
:
297 if (!IS_CHAN_B(chan
))
303 && !(IS_CHAN_2GHZ(chan
) && IS_CHAN_HT20(chan
)))
311 static void ath9k_hw_iqcal_collect(struct ath_hal
*ah
)
313 struct ath_hal_5416
*ahp
= AH5416(ah
);
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
]);
331 static void ath9k_hw_adc_gaincal_collect(struct ath_hal
*ah
)
333 struct ath_hal_5416
*ahp
= AH5416(ah
);
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
));
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
]);
357 static void ath9k_hw_adc_dccal_collect(struct ath_hal
*ah
)
359 struct ath_hal_5416
*ahp
= AH5416(ah
);
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
));
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
]);
383 static void ath9k_hw_iqcalibrate(struct ath_hal
*ah
, u8 numChains
)
385 struct ath_hal_5416
*ahp
= AH5416(ah
);
386 u32 powerMeasQ
, powerMeasI
, iqCorrMeas
;
387 u32 qCoffDenom
, iCoffDenom
;
388 int32_t qCoff
, iCoff
;
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
];
396 DPRINTF(ah
->ah_sc
, ATH_DBG_CALIBRATE
,
397 "Starting IQ Cal and Correction for Chain %d\n",
400 DPRINTF(ah
->ah_sc
, ATH_DBG_CALIBRATE
,
401 "Orignal: Chn %diq_corr_meas = 0x%08x\n",
402 i
, ahp
->ah_totalIqCorrMeas
[i
]);
406 if (iqCorrMeas
> 0x80000000) {
407 iqCorrMeas
= (0xffffffff - iqCorrMeas
) + 1;
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",
418 iCoffDenom
= (powerMeasI
/ 2 + powerMeasQ
/ 2) / 128;
419 qCoffDenom
= powerMeasQ
/ 64;
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
);
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
;
437 else if (qCoff
<= -16)
440 DPRINTF(ah
->ah_sc
, ATH_DBG_CALIBRATE
,
441 "Chn %d : iCoff = 0x%x qCoff = 0x%x\n",
444 REG_RMW_FIELD(ah
, AR_PHY_TIMING_CTRL4(i
),
445 AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF
,
447 REG_RMW_FIELD(ah
, AR_PHY_TIMING_CTRL4(i
),
448 AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF
,
450 DPRINTF(ah
->ah_sc
, ATH_DBG_CALIBRATE
,
451 "IQ Cal and Correction done for Chain %d\n",
456 REG_SET_BIT(ah
, AR_PHY_TIMING_CTRL4(0),
457 AR_PHY_TIMING_CTRL4_IQCORR_ENABLE
);
460 static void ath9k_hw_adc_gaincal_calibrate(struct ath_hal
*ah
, u8 numChains
)
462 struct ath_hal_5416
*ahp
= AH5416(ah
);
463 u32 iOddMeasOffset
, iEvenMeasOffset
, qOddMeasOffset
, qEvenMeasOffset
;
464 u32 qGainMismatch
, iGainMismatch
, val
, i
;
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
];
472 DPRINTF(ah
->ah_sc
, ATH_DBG_CALIBRATE
,
473 "Starting ADC Gain Cal for Chain %d\n", i
);
475 DPRINTF(ah
->ah_sc
, ATH_DBG_CALIBRATE
,
476 "Chn %d pwr_meas_odd_i = 0x%08x\n", i
,
478 DPRINTF(ah
->ah_sc
, ATH_DBG_CALIBRATE
,
479 "Chn %d pwr_meas_even_i = 0x%08x\n", i
,
481 DPRINTF(ah
->ah_sc
, ATH_DBG_CALIBRATE
,
482 "Chn %d pwr_meas_odd_q = 0x%08x\n", i
,
484 DPRINTF(ah
->ah_sc
, ATH_DBG_CALIBRATE
,
485 "Chn %d pwr_meas_even_q = 0x%08x\n", i
,
488 if (iOddMeasOffset
!= 0 && qEvenMeasOffset
!= 0) {
490 ((iEvenMeasOffset
* 32) /
491 iOddMeasOffset
) & 0x3f;
493 ((qOddMeasOffset
* 32) /
494 qEvenMeasOffset
) & 0x3f;
496 DPRINTF(ah
->ah_sc
, ATH_DBG_CALIBRATE
,
497 "Chn %d gain_mismatch_i = 0x%08x\n", i
,
499 DPRINTF(ah
->ah_sc
, ATH_DBG_CALIBRATE
,
500 "Chn %d gain_mismatch_q = 0x%08x\n", i
,
503 val
= REG_READ(ah
, AR_PHY_NEW_ADC_DC_GAIN_CORR(i
));
505 val
|= (qGainMismatch
) | (iGainMismatch
<< 6);
506 REG_WRITE(ah
, AR_PHY_NEW_ADC_DC_GAIN_CORR(i
), val
);
508 DPRINTF(ah
->ah_sc
, ATH_DBG_CALIBRATE
,
509 "ADC Gain Cal done for Chain %d\n", i
);
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
);
518 static void ath9k_hw_adc_dccal_calibrate(struct ath_hal
*ah
, u8 numChains
)
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
;
526 (1 << (calData
->calCountMax
+ 5)) * calData
->calNumSamples
;
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
];
534 DPRINTF(ah
->ah_sc
, ATH_DBG_CALIBRATE
,
535 "Starting ADC DC Offset Cal for Chain %d\n", i
);
537 DPRINTF(ah
->ah_sc
, ATH_DBG_CALIBRATE
,
538 "Chn %d pwr_meas_odd_i = %d\n", i
,
540 DPRINTF(ah
->ah_sc
, ATH_DBG_CALIBRATE
,
541 "Chn %d pwr_meas_even_i = %d\n", i
,
543 DPRINTF(ah
->ah_sc
, ATH_DBG_CALIBRATE
,
544 "Chn %d pwr_meas_odd_q = %d\n", i
,
546 DPRINTF(ah
->ah_sc
, ATH_DBG_CALIBRATE
,
547 "Chn %d pwr_meas_even_q = %d\n", i
,
550 iDcMismatch
= (((iEvenMeasOffset
- iOddMeasOffset
) * 2) /
552 qDcMismatch
= (((qOddMeasOffset
- qEvenMeasOffset
) * 2) /
555 DPRINTF(ah
->ah_sc
, ATH_DBG_CALIBRATE
,
556 "Chn %d dc_offset_mismatch_i = 0x%08x\n", i
,
558 DPRINTF(ah
->ah_sc
, ATH_DBG_CALIBRATE
,
559 "Chn %d dc_offset_mismatch_q = 0x%08x\n", i
,
562 val
= REG_READ(ah
, AR_PHY_NEW_ADC_DC_GAIN_CORR(i
));
564 val
|= (qDcMismatch
<< 12) | (iDcMismatch
<< 21);
565 REG_WRITE(ah
, AR_PHY_NEW_ADC_DC_GAIN_CORR(i
), val
);
567 DPRINTF(ah
->ah_sc
, ATH_DBG_CALIBRATE
,
568 "ADC DC Offset Cal done for Chain %d\n", i
);
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
);
576 void ath9k_hw_reset_calvalid(struct ath_hal
*ah
, struct ath9k_channel
*chan
,
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
;
586 if (!AR_SREV_9100(ah
) && !AR_SREV_9160_10_OR_LATER(ah
))
593 DPRINTF(ah
->ah_sc
, ATH_DBG_CALIBRATE
,
594 "invalid channel %u/0x%x; no mapping\n",
595 chan
->channel
, chan
->channelFlags
);
600 if (currCal
->calState
!= CAL_DONE
) {
601 DPRINTF(ah
->ah_sc
, ATH_DBG_CALIBRATE
,
602 "Calibration state incorrect, %d\n",
608 if (!ath9k_hw_iscal_supported(ah
, chan
, currCal
->calData
->calType
))
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
,
616 ichan
->CalValid
&= ~currCal
->calData
->calType
;
617 currCal
->calState
= CAL_WAITING
;
622 void ath9k_hw_start_nfcal(struct ath_hal
*ah
)
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
);
631 void ath9k_hw_loadnf(struct ath_hal
*ah
, struct ath9k_channel
*chan
)
633 struct ath9k_nfcal_hist
*h
;
636 const u32 ar5416_cca_regs
[6] = {
646 if (AR_SREV_9280(ah
))
651 #ifdef ATH_NF_PER_CHAN
657 for (i
= 0; i
< NUM_NF_READINGS
; i
++) {
658 if (chainmask
& (1 << i
)) {
659 val
= REG_READ(ah
, ar5416_cca_regs
[i
]);
661 val
|= (((u32
) (h
[i
].privNF
) << 1) & 0x1ff);
662 REG_WRITE(ah
, ar5416_cca_regs
[i
], val
);
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
);
672 for (j
= 0; j
< 1000; j
++) {
673 if ((REG_READ(ah
, AR_PHY_AGC_CONTROL
) &
674 AR_PHY_AGC_CONTROL_NF
) == 0)
679 for (i
= 0; i
< NUM_NF_READINGS
; i
++) {
680 if (chainmask
& (1 << i
)) {
681 val
= REG_READ(ah
, ar5416_cca_regs
[i
]);
683 val
|= (((u32
) (-50) << 1) & 0x1ff);
684 REG_WRITE(ah
, ar5416_cca_regs
[i
], val
);
689 int16_t ath9k_hw_getnf(struct ath_hal
*ah
,
690 struct ath9k_channel
*chan
)
692 int16_t nf
, nfThresh
;
693 int16_t nfarray
[NUM_NF_READINGS
] = { 0 };
694 struct ath9k_nfcal_hist
*h
;
697 if (AR_SREV_9280(ah
))
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");
707 chan
->rawNoiseFloor
= nf
;
708 return chan
->rawNoiseFloor
;
710 ath9k_hw_do_getnf(ah
, nfarray
);
712 if (getNoiseFloorThresh(ah
, chan
, &nfThresh
)
714 DPRINTF(ah
->ah_sc
, ATH_DBG_CALIBRATE
,
715 "noise floor failed detected; "
716 "detected %d, threshold %d\n",
718 chan
->channelFlags
|= CHANNEL_CW_INT
;
722 #ifdef ATH_NF_PER_CHAN
728 ath9k_hw_update_nfcal_hist_buffer(h
, nfarray
);
729 chan
->rawNoiseFloor
= h
[0].privNF
;
731 return chan
->rawNoiseFloor
;
734 void ath9k_init_nfcal_hist_buffer(struct ath_hal
*ah
)
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
;
751 s16
ath9k_hw_getchan_noise(struct ath_hal
*ah
, struct ath9k_channel
*chan
)
753 struct ath9k_channel
*ichan
;
756 ichan
= ath9k_regd_check_channel(ah
, chan
);
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
;
763 if (ichan
->rawNoiseFloor
== 0) {
764 enum wireless_mode mode
= ath9k_hw_chan2wmode(ah
, chan
);
765 nf
= NOISE_FLOOR
[mode
];
767 nf
= ichan
->rawNoiseFloor
;
769 if (!ath9k_hw_nf_in_range(ah
, nf
))
770 nf
= ATH_DEFAULT_NOISE_FLOOR
;
775 bool ath9k_hw_calibrate(struct ath_hal
*ah
, struct ath9k_channel
*chan
,
776 u8 rxchainmask
, bool longcal
,
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
);
786 DPRINTF(ah
->ah_sc
, ATH_DBG_CHANNEL
,
787 "invalid channel %u/0x%x; no mapping\n",
788 chan
->channel
, chan
->channelFlags
);
793 (currCal
->calState
== CAL_RUNNING
||
794 currCal
->calState
== CAL_WAITING
)) {
795 ath9k_hw_per_calibration(ah
, ichan
, rxchainmask
, currCal
,
798 ahp
->ah_cal_list_curr
= currCal
= currCal
->calNext
;
800 if (currCal
->calState
== CAL_WAITING
) {
802 ath9k_hw_reset_calibration(ah
, currCal
);
808 ath9k_hw_getnf(ah
, ichan
);
809 ath9k_hw_loadnf(ah
, ah
->ah_curchan
);
810 ath9k_hw_start_nfcal(ah
);
812 if ((ichan
->channelFlags
& CHANNEL_CW_INT
) != 0) {
813 chan
->channelFlags
|= CHANNEL_CW_INT
;
814 ichan
->channelFlags
&= ~CHANNEL_CW_INT
;
821 bool ath9k_hw_init_cal(struct ath_hal
*ah
,
822 struct ath9k_channel
*chan
)
824 struct ath_hal_5416
*ahp
= AH5416(ah
);
825 struct ath9k_channel
*ichan
= ath9k_regd_check_channel(ah
, chan
);
827 REG_WRITE(ah
, AR_PHY_AGC_CONTROL
,
828 REG_READ(ah
, AR_PHY_AGC_CONTROL
) |
829 AR_PHY_AGC_CONTROL_CAL
);
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");
838 REG_WRITE(ah
, AR_PHY_AGC_CONTROL
,
839 REG_READ(ah
, AR_PHY_AGC_CONTROL
) |
840 AR_PHY_AGC_CONTROL_NF
);
842 ahp
->ah_cal_list
= ahp
->ah_cal_list_last
= ahp
->ah_cal_list_curr
= NULL
;
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");
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");
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");
864 ahp
->ah_cal_list_curr
= ahp
->ah_cal_list
;
866 if (ahp
->ah_cal_list_curr
)
867 ath9k_hw_reset_calibration(ah
, ahp
->ah_cal_list_curr
);
875 const struct hal_percal_data iq_cal_multi_sample
= {
879 ath9k_hw_iqcal_collect
,
882 const struct hal_percal_data iq_cal_single_sample
= {
886 ath9k_hw_iqcal_collect
,
889 const struct hal_percal_data adc_gain_cal_multi_sample
= {
893 ath9k_hw_adc_gaincal_collect
,
894 ath9k_hw_adc_gaincal_calibrate
896 const struct hal_percal_data adc_gain_cal_single_sample
= {
900 ath9k_hw_adc_gaincal_collect
,
901 ath9k_hw_adc_gaincal_calibrate
903 const struct hal_percal_data adc_dc_cal_multi_sample
= {
907 ath9k_hw_adc_dccal_collect
,
908 ath9k_hw_adc_dccal_calibrate
910 const struct hal_percal_data adc_dc_cal_single_sample
= {
914 ath9k_hw_adc_dccal_collect
,
915 ath9k_hw_adc_dccal_calibrate
917 const struct hal_percal_data adc_init_dc_cal
= {
921 ath9k_hw_adc_dccal_collect
,
922 ath9k_hw_adc_dccal_calibrate