2 * Copyright (c) 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 "ar9003_phy.h"
22 #define MAX_MEASUREMENT 8
23 #define MAX_DIFFERENCE 10
26 int mag_coeff
[AR9300_MAX_CHAINS
][MAX_MEASUREMENT
][MPASS
];
27 int phs_coeff
[AR9300_MAX_CHAINS
][MAX_MEASUREMENT
][MPASS
];
31 enum ar9003_cal_types
{
32 IQ_MISMATCH_CAL
= BIT(0),
33 TEMP_COMP_CAL
= BIT(1),
36 static void ar9003_hw_setup_calibration(struct ath_hw
*ah
,
37 struct ath9k_cal_list
*currCal
)
39 struct ath_common
*common
= ath9k_hw_common(ah
);
41 /* Select calibration to run */
42 switch (currCal
->calData
->calType
) {
45 * Start calibration with
46 * 2^(INIT_IQCAL_LOG_COUNT_MAX+1) samples
48 REG_RMW_FIELD(ah
, AR_PHY_TIMING4
,
49 AR_PHY_TIMING4_IQCAL_LOG_COUNT_MAX
,
50 currCal
->calData
->calCountMax
);
51 REG_WRITE(ah
, AR_PHY_CALMODE
, AR_PHY_CALMODE_IQ
);
53 ath_dbg(common
, ATH_DBG_CALIBRATE
,
54 "starting IQ Mismatch Calibration\n");
57 REG_SET_BIT(ah
, AR_PHY_TIMING4
, AR_PHY_TIMING4_DO_CAL
);
60 REG_RMW_FIELD(ah
, AR_PHY_65NM_CH0_THERM
,
61 AR_PHY_65NM_CH0_THERM_LOCAL
, 1);
62 REG_RMW_FIELD(ah
, AR_PHY_65NM_CH0_THERM
,
63 AR_PHY_65NM_CH0_THERM_START
, 1);
65 ath_dbg(common
, ATH_DBG_CALIBRATE
,
66 "starting Temperature Compensation Calibration\n");
72 * Generic calibration routine.
73 * Recalibrate the lower PHY chips to account for temperature/environment
76 static bool ar9003_hw_per_calibration(struct ath_hw
*ah
,
77 struct ath9k_channel
*ichan
,
79 struct ath9k_cal_list
*currCal
)
81 struct ath9k_hw_cal_data
*caldata
= ah
->caldata
;
82 /* Cal is assumed not done until explicitly set below */
83 bool iscaldone
= false;
85 /* Calibration in progress. */
86 if (currCal
->calState
== CAL_RUNNING
) {
87 /* Check to see if it has finished. */
88 if (!(REG_READ(ah
, AR_PHY_TIMING4
) & AR_PHY_TIMING4_DO_CAL
)) {
90 * Accumulate cal measures for active chains
92 currCal
->calData
->calCollect(ah
);
95 if (ah
->cal_samples
>=
96 currCal
->calData
->calNumSamples
) {
97 unsigned int i
, numChains
= 0;
98 for (i
= 0; i
< AR9300_MAX_CHAINS
; i
++) {
99 if (rxchainmask
& (1 << i
))
104 * Process accumulated data
106 currCal
->calData
->calPostProc(ah
, numChains
);
108 /* Calibration has finished. */
109 caldata
->CalValid
|= currCal
->calData
->calType
;
110 currCal
->calState
= CAL_DONE
;
114 * Set-up collection of another sub-sample until we
117 ar9003_hw_setup_calibration(ah
, currCal
);
120 } else if (!(caldata
->CalValid
& currCal
->calData
->calType
)) {
121 /* If current cal is marked invalid in channel, kick it off */
122 ath9k_hw_reset_calibration(ah
, currCal
);
128 static bool ar9003_hw_calibrate(struct ath_hw
*ah
,
129 struct ath9k_channel
*chan
,
133 bool iscaldone
= true;
134 struct ath9k_cal_list
*currCal
= ah
->cal_list_curr
;
137 * For given calibration:
138 * 1. Call generic cal routine
139 * 2. When this cal is done (isCalDone) if we have more cals waiting
140 * (eg after reset), mask this to upper layers by not propagating
141 * isCalDone if it is set to TRUE.
142 * Instead, change isCalDone to FALSE and setup the waiting cal(s)
146 (currCal
->calState
== CAL_RUNNING
||
147 currCal
->calState
== CAL_WAITING
)) {
148 iscaldone
= ar9003_hw_per_calibration(ah
, chan
,
149 rxchainmask
, currCal
);
151 ah
->cal_list_curr
= currCal
= currCal
->calNext
;
153 if (currCal
->calState
== CAL_WAITING
) {
155 ath9k_hw_reset_calibration(ah
, currCal
);
160 /* Do NF cal only at longer intervals */
163 * Get the value from the previous NF cal and update
166 ath9k_hw_getnf(ah
, chan
);
169 * Load the NF from history buffer of the current channel.
170 * NF is slow time-variant, so it is OK to use a historical
173 ath9k_hw_loadnf(ah
, ah
->curchan
);
175 /* start NF calibration, without updating BB NF register */
176 ath9k_hw_start_nfcal(ah
, false);
182 static void ar9003_hw_iqcal_collect(struct ath_hw
*ah
)
186 /* Accumulate IQ cal measures for active chains */
187 for (i
= 0; i
< AR5416_MAX_CHAINS
; i
++) {
188 ah
->totalPowerMeasI
[i
] +=
189 REG_READ(ah
, AR_PHY_CAL_MEAS_0(i
));
190 ah
->totalPowerMeasQ
[i
] +=
191 REG_READ(ah
, AR_PHY_CAL_MEAS_1(i
));
192 ah
->totalIqCorrMeas
[i
] +=
193 (int32_t) REG_READ(ah
, AR_PHY_CAL_MEAS_2(i
));
194 ath_dbg(ath9k_hw_common(ah
), ATH_DBG_CALIBRATE
,
195 "%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n",
196 ah
->cal_samples
, i
, ah
->totalPowerMeasI
[i
],
197 ah
->totalPowerMeasQ
[i
],
198 ah
->totalIqCorrMeas
[i
]);
202 static void ar9003_hw_iqcalibrate(struct ath_hw
*ah
, u8 numChains
)
204 struct ath_common
*common
= ath9k_hw_common(ah
);
205 u32 powerMeasQ
, powerMeasI
, iqCorrMeas
;
206 u32 qCoffDenom
, iCoffDenom
;
207 int32_t qCoff
, iCoff
;
209 static const u_int32_t offset_array
[3] = {
210 AR_PHY_RX_IQCAL_CORR_B0
,
211 AR_PHY_RX_IQCAL_CORR_B1
,
212 AR_PHY_RX_IQCAL_CORR_B2
,
215 for (i
= 0; i
< numChains
; i
++) {
216 powerMeasI
= ah
->totalPowerMeasI
[i
];
217 powerMeasQ
= ah
->totalPowerMeasQ
[i
];
218 iqCorrMeas
= ah
->totalIqCorrMeas
[i
];
220 ath_dbg(common
, ATH_DBG_CALIBRATE
,
221 "Starting IQ Cal and Correction for Chain %d\n",
224 ath_dbg(common
, ATH_DBG_CALIBRATE
,
225 "Orignal: Chn %diq_corr_meas = 0x%08x\n",
226 i
, ah
->totalIqCorrMeas
[i
]);
230 if (iqCorrMeas
> 0x80000000) {
231 iqCorrMeas
= (0xffffffff - iqCorrMeas
) + 1;
235 ath_dbg(common
, ATH_DBG_CALIBRATE
,
236 "Chn %d pwr_meas_i = 0x%08x\n", i
, powerMeasI
);
237 ath_dbg(common
, ATH_DBG_CALIBRATE
,
238 "Chn %d pwr_meas_q = 0x%08x\n", i
, powerMeasQ
);
239 ath_dbg(common
, ATH_DBG_CALIBRATE
, "iqCorrNeg is 0x%08x\n",
242 iCoffDenom
= (powerMeasI
/ 2 + powerMeasQ
/ 2) / 256;
243 qCoffDenom
= powerMeasQ
/ 64;
245 if ((iCoffDenom
!= 0) && (qCoffDenom
!= 0)) {
246 iCoff
= iqCorrMeas
/ iCoffDenom
;
247 qCoff
= powerMeasI
/ qCoffDenom
- 64;
248 ath_dbg(common
, ATH_DBG_CALIBRATE
,
249 "Chn %d iCoff = 0x%08x\n", i
, iCoff
);
250 ath_dbg(common
, ATH_DBG_CALIBRATE
,
251 "Chn %d qCoff = 0x%08x\n", i
, qCoff
);
253 /* Force bounds on iCoff */
256 else if (iCoff
<= -63)
259 /* Negate iCoff if iqCorrNeg == 0 */
260 if (iqCorrNeg
== 0x0)
263 /* Force bounds on qCoff */
266 else if (qCoff
<= -63)
269 iCoff
= iCoff
& 0x7f;
270 qCoff
= qCoff
& 0x7f;
272 ath_dbg(common
, ATH_DBG_CALIBRATE
,
273 "Chn %d : iCoff = 0x%x qCoff = 0x%x\n",
275 ath_dbg(common
, ATH_DBG_CALIBRATE
,
276 "Register offset (0x%04x) before update = 0x%x\n",
278 REG_READ(ah
, offset_array
[i
]));
280 REG_RMW_FIELD(ah
, offset_array
[i
],
281 AR_PHY_RX_IQCAL_CORR_IQCORR_Q_I_COFF
,
283 REG_RMW_FIELD(ah
, offset_array
[i
],
284 AR_PHY_RX_IQCAL_CORR_IQCORR_Q_Q_COFF
,
286 ath_dbg(common
, ATH_DBG_CALIBRATE
,
287 "Register offset (0x%04x) QI COFF (bitfields 0x%08x) after update = 0x%x\n",
289 AR_PHY_RX_IQCAL_CORR_IQCORR_Q_I_COFF
,
290 REG_READ(ah
, offset_array
[i
]));
291 ath_dbg(common
, ATH_DBG_CALIBRATE
,
292 "Register offset (0x%04x) QQ COFF (bitfields 0x%08x) after update = 0x%x\n",
294 AR_PHY_RX_IQCAL_CORR_IQCORR_Q_Q_COFF
,
295 REG_READ(ah
, offset_array
[i
]));
297 ath_dbg(common
, ATH_DBG_CALIBRATE
,
298 "IQ Cal and Correction done for Chain %d\n", i
);
302 REG_SET_BIT(ah
, AR_PHY_RX_IQCAL_CORR_B0
,
303 AR_PHY_RX_IQCAL_CORR_IQCORR_ENABLE
);
304 ath_dbg(common
, ATH_DBG_CALIBRATE
,
305 "IQ Cal and Correction (offset 0x%04x) enabled (bit position 0x%08x). New Value 0x%08x\n",
306 (unsigned) (AR_PHY_RX_IQCAL_CORR_B0
),
307 AR_PHY_RX_IQCAL_CORR_IQCORR_ENABLE
,
308 REG_READ(ah
, AR_PHY_RX_IQCAL_CORR_B0
));
311 static const struct ath9k_percal_data iq_cal_single_sample
= {
315 ar9003_hw_iqcal_collect
,
316 ar9003_hw_iqcalibrate
319 static void ar9003_hw_init_cal_settings(struct ath_hw
*ah
)
321 ah
->iq_caldata
.calData
= &iq_cal_single_sample
;
325 * solve 4x4 linear equation used in loopback iq cal.
327 static bool ar9003_hw_solve_iq_cal(struct ath_hw
*ah
,
338 s32 f1
= cos_2phi_1
- cos_2phi_2
,
339 f3
= sin_2phi_1
- sin_2phi_2
,
341 s32 mag_tx
, phs_tx
, mag_rx
, phs_rx
;
342 const s32 result_shift
= 1 << 15;
343 struct ath_common
*common
= ath9k_hw_common(ah
);
345 f2
= (f1
* f1
+ f3
* f3
) / result_shift
;
348 ath_dbg(common
, ATH_DBG_CALIBRATE
, "Divide by 0\n");
352 /* mag mismatch, tx */
353 mag_tx
= f1
* (mag_a0_d0
- mag_a1_d0
) + f3
* (phs_a0_d0
- phs_a1_d0
);
354 /* phs mismatch, tx */
355 phs_tx
= f3
* (-mag_a0_d0
+ mag_a1_d0
) + f1
* (phs_a0_d0
- phs_a1_d0
);
357 mag_tx
= (mag_tx
/ f2
);
358 phs_tx
= (phs_tx
/ f2
);
360 /* mag mismatch, rx */
361 mag_rx
= mag_a0_d0
- (cos_2phi_1
* mag_tx
+ sin_2phi_1
* phs_tx
) /
363 /* phs mismatch, rx */
364 phs_rx
= phs_a0_d0
+ (sin_2phi_1
* mag_tx
- cos_2phi_1
* phs_tx
) /
367 solved_eq
[0] = mag_tx
;
368 solved_eq
[1] = phs_tx
;
369 solved_eq
[2] = mag_rx
;
370 solved_eq
[3] = phs_rx
;
375 static s32
ar9003_hw_find_mag_approx(struct ath_hw
*ah
, s32 in_re
, s32 in_im
)
377 s32 abs_i
= abs(in_re
),
389 return max_abs
- (max_abs
/ 32) + (min_abs
/ 8) + (min_abs
/ 4);
394 static bool ar9003_hw_calc_iq_corr(struct ath_hw
*ah
,
399 s32 i2_m_q2_a0_d0
, i2_p_q2_a0_d0
, iq_corr_a0_d0
,
400 i2_m_q2_a0_d1
, i2_p_q2_a0_d1
, iq_corr_a0_d1
,
401 i2_m_q2_a1_d0
, i2_p_q2_a1_d0
, iq_corr_a1_d0
,
402 i2_m_q2_a1_d1
, i2_p_q2_a1_d1
, iq_corr_a1_d1
;
403 s32 mag_a0_d0
, mag_a1_d0
, mag_a0_d1
, mag_a1_d1
,
404 phs_a0_d0
, phs_a1_d0
, phs_a0_d1
, phs_a1_d1
,
405 sin_2phi_1
, cos_2phi_1
,
406 sin_2phi_2
, cos_2phi_2
;
407 s32 mag_tx
, phs_tx
, mag_rx
, phs_rx
;
408 s32 solved_eq
[4], mag_corr_tx
, phs_corr_tx
, mag_corr_rx
, phs_corr_rx
,
410 const s32 res_scale
= 1 << 15;
411 const s32 delpt_shift
= 1 << 8;
413 struct ath_common
*common
= ath9k_hw_common(ah
);
415 i2_m_q2_a0_d0
= iq_res
[0] & 0xfff;
416 i2_p_q2_a0_d0
= (iq_res
[0] >> 12) & 0xfff;
417 iq_corr_a0_d0
= ((iq_res
[0] >> 24) & 0xff) + ((iq_res
[1] & 0xf) << 8);
419 if (i2_m_q2_a0_d0
> 0x800)
420 i2_m_q2_a0_d0
= -((0xfff - i2_m_q2_a0_d0
) + 1);
422 if (i2_p_q2_a0_d0
> 0x800)
423 i2_p_q2_a0_d0
= -((0xfff - i2_p_q2_a0_d0
) + 1);
425 if (iq_corr_a0_d0
> 0x800)
426 iq_corr_a0_d0
= -((0xfff - iq_corr_a0_d0
) + 1);
428 i2_m_q2_a0_d1
= (iq_res
[1] >> 4) & 0xfff;
429 i2_p_q2_a0_d1
= (iq_res
[2] & 0xfff);
430 iq_corr_a0_d1
= (iq_res
[2] >> 12) & 0xfff;
432 if (i2_m_q2_a0_d1
> 0x800)
433 i2_m_q2_a0_d1
= -((0xfff - i2_m_q2_a0_d1
) + 1);
435 if (i2_p_q2_a0_d1
> 0x800)
436 i2_p_q2_a0_d1
= -((0xfff - i2_p_q2_a0_d1
) + 1);
438 if (iq_corr_a0_d1
> 0x800)
439 iq_corr_a0_d1
= -((0xfff - iq_corr_a0_d1
) + 1);
441 i2_m_q2_a1_d0
= ((iq_res
[2] >> 24) & 0xff) + ((iq_res
[3] & 0xf) << 8);
442 i2_p_q2_a1_d0
= (iq_res
[3] >> 4) & 0xfff;
443 iq_corr_a1_d0
= iq_res
[4] & 0xfff;
445 if (i2_m_q2_a1_d0
> 0x800)
446 i2_m_q2_a1_d0
= -((0xfff - i2_m_q2_a1_d0
) + 1);
448 if (i2_p_q2_a1_d0
> 0x800)
449 i2_p_q2_a1_d0
= -((0xfff - i2_p_q2_a1_d0
) + 1);
451 if (iq_corr_a1_d0
> 0x800)
452 iq_corr_a1_d0
= -((0xfff - iq_corr_a1_d0
) + 1);
454 i2_m_q2_a1_d1
= (iq_res
[4] >> 12) & 0xfff;
455 i2_p_q2_a1_d1
= ((iq_res
[4] >> 24) & 0xff) + ((iq_res
[5] & 0xf) << 8);
456 iq_corr_a1_d1
= (iq_res
[5] >> 4) & 0xfff;
458 if (i2_m_q2_a1_d1
> 0x800)
459 i2_m_q2_a1_d1
= -((0xfff - i2_m_q2_a1_d1
) + 1);
461 if (i2_p_q2_a1_d1
> 0x800)
462 i2_p_q2_a1_d1
= -((0xfff - i2_p_q2_a1_d1
) + 1);
464 if (iq_corr_a1_d1
> 0x800)
465 iq_corr_a1_d1
= -((0xfff - iq_corr_a1_d1
) + 1);
467 if ((i2_p_q2_a0_d0
== 0) || (i2_p_q2_a0_d1
== 0) ||
468 (i2_p_q2_a1_d0
== 0) || (i2_p_q2_a1_d1
== 0)) {
469 ath_dbg(common
, ATH_DBG_CALIBRATE
,
475 i2_p_q2_a0_d0
, i2_p_q2_a0_d1
,
476 i2_p_q2_a1_d0
, i2_p_q2_a1_d1
);
480 mag_a0_d0
= (i2_m_q2_a0_d0
* res_scale
) / i2_p_q2_a0_d0
;
481 phs_a0_d0
= (iq_corr_a0_d0
* res_scale
) / i2_p_q2_a0_d0
;
483 mag_a0_d1
= (i2_m_q2_a0_d1
* res_scale
) / i2_p_q2_a0_d1
;
484 phs_a0_d1
= (iq_corr_a0_d1
* res_scale
) / i2_p_q2_a0_d1
;
486 mag_a1_d0
= (i2_m_q2_a1_d0
* res_scale
) / i2_p_q2_a1_d0
;
487 phs_a1_d0
= (iq_corr_a1_d0
* res_scale
) / i2_p_q2_a1_d0
;
489 mag_a1_d1
= (i2_m_q2_a1_d1
* res_scale
) / i2_p_q2_a1_d1
;
490 phs_a1_d1
= (iq_corr_a1_d1
* res_scale
) / i2_p_q2_a1_d1
;
492 /* w/o analog phase shift */
493 sin_2phi_1
= (((mag_a0_d0
- mag_a0_d1
) * delpt_shift
) / DELPT
);
494 /* w/o analog phase shift */
495 cos_2phi_1
= (((phs_a0_d1
- phs_a0_d0
) * delpt_shift
) / DELPT
);
496 /* w/ analog phase shift */
497 sin_2phi_2
= (((mag_a1_d0
- mag_a1_d1
) * delpt_shift
) / DELPT
);
498 /* w/ analog phase shift */
499 cos_2phi_2
= (((phs_a1_d1
- phs_a1_d0
) * delpt_shift
) / DELPT
);
502 * force sin^2 + cos^2 = 1;
503 * find magnitude by approximation
505 mag1
= ar9003_hw_find_mag_approx(ah
, cos_2phi_1
, sin_2phi_1
);
506 mag2
= ar9003_hw_find_mag_approx(ah
, cos_2phi_2
, sin_2phi_2
);
508 if ((mag1
== 0) || (mag2
== 0)) {
509 ath_dbg(common
, ATH_DBG_CALIBRATE
,
510 "Divide by 0: mag1=%d, mag2=%d\n",
515 /* normalization sin and cos by mag */
516 sin_2phi_1
= (sin_2phi_1
* res_scale
/ mag1
);
517 cos_2phi_1
= (cos_2phi_1
* res_scale
/ mag1
);
518 sin_2phi_2
= (sin_2phi_2
* res_scale
/ mag2
);
519 cos_2phi_2
= (cos_2phi_2
* res_scale
/ mag2
);
521 /* calculate IQ mismatch */
522 if (!ar9003_hw_solve_iq_cal(ah
,
523 sin_2phi_1
, cos_2phi_1
,
524 sin_2phi_2
, cos_2phi_2
,
525 mag_a0_d0
, phs_a0_d0
,
527 phs_a1_d0
, solved_eq
)) {
528 ath_dbg(common
, ATH_DBG_CALIBRATE
,
529 "Call to ar9003_hw_solve_iq_cal() failed.\n");
533 mag_tx
= solved_eq
[0];
534 phs_tx
= solved_eq
[1];
535 mag_rx
= solved_eq
[2];
536 phs_rx
= solved_eq
[3];
538 ath_dbg(common
, ATH_DBG_CALIBRATE
,
539 "chain %d: mag mismatch=%d phase mismatch=%d\n",
540 chain_idx
, mag_tx
/res_scale
, phs_tx
/res_scale
);
542 if (res_scale
== mag_tx
) {
543 ath_dbg(common
, ATH_DBG_CALIBRATE
,
544 "Divide by 0: mag_tx=%d, res_scale=%d\n",
549 /* calculate and quantize Tx IQ correction factor */
550 mag_corr_tx
= (mag_tx
* res_scale
) / (res_scale
- mag_tx
);
551 phs_corr_tx
= -phs_tx
;
553 q_q_coff
= (mag_corr_tx
* 128 / res_scale
);
554 q_i_coff
= (phs_corr_tx
* 256 / res_scale
);
556 ath_dbg(common
, ATH_DBG_CALIBRATE
,
557 "tx chain %d: mag corr=%d phase corr=%d\n",
558 chain_idx
, q_q_coff
, q_i_coff
);
569 iqc_coeff
[0] = (q_q_coff
* 128) + q_i_coff
;
571 ath_dbg(common
, ATH_DBG_CALIBRATE
,
572 "tx chain %d: iq corr coeff=%x\n",
573 chain_idx
, iqc_coeff
[0]);
575 if (-mag_rx
== res_scale
) {
576 ath_dbg(common
, ATH_DBG_CALIBRATE
,
577 "Divide by 0: mag_rx=%d, res_scale=%d\n",
582 /* calculate and quantize Rx IQ correction factors */
583 mag_corr_rx
= (-mag_rx
* res_scale
) / (res_scale
+ mag_rx
);
584 phs_corr_rx
= -phs_rx
;
586 q_q_coff
= (mag_corr_rx
* 128 / res_scale
);
587 q_i_coff
= (phs_corr_rx
* 256 / res_scale
);
589 ath_dbg(common
, ATH_DBG_CALIBRATE
,
590 "rx chain %d: mag corr=%d phase corr=%d\n",
591 chain_idx
, q_q_coff
, q_i_coff
);
602 iqc_coeff
[1] = (q_q_coff
* 128) + q_i_coff
;
604 ath_dbg(common
, ATH_DBG_CALIBRATE
,
605 "rx chain %d: iq corr coeff=%x\n",
606 chain_idx
, iqc_coeff
[1]);
611 static bool ar9003_hw_compute_closest_pass_and_avg(int *mp_coeff
, int *mp_avg
)
615 diff
[0] = abs(mp_coeff
[0] - mp_coeff
[1]);
616 diff
[1] = abs(mp_coeff
[1] - mp_coeff
[2]);
617 diff
[2] = abs(mp_coeff
[2] - mp_coeff
[0]);
619 if (diff
[0] > MAX_DIFFERENCE
&&
620 diff
[1] > MAX_DIFFERENCE
&&
621 diff
[2] > MAX_DIFFERENCE
)
624 if (diff
[0] <= diff
[1] && diff
[0] <= diff
[2])
625 *mp_avg
= (mp_coeff
[0] + mp_coeff
[1]) / 2;
626 else if (diff
[1] <= diff
[2])
627 *mp_avg
= (mp_coeff
[1] + mp_coeff
[2]) / 2;
629 *mp_avg
= (mp_coeff
[2] + mp_coeff
[0]) / 2;
634 static void ar9003_hw_tx_iqcal_load_avg_2_passes(struct ath_hw
*ah
,
638 struct ath_common
*common
= ath9k_hw_common(ah
);
639 int i
, im
, nmeasurement
;
640 int magnitude
, phase
;
641 u32 tx_corr_coeff
[MAX_MEASUREMENT
][AR9300_MAX_CHAINS
];
643 memset(tx_corr_coeff
, 0, sizeof(tx_corr_coeff
));
644 for (i
= 0; i
< MAX_MEASUREMENT
/ 2; i
++) {
645 tx_corr_coeff
[i
* 2][0] = tx_corr_coeff
[(i
* 2) + 1][0] =
646 AR_PHY_TX_IQCAL_CORR_COEFF_B0(i
);
647 if (!AR_SREV_9485(ah
)) {
648 tx_corr_coeff
[i
* 2][1] =
649 tx_corr_coeff
[(i
* 2) + 1][1] =
650 AR_PHY_TX_IQCAL_CORR_COEFF_B1(i
);
652 tx_corr_coeff
[i
* 2][2] =
653 tx_corr_coeff
[(i
* 2) + 1][2] =
654 AR_PHY_TX_IQCAL_CORR_COEFF_B2(i
);
658 /* Load the average of 2 passes */
659 for (i
= 0; i
< num_chains
; i
++) {
660 if (AR_SREV_9485(ah
))
661 nmeasurement
= REG_READ_FIELD(ah
,
662 AR_PHY_TX_IQCAL_STATUS_B0_9485
,
663 AR_PHY_CALIBRATED_GAINS_0
);
665 nmeasurement
= REG_READ_FIELD(ah
,
666 AR_PHY_TX_IQCAL_STATUS_B0
,
667 AR_PHY_CALIBRATED_GAINS_0
);
669 if (nmeasurement
> MAX_MEASUREMENT
)
670 nmeasurement
= MAX_MEASUREMENT
;
672 for (im
= 0; im
< nmeasurement
; im
++) {
674 * Determine which 2 passes are closest and compute avg
677 if (!ar9003_hw_compute_closest_pass_and_avg(coeff
->mag_coeff
[i
][im
],
679 goto disable_txiqcal
;
682 * Determine which 2 passes are closest and compute avg
685 if (!ar9003_hw_compute_closest_pass_and_avg(coeff
->phs_coeff
[i
][im
],
687 goto disable_txiqcal
;
689 coeff
->iqc_coeff
[0] = (magnitude
& 0x7f) |
690 ((phase
& 0x7f) << 7);
693 REG_RMW_FIELD(ah
, tx_corr_coeff
[im
][i
],
694 AR_PHY_TX_IQCAL_CORR_COEFF_00_COEFF_TABLE
,
695 coeff
->iqc_coeff
[0]);
697 REG_RMW_FIELD(ah
, tx_corr_coeff
[im
][i
],
698 AR_PHY_TX_IQCAL_CORR_COEFF_01_COEFF_TABLE
,
699 coeff
->iqc_coeff
[0]);
703 REG_RMW_FIELD(ah
, AR_PHY_TX_IQCAL_CONTROL_3
,
704 AR_PHY_TX_IQCAL_CONTROL_3_IQCORR_EN
, 0x1);
705 REG_RMW_FIELD(ah
, AR_PHY_RX_IQCAL_CORR_B0
,
706 AR_PHY_RX_IQCAL_CORR_B0_LOOPBACK_IQCORR_EN
, 0x1);
711 REG_RMW_FIELD(ah
, AR_PHY_TX_IQCAL_CONTROL_3
,
712 AR_PHY_TX_IQCAL_CONTROL_3_IQCORR_EN
, 0x0);
713 REG_RMW_FIELD(ah
, AR_PHY_RX_IQCAL_CORR_B0
,
714 AR_PHY_RX_IQCAL_CORR_B0_LOOPBACK_IQCORR_EN
, 0x0);
716 ath_dbg(common
, ATH_DBG_CALIBRATE
, "TX IQ Cal disabled\n");
719 static void ar9003_hw_tx_iq_cal(struct ath_hw
*ah
)
721 struct ath_common
*common
= ath9k_hw_common(ah
);
722 static const u32 txiqcal_status
[AR9300_MAX_CHAINS
] = {
723 AR_PHY_TX_IQCAL_STATUS_B0
,
724 AR_PHY_TX_IQCAL_STATUS_B1
,
725 AR_PHY_TX_IQCAL_STATUS_B2
,
727 static const u32 chan_info_tab
[] = {
728 AR_PHY_CHAN_INFO_TAB_0
,
729 AR_PHY_CHAN_INFO_TAB_1
,
730 AR_PHY_CHAN_INFO_TAB_2
,
734 s32 i
, j
, ip
, im
, nmeasurement
;
735 u8 nchains
= get_streams(common
->tx_chainmask
);
737 for (ip
= 0; ip
< MPASS
; ip
++) {
738 REG_RMW_FIELD(ah
, AR_PHY_TX_IQCAL_CONTROL_1
,
739 AR_PHY_TX_IQCAQL_CONTROL_1_IQCORR_I_Q_COFF_DELPT
,
741 REG_RMW_FIELD(ah
, AR_PHY_TX_IQCAL_START
,
742 AR_PHY_TX_IQCAL_START_DO_CAL
,
743 AR_PHY_TX_IQCAL_START_DO_CAL
);
745 if (!ath9k_hw_wait(ah
, AR_PHY_TX_IQCAL_START
,
746 AR_PHY_TX_IQCAL_START_DO_CAL
,
747 0, AH_WAIT_TIMEOUT
)) {
748 ath_dbg(common
, ATH_DBG_CALIBRATE
,
749 "Tx IQ Cal not complete.\n");
750 goto TX_IQ_CAL_FAILED
;
753 nmeasurement
= REG_READ_FIELD(ah
, AR_PHY_TX_IQCAL_STATUS_B0
,
754 AR_PHY_CALIBRATED_GAINS_0
);
755 if (nmeasurement
> MAX_MEASUREMENT
)
756 nmeasurement
= MAX_MEASUREMENT
;
758 for (i
= 0; i
< nchains
; i
++) {
759 ath_dbg(common
, ATH_DBG_CALIBRATE
,
760 "Doing Tx IQ Cal for chain %d.\n", i
);
761 for (im
= 0; im
< nmeasurement
; im
++) {
762 if (REG_READ(ah
, txiqcal_status
[i
]) &
763 AR_PHY_TX_IQCAL_STATUS_FAILED
) {
764 ath_dbg(common
, ATH_DBG_CALIBRATE
,
765 "Tx IQ Cal failed for chain %d.\n", i
);
766 goto TX_IQ_CAL_FAILED
;
769 for (j
= 0; j
< 3; j
++) {
771 offset
= 4 * (3 * im
+ j
);
773 REG_RMW_FIELD(ah
, AR_PHY_CHAN_INFO_MEMORY
,
774 AR_PHY_CHAN_INFO_TAB_S2_READ
,
778 iq_res
[idx
] = REG_READ(ah
,
782 REG_RMW_FIELD(ah
, AR_PHY_CHAN_INFO_MEMORY
,
783 AR_PHY_CHAN_INFO_TAB_S2_READ
,
787 iq_res
[idx
+1] = 0xffff & REG_READ(ah
,
791 ath_dbg(common
, ATH_DBG_CALIBRATE
,
792 "IQ RES[%d]=0x%x IQ_RES[%d]=0x%x\n",
793 idx
, iq_res
[idx
], idx
+1, iq_res
[idx
+1]);
796 if (!ar9003_hw_calc_iq_corr(ah
, i
, iq_res
,
798 ath_dbg(common
, ATH_DBG_CALIBRATE
,
799 "Failed in calculation of IQ correction.\n");
800 goto TX_IQ_CAL_FAILED
;
802 coeff
.mag_coeff
[i
][im
][ip
] =
803 coeff
.iqc_coeff
[0] & 0x7f;
804 coeff
.phs_coeff
[i
][im
][ip
] =
805 (coeff
.iqc_coeff
[0] >> 7) & 0x7f;
807 if (coeff
.mag_coeff
[i
][im
][ip
] > 63)
808 coeff
.mag_coeff
[i
][im
][ip
] -= 128;
809 if (coeff
.phs_coeff
[i
][im
][ip
] > 63)
810 coeff
.phs_coeff
[i
][im
][ip
] -= 128;
816 ar9003_hw_tx_iqcal_load_avg_2_passes(ah
, nchains
, &coeff
);
821 ath_dbg(common
, ATH_DBG_CALIBRATE
, "Tx IQ Cal failed\n");
824 static void ar9003_hw_tx_iq_cal_run(struct ath_hw
*ah
)
828 REG_RMW_FIELD(ah
, AR_PHY_TX_IQCAL_CONTROL_1_9485
,
829 AR_PHY_TX_IQCAQL_CONTROL_1_IQCORR_I_Q_COFF_DELPT
, DELPT
);
830 tx_gain_forced
= REG_READ_FIELD(ah
, AR_PHY_TX_FORCED_GAIN
,
831 AR_PHY_TXGAIN_FORCE
);
833 REG_RMW_FIELD(ah
, AR_PHY_TX_FORCED_GAIN
,
834 AR_PHY_TXGAIN_FORCE
, 0);
836 REG_RMW_FIELD(ah
, AR_PHY_TX_IQCAL_START_9485
,
837 AR_PHY_TX_IQCAL_START_DO_CAL_9485
, 1);
840 static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw
*ah
)
842 struct ath_common
*common
= ath9k_hw_common(ah
);
843 const u32 txiqcal_status
[AR9300_MAX_CHAINS
] = {
844 AR_PHY_TX_IQCAL_STATUS_B0_9485
,
845 AR_PHY_TX_IQCAL_STATUS_B1
,
846 AR_PHY_TX_IQCAL_STATUS_B2
,
848 const u_int32_t chan_info_tab
[] = {
849 AR_PHY_CHAN_INFO_TAB_0
,
850 AR_PHY_CHAN_INFO_TAB_1
,
851 AR_PHY_CHAN_INFO_TAB_2
,
859 for (i
= 0; i
< AR9300_MAX_CHAINS
; i
++) {
860 if (ah
->txchainmask
& (1 << i
))
864 for (ip
= 0; ip
< MPASS
; ip
++) {
865 for (i
= 0; i
< num_chains
; i
++) {
866 nmeasurement
= REG_READ_FIELD(ah
,
867 AR_PHY_TX_IQCAL_STATUS_B0_9485
,
868 AR_PHY_CALIBRATED_GAINS_0
);
869 if (nmeasurement
> MAX_MEASUREMENT
)
870 nmeasurement
= MAX_MEASUREMENT
;
872 for (im
= 0; im
< nmeasurement
; im
++) {
873 ath_dbg(common
, ATH_DBG_CALIBRATE
,
874 "Doing Tx IQ Cal for chain %d.\n", i
);
876 if (REG_READ(ah
, txiqcal_status
[i
]) &
877 AR_PHY_TX_IQCAL_STATUS_FAILED
) {
878 ath_dbg(common
, ATH_DBG_CALIBRATE
,
879 "Tx IQ Cal failed for chain %d.\n", i
);
883 for (j
= 0; j
< 3; j
++) {
884 u32 idx
= 2 * j
, offset
= 4 * (3 * im
+ j
);
887 AR_PHY_CHAN_INFO_MEMORY
,
888 AR_PHY_CHAN_INFO_TAB_S2_READ
,
892 iq_res
[idx
] = REG_READ(ah
,
897 AR_PHY_CHAN_INFO_MEMORY
,
898 AR_PHY_CHAN_INFO_TAB_S2_READ
,
902 iq_res
[idx
+ 1] = 0xffff & REG_READ(ah
,
903 chan_info_tab
[i
] + offset
);
905 ath_dbg(common
, ATH_DBG_CALIBRATE
,
908 idx
, iq_res
[idx
], idx
+ 1,
912 if (!ar9003_hw_calc_iq_corr(ah
, i
, iq_res
,
914 ath_dbg(common
, ATH_DBG_CALIBRATE
,
915 "Failed in calculation of IQ correction.\n");
919 coeff
.mag_coeff
[i
][im
][ip
] =
920 coeff
.iqc_coeff
[0] & 0x7f;
921 coeff
.phs_coeff
[i
][im
][ip
] =
922 (coeff
.iqc_coeff
[0] >> 7) & 0x7f;
924 if (coeff
.mag_coeff
[i
][im
][ip
] > 63)
925 coeff
.mag_coeff
[i
][im
][ip
] -= 128;
926 if (coeff
.phs_coeff
[i
][im
][ip
] > 63)
927 coeff
.phs_coeff
[i
][im
][ip
] -= 128;
931 ar9003_hw_tx_iqcal_load_avg_2_passes(ah
, num_chains
, &coeff
);
936 ath_dbg(common
, ATH_DBG_CALIBRATE
, "Tx IQ Cal failed\n");
939 static bool ar9003_hw_init_cal(struct ath_hw
*ah
,
940 struct ath9k_channel
*chan
)
942 struct ath_common
*common
= ath9k_hw_common(ah
);
945 val
= REG_READ(ah
, AR_ENT_OTP
);
946 ath_dbg(common
, ATH_DBG_CALIBRATE
, "ath9k: AR_ENT_OTP 0x%x\n", val
);
948 if (AR_SREV_9485(ah
))
949 ar9003_hw_set_chain_masks(ah
, 0x1, 0x1);
950 else if (val
& AR_ENT_OTP_CHAIN2_DISABLE
)
951 ar9003_hw_set_chain_masks(ah
, 0x3, 0x3);
954 * 0x7 = 0b111 , AR9003 needs to be configured for 3-chain
955 * mode before running AGC/TxIQ cals
957 ar9003_hw_set_chain_masks(ah
, 0x7, 0x7);
959 /* Do Tx IQ Calibration */
960 if (AR_SREV_9485(ah
))
961 ar9003_hw_tx_iq_cal_run(ah
);
963 ar9003_hw_tx_iq_cal(ah
);
965 REG_WRITE(ah
, AR_PHY_ACTIVE
, AR_PHY_ACTIVE_DIS
);
967 REG_WRITE(ah
, AR_PHY_ACTIVE
, AR_PHY_ACTIVE_EN
);
969 /* Calibrate the AGC */
970 REG_WRITE(ah
, AR_PHY_AGC_CONTROL
,
971 REG_READ(ah
, AR_PHY_AGC_CONTROL
) |
972 AR_PHY_AGC_CONTROL_CAL
);
974 /* Poll for offset calibration complete */
975 if (!ath9k_hw_wait(ah
, AR_PHY_AGC_CONTROL
, AR_PHY_AGC_CONTROL_CAL
,
976 0, AH_WAIT_TIMEOUT
)) {
977 ath_dbg(common
, ATH_DBG_CALIBRATE
,
978 "offset calibration failed to complete in 1ms; noisy environment?\n");
982 if (AR_SREV_9485(ah
))
983 ar9003_hw_tx_iq_cal_post_proc(ah
);
985 /* Revert chainmasks to their original values before NF cal */
986 ar9003_hw_set_chain_masks(ah
, ah
->rxchainmask
, ah
->txchainmask
);
988 ath9k_hw_start_nfcal(ah
, true);
990 /* Initialize list pointers */
991 ah
->cal_list
= ah
->cal_list_last
= ah
->cal_list_curr
= NULL
;
992 ah
->supp_cals
= IQ_MISMATCH_CAL
;
994 if (ah
->supp_cals
& IQ_MISMATCH_CAL
) {
995 INIT_CAL(&ah
->iq_caldata
);
996 INSERT_CAL(ah
, &ah
->iq_caldata
);
997 ath_dbg(common
, ATH_DBG_CALIBRATE
,
998 "enabling IQ Calibration.\n");
1001 if (ah
->supp_cals
& TEMP_COMP_CAL
) {
1002 INIT_CAL(&ah
->tempCompCalData
);
1003 INSERT_CAL(ah
, &ah
->tempCompCalData
);
1004 ath_dbg(common
, ATH_DBG_CALIBRATE
,
1005 "enabling Temperature Compensation Calibration.\n");
1008 /* Initialize current pointer to first element in list */
1009 ah
->cal_list_curr
= ah
->cal_list
;
1011 if (ah
->cal_list_curr
)
1012 ath9k_hw_reset_calibration(ah
, ah
->cal_list_curr
);
1015 ah
->caldata
->CalValid
= 0;
1020 void ar9003_hw_attach_calib_ops(struct ath_hw
*ah
)
1022 struct ath_hw_private_ops
*priv_ops
= ath9k_hw_private_ops(ah
);
1023 struct ath_hw_ops
*ops
= ath9k_hw_ops(ah
);
1025 priv_ops
->init_cal_settings
= ar9003_hw_init_cal_settings
;
1026 priv_ops
->init_cal
= ar9003_hw_init_cal
;
1027 priv_ops
->setup_calibration
= ar9003_hw_setup_calibration
;
1029 ops
->calibrate
= ar9003_hw_calibrate
;