2
* Copyright (c) 2008-2011 Atheros Communications Inc.
4
* Modified for iPXE by Scott K Logan <logans@cottsay.net> July 2011
5
* Original from Linux kernel 3.0.1
7
* Permission to use, copy, modify, and/or distribute this software for any
8
* purpose with or without fee is hereby granted, provided that the above
9
* copyright notice and this permission notice appear in all copies.
11
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22
#include "ar9002_phy.h"
24
#define AR9285_CLCAL_REDO_THRESH 1
26
enum ar9002_cal_types {
27
ADC_GAIN_CAL = BIT(0),
29
IQ_MISMATCH_CAL = BIT(2),
32
static int ar9002_hw_is_cal_supported(struct ath_hw *ah,
33
struct ath9k_channel *chan,
34
enum ar9002_cal_types cal_type)
37
switch (ah->supp_cals & cal_type) {
39
/* Run IQ Mismatch for non-CCK only */
45
/* Run ADC Gain Cal for non-CCK & non 2GHz-HT20 only */
46
if (!IS_CHAN_B(chan) &&
47
!(IS_CHAN_2GHZ(chan) && IS_CHAN_HT20(chan)))
54
static void ar9002_hw_setup_calibration(struct ath_hw *ah,
55
struct ath9k_cal_list *currCal)
57
REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(0),
58
AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX,
59
currCal->calData->calCountMax);
61
switch (currCal->calData->calType) {
63
REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_IQ);
65
"starting IQ Mismatch Calibration\n");
68
REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_GAIN);
70
"starting ADC Gain Calibration\n");
73
REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_PER);
75
"starting ADC DC Calibration\n");
79
REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4(0),
80
AR_PHY_TIMING_CTRL4_DO_CAL);
83
static int ar9002_hw_per_calibration(struct ath_hw *ah,
84
struct ath9k_channel *ichan __unused,
86
struct ath9k_cal_list *currCal)
88
struct ath9k_hw_cal_data *caldata = ah->caldata;
91
if (currCal->calState == CAL_RUNNING) {
92
if (!(REG_READ(ah, AR_PHY_TIMING_CTRL4(0)) &
93
AR_PHY_TIMING_CTRL4_DO_CAL)) {
95
currCal->calData->calCollect(ah);
98
if (ah->cal_samples >=
99
currCal->calData->calNumSamples) {
100
int i, numChains = 0;
101
for (i = 0; i < AR5416_MAX_CHAINS; i++) {
102
if (rxchainmask & (1 << i))
106
currCal->calData->calPostProc(ah, numChains);
107
caldata->CalValid |= currCal->calData->calType;
108
currCal->calState = CAL_DONE;
111
ar9002_hw_setup_calibration(ah, currCal);
114
} else if (!(caldata->CalValid & currCal->calData->calType)) {
115
ath9k_hw_reset_calibration(ah, currCal);
121
static void ar9002_hw_iqcal_collect(struct ath_hw *ah)
125
for (i = 0; i < AR5416_MAX_CHAINS; i++) {
126
ah->totalPowerMeasI[i] +=
127
REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
128
ah->totalPowerMeasQ[i] +=
129
REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
130
ah->totalIqCorrMeas[i] +=
131
(int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
133
"%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n",
134
ah->cal_samples, i, ah->totalPowerMeasI[i],
135
ah->totalPowerMeasQ[i],
136
ah->totalIqCorrMeas[i]);
140
static void ar9002_hw_adc_gaincal_collect(struct ath_hw *ah)
144
for (i = 0; i < AR5416_MAX_CHAINS; i++) {
145
ah->totalAdcIOddPhase[i] +=
146
REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
147
ah->totalAdcIEvenPhase[i] +=
148
REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
149
ah->totalAdcQOddPhase[i] +=
150
REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
151
ah->totalAdcQEvenPhase[i] +=
152
REG_READ(ah, AR_PHY_CAL_MEAS_3(i));
155
"%d: Chn %d oddi=0x%08x; eveni=0x%08x; oddq=0x%08x; evenq=0x%08x;\n",
157
ah->totalAdcIOddPhase[i],
158
ah->totalAdcIEvenPhase[i],
159
ah->totalAdcQOddPhase[i],
160
ah->totalAdcQEvenPhase[i]);
164
static void ar9002_hw_adc_dccal_collect(struct ath_hw *ah)
168
for (i = 0; i < AR5416_MAX_CHAINS; i++) {
169
ah->totalAdcDcOffsetIOddPhase[i] +=
170
(int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
171
ah->totalAdcDcOffsetIEvenPhase[i] +=
172
(int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
173
ah->totalAdcDcOffsetQOddPhase[i] +=
174
(int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
175
ah->totalAdcDcOffsetQEvenPhase[i] +=
176
(int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_3(i));
179
"%d: Chn %d oddi=0x%08x; eveni=0x%08x; oddq=0x%08x; evenq=0x%08x;\n",
181
ah->totalAdcDcOffsetIOddPhase[i],
182
ah->totalAdcDcOffsetIEvenPhase[i],
183
ah->totalAdcDcOffsetQOddPhase[i],
184
ah->totalAdcDcOffsetQEvenPhase[i]);
188
static void ar9002_hw_iqcalibrate(struct ath_hw *ah, u8 numChains)
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];
201
"Starting IQ Cal and Correction for Chain %d\n",
205
"Orignal: Chn %diq_corr_meas = 0x%08x\n",
206
i, ah->totalIqCorrMeas[i]);
210
if (iqCorrMeas > 0x80000000) {
211
iqCorrMeas = (0xffffffff - iqCorrMeas) + 1;
216
"Chn %d pwr_meas_i = 0x%08x\n", i, powerMeasI);
218
"Chn %d pwr_meas_q = 0x%08x\n", i, powerMeasQ);
219
DBG2("ath9k: 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;
230
"Chn %d iCoff = 0x%08x\n", i, iCoff);
232
"Chn %d qCoff = 0x%08x\n", i, qCoff);
234
iCoff = iCoff & 0x3f;
236
"New: Chn %d iCoff = 0x%08x\n", i, iCoff);
237
if (iqCorrNeg == 0x0)
238
iCoff = 0x40 - iCoff;
242
else if (qCoff <= -16)
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,
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
u32 iOddMeasOffset, iEvenMeasOffset, qOddMeasOffset, qEvenMeasOffset;
268
u32 qGainMismatch, iGainMismatch, val, i;
270
for (i = 0; i < numChains; i++) {
271
iOddMeasOffset = ah->totalAdcIOddPhase[i];
272
iEvenMeasOffset = ah->totalAdcIEvenPhase[i];
273
qOddMeasOffset = ah->totalAdcQOddPhase[i];
274
qEvenMeasOffset = ah->totalAdcQEvenPhase[i];
277
"Starting ADC Gain Cal for Chain %d\n", i);
280
"Chn %d pwr_meas_odd_i = 0x%08x\n", i,
283
"Chn %d pwr_meas_even_i = 0x%08x\n", i,
286
"Chn %d pwr_meas_odd_q = 0x%08x\n", i,
289
"Chn %d pwr_meas_even_q = 0x%08x\n", i,
292
if (iOddMeasOffset != 0 && qEvenMeasOffset != 0) {
294
((iEvenMeasOffset * 32) /
295
iOddMeasOffset) & 0x3f;
297
((qOddMeasOffset * 32) /
298
qEvenMeasOffset) & 0x3f;
301
"Chn %d gain_mismatch_i = 0x%08x\n", i,
304
"Chn %d gain_mismatch_q = 0x%08x\n", i,
307
val = REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i));
309
val |= (qGainMismatch) | (iGainMismatch << 6);
310
REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val);
313
"ADC Gain Cal done for Chain %d\n", i);
317
REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0),
318
REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0)) |
319
AR_PHY_NEW_ADC_GAIN_CORR_ENABLE);
322
static void ar9002_hw_adc_dccal_calibrate(struct ath_hw *ah, u8 numChains)
324
u32 iOddMeasOffset, iEvenMeasOffset, val, i;
325
int32_t qOddMeasOffset, qEvenMeasOffset, qDcMismatch, iDcMismatch;
326
const struct ath9k_percal_data *calData =
327
ah->cal_list_curr->calData;
329
(1 << (calData->calCountMax + 5)) * calData->calNumSamples;
331
for (i = 0; i < numChains; i++) {
332
iOddMeasOffset = ah->totalAdcDcOffsetIOddPhase[i];
333
iEvenMeasOffset = ah->totalAdcDcOffsetIEvenPhase[i];
334
qOddMeasOffset = ah->totalAdcDcOffsetQOddPhase[i];
335
qEvenMeasOffset = ah->totalAdcDcOffsetQEvenPhase[i];
338
"Starting ADC DC Offset Cal for Chain %d\n", i);
341
"Chn %d pwr_meas_odd_i = %d\n", i,
344
"Chn %d pwr_meas_even_i = %d\n", i,
347
"Chn %d pwr_meas_odd_q = %d\n", i,
350
"Chn %d pwr_meas_even_q = %d\n", i,
353
iDcMismatch = (((iEvenMeasOffset - iOddMeasOffset) * 2) /
355
qDcMismatch = (((qOddMeasOffset - qEvenMeasOffset) * 2) /
359
"Chn %d dc_offset_mismatch_i = 0x%08x\n", i,
362
"Chn %d dc_offset_mismatch_q = 0x%08x\n", i,
365
val = REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i));
367
val |= (qDcMismatch << 12) | (iDcMismatch << 21);
368
REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val);
371
"ADC DC Offset Cal done for Chain %d\n", i);
374
REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0),
375
REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0)) |
376
AR_PHY_NEW_ADC_DC_OFFSET_CORR_ENABLE);
379
static void ar9287_hw_olc_temp_compensation(struct ath_hw *ah)
382
int32_t delta, currPDADC, slope;
384
rddata = REG_READ(ah, AR_PHY_TX_PWRCTRL4);
385
currPDADC = MS(rddata, AR_PHY_TX_PWRCTRL_PD_AVG_OUT);
387
if (ah->initPDADC == 0 || currPDADC == 0) {
389
* Zero value indicates that no frames have been transmitted
390
* yet, can't do temperature compensation until frames are
395
slope = ah->eep_ops->get_eeprom(ah, EEP_TEMPSENSE_SLOPE);
397
if (slope == 0) { /* to avoid divide by zero case */
400
delta = ((currPDADC - ah->initPDADC)*4) / slope;
402
REG_RMW_FIELD(ah, AR_PHY_CH0_TX_PWRCTRL11,
403
AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP, delta);
404
REG_RMW_FIELD(ah, AR_PHY_CH1_TX_PWRCTRL11,
405
AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP, delta);
409
static void ar9280_hw_olc_temp_compensation(struct ath_hw *ah)
412
int delta, currPDADC, regval;
414
rddata = REG_READ(ah, AR_PHY_TX_PWRCTRL4);
415
currPDADC = MS(rddata, AR_PHY_TX_PWRCTRL_PD_AVG_OUT);
417
if (ah->initPDADC == 0 || currPDADC == 0)
420
if (ah->eep_ops->get_eeprom(ah, EEP_DAC_HPWR_5G))
421
delta = (currPDADC - ah->initPDADC + 4) / 8;
423
delta = (currPDADC - ah->initPDADC + 5) / 10;
425
if (delta != ah->PDADCdelta) {
426
ah->PDADCdelta = delta;
427
for (i = 1; i < AR9280_TX_GAIN_TABLE_SIZE; i++) {
428
regval = ah->originalGain[i] - delta;
433
AR_PHY_TX_GAIN_TBL1 + i * 4,
434
AR_PHY_TX_GAIN, regval);
439
static void ar9271_hw_pa_cal(struct ath_hw *ah, int is_reset)
454
for (i = 0; i < ARRAY_SIZE(regList); i++)
455
regList[i][1] = REG_READ(ah, regList[i][0]);
457
regVal = REG_READ(ah, 0x7834);
459
REG_WRITE(ah, 0x7834, regVal);
460
regVal = REG_READ(ah, 0x9808);
461
regVal |= (0x1 << 27);
462
REG_WRITE(ah, 0x9808, regVal);
464
/* 786c,b23,1, pwddac=1 */
465
REG_RMW_FIELD(ah, AR9285_AN_TOP3, AR9285_AN_TOP3_PWDDAC, 1);
466
/* 7854, b5,1, pdrxtxbb=1 */
467
REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDRXTXBB1, 1);
468
/* 7854, b7,1, pdv2i=1 */
469
REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDV2I, 1);
470
/* 7854, b8,1, pddacinterface=1 */
471
REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDDACIF, 1);
472
/* 7824,b12,0, offcal=0 */
473
REG_RMW_FIELD(ah, AR9285_AN_RF2G2, AR9285_AN_RF2G2_OFFCAL, 0);
474
/* 7838, b1,0, pwddb=0 */
475
REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PWDDB, 0);
476
/* 7820,b11,0, enpacal=0 */
477
REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_ENPACAL, 0);
478
/* 7820,b25,1, pdpadrv1=0 */
479
REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV1, 0);
480
/* 7820,b24,0, pdpadrv2=0 */
481
REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV2, 0);
482
/* 7820,b23,0, pdpaout=0 */
483
REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPAOUT, 0);
484
/* 783c,b14-16,7, padrvgn2tab_0=7 */
485
REG_RMW_FIELD(ah, AR9285_AN_RF2G8, AR9285_AN_RF2G8_PADRVGN2TAB0, 7);
487
* 7838,b29-31,0, padrvgn1tab_0=0
488
* does not matter since we turn it off
490
REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PADRVGN2TAB0, 0);
492
REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9271_AN_RF2G3_CCOMP, 0xfff);
495
* localmode=1,bmode=1,bmoderxtx=1,synthon=1,
496
* txon=1,paon=1,oscon=1,synthon_force=1
498
REG_WRITE(ah, AR9285_AN_TOP2, 0xca0358a0);
500
REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9271_AN_RF2G6_OFFS, 0);
503
for (i = 6; i > 0; i--) {
504
regVal = REG_READ(ah, 0x7834);
505
regVal |= (1 << (20 + i));
506
REG_WRITE(ah, 0x7834, regVal);
508
/* regVal = REG_READ(ah, 0x7834); */
509
regVal &= (~(0x1 << (20 + i)));
510
regVal |= (MS(REG_READ(ah, 0x7840), AR9285_AN_RXTXBB1_SPARE9)
512
REG_WRITE(ah, 0x7834, regVal);
515
regVal = (regVal >> 20) & 0x7f;
517
/* Update PA cal info */
518
if ((!is_reset) && ((unsigned int)ah->pacal_info.prev_offset == regVal)) {
519
if (ah->pacal_info.max_skipcount < MAX_PACAL_SKIPCOUNT)
520
ah->pacal_info.max_skipcount =
521
2 * ah->pacal_info.max_skipcount;
522
ah->pacal_info.skipcount = ah->pacal_info.max_skipcount;
524
ah->pacal_info.max_skipcount = 1;
525
ah->pacal_info.skipcount = 0;
526
ah->pacal_info.prev_offset = regVal;
529
ENABLE_REGWRITE_BUFFER(ah);
531
regVal = REG_READ(ah, 0x7834);
533
REG_WRITE(ah, 0x7834, regVal);
534
regVal = REG_READ(ah, 0x9808);
535
regVal &= (~(0x1 << 27));
536
REG_WRITE(ah, 0x9808, regVal);
538
for (i = 0; i < ARRAY_SIZE(regList); i++)
539
REG_WRITE(ah, regList[i][0], regList[i][1]);
541
REGWRITE_BUFFER_FLUSH(ah);
544
static inline void ar9285_hw_pa_cal(struct ath_hw *ah, int is_reset)
548
int offset, offs_6_1, offs_0;
549
u32 ccomp_org, reg_field;
560
DBG2("ath9k: Running PA Calibration\n");
562
/* PA CAL is not needed for high power solution */
563
if (ah->eep_ops->get_eeprom(ah, EEP_TXGAIN_TYPE) ==
564
AR5416_EEP_TXGAIN_HIGH_POWER)
567
for (i = 0; i < ARRAY_SIZE(regList); i++)
568
regList[i][1] = REG_READ(ah, regList[i][0]);
570
regVal = REG_READ(ah, 0x7834);
572
REG_WRITE(ah, 0x7834, regVal);
573
regVal = REG_READ(ah, 0x9808);
574
regVal |= (0x1 << 27);
575
REG_WRITE(ah, 0x9808, regVal);
577
REG_RMW_FIELD(ah, AR9285_AN_TOP3, AR9285_AN_TOP3_PWDDAC, 1);
578
REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDRXTXBB1, 1);
579
REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDV2I, 1);
580
REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDDACIF, 1);
581
REG_RMW_FIELD(ah, AR9285_AN_RF2G2, AR9285_AN_RF2G2_OFFCAL, 0);
582
REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PWDDB, 0);
583
REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_ENPACAL, 0);
584
REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV1, 0);
585
REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV2, 0);
586
REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPAOUT, 0);
587
REG_RMW_FIELD(ah, AR9285_AN_RF2G8, AR9285_AN_RF2G8_PADRVGN2TAB0, 7);
588
REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PADRVGN2TAB0, 0);
589
ccomp_org = MS(REG_READ(ah, AR9285_AN_RF2G6), AR9285_AN_RF2G6_CCOMP);
590
REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_CCOMP, 0xf);
592
REG_WRITE(ah, AR9285_AN_TOP2, 0xca0358a0);
594
REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_OFFS, 0);
595
REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, 0);
597
for (i = 6; i > 0; i--) {
598
regVal = REG_READ(ah, 0x7834);
599
regVal |= (1 << (19 + i));
600
REG_WRITE(ah, 0x7834, regVal);
602
regVal = REG_READ(ah, 0x7834);
603
regVal &= (~(0x1 << (19 + i)));
604
reg_field = MS(REG_READ(ah, 0x7840), AR9285_AN_RXTXBB1_SPARE9);
605
regVal |= (reg_field << (19 + i));
606
REG_WRITE(ah, 0x7834, regVal);
609
REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, 1);
611
reg_field = MS(REG_READ(ah, AR9285_AN_RF2G9), AR9285_AN_RXTXBB1_SPARE9);
612
REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, reg_field);
613
offs_6_1 = MS(REG_READ(ah, AR9285_AN_RF2G6), AR9285_AN_RF2G6_OFFS);
614
offs_0 = MS(REG_READ(ah, AR9285_AN_RF2G3), AR9285_AN_RF2G3_PDVCCOMP);
616
offset = (offs_6_1<<1) | offs_0;
618
offs_6_1 = offset>>1;
621
if ((!is_reset) && (ah->pacal_info.prev_offset == offset)) {
622
if (ah->pacal_info.max_skipcount < MAX_PACAL_SKIPCOUNT)
623
ah->pacal_info.max_skipcount =
624
2 * ah->pacal_info.max_skipcount;
625
ah->pacal_info.skipcount = ah->pacal_info.max_skipcount;
627
ah->pacal_info.max_skipcount = 1;
628
ah->pacal_info.skipcount = 0;
629
ah->pacal_info.prev_offset = offset;
632
REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_OFFS, offs_6_1);
633
REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, offs_0);
635
regVal = REG_READ(ah, 0x7834);
637
REG_WRITE(ah, 0x7834, regVal);
638
regVal = REG_READ(ah, 0x9808);
639
regVal &= (~(0x1 << 27));
640
REG_WRITE(ah, 0x9808, regVal);
642
for (i = 0; i < ARRAY_SIZE(regList); i++)
643
REG_WRITE(ah, regList[i][0], regList[i][1]);
645
REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_CCOMP, ccomp_org);
648
static void ar9002_hw_pa_cal(struct ath_hw *ah, int is_reset)
650
if (AR_SREV_9271(ah)) {
651
if (is_reset || !ah->pacal_info.skipcount)
652
ar9271_hw_pa_cal(ah, is_reset);
654
ah->pacal_info.skipcount--;
655
} else if (AR_SREV_9285_12_OR_LATER(ah)) {
656
if (is_reset || !ah->pacal_info.skipcount)
657
ar9285_hw_pa_cal(ah, is_reset);
659
ah->pacal_info.skipcount--;
663
static void ar9002_hw_olc_temp_compensation(struct ath_hw *ah)
665
if (OLC_FOR_AR9287_10_LATER)
666
ar9287_hw_olc_temp_compensation(ah);
667
else if (OLC_FOR_AR9280_20_LATER)
668
ar9280_hw_olc_temp_compensation(ah);
671
static int ar9002_hw_calibrate(struct ath_hw *ah,
672
struct ath9k_channel *chan,
677
struct ath9k_cal_list *currCal = ah->cal_list_curr;
678
int nfcal, nfcal_pending = 0;
680
nfcal = !!(REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF);
682
nfcal_pending = ah->caldata->nfcal_pending;
684
if (currCal && !nfcal &&
685
(currCal->calState == CAL_RUNNING ||
686
currCal->calState == CAL_WAITING)) {
687
iscaldone = ar9002_hw_per_calibration(ah, chan,
688
rxchainmask, currCal);
690
ah->cal_list_curr = currCal = currCal->calNext;
692
if (currCal->calState == CAL_WAITING) {
694
ath9k_hw_reset_calibration(ah, currCal);
699
/* Do NF cal only at longer intervals */
700
if (longcal || nfcal_pending) {
702
* Get the value from the previous NF cal and update
705
if (ath9k_hw_getnf(ah, chan)) {
707
* Load the NF from history buffer of the current
709
* NF is slow time-variant, so it is OK to use a
712
ath9k_hw_loadnf(ah, ah->curchan);
716
ath9k_hw_start_nfcal(ah, 0);
717
/* Do periodic PAOffset Cal */
718
ar9002_hw_pa_cal(ah, 0);
719
ar9002_hw_olc_temp_compensation(ah);
726
/* Carrier leakage Calibration fix */
727
static int ar9285_hw_cl_cal(struct ath_hw *ah, struct ath9k_channel *chan)
729
REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE);
730
if (IS_CHAN_HT20(chan)) {
731
REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_PARALLEL_CAL_ENABLE);
732
REG_SET_BIT(ah, AR_PHY_TURBO, AR_PHY_FC_DYN2040_EN);
733
REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
734
AR_PHY_AGC_CONTROL_FLTR_CAL);
735
REG_CLR_BIT(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_CAL_ENABLE);
736
REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL);
737
if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL,
738
AR_PHY_AGC_CONTROL_CAL, 0, AH_WAIT_TIMEOUT)) {
740
"offset calibration failed to complete in 1ms; noisy environment?\n");
743
REG_CLR_BIT(ah, AR_PHY_TURBO, AR_PHY_FC_DYN2040_EN);
744
REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_PARALLEL_CAL_ENABLE);
745
REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE);
747
REG_CLR_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC);
748
REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL);
749
REG_SET_BIT(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_CAL_ENABLE);
750
REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL);
751
if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL,
752
0, AH_WAIT_TIMEOUT)) {
754
"offset calibration failed to complete in 1ms; noisy environment?\n");
758
REG_SET_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC);
759
REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE);
760
REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL);
765
static int ar9285_hw_clc(struct ath_hw *ah, struct ath9k_channel *chan)
769
uint32_t clc_gain, gain_mask = 0, clc_num = 0;
770
uint32_t reg_clc_I0, reg_clc_Q0;
773
uint32_t total_num = 0;
774
uint32_t reg_rf2g5_org;
777
if (!(ar9285_hw_cl_cal(ah, chan)))
780
txgain_max = MS(REG_READ(ah, AR_PHY_TX_PWRCTRL7),
781
AR_PHY_TX_PWRCTRL_TX_GAIN_TAB_MAX);
783
for (i = 0; i < (txgain_max+1); i++) {
784
clc_gain = (REG_READ(ah, (AR_PHY_TX_GAIN_TBL1+(i<<2))) &
785
AR_PHY_TX_GAIN_CLC) >> AR_PHY_TX_GAIN_CLC_S;
786
if (!(gain_mask & (1 << clc_gain))) {
787
gain_mask |= (1 << clc_gain);
792
for (i = 0; i < clc_num; i++) {
793
reg_clc_I0 = (REG_READ(ah, (AR_PHY_CLC_TBL1 + (i << 2)))
794
& AR_PHY_CLC_I0) >> AR_PHY_CLC_I0_S;
795
reg_clc_Q0 = (REG_READ(ah, (AR_PHY_CLC_TBL1 + (i << 2)))
796
& AR_PHY_CLC_Q0) >> AR_PHY_CLC_Q0_S;
803
total_num = i0_num + q0_num;
804
if (total_num > AR9285_CLCAL_REDO_THRESH) {
805
reg_rf2g5_org = REG_READ(ah, AR9285_RF2G5);
806
if (AR_SREV_9285E_20(ah)) {
807
REG_WRITE(ah, AR9285_RF2G5,
808
(reg_rf2g5_org & AR9285_RF2G5_IC50TX) |
809
AR9285_RF2G5_IC50TX_XE_SET);
811
REG_WRITE(ah, AR9285_RF2G5,
812
(reg_rf2g5_org & AR9285_RF2G5_IC50TX) |
813
AR9285_RF2G5_IC50TX_SET);
815
retv = ar9285_hw_cl_cal(ah, chan);
816
REG_WRITE(ah, AR9285_RF2G5, reg_rf2g5_org);
821
static int ar9002_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan)
823
if (AR_SREV_9271(ah)) {
824
if (!ar9285_hw_cl_cal(ah, chan))
826
} else if (AR_SREV_9285(ah) && AR_SREV_9285_12_OR_LATER(ah)) {
827
if (!ar9285_hw_clc(ah, chan))
830
if (AR_SREV_9280_20_OR_LATER(ah)) {
831
if (!AR_SREV_9287_11_OR_LATER(ah))
832
REG_CLR_BIT(ah, AR_PHY_ADC_CTL,
833
AR_PHY_ADC_CTL_OFF_PWDADC);
834
REG_SET_BIT(ah, AR_PHY_AGC_CONTROL,
835
AR_PHY_AGC_CONTROL_FLTR_CAL);
838
/* Calibrate the AGC */
839
REG_WRITE(ah, AR_PHY_AGC_CONTROL,
840
REG_READ(ah, AR_PHY_AGC_CONTROL) |
841
AR_PHY_AGC_CONTROL_CAL);
843
/* Poll for offset calibration complete */
844
if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL,
845
AR_PHY_AGC_CONTROL_CAL,
846
0, AH_WAIT_TIMEOUT)) {
848
"offset calibration failed to complete in 1ms; noisy environment?\n");
852
if (AR_SREV_9280_20_OR_LATER(ah)) {
853
if (!AR_SREV_9287_11_OR_LATER(ah))
854
REG_SET_BIT(ah, AR_PHY_ADC_CTL,
855
AR_PHY_ADC_CTL_OFF_PWDADC);
856
REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
857
AR_PHY_AGC_CONTROL_FLTR_CAL);
861
/* Do PA Calibration */
862
ar9002_hw_pa_cal(ah, 1);
864
/* Do NF Calibration after DC offset and other calibrations */
865
ath9k_hw_start_nfcal(ah, 1);
868
ah->caldata->nfcal_pending = 1;
870
ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL;
872
/* Enable IQ, ADC Gain and ADC DC offset CALs */
873
if (AR_SREV_9100(ah) || AR_SREV_9160_10_OR_LATER(ah)) {
874
ah->supp_cals = IQ_MISMATCH_CAL;
876
if (AR_SREV_9160_10_OR_LATER(ah))
877
ah->supp_cals |= ADC_GAIN_CAL | ADC_DC_CAL;
879
if (AR_SREV_9287(ah))
880
ah->supp_cals &= ~ADC_GAIN_CAL;
882
if (ar9002_hw_is_cal_supported(ah, chan, ADC_GAIN_CAL)) {
883
INIT_CAL(&ah->adcgain_caldata);
884
INSERT_CAL(ah, &ah->adcgain_caldata);
886
"enabling ADC Gain Calibration.\n");
889
if (ar9002_hw_is_cal_supported(ah, chan, ADC_DC_CAL)) {
890
INIT_CAL(&ah->adcdc_caldata);
891
INSERT_CAL(ah, &ah->adcdc_caldata);
893
"enabling ADC DC Calibration.\n");
896
if (ar9002_hw_is_cal_supported(ah, chan, IQ_MISMATCH_CAL)) {
897
INIT_CAL(&ah->iq_caldata);
898
INSERT_CAL(ah, &ah->iq_caldata);
900
"enabling IQ Calibration.\n");
903
ah->cal_list_curr = ah->cal_list;
905
if (ah->cal_list_curr)
906
ath9k_hw_reset_calibration(ah, ah->cal_list_curr);
910
ah->caldata->CalValid = 0;
915
static const struct ath9k_percal_data iq_cal_multi_sample = {
919
ar9002_hw_iqcal_collect,
920
ar9002_hw_iqcalibrate
922
static const struct ath9k_percal_data iq_cal_single_sample = {
926
ar9002_hw_iqcal_collect,
927
ar9002_hw_iqcalibrate
929
static const struct ath9k_percal_data adc_gain_cal_multi_sample = {
933
ar9002_hw_adc_gaincal_collect,
934
ar9002_hw_adc_gaincal_calibrate
936
static const struct ath9k_percal_data adc_gain_cal_single_sample = {
940
ar9002_hw_adc_gaincal_collect,
941
ar9002_hw_adc_gaincal_calibrate
943
static const struct ath9k_percal_data adc_dc_cal_multi_sample = {
947
ar9002_hw_adc_dccal_collect,
948
ar9002_hw_adc_dccal_calibrate
950
static const struct ath9k_percal_data adc_dc_cal_single_sample = {
954
ar9002_hw_adc_dccal_collect,
955
ar9002_hw_adc_dccal_calibrate
958
static void ar9002_hw_init_cal_settings(struct ath_hw *ah)
960
if (AR_SREV_9100(ah)) {
961
ah->iq_caldata.calData = &iq_cal_multi_sample;
962
ah->supp_cals = IQ_MISMATCH_CAL;
966
if (AR_SREV_9160_10_OR_LATER(ah)) {
967
if (AR_SREV_9280_20_OR_LATER(ah)) {
968
ah->iq_caldata.calData = &iq_cal_single_sample;
969
ah->adcgain_caldata.calData =
970
&adc_gain_cal_single_sample;
971
ah->adcdc_caldata.calData =
972
&adc_dc_cal_single_sample;
974
ah->iq_caldata.calData = &iq_cal_multi_sample;
975
ah->adcgain_caldata.calData =
976
&adc_gain_cal_multi_sample;
977
ah->adcdc_caldata.calData =
978
&adc_dc_cal_multi_sample;
980
ah->supp_cals = ADC_GAIN_CAL | ADC_DC_CAL | IQ_MISMATCH_CAL;
982
if (AR_SREV_9287(ah))
983
ah->supp_cals &= ~ADC_GAIN_CAL;
987
void ar9002_hw_attach_calib_ops(struct ath_hw *ah)
989
struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
990
struct ath_hw_ops *ops = ath9k_hw_ops(ah);
992
priv_ops->init_cal_settings = ar9002_hw_init_cal_settings;
993
priv_ops->init_cal = ar9002_hw_init_cal;
994
priv_ops->setup_calibration = ar9002_hw_setup_calibration;
996
ops->calibrate = ar9002_hw_calibrate;