Check for SYS/GL during library init. Reason is that
[AROS.git] / workbench / devs / networks / atheros5000 / hal / ar5212 / ar5413.c
blob218fbc962f9a29ad3ab380ce3508b2165cb606cd
1 /*
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$
19 #include "opt_ah.h"
21 #ifdef AH_SUPPORT_5413
23 #include "ah.h"
24 #include "ah_internal.h"
26 #include "ah_eeprom_v3.h"
28 #include "ar5212/ar5212.h"
29 #include "ar5212/ar5212reg.h"
30 #include "ar5212/ar5212phy.h"
32 #define AH_5212_5413
33 #include "ar5212/ar5212.ini"
35 #define N(a) (sizeof(a)/sizeof(a[0]))
37 struct ar5413State {
38 RF_HAL_FUNCS base; /* public state, must be first */
39 uint16_t pcdacTable[PWR_TABLE_SIZE_2413];
41 uint32_t Bank1Data[N(ar5212Bank1_5413)];
42 uint32_t Bank2Data[N(ar5212Bank2_5413)];
43 uint32_t Bank3Data[N(ar5212Bank3_5413)];
44 uint32_t Bank6Data[N(ar5212Bank6_5413)];
45 uint32_t Bank7Data[N(ar5212Bank7_5413)];
48 * Private state for reduced stack usage.
50 /* filled out Vpd table for all pdGains (chanL) */
51 uint16_t vpdTable_L[MAX_NUM_PDGAINS_PER_CHANNEL]
52 [MAX_PWR_RANGE_IN_HALF_DB];
53 /* filled out Vpd table for all pdGains (chanR) */
54 uint16_t vpdTable_R[MAX_NUM_PDGAINS_PER_CHANNEL]
55 [MAX_PWR_RANGE_IN_HALF_DB];
56 /* filled out Vpd table for all pdGains (interpolated) */
57 uint16_t vpdTable_I[MAX_NUM_PDGAINS_PER_CHANNEL]
58 [MAX_PWR_RANGE_IN_HALF_DB];
60 #define AR5413(ah) ((struct ar5413State *) AH5212(ah)->ah_rfHal)
62 extern void ar5212ModifyRfBuffer(uint32_t *rfBuf, uint32_t reg32,
63 uint32_t numBits, uint32_t firstBit, uint32_t column);
65 static void
66 ar5413WriteRegs(struct ath_hal *ah, u_int modesIndex, u_int freqIndex,
67 int writes)
69 HAL_INI_WRITE_ARRAY(ah, ar5212Modes_5413, modesIndex, writes);
70 HAL_INI_WRITE_ARRAY(ah, ar5212Common_5413, 1, writes);
71 HAL_INI_WRITE_ARRAY(ah, ar5212BB_RfGain_5413, freqIndex, writes);
75 * Take the MHz channel value and set the Channel value
77 * ASSUMES: Writes enabled to analog bus
79 static HAL_BOOL
80 ar5413SetChannel(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan)
82 uint32_t channelSel = 0;
83 uint32_t bModeSynth = 0;
84 uint32_t aModeRefSel = 0;
85 uint32_t reg32 = 0;
86 uint16_t freq;
88 OS_MARK(ah, AH_MARK_SETCHANNEL, chan->channel);
90 if (chan->channel < 4800) {
91 uint32_t txctl;
93 if (((chan->channel - 2192) % 5) == 0) {
94 channelSel = ((chan->channel - 672) * 2 - 3040)/10;
95 bModeSynth = 0;
96 } else if (((chan->channel - 2224) % 5) == 0) {
97 channelSel = ((chan->channel - 704) * 2 - 3040) / 10;
98 bModeSynth = 1;
99 } else {
100 HALDEBUG(ah, HAL_DEBUG_ANY,
101 "%s: invalid channel %u MHz\n",
102 __func__, chan->channel);
103 return AH_FALSE;
106 channelSel = (channelSel << 2) & 0xff;
107 channelSel = ath_hal_reverseBits(channelSel, 8);
109 txctl = OS_REG_READ(ah, AR_PHY_CCK_TX_CTRL);
110 if (chan->channel == 2484) {
111 /* Enable channel spreading for channel 14 */
112 OS_REG_WRITE(ah, AR_PHY_CCK_TX_CTRL,
113 txctl | AR_PHY_CCK_TX_CTRL_JAPAN);
114 } else {
115 OS_REG_WRITE(ah, AR_PHY_CCK_TX_CTRL,
116 txctl &~ AR_PHY_CCK_TX_CTRL_JAPAN);
118 } else if (((chan->channel % 5) == 2) && (chan->channel <= 5435)) {
119 freq = chan->channel - 2; /* Align to even 5MHz raster */
120 channelSel = ath_hal_reverseBits(
121 (uint32_t)(((freq - 4800)*10)/25 + 1), 8);
122 aModeRefSel = ath_hal_reverseBits(0, 2);
123 } else if ((chan->channel % 20) == 0 && chan->channel >= 5120) {
124 channelSel = ath_hal_reverseBits(
125 ((chan->channel - 4800) / 20 << 2), 8);
126 aModeRefSel = ath_hal_reverseBits(1, 2);
127 } else if ((chan->channel % 10) == 0) {
128 channelSel = ath_hal_reverseBits(
129 ((chan->channel - 4800) / 10 << 1), 8);
130 aModeRefSel = ath_hal_reverseBits(1, 2);
131 } else if ((chan->channel % 5) == 0) {
132 channelSel = ath_hal_reverseBits(
133 (chan->channel - 4800) / 5, 8);
134 aModeRefSel = ath_hal_reverseBits(1, 2);
135 } else {
136 HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel %u MHz\n",
137 __func__, chan->channel);
138 return AH_FALSE;
141 reg32 = (channelSel << 4) | (aModeRefSel << 2) | (bModeSynth << 1) |
142 (1 << 12) | 0x1;
143 OS_REG_WRITE(ah, AR_PHY(0x27), reg32 & 0xff);
145 reg32 >>= 8;
146 OS_REG_WRITE(ah, AR_PHY(0x36), reg32 & 0x7f);
148 AH_PRIVATE(ah)->ah_curchan = chan;
149 return AH_TRUE;
153 * Reads EEPROM header info from device structure and programs
154 * all rf registers
156 * REQUIRES: Access to the analog rf device
158 static HAL_BOOL
159 ar5413SetRfRegs(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan, uint16_t modesIndex, uint16_t *rfXpdGain)
161 #define RF_BANK_SETUP(_priv, _ix, _col) do { \
162 int i; \
163 for (i = 0; i < N(ar5212Bank##_ix##_5413); i++) \
164 (_priv)->Bank##_ix##Data[i] = ar5212Bank##_ix##_5413[i][_col];\
165 } while (0)
166 struct ath_hal_5212 *ahp = AH5212(ah);
167 const HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom;
168 uint16_t ob5GHz = 0, db5GHz = 0;
169 uint16_t ob2GHz = 0, db2GHz = 0;
170 struct ar5413State *priv = AR5413(ah);
171 int regWrites = 0;
173 HALDEBUG(ah, HAL_DEBUG_RFPARAM,
174 "%s: chan 0x%x flag 0x%x modesIndex 0x%x\n",
175 __func__, chan->channel, chan->channelFlags, modesIndex);
177 HALASSERT(priv != AH_NULL);
179 /* Setup rf parameters */
180 switch (chan->channelFlags & CHANNEL_ALL) {
181 case CHANNEL_A:
182 case CHANNEL_T:
183 if (chan->channel > 4000 && chan->channel < 5260) {
184 ob5GHz = ee->ee_ob1;
185 db5GHz = ee->ee_db1;
186 } else if (chan->channel >= 5260 && chan->channel < 5500) {
187 ob5GHz = ee->ee_ob2;
188 db5GHz = ee->ee_db2;
189 } else if (chan->channel >= 5500 && chan->channel < 5725) {
190 ob5GHz = ee->ee_ob3;
191 db5GHz = ee->ee_db3;
192 } else if (chan->channel >= 5725) {
193 ob5GHz = ee->ee_ob4;
194 db5GHz = ee->ee_db4;
195 } else {
196 /* XXX else */
198 break;
199 case CHANNEL_B:
200 ob2GHz = ee->ee_obFor24;
201 db2GHz = ee->ee_dbFor24;
202 break;
203 case CHANNEL_G:
204 case CHANNEL_108G:
205 ob2GHz = ee->ee_obFor24g;
206 db2GHz = ee->ee_dbFor24g;
207 break;
208 default:
209 HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel flags 0x%x\n",
210 __func__, chan->channelFlags);
211 return AH_FALSE;
214 /* Bank 1 Write */
215 RF_BANK_SETUP(priv, 1, 1);
217 /* Bank 2 Write */
218 RF_BANK_SETUP(priv, 2, modesIndex);
220 /* Bank 3 Write */
221 RF_BANK_SETUP(priv, 3, modesIndex);
223 /* Bank 6 Write */
224 RF_BANK_SETUP(priv, 6, modesIndex);
226 /* Only the 5 or 2 GHz OB/DB need to be set for a mode */
227 if (IS_CHAN_2GHZ(chan)) {
228 ar5212ModifyRfBuffer(priv->Bank6Data, ob2GHz, 3, 241, 0);
229 ar5212ModifyRfBuffer(priv->Bank6Data, db2GHz, 3, 238, 0);
231 /* TODO - only for Eagle 1.0 2GHz - remove for production */
232 /* XXX: but without this bit G doesn't work. */
233 ar5212ModifyRfBuffer(priv->Bank6Data, 1 , 1, 291, 2);
235 /* Optimum value for rf_pwd_iclobuf2G for PCIe chips only */
236 if (IS_PCIE(ah)) {
237 ar5212ModifyRfBuffer(priv->Bank6Data, ath_hal_reverseBits(6, 3),
238 3, 131, 3);
240 } else {
241 ar5212ModifyRfBuffer(priv->Bank6Data, ob5GHz, 3, 247, 0);
242 ar5212ModifyRfBuffer(priv->Bank6Data, db5GHz, 3, 244, 0);
246 /* Bank 7 Setup */
247 RF_BANK_SETUP(priv, 7, modesIndex);
249 /* Write Analog registers */
250 HAL_INI_WRITE_BANK(ah, ar5212Bank1_5413, priv->Bank1Data, regWrites);
251 HAL_INI_WRITE_BANK(ah, ar5212Bank2_5413, priv->Bank2Data, regWrites);
252 HAL_INI_WRITE_BANK(ah, ar5212Bank3_5413, priv->Bank3Data, regWrites);
253 HAL_INI_WRITE_BANK(ah, ar5212Bank6_5413, priv->Bank6Data, regWrites);
254 HAL_INI_WRITE_BANK(ah, ar5212Bank7_5413, priv->Bank7Data, regWrites);
256 /* Now that we have reprogrammed rfgain value, clear the flag. */
257 ahp->ah_rfgainState = HAL_RFGAIN_INACTIVE;
259 return AH_TRUE;
260 #undef RF_BANK_SETUP
264 * Return a reference to the requested RF Bank.
266 static uint32_t *
267 ar5413GetRfBank(struct ath_hal *ah, int bank)
269 struct ar5413State *priv = AR5413(ah);
271 HALASSERT(priv != AH_NULL);
272 switch (bank) {
273 case 1: return priv->Bank1Data;
274 case 2: return priv->Bank2Data;
275 case 3: return priv->Bank3Data;
276 case 6: return priv->Bank6Data;
277 case 7: return priv->Bank7Data;
279 HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unknown RF Bank %d requested\n",
280 __func__, bank);
281 return AH_NULL;
285 * Return indices surrounding the value in sorted integer lists.
287 * NB: the input list is assumed to be sorted in ascending order
289 static void
290 GetLowerUpperIndex(int16_t v, const uint16_t *lp, uint16_t listSize,
291 uint32_t *vlo, uint32_t *vhi)
293 int16_t target = v;
294 const uint16_t *ep = lp+listSize;
295 const uint16_t *tp;
298 * Check first and last elements for out-of-bounds conditions.
300 if (target < lp[0]) {
301 *vlo = *vhi = 0;
302 return;
304 if (target >= ep[-1]) {
305 *vlo = *vhi = listSize - 1;
306 return;
309 /* look for value being near or between 2 values in list */
310 for (tp = lp; tp < ep; tp++) {
312 * If value is close to the current value of the list
313 * then target is not between values, it is one of the values
315 if (*tp == target) {
316 *vlo = *vhi = tp - (const uint16_t *) lp;
317 return;
320 * Look for value being between current value and next value
321 * if so return these 2 values
323 if (target < tp[1]) {
324 *vlo = tp - (const uint16_t *) lp;
325 *vhi = *vlo + 1;
326 return;
332 * Fill the Vpdlist for indices Pmax-Pmin
334 static HAL_BOOL
335 ar5413FillVpdTable(uint32_t pdGainIdx, int16_t Pmin, int16_t Pmax,
336 const int16_t *pwrList, const uint16_t *VpdList,
337 uint16_t numIntercepts,
338 uint16_t retVpdList[][64])
340 uint16_t ii, kk;
341 int16_t currPwr = (int16_t)(2*Pmin);
342 /* since Pmin is pwr*2 and pwrList is 4*pwr */
343 uint32_t idxL, idxR;
345 ii = 0;
347 if (numIntercepts < 2)
348 return AH_FALSE;
350 while (ii <= (uint16_t)(Pmax - Pmin)) {
351 GetLowerUpperIndex(currPwr, (const uint16_t *) pwrList,
352 numIntercepts, &(idxL), &(idxR));
353 if (idxR < 1)
354 idxR = 1; /* extrapolate below */
355 if (idxL == (uint32_t)(numIntercepts - 1))
356 idxL = numIntercepts - 2; /* extrapolate above */
357 if (pwrList[idxL] == pwrList[idxR])
358 kk = VpdList[idxL];
359 else
360 kk = (uint16_t)
361 (((currPwr - pwrList[idxL])*VpdList[idxR]+
362 (pwrList[idxR] - currPwr)*VpdList[idxL])/
363 (pwrList[idxR] - pwrList[idxL]));
364 retVpdList[pdGainIdx][ii] = kk;
365 ii++;
366 currPwr += 2; /* half dB steps */
369 return AH_TRUE;
373 * Returns interpolated or the scaled up interpolated value
375 static int16_t
376 interpolate_signed(uint16_t target, uint16_t srcLeft, uint16_t srcRight,
377 int16_t targetLeft, int16_t targetRight)
379 int16_t rv;
381 if (srcRight != srcLeft) {
382 rv = ((target - srcLeft)*targetRight +
383 (srcRight - target)*targetLeft) / (srcRight - srcLeft);
384 } else {
385 rv = targetLeft;
387 return rv;
391 * Uses the data points read from EEPROM to reconstruct the pdadc power table
392 * Called by ar5413SetPowerTable()
394 static int
395 ar5413getGainBoundariesAndPdadcsForPowers(struct ath_hal *ah, uint16_t channel,
396 const RAW_DATA_STRUCT_2413 *pRawDataset,
397 uint16_t pdGainOverlap_t2,
398 int16_t *pMinCalPower, uint16_t pPdGainBoundaries[],
399 uint16_t pPdGainValues[], uint16_t pPDADCValues[])
401 struct ar5413State *priv = AR5413(ah);
402 #define VpdTable_L priv->vpdTable_L
403 #define VpdTable_R priv->vpdTable_R
404 #define VpdTable_I priv->vpdTable_I
405 uint32_t ii, jj, kk;
406 int32_t ss;/* potentially -ve index for taking care of pdGainOverlap */
407 uint32_t idxL, idxR;
408 uint32_t numPdGainsUsed = 0;
410 * If desired to support -ve power levels in future, just
411 * change pwr_I_0 to signed 5-bits.
413 int16_t Pmin_t2[MAX_NUM_PDGAINS_PER_CHANNEL];
414 /* to accomodate -ve power levels later on. */
415 int16_t Pmax_t2[MAX_NUM_PDGAINS_PER_CHANNEL];
416 /* to accomodate -ve power levels later on */
417 uint16_t numVpd = 0;
418 uint16_t Vpd_step;
419 int16_t tmpVal ;
420 uint32_t sizeCurrVpdTable, maxIndex, tgtIndex;
422 /* Get upper lower index */
423 GetLowerUpperIndex(channel, pRawDataset->pChannels,
424 pRawDataset->numChannels, &(idxL), &(idxR));
426 for (ii = 0; ii < MAX_NUM_PDGAINS_PER_CHANNEL; ii++) {
427 jj = MAX_NUM_PDGAINS_PER_CHANNEL - ii - 1;
428 /* work backwards 'cause highest pdGain for lowest power */
429 numVpd = pRawDataset->pDataPerChannel[idxL].pDataPerPDGain[jj].numVpd;
430 if (numVpd > 0) {
431 pPdGainValues[numPdGainsUsed] = pRawDataset->pDataPerChannel[idxL].pDataPerPDGain[jj].pd_gain;
432 Pmin_t2[numPdGainsUsed] = pRawDataset->pDataPerChannel[idxL].pDataPerPDGain[jj].pwr_t4[0];
433 if (Pmin_t2[numPdGainsUsed] >pRawDataset->pDataPerChannel[idxR].pDataPerPDGain[jj].pwr_t4[0]) {
434 Pmin_t2[numPdGainsUsed] = pRawDataset->pDataPerChannel[idxR].pDataPerPDGain[jj].pwr_t4[0];
436 Pmin_t2[numPdGainsUsed] = (int16_t)
437 (Pmin_t2[numPdGainsUsed] / 2);
438 Pmax_t2[numPdGainsUsed] = pRawDataset->pDataPerChannel[idxL].pDataPerPDGain[jj].pwr_t4[numVpd-1];
439 if (Pmax_t2[numPdGainsUsed] > pRawDataset->pDataPerChannel[idxR].pDataPerPDGain[jj].pwr_t4[numVpd-1])
440 Pmax_t2[numPdGainsUsed] =
441 pRawDataset->pDataPerChannel[idxR].pDataPerPDGain[jj].pwr_t4[numVpd-1];
442 Pmax_t2[numPdGainsUsed] = (int16_t)(Pmax_t2[numPdGainsUsed] / 2);
443 ar5413FillVpdTable(
444 numPdGainsUsed, Pmin_t2[numPdGainsUsed], Pmax_t2[numPdGainsUsed],
445 &(pRawDataset->pDataPerChannel[idxL].pDataPerPDGain[jj].pwr_t4[0]),
446 &(pRawDataset->pDataPerChannel[idxL].pDataPerPDGain[jj].Vpd[0]), numVpd, VpdTable_L
448 ar5413FillVpdTable(
449 numPdGainsUsed, Pmin_t2[numPdGainsUsed], Pmax_t2[numPdGainsUsed],
450 &(pRawDataset->pDataPerChannel[idxR].pDataPerPDGain[jj].pwr_t4[0]),
451 &(pRawDataset->pDataPerChannel[idxR].pDataPerPDGain[jj].Vpd[0]), numVpd, VpdTable_R
453 for (kk = 0; kk < (uint16_t)(Pmax_t2[numPdGainsUsed] - Pmin_t2[numPdGainsUsed]); kk++) {
454 VpdTable_I[numPdGainsUsed][kk] =
455 interpolate_signed(
456 channel, pRawDataset->pChannels[idxL], pRawDataset->pChannels[idxR],
457 (int16_t)VpdTable_L[numPdGainsUsed][kk], (int16_t)VpdTable_R[numPdGainsUsed][kk]);
459 /* fill VpdTable_I for this pdGain */
460 numPdGainsUsed++;
462 /* if this pdGain is used */
465 *pMinCalPower = Pmin_t2[0];
466 kk = 0; /* index for the final table */
467 for (ii = 0; ii < numPdGainsUsed; ii++) {
468 if (ii == (numPdGainsUsed - 1))
469 pPdGainBoundaries[ii] = Pmax_t2[ii] +
470 PD_GAIN_BOUNDARY_STRETCH_IN_HALF_DB;
471 else
472 pPdGainBoundaries[ii] = (uint16_t)
473 ((Pmax_t2[ii] + Pmin_t2[ii+1]) / 2 );
474 if (pPdGainBoundaries[ii] > 63) {
475 HALDEBUG(ah, HAL_DEBUG_ANY,
476 "%s: clamp pPdGainBoundaries[%d] %d\n",
477 __func__, ii, pPdGainBoundaries[ii]);/*XXX*/
478 pPdGainBoundaries[ii] = 63;
481 /* Find starting index for this pdGain */
482 if (ii == 0)
483 ss = 0; /* for the first pdGain, start from index 0 */
484 else
485 ss = (pPdGainBoundaries[ii-1] - Pmin_t2[ii]) -
486 pdGainOverlap_t2;
487 Vpd_step = (uint16_t)(VpdTable_I[ii][1] - VpdTable_I[ii][0]);
488 Vpd_step = (uint16_t)((Vpd_step < 1) ? 1 : Vpd_step);
490 *-ve ss indicates need to extrapolate data below for this pdGain
492 while (ss < 0) {
493 tmpVal = (int16_t)(VpdTable_I[ii][0] + ss*Vpd_step);
494 pPDADCValues[kk++] = (uint16_t)((tmpVal < 0) ? 0 : tmpVal);
495 ss++;
498 sizeCurrVpdTable = Pmax_t2[ii] - Pmin_t2[ii];
499 tgtIndex = pPdGainBoundaries[ii] + pdGainOverlap_t2 - Pmin_t2[ii];
500 maxIndex = (tgtIndex < sizeCurrVpdTable) ? tgtIndex : sizeCurrVpdTable;
502 while (ss < (int16_t)maxIndex)
503 pPDADCValues[kk++] = VpdTable_I[ii][ss++];
505 Vpd_step = (uint16_t)(VpdTable_I[ii][sizeCurrVpdTable-1] -
506 VpdTable_I[ii][sizeCurrVpdTable-2]);
507 Vpd_step = (uint16_t)((Vpd_step < 1) ? 1 : Vpd_step);
509 * for last gain, pdGainBoundary == Pmax_t2, so will
510 * have to extrapolate
512 if (tgtIndex > maxIndex) { /* need to extrapolate above */
513 while(ss < (int16_t)tgtIndex) {
514 tmpVal = (uint16_t)
515 (VpdTable_I[ii][sizeCurrVpdTable-1] +
516 (ss-maxIndex)*Vpd_step);
517 pPDADCValues[kk++] = (tmpVal > 127) ?
518 127 : tmpVal;
519 ss++;
521 } /* extrapolated above */
522 } /* for all pdGainUsed */
524 while (ii < MAX_NUM_PDGAINS_PER_CHANNEL) {
525 pPdGainBoundaries[ii] = pPdGainBoundaries[ii-1];
526 ii++;
528 while (kk < 128) {
529 pPDADCValues[kk] = pPDADCValues[kk-1];
530 kk++;
533 return numPdGainsUsed;
534 #undef VpdTable_L
535 #undef VpdTable_R
536 #undef VpdTable_I
539 static HAL_BOOL
540 ar5413SetPowerTable(struct ath_hal *ah,
541 int16_t *minPower, int16_t *maxPower, HAL_CHANNEL_INTERNAL *chan,
542 uint16_t *rfXpdGain)
544 struct ath_hal_5212 *ahp = AH5212(ah);
545 const HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom;
546 const RAW_DATA_STRUCT_2413 *pRawDataset = AH_NULL;
547 uint16_t pdGainOverlap_t2;
548 int16_t minCalPower5413_t2;
549 uint16_t *pdadcValues = ahp->ah_pcdacTable;
550 uint16_t gainBoundaries[4];
551 uint32_t i, reg32, regoffset, tpcrg1;
552 int numPdGainsUsed;
554 HALDEBUG(ah, HAL_DEBUG_RFPARAM, "%s: chan 0x%x flag 0x%x\n",
555 __func__, chan->channel,chan->channelFlags);
557 if (IS_CHAN_G(chan) || IS_CHAN_108G(chan))
558 pRawDataset = &ee->ee_rawDataset2413[headerInfo11G];
559 else if (IS_CHAN_B(chan))
560 pRawDataset = &ee->ee_rawDataset2413[headerInfo11B];
561 else {
562 HALASSERT(IS_CHAN_5GHZ(chan));
563 pRawDataset = &ee->ee_rawDataset2413[headerInfo11A];
566 pdGainOverlap_t2 = (uint16_t) SM(OS_REG_READ(ah, AR_PHY_TPCRG5),
567 AR_PHY_TPCRG5_PD_GAIN_OVERLAP);
569 numPdGainsUsed = ar5413getGainBoundariesAndPdadcsForPowers(ah,
570 chan->channel, pRawDataset, pdGainOverlap_t2,
571 &minCalPower5413_t2,gainBoundaries, rfXpdGain, pdadcValues);
572 HALASSERT(1 <= numPdGainsUsed && numPdGainsUsed <= 3);
574 #if 0
575 OS_REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN,
576 (pRawDataset->pDataPerChannel[0].numPdGains - 1));
577 #endif
578 tpcrg1 = OS_REG_READ(ah, AR_PHY_TPCRG1);
579 tpcrg1 = (tpcrg1 &~ AR_PHY_TPCRG1_NUM_PD_GAIN)
580 | SM(numPdGainsUsed-1, AR_PHY_TPCRG1_NUM_PD_GAIN);
581 switch (numPdGainsUsed) {
582 case 3:
583 tpcrg1 &= ~AR_PHY_TPCRG1_PDGAIN_SETTING3;
584 tpcrg1 |= SM(rfXpdGain[2], AR_PHY_TPCRG1_PDGAIN_SETTING3);
585 /* fall thru... */
586 case 2:
587 tpcrg1 &= ~AR_PHY_TPCRG1_PDGAIN_SETTING2;
588 tpcrg1 |= SM(rfXpdGain[1], AR_PHY_TPCRG1_PDGAIN_SETTING2);
589 /* fall thru... */
590 case 1:
591 tpcrg1 &= ~AR_PHY_TPCRG1_PDGAIN_SETTING1;
592 tpcrg1 |= SM(rfXpdGain[0], AR_PHY_TPCRG1_PDGAIN_SETTING1);
593 break;
595 #ifdef AH_DEBUG
596 if (tpcrg1 != OS_REG_READ(ah, AR_PHY_TPCRG1))
597 HALDEBUG(ah, HAL_DEBUG_RFPARAM, "%s: using non-default "
598 "pd_gains (default 0x%x, calculated 0x%x)\n",
599 __func__, OS_REG_READ(ah, AR_PHY_TPCRG1), tpcrg1);
600 #endif
601 OS_REG_WRITE(ah, AR_PHY_TPCRG1, tpcrg1);
604 * Note the pdadc table may not start at 0 dBm power, could be
605 * negative or greater than 0. Need to offset the power
606 * values by the amount of minPower for griffin
608 if (minCalPower5413_t2 != 0)
609 ahp->ah_txPowerIndexOffset = (int16_t)(0 - minCalPower5413_t2);
610 else
611 ahp->ah_txPowerIndexOffset = 0;
613 /* Finally, write the power values into the baseband power table */
614 regoffset = 0x9800 + (672 <<2); /* beginning of pdadc table in griffin */
615 for (i = 0; i < 32; i++) {
616 reg32 = ((pdadcValues[4*i + 0] & 0xFF) << 0) |
617 ((pdadcValues[4*i + 1] & 0xFF) << 8) |
618 ((pdadcValues[4*i + 2] & 0xFF) << 16) |
619 ((pdadcValues[4*i + 3] & 0xFF) << 24) ;
620 OS_REG_WRITE(ah, regoffset, reg32);
621 regoffset += 4;
624 OS_REG_WRITE(ah, AR_PHY_TPCRG5,
625 SM(pdGainOverlap_t2, AR_PHY_TPCRG5_PD_GAIN_OVERLAP) |
626 SM(gainBoundaries[0], AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1) |
627 SM(gainBoundaries[1], AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2) |
628 SM(gainBoundaries[2], AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3) |
629 SM(gainBoundaries[3], AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4));
631 return AH_TRUE;
634 static int16_t
635 ar5413GetMinPower(struct ath_hal *ah, const RAW_DATA_PER_CHANNEL_2413 *data)
637 uint32_t ii,jj;
638 uint16_t Pmin=0,numVpd;
640 for (ii = 0; ii < MAX_NUM_PDGAINS_PER_CHANNEL; ii++) {
641 jj = MAX_NUM_PDGAINS_PER_CHANNEL - ii - 1;
642 /* work backwards 'cause highest pdGain for lowest power */
643 numVpd = data->pDataPerPDGain[jj].numVpd;
644 if (numVpd > 0) {
645 Pmin = data->pDataPerPDGain[jj].pwr_t4[0];
646 return(Pmin);
649 return(Pmin);
652 static int16_t
653 ar5413GetMaxPower(struct ath_hal *ah, const RAW_DATA_PER_CHANNEL_2413 *data)
655 uint32_t ii;
656 uint16_t Pmax=0,numVpd;
658 for (ii=0; ii< MAX_NUM_PDGAINS_PER_CHANNEL; ii++) {
659 /* work forwards cuase lowest pdGain for highest power */
660 numVpd = data->pDataPerPDGain[ii].numVpd;
661 if (numVpd > 0) {
662 Pmax = data->pDataPerPDGain[ii].pwr_t4[numVpd-1];
663 return(Pmax);
666 return(Pmax);
669 static HAL_BOOL
670 ar5413GetChannelMaxMinPower(struct ath_hal *ah, HAL_CHANNEL *chan,
671 int16_t *maxPow, int16_t *minPow)
673 const HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom;
674 const RAW_DATA_STRUCT_2413 *pRawDataset = AH_NULL;
675 const RAW_DATA_PER_CHANNEL_2413 *data=AH_NULL;
676 uint16_t numChannels;
677 int totalD,totalF, totalMin,last, i;
679 *maxPow = 0;
681 if (IS_CHAN_G(chan) || IS_CHAN_108G(chan))
682 pRawDataset = &ee->ee_rawDataset2413[headerInfo11G];
683 else if (IS_CHAN_B(chan))
684 pRawDataset = &ee->ee_rawDataset2413[headerInfo11B];
685 else {
686 HALASSERT(IS_CHAN_5GHZ(chan));
687 pRawDataset = &ee->ee_rawDataset2413[headerInfo11A];
690 numChannels = pRawDataset->numChannels;
691 data = pRawDataset->pDataPerChannel;
693 /* Make sure the channel is in the range of the TP values
694 * (freq piers)
696 if (numChannels < 1)
697 return(AH_FALSE);
699 if ((chan->channel < data[0].channelValue) ||
700 (chan->channel > data[numChannels-1].channelValue)) {
701 if (chan->channel < data[0].channelValue) {
702 *maxPow = ar5413GetMaxPower(ah, &data[0]);
703 *minPow = ar5413GetMinPower(ah, &data[0]);
704 return(AH_TRUE);
705 } else {
706 *maxPow = ar5413GetMaxPower(ah, &data[numChannels - 1]);
707 *minPow = ar5413GetMinPower(ah, &data[numChannels - 1]);
708 return(AH_TRUE);
712 /* Linearly interpolate the power value now */
713 for (last=0,i=0; (i<numChannels) && (chan->channel > data[i].channelValue);
714 last = i++);
715 totalD = data[i].channelValue - data[last].channelValue;
716 if (totalD > 0) {
717 totalF = ar5413GetMaxPower(ah, &data[i]) - ar5413GetMaxPower(ah, &data[last]);
718 *maxPow = (int8_t) ((totalF*(chan->channel-data[last].channelValue) +
719 ar5413GetMaxPower(ah, &data[last])*totalD)/totalD);
720 totalMin = ar5413GetMinPower(ah, &data[i]) - ar5413GetMinPower(ah, &data[last]);
721 *minPow = (int8_t) ((totalMin*(chan->channel-data[last].channelValue) +
722 ar5413GetMinPower(ah, &data[last])*totalD)/totalD);
723 return(AH_TRUE);
724 } else {
725 if (chan->channel == data[i].channelValue) {
726 *maxPow = ar5413GetMaxPower(ah, &data[i]);
727 *minPow = ar5413GetMinPower(ah, &data[i]);
728 return(AH_TRUE);
729 } else
730 return(AH_FALSE);
735 * Free memory for analog bank scratch buffers
737 static void
738 ar5413RfDetach(struct ath_hal *ah)
740 struct ath_hal_5212 *ahp = AH5212(ah);
742 HALASSERT(ahp->ah_rfHal != AH_NULL);
743 ath_hal_free(ahp->ah_rfHal);
744 ahp->ah_rfHal = AH_NULL;
748 * Allocate memory for analog bank scratch buffers
749 * Scratch Buffer will be reinitialized every reset so no need to zero now
751 HAL_BOOL
752 ar5413RfAttach(struct ath_hal *ah, HAL_STATUS *status)
754 struct ath_hal_5212 *ahp = AH5212(ah);
755 struct ar5413State *priv;
757 HALASSERT(ah->ah_magic == AR5212_MAGIC);
759 HALASSERT(ahp->ah_rfHal == AH_NULL);
760 priv = ath_hal_malloc(sizeof(struct ar5413State));
761 if (priv == AH_NULL) {
762 HALDEBUG(ah, HAL_DEBUG_ANY,
763 "%s: cannot allocate private state\n", __func__);
764 *status = HAL_ENOMEM; /* XXX */
765 return AH_FALSE;
767 priv->base.rfDetach = ar5413RfDetach;
768 priv->base.writeRegs = ar5413WriteRegs;
769 priv->base.getRfBank = ar5413GetRfBank;
770 priv->base.setChannel = ar5413SetChannel;
771 priv->base.setRfRegs = ar5413SetRfRegs;
772 priv->base.setPowerTable = ar5413SetPowerTable;
773 priv->base.getChannelMaxMinPower = ar5413GetChannelMaxMinPower;
774 priv->base.getNfAdjust = ar5212GetNfAdjust;
776 ahp->ah_pcdacTable = priv->pcdacTable;
777 ahp->ah_pcdacTableSize = sizeof(priv->pcdacTable);
778 ahp->ah_rfHal = &priv->base;
780 return AH_TRUE;
782 #endif /* AH_SUPPORT_5413 */