]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - sys/dev/ath/ath_hal/ar5212/ar2316.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.git] / sys / dev / ath / ath_hal / ar5212 / ar2316.c
1 /*
2  * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
3  * Copyright (c) 2002-2008 Atheros Communications, Inc.
4  *
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.
8  *
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.
16  *
17  * $Id: ar2316.c,v 1.9 2008/11/15 22:15:46 sam Exp $
18  */
19 #include "opt_ah.h"
20
21 #include "ah.h"
22 #include "ah_internal.h"
23
24 #include "ar5212/ar5212.h"
25 #include "ar5212/ar5212reg.h"
26 #include "ar5212/ar5212phy.h"
27
28 #include "ah_eeprom_v3.h"
29
30 #define AH_5212_2316
31 #include "ar5212/ar5212.ini"
32
33 #define N(a)    (sizeof(a)/sizeof(a[0]))
34
35 typedef RAW_DATA_STRUCT_2413 RAW_DATA_STRUCT_2316;
36 typedef RAW_DATA_PER_CHANNEL_2413 RAW_DATA_PER_CHANNEL_2316;
37 #define PWR_TABLE_SIZE_2316 PWR_TABLE_SIZE_2413
38
39 struct ar2316State {
40         RF_HAL_FUNCS    base;           /* public state, must be first */
41         uint16_t        pcdacTable[PWR_TABLE_SIZE_2316];
42
43         uint32_t        Bank1Data[N(ar5212Bank1_2316)];
44         uint32_t        Bank2Data[N(ar5212Bank2_2316)];
45         uint32_t        Bank3Data[N(ar5212Bank3_2316)];
46         uint32_t        Bank6Data[N(ar5212Bank6_2316)];
47         uint32_t        Bank7Data[N(ar5212Bank7_2316)];
48
49         /*
50          * Private state for reduced stack usage.
51          */
52         /* filled out Vpd table for all pdGains (chanL) */
53         uint16_t vpdTable_L[MAX_NUM_PDGAINS_PER_CHANNEL]
54                             [MAX_PWR_RANGE_IN_HALF_DB];
55         /* filled out Vpd table for all pdGains (chanR) */
56         uint16_t vpdTable_R[MAX_NUM_PDGAINS_PER_CHANNEL]
57                             [MAX_PWR_RANGE_IN_HALF_DB];
58         /* filled out Vpd table for all pdGains (interpolated) */
59         uint16_t vpdTable_I[MAX_NUM_PDGAINS_PER_CHANNEL]
60                             [MAX_PWR_RANGE_IN_HALF_DB];
61 };
62 #define AR2316(ah)      ((struct ar2316State *) AH5212(ah)->ah_rfHal)
63
64 extern  void ar5212ModifyRfBuffer(uint32_t *rfBuf, uint32_t reg32,
65                 uint32_t numBits, uint32_t firstBit, uint32_t column);
66
67 static void
68 ar2316WriteRegs(struct ath_hal *ah, u_int modesIndex, u_int freqIndex,
69         int regWrites)
70 {
71         struct ath_hal_5212 *ahp = AH5212(ah);
72
73         HAL_INI_WRITE_ARRAY(ah, ar5212Modes_2316, modesIndex, regWrites);
74         HAL_INI_WRITE_ARRAY(ah, ar5212Common_2316, 1, regWrites);
75         HAL_INI_WRITE_ARRAY(ah, ar5212BB_RfGain_2316, freqIndex, regWrites);
76
77         /* For AP51 */
78         if (!ahp->ah_cwCalRequire) {
79                 OS_REG_WRITE(ah, 0xa358, (OS_REG_READ(ah, 0xa358) & ~0x2));
80         } else {
81                 ahp->ah_cwCalRequire = AH_FALSE;
82         }
83 }
84
85 /*
86  * Take the MHz channel value and set the Channel value
87  *
88  * ASSUMES: Writes enabled to analog bus
89  */
90 static HAL_BOOL
91 ar2316SetChannel(struct ath_hal *ah,  HAL_CHANNEL_INTERNAL *chan)
92 {
93         uint32_t channelSel  = 0;
94         uint32_t bModeSynth  = 0;
95         uint32_t aModeRefSel = 0;
96         uint32_t reg32       = 0;
97
98         OS_MARK(ah, AH_MARK_SETCHANNEL, chan->channel);
99
100         if (chan->channel < 4800) {
101                 uint32_t txctl;
102
103                 if (((chan->channel - 2192) % 5) == 0) {
104                         channelSel = ((chan->channel - 672) * 2 - 3040)/10;
105                         bModeSynth = 0;
106                 } else if (((chan->channel - 2224) % 5) == 0) {
107                         channelSel = ((chan->channel - 704) * 2 - 3040) / 10;
108                         bModeSynth = 1;
109                 } else {
110                         HALDEBUG(ah, HAL_DEBUG_ANY,
111                             "%s: invalid channel %u MHz\n",
112                             __func__, chan->channel);
113                         return AH_FALSE;
114                 }
115
116                 channelSel = (channelSel << 2) & 0xff;
117                 channelSel = ath_hal_reverseBits(channelSel, 8);
118
119                 txctl = OS_REG_READ(ah, AR_PHY_CCK_TX_CTRL);
120                 if (chan->channel == 2484) {
121                         /* Enable channel spreading for channel 14 */
122                         OS_REG_WRITE(ah, AR_PHY_CCK_TX_CTRL,
123                                 txctl | AR_PHY_CCK_TX_CTRL_JAPAN);
124                 } else {
125                         OS_REG_WRITE(ah, AR_PHY_CCK_TX_CTRL,
126                                 txctl &~ AR_PHY_CCK_TX_CTRL_JAPAN);
127                 }
128         } else if ((chan->channel % 20) == 0 && chan->channel >= 5120) {
129                 channelSel = ath_hal_reverseBits(
130                         ((chan->channel - 4800) / 20 << 2), 8);
131                 aModeRefSel = ath_hal_reverseBits(3, 2);
132         } else if ((chan->channel % 10) == 0) {
133                 channelSel = ath_hal_reverseBits(
134                         ((chan->channel - 4800) / 10 << 1), 8);
135                 aModeRefSel = ath_hal_reverseBits(2, 2);
136         } else if ((chan->channel % 5) == 0) {
137                 channelSel = ath_hal_reverseBits(
138                         (chan->channel - 4800) / 5, 8);
139                 aModeRefSel = ath_hal_reverseBits(1, 2);
140         } else {
141                 HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel %u MHz\n",
142                     __func__, chan->channel);
143                 return AH_FALSE;
144         }
145
146         reg32 = (channelSel << 4) | (aModeRefSel << 2) | (bModeSynth << 1) |
147                         (1 << 12) | 0x1;
148         OS_REG_WRITE(ah, AR_PHY(0x27), reg32 & 0xff);
149
150         reg32 >>= 8;
151         OS_REG_WRITE(ah, AR_PHY(0x36), reg32 & 0x7f);
152
153         AH_PRIVATE(ah)->ah_curchan = chan;
154         return AH_TRUE;
155 }
156
157 /*
158  * Reads EEPROM header info from device structure and programs
159  * all rf registers
160  *
161  * REQUIRES: Access to the analog rf device
162  */
163 static HAL_BOOL
164 ar2316SetRfRegs(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan, uint16_t modesIndex, uint16_t *rfXpdGain)
165 {
166 #define RF_BANK_SETUP(_priv, _ix, _col) do {                                \
167         int i;                                                              \
168         for (i = 0; i < N(ar5212Bank##_ix##_2316); i++)                     \
169                 (_priv)->Bank##_ix##Data[i] = ar5212Bank##_ix##_2316[i][_col];\
170 } while (0)
171         struct ath_hal_5212 *ahp = AH5212(ah);
172         const HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom;
173         uint16_t ob2GHz = 0, db2GHz = 0;
174         struct ar2316State *priv = AR2316(ah);
175         int regWrites = 0;
176
177         HALDEBUG(ah, HAL_DEBUG_RFPARAM,
178             "%s: chan 0x%x flag 0x%x modesIndex 0x%x\n",
179             __func__, chan->channel, chan->channelFlags, modesIndex);
180
181         HALASSERT(priv != AH_NULL);
182
183         /* Setup rf parameters */
184         switch (chan->channelFlags & CHANNEL_ALL) {
185         case CHANNEL_B:
186                 ob2GHz = ee->ee_obFor24;
187                 db2GHz = ee->ee_dbFor24;
188                 break;
189         case CHANNEL_G:
190         case CHANNEL_108G:
191                 ob2GHz = ee->ee_obFor24g;
192                 db2GHz = ee->ee_dbFor24g;
193                 break;
194         default:
195                 HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel flags 0x%x\n",
196                     __func__, chan->channelFlags);
197                 return AH_FALSE;
198         }
199
200         /* Bank 1 Write */
201         RF_BANK_SETUP(priv, 1, 1);
202
203         /* Bank 2 Write */
204         RF_BANK_SETUP(priv, 2, modesIndex);
205
206         /* Bank 3 Write */
207         RF_BANK_SETUP(priv, 3, modesIndex);
208
209         /* Bank 6 Write */
210         RF_BANK_SETUP(priv, 6, modesIndex);
211
212         ar5212ModifyRfBuffer(priv->Bank6Data, ob2GHz,   3, 178, 0);
213         ar5212ModifyRfBuffer(priv->Bank6Data, db2GHz,   3, 175, 0);
214
215         /* Bank 7 Setup */
216         RF_BANK_SETUP(priv, 7, modesIndex);
217
218         /* Write Analog registers */
219         HAL_INI_WRITE_BANK(ah, ar5212Bank1_2316, priv->Bank1Data, regWrites);
220         HAL_INI_WRITE_BANK(ah, ar5212Bank2_2316, priv->Bank2Data, regWrites);
221         HAL_INI_WRITE_BANK(ah, ar5212Bank3_2316, priv->Bank3Data, regWrites);
222         HAL_INI_WRITE_BANK(ah, ar5212Bank6_2316, priv->Bank6Data, regWrites);
223         HAL_INI_WRITE_BANK(ah, ar5212Bank7_2316, priv->Bank7Data, regWrites);
224
225         /* Now that we have reprogrammed rfgain value, clear the flag. */
226         ahp->ah_rfgainState = HAL_RFGAIN_INACTIVE;
227
228         return AH_TRUE;
229 #undef  RF_BANK_SETUP
230 }
231
232 /*
233  * Return a reference to the requested RF Bank.
234  */
235 static uint32_t *
236 ar2316GetRfBank(struct ath_hal *ah, int bank)
237 {
238         struct ar2316State *priv = AR2316(ah);
239
240         HALASSERT(priv != AH_NULL);
241         switch (bank) {
242         case 1: return priv->Bank1Data;
243         case 2: return priv->Bank2Data;
244         case 3: return priv->Bank3Data;
245         case 6: return priv->Bank6Data;
246         case 7: return priv->Bank7Data;
247         }
248         HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unknown RF Bank %d requested\n",
249             __func__, bank);
250         return AH_NULL;
251 }
252
253 /*
254  * Return indices surrounding the value in sorted integer lists.
255  *
256  * NB: the input list is assumed to be sorted in ascending order
257  */
258 static void
259 GetLowerUpperIndex(int16_t v, const uint16_t *lp, uint16_t listSize,
260                           uint32_t *vlo, uint32_t *vhi)
261 {
262         int16_t target = v;
263         const int16_t *ep = lp+listSize;
264         const int16_t *tp;
265
266         /*
267          * Check first and last elements for out-of-bounds conditions.
268          */
269         if (target < lp[0]) {
270                 *vlo = *vhi = 0;
271                 return;
272         }
273         if (target >= ep[-1]) {
274                 *vlo = *vhi = listSize - 1;
275                 return;
276         }
277
278         /* look for value being near or between 2 values in list */
279         for (tp = lp; tp < ep; tp++) {
280                 /*
281                  * If value is close to the current value of the list
282                  * then target is not between values, it is one of the values
283                  */
284                 if (*tp == target) {
285                         *vlo = *vhi = tp - (const int16_t *) lp;
286                         return;
287                 }
288                 /*
289                  * Look for value being between current value and next value
290                  * if so return these 2 values
291                  */
292                 if (target < tp[1]) {
293                         *vlo = tp - (const int16_t *) lp;
294                         *vhi = *vlo + 1;
295                         return;
296                 }
297         }
298 }
299
300 /*
301  * Fill the Vpdlist for indices Pmax-Pmin
302  */
303 static HAL_BOOL
304 ar2316FillVpdTable(uint32_t pdGainIdx, int16_t Pmin, int16_t  Pmax,
305                    const int16_t *pwrList, const int16_t *VpdList,
306                    uint16_t numIntercepts, uint16_t retVpdList[][64])
307 {
308         uint16_t ii, jj, kk;
309         int16_t currPwr = (int16_t)(2*Pmin);
310         /* since Pmin is pwr*2 and pwrList is 4*pwr */
311         uint32_t  idxL, idxR;
312
313         ii = 0;
314         jj = 0;
315
316         if (numIntercepts < 2)
317                 return AH_FALSE;
318
319         while (ii <= (uint16_t)(Pmax - Pmin)) {
320                 GetLowerUpperIndex(currPwr, pwrList, numIntercepts, 
321                                          &(idxL), &(idxR));
322                 if (idxR < 1)
323                         idxR = 1;                       /* extrapolate below */
324                 if (idxL == (uint32_t)(numIntercepts - 1))
325                         idxL = numIntercepts - 2;       /* extrapolate above */
326                 if (pwrList[idxL] == pwrList[idxR])
327                         kk = VpdList[idxL];
328                 else
329                         kk = (uint16_t)
330                                 (((currPwr - pwrList[idxL])*VpdList[idxR]+ 
331                                   (pwrList[idxR] - currPwr)*VpdList[idxL])/
332                                  (pwrList[idxR] - pwrList[idxL]));
333                 retVpdList[pdGainIdx][ii] = kk;
334                 ii++;
335                 currPwr += 2;                           /* half dB steps */
336         }
337
338         return AH_TRUE;
339 }
340
341 /*
342  * Returns interpolated or the scaled up interpolated value
343  */
344 static int16_t
345 interpolate_signed(uint16_t target, uint16_t srcLeft, uint16_t srcRight,
346         int16_t targetLeft, int16_t targetRight)
347 {
348         int16_t rv;
349
350         if (srcRight != srcLeft) {
351                 rv = ((target - srcLeft)*targetRight +
352                       (srcRight - target)*targetLeft) / (srcRight - srcLeft);
353         } else {
354                 rv = targetLeft;
355         }
356         return rv;
357 }
358
359 /*
360  * Uses the data points read from EEPROM to reconstruct the pdadc power table
361  * Called by ar2316SetPowerTable()
362  */
363 static int 
364 ar2316getGainBoundariesAndPdadcsForPowers(struct ath_hal *ah, uint16_t channel,
365                 const RAW_DATA_STRUCT_2316 *pRawDataset,
366                 uint16_t pdGainOverlap_t2, 
367                 int16_t  *pMinCalPower, uint16_t pPdGainBoundaries[], 
368                 uint16_t pPdGainValues[], uint16_t pPDADCValues[]) 
369 {
370         struct ar2316State *priv = AR2316(ah);
371 #define VpdTable_L      priv->vpdTable_L
372 #define VpdTable_R      priv->vpdTable_R
373 #define VpdTable_I      priv->vpdTable_I
374         uint32_t ii, jj, kk;
375         int32_t ss;/* potentially -ve index for taking care of pdGainOverlap */
376         uint32_t idxL, idxR;
377         uint32_t numPdGainsUsed = 0;
378         /* 
379          * If desired to support -ve power levels in future, just
380          * change pwr_I_0 to signed 5-bits.
381          */
382         int16_t Pmin_t2[MAX_NUM_PDGAINS_PER_CHANNEL];
383         /* to accomodate -ve power levels later on. */
384         int16_t Pmax_t2[MAX_NUM_PDGAINS_PER_CHANNEL];
385         /* to accomodate -ve power levels later on */
386         uint16_t numVpd = 0;
387         uint16_t Vpd_step;
388         int16_t tmpVal ; 
389         uint32_t sizeCurrVpdTable, maxIndex, tgtIndex;
390
391         /* Get upper lower index */
392         GetLowerUpperIndex(channel, pRawDataset->pChannels,
393                                  pRawDataset->numChannels, &(idxL), &(idxR));
394
395         for (ii = 0; ii < MAX_NUM_PDGAINS_PER_CHANNEL; ii++) {
396                 jj = MAX_NUM_PDGAINS_PER_CHANNEL - ii - 1;
397                 /* work backwards 'cause highest pdGain for lowest power */
398                 numVpd = pRawDataset->pDataPerChannel[idxL].pDataPerPDGain[jj].numVpd;
399                 if (numVpd > 0) {
400                         pPdGainValues[numPdGainsUsed] = pRawDataset->pDataPerChannel[idxL].pDataPerPDGain[jj].pd_gain;
401                         Pmin_t2[numPdGainsUsed] = pRawDataset->pDataPerChannel[idxL].pDataPerPDGain[jj].pwr_t4[0];
402                         if (Pmin_t2[numPdGainsUsed] >pRawDataset->pDataPerChannel[idxR].pDataPerPDGain[jj].pwr_t4[0]) {
403                                 Pmin_t2[numPdGainsUsed] = pRawDataset->pDataPerChannel[idxR].pDataPerPDGain[jj].pwr_t4[0];
404                         }
405                         Pmin_t2[numPdGainsUsed] = (int16_t)
406                                 (Pmin_t2[numPdGainsUsed] / 2);
407                         Pmax_t2[numPdGainsUsed] = pRawDataset->pDataPerChannel[idxL].pDataPerPDGain[jj].pwr_t4[numVpd-1];
408                         if (Pmax_t2[numPdGainsUsed] > pRawDataset->pDataPerChannel[idxR].pDataPerPDGain[jj].pwr_t4[numVpd-1])
409                                 Pmax_t2[numPdGainsUsed] = 
410                                         pRawDataset->pDataPerChannel[idxR].pDataPerPDGain[jj].pwr_t4[numVpd-1];
411                         Pmax_t2[numPdGainsUsed] = (int16_t)(Pmax_t2[numPdGainsUsed] / 2);
412                         ar2316FillVpdTable(
413                                            numPdGainsUsed, Pmin_t2[numPdGainsUsed], Pmax_t2[numPdGainsUsed], 
414                                            &(pRawDataset->pDataPerChannel[idxL].pDataPerPDGain[jj].pwr_t4[0]), 
415                                            &(pRawDataset->pDataPerChannel[idxL].pDataPerPDGain[jj].Vpd[0]), numVpd, VpdTable_L
416                                            );
417                         ar2316FillVpdTable(
418                                            numPdGainsUsed, Pmin_t2[numPdGainsUsed], Pmax_t2[numPdGainsUsed], 
419                                            &(pRawDataset->pDataPerChannel[idxR].pDataPerPDGain[jj].pwr_t4[0]),
420                                            &(pRawDataset->pDataPerChannel[idxR].pDataPerPDGain[jj].Vpd[0]), numVpd, VpdTable_R
421                                            );
422                         for (kk = 0; kk < (uint16_t)(Pmax_t2[numPdGainsUsed] - Pmin_t2[numPdGainsUsed]); kk++) {
423                                 VpdTable_I[numPdGainsUsed][kk] = 
424                                         interpolate_signed(
425                                                            channel, pRawDataset->pChannels[idxL], pRawDataset->pChannels[idxR],
426                                                            (int16_t)VpdTable_L[numPdGainsUsed][kk], (int16_t)VpdTable_R[numPdGainsUsed][kk]);
427                         }
428                         /* fill VpdTable_I for this pdGain */
429                         numPdGainsUsed++;
430                 }
431                 /* if this pdGain is used */
432         }
433
434         *pMinCalPower = Pmin_t2[0];
435         kk = 0; /* index for the final table */
436         for (ii = 0; ii < numPdGainsUsed; ii++) {
437                 if (ii == (numPdGainsUsed - 1))
438                         pPdGainBoundaries[ii] = Pmax_t2[ii] +
439                                 PD_GAIN_BOUNDARY_STRETCH_IN_HALF_DB;
440                 else 
441                         pPdGainBoundaries[ii] = (uint16_t)
442                                 ((Pmax_t2[ii] + Pmin_t2[ii+1]) / 2 );
443                 if (pPdGainBoundaries[ii] > 63) {
444                         HALDEBUG(ah, HAL_DEBUG_ANY,
445                             "%s: clamp pPdGainBoundaries[%d] %d\n",
446                             __func__, ii, pPdGainBoundaries[ii]);/*XXX*/
447                         pPdGainBoundaries[ii] = 63;
448                 }
449
450                 /* Find starting index for this pdGain */
451                 if (ii == 0) 
452                         ss = 0; /* for the first pdGain, start from index 0 */
453                 else 
454                         ss = (pPdGainBoundaries[ii-1] - Pmin_t2[ii]) - 
455                                 pdGainOverlap_t2;
456                 Vpd_step = (uint16_t)(VpdTable_I[ii][1] - VpdTable_I[ii][0]);
457                 Vpd_step = (uint16_t)((Vpd_step < 1) ? 1 : Vpd_step);
458                 /*
459                  *-ve ss indicates need to extrapolate data below for this pdGain
460                  */
461                 while (ss < 0) {
462                         tmpVal = (int16_t)(VpdTable_I[ii][0] + ss*Vpd_step);
463                         pPDADCValues[kk++] = (uint16_t)((tmpVal < 0) ? 0 : tmpVal);
464                         ss++;
465                 }
466
467                 sizeCurrVpdTable = Pmax_t2[ii] - Pmin_t2[ii];
468                 tgtIndex = pPdGainBoundaries[ii] + pdGainOverlap_t2 - Pmin_t2[ii];
469                 maxIndex = (tgtIndex < sizeCurrVpdTable) ? tgtIndex : sizeCurrVpdTable;
470
471                 while (ss < (int16_t)maxIndex)
472                         pPDADCValues[kk++] = VpdTable_I[ii][ss++];
473
474                 Vpd_step = (uint16_t)(VpdTable_I[ii][sizeCurrVpdTable-1] -
475                                        VpdTable_I[ii][sizeCurrVpdTable-2]);
476                 Vpd_step = (uint16_t)((Vpd_step < 1) ? 1 : Vpd_step);           
477                 /*
478                  * for last gain, pdGainBoundary == Pmax_t2, so will 
479                  * have to extrapolate
480                  */
481                 if (tgtIndex > maxIndex) {      /* need to extrapolate above */
482                         while(ss < (int16_t)tgtIndex) {
483                                 tmpVal = (uint16_t)
484                                         (VpdTable_I[ii][sizeCurrVpdTable-1] + 
485                                          (ss-maxIndex)*Vpd_step);
486                                 pPDADCValues[kk++] = (tmpVal > 127) ? 
487                                         127 : tmpVal;
488                                 ss++;
489                         }
490                 }                               /* extrapolated above */
491         }                                       /* for all pdGainUsed */
492
493         while (ii < MAX_NUM_PDGAINS_PER_CHANNEL) {
494                 pPdGainBoundaries[ii] = pPdGainBoundaries[ii-1];
495                 ii++;
496         }
497         while (kk < 128) {
498                 pPDADCValues[kk] = pPDADCValues[kk-1];
499                 kk++;
500         }
501
502         return numPdGainsUsed;
503 #undef VpdTable_L
504 #undef VpdTable_R
505 #undef VpdTable_I
506 }
507
508 static HAL_BOOL
509 ar2316SetPowerTable(struct ath_hal *ah,
510         int16_t *minPower, int16_t *maxPower, HAL_CHANNEL_INTERNAL *chan, 
511         uint16_t *rfXpdGain)
512 {
513         struct ath_hal_5212 *ahp = AH5212(ah);
514         const HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom;
515         const RAW_DATA_STRUCT_2316 *pRawDataset = AH_NULL;
516         uint16_t pdGainOverlap_t2;
517         int16_t minCalPower2316_t2;
518         uint16_t *pdadcValues = ahp->ah_pcdacTable;
519         uint16_t gainBoundaries[4];
520         uint32_t reg32, regoffset;
521         int i, numPdGainsUsed;
522 #ifndef AH_USE_INIPDGAIN
523         uint32_t tpcrg1;
524 #endif
525
526         HALDEBUG(ah, HAL_DEBUG_RFPARAM, "%s: chan 0x%x flag 0x%x\n",
527             __func__, chan->channel,chan->channelFlags);
528
529         if (IS_CHAN_G(chan) || IS_CHAN_108G(chan))
530                 pRawDataset = &ee->ee_rawDataset2413[headerInfo11G];
531         else if (IS_CHAN_B(chan))
532                 pRawDataset = &ee->ee_rawDataset2413[headerInfo11B];
533         else {
534                 HALDEBUG(ah, HAL_DEBUG_ANY, "%s: illegal mode\n", __func__);
535                 return AH_FALSE;
536         }
537
538         pdGainOverlap_t2 = (uint16_t) SM(OS_REG_READ(ah, AR_PHY_TPCRG5),
539                                           AR_PHY_TPCRG5_PD_GAIN_OVERLAP);
540     
541         numPdGainsUsed = ar2316getGainBoundariesAndPdadcsForPowers(ah,
542                 chan->channel, pRawDataset, pdGainOverlap_t2,
543                 &minCalPower2316_t2,gainBoundaries, rfXpdGain, pdadcValues);
544         HALASSERT(1 <= numPdGainsUsed && numPdGainsUsed <= 3);
545
546 #ifdef AH_USE_INIPDGAIN
547         /*
548          * Use pd_gains curve from eeprom; Atheros always uses
549          * the default curve from the ini file but some vendors
550          * (e.g. Zcomax) want to override this curve and not
551          * honoring their settings results in tx power 5dBm low.
552          */
553         OS_REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN, 
554                          (pRawDataset->pDataPerChannel[0].numPdGains - 1));
555 #else
556         tpcrg1 = OS_REG_READ(ah, AR_PHY_TPCRG1);
557         tpcrg1 = (tpcrg1 &~ AR_PHY_TPCRG1_NUM_PD_GAIN)
558                   | SM(numPdGainsUsed-1, AR_PHY_TPCRG1_NUM_PD_GAIN);
559         switch (numPdGainsUsed) {
560         case 3:
561                 tpcrg1 &= ~AR_PHY_TPCRG1_PDGAIN_SETTING3;
562                 tpcrg1 |= SM(rfXpdGain[2], AR_PHY_TPCRG1_PDGAIN_SETTING3);
563                 /* fall thru... */
564         case 2:
565                 tpcrg1 &= ~AR_PHY_TPCRG1_PDGAIN_SETTING2;
566                 tpcrg1 |= SM(rfXpdGain[1], AR_PHY_TPCRG1_PDGAIN_SETTING2);
567                 /* fall thru... */
568         case 1:
569                 tpcrg1 &= ~AR_PHY_TPCRG1_PDGAIN_SETTING1;
570                 tpcrg1 |= SM(rfXpdGain[0], AR_PHY_TPCRG1_PDGAIN_SETTING1);
571                 break;
572         }
573 #ifdef AH_DEBUG
574         if (tpcrg1 != OS_REG_READ(ah, AR_PHY_TPCRG1))
575                 HALDEBUG(ah, HAL_DEBUG_RFPARAM, "%s: using non-default "
576                     "pd_gains (default 0x%x, calculated 0x%x)\n",
577                     __func__, OS_REG_READ(ah, AR_PHY_TPCRG1), tpcrg1);
578 #endif
579         OS_REG_WRITE(ah, AR_PHY_TPCRG1, tpcrg1);
580 #endif
581
582         /*
583          * Note the pdadc table may not start at 0 dBm power, could be
584          * negative or greater than 0.  Need to offset the power
585          * values by the amount of minPower for griffin
586          */
587         if (minCalPower2316_t2 != 0)
588                 ahp->ah_txPowerIndexOffset = (int16_t)(0 - minCalPower2316_t2);
589         else
590                 ahp->ah_txPowerIndexOffset = 0;
591
592         /* Finally, write the power values into the baseband power table */
593         regoffset = 0x9800 + (672 <<2); /* beginning of pdadc table in griffin */
594         for (i = 0; i < 32; i++) {
595                 reg32 = ((pdadcValues[4*i + 0] & 0xFF) << 0)  | 
596                         ((pdadcValues[4*i + 1] & 0xFF) << 8)  |
597                         ((pdadcValues[4*i + 2] & 0xFF) << 16) |
598                         ((pdadcValues[4*i + 3] & 0xFF) << 24) ;        
599                 OS_REG_WRITE(ah, regoffset, reg32);
600                 regoffset += 4;
601         }
602
603         OS_REG_WRITE(ah, AR_PHY_TPCRG5, 
604                      SM(pdGainOverlap_t2, AR_PHY_TPCRG5_PD_GAIN_OVERLAP) | 
605                      SM(gainBoundaries[0], AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1) |
606                      SM(gainBoundaries[1], AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2) |
607                      SM(gainBoundaries[2], AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3) |
608                      SM(gainBoundaries[3], AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4));
609
610         return AH_TRUE;
611 }
612
613 static int16_t
614 ar2316GetMinPower(struct ath_hal *ah, const RAW_DATA_PER_CHANNEL_2316 *data)
615 {
616         uint32_t ii,jj;
617         uint16_t Pmin=0,numVpd;
618
619         for (ii = 0; ii < MAX_NUM_PDGAINS_PER_CHANNEL; ii++) {
620                 jj = MAX_NUM_PDGAINS_PER_CHANNEL - ii - 1;
621                 /* work backwards 'cause highest pdGain for lowest power */
622                 numVpd = data->pDataPerPDGain[jj].numVpd;
623                 if (numVpd > 0) {
624                         Pmin = data->pDataPerPDGain[jj].pwr_t4[0];
625                         return(Pmin);
626                 }
627         }
628         return(Pmin);
629 }
630
631 static int16_t
632 ar2316GetMaxPower(struct ath_hal *ah, const RAW_DATA_PER_CHANNEL_2316 *data)
633 {
634         uint32_t ii;
635         uint16_t Pmax=0,numVpd;
636         
637         for (ii=0; ii< MAX_NUM_PDGAINS_PER_CHANNEL; ii++) {
638                 /* work forwards cuase lowest pdGain for highest power */
639                 numVpd = data->pDataPerPDGain[ii].numVpd;
640                 if (numVpd > 0) {
641                         Pmax = data->pDataPerPDGain[ii].pwr_t4[numVpd-1];
642                         return(Pmax);
643                 }
644         }
645         return(Pmax);
646 }
647
648 static HAL_BOOL
649 ar2316GetChannelMaxMinPower(struct ath_hal *ah, HAL_CHANNEL *chan,
650         int16_t *maxPow, int16_t *minPow)
651 {
652         const HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom;
653         const RAW_DATA_STRUCT_2316 *pRawDataset = AH_NULL;
654         const RAW_DATA_PER_CHANNEL_2316 *data=AH_NULL;
655         uint16_t numChannels;
656         int totalD,totalF, totalMin,last, i;
657
658         *maxPow = 0;
659
660         if (IS_CHAN_G(chan) || IS_CHAN_108G(chan))
661                 pRawDataset = &ee->ee_rawDataset2413[headerInfo11G];
662         else if (IS_CHAN_B(chan))
663                 pRawDataset = &ee->ee_rawDataset2413[headerInfo11B];
664         else
665                 return(AH_FALSE);
666
667         numChannels = pRawDataset->numChannels;
668         data = pRawDataset->pDataPerChannel;
669         
670         /* Make sure the channel is in the range of the TP values 
671          *  (freq piers)
672          */
673         if (numChannels < 1)
674                 return(AH_FALSE);
675
676         if ((chan->channel < data[0].channelValue) ||
677             (chan->channel > data[numChannels-1].channelValue)) {
678                 if (chan->channel < data[0].channelValue) {
679                         *maxPow = ar2316GetMaxPower(ah, &data[0]);
680                         *minPow = ar2316GetMinPower(ah, &data[0]);
681                         return(AH_TRUE);
682                 } else {
683                         *maxPow = ar2316GetMaxPower(ah, &data[numChannels - 1]);
684                         *minPow = ar2316GetMinPower(ah, &data[numChannels - 1]);
685                         return(AH_TRUE);
686                 }
687         }
688
689         /* Linearly interpolate the power value now */
690         for (last=0,i=0; (i<numChannels) && (chan->channel > data[i].channelValue);
691              last = i++);
692         totalD = data[i].channelValue - data[last].channelValue;
693         if (totalD > 0) {
694                 totalF = ar2316GetMaxPower(ah, &data[i]) - ar2316GetMaxPower(ah, &data[last]);
695                 *maxPow = (int8_t) ((totalF*(chan->channel-data[last].channelValue) + 
696                                      ar2316GetMaxPower(ah, &data[last])*totalD)/totalD);
697                 totalMin = ar2316GetMinPower(ah, &data[i]) - ar2316GetMinPower(ah, &data[last]);
698                 *minPow = (int8_t) ((totalMin*(chan->channel-data[last].channelValue) +
699                                      ar2316GetMinPower(ah, &data[last])*totalD)/totalD);
700                 return(AH_TRUE);
701         } else {
702                 if (chan->channel == data[i].channelValue) {
703                         *maxPow = ar2316GetMaxPower(ah, &data[i]);
704                         *minPow = ar2316GetMinPower(ah, &data[i]);
705                         return(AH_TRUE);
706                 } else
707                         return(AH_FALSE);
708         }
709 }
710
711 /*
712  * Free memory for analog bank scratch buffers
713  */
714 static void
715 ar2316RfDetach(struct ath_hal *ah)
716 {
717         struct ath_hal_5212 *ahp = AH5212(ah);
718
719         HALASSERT(ahp->ah_rfHal != AH_NULL);
720         ath_hal_free(ahp->ah_rfHal);
721         ahp->ah_rfHal = AH_NULL;
722 }
723
724 /*
725  * Allocate memory for private state.
726  * Scratch Buffer will be reinitialized every reset so no need to zero now
727  */
728 static HAL_BOOL
729 ar2316RfAttach(struct ath_hal *ah, HAL_STATUS *status)
730 {
731         struct ath_hal_5212 *ahp = AH5212(ah);
732         struct ar2316State *priv;
733
734         HALASSERT(ah->ah_magic == AR5212_MAGIC);
735
736         HALASSERT(ahp->ah_rfHal == AH_NULL);
737         priv = ath_hal_malloc(sizeof(struct ar2316State));
738         if (priv == AH_NULL) {
739                 HALDEBUG(ah, HAL_DEBUG_ANY,
740                     "%s: cannot allocate private state\n", __func__);
741                 *status = HAL_ENOMEM;           /* XXX */
742                 return AH_FALSE;
743         }
744         priv->base.rfDetach             = ar2316RfDetach;
745         priv->base.writeRegs            = ar2316WriteRegs;
746         priv->base.getRfBank            = ar2316GetRfBank;
747         priv->base.setChannel           = ar2316SetChannel;
748         priv->base.setRfRegs            = ar2316SetRfRegs;
749         priv->base.setPowerTable        = ar2316SetPowerTable;
750         priv->base.getChannelMaxMinPower = ar2316GetChannelMaxMinPower;
751         priv->base.getNfAdjust          = ar5212GetNfAdjust;
752
753         ahp->ah_pcdacTable = priv->pcdacTable;
754         ahp->ah_pcdacTableSize = sizeof(priv->pcdacTable);
755         ahp->ah_rfHal = &priv->base;
756
757         ahp->ah_cwCalRequire = AH_TRUE;         /* force initial cal */
758
759         return AH_TRUE;
760 }
761
762 static HAL_BOOL
763 ar2316Probe(struct ath_hal *ah)
764 {
765         return IS_2316(ah);
766 }
767 AH_RF(RF2316, ar2316Probe, ar2316RfAttach);