2 * Copyright (c) 2008-2010 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.
19 #include "ar9002_phy.h"
21 #define AR9285_CLCAL_REDO_THRESH 1
23 enum ar9002_cal_types
{
24 ADC_GAIN_CAL
= BIT(0),
26 IQ_MISMATCH_CAL
= BIT(2),
29 static bool ar9002_hw_is_cal_supported(struct ath_hw
*ah
,
30 struct ath9k_channel
*chan
,
31 enum ar9002_cal_types cal_type
)
33 bool supported
= false;
34 switch (ah
->supp_cals
& cal_type
) {
36 /* Run IQ Mismatch for non-CCK only */
42 /* Run ADC Gain Cal for non-CCK & non 2GHz-HT20 only */
43 if (!IS_CHAN_B(chan
) &&
44 !(IS_CHAN_2GHZ(chan
) && IS_CHAN_HT20(chan
)))
51 static void ar9002_hw_setup_calibration(struct ath_hw
*ah
,
52 struct ath9k_cal_list
*currCal
)
54 struct ath_common
*common
= ath9k_hw_common(ah
);
56 REG_RMW_FIELD(ah
, AR_PHY_TIMING_CTRL4(0),
57 AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX
,
58 currCal
->calData
->calCountMax
);
60 switch (currCal
->calData
->calType
) {
62 REG_WRITE(ah
, AR_PHY_CALMODE
, AR_PHY_CALMODE_IQ
);
63 ath_dbg(common
, ATH_DBG_CALIBRATE
,
64 "starting IQ Mismatch Calibration\n");
67 REG_WRITE(ah
, AR_PHY_CALMODE
, AR_PHY_CALMODE_ADC_GAIN
);
68 ath_dbg(common
, ATH_DBG_CALIBRATE
,
69 "starting ADC Gain Calibration\n");
72 REG_WRITE(ah
, AR_PHY_CALMODE
, AR_PHY_CALMODE_ADC_DC_PER
);
73 ath_dbg(common
, ATH_DBG_CALIBRATE
,
74 "starting ADC DC Calibration\n");
78 REG_SET_BIT(ah
, AR_PHY_TIMING_CTRL4(0),
79 AR_PHY_TIMING_CTRL4_DO_CAL
);
82 static bool ar9002_hw_per_calibration(struct ath_hw
*ah
,
83 struct ath9k_channel
*ichan
,
85 struct ath9k_cal_list
*currCal
)
87 struct ath9k_hw_cal_data
*caldata
= ah
->caldata
;
88 bool iscaldone
= false;
90 if (currCal
->calState
== CAL_RUNNING
) {
91 if (!(REG_READ(ah
, AR_PHY_TIMING_CTRL4(0)) &
92 AR_PHY_TIMING_CTRL4_DO_CAL
)) {
94 currCal
->calData
->calCollect(ah
);
97 if (ah
->cal_samples
>=
98 currCal
->calData
->calNumSamples
) {
100 for (i
= 0; i
< AR5416_MAX_CHAINS
; i
++) {
101 if (rxchainmask
& (1 << i
))
105 currCal
->calData
->calPostProc(ah
, numChains
);
106 caldata
->CalValid
|= currCal
->calData
->calType
;
107 currCal
->calState
= CAL_DONE
;
110 ar9002_hw_setup_calibration(ah
, currCal
);
113 } else if (!(caldata
->CalValid
& currCal
->calData
->calType
)) {
114 ath9k_hw_reset_calibration(ah
, currCal
);
120 static void ar9002_hw_iqcal_collect(struct ath_hw
*ah
)
124 for (i
= 0; i
< AR5416_MAX_CHAINS
; i
++) {
125 ah
->totalPowerMeasI
[i
] +=
126 REG_READ(ah
, AR_PHY_CAL_MEAS_0(i
));
127 ah
->totalPowerMeasQ
[i
] +=
128 REG_READ(ah
, AR_PHY_CAL_MEAS_1(i
));
129 ah
->totalIqCorrMeas
[i
] +=
130 (int32_t) REG_READ(ah
, AR_PHY_CAL_MEAS_2(i
));
131 ath_dbg(ath9k_hw_common(ah
), ATH_DBG_CALIBRATE
,
132 "%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n",
133 ah
->cal_samples
, i
, ah
->totalPowerMeasI
[i
],
134 ah
->totalPowerMeasQ
[i
],
135 ah
->totalIqCorrMeas
[i
]);
139 static void ar9002_hw_adc_gaincal_collect(struct ath_hw
*ah
)
143 for (i
= 0; i
< AR5416_MAX_CHAINS
; i
++) {
144 ah
->totalAdcIOddPhase
[i
] +=
145 REG_READ(ah
, AR_PHY_CAL_MEAS_0(i
));
146 ah
->totalAdcIEvenPhase
[i
] +=
147 REG_READ(ah
, AR_PHY_CAL_MEAS_1(i
));
148 ah
->totalAdcQOddPhase
[i
] +=
149 REG_READ(ah
, AR_PHY_CAL_MEAS_2(i
));
150 ah
->totalAdcQEvenPhase
[i
] +=
151 REG_READ(ah
, AR_PHY_CAL_MEAS_3(i
));
153 ath_dbg(ath9k_hw_common(ah
), ATH_DBG_CALIBRATE
,
154 "%d: Chn %d oddi=0x%08x; eveni=0x%08x; oddq=0x%08x; evenq=0x%08x;\n",
156 ah
->totalAdcIOddPhase
[i
],
157 ah
->totalAdcIEvenPhase
[i
],
158 ah
->totalAdcQOddPhase
[i
],
159 ah
->totalAdcQEvenPhase
[i
]);
163 static void ar9002_hw_adc_dccal_collect(struct ath_hw
*ah
)
167 for (i
= 0; i
< AR5416_MAX_CHAINS
; i
++) {
168 ah
->totalAdcDcOffsetIOddPhase
[i
] +=
169 (int32_t) REG_READ(ah
, AR_PHY_CAL_MEAS_0(i
));
170 ah
->totalAdcDcOffsetIEvenPhase
[i
] +=
171 (int32_t) REG_READ(ah
, AR_PHY_CAL_MEAS_1(i
));
172 ah
->totalAdcDcOffsetQOddPhase
[i
] +=
173 (int32_t) REG_READ(ah
, AR_PHY_CAL_MEAS_2(i
));
174 ah
->totalAdcDcOffsetQEvenPhase
[i
] +=
175 (int32_t) REG_READ(ah
, AR_PHY_CAL_MEAS_3(i
));
177 ath_dbg(ath9k_hw_common(ah
), ATH_DBG_CALIBRATE
,
178 "%d: Chn %d oddi=0x%08x; eveni=0x%08x; oddq=0x%08x; evenq=0x%08x;\n",
180 ah
->totalAdcDcOffsetIOddPhase
[i
],
181 ah
->totalAdcDcOffsetIEvenPhase
[i
],
182 ah
->totalAdcDcOffsetQOddPhase
[i
],
183 ah
->totalAdcDcOffsetQEvenPhase
[i
]);
187 static void ar9002_hw_iqcalibrate(struct ath_hw
*ah
, u8 numChains
)
189 struct ath_common
*common
= ath9k_hw_common(ah
);
190 u32 powerMeasQ
, powerMeasI
, iqCorrMeas
;
191 u32 qCoffDenom
, iCoffDenom
;
192 int32_t qCoff
, iCoff
;
195 for (i
= 0; i
< numChains
; i
++) {
196 powerMeasI
= ah
->totalPowerMeasI
[i
];
197 powerMeasQ
= ah
->totalPowerMeasQ
[i
];
198 iqCorrMeas
= ah
->totalIqCorrMeas
[i
];
200 ath_dbg(common
, ATH_DBG_CALIBRATE
,
201 "Starting IQ Cal and Correction for Chain %d\n",
204 ath_dbg(common
, ATH_DBG_CALIBRATE
,
205 "Orignal: Chn %diq_corr_meas = 0x%08x\n",
206 i
, ah
->totalIqCorrMeas
[i
]);
210 if (iqCorrMeas
> 0x80000000) {
211 iqCorrMeas
= (0xffffffff - iqCorrMeas
) + 1;
215 ath_dbg(common
, ATH_DBG_CALIBRATE
,
216 "Chn %d pwr_meas_i = 0x%08x\n", i
, powerMeasI
);
217 ath_dbg(common
, ATH_DBG_CALIBRATE
,
218 "Chn %d pwr_meas_q = 0x%08x\n", i
, powerMeasQ
);
219 ath_dbg(common
, ATH_DBG_CALIBRATE
, "iqCorrNeg is 0x%08x\n",
222 iCoffDenom
= (powerMeasI
/ 2 + powerMeasQ
/ 2) / 128;
223 qCoffDenom
= powerMeasQ
/ 64;
225 if ((powerMeasQ
!= 0) && (iCoffDenom
!= 0) &&
227 iCoff
= iqCorrMeas
/ iCoffDenom
;
228 qCoff
= powerMeasI
/ qCoffDenom
- 64;
229 ath_dbg(common
, ATH_DBG_CALIBRATE
,
230 "Chn %d iCoff = 0x%08x\n", i
, iCoff
);
231 ath_dbg(common
, ATH_DBG_CALIBRATE
,
232 "Chn %d qCoff = 0x%08x\n", i
, qCoff
);
234 iCoff
= iCoff
& 0x3f;
235 ath_dbg(common
, ATH_DBG_CALIBRATE
,
236 "New: Chn %d iCoff = 0x%08x\n", i
, iCoff
);
237 if (iqCorrNeg
== 0x0)
238 iCoff
= 0x40 - iCoff
;
242 else if (qCoff
<= -16)
245 ath_dbg(common
, ATH_DBG_CALIBRATE
,
246 "Chn %d : iCoff = 0x%x qCoff = 0x%x\n",
249 REG_RMW_FIELD(ah
, AR_PHY_TIMING_CTRL4(i
),
250 AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF
,
252 REG_RMW_FIELD(ah
, AR_PHY_TIMING_CTRL4(i
),
253 AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF
,
255 ath_dbg(common
, ATH_DBG_CALIBRATE
,
256 "IQ Cal and Correction done for Chain %d\n",
261 REG_SET_BIT(ah
, AR_PHY_TIMING_CTRL4(0),
262 AR_PHY_TIMING_CTRL4_IQCORR_ENABLE
);
265 static void ar9002_hw_adc_gaincal_calibrate(struct ath_hw
*ah
, u8 numChains
)
267 struct ath_common
*common
= ath9k_hw_common(ah
);
268 u32 iOddMeasOffset
, iEvenMeasOffset
, qOddMeasOffset
, qEvenMeasOffset
;
269 u32 qGainMismatch
, iGainMismatch
, val
, i
;
271 for (i
= 0; i
< numChains
; i
++) {
272 iOddMeasOffset
= ah
->totalAdcIOddPhase
[i
];
273 iEvenMeasOffset
= ah
->totalAdcIEvenPhase
[i
];
274 qOddMeasOffset
= ah
->totalAdcQOddPhase
[i
];
275 qEvenMeasOffset
= ah
->totalAdcQEvenPhase
[i
];
277 ath_dbg(common
, ATH_DBG_CALIBRATE
,
278 "Starting ADC Gain Cal for Chain %d\n", i
);
280 ath_dbg(common
, ATH_DBG_CALIBRATE
,
281 "Chn %d pwr_meas_odd_i = 0x%08x\n", i
,
283 ath_dbg(common
, ATH_DBG_CALIBRATE
,
284 "Chn %d pwr_meas_even_i = 0x%08x\n", i
,
286 ath_dbg(common
, ATH_DBG_CALIBRATE
,
287 "Chn %d pwr_meas_odd_q = 0x%08x\n", i
,
289 ath_dbg(common
, ATH_DBG_CALIBRATE
,
290 "Chn %d pwr_meas_even_q = 0x%08x\n", i
,
293 if (iOddMeasOffset
!= 0 && qEvenMeasOffset
!= 0) {
295 ((iEvenMeasOffset
* 32) /
296 iOddMeasOffset
) & 0x3f;
298 ((qOddMeasOffset
* 32) /
299 qEvenMeasOffset
) & 0x3f;
301 ath_dbg(common
, ATH_DBG_CALIBRATE
,
302 "Chn %d gain_mismatch_i = 0x%08x\n", i
,
304 ath_dbg(common
, ATH_DBG_CALIBRATE
,
305 "Chn %d gain_mismatch_q = 0x%08x\n", i
,
308 val
= REG_READ(ah
, AR_PHY_NEW_ADC_DC_GAIN_CORR(i
));
310 val
|= (qGainMismatch
) | (iGainMismatch
<< 6);
311 REG_WRITE(ah
, AR_PHY_NEW_ADC_DC_GAIN_CORR(i
), val
);
313 ath_dbg(common
, ATH_DBG_CALIBRATE
,
314 "ADC Gain Cal done for Chain %d\n", i
);
318 REG_WRITE(ah
, AR_PHY_NEW_ADC_DC_GAIN_CORR(0),
319 REG_READ(ah
, AR_PHY_NEW_ADC_DC_GAIN_CORR(0)) |
320 AR_PHY_NEW_ADC_GAIN_CORR_ENABLE
);
323 static void ar9002_hw_adc_dccal_calibrate(struct ath_hw
*ah
, u8 numChains
)
325 struct ath_common
*common
= ath9k_hw_common(ah
);
326 u32 iOddMeasOffset
, iEvenMeasOffset
, val
, i
;
327 int32_t qOddMeasOffset
, qEvenMeasOffset
, qDcMismatch
, iDcMismatch
;
328 const struct ath9k_percal_data
*calData
=
329 ah
->cal_list_curr
->calData
;
331 (1 << (calData
->calCountMax
+ 5)) * calData
->calNumSamples
;
333 for (i
= 0; i
< numChains
; i
++) {
334 iOddMeasOffset
= ah
->totalAdcDcOffsetIOddPhase
[i
];
335 iEvenMeasOffset
= ah
->totalAdcDcOffsetIEvenPhase
[i
];
336 qOddMeasOffset
= ah
->totalAdcDcOffsetQOddPhase
[i
];
337 qEvenMeasOffset
= ah
->totalAdcDcOffsetQEvenPhase
[i
];
339 ath_dbg(common
, ATH_DBG_CALIBRATE
,
340 "Starting ADC DC Offset Cal for Chain %d\n", i
);
342 ath_dbg(common
, ATH_DBG_CALIBRATE
,
343 "Chn %d pwr_meas_odd_i = %d\n", i
,
345 ath_dbg(common
, ATH_DBG_CALIBRATE
,
346 "Chn %d pwr_meas_even_i = %d\n", i
,
348 ath_dbg(common
, ATH_DBG_CALIBRATE
,
349 "Chn %d pwr_meas_odd_q = %d\n", i
,
351 ath_dbg(common
, ATH_DBG_CALIBRATE
,
352 "Chn %d pwr_meas_even_q = %d\n", i
,
355 iDcMismatch
= (((iEvenMeasOffset
- iOddMeasOffset
) * 2) /
357 qDcMismatch
= (((qOddMeasOffset
- qEvenMeasOffset
) * 2) /
360 ath_dbg(common
, ATH_DBG_CALIBRATE
,
361 "Chn %d dc_offset_mismatch_i = 0x%08x\n", i
,
363 ath_dbg(common
, ATH_DBG_CALIBRATE
,
364 "Chn %d dc_offset_mismatch_q = 0x%08x\n", i
,
367 val
= REG_READ(ah
, AR_PHY_NEW_ADC_DC_GAIN_CORR(i
));
369 val
|= (qDcMismatch
<< 12) | (iDcMismatch
<< 21);
370 REG_WRITE(ah
, AR_PHY_NEW_ADC_DC_GAIN_CORR(i
), val
);
372 ath_dbg(common
, ATH_DBG_CALIBRATE
,
373 "ADC DC Offset Cal done for Chain %d\n", i
);
376 REG_WRITE(ah
, AR_PHY_NEW_ADC_DC_GAIN_CORR(0),
377 REG_READ(ah
, AR_PHY_NEW_ADC_DC_GAIN_CORR(0)) |
378 AR_PHY_NEW_ADC_DC_OFFSET_CORR_ENABLE
);
381 static void ar9287_hw_olc_temp_compensation(struct ath_hw
*ah
)
384 int32_t delta
, currPDADC
, slope
;
386 rddata
= REG_READ(ah
, AR_PHY_TX_PWRCTRL4
);
387 currPDADC
= MS(rddata
, AR_PHY_TX_PWRCTRL_PD_AVG_OUT
);
389 if (ah
->initPDADC
== 0 || currPDADC
== 0) {
391 * Zero value indicates that no frames have been transmitted
392 * yet, can't do temperature compensation until frames are
397 slope
= ah
->eep_ops
->get_eeprom(ah
, EEP_TEMPSENSE_SLOPE
);
399 if (slope
== 0) { /* to avoid divide by zero case */
402 delta
= ((currPDADC
- ah
->initPDADC
)*4) / slope
;
404 REG_RMW_FIELD(ah
, AR_PHY_CH0_TX_PWRCTRL11
,
405 AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP
, delta
);
406 REG_RMW_FIELD(ah
, AR_PHY_CH1_TX_PWRCTRL11
,
407 AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP
, delta
);
411 static void ar9280_hw_olc_temp_compensation(struct ath_hw
*ah
)
414 int delta
, currPDADC
, regval
;
416 rddata
= REG_READ(ah
, AR_PHY_TX_PWRCTRL4
);
417 currPDADC
= MS(rddata
, AR_PHY_TX_PWRCTRL_PD_AVG_OUT
);
419 if (ah
->initPDADC
== 0 || currPDADC
== 0)
422 if (ah
->eep_ops
->get_eeprom(ah
, EEP_DAC_HPWR_5G
))
423 delta
= (currPDADC
- ah
->initPDADC
+ 4) / 8;
425 delta
= (currPDADC
- ah
->initPDADC
+ 5) / 10;
427 if (delta
!= ah
->PDADCdelta
) {
428 ah
->PDADCdelta
= delta
;
429 for (i
= 1; i
< AR9280_TX_GAIN_TABLE_SIZE
; i
++) {
430 regval
= ah
->originalGain
[i
] - delta
;
435 AR_PHY_TX_GAIN_TBL1
+ i
* 4,
436 AR_PHY_TX_GAIN
, regval
);
441 static void ar9271_hw_pa_cal(struct ath_hw
*ah
, bool is_reset
)
456 for (i
= 0; i
< ARRAY_SIZE(regList
); i
++)
457 regList
[i
][1] = REG_READ(ah
, regList
[i
][0]);
459 regVal
= REG_READ(ah
, 0x7834);
461 REG_WRITE(ah
, 0x7834, regVal
);
462 regVal
= REG_READ(ah
, 0x9808);
463 regVal
|= (0x1 << 27);
464 REG_WRITE(ah
, 0x9808, regVal
);
466 /* 786c,b23,1, pwddac=1 */
467 REG_RMW_FIELD(ah
, AR9285_AN_TOP3
, AR9285_AN_TOP3_PWDDAC
, 1);
468 /* 7854, b5,1, pdrxtxbb=1 */
469 REG_RMW_FIELD(ah
, AR9285_AN_RXTXBB1
, AR9285_AN_RXTXBB1_PDRXTXBB1
, 1);
470 /* 7854, b7,1, pdv2i=1 */
471 REG_RMW_FIELD(ah
, AR9285_AN_RXTXBB1
, AR9285_AN_RXTXBB1_PDV2I
, 1);
472 /* 7854, b8,1, pddacinterface=1 */
473 REG_RMW_FIELD(ah
, AR9285_AN_RXTXBB1
, AR9285_AN_RXTXBB1_PDDACIF
, 1);
474 /* 7824,b12,0, offcal=0 */
475 REG_RMW_FIELD(ah
, AR9285_AN_RF2G2
, AR9285_AN_RF2G2_OFFCAL
, 0);
476 /* 7838, b1,0, pwddb=0 */
477 REG_RMW_FIELD(ah
, AR9285_AN_RF2G7
, AR9285_AN_RF2G7_PWDDB
, 0);
478 /* 7820,b11,0, enpacal=0 */
479 REG_RMW_FIELD(ah
, AR9285_AN_RF2G1
, AR9285_AN_RF2G1_ENPACAL
, 0);
480 /* 7820,b25,1, pdpadrv1=0 */
481 REG_RMW_FIELD(ah
, AR9285_AN_RF2G1
, AR9285_AN_RF2G1_PDPADRV1
, 0);
482 /* 7820,b24,0, pdpadrv2=0 */
483 REG_RMW_FIELD(ah
, AR9285_AN_RF2G1
, AR9285_AN_RF2G1_PDPADRV2
, 0);
484 /* 7820,b23,0, pdpaout=0 */
485 REG_RMW_FIELD(ah
, AR9285_AN_RF2G1
, AR9285_AN_RF2G1_PDPAOUT
, 0);
486 /* 783c,b14-16,7, padrvgn2tab_0=7 */
487 REG_RMW_FIELD(ah
, AR9285_AN_RF2G8
, AR9285_AN_RF2G8_PADRVGN2TAB0
, 7);
489 * 7838,b29-31,0, padrvgn1tab_0=0
490 * does not matter since we turn it off
492 REG_RMW_FIELD(ah
, AR9285_AN_RF2G7
, AR9285_AN_RF2G7_PADRVGN2TAB0
, 0);
494 REG_RMW_FIELD(ah
, AR9285_AN_RF2G3
, AR9271_AN_RF2G3_CCOMP
, 0xfff);
497 * localmode=1,bmode=1,bmoderxtx=1,synthon=1,
498 * txon=1,paon=1,oscon=1,synthon_force=1
500 REG_WRITE(ah
, AR9285_AN_TOP2
, 0xca0358a0);
502 REG_RMW_FIELD(ah
, AR9285_AN_RF2G6
, AR9271_AN_RF2G6_OFFS
, 0);
505 for (i
= 6; i
> 0; i
--) {
506 regVal
= REG_READ(ah
, 0x7834);
507 regVal
|= (1 << (20 + i
));
508 REG_WRITE(ah
, 0x7834, regVal
);
510 /* regVal = REG_READ(ah, 0x7834); */
511 regVal
&= (~(0x1 << (20 + i
)));
512 regVal
|= (MS(REG_READ(ah
, 0x7840), AR9285_AN_RXTXBB1_SPARE9
)
514 REG_WRITE(ah
, 0x7834, regVal
);
517 regVal
= (regVal
>> 20) & 0x7f;
519 /* Update PA cal info */
520 if ((!is_reset
) && (ah
->pacal_info
.prev_offset
== regVal
)) {
521 if (ah
->pacal_info
.max_skipcount
< MAX_PACAL_SKIPCOUNT
)
522 ah
->pacal_info
.max_skipcount
=
523 2 * ah
->pacal_info
.max_skipcount
;
524 ah
->pacal_info
.skipcount
= ah
->pacal_info
.max_skipcount
;
526 ah
->pacal_info
.max_skipcount
= 1;
527 ah
->pacal_info
.skipcount
= 0;
528 ah
->pacal_info
.prev_offset
= regVal
;
531 ENABLE_REGWRITE_BUFFER(ah
);
533 regVal
= REG_READ(ah
, 0x7834);
535 REG_WRITE(ah
, 0x7834, regVal
);
536 regVal
= REG_READ(ah
, 0x9808);
537 regVal
&= (~(0x1 << 27));
538 REG_WRITE(ah
, 0x9808, regVal
);
540 for (i
= 0; i
< ARRAY_SIZE(regList
); i
++)
541 REG_WRITE(ah
, regList
[i
][0], regList
[i
][1]);
543 REGWRITE_BUFFER_FLUSH(ah
);
546 static inline void ar9285_hw_pa_cal(struct ath_hw
*ah
, bool is_reset
)
548 struct ath_common
*common
= ath9k_hw_common(ah
);
550 int i
, offset
, offs_6_1
, offs_0
;
551 u32 ccomp_org
, reg_field
;
562 ath_dbg(common
, ATH_DBG_CALIBRATE
, "Running PA Calibration\n");
564 /* PA CAL is not needed for high power solution */
565 if (ah
->eep_ops
->get_eeprom(ah
, EEP_TXGAIN_TYPE
) ==
566 AR5416_EEP_TXGAIN_HIGH_POWER
)
569 for (i
= 0; i
< ARRAY_SIZE(regList
); i
++)
570 regList
[i
][1] = REG_READ(ah
, regList
[i
][0]);
572 regVal
= REG_READ(ah
, 0x7834);
574 REG_WRITE(ah
, 0x7834, regVal
);
575 regVal
= REG_READ(ah
, 0x9808);
576 regVal
|= (0x1 << 27);
577 REG_WRITE(ah
, 0x9808, regVal
);
579 REG_RMW_FIELD(ah
, AR9285_AN_TOP3
, AR9285_AN_TOP3_PWDDAC
, 1);
580 REG_RMW_FIELD(ah
, AR9285_AN_RXTXBB1
, AR9285_AN_RXTXBB1_PDRXTXBB1
, 1);
581 REG_RMW_FIELD(ah
, AR9285_AN_RXTXBB1
, AR9285_AN_RXTXBB1_PDV2I
, 1);
582 REG_RMW_FIELD(ah
, AR9285_AN_RXTXBB1
, AR9285_AN_RXTXBB1_PDDACIF
, 1);
583 REG_RMW_FIELD(ah
, AR9285_AN_RF2G2
, AR9285_AN_RF2G2_OFFCAL
, 0);
584 REG_RMW_FIELD(ah
, AR9285_AN_RF2G7
, AR9285_AN_RF2G7_PWDDB
, 0);
585 REG_RMW_FIELD(ah
, AR9285_AN_RF2G1
, AR9285_AN_RF2G1_ENPACAL
, 0);
586 REG_RMW_FIELD(ah
, AR9285_AN_RF2G1
, AR9285_AN_RF2G1_PDPADRV1
, 0);
587 REG_RMW_FIELD(ah
, AR9285_AN_RF2G1
, AR9285_AN_RF2G1_PDPADRV2
, 0);
588 REG_RMW_FIELD(ah
, AR9285_AN_RF2G1
, AR9285_AN_RF2G1_PDPAOUT
, 0);
589 REG_RMW_FIELD(ah
, AR9285_AN_RF2G8
, AR9285_AN_RF2G8_PADRVGN2TAB0
, 7);
590 REG_RMW_FIELD(ah
, AR9285_AN_RF2G7
, AR9285_AN_RF2G7_PADRVGN2TAB0
, 0);
591 ccomp_org
= MS(REG_READ(ah
, AR9285_AN_RF2G6
), AR9285_AN_RF2G6_CCOMP
);
592 REG_RMW_FIELD(ah
, AR9285_AN_RF2G6
, AR9285_AN_RF2G6_CCOMP
, 0xf);
594 REG_WRITE(ah
, AR9285_AN_TOP2
, 0xca0358a0);
596 REG_RMW_FIELD(ah
, AR9285_AN_RF2G6
, AR9285_AN_RF2G6_OFFS
, 0);
597 REG_RMW_FIELD(ah
, AR9285_AN_RF2G3
, AR9285_AN_RF2G3_PDVCCOMP
, 0);
599 for (i
= 6; i
> 0; i
--) {
600 regVal
= REG_READ(ah
, 0x7834);
601 regVal
|= (1 << (19 + i
));
602 REG_WRITE(ah
, 0x7834, regVal
);
604 regVal
= REG_READ(ah
, 0x7834);
605 regVal
&= (~(0x1 << (19 + i
)));
606 reg_field
= MS(REG_READ(ah
, 0x7840), AR9285_AN_RXTXBB1_SPARE9
);
607 regVal
|= (reg_field
<< (19 + i
));
608 REG_WRITE(ah
, 0x7834, regVal
);
611 REG_RMW_FIELD(ah
, AR9285_AN_RF2G3
, AR9285_AN_RF2G3_PDVCCOMP
, 1);
613 reg_field
= MS(REG_READ(ah
, AR9285_AN_RF2G9
), AR9285_AN_RXTXBB1_SPARE9
);
614 REG_RMW_FIELD(ah
, AR9285_AN_RF2G3
, AR9285_AN_RF2G3_PDVCCOMP
, reg_field
);
615 offs_6_1
= MS(REG_READ(ah
, AR9285_AN_RF2G6
), AR9285_AN_RF2G6_OFFS
);
616 offs_0
= MS(REG_READ(ah
, AR9285_AN_RF2G3
), AR9285_AN_RF2G3_PDVCCOMP
);
618 offset
= (offs_6_1
<<1) | offs_0
;
620 offs_6_1
= offset
>>1;
623 if ((!is_reset
) && (ah
->pacal_info
.prev_offset
== offset
)) {
624 if (ah
->pacal_info
.max_skipcount
< MAX_PACAL_SKIPCOUNT
)
625 ah
->pacal_info
.max_skipcount
=
626 2 * ah
->pacal_info
.max_skipcount
;
627 ah
->pacal_info
.skipcount
= ah
->pacal_info
.max_skipcount
;
629 ah
->pacal_info
.max_skipcount
= 1;
630 ah
->pacal_info
.skipcount
= 0;
631 ah
->pacal_info
.prev_offset
= offset
;
634 REG_RMW_FIELD(ah
, AR9285_AN_RF2G6
, AR9285_AN_RF2G6_OFFS
, offs_6_1
);
635 REG_RMW_FIELD(ah
, AR9285_AN_RF2G3
, AR9285_AN_RF2G3_PDVCCOMP
, offs_0
);
637 regVal
= REG_READ(ah
, 0x7834);
639 REG_WRITE(ah
, 0x7834, regVal
);
640 regVal
= REG_READ(ah
, 0x9808);
641 regVal
&= (~(0x1 << 27));
642 REG_WRITE(ah
, 0x9808, regVal
);
644 for (i
= 0; i
< ARRAY_SIZE(regList
); i
++)
645 REG_WRITE(ah
, regList
[i
][0], regList
[i
][1]);
647 REG_RMW_FIELD(ah
, AR9285_AN_RF2G6
, AR9285_AN_RF2G6_CCOMP
, ccomp_org
);
650 static void ar9002_hw_pa_cal(struct ath_hw
*ah
, bool is_reset
)
652 if (AR_SREV_9271(ah
)) {
653 if (is_reset
|| !ah
->pacal_info
.skipcount
)
654 ar9271_hw_pa_cal(ah
, is_reset
);
656 ah
->pacal_info
.skipcount
--;
657 } else if (AR_SREV_9285_12_OR_LATER(ah
)) {
658 if (is_reset
|| !ah
->pacal_info
.skipcount
)
659 ar9285_hw_pa_cal(ah
, is_reset
);
661 ah
->pacal_info
.skipcount
--;
665 static void ar9002_hw_olc_temp_compensation(struct ath_hw
*ah
)
667 if (OLC_FOR_AR9287_10_LATER
)
668 ar9287_hw_olc_temp_compensation(ah
);
669 else if (OLC_FOR_AR9280_20_LATER
)
670 ar9280_hw_olc_temp_compensation(ah
);
673 static bool ar9002_hw_calibrate(struct ath_hw
*ah
,
674 struct ath9k_channel
*chan
,
678 bool iscaldone
= true;
679 struct ath9k_cal_list
*currCal
= ah
->cal_list_curr
;
680 bool nfcal
, nfcal_pending
= false;
682 nfcal
= !!(REG_READ(ah
, AR_PHY_AGC_CONTROL
) & AR_PHY_AGC_CONTROL_NF
);
684 nfcal_pending
= ah
->caldata
->nfcal_pending
;
686 if (currCal
&& !nfcal
&&
687 (currCal
->calState
== CAL_RUNNING
||
688 currCal
->calState
== CAL_WAITING
)) {
689 iscaldone
= ar9002_hw_per_calibration(ah
, chan
,
690 rxchainmask
, currCal
);
692 ah
->cal_list_curr
= currCal
= currCal
->calNext
;
694 if (currCal
->calState
== CAL_WAITING
) {
696 ath9k_hw_reset_calibration(ah
, currCal
);
701 /* Do NF cal only at longer intervals */
702 if (longcal
|| nfcal_pending
) {
704 * Get the value from the previous NF cal and update
707 if (ath9k_hw_getnf(ah
, chan
)) {
709 * Load the NF from history buffer of the current
711 * NF is slow time-variant, so it is OK to use a
714 ath9k_hw_loadnf(ah
, ah
->curchan
);
718 ath9k_hw_start_nfcal(ah
, false);
719 /* Do periodic PAOffset Cal */
720 ar9002_hw_pa_cal(ah
, false);
721 ar9002_hw_olc_temp_compensation(ah
);
728 /* Carrier leakage Calibration fix */
729 static bool ar9285_hw_cl_cal(struct ath_hw
*ah
, struct ath9k_channel
*chan
)
731 struct ath_common
*common
= ath9k_hw_common(ah
);
733 REG_SET_BIT(ah
, AR_PHY_CL_CAL_CTL
, AR_PHY_CL_CAL_ENABLE
);
734 if (IS_CHAN_HT20(chan
)) {
735 REG_SET_BIT(ah
, AR_PHY_CL_CAL_CTL
, AR_PHY_PARALLEL_CAL_ENABLE
);
736 REG_SET_BIT(ah
, AR_PHY_TURBO
, AR_PHY_FC_DYN2040_EN
);
737 REG_CLR_BIT(ah
, AR_PHY_AGC_CONTROL
,
738 AR_PHY_AGC_CONTROL_FLTR_CAL
);
739 REG_CLR_BIT(ah
, AR_PHY_TPCRG1
, AR_PHY_TPCRG1_PD_CAL_ENABLE
);
740 REG_SET_BIT(ah
, AR_PHY_AGC_CONTROL
, AR_PHY_AGC_CONTROL_CAL
);
741 if (!ath9k_hw_wait(ah
, AR_PHY_AGC_CONTROL
,
742 AR_PHY_AGC_CONTROL_CAL
, 0, AH_WAIT_TIMEOUT
)) {
743 ath_dbg(common
, ATH_DBG_CALIBRATE
,
744 "offset calibration failed to complete in 1ms; noisy environment?\n");
747 REG_CLR_BIT(ah
, AR_PHY_TURBO
, AR_PHY_FC_DYN2040_EN
);
748 REG_CLR_BIT(ah
, AR_PHY_CL_CAL_CTL
, AR_PHY_PARALLEL_CAL_ENABLE
);
749 REG_CLR_BIT(ah
, AR_PHY_CL_CAL_CTL
, AR_PHY_CL_CAL_ENABLE
);
751 REG_CLR_BIT(ah
, AR_PHY_ADC_CTL
, AR_PHY_ADC_CTL_OFF_PWDADC
);
752 REG_SET_BIT(ah
, AR_PHY_AGC_CONTROL
, AR_PHY_AGC_CONTROL_FLTR_CAL
);
753 REG_SET_BIT(ah
, AR_PHY_TPCRG1
, AR_PHY_TPCRG1_PD_CAL_ENABLE
);
754 REG_SET_BIT(ah
, AR_PHY_AGC_CONTROL
, AR_PHY_AGC_CONTROL_CAL
);
755 if (!ath9k_hw_wait(ah
, AR_PHY_AGC_CONTROL
, AR_PHY_AGC_CONTROL_CAL
,
756 0, AH_WAIT_TIMEOUT
)) {
757 ath_dbg(common
, ATH_DBG_CALIBRATE
,
758 "offset calibration failed to complete in 1ms; noisy environment?\n");
762 REG_SET_BIT(ah
, AR_PHY_ADC_CTL
, AR_PHY_ADC_CTL_OFF_PWDADC
);
763 REG_CLR_BIT(ah
, AR_PHY_CL_CAL_CTL
, AR_PHY_CL_CAL_ENABLE
);
764 REG_CLR_BIT(ah
, AR_PHY_AGC_CONTROL
, AR_PHY_AGC_CONTROL_FLTR_CAL
);
769 static bool ar9285_hw_clc(struct ath_hw
*ah
, struct ath9k_channel
*chan
)
772 u_int32_t txgain_max
;
773 u_int32_t clc_gain
, gain_mask
= 0, clc_num
= 0;
774 u_int32_t reg_clc_I0
, reg_clc_Q0
;
775 u_int32_t i0_num
= 0;
776 u_int32_t q0_num
= 0;
777 u_int32_t total_num
= 0;
778 u_int32_t reg_rf2g5_org
;
781 if (!(ar9285_hw_cl_cal(ah
, chan
)))
784 txgain_max
= MS(REG_READ(ah
, AR_PHY_TX_PWRCTRL7
),
785 AR_PHY_TX_PWRCTRL_TX_GAIN_TAB_MAX
);
787 for (i
= 0; i
< (txgain_max
+1); i
++) {
788 clc_gain
= (REG_READ(ah
, (AR_PHY_TX_GAIN_TBL1
+(i
<<2))) &
789 AR_PHY_TX_GAIN_CLC
) >> AR_PHY_TX_GAIN_CLC_S
;
790 if (!(gain_mask
& (1 << clc_gain
))) {
791 gain_mask
|= (1 << clc_gain
);
796 for (i
= 0; i
< clc_num
; i
++) {
797 reg_clc_I0
= (REG_READ(ah
, (AR_PHY_CLC_TBL1
+ (i
<< 2)))
798 & AR_PHY_CLC_I0
) >> AR_PHY_CLC_I0_S
;
799 reg_clc_Q0
= (REG_READ(ah
, (AR_PHY_CLC_TBL1
+ (i
<< 2)))
800 & AR_PHY_CLC_Q0
) >> AR_PHY_CLC_Q0_S
;
807 total_num
= i0_num
+ q0_num
;
808 if (total_num
> AR9285_CLCAL_REDO_THRESH
) {
809 reg_rf2g5_org
= REG_READ(ah
, AR9285_RF2G5
);
810 if (AR_SREV_9285E_20(ah
)) {
811 REG_WRITE(ah
, AR9285_RF2G5
,
812 (reg_rf2g5_org
& AR9285_RF2G5_IC50TX
) |
813 AR9285_RF2G5_IC50TX_XE_SET
);
815 REG_WRITE(ah
, AR9285_RF2G5
,
816 (reg_rf2g5_org
& AR9285_RF2G5_IC50TX
) |
817 AR9285_RF2G5_IC50TX_SET
);
819 retv
= ar9285_hw_cl_cal(ah
, chan
);
820 REG_WRITE(ah
, AR9285_RF2G5
, reg_rf2g5_org
);
825 static bool ar9002_hw_init_cal(struct ath_hw
*ah
, struct ath9k_channel
*chan
)
827 struct ath_common
*common
= ath9k_hw_common(ah
);
829 if (AR_SREV_9271(ah
)) {
830 if (!ar9285_hw_cl_cal(ah
, chan
))
832 } else if (AR_SREV_9285_12_OR_LATER(ah
)) {
833 if (!ar9285_hw_clc(ah
, chan
))
836 if (AR_SREV_9280_20_OR_LATER(ah
)) {
837 if (!AR_SREV_9287_11_OR_LATER(ah
))
838 REG_CLR_BIT(ah
, AR_PHY_ADC_CTL
,
839 AR_PHY_ADC_CTL_OFF_PWDADC
);
840 REG_SET_BIT(ah
, AR_PHY_AGC_CONTROL
,
841 AR_PHY_AGC_CONTROL_FLTR_CAL
);
844 /* Calibrate the AGC */
845 REG_WRITE(ah
, AR_PHY_AGC_CONTROL
,
846 REG_READ(ah
, AR_PHY_AGC_CONTROL
) |
847 AR_PHY_AGC_CONTROL_CAL
);
849 /* Poll for offset calibration complete */
850 if (!ath9k_hw_wait(ah
, AR_PHY_AGC_CONTROL
,
851 AR_PHY_AGC_CONTROL_CAL
,
852 0, AH_WAIT_TIMEOUT
)) {
853 ath_dbg(common
, ATH_DBG_CALIBRATE
,
854 "offset calibration failed to complete in 1ms; noisy environment?\n");
858 if (AR_SREV_9280_20_OR_LATER(ah
)) {
859 if (!AR_SREV_9287_11_OR_LATER(ah
))
860 REG_SET_BIT(ah
, AR_PHY_ADC_CTL
,
861 AR_PHY_ADC_CTL_OFF_PWDADC
);
862 REG_CLR_BIT(ah
, AR_PHY_AGC_CONTROL
,
863 AR_PHY_AGC_CONTROL_FLTR_CAL
);
867 /* Do PA Calibration */
868 ar9002_hw_pa_cal(ah
, true);
870 /* Do NF Calibration after DC offset and other calibrations */
871 ath9k_hw_start_nfcal(ah
, true);
874 ah
->caldata
->nfcal_pending
= true;
876 ah
->cal_list
= ah
->cal_list_last
= ah
->cal_list_curr
= NULL
;
878 /* Enable IQ, ADC Gain and ADC DC offset CALs */
879 if (AR_SREV_9100(ah
) || AR_SREV_9160_10_OR_LATER(ah
)) {
880 ah
->supp_cals
= IQ_MISMATCH_CAL
;
882 if (AR_SREV_9160_10_OR_LATER(ah
))
883 ah
->supp_cals
|= ADC_GAIN_CAL
| ADC_DC_CAL
;
885 if (AR_SREV_9287(ah
))
886 ah
->supp_cals
&= ~ADC_GAIN_CAL
;
888 if (ar9002_hw_is_cal_supported(ah
, chan
, ADC_GAIN_CAL
)) {
889 INIT_CAL(&ah
->adcgain_caldata
);
890 INSERT_CAL(ah
, &ah
->adcgain_caldata
);
891 ath_dbg(common
, ATH_DBG_CALIBRATE
,
892 "enabling ADC Gain Calibration.\n");
895 if (ar9002_hw_is_cal_supported(ah
, chan
, ADC_DC_CAL
)) {
896 INIT_CAL(&ah
->adcdc_caldata
);
897 INSERT_CAL(ah
, &ah
->adcdc_caldata
);
898 ath_dbg(common
, ATH_DBG_CALIBRATE
,
899 "enabling ADC DC Calibration.\n");
902 if (ar9002_hw_is_cal_supported(ah
, chan
, IQ_MISMATCH_CAL
)) {
903 INIT_CAL(&ah
->iq_caldata
);
904 INSERT_CAL(ah
, &ah
->iq_caldata
);
905 ath_dbg(common
, ATH_DBG_CALIBRATE
,
906 "enabling IQ Calibration.\n");
909 ah
->cal_list_curr
= ah
->cal_list
;
911 if (ah
->cal_list_curr
)
912 ath9k_hw_reset_calibration(ah
, ah
->cal_list_curr
);
916 ah
->caldata
->CalValid
= 0;
921 static const struct ath9k_percal_data iq_cal_multi_sample
= {
925 ar9002_hw_iqcal_collect
,
926 ar9002_hw_iqcalibrate
928 static const struct ath9k_percal_data iq_cal_single_sample
= {
932 ar9002_hw_iqcal_collect
,
933 ar9002_hw_iqcalibrate
935 static const struct ath9k_percal_data adc_gain_cal_multi_sample
= {
939 ar9002_hw_adc_gaincal_collect
,
940 ar9002_hw_adc_gaincal_calibrate
942 static const struct ath9k_percal_data adc_gain_cal_single_sample
= {
946 ar9002_hw_adc_gaincal_collect
,
947 ar9002_hw_adc_gaincal_calibrate
949 static const struct ath9k_percal_data adc_dc_cal_multi_sample
= {
953 ar9002_hw_adc_dccal_collect
,
954 ar9002_hw_adc_dccal_calibrate
956 static const struct ath9k_percal_data adc_dc_cal_single_sample
= {
960 ar9002_hw_adc_dccal_collect
,
961 ar9002_hw_adc_dccal_calibrate
964 static void ar9002_hw_init_cal_settings(struct ath_hw
*ah
)
966 if (AR_SREV_9100(ah
)) {
967 ah
->iq_caldata
.calData
= &iq_cal_multi_sample
;
968 ah
->supp_cals
= IQ_MISMATCH_CAL
;
972 if (AR_SREV_9160_10_OR_LATER(ah
)) {
973 if (AR_SREV_9280_20_OR_LATER(ah
)) {
974 ah
->iq_caldata
.calData
= &iq_cal_single_sample
;
975 ah
->adcgain_caldata
.calData
=
976 &adc_gain_cal_single_sample
;
977 ah
->adcdc_caldata
.calData
=
978 &adc_dc_cal_single_sample
;
980 ah
->iq_caldata
.calData
= &iq_cal_multi_sample
;
981 ah
->adcgain_caldata
.calData
=
982 &adc_gain_cal_multi_sample
;
983 ah
->adcdc_caldata
.calData
=
984 &adc_dc_cal_multi_sample
;
986 ah
->supp_cals
= ADC_GAIN_CAL
| ADC_DC_CAL
| IQ_MISMATCH_CAL
;
988 if (AR_SREV_9287(ah
))
989 ah
->supp_cals
&= ~ADC_GAIN_CAL
;
993 void ar9002_hw_attach_calib_ops(struct ath_hw
*ah
)
995 struct ath_hw_private_ops
*priv_ops
= ath9k_hw_private_ops(ah
);
996 struct ath_hw_ops
*ops
= ath9k_hw_ops(ah
);
998 priv_ops
->init_cal_settings
= ar9002_hw_init_cal_settings
;
999 priv_ops
->init_cal
= ar9002_hw_init_cal
;
1000 priv_ops
->setup_calibration
= ar9002_hw_setup_calibration
;
1002 ops
->calibrate
= ar9002_hw_calibrate
;