]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/ath/ath_hal/ar5212/ar5212_rfgain.c
Add LLVM openmp trunk r351319 (just before the release_80 branch point)
[FreeBSD/FreeBSD.git] / sys / dev / ath / ath_hal / ar5212 / ar5212_rfgain.c
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
33 static const GAIN_OPTIMIZATION_LADDER gainLadder = {
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
48 static const GAIN_OPTIMIZATION_LADDER gainLadder5112 = {
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  */
65 void
66 ar5212InitializeGainValues(struct ath_hal *ah)
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)) {
73                 gv->currStepNum = gainLadder5112.defaultStepNum;
74                 gv->currStep =
75                         &gainLadder5112.optStep[gainLadder5112.defaultStepNum];
76                 gv->active = AH_TRUE;
77                 gv->loTrig = 20;
78                 gv->hiTrig = 85;
79         } else {
80                 gv->currStepNum = gainLadder.defaultStepNum;
81                 gv->currStep = &gainLadder.optStep[gainLadder.defaultStepNum];
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  */
93 static uint32_t
94 ar5212GetRfField(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
124 static HAL_BOOL
125 ar5212InvalidGainReadback(struct ath_hal *ah, GAIN_VALUES *gv)
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  */
161 void
162 ar5212RequestRfgain(struct ath_hal *ah)
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;
169         OS_REG_WRITE(ah, AR_PHY_PAPD_PROBE,
170                   SM(probePowerIndex, AR_PHY_PAPD_PROBE_POWERTX)
171                 | AR_PHY_PAPD_PROBE_NEXT_TX);
172
173         ahp->ah_rfgainState = HAL_RFGAIN_READ_REQUESTED;
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  */
180 static HAL_BOOL
181 ar5212IsGainAdjustNeeded(struct ath_hal *ah, const GAIN_VALUES *gv)
182 {
183         return (gv->currGain <= gv->loTrig || gv->currGain >= gv->hiTrig);
184 }
185
186 /*
187  * Move the rabbit ears in the correct direction.
188  */
189 static int32_t 
190 ar5212AdjustGain(struct ath_hal *ah, GAIN_VALUES *gv)
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                 }
205                 HALDEBUG(ah, HAL_DEBUG_RFPARAM,
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) {
220                         HALDEBUG(ah, HAL_DEBUG_RFPARAM,
221                             "%s: Min gain limit.\n", __func__);
222                         return -2;
223                 }
224                 HALDEBUG(ah, HAL_DEBUG_RFPARAM,
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  */
244 static uint32_t
245 ar5212GetGainFCorrection(struct ath_hal *ah)
246 {
247         struct ath_hal_5212 *ahp = AH5212(ah);
248         uint32_t correction;
249
250         HALASSERT(IS_RADX112_REV2(ah));
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  */
280 HAL_RFGAIN
281 ar5212GetRfgain(struct ath_hal *ah)
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
291         if (ahp->ah_rfgainState == HAL_RFGAIN_READ_REQUESTED) {
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
302                                 HALASSERT(IS_RAD5112_ANY(ah));
303                                 HALASSERT(ah->ah_magic == AR5212_MAGIC);
304                                 if (AH_PRIVATE(ah)->ah_phyRev >= AR_PHY_CHIP_ID_REV_2)
305                                         gv->currGain += ee->ee_cckOfdmGainDelta;
306                                 else
307                                         gv->currGain += PHY_PROBE_CCK_CORRECTION;
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 */
317                         ahp->ah_rfgainState = HAL_RFGAIN_INACTIVE;
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                                  */
326                                 ahp->ah_rfgainState = HAL_RFGAIN_NEED_CHANGE;
327                                 /* for ap51 */
328                                 ahp->ah_cwCalRequire = AH_TRUE;
329                                 /* Request IQ recalibration for temperature chang */
330                                 ahp->ah_bIQCalibration = IQ_CAL_INACTIVE;
331                         }
332                 }
333         }
334         return ahp->ah_rfgainState;
335 }