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.
21 #ifdef AH_SUPPORT_5413
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"
33 #include "ar5212/ar5212.ini"
35 #define N(a) (sizeof(a)/sizeof(a[0]))
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
);
66 ar5413WriteRegs(struct ath_hal
*ah
, u_int modesIndex
, u_int freqIndex
,
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
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;
88 OS_MARK(ah
, AH_MARK_SETCHANNEL
, chan
->channel
);
90 if (chan
->channel
< 4800) {
93 if (((chan
->channel
- 2192) % 5) == 0) {
94 channelSel
= ((chan
->channel
- 672) * 2 - 3040)/10;
96 } else if (((chan
->channel
- 2224) % 5) == 0) {
97 channelSel
= ((chan
->channel
- 704) * 2 - 3040) / 10;
100 HALDEBUG(ah
, HAL_DEBUG_ANY
,
101 "%s: invalid channel %u MHz\n",
102 __func__
, chan
->channel
);
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
);
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);
136 HALDEBUG(ah
, HAL_DEBUG_ANY
, "%s: invalid channel %u MHz\n",
137 __func__
, chan
->channel
);
141 reg32
= (channelSel
<< 4) | (aModeRefSel
<< 2) | (bModeSynth
<< 1) |
143 OS_REG_WRITE(ah
, AR_PHY(0x27), reg32
& 0xff);
146 OS_REG_WRITE(ah
, AR_PHY(0x36), reg32
& 0x7f);
148 AH_PRIVATE(ah
)->ah_curchan
= chan
;
153 * Reads EEPROM header info from device structure and programs
156 * REQUIRES: Access to the analog rf device
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 { \
163 for (i = 0; i < N(ar5212Bank##_ix##_5413); i++) \
164 (_priv)->Bank##_ix##Data[i] = ar5212Bank##_ix##_5413[i][_col];\
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
);
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
) {
183 if (chan
->channel
> 4000 && chan
->channel
< 5260) {
186 } else if (chan
->channel
>= 5260 && chan
->channel
< 5500) {
189 } else if (chan
->channel
>= 5500 && chan
->channel
< 5725) {
192 } else if (chan
->channel
>= 5725) {
200 ob2GHz
= ee
->ee_obFor24
;
201 db2GHz
= ee
->ee_dbFor24
;
205 ob2GHz
= ee
->ee_obFor24g
;
206 db2GHz
= ee
->ee_dbFor24g
;
209 HALDEBUG(ah
, HAL_DEBUG_ANY
, "%s: invalid channel flags 0x%x\n",
210 __func__
, chan
->channelFlags
);
215 RF_BANK_SETUP(priv
, 1, 1);
218 RF_BANK_SETUP(priv
, 2, modesIndex
);
221 RF_BANK_SETUP(priv
, 3, modesIndex
);
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 */
237 ar5212ModifyRfBuffer(priv
->Bank6Data
, ath_hal_reverseBits(6, 3),
241 ar5212ModifyRfBuffer(priv
->Bank6Data
, ob5GHz
, 3, 247, 0);
242 ar5212ModifyRfBuffer(priv
->Bank6Data
, db5GHz
, 3, 244, 0);
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
;
264 * Return a reference to the requested RF Bank.
267 ar5413GetRfBank(struct ath_hal
*ah
, int bank
)
269 struct ar5413State
*priv
= AR5413(ah
);
271 HALASSERT(priv
!= AH_NULL
);
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",
285 * Return indices surrounding the value in sorted integer lists.
287 * NB: the input list is assumed to be sorted in ascending order
290 GetLowerUpperIndex(int16_t v
, const uint16_t *lp
, uint16_t listSize
,
291 uint32_t *vlo
, uint32_t *vhi
)
294 const uint16_t *ep
= lp
+listSize
;
298 * Check first and last elements for out-of-bounds conditions.
300 if (target
< lp
[0]) {
304 if (target
>= ep
[-1]) {
305 *vlo
= *vhi
= listSize
- 1;
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
316 *vlo
= *vhi
= tp
- (const uint16_t *) lp
;
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
;
332 * Fill the Vpdlist for indices Pmax-Pmin
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])
341 int16_t currPwr
= (int16_t)(2*Pmin
);
342 /* since Pmin is pwr*2 and pwrList is 4*pwr */
347 if (numIntercepts
< 2)
350 while (ii
<= (uint16_t)(Pmax
- Pmin
)) {
351 GetLowerUpperIndex(currPwr
, (const uint16_t *) pwrList
,
352 numIntercepts
, &(idxL
), &(idxR
));
354 idxR
= 1; /* extrapolate below */
355 if (idxL
== (uint32_t)(numIntercepts
- 1))
356 idxL
= numIntercepts
- 2; /* extrapolate above */
357 if (pwrList
[idxL
] == pwrList
[idxR
])
361 (((currPwr
- pwrList
[idxL
])*VpdList
[idxR
]+
362 (pwrList
[idxR
] - currPwr
)*VpdList
[idxL
])/
363 (pwrList
[idxR
] - pwrList
[idxL
]));
364 retVpdList
[pdGainIdx
][ii
] = kk
;
366 currPwr
+= 2; /* half dB steps */
373 * Returns interpolated or the scaled up interpolated value
376 interpolate_signed(uint16_t target
, uint16_t srcLeft
, uint16_t srcRight
,
377 int16_t targetLeft
, int16_t targetRight
)
381 if (srcRight
!= srcLeft
) {
382 rv
= ((target
- srcLeft
)*targetRight
+
383 (srcRight
- target
)*targetLeft
) / (srcRight
- srcLeft
);
391 * Uses the data points read from EEPROM to reconstruct the pdadc power table
392 * Called by ar5413SetPowerTable()
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
406 int32_t ss
;/* potentially -ve index for taking care of pdGainOverlap */
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 */
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
;
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);
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
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
] =
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 */
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
;
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 */
483 ss
= 0; /* for the first pdGain, start from index 0 */
485 ss
= (pPdGainBoundaries
[ii
-1] - Pmin_t2
[ii
]) -
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
493 tmpVal
= (int16_t)(VpdTable_I
[ii
][0] + ss
*Vpd_step
);
494 pPDADCValues
[kk
++] = (uint16_t)((tmpVal
< 0) ? 0 : tmpVal
);
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
) {
515 (VpdTable_I
[ii
][sizeCurrVpdTable
-1] +
516 (ss
-maxIndex
)*Vpd_step
);
517 pPDADCValues
[kk
++] = (tmpVal
> 127) ?
521 } /* extrapolated above */
522 } /* for all pdGainUsed */
524 while (ii
< MAX_NUM_PDGAINS_PER_CHANNEL
) {
525 pPdGainBoundaries
[ii
] = pPdGainBoundaries
[ii
-1];
529 pPDADCValues
[kk
] = pPDADCValues
[kk
-1];
533 return numPdGainsUsed
;
540 ar5413SetPowerTable(struct ath_hal
*ah
,
541 int16_t *minPower
, int16_t *maxPower
, HAL_CHANNEL_INTERNAL
*chan
,
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
;
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
];
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);
575 OS_REG_RMW_FIELD(ah
, AR_PHY_TPCRG1
, AR_PHY_TPCRG1_NUM_PD_GAIN
,
576 (pRawDataset
->pDataPerChannel
[0].numPdGains
- 1));
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
) {
583 tpcrg1
&= ~AR_PHY_TPCRG1_PDGAIN_SETTING3
;
584 tpcrg1
|= SM(rfXpdGain
[2], AR_PHY_TPCRG1_PDGAIN_SETTING3
);
587 tpcrg1
&= ~AR_PHY_TPCRG1_PDGAIN_SETTING2
;
588 tpcrg1
|= SM(rfXpdGain
[1], AR_PHY_TPCRG1_PDGAIN_SETTING2
);
591 tpcrg1
&= ~AR_PHY_TPCRG1_PDGAIN_SETTING1
;
592 tpcrg1
|= SM(rfXpdGain
[0], AR_PHY_TPCRG1_PDGAIN_SETTING1
);
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
);
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
);
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
);
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
));
635 ar5413GetMinPower(struct ath_hal
*ah
, const RAW_DATA_PER_CHANNEL_2413
*data
)
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
;
645 Pmin
= data
->pDataPerPDGain
[jj
].pwr_t4
[0];
653 ar5413GetMaxPower(struct ath_hal
*ah
, const RAW_DATA_PER_CHANNEL_2413
*data
)
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
;
662 Pmax
= data
->pDataPerPDGain
[ii
].pwr_t4
[numVpd
-1];
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
;
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
];
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
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]);
706 *maxPow
= ar5413GetMaxPower(ah
, &data
[numChannels
- 1]);
707 *minPow
= ar5413GetMinPower(ah
, &data
[numChannels
- 1]);
712 /* Linearly interpolate the power value now */
713 for (last
=0,i
=0; (i
<numChannels
) && (chan
->channel
> data
[i
].channelValue
);
715 totalD
= data
[i
].channelValue
- data
[last
].channelValue
;
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
);
725 if (chan
->channel
== data
[i
].channelValue
) {
726 *maxPow
= ar5413GetMaxPower(ah
, &data
[i
]);
727 *minPow
= ar5413GetMinPower(ah
, &data
[i
]);
735 * Free memory for analog bank scratch buffers
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
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 */
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
;
782 #endif /* AH_SUPPORT_5413 */