2 * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
3 * Copyright (c) 2002-2008 Atheros Communications, Inc.
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 * $Id: ar5212_rfgain.c,v 1.1.1.1 2008/12/11 04:46:43 alc Exp $
22 #include "ah_internal.h"
25 #include "ar5212/ar5212.h"
26 #include "ar5212/ar5212reg.h"
27 #include "ar5212/ar5212phy.h"
29 #include "ah_eeprom_v3.h"
31 static const GAIN_OPTIMIZATION_LADDER gainLadder
= {
32 9, /* numStepsInLadder */
33 4, /* defaultStepNum */
34 { { {4, 1, 1, 1}, 6, "FG8"},
35 { {4, 0, 1, 1}, 4, "FG7"},
36 { {3, 1, 1, 1}, 3, "FG6"},
37 { {4, 0, 0, 1}, 1, "FG5"},
38 { {4, 1, 1, 0}, 0, "FG4"}, /* noJack */
39 { {4, 0, 1, 0}, -2, "FG3"}, /* halfJack */
40 { {3, 1, 1, 0}, -3, "FG2"}, /* clip3 */
41 { {4, 0, 0, 0}, -4, "FG1"}, /* noJack */
42 { {2, 1, 1, 0}, -6, "FG0"} /* clip2 */
46 static const GAIN_OPTIMIZATION_LADDER gainLadder5112
= {
47 8, /* numStepsInLadder */
48 1, /* defaultStepNum */
49 { { {3, 0,0,0, 0,0,0}, 6, "FG7"}, /* most fixed gain */
50 { {2, 0,0,0, 0,0,0}, 0, "FG6"},
51 { {1, 0,0,0, 0,0,0}, -3, "FG5"},
52 { {0, 0,0,0, 0,0,0}, -6, "FG4"},
53 { {0, 1,1,0, 0,0,0}, -8, "FG3"},
54 { {0, 1,1,0, 1,1,0}, -10, "FG2"},
55 { {0, 1,0,1, 1,1,0}, -13, "FG1"},
56 { {0, 1,0,1, 1,0,1}, -16, "FG0"}, /* least fixed gain */
61 * Initialize the gain structure to good values
64 ar5212InitializeGainValues(struct ath_hal
*ah
)
66 struct ath_hal_5212
*ahp
= AH5212(ah
);
67 GAIN_VALUES
*gv
= &ahp
->ah_gainValues
;
69 /* initialize gain optimization values */
70 if (IS_RAD5112_ANY(ah
)) {
71 gv
->currStepNum
= gainLadder5112
.defaultStepNum
;
73 &gainLadder5112
.optStep
[gainLadder5112
.defaultStepNum
];
78 gv
->currStepNum
= gainLadder
.defaultStepNum
;
79 gv
->currStep
= &gainLadder
.optStep
[gainLadder
.defaultStepNum
];
86 #define MAX_ANALOG_START 319 /* XXX */
89 * Find analog bits of given parameter data and return a reversed value
92 ar5212GetRfField(uint32_t *rfBuf
, uint32_t numBits
, uint32_t firstBit
, uint32_t column
)
94 uint32_t reg32
= 0, mask
, arrayEntry
, lastBit
;
95 uint32_t bitPosition
, bitsShifted
;
98 HALASSERT(column
<= 3);
99 HALASSERT(numBits
<= 32);
100 HALASSERT(firstBit
+ numBits
<= MAX_ANALOG_START
);
102 arrayEntry
= (firstBit
- 1) / 8;
103 bitPosition
= (firstBit
- 1) % 8;
106 while (bitsLeft
> 0) {
107 lastBit
= (bitPosition
+ bitsLeft
> 8) ?
108 (8) : (bitPosition
+ bitsLeft
);
109 mask
= (((1 << lastBit
) - 1) ^ ((1 << bitPosition
) - 1)) <<
111 reg32
|= (((rfBuf
[arrayEntry
] & mask
) >> (column
* 8)) >>
112 bitPosition
) << bitsShifted
;
113 bitsShifted
+= lastBit
- bitPosition
;
114 bitsLeft
-= (8 - bitPosition
);
118 reg32
= ath_hal_reverseBits(reg32
, numBits
);
123 ar5212InvalidGainReadback(struct ath_hal
*ah
, GAIN_VALUES
*gv
)
125 uint32_t gStep
, g
, mixOvr
;
126 uint32_t L1
, L2
, L3
, L4
;
128 if (IS_RAD5112_ANY(ah
)) {
129 mixOvr
= ar5212GetRfField(ar5212GetRfBank(ah
, 7), 1, 36, 0);
140 gStep
= ar5212GetRfField(ar5212GetRfBank(ah
, 7), 6, 37, 0);
143 L2
= (gStep
== 0x3f) ? 50 : gStep
+ 4;
144 L3
= (gStep
!= 0x3f) ? 0x40 : L1
;
147 gv
->loTrig
= L1
+ (gStep
== 0x3f ? DYN_ADJ_LO_MARGIN
: 0);
148 /* never adjust if != 0x3f */
149 gv
->hiTrig
= L4
- (gStep
== 0x3f ? DYN_ADJ_UP_MARGIN
: -5);
153 return !((g
>= L1
&& g
<= L2
) || (g
>= L3
&& g
<= L4
));
157 * Enable the probe gain check on the next packet
160 ar5212RequestRfgain(struct ath_hal
*ah
)
162 struct ath_hal_5212
*ahp
= AH5212(ah
);
163 uint32_t probePowerIndex
;
165 /* Enable the gain readback probe */
166 probePowerIndex
= ahp
->ah_ofdmTxPower
+ ahp
->ah_txPowerIndexOffset
;
167 OS_REG_WRITE(ah
, AR_PHY_PAPD_PROBE
,
168 SM(probePowerIndex
, AR_PHY_PAPD_PROBE_POWERTX
)
169 | AR_PHY_PAPD_PROBE_NEXT_TX
);
171 ahp
->ah_rfgainState
= HAL_RFGAIN_READ_REQUESTED
;
175 * Check to see if our readback gain level sits within the linear
176 * region of our current variable attenuation window
179 ar5212IsGainAdjustNeeded(struct ath_hal
*ah
, const GAIN_VALUES
*gv
)
181 return (gv
->currGain
<= gv
->loTrig
|| gv
->currGain
>= gv
->hiTrig
);
185 * Move the rabbit ears in the correct direction.
188 ar5212AdjustGain(struct ath_hal
*ah
, GAIN_VALUES
*gv
)
190 const GAIN_OPTIMIZATION_LADDER
*gl
;
192 if (IS_RAD5112_ANY(ah
))
193 gl
= &gainLadder5112
;
196 gv
->currStep
= &gl
->optStep
[gv
->currStepNum
];
197 if (gv
->currGain
>= gv
->hiTrig
) {
198 if (gv
->currStepNum
== 0) {
199 HALDEBUG(ah
, HAL_DEBUG_ANY
, "%s: Max gain limit.\n",
203 HALDEBUG(ah
, HAL_DEBUG_RFPARAM
,
204 "%s: Adding gain: currG=%d [%s] --> ",
205 __func__
, gv
->currGain
, gv
->currStep
->stepName
);
206 gv
->targetGain
= gv
->currGain
;
207 while (gv
->targetGain
>= gv
->hiTrig
&& gv
->currStepNum
> 0) {
208 gv
->targetGain
-= 2 * (gl
->optStep
[--(gv
->currStepNum
)].stepGain
-
209 gv
->currStep
->stepGain
);
210 gv
->currStep
= &gl
->optStep
[gv
->currStepNum
];
212 HALDEBUG(ah
, HAL_DEBUG_RFPARAM
, "targG=%d [%s]\n",
213 gv
->targetGain
, gv
->currStep
->stepName
);
216 if (gv
->currGain
<= gv
->loTrig
) {
217 if (gv
->currStepNum
== gl
->numStepsInLadder
-1) {
218 HALDEBUG(ah
, HAL_DEBUG_RFPARAM
,
219 "%s: Min gain limit.\n", __func__
);
222 HALDEBUG(ah
, HAL_DEBUG_RFPARAM
,
223 "%s: Deducting gain: currG=%d [%s] --> ",
224 __func__
, gv
->currGain
, gv
->currStep
->stepName
);
225 gv
->targetGain
= gv
->currGain
;
226 while (gv
->targetGain
<= gv
->loTrig
&&
227 gv
->currStepNum
< (gl
->numStepsInLadder
- 1)) {
228 gv
->targetGain
-= 2 *
229 (gl
->optStep
[++(gv
->currStepNum
)].stepGain
- gv
->currStep
->stepGain
);
230 gv
->currStep
= &gl
->optStep
[gv
->currStepNum
];
232 HALDEBUG(ah
, HAL_DEBUG_RFPARAM
, "targG=%d [%s]\n",
233 gv
->targetGain
, gv
->currStep
->stepName
);
236 return 0; /* caller didn't call needAdjGain first */
240 * Read rf register to determine if gainF needs correction
243 ar5212GetGainFCorrection(struct ath_hal
*ah
)
245 struct ath_hal_5212
*ahp
= AH5212(ah
);
246 GAIN_VALUES
*gv
= &ahp
->ah_gainValues
;
248 HALASSERT(IS_RADX112_REV2(ah
));
250 gv
->gainFCorrection
= 0;
251 if (ar5212GetRfField(ar5212GetRfBank(ah
, 7), 1, 36, 0) == 1) {
252 uint32_t mixGain
= gv
->currStep
->paramVal
[0];
254 ar5212GetRfField(ar5212GetRfBank(ah
, 7), 4, 32, 0);
257 gv
->gainFCorrection
= 0;
260 gv
->gainFCorrection
= gainStep
;
263 gv
->gainFCorrection
= 2 * gainStep
- 5;
266 gv
->gainFCorrection
= 2 * gainStep
;
273 * Exported call to check for a recent gain reading and return
274 * the current state of the thermal calibration gain engine.
277 ar5212GetRfgain(struct ath_hal
*ah
)
279 struct ath_hal_5212
*ahp
= AH5212(ah
);
280 GAIN_VALUES
*gv
= &ahp
->ah_gainValues
;
281 uint32_t rddata
, probeType
;
284 return HAL_RFGAIN_INACTIVE
;
286 if (ahp
->ah_rfgainState
== HAL_RFGAIN_READ_REQUESTED
) {
287 /* Caller had asked to setup a new reading. Check it. */
288 rddata
= OS_REG_READ(ah
, AR_PHY_PAPD_PROBE
);
290 if ((rddata
& AR_PHY_PAPD_PROBE_NEXT_TX
) == 0) {
291 /* bit got cleared, we have a new reading. */
292 gv
->currGain
= rddata
>> AR_PHY_PAPD_PROBE_GAINF_S
;
293 probeType
= MS(rddata
, AR_PHY_PAPD_PROBE_TYPE
);
294 if (probeType
== AR_PHY_PAPD_PROBE_TYPE_CCK
) {
295 const HAL_EEPROM
*ee
= AH_PRIVATE(ah
)->ah_eeprom
;
297 HALASSERT(IS_RAD5112_ANY(ah
));
298 HALASSERT(ah
->ah_magic
== AR5212_MAGIC
);
299 if (AH_PRIVATE(ah
)->ah_phyRev
>= AR_PHY_CHIP_ID_REV_2
)
300 gv
->currGain
+= ee
->ee_cckOfdmGainDelta
;
302 gv
->currGain
+= PHY_PROBE_CCK_CORRECTION
;
304 if (IS_RADX112_REV2(ah
)) {
305 ar5212GetGainFCorrection(ah
);
306 if (gv
->currGain
>= gv
->gainFCorrection
)
307 gv
->currGain
-= gv
->gainFCorrection
;
311 /* inactive by default */
312 ahp
->ah_rfgainState
= HAL_RFGAIN_INACTIVE
;
314 if (!ar5212InvalidGainReadback(ah
, gv
) &&
315 ar5212IsGainAdjustNeeded(ah
, gv
) &&
316 ar5212AdjustGain(ah
, gv
) > 0) {
318 * Change needed. Copy ladder info
321 ahp
->ah_rfgainState
= HAL_RFGAIN_NEED_CHANGE
;
323 ahp
->ah_cwCalRequire
= AH_TRUE
;
324 /* Request IQ recalibration for temperature chang */
325 ahp
->ah_bIQCalibration
= IQ_CAL_INACTIVE
;
329 return ahp
->ah_rfgainState
;