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: ar2133.c,v 1.1.1.1 2008/12/11 04:46:46 alc Exp $
22 #include "ah_internal.h"
24 #include "ah_eeprom_v14.h"
26 #include "ar5416/ar5416.h"
27 #include "ar5416/ar5416reg.h"
28 #include "ar5416/ar5416phy.h"
30 #define N(a) (sizeof(a)/sizeof(a[0]))
33 RF_HAL_FUNCS base
; /* public state, must be first */
34 uint16_t pcdacTable
[1];
43 /* NB: Bank*Data storage follows */
45 #define AR2133(ah) ((struct ar2133State *) AH5212(ah)->ah_rfHal)
47 #define ar5416ModifyRfBuffer ar5212ModifyRfBuffer /*XXX*/
49 extern void ar5416ModifyRfBuffer(uint32_t *rfBuf
, uint32_t reg32
,
50 uint32_t numBits
, uint32_t firstBit
, uint32_t column
);
51 HAL_BOOL
ar2133GetChipPowerLimits(struct ath_hal
*ah
, HAL_CHANNEL
52 *chans
, uint32_t nchans
);
54 static HAL_BOOL
ar2133GetChannelMaxMinPower(struct ath_hal
*, HAL_CHANNEL
*,
55 int16_t *maxPow
,int16_t *minPow
);
56 int16_t ar2133GetNfAdjust(struct ath_hal
*ah
, const HAL_CHANNEL_INTERNAL
*c
);
59 ar2133WriteRegs(struct ath_hal
*ah
, u_int modesIndex
, u_int freqIndex
,
62 (void) ath_hal_ini_write(ah
, &AH5416(ah
)->ah_ini_bb_rfgain
,
67 * Take the MHz channel value and set the Channel value
69 * ASSUMES: Writes enabled to analog bus
72 ar2133SetChannel(struct ath_hal
*ah
, HAL_CHANNEL_INTERNAL
*chan
)
74 uint32_t channelSel
= 0;
75 uint32_t bModeSynth
= 0;
76 uint32_t aModeRefSel
= 0;
81 OS_MARK(ah
, AH_MARK_SETCHANNEL
, chan
->channel
);
83 ar5416GetChannelCenters(ah
, chan
, ¢ers
);
84 freq
= centers
.synth_center
;
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", __func__
, freq
);
101 channelSel
= (channelSel
<< 2) & 0xff;
102 channelSel
= ath_hal_reverseBits(channelSel
, 8);
104 txctl
= OS_REG_READ(ah
, AR_PHY_CCK_TX_CTRL
);
106 /* Enable channel spreading for channel 14 */
107 OS_REG_WRITE(ah
, AR_PHY_CCK_TX_CTRL
,
108 txctl
| AR_PHY_CCK_TX_CTRL_JAPAN
);
110 OS_REG_WRITE(ah
, AR_PHY_CCK_TX_CTRL
,
111 txctl
&~ AR_PHY_CCK_TX_CTRL_JAPAN
);
113 } else if ((freq
% 20) == 0 && freq
>= 5120) {
114 channelSel
= ath_hal_reverseBits(((freq
- 4800) / 20 << 2), 8);
115 if (AR_SREV_SOWL_10_OR_LATER(ah
))
116 aModeRefSel
= ath_hal_reverseBits(3, 2);
118 aModeRefSel
= ath_hal_reverseBits(1, 2);
119 } else if ((freq
% 10) == 0) {
120 channelSel
= ath_hal_reverseBits(((freq
- 4800) / 10 << 1), 8);
121 if (AR_SREV_SOWL_10_OR_LATER(ah
))
122 aModeRefSel
= ath_hal_reverseBits(2, 2);
124 aModeRefSel
= ath_hal_reverseBits(1, 2);
125 } else if ((freq
% 5) == 0) {
126 channelSel
= ath_hal_reverseBits((freq
- 4800) / 5, 8);
127 aModeRefSel
= ath_hal_reverseBits(1, 2);
129 HALDEBUG(ah
, HAL_DEBUG_ANY
, "%s: invalid channel %u MHz\n",
134 reg32
= (channelSel
<< 8) | (aModeRefSel
<< 2) | (bModeSynth
<< 1) |
137 OS_REG_WRITE(ah
, AR_PHY(0x37), reg32
);
139 AH_PRIVATE(ah
)->ah_curchan
= chan
;
145 * Return a reference to the requested RF Bank.
148 ar2133GetRfBank(struct ath_hal
*ah
, int bank
)
150 struct ar2133State
*priv
= AR2133(ah
);
152 HALASSERT(priv
!= AH_NULL
);
154 case 1: return priv
->Bank1Data
;
155 case 2: return priv
->Bank2Data
;
156 case 3: return priv
->Bank3Data
;
157 case 6: return priv
->Bank6Data
;
158 case 7: return priv
->Bank7Data
;
160 HALDEBUG(ah
, HAL_DEBUG_ANY
, "%s: unknown RF Bank %d requested\n",
166 * Reads EEPROM header info from device structure and programs
169 * REQUIRES: Access to the analog rf device
172 ar2133SetRfRegs(struct ath_hal
*ah
, HAL_CHANNEL_INTERNAL
*chan
,
173 uint16_t modesIndex
, uint16_t *rfXpdGain
)
175 struct ar2133State
*priv
= AR2133(ah
);
180 /* Setup Bank 0 Write */
181 ath_hal_ini_bank_setup(priv
->Bank0Data
, &AH5416(ah
)->ah_ini_bank0
, 1);
183 /* Setup Bank 1 Write */
184 ath_hal_ini_bank_setup(priv
->Bank1Data
, &AH5416(ah
)->ah_ini_bank1
, 1);
186 /* Setup Bank 2 Write */
187 ath_hal_ini_bank_setup(priv
->Bank2Data
, &AH5416(ah
)->ah_ini_bank2
, 1);
189 /* Setup Bank 3 Write */
190 ath_hal_ini_bank_setup(priv
->Bank3Data
, &AH5416(ah
)->ah_ini_bank3
, modesIndex
);
192 /* Setup Bank 6 Write */
193 ath_hal_ini_bank_setup(priv
->Bank6Data
, &AH5416(ah
)->ah_ini_bank6
, modesIndex
);
195 /* Only the 5 or 2 GHz OB/DB need to be set for a mode */
196 if (IS_CHAN_2GHZ(chan
)) {
197 ar5416ModifyRfBuffer(priv
->Bank6Data
,
198 ath_hal_eepromGet(ah
, AR_EEP_OB_2
, AH_NULL
), 3, 197, 0);
199 ar5416ModifyRfBuffer(priv
->Bank6Data
,
200 ath_hal_eepromGet(ah
, AR_EEP_DB_2
, AH_NULL
), 3, 194, 0);
202 ar5416ModifyRfBuffer(priv
->Bank6Data
,
203 ath_hal_eepromGet(ah
, AR_EEP_OB_5
, AH_NULL
), 3, 203, 0);
204 ar5416ModifyRfBuffer(priv
->Bank6Data
,
205 ath_hal_eepromGet(ah
, AR_EEP_DB_5
, AH_NULL
), 3, 200, 0);
207 /* Setup Bank 7 Setup */
208 ath_hal_ini_bank_setup(priv
->Bank7Data
, &AH5416(ah
)->ah_ini_bank7
, 1);
210 /* Write Analog registers */
211 writes
= ath_hal_ini_bank_write(ah
, &AH5416(ah
)->ah_ini_bank0
,
213 writes
= ath_hal_ini_bank_write(ah
, &AH5416(ah
)->ah_ini_bank1
,
214 priv
->Bank1Data
, writes
);
215 writes
= ath_hal_ini_bank_write(ah
, &AH5416(ah
)->ah_ini_bank2
,
216 priv
->Bank2Data
, writes
);
217 writes
= ath_hal_ini_bank_write(ah
, &AH5416(ah
)->ah_ini_bank3
,
218 priv
->Bank3Data
, writes
);
219 writes
= ath_hal_ini_bank_write(ah
, &AH5416(ah
)->ah_ini_bank6
,
220 priv
->Bank6Data
, writes
);
221 (void) ath_hal_ini_bank_write(ah
, &AH5416(ah
)->ah_ini_bank7
,
222 priv
->Bank7Data
, writes
);
229 * Read the transmit power levels from the structures taken from EEPROM
230 * Interpolate read transmit power values for this channel
231 * Organize the transmit power values into a table for writing into the hardware
235 ar2133SetPowerTable(struct ath_hal
*ah
, int16_t *pPowerMin
, int16_t *pPowerMax
,
236 HAL_CHANNEL_INTERNAL
*chan
, uint16_t *rfXpdGain
)
243 ar2133GetMinPower(struct ath_hal
*ah
, EXPN_DATA_PER_CHANNEL_5112
*data
)
246 int16_t minGain
,minPwr
,minPcdac
,retVal
;
248 /* Assume NUM_POINTS_XPD0 > 0 */
249 minGain
= data
->pDataPerXPD
[0].xpd_gain
;
250 for (minIndex
=0,i
=1; i
<NUM_XPD_PER_CHANNEL
; i
++) {
251 if (data
->pDataPerXPD
[i
].xpd_gain
< minGain
) {
253 minGain
= data
->pDataPerXPD
[i
].xpd_gain
;
256 minPwr
= data
->pDataPerXPD
[minIndex
].pwr_t4
[0];
257 minPcdac
= data
->pDataPerXPD
[minIndex
].pcdac
[0];
258 for (i
=1; i
<NUM_POINTS_XPD0
; i
++) {
259 if (data
->pDataPerXPD
[minIndex
].pwr_t4
[i
] < minPwr
) {
260 minPwr
= data
->pDataPerXPD
[minIndex
].pwr_t4
[i
];
261 minPcdac
= data
->pDataPerXPD
[minIndex
].pcdac
[i
];
264 retVal
= minPwr
- (minPcdac
*2);
270 ar2133GetChannelMaxMinPower(struct ath_hal
*ah
, HAL_CHANNEL
*chan
, int16_t *maxPow
,
274 struct ath_hal_5212
*ahp
= AH5212(ah
);
275 int numChannels
=0,i
,last
;
276 int totalD
, totalF
,totalMin
;
277 EXPN_DATA_PER_CHANNEL_5112
*data
=AH_NULL
;
278 EEPROM_POWER_EXPN_5112
*powerArray
=AH_NULL
;
281 if (IS_CHAN_A(chan
)) {
282 powerArray
= ahp
->ah_modePowerArray5112
;
283 data
= powerArray
[headerInfo11A
].pDataPerChannel
;
284 numChannels
= powerArray
[headerInfo11A
].numChannels
;
285 } else if (IS_CHAN_G(chan
) || IS_CHAN_108G(chan
)) {
286 /* XXX - is this correct? Should we also use the same power for turbo G? */
287 powerArray
= ahp
->ah_modePowerArray5112
;
288 data
= powerArray
[headerInfo11G
].pDataPerChannel
;
289 numChannels
= powerArray
[headerInfo11G
].numChannels
;
290 } else if (IS_CHAN_B(chan
)) {
291 powerArray
= ahp
->ah_modePowerArray5112
;
292 data
= powerArray
[headerInfo11B
].pDataPerChannel
;
293 numChannels
= powerArray
[headerInfo11B
].numChannels
;
297 /* Make sure the channel is in the range of the TP values
300 if ((numChannels
< 1) ||
301 (chan
->channel
< data
[0].channelValue
) ||
302 (chan
->channel
> data
[numChannels
-1].channelValue
))
305 /* Linearly interpolate the power value now */
307 (i
<numChannels
) && (chan
->channel
> data
[i
].channelValue
);
309 totalD
= data
[i
].channelValue
- data
[last
].channelValue
;
311 totalF
= data
[i
].maxPower_t4
- data
[last
].maxPower_t4
;
312 *maxPow
= (int8_t) ((totalF
*(chan
->channel
-data
[last
].channelValue
) + data
[last
].maxPower_t4
*totalD
)/totalD
);
314 totalMin
= ar2133GetMinPower(ah
,&data
[i
]) - ar2133GetMinPower(ah
, &data
[last
]);
315 *minPow
= (int8_t) ((totalMin
*(chan
->channel
-data
[last
].channelValue
) + ar2133GetMinPower(ah
, &data
[last
])*totalD
)/totalD
);
318 if (chan
->channel
== data
[i
].channelValue
) {
319 *maxPow
= data
[i
].maxPower_t4
;
320 *minPow
= ar2133GetMinPower(ah
, &data
[i
]);
326 *maxPow
= *minPow
= 0;
332 ar2133GetNoiseFloor(struct ath_hal
*ah
, int16_t nfarray
[])
334 struct ath_hal_5416
*ahp
= AH5416(ah
);
337 switch (ahp
->ah_rx_chainmask
) {
339 nf
= MS(OS_REG_READ(ah
, AR_PHY_CH2_CCA
), AR_PHY_CH2_MINCCA_PWR
);
341 nf
= 0 - ((nf
^ 0x1ff) + 1);
342 HALDEBUG(ah
, HAL_DEBUG_NFCAL
,
343 "NF calibrated [ctl] [chain 2] is %d\n", nf
);
346 nf
= MS(OS_REG_READ(ah
, AR_PHY_CH2_EXT_CCA
), AR_PHY_CH2_EXT_MINCCA_PWR
);
348 nf
= 0 - ((nf
^ 0x1ff) + 1);
349 HALDEBUG(ah
, HAL_DEBUG_NFCAL
,
350 "NF calibrated [ext] [chain 2] is %d\n", nf
);
355 nf
= MS(OS_REG_READ(ah
, AR_PHY_CH1_CCA
), AR_PHY_CH1_MINCCA_PWR
);
357 nf
= 0 - ((nf
^ 0x1ff) + 1);
358 HALDEBUG(ah
, HAL_DEBUG_NFCAL
,
359 "NF calibrated [ctl] [chain 1] is %d\n", nf
);
363 nf
= MS(OS_REG_READ(ah
, AR_PHY_CH1_EXT_CCA
), AR_PHY_CH1_EXT_MINCCA_PWR
);
365 nf
= 0 - ((nf
^ 0x1ff) + 1);
366 HALDEBUG(ah
, HAL_DEBUG_NFCAL
,
367 "NF calibrated [ext] [chain 1] is %d\n", nf
);
371 nf
= MS(OS_REG_READ(ah
, AR_PHY_CCA
), AR_PHY_MINCCA_PWR
);
373 nf
= 0 - ((nf
^ 0x1ff) + 1);
374 HALDEBUG(ah
, HAL_DEBUG_NFCAL
,
375 "NF calibrated [ctl] [chain 0] is %d\n", nf
);
378 nf
= MS(OS_REG_READ(ah
, AR_PHY_EXT_CCA
), AR_PHY_EXT_MINCCA_PWR
);
380 nf
= 0 - ((nf
^ 0x1ff) + 1);
381 HALDEBUG(ah
, HAL_DEBUG_NFCAL
,
382 "NF calibrated [ext] [chain 0] is %d\n", nf
);
390 * Adjust NF based on statistical values for 5GHz frequencies.
391 * Stubbed:Not used by Fowl
394 ar2133GetNfAdjust(struct ath_hal
*ah
, const HAL_CHANNEL_INTERNAL
*c
)
400 * Free memory for analog bank scratch buffers
403 ar2133RfDetach(struct ath_hal
*ah
)
405 struct ath_hal_5212
*ahp
= AH5212(ah
);
407 HALASSERT(ahp
->ah_rfHal
!= AH_NULL
);
408 ath_hal_free(ahp
->ah_rfHal
);
409 ahp
->ah_rfHal
= AH_NULL
;
413 * Allocate memory for analog bank scratch buffers
414 * Scratch Buffer will be reinitialized every reset so no need to zero now
417 ar2133RfAttach(struct ath_hal
*ah
, HAL_STATUS
*status
)
419 struct ath_hal_5212
*ahp
= AH5212(ah
);
420 struct ar2133State
*priv
;
423 HALASSERT(ahp
->ah_rfHal
== AH_NULL
);
424 priv
= ath_hal_malloc(sizeof(struct ar2133State
)
425 + AH5416(ah
)->ah_ini_bank0
.rows
* sizeof(uint32_t)
426 + AH5416(ah
)->ah_ini_bank1
.rows
* sizeof(uint32_t)
427 + AH5416(ah
)->ah_ini_bank2
.rows
* sizeof(uint32_t)
428 + AH5416(ah
)->ah_ini_bank3
.rows
* sizeof(uint32_t)
429 + AH5416(ah
)->ah_ini_bank6
.rows
* sizeof(uint32_t)
430 + AH5416(ah
)->ah_ini_bank7
.rows
* sizeof(uint32_t)
432 if (priv
== AH_NULL
) {
433 HALDEBUG(ah
, HAL_DEBUG_ANY
,
434 "%s: cannot allocate private state\n", __func__
);
435 *status
= HAL_ENOMEM
; /* XXX */
438 priv
->base
.rfDetach
= ar2133RfDetach
;
439 priv
->base
.writeRegs
= ar2133WriteRegs
;
440 priv
->base
.getRfBank
= ar2133GetRfBank
;
441 priv
->base
.setChannel
= ar2133SetChannel
;
442 priv
->base
.setRfRegs
= ar2133SetRfRegs
;
443 priv
->base
.setPowerTable
= ar2133SetPowerTable
;
444 priv
->base
.getChannelMaxMinPower
= ar2133GetChannelMaxMinPower
;
445 priv
->base
.getNfAdjust
= ar2133GetNfAdjust
;
447 bankData
= (uint32_t *) &priv
[1];
448 priv
->Bank0Data
= bankData
, bankData
+= AH5416(ah
)->ah_ini_bank0
.rows
;
449 priv
->Bank1Data
= bankData
, bankData
+= AH5416(ah
)->ah_ini_bank1
.rows
;
450 priv
->Bank2Data
= bankData
, bankData
+= AH5416(ah
)->ah_ini_bank2
.rows
;
451 priv
->Bank3Data
= bankData
, bankData
+= AH5416(ah
)->ah_ini_bank3
.rows
;
452 priv
->Bank6Data
= bankData
, bankData
+= AH5416(ah
)->ah_ini_bank6
.rows
;
453 priv
->Bank7Data
= bankData
, bankData
+= AH5416(ah
)->ah_ini_bank7
.rows
;
455 ahp
->ah_pcdacTable
= priv
->pcdacTable
;
456 ahp
->ah_pcdacTableSize
= sizeof(priv
->pcdacTable
);
457 ahp
->ah_rfHal
= &priv
->base
;
459 * Set noise floor adjust method; we arrange a
460 * direct call instead of thunking.
462 AH_PRIVATE(ah
)->ah_getNfAdjust
= priv
->base
.getNfAdjust
;
463 AH_PRIVATE(ah
)->ah_getNoiseFloor
= ar2133GetNoiseFloor
;