2 * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
3 * Copyright (c) 2002-2004 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_AR5210
24 #include "ah_internal.h"
26 #include "ar5210/ar5210.h"
27 #include "ar5210/ar5210reg.h"
28 #include "ar5210/ar5210phy.h"
35 static const REGISTER_VAL ar5k0007_init
[] = {
36 #include "ar5210/ar5k_0007.ini"
39 /* Default Power Settings for channels outside of EEPROM range */
40 static const uint8_t ar5k0007_pwrSettings
[17] = {
41 /* gain delta pc dac */
42 /* 54 48 36 24 18 12 9 54 48 36 24 18 12 9 6 ob db */
43 9, 9, 0, 0, 0, 0, 0, 2, 2, 6, 6, 6, 6, 6, 6, 2, 2
47 * The delay, in usecs, between writing AR_RC with a reset
48 * request and waiting for the chip to settle. If this is
49 * too short then the chip does not come out of sleep state.
50 * Note this value was empirically derived and may be dependent
51 * on the host machine (don't know--the problem was identified
52 * on an IBM 570e laptop; 10us delays worked on other systems).
54 #define AR_RC_SETTLE_TIME 20000
56 static HAL_BOOL
ar5210SetResetReg(struct ath_hal
*,
57 uint32_t resetMask
, u_int delay
);
58 static HAL_BOOL
ar5210SetChannel(struct ath_hal
*, HAL_CHANNEL_INTERNAL
*);
59 static void ar5210SetOperatingMode(struct ath_hal
*, int opmode
);
62 * Places the device in and out of reset and then places sane
63 * values in the registers based on EEPROM config, initialization
64 * vectors (as determined by the mode), and station configuration
66 * bChannelChange is used to preserve DMA/PCU registers across
67 * a HW Reset during channel change.
70 ar5210Reset(struct ath_hal
*ah
, HAL_OPMODE opmode
,
71 HAL_CHANNEL
*chan
, HAL_BOOL bChannelChange
, HAL_STATUS
*status
)
73 #define N(a) (sizeof (a) /sizeof (a[0]))
74 #define FAIL(_code) do { ecode = _code; goto bad; } while (0)
75 struct ath_hal_5210
*ahp
= AH5210(ah
);
76 HAL_CHANNEL_INTERNAL
*ichan
;
81 HALDEBUG(ah
, HAL_DEBUG_RESET
,
82 "%s: opmode %u channel %u/0x%x %s channel\n", __func__
,
83 opmode
, chan
->channel
, chan
->channelFlags
,
84 bChannelChange
? "change" : "same");
86 if ((chan
->channelFlags
& CHANNEL_5GHZ
) == 0) {
88 HALDEBUG(ah
, HAL_DEBUG_ANY
, "%s: channel not 5Ghz\n", __func__
);
92 * Map public channel to private.
94 ichan
= ath_hal_checkchannel(ah
, chan
);
95 if (ichan
== AH_NULL
) {
96 HALDEBUG(ah
, HAL_DEBUG_ANY
,
97 "%s: invalid channel %u/0x%x; no mapping\n",
98 __func__
, chan
->channel
, chan
->channelFlags
);
108 HALDEBUG(ah
, HAL_DEBUG_ANY
, "%s: invalid operating mode %u\n",
114 ledstate
= OS_REG_READ(ah
, AR_PCICFG
) &
115 (AR_PCICFG_LED_PEND
| AR_PCICFG_LED_ACT
);
117 if (!ar5210ChipReset(ah
, chan
)) {
118 HALDEBUG(ah
, HAL_DEBUG_ANY
, "%s: chip reset failed\n",
123 OS_REG_WRITE(ah
, AR_STA_ID0
, LE_READ_4(ahp
->ah_macaddr
));
124 OS_REG_WRITE(ah
, AR_STA_ID1
, LE_READ_2(ahp
->ah_macaddr
+ 4));
125 ar5210SetOperatingMode(ah
, opmode
);
129 OS_REG_WRITE(ah
, AR_BCR
, INIT_BCON_CNTRL_REG
);
130 OS_REG_WRITE(ah
, AR_PCICFG
,
131 AR_PCICFG_LED_ACT
| AR_PCICFG_LED_BCTL
);
134 OS_REG_WRITE(ah
, AR_BCR
, INIT_BCON_CNTRL_REG
| AR_BCR_BCMD
);
135 OS_REG_WRITE(ah
, AR_PCICFG
,
136 AR_PCICFG_CLKRUNEN
| AR_PCICFG_LED_PEND
| AR_PCICFG_LED_BCTL
);
139 OS_REG_WRITE(ah
, AR_BCR
, INIT_BCON_CNTRL_REG
);
140 OS_REG_WRITE(ah
, AR_PCICFG
,
141 AR_PCICFG_CLKRUNEN
| AR_PCICFG_LED_PEND
| AR_PCICFG_LED_BCTL
);
144 OS_REG_WRITE(ah
, AR_BCR
, INIT_BCON_CNTRL_REG
);
145 OS_REG_WRITE(ah
, AR_PCICFG
,
146 AR_PCICFG_LED_ACT
| AR_PCICFG_LED_BCTL
);
150 /* Restore previous led state */
151 OS_REG_WRITE(ah
, AR_PCICFG
, OS_REG_READ(ah
, AR_PCICFG
) | ledstate
);
153 OS_REG_WRITE(ah
, AR_BSS_ID0
, LE_READ_4(ahp
->ah_bssid
));
154 OS_REG_WRITE(ah
, AR_BSS_ID1
, LE_READ_2(ahp
->ah_bssid
+ 4));
156 OS_REG_WRITE(ah
, AR_TXDP0
, 0);
157 OS_REG_WRITE(ah
, AR_TXDP1
, 0);
158 OS_REG_WRITE(ah
, AR_RXDP
, 0);
161 * Initialize interrupt state.
163 (void) OS_REG_READ(ah
, AR_ISR
); /* cleared on read */
164 OS_REG_WRITE(ah
, AR_IMR
, 0);
165 OS_REG_WRITE(ah
, AR_IER
, AR_IER_DISABLE
);
168 (void) OS_REG_READ(ah
, AR_BSR
); /* cleared on read */
169 OS_REG_WRITE(ah
, AR_TXCFG
, AR_DMASIZE_128B
);
170 OS_REG_WRITE(ah
, AR_RXCFG
, AR_DMASIZE_128B
);
172 OS_REG_WRITE(ah
, AR_TOPS
, 8); /* timeout prescale */
173 OS_REG_WRITE(ah
, AR_RXNOFRM
, 8); /* RX no frame timeout */
174 OS_REG_WRITE(ah
, AR_RPGTO
, 0); /* RX frame gap timeout */
175 OS_REG_WRITE(ah
, AR_TXNOFRM
, 0); /* TX no frame timeout */
177 OS_REG_WRITE(ah
, AR_SFR
, 0);
178 OS_REG_WRITE(ah
, AR_MIBC
, 0); /* unfreeze ctrs + clr state */
179 OS_REG_WRITE(ah
, AR_RSSI_THR
, ahp
->ah_rssiThr
);
180 OS_REG_WRITE(ah
, AR_CFP_DUR
, 0);
182 ar5210SetRxFilter(ah
, 0); /* nothing for now */
183 OS_REG_WRITE(ah
, AR_MCAST_FIL0
, 0); /* multicast filter */
184 OS_REG_WRITE(ah
, AR_MCAST_FIL1
, 0); /* XXX was 2 */
186 OS_REG_WRITE(ah
, AR_TX_MASK0
, 0);
187 OS_REG_WRITE(ah
, AR_TX_MASK1
, 0);
188 OS_REG_WRITE(ah
, AR_CLR_TMASK
, 1);
189 OS_REG_WRITE(ah
, AR_TRIG_LEV
, 1); /* minimum */
191 OS_REG_WRITE(ah
, AR_DIAG_SW
, 0);
193 OS_REG_WRITE(ah
, AR_CFP_PERIOD
, 0);
194 OS_REG_WRITE(ah
, AR_TIMER0
, 0); /* next beacon time */
195 OS_REG_WRITE(ah
, AR_TSF_L32
, 0); /* local clock */
196 OS_REG_WRITE(ah
, AR_TIMER1
, ~0); /* next DMA beacon alert */
197 OS_REG_WRITE(ah
, AR_TIMER2
, ~0); /* next SW beacon alert */
198 OS_REG_WRITE(ah
, AR_TIMER3
, 1); /* next ATIM window */
200 /* Write the INI values for PHYreg initialization */
201 for (i
= 0; i
< N(ar5k0007_init
); i
++) {
202 uint32_t reg
= ar5k0007_init
[i
].Offset
;
203 /* On channel change, don't reset the PCU registers */
204 if (!(bChannelChange
&& (0x8000 <= reg
&& reg
< 0x9000)))
205 OS_REG_WRITE(ah
, reg
, ar5k0007_init
[i
].Value
);
208 /* Setup the transmit power values for cards since 0x0[0-2]05 */
209 if (!ar5210SetTransmitPower(ah
, chan
)) {
210 HALDEBUG(ah
, HAL_DEBUG_ANY
,
211 "%s: error init'ing transmit power\n", __func__
);
215 OS_REG_WRITE(ah
, AR_PHY(10),
216 (OS_REG_READ(ah
, AR_PHY(10)) & 0xFFFF00FF) |
217 (ahp
->ah_xlnaOn
<< 8));
218 OS_REG_WRITE(ah
, AR_PHY(13),
219 (ahp
->ah_xpaOff
<< 24) | (ahp
->ah_xpaOff
<< 16) |
220 (ahp
->ah_xpaOn
<< 8) | ahp
->ah_xpaOn
);
221 OS_REG_WRITE(ah
, AR_PHY(17),
222 (OS_REG_READ(ah
, AR_PHY(17)) & 0xFFFFC07F) |
223 ((ahp
->ah_antenna
>> 1) & 0x3F80));
224 OS_REG_WRITE(ah
, AR_PHY(18),
225 (OS_REG_READ(ah
, AR_PHY(18)) & 0xFFFC0FFF) |
226 ((ahp
->ah_antenna
<< 10) & 0x3F000));
227 OS_REG_WRITE(ah
, AR_PHY(25),
228 (OS_REG_READ(ah
, AR_PHY(25)) & 0xFFF80FFF) |
229 ((ahp
->ah_thresh62
<< 12) & 0x7F000));
230 OS_REG_WRITE(ah
, AR_PHY(68),
231 (OS_REG_READ(ah
, AR_PHY(68)) & 0xFFFFFFFC) |
232 (ahp
->ah_antenna
& 0x3));
234 if (!ar5210SetChannel(ah
, ichan
)) {
235 HALDEBUG(ah
, HAL_DEBUG_ANY
, "%s: unable to set channel\n",
239 if (bChannelChange
) {
240 if (!(ichan
->privFlags
& CHANNEL_DFS
))
241 ichan
->privFlags
&= ~CHANNEL_INTERFERENCE
;
242 chan
->channelFlags
= ichan
->channelFlags
;
243 chan
->privFlags
= ichan
->privFlags
;
246 /* Activate the PHY */
247 OS_REG_WRITE(ah
, AR_PHY_ACTIVE
, AR_PHY_ENABLE
);
249 OS_DELAY(1000); /* Wait a bit (1 msec) */
251 /* calibrate the HW and poll the bit going to 0 for completion */
252 OS_REG_WRITE(ah
, AR_PHY_AGCCTL
,
253 OS_REG_READ(ah
, AR_PHY_AGCCTL
) | AR_PHY_AGC_CAL
);
254 (void) ath_hal_wait(ah
, AR_PHY_AGCCTL
, AR_PHY_AGC_CAL
, 0);
256 /* Perform noise floor calibration and set status */
257 if (!ar5210CalNoiseFloor(ah
, ichan
)) {
258 chan
->channelFlags
|= CHANNEL_CW_INT
;
259 HALDEBUG(ah
, HAL_DEBUG_ANY
,
260 "%s: noise floor calibration failed\n", __func__
);
264 for (q
= 0; q
< HAL_NUM_TX_QUEUES
; q
++)
265 ar5210ResetTxQueue(ah
, q
);
267 if (AH_PRIVATE(ah
)->ah_rfkillEnabled
)
268 ar5210EnableRfKill(ah
);
271 * Writing to AR_BEACON will start timers. Hence it should be
272 * the last register to be written. Do not reset tsf, do not
273 * enable beacons at this point, but preserve other values
274 * like beaconInterval.
276 OS_REG_WRITE(ah
, AR_BEACON
,
277 (OS_REG_READ(ah
, AR_BEACON
) &
278 ~(AR_BEACON_EN
| AR_BEACON_RESET_TSF
)));
280 /* Restore user-specified slot time and timeouts */
281 if (ahp
->ah_sifstime
!= (u_int
) -1)
282 ar5210SetSifsTime(ah
, ahp
->ah_sifstime
);
283 if (ahp
->ah_slottime
!= (u_int
) -1)
284 ar5210SetSlotTime(ah
, ahp
->ah_slottime
);
285 if (ahp
->ah_acktimeout
!= (u_int
) -1)
286 ar5210SetAckTimeout(ah
, ahp
->ah_acktimeout
);
287 if (ahp
->ah_ctstimeout
!= (u_int
) -1)
288 ar5210SetCTSTimeout(ah
, ahp
->ah_ctstimeout
);
289 if (AH_PRIVATE(ah
)->ah_diagreg
!= 0)
290 OS_REG_WRITE(ah
, AR_DIAG_SW
, AH_PRIVATE(ah
)->ah_diagreg
);
292 AH_PRIVATE(ah
)->ah_opmode
= opmode
; /* record operating mode */
294 HALDEBUG(ah
, HAL_DEBUG_RESET
, "%s: done\n", __func__
);
306 ar5210SetOperatingMode(struct ath_hal
*ah
, int opmode
)
308 struct ath_hal_5210
*ahp
= AH5210(ah
);
311 val
= OS_REG_READ(ah
, AR_STA_ID1
) & 0xffff;
314 OS_REG_WRITE(ah
, AR_STA_ID1
, val
316 | AR_STA_ID1_NO_PSPOLL
317 | AR_STA_ID1_DESC_ANTENNA
318 | ahp
->ah_staId1Defaults
);
321 OS_REG_WRITE(ah
, AR_STA_ID1
, val
323 | AR_STA_ID1_NO_PSPOLL
324 | AR_STA_ID1_DESC_ANTENNA
325 | ahp
->ah_staId1Defaults
);
328 OS_REG_WRITE(ah
, AR_STA_ID1
, val
329 | AR_STA_ID1_NO_PSPOLL
331 | ahp
->ah_staId1Defaults
);
334 OS_REG_WRITE(ah
, AR_STA_ID1
, val
335 | AR_STA_ID1_NO_PSPOLL
336 | ahp
->ah_staId1Defaults
);
342 ar5210SetPCUConfig(struct ath_hal
*ah
)
344 ar5210SetOperatingMode(ah
, AH_PRIVATE(ah
)->ah_opmode
);
348 * Places the PHY and Radio chips into reset. A full reset
349 * must be called to leave this state. The PCI/MAC/PCU are
350 * not placed into reset as we must receive interrupt to
351 * re-enable the hardware.
354 ar5210PhyDisable(struct ath_hal
*ah
)
356 return ar5210SetResetReg(ah
, AR_RC_RPHY
, 10);
360 * Places all of hardware into reset
363 ar5210Disable(struct ath_hal
*ah
)
365 #define AR_RC_HW (AR_RC_RPCU | AR_RC_RDMA | AR_RC_RPHY | AR_RC_RMAC)
366 if (!ar5210SetPowerMode(ah
, HAL_PM_AWAKE
, AH_TRUE
))
370 * Reset the HW - PCI must be reset after the rest of the
371 * device has been reset
373 if (!ar5210SetResetReg(ah
, AR_RC_HW
, AR_RC_SETTLE_TIME
))
376 (void) ar5210SetResetReg(ah
, AR_RC_HW
| AR_RC_RPCI
, AR_RC_SETTLE_TIME
);
377 OS_DELAY(2100); /* 8245 @ 96Mhz hangs with 2000us. */
384 * Places the hardware into reset and then pulls it out of reset
387 ar5210ChipReset(struct ath_hal
*ah
, HAL_CHANNEL
*chan
)
389 #define AR_RC_HW (AR_RC_RPCU | AR_RC_RDMA | AR_RC_RPHY | AR_RC_RMAC)
391 HALDEBUG(ah
, HAL_DEBUG_RESET
, "%s turbo %s\n", __func__
,
392 chan
&& IS_CHAN_TURBO(chan
) ? "enabled" : "disabled");
394 if (!ar5210SetPowerMode(ah
, HAL_PM_AWAKE
, AH_TRUE
))
397 /* Place chip in turbo before reset to cleanly reset clocks */
398 OS_REG_WRITE(ah
, AR_PHY_FRCTL
,
399 chan
&& IS_CHAN_TURBO(chan
) ? AR_PHY_TURBO_MODE
: 0);
403 * PCI must be reset after the rest of the device has been reset.
405 if (!ar5210SetResetReg(ah
, AR_RC_HW
, AR_RC_SETTLE_TIME
))
408 if (!ar5210SetResetReg(ah
, AR_RC_HW
| AR_RC_RPCI
, AR_RC_SETTLE_TIME
))
410 OS_DELAY(2100); /* 8245 @ 96Mhz hangs with 2000us. */
413 * Bring out of sleep mode (AGAIN)
415 * WARNING WARNING WARNING
417 * There is a problem with the chip where it doesn't always indicate
418 * that it's awake, so initializePowerUp() will fail.
420 if (!ar5210SetPowerMode(ah
, HAL_PM_AWAKE
, AH_TRUE
))
423 /* Clear warm reset reg */
424 return ar5210SetResetReg(ah
, 0, 10);
429 FIRPWR_M
= 0x03fc0000,
431 KCOARSEHIGH_M
= 0x003f8000,
433 KCOARSELOW_M
= 0x00007f80,
435 ADCSAT_ICOUNT_M
= 0x0001f800,
436 ADCSAT_ICOUNT_S
= 11,
437 ADCSAT_THRESH_M
= 0x000007e0,
442 * Recalibrate the lower PHY chips to account for temperature/environment
446 ar5210PerCalibration(struct ath_hal
*ah
, HAL_CHANNEL
*chan
, HAL_BOOL
*isIQdone
)
449 uint32_t reg9858
, reg985c
, reg9868
;
450 HAL_CHANNEL_INTERNAL
*ichan
;
452 ichan
= ath_hal_checkchannel(ah
, chan
);
453 if (ichan
== AH_NULL
) {
454 HALDEBUG(ah
, HAL_DEBUG_ANY
,
455 "%s: invalid channel %u/0x%x; no mapping\n",
456 __func__
, chan
->channel
, chan
->channelFlags
);
459 /* Disable tx and rx */
460 OS_REG_WRITE(ah
, AR_DIAG_SW
,
461 OS_REG_READ(ah
, AR_DIAG_SW
) | (AR_DIAG_SW_DIS_TX
| AR_DIAG_SW_DIS_RX
));
463 /* Disable Beacon Enable */
464 regBeacon
= OS_REG_READ(ah
, AR_BEACON
);
465 OS_REG_WRITE(ah
, AR_BEACON
, regBeacon
& ~AR_BEACON_EN
);
467 /* Delay 4ms to ensure that all tx and rx activity has ceased */
470 /* Disable AGC to radio traffic */
471 OS_REG_WRITE(ah
, 0x9808, OS_REG_READ(ah
, 0x9808) | 0x08000000);
472 /* Wait for the AGC traffic to cease. */
475 /* Change Channel to relock synth */
476 if (!ar5210SetChannel(ah
, ichan
))
479 /* wait for the synthesizer lock to stabilize */
482 /* Re-enable AGC to radio traffic */
483 OS_REG_WRITE(ah
, 0x9808, OS_REG_READ(ah
, 0x9808) & (~0x08000000));
486 * Configure the AGC so that it is highly unlikely (if not
487 * impossible) for it to send any gain changes to the analog
488 * chip. We store off the current values so that they can
489 * be rewritten below. Setting the following values:
496 reg9858
= OS_REG_READ(ah
, 0x9858);
497 reg985c
= OS_REG_READ(ah
, 0x985c);
498 reg9868
= OS_REG_READ(ah
, 0x9868);
500 OS_REG_WRITE(ah
, 0x9858, (reg9858
& ~FIRPWR_M
) |
501 ((-1 << FIRPWR_S
) & FIRPWR_M
));
502 OS_REG_WRITE(ah
, 0x985c,
503 (reg985c
& ~(KCOARSEHIGH_M
| KCOARSELOW_M
)) |
504 ((-1 << KCOARSEHIGH_S
) & KCOARSEHIGH_M
) |
505 ((-127 << KCOARSELOW_S
) & KCOARSELOW_M
));
506 OS_REG_WRITE(ah
, 0x9868,
507 (reg9868
& ~(ADCSAT_ICOUNT_M
| ADCSAT_THRESH_M
)) |
508 ((2 << ADCSAT_ICOUNT_S
) & ADCSAT_ICOUNT_M
) |
509 ((12 << ADCSAT_THRESH_S
) & ADCSAT_THRESH_M
));
511 /* Wait for AGC changes to be enacted */
515 * We disable RF mix/gain stages for the PGA to avoid a
516 * race condition that will occur with receiving a frame
517 * and performing the AGC calibration. This will be
518 * re-enabled at the end of offset cal. We turn off AGC
519 * writes during this write as it will go over the analog bus.
521 OS_REG_WRITE(ah
, 0x9808, OS_REG_READ(ah
, 0x9808) | 0x08000000);
522 OS_DELAY(10); /* wait for the AGC traffic to cease */
523 OS_REG_WRITE(ah
, 0x98D4, 0x21);
524 OS_REG_WRITE(ah
, 0x9808, OS_REG_READ(ah
, 0x9808) & (~0x08000000));
526 /* wait to make sure that additional AGC traffic has quiesced */
529 /* AGC calibration (this was added to make the NF threshold check work) */
530 OS_REG_WRITE(ah
, AR_PHY_AGCCTL
,
531 OS_REG_READ(ah
, AR_PHY_AGCCTL
) | AR_PHY_AGC_CAL
);
532 if (!ath_hal_wait(ah
, AR_PHY_AGCCTL
, AR_PHY_AGC_CAL
, 0))
533 HALDEBUG(ah
, HAL_DEBUG_ANY
, "%s: AGC calibration timeout\n",
536 /* Rewrite our AGC values we stored off earlier (return AGC to normal operation) */
537 OS_REG_WRITE(ah
, 0x9858, reg9858
);
538 OS_REG_WRITE(ah
, 0x985c, reg985c
);
539 OS_REG_WRITE(ah
, 0x9868, reg9868
);
541 /* Perform noise floor and set status */
542 if (!ar5210CalNoiseFloor(ah
, ichan
)) {
544 * Delay 5ms before retrying the noise floor -
545 * just to make sure. We're in an error
548 HALDEBUG(ah
, HAL_DEBUG_NFCAL
| HAL_DEBUG_PERCAL
,
549 "%s: Performing 2nd Noise Cal\n", __func__
);
551 if (!ar5210CalNoiseFloor(ah
, ichan
))
552 chan
->channelFlags
|= CHANNEL_CW_INT
;
555 /* Clear tx and rx disable bit */
556 OS_REG_WRITE(ah
, AR_DIAG_SW
,
557 OS_REG_READ(ah
, AR_DIAG_SW
) & ~(AR_DIAG_SW_DIS_TX
| AR_DIAG_SW_DIS_RX
));
559 /* Re-enable Beacons */
560 OS_REG_WRITE(ah
, AR_BEACON
, regBeacon
);
568 * Writes the given reset bit mask into the reset register
571 ar5210SetResetReg(struct ath_hal
*ah
, uint32_t resetMask
, u_int delay
)
573 uint32_t mask
= resetMask
? resetMask
: ~0;
576 OS_REG_WRITE(ah
, AR_RC
, resetMask
);
577 /* need to wait at least 128 clocks when reseting PCI before read */
580 resetMask
&= AR_RC_RPCU
| AR_RC_RDMA
| AR_RC_RPHY
| AR_RC_RMAC
;
581 mask
&= AR_RC_RPCU
| AR_RC_RDMA
| AR_RC_RPHY
| AR_RC_RMAC
;
582 rt
= ath_hal_wait(ah
, AR_RC
, mask
, resetMask
);
583 if ((resetMask
& AR_RC_RMAC
) == 0) {
586 * Set CFG, little-endian for register
587 * and descriptor accesses.
589 mask
= INIT_CONFIG_STATUS
|
590 AR_CFG_SWTD
| AR_CFG_SWRD
| AR_CFG_SWRG
;
591 OS_REG_WRITE(ah
, AR_CFG
, LE_READ_4(&mask
));
593 OS_REG_WRITE(ah
, AR_CFG
, INIT_CONFIG_STATUS
);
600 * Returns: the pcdac value
603 getPcdac(struct ath_hal
*ah
, struct tpcMap
*pRD
, uint8_t dBm
)
606 int useNextEntry
= AH_FALSE
;
609 for (i
= AR_TP_SCALING_ENTRIES
- 1; i
>= 0; i
--) {
610 /* Check for exact entry */
611 if (dBm
== AR_I2DBM(i
)) {
612 if (pRD
->pcdac
[i
] != 63)
613 return pRD
->pcdac
[i
];
614 useNextEntry
= AH_TRUE
;
615 } else if (dBm
+ 1 == AR_I2DBM(i
) && i
> 0) {
616 /* Interpolate for between entry with a logish scale */
617 if (pRD
->pcdac
[i
] != 63 && pRD
->pcdac
[i
-1] != 63) {
618 interp
= (350 * (pRD
->pcdac
[i
] - pRD
->pcdac
[i
-1])) + 999;
619 interp
= (interp
/ 1000) + pRD
->pcdac
[i
-1];
622 useNextEntry
= AH_TRUE
;
623 } else if (useNextEntry
== AH_TRUE
) {
624 /* Grab the next lowest */
625 if (pRD
->pcdac
[i
] != 63)
626 return pRD
->pcdac
[i
];
630 /* Return the lowest Entry if we haven't returned */
631 for (i
= 0; i
< AR_TP_SCALING_ENTRIES
; i
++)
632 if (pRD
->pcdac
[i
] != 63)
633 return pRD
->pcdac
[i
];
635 /* No value to return from table */
637 ath_hal_printf(ah
, "%s: empty transmit power table?\n", __func__
);
643 * Find or interpolates the gainF value from the table ptr.
646 getGainF(struct ath_hal
*ah
, struct tpcMap
*pRD
, uint8_t pcdac
, uint8_t *dBm
)
653 for (i
= 0; i
< AR_TP_SCALING_ENTRIES
; i
++) {
654 if(pRD
->pcdac
[i
] == 63)
656 if (pcdac
== pRD
->pcdac
[i
]) {
658 return pRD
->gainF
[i
]; /* Exact Match */
660 if (pcdac
> pRD
->pcdac
[i
])
662 if (pcdac
< pRD
->pcdac
[i
]) {
666 /* PCDAC is lower than lowest setting */
667 return pRD
->gainF
[i
];
672 if (i
>= AR_TP_SCALING_ENTRIES
&& low
== -1) {
673 /* No settings were found */
676 "%s: no valid entries in the pcdac table: %d\n",
681 if (i
>= AR_TP_SCALING_ENTRIES
) {
682 /* PCDAC setting was above the max setting in the table */
683 *dBm
= AR_I2DBM(low
);
684 return pRD
->gainF
[low
];
686 /* Only exact if table has no missing entries */
687 *dBm
= (low
+ high
) + 3;
690 * Perform interpolation between low and high values to find gainF
691 * linearly scale the pcdac between low and high
693 interp
= ((pcdac
- pRD
->pcdac
[low
]) * 1000) /
694 (pRD
->pcdac
[high
] - pRD
->pcdac
[low
]);
696 * Multiply the scale ratio by the gainF difference
697 * (plus a rnd up factor)
699 interp
= ((interp
* (pRD
->gainF
[high
] - pRD
->gainF
[low
])) + 999) / 1000;
701 /* Add ratioed gain_f to low gain_f value */
702 return interp
+ pRD
->gainF
[low
];
706 ar5210SetTxPowerLimit(struct ath_hal
*ah
, uint32_t limit
)
708 AH_PRIVATE(ah
)->ah_powerLimit
= AH_MIN(limit
, MAX_RATE_POWER
);
709 /* XXX flush to h/w */
714 * Get TXPower values and set them in the radio
717 setupPowerSettings(struct ath_hal
*ah
, HAL_CHANNEL
*chan
, uint8_t cp
[17])
719 struct ath_hal_5210
*ahp
= AH5210(ah
);
720 uint8_t gainFRD
, gainF36
, gainF48
, gainF54
;
721 uint8_t dBmRD
, dBm36
, dBm48
, dBm54
, dontcare
;
725 /* Set OB/DB Values regardless of channel */
726 cp
[15] = (ahp
->ah_biasCurrents
>> 4) & 0x7;
727 cp
[16] = ahp
->ah_biasCurrents
& 0x7;
729 if (chan
->channel
< 5170 || chan
->channel
> 5320) {
730 HALDEBUG(ah
, HAL_DEBUG_ANY
, "%s: invalid channel %u\n",
731 __func__
, chan
->channel
);
735 HALASSERT(ahp
->ah_eeversion
== 1);
737 /* Match regulatory domain */
738 for (rd
= 0; rd
< AR_REG_DOMAINS_MAX
; rd
++)
739 if (AH_PRIVATE(ah
)->ah_currentRD
== ahp
->ah_regDomain
[rd
])
741 if (rd
== AR_REG_DOMAINS_MAX
) {
744 "%s: no calibrated regulatory domain matches the "
745 "current regularly domain (0x%0x)\n", __func__
,
746 AH_PRIVATE(ah
)->ah_currentRD
);
750 group
= ((chan
->channel
- 5170) / 10);
753 /* Pull 5.29 into the 5.27 group */
757 /* Integer divide will set group from 0 to 4 */
759 pRD
= &ahp
->ah_tpc
[group
];
761 /* Set PC DAC Values */
762 cp
[14] = pRD
->regdmn
[rd
];
763 cp
[9] = AH_MIN(pRD
->regdmn
[rd
], pRD
->rate36
);
764 cp
[8] = AH_MIN(pRD
->regdmn
[rd
], pRD
->rate48
);
765 cp
[7] = AH_MIN(pRD
->regdmn
[rd
], pRD
->rate54
);
767 /* Find Corresponding gainF values for RD, 36, 48, 54 */
768 gainFRD
= getGainF(ah
, pRD
, pRD
->regdmn
[rd
], &dBmRD
);
769 gainF36
= getGainF(ah
, pRD
, cp
[9], &dBm36
);
770 gainF48
= getGainF(ah
, pRD
, cp
[8], &dBm48
);
771 gainF54
= getGainF(ah
, pRD
, cp
[7], &dBm54
);
773 /* Power Scale if requested */
774 if (AH_PRIVATE(ah
)->ah_tpScale
!= HAL_TP_SCALE_MAX
) {
775 static const uint16_t tpcScaleReductionTable
[5] =
776 { 0, 3, 6, 9, MAX_RATE_POWER
};
779 tpScale
= tpcScaleReductionTable
[AH_PRIVATE(ah
)->ah_tpScale
];
780 if (dBmRD
< tpScale
+3)
784 cp
[14] = getPcdac(ah
, pRD
, dBmRD
);
785 gainFRD
= getGainF(ah
, pRD
, cp
[14], &dontcare
);
786 dBm36
= AH_MIN(dBm36
, dBmRD
);
787 cp
[9] = getPcdac(ah
, pRD
, dBm36
);
788 gainF36
= getGainF(ah
, pRD
, cp
[9], &dontcare
);
789 dBm48
= AH_MIN(dBm48
, dBmRD
);
790 cp
[8] = getPcdac(ah
, pRD
, dBm48
);
791 gainF48
= getGainF(ah
, pRD
, cp
[8], &dontcare
);
792 dBm54
= AH_MIN(dBm54
, dBmRD
);
793 cp
[7] = getPcdac(ah
, pRD
, dBm54
);
794 gainF54
= getGainF(ah
, pRD
, cp
[7], &dontcare
);
796 /* Record current dBm at rate 6 */
797 AH_PRIVATE(ah
)->ah_maxPowerLevel
= 2*dBmRD
;
799 cp
[13] = cp
[12] = cp
[11] = cp
[10] = cp
[14];
801 /* Set GainF Values */
802 cp
[0] = gainFRD
- gainF54
;
803 cp
[1] = gainFRD
- gainF48
;
804 cp
[2] = gainFRD
- gainF36
;
805 /* 9, 12, 18, 24 have no gain_delta from 6 */
806 cp
[3] = cp
[4] = cp
[5] = cp
[6] = 0;
811 * Places the device in and out of reset and then places sane
812 * values in the registers based on EEPROM config, initialization
813 * vectors (as determined by the mode), and station configuration
816 ar5210SetTransmitPower(struct ath_hal
*ah
, HAL_CHANNEL
*chan
)
818 #define N(a) (sizeof (a) / sizeof (a[0]))
819 static const uint32_t pwr_regs_start
[17] = {
820 0x00000000, 0x00000000, 0x00000000,
821 0x00000000, 0x00000000, 0xf0000000,
822 0xcc000000, 0x00000000, 0x00000000,
823 0x00000000, 0x0a000000, 0x000000e2,
824 0x0a000020, 0x01000002, 0x01000018,
825 0x40000000, 0x00000418
828 uint8_t cp
[sizeof(ar5k0007_pwrSettings
)];
829 uint32_t pwr_regs
[17];
831 OS_MEMCPY(pwr_regs
, pwr_regs_start
, sizeof(pwr_regs
));
832 OS_MEMCPY(cp
, ar5k0007_pwrSettings
, sizeof(cp
));
834 /* Check the EEPROM tx power calibration settings */
835 if (!setupPowerSettings(ah
, chan
, cp
)) {
837 ath_hal_printf(ah
, "%s: unable to setup power settings\n",
842 if (cp
[15] < 1 || cp
[15] > 5) {
844 ath_hal_printf(ah
, "%s: OB out of range (%u)\n",
849 if (cp
[16] < 1 || cp
[16] > 5) {
851 ath_hal_printf(ah
, "%s: DB out of range (%u)\n",
857 /* reverse bits of the transmit power array */
858 for (i
= 0; i
< 7; i
++)
859 cp
[i
] = ath_hal_reverseBits(cp
[i
], 5);
860 for (i
= 7; i
< 15; i
++)
861 cp
[i
] = ath_hal_reverseBits(cp
[i
], 6);
863 /* merge transmit power values into the register */
864 pwr_regs
[0] |= ((cp
[1] << 5) & 0xE0) | (cp
[0] & 0x1F);
865 pwr_regs
[1] |= ((cp
[3] << 7) & 0x80) | ((cp
[2] << 2) & 0x7C) |
866 ((cp
[1] >> 3) & 0x03);
867 pwr_regs
[2] |= ((cp
[4] << 4) & 0xF0) | ((cp
[3] >> 1) & 0x0F);
868 pwr_regs
[3] |= ((cp
[6] << 6) & 0xC0) | ((cp
[5] << 1) & 0x3E) |
869 ((cp
[4] >> 4) & 0x01);
870 pwr_regs
[4] |= ((cp
[7] << 3) & 0xF8) | ((cp
[6] >> 2) & 0x07);
871 pwr_regs
[5] |= ((cp
[9] << 7) & 0x80) | ((cp
[8] << 1) & 0x7E) |
872 ((cp
[7] >> 5) & 0x01);
873 pwr_regs
[6] |= ((cp
[10] << 5) & 0xE0) | ((cp
[9] >> 1) & 0x1F);
874 pwr_regs
[7] |= ((cp
[11] << 3) & 0xF8) | ((cp
[10] >> 3) & 0x07);
875 pwr_regs
[8] |= ((cp
[12] << 1) & 0x7E) | ((cp
[11] >> 5) & 0x01);
876 pwr_regs
[9] |= ((cp
[13] << 5) & 0xE0);
877 pwr_regs
[10] |= ((cp
[14] << 3) & 0xF8) | ((cp
[13] >> 3) & 0x07);
878 pwr_regs
[11] |= ((cp
[14] >> 5) & 0x01);
881 pwr_regs
[8] |= (ath_hal_reverseBits(cp
[15], 3) << 7) & 0x80;
882 pwr_regs
[9] |= (ath_hal_reverseBits(cp
[15], 3) >> 1) & 0x03;
885 pwr_regs
[9] |= (ath_hal_reverseBits(cp
[16], 3) << 2) & 0x1C;
887 /* Write the registers */
888 for (i
= 0; i
< N(pwr_regs
)-1; i
++)
889 OS_REG_WRITE(ah
, 0x0000989c, pwr_regs
[i
]);
890 /* last write is a flush */
891 OS_REG_WRITE(ah
, 0x000098d4, pwr_regs
[i
]);
898 * Takes the MHz channel value and sets the Channel value
900 * ASSUMES: Writes enabled to analog bus before AGC is active
901 * or by disabling the AGC.
904 ar5210SetChannel(struct ath_hal
*ah
, HAL_CHANNEL_INTERNAL
*chan
)
908 /* Set the Channel */
909 data
= ath_hal_reverseBits((chan
->channel
- 5120)/10, 5);
910 data
= (data
<< 1) | 0x41;
911 OS_REG_WRITE(ah
, AR_PHY(0x27), data
);
912 OS_REG_WRITE(ah
, AR_PHY(0x30), 0);
913 AH_PRIVATE(ah
)->ah_curchan
= chan
;
918 ar5210GetNoiseFloor(struct ath_hal
*ah
)
922 nf
= (OS_REG_READ(ah
, AR_PHY(25)) >> 19) & 0x1ff;
924 nf
= 0 - ((nf
^ 0x1ff) + 1);
928 #define NORMAL_NF_THRESH (-72)
930 * Peform the noisefloor calibration and check for
931 * any constant channel interference
933 * Returns: TRUE for a successful noise floor calibration; else FALSE
936 ar5210CalNoiseFloor(struct ath_hal
*ah
, HAL_CHANNEL_INTERNAL
*chan
)
940 /* Calibrate the noise floor */
941 OS_REG_WRITE(ah
, AR_PHY_AGCCTL
,
942 OS_REG_READ(ah
, AR_PHY_AGCCTL
) | AR_PHY_AGC_NF
);
944 /* Do not read noise floor until it has done the first update */
945 if (!ath_hal_wait(ah
, AR_PHY_AGCCTL
, AR_PHY_AGC_NF
, 0)) {
947 ath_hal_printf(ah
, " -PHY NF Reg state: 0x%x\n",
948 OS_REG_READ(ah
, AR_PHY_AGCCTL
));
949 ath_hal_printf(ah
, " -MAC Reset Reg state: 0x%x\n",
950 OS_REG_READ(ah
, AR_RC
));
951 ath_hal_printf(ah
, " -PHY Active Reg state: 0x%x\n",
952 OS_REG_READ(ah
, AR_PHY_ACTIVE
));
953 #endif /* ATH_HAL_DEBUG */
958 /* Keep checking until the floor is below the threshold or the nf is done */
959 for (nfLoops
= 0; ((nfLoops
< 21) && (nf
> NORMAL_NF_THRESH
)); nfLoops
++) {
960 OS_DELAY(1000); /* Sleep for 1 ms */
961 nf
= ar5210GetNoiseFloor(ah
);
964 if (nf
> NORMAL_NF_THRESH
) {
965 HALDEBUG(ah
, HAL_DEBUG_ANY
, "%s: Bad noise cal %d\n",
967 chan
->rawNoiseFloor
= 0;
970 chan
->rawNoiseFloor
= nf
;
975 * Adjust NF based on statistical values for 5GHz frequencies.
978 ar5210GetNfAdjust(struct ath_hal
*ah
, const HAL_CHANNEL_INTERNAL
*c
)
984 ar5210GetRfgain(struct ath_hal
*ah
)
986 return HAL_RFGAIN_INACTIVE
;
988 #endif /* AH_SUPPORT_AR5210 */