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: ar5112.c,v 1.1.1.1 2008/12/11 04:46:37 alc Exp $
22 #include "ah_internal.h"
24 #include "ah_eeprom_v3.h"
26 #include "ar5212/ar5212.h"
27 #include "ar5212/ar5212reg.h"
28 #include "ar5212/ar5212phy.h"
31 #include "ar5212/ar5212.ini"
33 #define N(a) (sizeof(a)/sizeof(a[0]))
36 RF_HAL_FUNCS base
; /* public state, must be first */
37 uint16_t pcdacTable
[PWR_TABLE_SIZE
];
39 uint32_t Bank1Data
[N(ar5212Bank1_5112
)];
40 uint32_t Bank2Data
[N(ar5212Bank2_5112
)];
41 uint32_t Bank3Data
[N(ar5212Bank3_5112
)];
42 uint32_t Bank6Data
[N(ar5212Bank6_5112
)];
43 uint32_t Bank7Data
[N(ar5212Bank7_5112
)];
45 #define AR5112(ah) ((struct ar5112State *) AH5212(ah)->ah_rfHal)
47 static void ar5212GetLowerUpperIndex(uint16_t v
,
48 uint16_t *lp
, uint16_t listSize
,
49 uint32_t *vlo
, uint32_t *vhi
);
50 static HAL_BOOL
getFullPwrTable(uint16_t numPcdacs
, uint16_t *pcdacs
,
51 int16_t *power
, int16_t maxPower
, int16_t *retVals
);
52 static int16_t getPminAndPcdacTableFromPowerTable(int16_t *pwrTableT4
,
54 static int16_t getPminAndPcdacTableFromTwoPowerTables(int16_t *pwrTableLXpdT4
,
55 int16_t *pwrTableHXpdT4
, uint16_t retVals
[], int16_t *pMid
);
56 static int16_t interpolate_signed(uint16_t target
,
57 uint16_t srcLeft
, uint16_t srcRight
,
58 int16_t targetLeft
, int16_t targetRight
);
60 extern void ar5212ModifyRfBuffer(uint32_t *rfBuf
, uint32_t reg32
,
61 uint32_t numBits
, uint32_t firstBit
, uint32_t column
);
64 ar5112WriteRegs(struct ath_hal
*ah
, u_int modesIndex
, u_int freqIndex
,
67 HAL_INI_WRITE_ARRAY(ah
, ar5212Modes_5112
, modesIndex
, writes
);
68 HAL_INI_WRITE_ARRAY(ah
, ar5212Common_5112
, 1, writes
);
69 HAL_INI_WRITE_ARRAY(ah
, ar5212BB_RfGain_5112
, freqIndex
, writes
);
73 * Take the MHz channel value and set the Channel value
75 * ASSUMES: Writes enabled to analog bus
78 ar5112SetChannel(struct ath_hal
*ah
, HAL_CHANNEL_INTERNAL
*chan
)
80 uint32_t channelSel
= 0;
81 uint32_t bModeSynth
= 0;
82 uint32_t aModeRefSel
= 0;
86 OS_MARK(ah
, AH_MARK_SETCHANNEL
, chan
->channel
);
88 if (chan
->channel
< 4800) {
91 if (((chan
->channel
- 2192) % 5) == 0) {
92 channelSel
= ((chan
->channel
- 672) * 2 - 3040)/10;
94 } else if (((chan
->channel
- 2224) % 5) == 0) {
95 channelSel
= ((chan
->channel
- 704) * 2 - 3040) / 10;
98 HALDEBUG(ah
, HAL_DEBUG_ANY
,
99 "%s: invalid channel %u MHz\n",
100 __func__
, chan
->channel
);
104 channelSel
= (channelSel
<< 2) & 0xff;
105 channelSel
= ath_hal_reverseBits(channelSel
, 8);
107 txctl
= OS_REG_READ(ah
, AR_PHY_CCK_TX_CTRL
);
108 if (chan
->channel
== 2484) {
109 /* Enable channel spreading for channel 14 */
110 OS_REG_WRITE(ah
, AR_PHY_CCK_TX_CTRL
,
111 txctl
| AR_PHY_CCK_TX_CTRL_JAPAN
);
113 OS_REG_WRITE(ah
, AR_PHY_CCK_TX_CTRL
,
114 txctl
&~ AR_PHY_CCK_TX_CTRL_JAPAN
);
116 } else if (((chan
->channel
% 5) == 2) && (chan
->channel
<= 5435)) {
117 freq
= chan
->channel
- 2; /* Align to even 5MHz raster */
118 channelSel
= ath_hal_reverseBits(
119 (uint32_t)(((freq
- 4800)*10)/25 + 1), 8);
120 aModeRefSel
= ath_hal_reverseBits(0, 2);
121 } else if ((chan
->channel
% 20) == 0 && chan
->channel
>= 5120) {
122 channelSel
= ath_hal_reverseBits(
123 ((chan
->channel
- 4800) / 20 << 2), 8);
124 aModeRefSel
= ath_hal_reverseBits(3, 2);
125 } else if ((chan
->channel
% 10) == 0) {
126 channelSel
= ath_hal_reverseBits(
127 ((chan
->channel
- 4800) / 10 << 1), 8);
128 aModeRefSel
= ath_hal_reverseBits(2, 2);
129 } else if ((chan
->channel
% 5) == 0) {
130 channelSel
= ath_hal_reverseBits(
131 (chan
->channel
- 4800) / 5, 8);
132 aModeRefSel
= ath_hal_reverseBits(1, 2);
134 HALDEBUG(ah
, HAL_DEBUG_ANY
, "%s: invalid channel %u MHz\n",
135 __func__
, chan
->channel
);
139 reg32
= (channelSel
<< 4) | (aModeRefSel
<< 2) | (bModeSynth
<< 1) |
141 OS_REG_WRITE(ah
, AR_PHY(0x27), reg32
& 0xff);
144 OS_REG_WRITE(ah
, AR_PHY(0x36), reg32
& 0x7f);
146 AH_PRIVATE(ah
)->ah_curchan
= chan
;
151 * Return a reference to the requested RF Bank.
154 ar5112GetRfBank(struct ath_hal
*ah
, int bank
)
156 struct ar5112State
*priv
= AR5112(ah
);
158 HALASSERT(priv
!= AH_NULL
);
160 case 1: return priv
->Bank1Data
;
161 case 2: return priv
->Bank2Data
;
162 case 3: return priv
->Bank3Data
;
163 case 6: return priv
->Bank6Data
;
164 case 7: return priv
->Bank7Data
;
166 HALDEBUG(ah
, HAL_DEBUG_ANY
, "%s: unknown RF Bank %d requested\n",
172 * Reads EEPROM header info from device structure and programs
175 * REQUIRES: Access to the analog rf device
178 ar5112SetRfRegs(struct ath_hal
*ah
, HAL_CHANNEL_INTERNAL
*chan
,
179 uint16_t modesIndex
, uint16_t *rfXpdGain
)
181 #define RF_BANK_SETUP(_priv, _ix, _col) do { \
183 for (i = 0; i < N(ar5212Bank##_ix##_5112); i++) \
184 (_priv)->Bank##_ix##Data[i] = ar5212Bank##_ix##_5112[i][_col];\
186 struct ath_hal_5212
*ahp
= AH5212(ah
);
187 const HAL_EEPROM
*ee
= AH_PRIVATE(ah
)->ah_eeprom
;
188 uint16_t rfXpdSel
, gainI
;
189 uint16_t ob5GHz
= 0, db5GHz
= 0;
190 uint16_t ob2GHz
= 0, db2GHz
= 0;
191 struct ar5112State
*priv
= AR5112(ah
);
192 GAIN_VALUES
*gv
= &ahp
->ah_gainValues
;
197 /* Setup rf parameters */
198 switch (chan
->channelFlags
& CHANNEL_ALL
) {
201 if (chan
->channel
> 4000 && chan
->channel
< 5260) {
204 } else if (chan
->channel
>= 5260 && chan
->channel
< 5500) {
207 } else if (chan
->channel
>= 5500 && chan
->channel
< 5725) {
210 } else if (chan
->channel
>= 5725) {
216 rfXpdSel
= ee
->ee_xpd
[headerInfo11A
];
217 gainI
= ee
->ee_gainI
[headerInfo11A
];
220 ob2GHz
= ee
->ee_ob2GHz
[0];
221 db2GHz
= ee
->ee_db2GHz
[0];
222 rfXpdSel
= ee
->ee_xpd
[headerInfo11B
];
223 gainI
= ee
->ee_gainI
[headerInfo11B
];
227 ob2GHz
= ee
->ee_ob2GHz
[1];
228 db2GHz
= ee
->ee_ob2GHz
[1];
229 rfXpdSel
= ee
->ee_xpd
[headerInfo11G
];
230 gainI
= ee
->ee_gainI
[headerInfo11G
];
233 HALDEBUG(ah
, HAL_DEBUG_ANY
, "%s: invalid channel flags 0x%x\n",
234 __func__
, chan
->channelFlags
);
238 /* Setup Bank 1 Write */
239 RF_BANK_SETUP(priv
, 1, 1);
241 /* Setup Bank 2 Write */
242 RF_BANK_SETUP(priv
, 2, modesIndex
);
244 /* Setup Bank 3 Write */
245 RF_BANK_SETUP(priv
, 3, modesIndex
);
247 /* Setup Bank 6 Write */
248 RF_BANK_SETUP(priv
, 6, modesIndex
);
250 ar5212ModifyRfBuffer(priv
->Bank6Data
, rfXpdSel
, 1, 302, 0);
252 ar5212ModifyRfBuffer(priv
->Bank6Data
, rfXpdGain
[0], 2, 270, 0);
253 ar5212ModifyRfBuffer(priv
->Bank6Data
, rfXpdGain
[1], 2, 257, 0);
255 if (IS_CHAN_OFDM(chan
)) {
256 ar5212ModifyRfBuffer(priv
->Bank6Data
,
257 gv
->currStep
->paramVal
[GP_PWD_138
], 1, 168, 3);
258 ar5212ModifyRfBuffer(priv
->Bank6Data
,
259 gv
->currStep
->paramVal
[GP_PWD_137
], 1, 169, 3);
260 ar5212ModifyRfBuffer(priv
->Bank6Data
,
261 gv
->currStep
->paramVal
[GP_PWD_136
], 1, 170, 3);
262 ar5212ModifyRfBuffer(priv
->Bank6Data
,
263 gv
->currStep
->paramVal
[GP_PWD_132
], 1, 174, 3);
264 ar5212ModifyRfBuffer(priv
->Bank6Data
,
265 gv
->currStep
->paramVal
[GP_PWD_131
], 1, 175, 3);
266 ar5212ModifyRfBuffer(priv
->Bank6Data
,
267 gv
->currStep
->paramVal
[GP_PWD_130
], 1, 176, 3);
270 /* Only the 5 or 2 GHz OB/DB need to be set for a mode */
271 if (IS_CHAN_2GHZ(chan
)) {
272 ar5212ModifyRfBuffer(priv
->Bank6Data
, ob2GHz
, 3, 287, 0);
273 ar5212ModifyRfBuffer(priv
->Bank6Data
, db2GHz
, 3, 290, 0);
275 ar5212ModifyRfBuffer(priv
->Bank6Data
, ob5GHz
, 3, 279, 0);
276 ar5212ModifyRfBuffer(priv
->Bank6Data
, db5GHz
, 3, 282, 0);
279 /* Lower synth voltage for X112 Rev 2.0 only */
280 if (IS_RADX112_REV2(ah
)) {
281 /* Non-Reversed analyg registers - so values are pre-reversed */
282 ar5212ModifyRfBuffer(priv
->Bank6Data
, 2, 2, 90, 2);
283 ar5212ModifyRfBuffer(priv
->Bank6Data
, 2, 2, 92, 2);
284 ar5212ModifyRfBuffer(priv
->Bank6Data
, 2, 2, 94, 2);
285 ar5212ModifyRfBuffer(priv
->Bank6Data
, 2, 1, 254, 2);
288 /* Decrease Power Consumption for 5312/5213 and up */
289 if (AH_PRIVATE(ah
)->ah_phyRev
>= AR_PHY_CHIP_ID_REV_2
) {
290 ar5212ModifyRfBuffer(priv
->Bank6Data
, 1, 1, 281, 1);
291 ar5212ModifyRfBuffer(priv
->Bank6Data
, 1, 2, 1, 3);
292 ar5212ModifyRfBuffer(priv
->Bank6Data
, 1, 2, 3, 3);
293 ar5212ModifyRfBuffer(priv
->Bank6Data
, 1, 1, 139, 3);
294 ar5212ModifyRfBuffer(priv
->Bank6Data
, 1, 1, 140, 3);
297 /* Setup Bank 7 Setup */
298 RF_BANK_SETUP(priv
, 7, modesIndex
);
299 if (IS_CHAN_OFDM(chan
))
300 ar5212ModifyRfBuffer(priv
->Bank7Data
,
301 gv
->currStep
->paramVal
[GP_MIXGAIN_OVR
], 2, 37, 0);
303 ar5212ModifyRfBuffer(priv
->Bank7Data
, gainI
, 6, 14, 0);
305 /* Adjust params for Derby TX power control */
306 if (IS_CHAN_HALF_RATE(chan
) || IS_CHAN_QUARTER_RATE(chan
)) {
307 uint32_t rfDelay
, rfPeriod
;
310 rfPeriod
= (IS_CHAN_HALF_RATE(chan
)) ? 0x8 : 0xf;
311 ar5212ModifyRfBuffer(priv
->Bank7Data
, rfDelay
, 4, 58, 0);
312 ar5212ModifyRfBuffer(priv
->Bank7Data
, rfPeriod
, 4, 70, 0);
316 /* Analog registers are setup - EAR can modify */
317 if (ar5212IsEarEngaged(pDev
, chan
))
319 ar5212EarModify(pDev
, EAR_LC_RF_WRITE
, chan
, &modifier
);
321 /* Write Analog registers */
322 HAL_INI_WRITE_BANK(ah
, ar5212Bank1_5112
, priv
->Bank1Data
, regWrites
);
323 HAL_INI_WRITE_BANK(ah
, ar5212Bank2_5112
, priv
->Bank2Data
, regWrites
);
324 HAL_INI_WRITE_BANK(ah
, ar5212Bank3_5112
, priv
->Bank3Data
, regWrites
);
325 HAL_INI_WRITE_BANK(ah
, ar5212Bank6_5112
, priv
->Bank6Data
, regWrites
);
326 HAL_INI_WRITE_BANK(ah
, ar5212Bank7_5112
, priv
->Bank7Data
, regWrites
);
328 /* Now that we have reprogrammed rfgain value, clear the flag. */
329 ahp
->ah_rfgainState
= HAL_RFGAIN_INACTIVE
;
335 * Read the transmit power levels from the structures taken from EEPROM
336 * Interpolate read transmit power values for this channel
337 * Organize the transmit power values into a table for writing into the hardware
340 ar5112SetPowerTable(struct ath_hal
*ah
,
341 int16_t *pPowerMin
, int16_t *pPowerMax
, HAL_CHANNEL_INTERNAL
*chan
,
344 struct ath_hal_5212
*ahp
= AH5212(ah
);
345 const HAL_EEPROM
*ee
= AH_PRIVATE(ah
)->ah_eeprom
;
346 uint32_t numXpdGain
= IS_RADX112_REV2(ah
) ? 2 : 1;
347 uint32_t xpdGainMask
= 0;
348 int16_t powerMid
, *pPowerMid
= &powerMid
;
350 const EXPN_DATA_PER_CHANNEL_5112
*pRawCh
;
351 const EEPROM_POWER_EXPN_5112
*pPowerExpn
= AH_NULL
;
354 int16_t minPwr_t4
, maxPwr_t4
, Pmin
, Pmid
;
356 uint32_t chan_idx_L
= 0, chan_idx_R
= 0;
357 uint16_t chan_L
, chan_R
;
359 int16_t pwr_table0
[64];
360 int16_t pwr_table1
[64];
364 int16_t powTableLXPD
[2][64];
365 int16_t powTableHXPD
[2][64];
366 int16_t tmpPowerTable
[64];
367 uint16_t xgainList
[2];
370 switch (chan
->channelFlags
& CHANNEL_ALL
) {
373 pPowerExpn
= &ee
->ee_modePowerArray5112
[headerInfo11A
];
374 xpdGainMask
= ee
->ee_xgain
[headerInfo11A
];
377 pPowerExpn
= &ee
->ee_modePowerArray5112
[headerInfo11B
];
378 xpdGainMask
= ee
->ee_xgain
[headerInfo11B
];
382 pPowerExpn
= &ee
->ee_modePowerArray5112
[headerInfo11G
];
383 xpdGainMask
= ee
->ee_xgain
[headerInfo11G
];
386 HALDEBUG(ah
, HAL_DEBUG_ANY
, "%s: unknown channel flags 0x%x\n",
387 __func__
, chan
->channelFlags
& CHANNEL_ALL
);
391 if ((xpdGainMask
& pPowerExpn
->xpdMask
) < 1) {
392 HALDEBUG(ah
, HAL_DEBUG_ANY
,
393 "%s: desired xpdGainMask 0x%x not supported by "
394 "calibrated xpdMask 0x%x\n", __func__
,
395 xpdGainMask
, pPowerExpn
->xpdMask
);
399 maxPwr_t4
= (int16_t)(2*(*pPowerMax
)); /* pwr_t2 -> pwr_t4 */
400 minPwr_t4
= (int16_t)(2*(*pPowerMin
)); /* pwr_t2 -> pwr_t4 */
402 xgainList
[0] = 0xDEAD;
403 xgainList
[1] = 0xDEAD;
406 xpdMask
= pPowerExpn
->xpdMask
;
407 for (jj
= 0; jj
< NUM_XPD_PER_CHANNEL
; jj
++) {
408 if (((xpdMask
>> jj
) & 1) > 0) {
410 HALDEBUG(ah
, HAL_DEBUG_ANY
,
411 "A maximum of 2 xpdGains supported"
412 "in pExpnPower data\n");
415 xgainList
[kk
++] = (uint16_t)jj
;
419 ar5212GetLowerUpperIndex(chan
->channel
, &pPowerExpn
->pChannels
[0],
420 pPowerExpn
->numChannels
, &chan_idx_L
, &chan_idx_R
);
423 for (ii
= chan_idx_L
; ii
<= chan_idx_R
; ii
++) {
424 pRawCh
= &(pPowerExpn
->pDataPerChannel
[ii
]);
425 if (xgainList
[1] == 0xDEAD) {
427 numPcd
= pRawCh
->pDataPerXPD
[jj
].numPcdacs
;
428 OS_MEMCPY(&pcdacs
[0], &pRawCh
->pDataPerXPD
[jj
].pcdac
[0],
429 numPcd
* sizeof(uint16_t));
430 OS_MEMCPY(&powers
[0], &pRawCh
->pDataPerXPD
[jj
].pwr_t4
[0],
431 numPcd
* sizeof(int16_t));
432 if (!getFullPwrTable(numPcd
, &pcdacs
[0], &powers
[0],
433 pRawCh
->maxPower_t4
, &tmpPowerTable
[0])) {
436 OS_MEMCPY(&powTableLXPD
[kk
][0], &tmpPowerTable
[0],
440 numPcd
= pRawCh
->pDataPerXPD
[jj
].numPcdacs
;
441 OS_MEMCPY(&pcdacs
[0], &pRawCh
->pDataPerXPD
[jj
].pcdac
[0],
442 numPcd
*sizeof(uint16_t));
443 OS_MEMCPY(&powers
[0],
444 &pRawCh
->pDataPerXPD
[jj
].pwr_t4
[0],
445 numPcd
*sizeof(int16_t));
446 if (!getFullPwrTable(numPcd
, &pcdacs
[0], &powers
[0],
447 pRawCh
->maxPower_t4
, &tmpPowerTable
[0])) {
450 OS_MEMCPY(&powTableLXPD
[kk
][0], &tmpPowerTable
[0],
451 64 * sizeof(int16_t));
454 numPcd
= pRawCh
->pDataPerXPD
[jj
].numPcdacs
;
455 OS_MEMCPY(&pcdacs
[0], &pRawCh
->pDataPerXPD
[jj
].pcdac
[0],
456 numPcd
* sizeof(uint16_t));
457 OS_MEMCPY(&powers
[0],
458 &pRawCh
->pDataPerXPD
[jj
].pwr_t4
[0],
459 numPcd
* sizeof(int16_t));
460 if (!getFullPwrTable(numPcd
, &pcdacs
[0], &powers
[0],
461 pRawCh
->maxPower_t4
, &tmpPowerTable
[0])) {
464 OS_MEMCPY(&powTableHXPD
[kk
][0], &tmpPowerTable
[0],
465 64 * sizeof(int16_t));
470 chan_L
= pPowerExpn
->pChannels
[chan_idx_L
];
471 chan_R
= pPowerExpn
->pChannels
[chan_idx_R
];
472 kk
= chan_idx_R
- chan_idx_L
;
474 if (xgainList
[1] == 0xDEAD) {
475 for (jj
= 0; jj
< 64; jj
++) {
476 pwr_table0
[jj
] = interpolate_signed(
477 chan
->channel
, chan_L
, chan_R
,
478 powTableLXPD
[0][jj
], powTableLXPD
[kk
][jj
]);
480 Pmin
= getPminAndPcdacTableFromPowerTable(&pwr_table0
[0],
482 *pPowerMin
= (int16_t) (Pmin
/ 2);
483 *pPowerMid
= (int16_t) (pwr_table0
[63] / 2);
484 *pPowerMax
= (int16_t) (pwr_table0
[63] / 2);
485 rfXpdGain
[0] = xgainList
[0];
486 rfXpdGain
[1] = rfXpdGain
[0];
488 for (jj
= 0; jj
< 64; jj
++) {
489 pwr_table0
[jj
] = interpolate_signed(
490 chan
->channel
, chan_L
, chan_R
,
491 powTableLXPD
[0][jj
], powTableLXPD
[kk
][jj
]);
492 pwr_table1
[jj
] = interpolate_signed(
493 chan
->channel
, chan_L
, chan_R
,
494 powTableHXPD
[0][jj
], powTableHXPD
[kk
][jj
]);
496 if (numXpdGain
== 2) {
497 Pmin
= getPminAndPcdacTableFromTwoPowerTables(
498 &pwr_table0
[0], &pwr_table1
[0],
499 ahp
->ah_pcdacTable
, &Pmid
);
500 *pPowerMin
= (int16_t) (Pmin
/ 2);
501 *pPowerMid
= (int16_t) (Pmid
/ 2);
502 *pPowerMax
= (int16_t) (pwr_table0
[63] / 2);
503 rfXpdGain
[0] = xgainList
[0];
504 rfXpdGain
[1] = xgainList
[1];
505 } else if (minPwr_t4
<= pwr_table1
[63] &&
506 maxPwr_t4
<= pwr_table1
[63]) {
507 Pmin
= getPminAndPcdacTableFromPowerTable(
508 &pwr_table1
[0], ahp
->ah_pcdacTable
);
509 rfXpdGain
[0] = xgainList
[1];
510 rfXpdGain
[1] = rfXpdGain
[0];
511 *pPowerMin
= (int16_t) (Pmin
/ 2);
512 *pPowerMid
= (int16_t) (pwr_table1
[63] / 2);
513 *pPowerMax
= (int16_t) (pwr_table1
[63] / 2);
515 Pmin
= getPminAndPcdacTableFromPowerTable(
516 &pwr_table0
[0], ahp
->ah_pcdacTable
);
517 rfXpdGain
[0] = xgainList
[0];
518 rfXpdGain
[1] = rfXpdGain
[0];
519 *pPowerMin
= (int16_t) (Pmin
/2);
520 *pPowerMid
= (int16_t) (pwr_table0
[63] / 2);
521 *pPowerMax
= (int16_t) (pwr_table0
[63] / 2);
526 * Move 5112 rates to match power tables where the max
527 * power table entry corresponds with maxPower.
529 HALASSERT(*pPowerMax
<= PCDAC_STOP
);
530 ahp
->ah_txPowerIndexOffset
= PCDAC_STOP
- *pPowerMax
;
536 * Returns interpolated or the scaled up interpolated value
539 interpolate_signed(uint16_t target
, uint16_t srcLeft
, uint16_t srcRight
,
540 int16_t targetLeft
, int16_t targetRight
)
544 if (srcRight
!= srcLeft
) {
545 rv
= ((target
- srcLeft
)*targetRight
+
546 (srcRight
- target
)*targetLeft
) / (srcRight
- srcLeft
);
554 * Return indices surrounding the value in sorted integer lists.
556 * NB: the input list is assumed to be sorted in ascending order
559 ar5212GetLowerUpperIndex(uint16_t v
, uint16_t *lp
, uint16_t listSize
,
560 uint32_t *vlo
, uint32_t *vhi
)
563 uint16_t *ep
= lp
+listSize
;
567 * Check first and last elements for out-of-bounds conditions.
569 if (target
< lp
[0]) {
573 if (target
>= ep
[-1]) {
574 *vlo
= *vhi
= listSize
- 1;
578 /* look for value being near or between 2 values in list */
579 for (tp
= lp
; tp
< ep
; tp
++) {
581 * If value is close to the current value of the list
582 * then target is not between values, it is one of the values
585 *vlo
= *vhi
= tp
- lp
;
589 * Look for value being between current value and next value
590 * if so return these 2 values
592 if (target
< tp
[1]) {
601 getFullPwrTable(uint16_t numPcdacs
, uint16_t *pcdacs
, int16_t *power
, int16_t maxPower
, int16_t *retVals
)
608 HALDEBUG(AH_NULL
, HAL_DEBUG_ANY
,
609 "%s: at least 2 pcdac values needed [%d]\n",
610 __func__
, numPcdacs
);
613 for (ii
= 0; ii
< 64; ii
++) {
614 if (ii
>pcdacs
[idxR
] && idxR
< numPcdacs
-1) {
618 retVals
[ii
] = interpolate_signed(ii
,
619 pcdacs
[idxL
], pcdacs
[idxR
], power
[idxL
], power
[idxR
]);
620 if (retVals
[ii
] >= maxPower
) {
622 retVals
[ii
++] = maxPower
;
629 * Takes a single calibration curve and creates a power table.
630 * Adjusts the new power table so the max power is relative
631 * to the maximum index in the power table.
633 * WARNING: rates must be adjusted for this relative power table
636 getPminAndPcdacTableFromPowerTable(int16_t *pwrTableT4
, uint16_t retVals
[])
638 int16_t ii
, jj
, jjMax
;
639 int16_t pMin
, currPower
, pMax
;
641 /* If the spread is > 31.5dB, keep the upper 31.5dB range */
642 if ((pwrTableT4
[63] - pwrTableT4
[0]) > 126) {
643 pMin
= pwrTableT4
[63] - 126;
645 pMin
= pwrTableT4
[0];
648 pMax
= pwrTableT4
[63];
651 /* Search for highest pcdac 0.25dB below maxPower */
652 while ((pwrTableT4
[jjMax
] > (pMax
- 1) ) && (jjMax
>= 0)) {
658 for (ii
= 63; ii
>= 0; ii
--) {
659 while ((jj
< 64) && (jj
> 0) && (pwrTableT4
[jj
] >= currPower
)) {
664 retVals
[ii
] = retVals
[ii
+ 1];
670 currPower
-= 2; // corresponds to a 0.5dB step
676 * Combines the XPD curves from two calibration sets into a single
677 * power table and adjusts the power table so the max power is relative
678 * to the maximum index in the power table
680 * WARNING: rates must be adjusted for this relative power table
683 getPminAndPcdacTableFromTwoPowerTables(int16_t *pwrTableLXpdT4
,
684 int16_t *pwrTableHXpdT4
, uint16_t retVals
[], int16_t *pMid
)
686 int16_t ii
, jj
, jjMax
;
687 int16_t pMin
, pMax
, currPower
;
689 uint16_t msbFlag
= 0x40; // turns on the 7th bit of the pcdac
691 /* If the spread is > 31.5dB, keep the upper 31.5dB range */
692 if ((pwrTableLXpdT4
[63] - pwrTableHXpdT4
[0]) > 126) {
693 pMin
= pwrTableLXpdT4
[63] - 126;
695 pMin
= pwrTableHXpdT4
[0];
698 pMax
= pwrTableLXpdT4
[63];
700 /* Search for highest pcdac 0.25dB below maxPower */
701 while ((pwrTableLXpdT4
[jjMax
] > (pMax
- 1) ) && (jjMax
>= 0)){
705 *pMid
= pwrTableHXpdT4
[63];
709 pwrTableT4
= &(pwrTableLXpdT4
[0]);
711 if ((currPower
<= *pMid
) || ( (jj
== 0) && (msbFlag
== 0x40))){
713 pwrTableT4
= &(pwrTableHXpdT4
[0]);
716 while ((jj
> 0) && (pwrTableT4
[jj
] >= currPower
)) {
719 if ((jj
== 0) && (msbFlag
== 0x00)) {
721 retVals
[ii
] = retVals
[ii
+1];
726 retVals
[ii
] = jj
| msbFlag
;
727 currPower
-= 2; // corresponds to a 0.5dB step
734 ar5112GetMinPower(struct ath_hal
*ah
, const EXPN_DATA_PER_CHANNEL_5112
*data
)
737 int16_t minGain
,minPwr
,minPcdac
,retVal
;
739 /* Assume NUM_POINTS_XPD0 > 0 */
740 minGain
= data
->pDataPerXPD
[0].xpd_gain
;
741 for (minIndex
=0,i
=1; i
<NUM_XPD_PER_CHANNEL
; i
++) {
742 if (data
->pDataPerXPD
[i
].xpd_gain
< minGain
) {
744 minGain
= data
->pDataPerXPD
[i
].xpd_gain
;
747 minPwr
= data
->pDataPerXPD
[minIndex
].pwr_t4
[0];
748 minPcdac
= data
->pDataPerXPD
[minIndex
].pcdac
[0];
749 for (i
=1; i
<NUM_POINTS_XPD0
; i
++) {
750 if (data
->pDataPerXPD
[minIndex
].pwr_t4
[i
] < minPwr
) {
751 minPwr
= data
->pDataPerXPD
[minIndex
].pwr_t4
[i
];
752 minPcdac
= data
->pDataPerXPD
[minIndex
].pcdac
[i
];
755 retVal
= minPwr
- (minPcdac
*2);
760 ar5112GetChannelMaxMinPower(struct ath_hal
*ah
, HAL_CHANNEL
*chan
,
761 int16_t *maxPow
, int16_t *minPow
)
763 const HAL_EEPROM
*ee
= AH_PRIVATE(ah
)->ah_eeprom
;
764 int numChannels
=0,i
,last
;
765 int totalD
, totalF
,totalMin
;
766 const EXPN_DATA_PER_CHANNEL_5112
*data
=AH_NULL
;
767 const EEPROM_POWER_EXPN_5112
*powerArray
=AH_NULL
;
770 if (IS_CHAN_A(chan
)) {
771 powerArray
= ee
->ee_modePowerArray5112
;
772 data
= powerArray
[headerInfo11A
].pDataPerChannel
;
773 numChannels
= powerArray
[headerInfo11A
].numChannels
;
774 } else if (IS_CHAN_G(chan
) || IS_CHAN_108G(chan
)) {
775 /* XXX - is this correct? Should we also use the same power for turbo G? */
776 powerArray
= ee
->ee_modePowerArray5112
;
777 data
= powerArray
[headerInfo11G
].pDataPerChannel
;
778 numChannels
= powerArray
[headerInfo11G
].numChannels
;
779 } else if (IS_CHAN_B(chan
)) {
780 powerArray
= ee
->ee_modePowerArray5112
;
781 data
= powerArray
[headerInfo11B
].pDataPerChannel
;
782 numChannels
= powerArray
[headerInfo11B
].numChannels
;
786 /* Make sure the channel is in the range of the TP values
792 if ((chan
->channel
< data
[0].channelValue
) ||
793 (chan
->channel
> data
[numChannels
-1].channelValue
)) {
794 if (chan
->channel
< data
[0].channelValue
) {
795 *maxPow
= data
[0].maxPower_t4
;
796 *minPow
= ar5112GetMinPower(ah
, &data
[0]);
799 *maxPow
= data
[numChannels
- 1].maxPower_t4
;
800 *minPow
= ar5112GetMinPower(ah
, &data
[numChannels
- 1]);
805 /* Linearly interpolate the power value now */
807 (i
<numChannels
) && (chan
->channel
> data
[i
].channelValue
);
809 totalD
= data
[i
].channelValue
- data
[last
].channelValue
;
811 totalF
= data
[i
].maxPower_t4
- data
[last
].maxPower_t4
;
812 *maxPow
= (int8_t) ((totalF
*(chan
->channel
-data
[last
].channelValue
) + data
[last
].maxPower_t4
*totalD
)/totalD
);
814 totalMin
= ar5112GetMinPower(ah
,&data
[i
]) - ar5112GetMinPower(ah
, &data
[last
]);
815 *minPow
= (int8_t) ((totalMin
*(chan
->channel
-data
[last
].channelValue
) + ar5112GetMinPower(ah
, &data
[last
])*totalD
)/totalD
);
818 if (chan
->channel
== data
[i
].channelValue
) {
819 *maxPow
= data
[i
].maxPower_t4
;
820 *minPow
= ar5112GetMinPower(ah
, &data
[i
]);
828 * Free memory for analog bank scratch buffers
831 ar5112RfDetach(struct ath_hal
*ah
)
833 struct ath_hal_5212
*ahp
= AH5212(ah
);
835 HALASSERT(ahp
->ah_rfHal
!= AH_NULL
);
836 ath_hal_free(ahp
->ah_rfHal
);
837 ahp
->ah_rfHal
= AH_NULL
;
841 * Allocate memory for analog bank scratch buffers
842 * Scratch Buffer will be reinitialized every reset so no need to zero now
845 ar5112RfAttach(struct ath_hal
*ah
, HAL_STATUS
*status
)
847 struct ath_hal_5212
*ahp
= AH5212(ah
);
848 struct ar5112State
*priv
;
850 HALASSERT(ah
->ah_magic
== AR5212_MAGIC
);
852 HALASSERT(ahp
->ah_rfHal
== AH_NULL
);
853 priv
= ath_hal_malloc(sizeof(struct ar5112State
));
854 if (priv
== AH_NULL
) {
855 HALDEBUG(ah
, HAL_DEBUG_ANY
,
856 "%s: cannot allocate private state\n", __func__
);
857 *status
= HAL_ENOMEM
; /* XXX */
860 priv
->base
.rfDetach
= ar5112RfDetach
;
861 priv
->base
.writeRegs
= ar5112WriteRegs
;
862 priv
->base
.getRfBank
= ar5112GetRfBank
;
863 priv
->base
.setChannel
= ar5112SetChannel
;
864 priv
->base
.setRfRegs
= ar5112SetRfRegs
;
865 priv
->base
.setPowerTable
= ar5112SetPowerTable
;
866 priv
->base
.getChannelMaxMinPower
= ar5112GetChannelMaxMinPower
;
867 priv
->base
.getNfAdjust
= ar5212GetNfAdjust
;
869 ahp
->ah_pcdacTable
= priv
->pcdacTable
;
870 ahp
->ah_pcdacTableSize
= sizeof(priv
->pcdacTable
);
871 ahp
->ah_rfHal
= &priv
->base
;
877 ar5112Probe(struct ath_hal
*ah
)
879 return IS_RAD5112(ah
);
881 AH_RF(RF5112
, ar5112Probe
, ar5112RfAttach
);