2 * Copyright (c) 2002-2009 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 * $FreeBSD: head/sys/dev/ath/ath_hal/ar5212/ar5112.c 187831 2009-01-28 18:00:22Z sam $
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"
34 RF_HAL_FUNCS base
; /* public state, must be first */
35 uint16_t pcdacTable
[PWR_TABLE_SIZE
];
37 uint32_t Bank1Data
[NELEM(ar5212Bank1_5112
)];
38 uint32_t Bank2Data
[NELEM(ar5212Bank2_5112
)];
39 uint32_t Bank3Data
[NELEM(ar5212Bank3_5112
)];
40 uint32_t Bank6Data
[NELEM(ar5212Bank6_5112
)];
41 uint32_t Bank7Data
[NELEM(ar5212Bank7_5112
)];
43 #define AR5112(ah) ((struct ar5112State *) AH5212(ah)->ah_rfHal)
45 static void ar5212GetLowerUpperIndex(uint16_t v
,
46 uint16_t *lp
, uint16_t listSize
,
47 uint32_t *vlo
, uint32_t *vhi
);
48 static HAL_BOOL
getFullPwrTable(uint16_t numPcdacs
, uint16_t *pcdacs
,
49 int16_t *power
, int16_t maxPower
, int16_t *retVals
);
50 static int16_t getPminAndPcdacTableFromPowerTable(int16_t *pwrTableT4
,
52 static int16_t getPminAndPcdacTableFromTwoPowerTables(int16_t *pwrTableLXpdT4
,
53 int16_t *pwrTableHXpdT4
, uint16_t retVals
[], int16_t *pMid
);
54 static int16_t interpolate_signed(uint16_t target
,
55 uint16_t srcLeft
, uint16_t srcRight
,
56 int16_t targetLeft
, int16_t targetRight
);
58 extern void ar5212ModifyRfBuffer(uint32_t *rfBuf
, uint32_t reg32
,
59 uint32_t numBits
, uint32_t firstBit
, uint32_t column
);
62 ar5112WriteRegs(struct ath_hal
*ah
, u_int modesIndex
, u_int freqIndex
,
65 HAL_INI_WRITE_ARRAY(ah
, ar5212Modes_5112
, modesIndex
, writes
);
66 HAL_INI_WRITE_ARRAY(ah
, ar5212Common_5112
, 1, writes
);
67 HAL_INI_WRITE_ARRAY(ah
, ar5212BB_RfGain_5112
, freqIndex
, writes
);
71 * Take the MHz channel value and set the Channel value
73 * ASSUMES: Writes enabled to analog bus
76 ar5112SetChannel(struct ath_hal
*ah
, const struct ieee80211_channel
*chan
)
78 uint16_t freq
= ath_hal_gethwchannel(ah
, chan
);
79 uint32_t channelSel
= 0;
80 uint32_t bModeSynth
= 0;
81 uint32_t aModeRefSel
= 0;
84 OS_MARK(ah
, AH_MARK_SETCHANNEL
, freq
);
89 if (((freq
- 2192) % 5) == 0) {
90 channelSel
= ((freq
- 672) * 2 - 3040)/10;
92 } else if (((freq
- 2224) % 5) == 0) {
93 channelSel
= ((freq
- 704) * 2 - 3040) / 10;
96 HALDEBUG(ah
, HAL_DEBUG_ANY
,
97 "%s: invalid channel %u MHz\n",
102 channelSel
= (channelSel
<< 2) & 0xff;
103 channelSel
= ath_hal_reverseBits(channelSel
, 8);
105 txctl
= OS_REG_READ(ah
, AR_PHY_CCK_TX_CTRL
);
107 /* Enable channel spreading for channel 14 */
108 OS_REG_WRITE(ah
, AR_PHY_CCK_TX_CTRL
,
109 txctl
| AR_PHY_CCK_TX_CTRL_JAPAN
);
111 OS_REG_WRITE(ah
, AR_PHY_CCK_TX_CTRL
,
112 txctl
&~ AR_PHY_CCK_TX_CTRL_JAPAN
);
114 } else if (((freq
% 5) == 2) && (freq
<= 5435)) {
115 freq
= freq
- 2; /* Align to even 5MHz raster */
116 channelSel
= ath_hal_reverseBits(
117 (uint32_t)(((freq
- 4800)*10)/25 + 1), 8);
118 aModeRefSel
= ath_hal_reverseBits(0, 2);
119 } else if ((freq
% 20) == 0 && freq
>= 5120) {
120 channelSel
= ath_hal_reverseBits(
121 ((freq
- 4800) / 20 << 2), 8);
122 aModeRefSel
= ath_hal_reverseBits(3, 2);
123 } else if ((freq
% 10) == 0) {
124 channelSel
= ath_hal_reverseBits(
125 ((freq
- 4800) / 10 << 1), 8);
126 aModeRefSel
= ath_hal_reverseBits(2, 2);
127 } else if ((freq
% 5) == 0) {
128 channelSel
= ath_hal_reverseBits(
129 (freq
- 4800) / 5, 8);
130 aModeRefSel
= ath_hal_reverseBits(1, 2);
132 HALDEBUG(ah
, HAL_DEBUG_ANY
, "%s: invalid channel %u MHz\n",
137 reg32
= (channelSel
<< 4) | (aModeRefSel
<< 2) | (bModeSynth
<< 1) |
139 OS_REG_WRITE(ah
, AR_PHY(0x27), reg32
& 0xff);
142 OS_REG_WRITE(ah
, AR_PHY(0x36), reg32
& 0x7f);
144 AH_PRIVATE(ah
)->ah_curchan
= chan
;
149 * Return a reference to the requested RF Bank.
152 ar5112GetRfBank(struct ath_hal
*ah
, int bank
)
154 struct ar5112State
*priv
= AR5112(ah
);
156 HALASSERT(priv
!= AH_NULL
);
158 case 1: return priv
->Bank1Data
;
159 case 2: return priv
->Bank2Data
;
160 case 3: return priv
->Bank3Data
;
161 case 6: return priv
->Bank6Data
;
162 case 7: return priv
->Bank7Data
;
164 HALDEBUG(ah
, HAL_DEBUG_ANY
, "%s: unknown RF Bank %d requested\n",
170 * Reads EEPROM header info from device structure and programs
173 * REQUIRES: Access to the analog rf device
176 ar5112SetRfRegs(struct ath_hal
*ah
,
177 const struct ieee80211_channel
*chan
,
178 uint16_t modesIndex
, uint16_t *rfXpdGain
)
180 #define RF_BANK_SETUP(_priv, _ix, _col) do { \
182 for (i = 0; i < NELEM(ar5212Bank##_ix##_5112); i++) \
183 (_priv)->Bank##_ix##Data[i] = ar5212Bank##_ix##_5112[i][_col];\
185 uint16_t freq
= ath_hal_gethwchannel(ah
, chan
);
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 HALDEBUG(ah
, HAL_DEBUG_RFPARAM
, "%s: chan %u/0x%x modesIndex %u\n",
198 __func__
, chan
->ic_freq
, chan
->ic_flags
, modesIndex
);
200 /* Setup rf parameters */
201 switch (chan
->ic_flags
& IEEE80211_CHAN_ALLFULL
) {
202 case IEEE80211_CHAN_A
:
203 if (freq
> 4000 && freq
< 5260) {
206 } else if (freq
>= 5260 && freq
< 5500) {
209 } else if (freq
>= 5500 && freq
< 5725) {
212 } else if (freq
>= 5725) {
218 rfXpdSel
= ee
->ee_xpd
[headerInfo11A
];
219 gainI
= ee
->ee_gainI
[headerInfo11A
];
221 case IEEE80211_CHAN_B
:
222 ob2GHz
= ee
->ee_ob2GHz
[0];
223 db2GHz
= ee
->ee_db2GHz
[0];
224 rfXpdSel
= ee
->ee_xpd
[headerInfo11B
];
225 gainI
= ee
->ee_gainI
[headerInfo11B
];
227 case IEEE80211_CHAN_G
:
228 case IEEE80211_CHAN_PUREG
: /* NB: really 108G */
229 ob2GHz
= ee
->ee_ob2GHz
[1];
230 db2GHz
= ee
->ee_ob2GHz
[1];
231 rfXpdSel
= ee
->ee_xpd
[headerInfo11G
];
232 gainI
= ee
->ee_gainI
[headerInfo11G
];
235 HALDEBUG(ah
, HAL_DEBUG_ANY
, "%s: invalid channel flags 0x%x\n",
236 __func__
, chan
->ic_flags
);
240 /* Setup Bank 1 Write */
241 RF_BANK_SETUP(priv
, 1, 1);
243 /* Setup Bank 2 Write */
244 RF_BANK_SETUP(priv
, 2, modesIndex
);
246 /* Setup Bank 3 Write */
247 RF_BANK_SETUP(priv
, 3, modesIndex
);
249 /* Setup Bank 6 Write */
250 RF_BANK_SETUP(priv
, 6, modesIndex
);
252 ar5212ModifyRfBuffer(priv
->Bank6Data
, rfXpdSel
, 1, 302, 0);
254 ar5212ModifyRfBuffer(priv
->Bank6Data
, rfXpdGain
[0], 2, 270, 0);
255 ar5212ModifyRfBuffer(priv
->Bank6Data
, rfXpdGain
[1], 2, 257, 0);
257 if (IEEE80211_IS_CHAN_OFDM(chan
)) {
258 ar5212ModifyRfBuffer(priv
->Bank6Data
,
259 gv
->currStep
->paramVal
[GP_PWD_138
], 1, 168, 3);
260 ar5212ModifyRfBuffer(priv
->Bank6Data
,
261 gv
->currStep
->paramVal
[GP_PWD_137
], 1, 169, 3);
262 ar5212ModifyRfBuffer(priv
->Bank6Data
,
263 gv
->currStep
->paramVal
[GP_PWD_136
], 1, 170, 3);
264 ar5212ModifyRfBuffer(priv
->Bank6Data
,
265 gv
->currStep
->paramVal
[GP_PWD_132
], 1, 174, 3);
266 ar5212ModifyRfBuffer(priv
->Bank6Data
,
267 gv
->currStep
->paramVal
[GP_PWD_131
], 1, 175, 3);
268 ar5212ModifyRfBuffer(priv
->Bank6Data
,
269 gv
->currStep
->paramVal
[GP_PWD_130
], 1, 176, 3);
272 /* Only the 5 or 2 GHz OB/DB need to be set for a mode */
273 if (IEEE80211_IS_CHAN_2GHZ(chan
)) {
274 ar5212ModifyRfBuffer(priv
->Bank6Data
, ob2GHz
, 3, 287, 0);
275 ar5212ModifyRfBuffer(priv
->Bank6Data
, db2GHz
, 3, 290, 0);
277 ar5212ModifyRfBuffer(priv
->Bank6Data
, ob5GHz
, 3, 279, 0);
278 ar5212ModifyRfBuffer(priv
->Bank6Data
, db5GHz
, 3, 282, 0);
281 /* Lower synth voltage for X112 Rev 2.0 only */
282 if (IS_RADX112_REV2(ah
)) {
283 /* Non-Reversed analyg registers - so values are pre-reversed */
284 ar5212ModifyRfBuffer(priv
->Bank6Data
, 2, 2, 90, 2);
285 ar5212ModifyRfBuffer(priv
->Bank6Data
, 2, 2, 92, 2);
286 ar5212ModifyRfBuffer(priv
->Bank6Data
, 2, 2, 94, 2);
287 ar5212ModifyRfBuffer(priv
->Bank6Data
, 2, 1, 254, 2);
290 /* Decrease Power Consumption for 5312/5213 and up */
291 if (AH_PRIVATE(ah
)->ah_phyRev
>= AR_PHY_CHIP_ID_REV_2
) {
292 ar5212ModifyRfBuffer(priv
->Bank6Data
, 1, 1, 281, 1);
293 ar5212ModifyRfBuffer(priv
->Bank6Data
, 1, 2, 1, 3);
294 ar5212ModifyRfBuffer(priv
->Bank6Data
, 1, 2, 3, 3);
295 ar5212ModifyRfBuffer(priv
->Bank6Data
, 1, 1, 139, 3);
296 ar5212ModifyRfBuffer(priv
->Bank6Data
, 1, 1, 140, 3);
299 /* Setup Bank 7 Setup */
300 RF_BANK_SETUP(priv
, 7, modesIndex
);
301 if (IEEE80211_IS_CHAN_OFDM(chan
))
302 ar5212ModifyRfBuffer(priv
->Bank7Data
,
303 gv
->currStep
->paramVal
[GP_MIXGAIN_OVR
], 2, 37, 0);
305 ar5212ModifyRfBuffer(priv
->Bank7Data
, gainI
, 6, 14, 0);
307 /* Adjust params for Derby TX power control */
308 if (IEEE80211_IS_CHAN_HALF(chan
) || IEEE80211_IS_CHAN_QUARTER(chan
)) {
309 uint32_t rfDelay
, rfPeriod
;
312 rfPeriod
= (IEEE80211_IS_CHAN_HALF(chan
)) ? 0x8 : 0xf;
313 ar5212ModifyRfBuffer(priv
->Bank7Data
, rfDelay
, 4, 58, 0);
314 ar5212ModifyRfBuffer(priv
->Bank7Data
, rfPeriod
, 4, 70, 0);
318 /* Analog registers are setup - EAR can modify */
319 if (ar5212IsEarEngaged(pDev
, chan
))
321 ar5212EarModify(pDev
, EAR_LC_RF_WRITE
, chan
, &modifier
);
323 /* Write Analog registers */
324 HAL_INI_WRITE_BANK(ah
, ar5212Bank1_5112
, priv
->Bank1Data
, regWrites
);
325 HAL_INI_WRITE_BANK(ah
, ar5212Bank2_5112
, priv
->Bank2Data
, regWrites
);
326 HAL_INI_WRITE_BANK(ah
, ar5212Bank3_5112
, priv
->Bank3Data
, regWrites
);
327 HAL_INI_WRITE_BANK(ah
, ar5212Bank6_5112
, priv
->Bank6Data
, regWrites
);
328 HAL_INI_WRITE_BANK(ah
, ar5212Bank7_5112
, priv
->Bank7Data
, regWrites
);
330 /* Now that we have reprogrammed rfgain value, clear the flag. */
331 ahp
->ah_rfgainState
= HAL_RFGAIN_INACTIVE
;
337 * Read the transmit power levels from the structures taken from EEPROM
338 * Interpolate read transmit power values for this channel
339 * Organize the transmit power values into a table for writing into the hardware
342 ar5112SetPowerTable(struct ath_hal
*ah
,
343 int16_t *pPowerMin
, int16_t *pPowerMax
,
344 const struct ieee80211_channel
*chan
,
347 uint16_t freq
= ath_hal_gethwchannel(ah
, chan
);
348 struct ath_hal_5212
*ahp
= AH5212(ah
);
349 const HAL_EEPROM
*ee
= AH_PRIVATE(ah
)->ah_eeprom
;
350 uint32_t numXpdGain
= IS_RADX112_REV2(ah
) ? 2 : 1;
351 uint32_t xpdGainMask
= 0;
352 int16_t powerMid
, *pPowerMid
= &powerMid
;
354 const EXPN_DATA_PER_CHANNEL_5112
*pRawCh
;
355 const EEPROM_POWER_EXPN_5112
*pPowerExpn
= AH_NULL
;
358 int16_t minPwr_t4
, maxPwr_t4
, Pmin
, Pmid
;
360 uint32_t chan_idx_L
= 0, chan_idx_R
= 0;
361 uint16_t chan_L
, chan_R
;
363 int16_t pwr_table0
[64];
364 int16_t pwr_table1
[64];
368 int16_t powTableLXPD
[2][64];
369 int16_t powTableHXPD
[2][64];
370 int16_t tmpPowerTable
[64];
371 uint16_t xgainList
[2];
374 switch (chan
->ic_flags
& IEEE80211_CHAN_ALLTURBOFULL
) {
375 case IEEE80211_CHAN_A
:
376 case IEEE80211_CHAN_ST
:
377 pPowerExpn
= &ee
->ee_modePowerArray5112
[headerInfo11A
];
378 xpdGainMask
= ee
->ee_xgain
[headerInfo11A
];
380 case IEEE80211_CHAN_B
:
381 pPowerExpn
= &ee
->ee_modePowerArray5112
[headerInfo11B
];
382 xpdGainMask
= ee
->ee_xgain
[headerInfo11B
];
384 case IEEE80211_CHAN_G
:
385 case IEEE80211_CHAN_108G
:
386 pPowerExpn
= &ee
->ee_modePowerArray5112
[headerInfo11G
];
387 xpdGainMask
= ee
->ee_xgain
[headerInfo11G
];
390 HALDEBUG(ah
, HAL_DEBUG_ANY
, "%s: unknown channel flags 0x%x\n",
391 __func__
, chan
->ic_flags
);
395 if ((xpdGainMask
& pPowerExpn
->xpdMask
) < 1) {
396 HALDEBUG(ah
, HAL_DEBUG_ANY
,
397 "%s: desired xpdGainMask 0x%x not supported by "
398 "calibrated xpdMask 0x%x\n", __func__
,
399 xpdGainMask
, pPowerExpn
->xpdMask
);
403 maxPwr_t4
= (int16_t)(2*(*pPowerMax
)); /* pwr_t2 -> pwr_t4 */
404 minPwr_t4
= (int16_t)(2*(*pPowerMin
)); /* pwr_t2 -> pwr_t4 */
406 xgainList
[0] = 0xDEAD;
407 xgainList
[1] = 0xDEAD;
410 xpdMask
= pPowerExpn
->xpdMask
;
411 for (jj
= 0; jj
< NUM_XPD_PER_CHANNEL
; jj
++) {
412 if (((xpdMask
>> jj
) & 1) > 0) {
414 HALDEBUG(ah
, HAL_DEBUG_ANY
,
415 "A maximum of 2 xpdGains supported"
416 "in pExpnPower data\n");
419 xgainList
[kk
++] = (uint16_t)jj
;
423 ar5212GetLowerUpperIndex(freq
, &pPowerExpn
->pChannels
[0],
424 pPowerExpn
->numChannels
, &chan_idx_L
, &chan_idx_R
);
427 for (ii
= chan_idx_L
; ii
<= chan_idx_R
; ii
++) {
428 pRawCh
= &(pPowerExpn
->pDataPerChannel
[ii
]);
429 if (xgainList
[1] == 0xDEAD) {
431 numPcd
= pRawCh
->pDataPerXPD
[jj
].numPcdacs
;
432 OS_MEMCPY(&pcdacs
[0], &pRawCh
->pDataPerXPD
[jj
].pcdac
[0],
433 numPcd
* sizeof(uint16_t));
434 OS_MEMCPY(&powers
[0], &pRawCh
->pDataPerXPD
[jj
].pwr_t4
[0],
435 numPcd
* sizeof(int16_t));
436 if (!getFullPwrTable(numPcd
, &pcdacs
[0], &powers
[0],
437 pRawCh
->maxPower_t4
, &tmpPowerTable
[0])) {
440 OS_MEMCPY(&powTableLXPD
[kk
][0], &tmpPowerTable
[0],
444 numPcd
= pRawCh
->pDataPerXPD
[jj
].numPcdacs
;
445 OS_MEMCPY(&pcdacs
[0], &pRawCh
->pDataPerXPD
[jj
].pcdac
[0],
446 numPcd
*sizeof(uint16_t));
447 OS_MEMCPY(&powers
[0],
448 &pRawCh
->pDataPerXPD
[jj
].pwr_t4
[0],
449 numPcd
*sizeof(int16_t));
450 if (!getFullPwrTable(numPcd
, &pcdacs
[0], &powers
[0],
451 pRawCh
->maxPower_t4
, &tmpPowerTable
[0])) {
454 OS_MEMCPY(&powTableLXPD
[kk
][0], &tmpPowerTable
[0],
455 64 * sizeof(int16_t));
458 numPcd
= pRawCh
->pDataPerXPD
[jj
].numPcdacs
;
459 OS_MEMCPY(&pcdacs
[0], &pRawCh
->pDataPerXPD
[jj
].pcdac
[0],
460 numPcd
* sizeof(uint16_t));
461 OS_MEMCPY(&powers
[0],
462 &pRawCh
->pDataPerXPD
[jj
].pwr_t4
[0],
463 numPcd
* sizeof(int16_t));
464 if (!getFullPwrTable(numPcd
, &pcdacs
[0], &powers
[0],
465 pRawCh
->maxPower_t4
, &tmpPowerTable
[0])) {
468 OS_MEMCPY(&powTableHXPD
[kk
][0], &tmpPowerTable
[0],
469 64 * sizeof(int16_t));
474 chan_L
= pPowerExpn
->pChannels
[chan_idx_L
];
475 chan_R
= pPowerExpn
->pChannels
[chan_idx_R
];
476 kk
= chan_idx_R
- chan_idx_L
;
478 if (xgainList
[1] == 0xDEAD) {
479 for (jj
= 0; jj
< 64; jj
++) {
480 pwr_table0
[jj
] = interpolate_signed(
481 freq
, chan_L
, chan_R
,
482 powTableLXPD
[0][jj
], powTableLXPD
[kk
][jj
]);
484 Pmin
= getPminAndPcdacTableFromPowerTable(&pwr_table0
[0],
486 *pPowerMin
= (int16_t) (Pmin
/ 2);
487 *pPowerMid
= (int16_t) (pwr_table0
[63] / 2);
488 *pPowerMax
= (int16_t) (pwr_table0
[63] / 2);
489 rfXpdGain
[0] = xgainList
[0];
490 rfXpdGain
[1] = rfXpdGain
[0];
492 for (jj
= 0; jj
< 64; jj
++) {
493 pwr_table0
[jj
] = interpolate_signed(
494 freq
, chan_L
, chan_R
,
495 powTableLXPD
[0][jj
], powTableLXPD
[kk
][jj
]);
496 pwr_table1
[jj
] = interpolate_signed(
497 freq
, chan_L
, chan_R
,
498 powTableHXPD
[0][jj
], powTableHXPD
[kk
][jj
]);
500 if (numXpdGain
== 2) {
501 Pmin
= getPminAndPcdacTableFromTwoPowerTables(
502 &pwr_table0
[0], &pwr_table1
[0],
503 ahp
->ah_pcdacTable
, &Pmid
);
504 *pPowerMin
= (int16_t) (Pmin
/ 2);
505 *pPowerMid
= (int16_t) (Pmid
/ 2);
506 *pPowerMax
= (int16_t) (pwr_table0
[63] / 2);
507 rfXpdGain
[0] = xgainList
[0];
508 rfXpdGain
[1] = xgainList
[1];
509 } else if (minPwr_t4
<= pwr_table1
[63] &&
510 maxPwr_t4
<= pwr_table1
[63]) {
511 Pmin
= getPminAndPcdacTableFromPowerTable(
512 &pwr_table1
[0], ahp
->ah_pcdacTable
);
513 rfXpdGain
[0] = xgainList
[1];
514 rfXpdGain
[1] = rfXpdGain
[0];
515 *pPowerMin
= (int16_t) (Pmin
/ 2);
516 *pPowerMid
= (int16_t) (pwr_table1
[63] / 2);
517 *pPowerMax
= (int16_t) (pwr_table1
[63] / 2);
519 Pmin
= getPminAndPcdacTableFromPowerTable(
520 &pwr_table0
[0], ahp
->ah_pcdacTable
);
521 rfXpdGain
[0] = xgainList
[0];
522 rfXpdGain
[1] = rfXpdGain
[0];
523 *pPowerMin
= (int16_t) (Pmin
/2);
524 *pPowerMid
= (int16_t) (pwr_table0
[63] / 2);
525 *pPowerMax
= (int16_t) (pwr_table0
[63] / 2);
530 * Move 5112 rates to match power tables where the max
531 * power table entry corresponds with maxPower.
533 HALASSERT(*pPowerMax
<= PCDAC_STOP
);
534 ahp
->ah_txPowerIndexOffset
= PCDAC_STOP
- *pPowerMax
;
540 * Returns interpolated or the scaled up interpolated value
543 interpolate_signed(uint16_t target
, uint16_t srcLeft
, uint16_t srcRight
,
544 int16_t targetLeft
, int16_t targetRight
)
548 if (srcRight
!= srcLeft
) {
549 rv
= ((target
- srcLeft
)*targetRight
+
550 (srcRight
- target
)*targetLeft
) / (srcRight
- srcLeft
);
558 * Return indices surrounding the value in sorted integer lists.
560 * NB: the input list is assumed to be sorted in ascending order
563 ar5212GetLowerUpperIndex(uint16_t v
, uint16_t *lp
, uint16_t listSize
,
564 uint32_t *vlo
, uint32_t *vhi
)
567 uint16_t *ep
= lp
+listSize
;
571 * Check first and last elements for out-of-bounds conditions.
573 if (target
< lp
[0]) {
577 if (target
>= ep
[-1]) {
578 *vlo
= *vhi
= listSize
- 1;
582 /* look for value being near or between 2 values in list */
583 for (tp
= lp
; tp
< ep
; tp
++) {
585 * If value is close to the current value of the list
586 * then target is not between values, it is one of the values
589 *vlo
= *vhi
= tp
- lp
;
593 * Look for value being between current value and next value
594 * if so return these 2 values
596 if (target
< tp
[1]) {
605 getFullPwrTable(uint16_t numPcdacs
, uint16_t *pcdacs
, int16_t *power
, int16_t maxPower
, int16_t *retVals
)
612 HALDEBUG(AH_NULL
, HAL_DEBUG_ANY
,
613 "%s: at least 2 pcdac values needed [%d]\n",
614 __func__
, numPcdacs
);
617 for (ii
= 0; ii
< 64; ii
++) {
618 if (ii
>pcdacs
[idxR
] && idxR
< numPcdacs
-1) {
622 retVals
[ii
] = interpolate_signed(ii
,
623 pcdacs
[idxL
], pcdacs
[idxR
], power
[idxL
], power
[idxR
]);
624 if (retVals
[ii
] >= maxPower
) {
626 retVals
[ii
++] = maxPower
;
633 * Takes a single calibration curve and creates a power table.
634 * Adjusts the new power table so the max power is relative
635 * to the maximum index in the power table.
637 * WARNING: rates must be adjusted for this relative power table
640 getPminAndPcdacTableFromPowerTable(int16_t *pwrTableT4
, uint16_t retVals
[])
642 int16_t ii
, jj
, jjMax
;
643 int16_t pMin
, currPower
, pMax
;
645 /* If the spread is > 31.5dB, keep the upper 31.5dB range */
646 if ((pwrTableT4
[63] - pwrTableT4
[0]) > 126) {
647 pMin
= pwrTableT4
[63] - 126;
649 pMin
= pwrTableT4
[0];
652 pMax
= pwrTableT4
[63];
655 /* Search for highest pcdac 0.25dB below maxPower */
656 while ((pwrTableT4
[jjMax
] > (pMax
- 1) ) && (jjMax
>= 0)) {
662 for (ii
= 63; ii
>= 0; ii
--) {
663 while ((jj
< 64) && (jj
> 0) && (pwrTableT4
[jj
] >= currPower
)) {
668 retVals
[ii
] = retVals
[ii
+ 1];
674 currPower
-= 2; // corresponds to a 0.5dB step
680 * Combines the XPD curves from two calibration sets into a single
681 * power table and adjusts the power table so the max power is relative
682 * to the maximum index in the power table
684 * WARNING: rates must be adjusted for this relative power table
687 getPminAndPcdacTableFromTwoPowerTables(int16_t *pwrTableLXpdT4
,
688 int16_t *pwrTableHXpdT4
, uint16_t retVals
[], int16_t *pMid
)
690 int16_t ii
, jj
, jjMax
;
691 int16_t pMin
, pMax
, currPower
;
693 uint16_t msbFlag
= 0x40; // turns on the 7th bit of the pcdac
695 /* If the spread is > 31.5dB, keep the upper 31.5dB range */
696 if ((pwrTableLXpdT4
[63] - pwrTableHXpdT4
[0]) > 126) {
697 pMin
= pwrTableLXpdT4
[63] - 126;
699 pMin
= pwrTableHXpdT4
[0];
702 pMax
= pwrTableLXpdT4
[63];
704 /* Search for highest pcdac 0.25dB below maxPower */
705 while ((pwrTableLXpdT4
[jjMax
] > (pMax
- 1) ) && (jjMax
>= 0)){
709 *pMid
= pwrTableHXpdT4
[63];
713 pwrTableT4
= &(pwrTableLXpdT4
[0]);
715 if ((currPower
<= *pMid
) || ( (jj
== 0) && (msbFlag
== 0x40))){
717 pwrTableT4
= &(pwrTableHXpdT4
[0]);
720 while ((jj
> 0) && (pwrTableT4
[jj
] >= currPower
)) {
723 if ((jj
== 0) && (msbFlag
== 0x00)) {
725 retVals
[ii
] = retVals
[ii
+1];
730 retVals
[ii
] = jj
| msbFlag
;
731 currPower
-= 2; // corresponds to a 0.5dB step
738 ar5112GetMinPower(struct ath_hal
*ah
, const EXPN_DATA_PER_CHANNEL_5112
*data
)
741 int16_t minGain
,minPwr
,minPcdac
,retVal
;
743 /* Assume NUM_POINTS_XPD0 > 0 */
744 minGain
= data
->pDataPerXPD
[0].xpd_gain
;
745 for (minIndex
=0,i
=1; i
<NUM_XPD_PER_CHANNEL
; i
++) {
746 if (data
->pDataPerXPD
[i
].xpd_gain
< minGain
) {
748 minGain
= data
->pDataPerXPD
[i
].xpd_gain
;
751 minPwr
= data
->pDataPerXPD
[minIndex
].pwr_t4
[0];
752 minPcdac
= data
->pDataPerXPD
[minIndex
].pcdac
[0];
753 for (i
=1; i
<NUM_POINTS_XPD0
; i
++) {
754 if (data
->pDataPerXPD
[minIndex
].pwr_t4
[i
] < minPwr
) {
755 minPwr
= data
->pDataPerXPD
[minIndex
].pwr_t4
[i
];
756 minPcdac
= data
->pDataPerXPD
[minIndex
].pcdac
[i
];
759 retVal
= minPwr
- (minPcdac
*2);
764 ar5112GetChannelMaxMinPower(struct ath_hal
*ah
,
765 const struct ieee80211_channel
*chan
,
766 int16_t *maxPow
, int16_t *minPow
)
768 uint16_t freq
= chan
->ic_freq
; /* NB: never mapped */
769 const HAL_EEPROM
*ee
= AH_PRIVATE(ah
)->ah_eeprom
;
770 int numChannels
=0,i
,last
;
771 int totalD
, totalF
,totalMin
;
772 const EXPN_DATA_PER_CHANNEL_5112
*data
=AH_NULL
;
773 const EEPROM_POWER_EXPN_5112
*powerArray
=AH_NULL
;
776 if (IEEE80211_IS_CHAN_A(chan
)) {
777 powerArray
= ee
->ee_modePowerArray5112
;
778 data
= powerArray
[headerInfo11A
].pDataPerChannel
;
779 numChannels
= powerArray
[headerInfo11A
].numChannels
;
780 } else if (IEEE80211_IS_CHAN_G(chan
) || IEEE80211_IS_CHAN_108G(chan
)) {
781 /* XXX - is this correct? Should we also use the same power for turbo G? */
782 powerArray
= ee
->ee_modePowerArray5112
;
783 data
= powerArray
[headerInfo11G
].pDataPerChannel
;
784 numChannels
= powerArray
[headerInfo11G
].numChannels
;
785 } else if (IEEE80211_IS_CHAN_B(chan
)) {
786 powerArray
= ee
->ee_modePowerArray5112
;
787 data
= powerArray
[headerInfo11B
].pDataPerChannel
;
788 numChannels
= powerArray
[headerInfo11B
].numChannels
;
792 /* Make sure the channel is in the range of the TP values
798 if ((freq
< data
[0].channelValue
) ||
799 (freq
> data
[numChannels
-1].channelValue
)) {
800 if (freq
< data
[0].channelValue
) {
801 *maxPow
= data
[0].maxPower_t4
;
802 *minPow
= ar5112GetMinPower(ah
, &data
[0]);
805 *maxPow
= data
[numChannels
- 1].maxPower_t4
;
806 *minPow
= ar5112GetMinPower(ah
, &data
[numChannels
- 1]);
811 /* Linearly interpolate the power value now */
813 (i
<numChannels
) && (freq
> data
[i
].channelValue
);
815 totalD
= data
[i
].channelValue
- data
[last
].channelValue
;
817 totalF
= data
[i
].maxPower_t4
- data
[last
].maxPower_t4
;
818 *maxPow
= (int8_t) ((totalF
*(freq
-data
[last
].channelValue
) + data
[last
].maxPower_t4
*totalD
)/totalD
);
820 totalMin
= ar5112GetMinPower(ah
,&data
[i
]) - ar5112GetMinPower(ah
, &data
[last
]);
821 *minPow
= (int8_t) ((totalMin
*(freq
-data
[last
].channelValue
) + ar5112GetMinPower(ah
, &data
[last
])*totalD
)/totalD
);
824 if (freq
== data
[i
].channelValue
) {
825 *maxPow
= data
[i
].maxPower_t4
;
826 *minPow
= ar5112GetMinPower(ah
, &data
[i
]);
834 * Free memory for analog bank scratch buffers
837 ar5112RfDetach(struct ath_hal
*ah
)
839 struct ath_hal_5212
*ahp
= AH5212(ah
);
841 HALASSERT(ahp
->ah_rfHal
!= AH_NULL
);
842 ath_hal_free(ahp
->ah_rfHal
);
843 ahp
->ah_rfHal
= AH_NULL
;
847 * Allocate memory for analog bank scratch buffers
848 * Scratch Buffer will be reinitialized every reset so no need to zero now
851 ar5112RfAttach(struct ath_hal
*ah
, HAL_STATUS
*status
)
853 struct ath_hal_5212
*ahp
= AH5212(ah
);
854 struct ar5112State
*priv
;
856 HALASSERT(ah
->ah_magic
== AR5212_MAGIC
);
858 HALASSERT(ahp
->ah_rfHal
== AH_NULL
);
859 priv
= ath_hal_malloc(sizeof(struct ar5112State
));
860 if (priv
== AH_NULL
) {
861 HALDEBUG(ah
, HAL_DEBUG_ANY
,
862 "%s: cannot allocate private state\n", __func__
);
863 *status
= HAL_ENOMEM
; /* XXX */
866 priv
->base
.rfDetach
= ar5112RfDetach
;
867 priv
->base
.writeRegs
= ar5112WriteRegs
;
868 priv
->base
.getRfBank
= ar5112GetRfBank
;
869 priv
->base
.setChannel
= ar5112SetChannel
;
870 priv
->base
.setRfRegs
= ar5112SetRfRegs
;
871 priv
->base
.setPowerTable
= ar5112SetPowerTable
;
872 priv
->base
.getChannelMaxMinPower
= ar5112GetChannelMaxMinPower
;
873 priv
->base
.getNfAdjust
= ar5212GetNfAdjust
;
875 ahp
->ah_pcdacTable
= priv
->pcdacTable
;
876 ahp
->ah_pcdacTableSize
= sizeof(priv
->pcdacTable
);
877 ahp
->ah_rfHal
= &priv
->base
;
883 ar5112Probe(struct ath_hal
*ah
)
885 return IS_RAD5112(ah
);
887 AH_RF(RF5112
, ar5112Probe
, ar5112RfAttach
);