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_2133
24 #include "ah_internal.h"
26 #include "ah_eeprom_v14.h"
28 #include "ar5416/ar5416.h"
29 #include "ar5416/ar5416reg.h"
30 #include "ar5416/ar5416phy.h"
32 #define N(a) (sizeof(a)/sizeof(a[0]))
35 RF_HAL_FUNCS base
; /* public state, must be first */
36 uint16_t pcdacTable
[1];
45 /* NB: Bank*Data storage follows */
47 #define AR2133(ah) ((struct ar2133State *) AH5212(ah)->ah_rfHal)
49 #define ar5416ModifyRfBuffer ar5212ModifyRfBuffer /*XXX*/
51 extern void ar5416ModifyRfBuffer(uint32_t *rfBuf
, uint32_t reg32
,
52 uint32_t numBits
, uint32_t firstBit
, uint32_t column
);
53 HAL_BOOL
ar2133GetChipPowerLimits(struct ath_hal
*ah
, HAL_CHANNEL
54 *chans
, uint32_t nchans
);
56 static HAL_BOOL
ar2133GetChannelMaxMinPower(struct ath_hal
*, HAL_CHANNEL
*,
57 int16_t *maxPow
,int16_t *minPow
);
58 int16_t ar2133GetNfAdjust(struct ath_hal
*ah
, const HAL_CHANNEL_INTERNAL
*c
);
61 ar2133WriteRegs(struct ath_hal
*ah
, u_int modesIndex
, u_int freqIndex
,
64 (void) ath_hal_ini_write(ah
, &AH5416(ah
)->ah_ini_bb_rfgain
,
69 * Take the MHz channel value and set the Channel value
71 * ASSUMES: Writes enabled to analog bus
74 ar2133SetChannel(struct ath_hal
*ah
, HAL_CHANNEL_INTERNAL
*chan
)
76 uint32_t channelSel
= 0;
77 uint32_t bModeSynth
= 0;
78 uint32_t aModeRefSel
= 0;
83 OS_MARK(ah
, AH_MARK_SETCHANNEL
, chan
->channel
);
85 ar5416GetChannelCenters(ah
, chan
, ¢ers
);
86 freq
= centers
.synth_center
;
91 if (((freq
- 2192) % 5) == 0) {
92 channelSel
= ((freq
- 672) * 2 - 3040)/10;
94 } else if (((freq
- 2224) % 5) == 0) {
95 channelSel
= ((freq
- 704) * 2 - 3040) / 10;
98 HALDEBUG(ah
, HAL_DEBUG_ANY
,
99 "%s: invalid channel %u MHz\n", __func__
, freq
);
103 channelSel
= (channelSel
<< 2) & 0xff;
104 channelSel
= ath_hal_reverseBits(channelSel
, 8);
106 txctl
= OS_REG_READ(ah
, AR_PHY_CCK_TX_CTRL
);
108 /* Enable channel spreading for channel 14 */
109 OS_REG_WRITE(ah
, AR_PHY_CCK_TX_CTRL
,
110 txctl
| AR_PHY_CCK_TX_CTRL_JAPAN
);
112 OS_REG_WRITE(ah
, AR_PHY_CCK_TX_CTRL
,
113 txctl
&~ AR_PHY_CCK_TX_CTRL_JAPAN
);
115 } else if ((freq
% 20) == 0 && freq
>= 5120) {
116 channelSel
= ath_hal_reverseBits(((freq
- 4800) / 20 << 2), 8);
117 if (AR_SREV_SOWL_10_OR_LATER(ah
))
118 aModeRefSel
= ath_hal_reverseBits(3, 2);
120 aModeRefSel
= ath_hal_reverseBits(1, 2);
121 } else if ((freq
% 10) == 0) {
122 channelSel
= ath_hal_reverseBits(((freq
- 4800) / 10 << 1), 8);
123 if (AR_SREV_SOWL_10_OR_LATER(ah
))
124 aModeRefSel
= ath_hal_reverseBits(2, 2);
126 aModeRefSel
= ath_hal_reverseBits(1, 2);
127 } else if ((freq
% 5) == 0) {
128 channelSel
= ath_hal_reverseBits((freq
- 4800) / 5, 8);
129 aModeRefSel
= ath_hal_reverseBits(1, 2);
131 HALDEBUG(ah
, HAL_DEBUG_ANY
, "%s: invalid channel %u MHz\n",
136 reg32
= (channelSel
<< 8) | (aModeRefSel
<< 2) | (bModeSynth
<< 1) |
139 OS_REG_WRITE(ah
, AR_PHY(0x37), reg32
);
141 AH_PRIVATE(ah
)->ah_curchan
= chan
;
147 * Return a reference to the requested RF Bank.
150 ar2133GetRfBank(struct ath_hal
*ah
, int bank
)
152 struct ar2133State
*priv
= AR2133(ah
);
154 HALASSERT(priv
!= AH_NULL
);
156 case 1: return priv
->Bank1Data
;
157 case 2: return priv
->Bank2Data
;
158 case 3: return priv
->Bank3Data
;
159 case 6: return priv
->Bank6Data
;
160 case 7: return priv
->Bank7Data
;
162 HALDEBUG(ah
, HAL_DEBUG_ANY
, "%s: unknown RF Bank %d requested\n",
168 * Reads EEPROM header info from device structure and programs
171 * REQUIRES: Access to the analog rf device
174 ar2133SetRfRegs(struct ath_hal
*ah
, HAL_CHANNEL_INTERNAL
*chan
,
175 uint16_t modesIndex
, uint16_t *rfXpdGain
)
177 struct ar2133State
*priv
= AR2133(ah
);
182 /* Setup Bank 0 Write */
183 ath_hal_ini_bank_setup(priv
->Bank0Data
, &AH5416(ah
)->ah_ini_bank0
, 1);
185 /* Setup Bank 1 Write */
186 ath_hal_ini_bank_setup(priv
->Bank1Data
, &AH5416(ah
)->ah_ini_bank1
, 1);
188 /* Setup Bank 2 Write */
189 ath_hal_ini_bank_setup(priv
->Bank2Data
, &AH5416(ah
)->ah_ini_bank2
, 1);
191 /* Setup Bank 3 Write */
192 ath_hal_ini_bank_setup(priv
->Bank3Data
, &AH5416(ah
)->ah_ini_bank3
, modesIndex
);
194 /* Setup Bank 6 Write */
195 ath_hal_ini_bank_setup(priv
->Bank6Data
, &AH5416(ah
)->ah_ini_bank6
, modesIndex
);
197 /* Only the 5 or 2 GHz OB/DB need to be set for a mode */
198 if (IS_CHAN_2GHZ(chan
)) {
199 ar5416ModifyRfBuffer(priv
->Bank6Data
,
200 ath_hal_eepromGet(ah
, AR_EEP_OB_2
, AH_NULL
), 3, 197, 0);
201 ar5416ModifyRfBuffer(priv
->Bank6Data
,
202 ath_hal_eepromGet(ah
, AR_EEP_DB_2
, AH_NULL
), 3, 194, 0);
204 ar5416ModifyRfBuffer(priv
->Bank6Data
,
205 ath_hal_eepromGet(ah
, AR_EEP_OB_5
, AH_NULL
), 3, 203, 0);
206 ar5416ModifyRfBuffer(priv
->Bank6Data
,
207 ath_hal_eepromGet(ah
, AR_EEP_DB_5
, AH_NULL
), 3, 200, 0);
209 /* Setup Bank 7 Setup */
210 ath_hal_ini_bank_setup(priv
->Bank7Data
, &AH5416(ah
)->ah_ini_bank7
, 1);
212 /* Write Analog registers */
213 writes
= ath_hal_ini_bank_write(ah
, &AH5416(ah
)->ah_ini_bank0
,
215 writes
= ath_hal_ini_bank_write(ah
, &AH5416(ah
)->ah_ini_bank1
,
216 priv
->Bank1Data
, writes
);
217 writes
= ath_hal_ini_bank_write(ah
, &AH5416(ah
)->ah_ini_bank2
,
218 priv
->Bank2Data
, writes
);
219 writes
= ath_hal_ini_bank_write(ah
, &AH5416(ah
)->ah_ini_bank3
,
220 priv
->Bank3Data
, writes
);
221 writes
= ath_hal_ini_bank_write(ah
, &AH5416(ah
)->ah_ini_bank6
,
222 priv
->Bank6Data
, writes
);
223 (void) ath_hal_ini_bank_write(ah
, &AH5416(ah
)->ah_ini_bank7
,
224 priv
->Bank7Data
, writes
);
231 * Read the transmit power levels from the structures taken from EEPROM
232 * Interpolate read transmit power values for this channel
233 * Organize the transmit power values into a table for writing into the hardware
237 ar2133SetPowerTable(struct ath_hal
*ah
, int16_t *pPowerMin
, int16_t *pPowerMax
,
238 HAL_CHANNEL_INTERNAL
*chan
, uint16_t *rfXpdGain
)
245 ar2133GetMinPower(struct ath_hal
*ah
, EXPN_DATA_PER_CHANNEL_5112
*data
)
248 int16_t minGain
,minPwr
,minPcdac
,retVal
;
250 /* Assume NUM_POINTS_XPD0 > 0 */
251 minGain
= data
->pDataPerXPD
[0].xpd_gain
;
252 for (minIndex
=0,i
=1; i
<NUM_XPD_PER_CHANNEL
; i
++) {
253 if (data
->pDataPerXPD
[i
].xpd_gain
< minGain
) {
255 minGain
= data
->pDataPerXPD
[i
].xpd_gain
;
258 minPwr
= data
->pDataPerXPD
[minIndex
].pwr_t4
[0];
259 minPcdac
= data
->pDataPerXPD
[minIndex
].pcdac
[0];
260 for (i
=1; i
<NUM_POINTS_XPD0
; i
++) {
261 if (data
->pDataPerXPD
[minIndex
].pwr_t4
[i
] < minPwr
) {
262 minPwr
= data
->pDataPerXPD
[minIndex
].pwr_t4
[i
];
263 minPcdac
= data
->pDataPerXPD
[minIndex
].pcdac
[i
];
266 retVal
= minPwr
- (minPcdac
*2);
272 ar2133GetChannelMaxMinPower(struct ath_hal
*ah
, HAL_CHANNEL
*chan
, int16_t *maxPow
,
276 struct ath_hal_5212
*ahp
= AH5212(ah
);
277 int numChannels
=0,i
,last
;
278 int totalD
, totalF
,totalMin
;
279 EXPN_DATA_PER_CHANNEL_5112
*data
=AH_NULL
;
280 EEPROM_POWER_EXPN_5112
*powerArray
=AH_NULL
;
283 if (IS_CHAN_A(chan
)) {
284 powerArray
= ahp
->ah_modePowerArray5112
;
285 data
= powerArray
[headerInfo11A
].pDataPerChannel
;
286 numChannels
= powerArray
[headerInfo11A
].numChannels
;
287 } else if (IS_CHAN_G(chan
) || IS_CHAN_108G(chan
)) {
288 /* XXX - is this correct? Should we also use the same power for turbo G? */
289 powerArray
= ahp
->ah_modePowerArray5112
;
290 data
= powerArray
[headerInfo11G
].pDataPerChannel
;
291 numChannels
= powerArray
[headerInfo11G
].numChannels
;
292 } else if (IS_CHAN_B(chan
)) {
293 powerArray
= ahp
->ah_modePowerArray5112
;
294 data
= powerArray
[headerInfo11B
].pDataPerChannel
;
295 numChannels
= powerArray
[headerInfo11B
].numChannels
;
299 /* Make sure the channel is in the range of the TP values
302 if ((numChannels
< 1) ||
303 (chan
->channel
< data
[0].channelValue
) ||
304 (chan
->channel
> data
[numChannels
-1].channelValue
))
307 /* Linearly interpolate the power value now */
309 (i
<numChannels
) && (chan
->channel
> data
[i
].channelValue
);
311 totalD
= data
[i
].channelValue
- data
[last
].channelValue
;
313 totalF
= data
[i
].maxPower_t4
- data
[last
].maxPower_t4
;
314 *maxPow
= (int8_t) ((totalF
*(chan
->channel
-data
[last
].channelValue
) + data
[last
].maxPower_t4
*totalD
)/totalD
);
316 totalMin
= ar2133GetMinPower(ah
,&data
[i
]) - ar2133GetMinPower(ah
, &data
[last
]);
317 *minPow
= (int8_t) ((totalMin
*(chan
->channel
-data
[last
].channelValue
) + ar2133GetMinPower(ah
, &data
[last
])*totalD
)/totalD
);
320 if (chan
->channel
== data
[i
].channelValue
) {
321 *maxPow
= data
[i
].maxPower_t4
;
322 *minPow
= ar2133GetMinPower(ah
, &data
[i
]);
328 *maxPow
= *minPow
= 0;
334 * Adjust NF based on statistical values for 5GHz frequencies.
335 * Stubbed:Not used by Fowl
338 ar2133GetNfAdjust(struct ath_hal
*ah
, const HAL_CHANNEL_INTERNAL
*c
)
344 * Free memory for analog bank scratch buffers
347 ar2133RfDetach(struct ath_hal
*ah
)
349 struct ath_hal_5212
*ahp
= AH5212(ah
);
351 HALASSERT(ahp
->ah_rfHal
!= AH_NULL
);
352 ath_hal_free(ahp
->ah_rfHal
);
353 ahp
->ah_rfHal
= AH_NULL
;
357 * Allocate memory for analog bank scratch buffers
358 * Scratch Buffer will be reinitialized every reset so no need to zero now
361 ar2133RfAttach(struct ath_hal
*ah
, HAL_STATUS
*status
)
363 struct ath_hal_5212
*ahp
= AH5212(ah
);
364 struct ar2133State
*priv
;
367 HALASSERT(ahp
->ah_rfHal
== AH_NULL
);
368 priv
= ath_hal_malloc(sizeof(struct ar2133State
)
369 + AH5416(ah
)->ah_ini_bank0
.rows
* sizeof(uint32_t)
370 + AH5416(ah
)->ah_ini_bank1
.rows
* sizeof(uint32_t)
371 + AH5416(ah
)->ah_ini_bank2
.rows
* sizeof(uint32_t)
372 + AH5416(ah
)->ah_ini_bank3
.rows
* sizeof(uint32_t)
373 + AH5416(ah
)->ah_ini_bank6
.rows
* sizeof(uint32_t)
374 + AH5416(ah
)->ah_ini_bank7
.rows
* sizeof(uint32_t)
376 if (priv
== AH_NULL
) {
377 HALDEBUG(ah
, HAL_DEBUG_ANY
,
378 "%s: cannot allocate private state\n", __func__
);
379 *status
= HAL_ENOMEM
; /* XXX */
382 priv
->base
.rfDetach
= ar2133RfDetach
;
383 priv
->base
.writeRegs
= ar2133WriteRegs
;
384 priv
->base
.getRfBank
= ar2133GetRfBank
;
385 priv
->base
.setChannel
= ar2133SetChannel
;
386 priv
->base
.setRfRegs
= ar2133SetRfRegs
;
387 priv
->base
.setPowerTable
= ar2133SetPowerTable
;
388 priv
->base
.getChannelMaxMinPower
= ar2133GetChannelMaxMinPower
;
389 priv
->base
.getNfAdjust
= ar2133GetNfAdjust
;
391 bankData
= (uint32_t *) &priv
[1];
392 priv
->Bank0Data
= bankData
, bankData
+= AH5416(ah
)->ah_ini_bank0
.rows
;
393 priv
->Bank1Data
= bankData
, bankData
+= AH5416(ah
)->ah_ini_bank1
.rows
;
394 priv
->Bank2Data
= bankData
, bankData
+= AH5416(ah
)->ah_ini_bank2
.rows
;
395 priv
->Bank3Data
= bankData
, bankData
+= AH5416(ah
)->ah_ini_bank3
.rows
;
396 priv
->Bank6Data
= bankData
, bankData
+= AH5416(ah
)->ah_ini_bank6
.rows
;
397 priv
->Bank7Data
= bankData
, bankData
+= AH5416(ah
)->ah_ini_bank7
.rows
;
399 ahp
->ah_pcdacTable
= priv
->pcdacTable
;
400 ahp
->ah_pcdacTableSize
= sizeof(priv
->pcdacTable
);
401 ahp
->ah_rfHal
= &priv
->base
;
403 * Set noise floor adjust method; we arrange a
404 * direct call instead of thunking.
406 AH_PRIVATE(ah
)->ah_getNfAdjust
= priv
->base
.getNfAdjust
;
410 #endif /* AH_SUPPORT_2133 */