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 static inline void ath9k_hw_9285_pa_cal(struct ath_hal
*ah
)
825 int i
, offset
, offs_6_1
, offs_0
;
826 u32 ccomp_org
, reg_field
;
837 if (AR_SREV_9285_11(ah
)) {
838 REG_WRITE(ah
, AR9285_AN_TOP4
, (AR9285_AN_TOP4_DEFAULT
| 0x14));
842 for (i
= 0; i
< ARRAY_SIZE(regList
); i
++)
843 regList
[i
][1] = REG_READ(ah
, regList
[i
][0]);
845 regVal
= REG_READ(ah
, 0x7834);
847 REG_WRITE(ah
, 0x7834, regVal
);
848 regVal
= REG_READ(ah
, 0x9808);
849 regVal
|= (0x1 << 27);
850 REG_WRITE(ah
, 0x9808, regVal
);
852 REG_RMW_FIELD(ah
, AR9285_AN_TOP3
, AR9285_AN_TOP3_PWDDAC
, 1);
853 REG_RMW_FIELD(ah
, AR9285_AN_RXTXBB1
, AR9285_AN_RXTXBB1_PDRXTXBB1
, 1);
854 REG_RMW_FIELD(ah
, AR9285_AN_RXTXBB1
, AR9285_AN_RXTXBB1_PDV2I
, 1);
855 REG_RMW_FIELD(ah
, AR9285_AN_RXTXBB1
, AR9285_AN_RXTXBB1_PDDACIF
, 1);
856 REG_RMW_FIELD(ah
, AR9285_AN_RF2G2
, AR9285_AN_RF2G2_OFFCAL
, 0);
857 REG_RMW_FIELD(ah
, AR9285_AN_RF2G7
, AR9285_AN_RF2G7_PWDDB
, 0);
858 REG_RMW_FIELD(ah
, AR9285_AN_RF2G1
, AR9285_AN_RF2G1_ENPACAL
, 0);
859 REG_RMW_FIELD(ah
, AR9285_AN_RF2G1
, AR9285_AN_RF2G1_PDPADRV1
, 1);
860 REG_RMW_FIELD(ah
, AR9285_AN_RF2G1
, AR9285_AN_RF2G1_PDPADRV2
, 0);
861 REG_RMW_FIELD(ah
, AR9285_AN_RF2G1
, AR9285_AN_RF2G1_PDPAOUT
, 0);
862 REG_RMW_FIELD(ah
, AR9285_AN_RF2G8
, AR9285_AN_RF2G8_PADRVGN2TAB0
, 7);
863 REG_RMW_FIELD(ah
, AR9285_AN_RF2G7
, AR9285_AN_RF2G7_PADRVGN2TAB0
, 0);
864 ccomp_org
= MS(REG_READ(ah
, AR9285_AN_RF2G6
), AR9285_AN_RF2G6_CCOMP
);
865 REG_RMW_FIELD(ah
, AR9285_AN_RF2G6
, AR9285_AN_RF2G6_CCOMP
, 7);
867 REG_WRITE(ah
, AR9285_AN_TOP2
, 0xca0358a0);
869 REG_RMW_FIELD(ah
, AR9285_AN_RF2G6
, AR9285_AN_RF2G6_OFFS
, 0);
870 REG_RMW_FIELD(ah
, AR9285_AN_RF2G3
, AR9285_AN_RF2G3_PDVCCOMP
, 0);
872 for (i
= 6; i
> 0; i
--) {
873 regVal
= REG_READ(ah
, 0x7834);
874 regVal
|= (1 << (19 + i
));
875 REG_WRITE(ah
, 0x7834, regVal
);
877 regVal
= REG_READ(ah
, 0x7834);
878 regVal
&= (~(0x1 << (19 + i
)));
879 reg_field
= MS(REG_READ(ah
, 0x7840), AR9285_AN_RXTXBB1_SPARE9
);
880 regVal
|= (reg_field
<< (19 + i
));
881 REG_WRITE(ah
, 0x7834, regVal
);
884 REG_RMW_FIELD(ah
, AR9285_AN_RF2G3
, AR9285_AN_RF2G3_PDVCCOMP
, 1);
886 reg_field
= MS(REG_READ(ah
, AR9285_AN_RF2G9
), AR9285_AN_RXTXBB1_SPARE9
);
887 REG_RMW_FIELD(ah
, AR9285_AN_RF2G3
, AR9285_AN_RF2G3_PDVCCOMP
, reg_field
);
888 offs_6_1
= MS(REG_READ(ah
, AR9285_AN_RF2G6
), AR9285_AN_RF2G6_OFFS
);
889 offs_0
= MS(REG_READ(ah
, AR9285_AN_RF2G3
), AR9285_AN_RF2G3_PDVCCOMP
);
891 offset
= (offs_6_1
<<1) | offs_0
;
893 offs_6_1
= offset
>>1;
896 REG_RMW_FIELD(ah
, AR9285_AN_RF2G6
, AR9285_AN_RF2G6_OFFS
, offs_6_1
);
897 REG_RMW_FIELD(ah
, AR9285_AN_RF2G3
, AR9285_AN_RF2G3_PDVCCOMP
, offs_0
);
899 regVal
= REG_READ(ah
, 0x7834);
901 REG_WRITE(ah
, 0x7834, regVal
);
902 regVal
= REG_READ(ah
, 0x9808);
903 regVal
&= (~(0x1 << 27));
904 REG_WRITE(ah
, 0x9808, regVal
);
906 for (i
= 0; i
< ARRAY_SIZE(regList
); i
++)
907 REG_WRITE(ah
, regList
[i
][0], regList
[i
][1]);
909 REG_RMW_FIELD(ah
, AR9285_AN_RF2G6
, AR9285_AN_RF2G6_CCOMP
, ccomp_org
);
911 if (AR_SREV_9285_11(ah
))
912 REG_WRITE(ah
, AR9285_AN_TOP4
, AR9285_AN_TOP4_DEFAULT
);
916 bool ath9k_hw_init_cal(struct ath_hal
*ah
,
917 struct ath9k_channel
*chan
)
919 struct ath_hal_5416
*ahp
= AH5416(ah
);
920 struct ath9k_channel
*ichan
= ath9k_regd_check_channel(ah
, chan
);
922 REG_WRITE(ah
, AR_PHY_AGC_CONTROL
,
923 REG_READ(ah
, AR_PHY_AGC_CONTROL
) |
924 AR_PHY_AGC_CONTROL_CAL
);
926 if (!ath9k_hw_wait(ah
, AR_PHY_AGC_CONTROL
, AR_PHY_AGC_CONTROL_CAL
, 0)) {
927 DPRINTF(ah
->ah_sc
, ATH_DBG_CALIBRATE
,
928 "offset calibration failed to complete in 1ms; "
929 "noisy environment?\n");
933 if (AR_SREV_9285(ah
) && AR_SREV_9285_11_OR_LATER(ah
))
934 ath9k_hw_9285_pa_cal(ah
);
936 REG_WRITE(ah
, AR_PHY_AGC_CONTROL
,
937 REG_READ(ah
, AR_PHY_AGC_CONTROL
) |
938 AR_PHY_AGC_CONTROL_NF
);
940 ahp
->ah_cal_list
= ahp
->ah_cal_list_last
= ahp
->ah_cal_list_curr
= NULL
;
942 if (AR_SREV_9100(ah
) || AR_SREV_9160_10_OR_LATER(ah
)) {
943 if (ath9k_hw_iscal_supported(ah
, chan
, ADC_GAIN_CAL
)) {
944 INIT_CAL(&ahp
->ah_adcGainCalData
);
945 INSERT_CAL(ahp
, &ahp
->ah_adcGainCalData
);
946 DPRINTF(ah
->ah_sc
, ATH_DBG_CALIBRATE
,
947 "enabling ADC Gain Calibration.\n");
949 if (ath9k_hw_iscal_supported(ah
, chan
, ADC_DC_CAL
)) {
950 INIT_CAL(&ahp
->ah_adcDcCalData
);
951 INSERT_CAL(ahp
, &ahp
->ah_adcDcCalData
);
952 DPRINTF(ah
->ah_sc
, ATH_DBG_CALIBRATE
,
953 "enabling ADC DC Calibration.\n");
955 if (ath9k_hw_iscal_supported(ah
, chan
, IQ_MISMATCH_CAL
)) {
956 INIT_CAL(&ahp
->ah_iqCalData
);
957 INSERT_CAL(ahp
, &ahp
->ah_iqCalData
);
958 DPRINTF(ah
->ah_sc
, ATH_DBG_CALIBRATE
,
959 "enabling IQ Calibration.\n");
962 ahp
->ah_cal_list_curr
= ahp
->ah_cal_list
;
964 if (ahp
->ah_cal_list_curr
)
965 ath9k_hw_reset_calibration(ah
, ahp
->ah_cal_list_curr
);
973 const struct hal_percal_data iq_cal_multi_sample
= {
977 ath9k_hw_iqcal_collect
,
980 const struct hal_percal_data iq_cal_single_sample
= {
984 ath9k_hw_iqcal_collect
,
987 const struct hal_percal_data adc_gain_cal_multi_sample
= {
991 ath9k_hw_adc_gaincal_collect
,
992 ath9k_hw_adc_gaincal_calibrate
994 const struct hal_percal_data adc_gain_cal_single_sample
= {
998 ath9k_hw_adc_gaincal_collect
,
999 ath9k_hw_adc_gaincal_calibrate
1001 const struct hal_percal_data adc_dc_cal_multi_sample
= {
1005 ath9k_hw_adc_dccal_collect
,
1006 ath9k_hw_adc_dccal_calibrate
1008 const struct hal_percal_data adc_dc_cal_single_sample
= {
1012 ath9k_hw_adc_dccal_collect
,
1013 ath9k_hw_adc_dccal_calibrate
1015 const struct hal_percal_data adc_init_dc_cal
= {
1019 ath9k_hw_adc_dccal_collect
,
1020 ath9k_hw_adc_dccal_calibrate