FreeBSD kernel ATH device code
ar5212_rfgain.c
Go to the documentation of this file.
1/*-
2 * SPDX-License-Identifier: ISC
3 *
4 * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
5 * Copyright (c) 2002-2008 Atheros Communications, Inc.
6 *
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.
10 *
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.
18 *
19 * $FreeBSD$
20 */
21#include "opt_ah.h"
22
23#include "ah.h"
24#include "ah_internal.h"
25#include "ah_devid.h"
26
27#include "ar5212/ar5212.h"
28#include "ar5212/ar5212reg.h"
29#include "ar5212/ar5212phy.h"
30
31#include "ah_eeprom_v3.h"
32
34 9, /* numStepsInLadder */
35 4, /* defaultStepNum */
36 { { {4, 1, 1, 1}, 6, "FG8"},
37 { {4, 0, 1, 1}, 4, "FG7"},
38 { {3, 1, 1, 1}, 3, "FG6"},
39 { {4, 0, 0, 1}, 1, "FG5"},
40 { {4, 1, 1, 0}, 0, "FG4"}, /* noJack */
41 { {4, 0, 1, 0}, -2, "FG3"}, /* halfJack */
42 { {3, 1, 1, 0}, -3, "FG2"}, /* clip3 */
43 { {4, 0, 0, 0}, -4, "FG1"}, /* noJack */
44 { {2, 1, 1, 0}, -6, "FG0"} /* clip2 */
45 }
46};
47
49 8, /* numStepsInLadder */
50 1, /* defaultStepNum */
51 { { {3, 0,0,0, 0,0,0}, 6, "FG7"}, /* most fixed gain */
52 { {2, 0,0,0, 0,0,0}, 0, "FG6"},
53 { {1, 0,0,0, 0,0,0}, -3, "FG5"},
54 { {0, 0,0,0, 0,0,0}, -6, "FG4"},
55 { {0, 1,1,0, 0,0,0}, -8, "FG3"},
56 { {0, 1,1,0, 1,1,0}, -10, "FG2"},
57 { {0, 1,0,1, 1,1,0}, -13, "FG1"},
58 { {0, 1,0,1, 1,0,1}, -16, "FG0"}, /* least fixed gain */
59 }
60};
61
62/*
63 * Initialize the gain structure to good values
64 */
65void
67{
68 struct ath_hal_5212 *ahp = AH5212(ah);
69 GAIN_VALUES *gv = &ahp->ah_gainValues;
70
71 /* initialize gain optimization values */
72 if (IS_RAD5112_ANY(ah)) {
74 gv->currStep =
76 gv->active = AH_TRUE;
77 gv->loTrig = 20;
78 gv->hiTrig = 85;
79 } else {
82 gv->active = AH_TRUE;
83 gv->loTrig = 20;
84 gv->hiTrig = 35;
85 }
86}
87
88#define MAX_ANALOG_START 319 /* XXX */
89
90/*
91 * Find analog bits of given parameter data and return a reversed value
92 */
93static uint32_t
94ar5212GetRfField(uint32_t *rfBuf, uint32_t numBits, uint32_t firstBit, uint32_t column)
95{
96 uint32_t reg32 = 0, mask, arrayEntry, lastBit;
97 uint32_t bitPosition, bitsShifted;
98 int32_t bitsLeft;
99
100 HALASSERT(column <= 3);
101 HALASSERT(numBits <= 32);
102 HALASSERT(firstBit + numBits <= MAX_ANALOG_START);
103
104 arrayEntry = (firstBit - 1) / 8;
105 bitPosition = (firstBit - 1) % 8;
106 bitsLeft = numBits;
107 bitsShifted = 0;
108 while (bitsLeft > 0) {
109 lastBit = (bitPosition + bitsLeft > 8) ?
110 (8) : (bitPosition + bitsLeft);
111 mask = (((1 << lastBit) - 1) ^ ((1 << bitPosition) - 1)) <<
112 (column * 8);
113 reg32 |= (((rfBuf[arrayEntry] & mask) >> (column * 8)) >>
114 bitPosition) << bitsShifted;
115 bitsShifted += lastBit - bitPosition;
116 bitsLeft -= (8 - bitPosition);
117 bitPosition = 0;
118 arrayEntry++;
119 }
120 reg32 = ath_hal_reverseBits(reg32, numBits);
121 return reg32;
122}
123
124static HAL_BOOL
126{
127 uint32_t gStep, g, mixOvr;
128 uint32_t L1, L2, L3, L4;
129
130 if (IS_RAD5112_ANY(ah)) {
131 mixOvr = ar5212GetRfField(ar5212GetRfBank(ah, 7), 1, 36, 0);
132 L1 = 0;
133 L2 = 107;
134 L3 = 0;
135 L4 = 107;
136 if (mixOvr == 1) {
137 L2 = 83;
138 L4 = 83;
139 gv->hiTrig = 55;
140 }
141 } else {
142 gStep = ar5212GetRfField(ar5212GetRfBank(ah, 7), 6, 37, 0);
143
144 L1 = 0;
145 L2 = (gStep == 0x3f) ? 50 : gStep + 4;
146 L3 = (gStep != 0x3f) ? 0x40 : L1;
147 L4 = L3 + 50;
148
149 gv->loTrig = L1 + (gStep == 0x3f ? DYN_ADJ_LO_MARGIN : 0);
150 /* never adjust if != 0x3f */
151 gv->hiTrig = L4 - (gStep == 0x3f ? DYN_ADJ_UP_MARGIN : -5);
152 }
153 g = gv->currGain;
154
155 return !((g >= L1 && g<= L2) || (g >= L3 && g <= L4));
156}
157
158/*
159 * Enable the probe gain check on the next packet
160 */
161void
163{
164 struct ath_hal_5212 *ahp = AH5212(ah);
165 uint32_t probePowerIndex;
166
167 /* Enable the gain readback probe */
168 probePowerIndex = ahp->ah_ofdmTxPower + ahp->ah_txPowerIndexOffset;
170 SM(probePowerIndex, AR_PHY_PAPD_PROBE_POWERTX)
172
174}
175
176/*
177 * Check to see if our readback gain level sits within the linear
178 * region of our current variable attenuation window
179 */
180static HAL_BOOL
182{
183 return (gv->currGain <= gv->loTrig || gv->currGain >= gv->hiTrig);
184}
185
186/*
187 * Move the rabbit ears in the correct direction.
188 */
189static int32_t
191{
192 const GAIN_OPTIMIZATION_LADDER *gl;
193
194 if (IS_RAD5112_ANY(ah))
195 gl = &gainLadder5112;
196 else
197 gl = &gainLadder;
198 gv->currStep = &gl->optStep[gv->currStepNum];
199 if (gv->currGain >= gv->hiTrig) {
200 if (gv->currStepNum == 0) {
201 HALDEBUG(ah, HAL_DEBUG_ANY, "%s: Max gain limit.\n",
202 __func__);
203 return -1;
204 }
206 "%s: Adding gain: currG=%d [%s] --> ",
207 __func__, gv->currGain, gv->currStep->stepName);
208 gv->targetGain = gv->currGain;
209 while (gv->targetGain >= gv->hiTrig && gv->currStepNum > 0) {
210 gv->targetGain -= 2 * (gl->optStep[--(gv->currStepNum)].stepGain -
211 gv->currStep->stepGain);
212 gv->currStep = &gl->optStep[gv->currStepNum];
213 }
214 HALDEBUG(ah, HAL_DEBUG_RFPARAM, "targG=%d [%s]\n",
215 gv->targetGain, gv->currStep->stepName);
216 return 1;
217 }
218 if (gv->currGain <= gv->loTrig) {
219 if (gv->currStepNum == gl->numStepsInLadder-1) {
221 "%s: Min gain limit.\n", __func__);
222 return -2;
223 }
225 "%s: Deducting gain: currG=%d [%s] --> ",
226 __func__, gv->currGain, gv->currStep->stepName);
227 gv->targetGain = gv->currGain;
228 while (gv->targetGain <= gv->loTrig &&
229 gv->currStepNum < (gl->numStepsInLadder - 1)) {
230 gv->targetGain -= 2 *
231 (gl->optStep[++(gv->currStepNum)].stepGain - gv->currStep->stepGain);
232 gv->currStep = &gl->optStep[gv->currStepNum];
233 }
234 HALDEBUG(ah, HAL_DEBUG_RFPARAM, "targG=%d [%s]\n",
235 gv->targetGain, gv->currStep->stepName);
236 return 2;
237 }
238 return 0; /* caller didn't call needAdjGain first */
239}
240
241/*
242 * Read rf register to determine if gainF needs correction
243 */
244static uint32_t
246{
247 struct ath_hal_5212 *ahp = AH5212(ah);
248 uint32_t correction;
249
251
252 correction = 0;
253 if (ar5212GetRfField(ar5212GetRfBank(ah, 7), 1, 36, 0) == 1) {
254 const GAIN_VALUES *gv = &ahp->ah_gainValues;
255 uint32_t mixGain = gv->currStep->paramVal[0];
256 uint32_t gainStep =
257 ar5212GetRfField(ar5212GetRfBank(ah, 7), 4, 32, 0);
258 switch (mixGain) {
259 case 0 :
260 correction = 0;
261 break;
262 case 1 :
263 correction = gainStep;
264 break;
265 case 2 :
266 correction = 2 * gainStep - 5;
267 break;
268 case 3 :
269 correction = 2 * gainStep;
270 break;
271 }
272 }
273 return correction;
274}
275
276/*
277 * Exported call to check for a recent gain reading and return
278 * the current state of the thermal calibration gain engine.
279 */
282{
283 struct ath_hal_5212 *ahp = AH5212(ah);
284 GAIN_VALUES *gv = &ahp->ah_gainValues;
285 uint32_t rddata, probeType;
286
287 /* NB: beware of touching the BB when PHY is powered down */
288 if (!gv->active || !ahp->ah_phyPowerOn)
289 return HAL_RFGAIN_INACTIVE;
290
292 /* Caller had asked to setup a new reading. Check it. */
293 rddata = OS_REG_READ(ah, AR_PHY_PAPD_PROBE);
294
295 if ((rddata & AR_PHY_PAPD_PROBE_NEXT_TX) == 0) {
296 /* bit got cleared, we have a new reading. */
297 gv->currGain = rddata >> AR_PHY_PAPD_PROBE_GAINF_S;
298 probeType = MS(rddata, AR_PHY_PAPD_PROBE_TYPE);
299 if (probeType == AR_PHY_PAPD_PROBE_TYPE_CCK) {
300 const HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom;
301
304 if (AH_PRIVATE(ah)->ah_phyRev >= AR_PHY_CHIP_ID_REV_2)
305 gv->currGain += ee->ee_cckOfdmGainDelta;
306 else
308 }
309 if (IS_RADX112_REV2(ah)) {
310 uint32_t correct = ar5212GetGainFCorrection(ah);
311 if (gv->currGain >= correct)
312 gv->currGain -= correct;
313 else
314 gv->currGain = 0;
315 }
316 /* inactive by default */
318
319 if (!ar5212InvalidGainReadback(ah, gv) &&
320 ar5212IsGainAdjustNeeded(ah, gv) &&
321 ar5212AdjustGain(ah, gv) > 0) {
322 /*
323 * Change needed. Copy ladder info
324 * into eeprom info.
325 */
327 /* for ap51 */
329 /* Request IQ recalibration for temperature chang */
331 }
332 }
333 }
334 return ahp->ah_rfgainState;
335}
uint32_t ath_hal_reverseBits(uint32_t val, uint32_t n)
Definition: ah.c:333
HAL_RFGAIN
Definition: ah.h:622
@ HAL_RFGAIN_INACTIVE
Definition: ah.h:623
@ HAL_RFGAIN_NEED_CHANGE
Definition: ah.h:625
@ HAL_RFGAIN_READ_REQUESTED
Definition: ah.h:624
HAL_BOOL
Definition: ah.h:93
@ AH_TRUE
Definition: ah.h:95
@ HAL_DEBUG_ANY
Definition: ah_debug.h:62
@ HAL_DEBUG_RFPARAM
Definition: ah_debug.h:37
#define SM(_v, _f)
Definition: ah_internal.h:587
#define MS(_v, _f)
Definition: ah_internal.h:588
#define AH_PRIVATE(_ah)
Definition: ah_internal.h:442
#define HALASSERT(_x)
Definition: ah_internal.h:683
#define HALDEBUG(_ah, __m,...)
Definition: ah_internal.h:658
#define OS_REG_WRITE(_ah, _reg, _val)
Definition: ah_osdep.h:139
#define OS_REG_READ(_ah, _reg)
Definition: ah_osdep.h:140
#define DYN_ADJ_UP_MARGIN
#define DYN_ADJ_LO_MARGIN
#define AR_PHY_PAPD_PROBE_POWERTX
Definition: ar5211phy.h:65
#define AR_PHY_PAPD_PROBE_GAINF_S
Definition: ar5211phy.h:69
#define AR_PHY_PAPD_PROBE
Definition: ar5211phy.h:64
#define AR_PHY_PAPD_PROBE_NEXT_TX
Definition: ar5211phy.h:67
#define PHY_PROBE_CCK_CORRECTION
Definition: ar5212.h:89
#define ar5212GetRfBank(ah, b)
Definition: ar5212.h:409
#define IS_RADX112_REV2(ah)
Definition: ar5212.h:399
#define IS_RAD5112_ANY(ah)
Definition: ar5212.h:393
#define AH5212(_ah)
Definition: ar5212.h:354
#define AR5212_MAGIC
Definition: ar5212.h:26
static int32_t ar5212AdjustGain(struct ath_hal *ah, GAIN_VALUES *gv)
HAL_RFGAIN ar5212GetRfgain(struct ath_hal *ah)
void ar5212InitializeGainValues(struct ath_hal *ah)
Definition: ar5212_rfgain.c:66
static HAL_BOOL ar5212InvalidGainReadback(struct ath_hal *ah, GAIN_VALUES *gv)
static uint32_t ar5212GetRfField(uint32_t *rfBuf, uint32_t numBits, uint32_t firstBit, uint32_t column)
Definition: ar5212_rfgain.c:94
static HAL_BOOL ar5212IsGainAdjustNeeded(struct ath_hal *ah, const GAIN_VALUES *gv)
static const GAIN_OPTIMIZATION_LADDER gainLadder5112
Definition: ar5212_rfgain.c:48
void ar5212RequestRfgain(struct ath_hal *ah)
static const GAIN_OPTIMIZATION_LADDER gainLadder
Definition: ar5212_rfgain.c:33
static uint32_t ar5212GetGainFCorrection(struct ath_hal *ah)
#define MAX_ANALOG_START
Definition: ar5212_rfgain.c:88
#define AR_PHY_PAPD_PROBE_TYPE_CCK
Definition: ar5212phy.h:187
#define AR_PHY_CHIP_ID_REV_2
Definition: ar5212phy.h:50
#define AR_PHY_PAPD_PROBE_TYPE
Definition: ar5212phy.h:184
uint32_t defaultStepNum
Definition: ar5211.h:81
GAIN_OPTIMIZATION_STEP optStep[10]
Definition: ar5211.h:82
uint32_t numStepsInLadder
Definition: ar5211.h:80
uint32_t active
Definition: ar5211.h:91
uint32_t targetGain
Definition: ar5211.h:88
uint32_t loTrig
Definition: ar5211.h:89
uint32_t hiTrig
Definition: ar5211.h:90
uint32_t currGain
Definition: ar5211.h:87
const GAIN_OPTIMIZATION_STEP * currStep
Definition: ar5211.h:92
uint32_t currStepNum
Definition: ar5211.h:86
uint16_t ee_cckOfdmGainDelta
Definition: ah_eeprom_v3.h:364
int8_t stepName[16]
Definition: ar5211.h:76
int16_t paramVal[4]
Definition: ar5211.h:74
int32_t stepGain
Definition: ar5211.h:75
GAIN_VALUES ah_gainValues
Definition: ar5212.h:254
HAL_BOOL ah_cwCalRequire
Definition: ar5212.h:289
int16_t ah_txPowerIndexOffset
Definition: ar5212.h:301
@ IQ_CAL_INACTIVE
Definition: ar5212.h:280
enum ath_hal_5212::@22 ah_bIQCalibration
HAL_BOOL ah_phyPowerOn
Definition: ar5212.h:291
HAL_RFGAIN ah_rfgainState
Definition: ar5212.h:284
uint32_t ah_ofdmTxPower
Definition: ar5212.h:300
Definition: ah.h:1219
uint32_t ah_magic
Definition: ah.h:1220