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.
17 * $Id: ar5210_reset.c,v 1.4 2009/01/06 06:03:57 mrg Exp $
22 #include "ah_internal.h"
24 #include "ar5210/ar5210.h"
25 #include "ar5210/ar5210reg.h"
26 #include "ar5210/ar5210phy.h"
28 #include "ah_eeprom_v1.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 waitTime
);
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 const HAL_EEPROM_v1
*ee
= AH_PRIVATE(ah
)->ah_eeprom
;
77 HAL_CHANNEL_INTERNAL
*ichan
;
82 HALDEBUG(ah
, HAL_DEBUG_RESET
,
83 "%s: opmode %u channel %u/0x%x %s channel\n", __func__
,
84 opmode
, chan
->channel
, chan
->channelFlags
,
85 bChannelChange
? "change" : "same");
87 if ((chan
->channelFlags
& CHANNEL_5GHZ
) == 0) {
89 HALDEBUG(ah
, HAL_DEBUG_ANY
, "%s: channel not 5Ghz\n", __func__
);
93 * Map public channel to private.
95 ichan
= ath_hal_checkchannel(ah
, chan
);
96 if (ichan
== AH_NULL
) {
97 HALDEBUG(ah
, HAL_DEBUG_ANY
,
98 "%s: invalid channel %u/0x%x; no mapping\n",
99 __func__
, chan
->channel
, chan
->channelFlags
);
109 HALDEBUG(ah
, HAL_DEBUG_ANY
, "%s: invalid operating mode %u\n",
115 ledstate
= OS_REG_READ(ah
, AR_PCICFG
) &
116 (AR_PCICFG_LED_PEND
| AR_PCICFG_LED_ACT
);
118 if (!ar5210ChipReset(ah
, chan
)) {
119 HALDEBUG(ah
, HAL_DEBUG_ANY
, "%s: chip reset failed\n",
124 OS_REG_WRITE(ah
, AR_STA_ID0
, LE_READ_4(ahp
->ah_macaddr
));
125 OS_REG_WRITE(ah
, AR_STA_ID1
, LE_READ_2(ahp
->ah_macaddr
+ 4));
126 ar5210SetOperatingMode(ah
, opmode
);
130 OS_REG_WRITE(ah
, AR_BCR
, INIT_BCON_CNTRL_REG
);
131 OS_REG_WRITE(ah
, AR_PCICFG
,
132 AR_PCICFG_LED_ACT
| AR_PCICFG_LED_BCTL
);
135 OS_REG_WRITE(ah
, AR_BCR
, INIT_BCON_CNTRL_REG
| AR_BCR_BCMD
);
136 OS_REG_WRITE(ah
, AR_PCICFG
,
137 AR_PCICFG_CLKRUNEN
| AR_PCICFG_LED_PEND
| AR_PCICFG_LED_BCTL
);
140 OS_REG_WRITE(ah
, AR_BCR
, INIT_BCON_CNTRL_REG
);
141 OS_REG_WRITE(ah
, AR_PCICFG
,
142 AR_PCICFG_CLKRUNEN
| AR_PCICFG_LED_PEND
| AR_PCICFG_LED_BCTL
);
145 OS_REG_WRITE(ah
, AR_BCR
, INIT_BCON_CNTRL_REG
);
146 OS_REG_WRITE(ah
, AR_PCICFG
,
147 AR_PCICFG_LED_ACT
| AR_PCICFG_LED_BCTL
);
151 /* Restore previous led state */
152 OS_REG_WRITE(ah
, AR_PCICFG
, OS_REG_READ(ah
, AR_PCICFG
) | ledstate
);
154 OS_REG_WRITE(ah
, AR_BSS_ID0
, LE_READ_4(ahp
->ah_bssid
));
155 OS_REG_WRITE(ah
, AR_BSS_ID1
, LE_READ_2(ahp
->ah_bssid
+ 4));
157 OS_REG_WRITE(ah
, AR_TXDP0
, 0);
158 OS_REG_WRITE(ah
, AR_TXDP1
, 0);
159 OS_REG_WRITE(ah
, AR_RXDP
, 0);
162 * Initialize interrupt state.
164 (void) OS_REG_READ(ah
, AR_ISR
); /* cleared on read */
165 OS_REG_WRITE(ah
, AR_IMR
, 0);
166 OS_REG_WRITE(ah
, AR_IER
, AR_IER_DISABLE
);
169 (void) OS_REG_READ(ah
, AR_BSR
); /* cleared on read */
170 OS_REG_WRITE(ah
, AR_TXCFG
, AR_DMASIZE_128B
);
171 OS_REG_WRITE(ah
, AR_RXCFG
, AR_DMASIZE_128B
);
173 OS_REG_WRITE(ah
, AR_TOPS
, 8); /* timeout prescale */
174 OS_REG_WRITE(ah
, AR_RXNOFRM
, 8); /* RX no frame timeout */
175 OS_REG_WRITE(ah
, AR_RPGTO
, 0); /* RX frame gap timeout */
176 OS_REG_WRITE(ah
, AR_TXNOFRM
, 0); /* TX no frame timeout */
178 OS_REG_WRITE(ah
, AR_SFR
, 0);
179 OS_REG_WRITE(ah
, AR_MIBC
, 0); /* unfreeze ctrs + clr state */
180 OS_REG_WRITE(ah
, AR_RSSI_THR
, ahp
->ah_rssiThr
);
181 OS_REG_WRITE(ah
, AR_CFP_DUR
, 0);
183 ar5210SetRxFilter(ah
, 0); /* nothing for now */
184 OS_REG_WRITE(ah
, AR_MCAST_FIL0
, 0); /* multicast filter */
185 OS_REG_WRITE(ah
, AR_MCAST_FIL1
, 0); /* XXX was 2 */
187 OS_REG_WRITE(ah
, AR_TX_MASK0
, 0);
188 OS_REG_WRITE(ah
, AR_TX_MASK1
, 0);
189 OS_REG_WRITE(ah
, AR_CLR_TMASK
, 1);
190 OS_REG_WRITE(ah
, AR_TRIG_LEV
, 1); /* minimum */
192 OS_REG_WRITE(ah
, AR_DIAG_SW
, 0);
194 OS_REG_WRITE(ah
, AR_CFP_PERIOD
, 0);
195 OS_REG_WRITE(ah
, AR_TIMER0
, 0); /* next beacon time */
196 OS_REG_WRITE(ah
, AR_TSF_L32
, 0); /* local clock */
197 OS_REG_WRITE(ah
, AR_TIMER1
, ~0); /* next DMA beacon alert */
198 OS_REG_WRITE(ah
, AR_TIMER2
, ~0); /* next SW beacon alert */
199 OS_REG_WRITE(ah
, AR_TIMER3
, 1); /* next ATIM window */
201 /* Write the INI values for PHYreg initialization */
202 for (i
= 0; i
< N(ar5k0007_init
); i
++) {
203 uint32_t reg
= ar5k0007_init
[i
].Offset
;
204 /* On channel change, don't reset the PCU registers */
205 if (!(bChannelChange
&& (0x8000 <= reg
&& reg
< 0x9000)))
206 OS_REG_WRITE(ah
, reg
, ar5k0007_init
[i
].Value
);
209 /* Setup the transmit power values for cards since 0x0[0-2]05 */
210 if (!ar5210SetTransmitPower(ah
, chan
)) {
211 HALDEBUG(ah
, HAL_DEBUG_ANY
,
212 "%s: error init'ing transmit power\n", __func__
);
216 OS_REG_WRITE(ah
, AR_PHY(10),
217 (OS_REG_READ(ah
, AR_PHY(10)) & 0xFFFF00FF) |
218 (ee
->ee_xlnaOn
<< 8));
219 OS_REG_WRITE(ah
, AR_PHY(13),
220 (ee
->ee_xpaOff
<< 24) | (ee
->ee_xpaOff
<< 16) |
221 (ee
->ee_xpaOn
<< 8) | ee
->ee_xpaOn
);
222 OS_REG_WRITE(ah
, AR_PHY(17),
223 (OS_REG_READ(ah
, AR_PHY(17)) & 0xFFFFC07F) |
224 ((ee
->ee_antenna
>> 1) & 0x3F80));
225 OS_REG_WRITE(ah
, AR_PHY(18),
226 (OS_REG_READ(ah
, AR_PHY(18)) & 0xFFFC0FFF) |
227 ((ee
->ee_antenna
<< 10) & 0x3F000));
228 OS_REG_WRITE(ah
, AR_PHY(25),
229 (OS_REG_READ(ah
, AR_PHY(25)) & 0xFFF80FFF) |
230 ((ee
->ee_thresh62
<< 12) & 0x7F000));
231 OS_REG_WRITE(ah
, AR_PHY(68),
232 (OS_REG_READ(ah
, AR_PHY(68)) & 0xFFFFFFFC) |
233 (ee
->ee_antenna
& 0x3));
235 if (!ar5210SetChannel(ah
, ichan
)) {
236 HALDEBUG(ah
, HAL_DEBUG_ANY
, "%s: unable to set channel\n",
240 if (bChannelChange
) {
241 if (!(ichan
->privFlags
& CHANNEL_DFS
))
242 ichan
->privFlags
&= ~CHANNEL_INTERFERENCE
;
243 chan
->channelFlags
= ichan
->channelFlags
;
244 chan
->privFlags
= ichan
->privFlags
;
247 /* Activate the PHY */
248 OS_REG_WRITE(ah
, AR_PHY_ACTIVE
, AR_PHY_ENABLE
);
250 OS_DELAY(1000); /* Wait a bit (1 msec) */
252 /* calibrate the HW and poll the bit going to 0 for completion */
253 OS_REG_WRITE(ah
, AR_PHY_AGCCTL
,
254 OS_REG_READ(ah
, AR_PHY_AGCCTL
) | AR_PHY_AGC_CAL
);
255 (void) ath_hal_wait(ah
, AR_PHY_AGCCTL
, AR_PHY_AGC_CAL
, 0);
257 /* Perform noise floor calibration and set status */
258 if (!ar5210CalNoiseFloor(ah
, ichan
)) {
259 chan
->channelFlags
|= CHANNEL_CW_INT
;
260 HALDEBUG(ah
, HAL_DEBUG_ANY
,
261 "%s: noise floor calibration failed\n", __func__
);
265 for (q
= 0; q
< HAL_NUM_TX_QUEUES
; q
++)
266 ar5210ResetTxQueue(ah
, q
);
268 if (AH_PRIVATE(ah
)->ah_rfkillEnabled
)
269 ar5210EnableRfKill(ah
);
272 * Writing to AR_BEACON will start timers. Hence it should be
273 * the last register to be written. Do not reset tsf, do not
274 * enable beacons at this point, but preserve other values
275 * like beaconInterval.
277 OS_REG_WRITE(ah
, AR_BEACON
,
278 (OS_REG_READ(ah
, AR_BEACON
) &
279 ~(AR_BEACON_EN
| AR_BEACON_RESET_TSF
)));
281 /* Restore user-specified slot time and timeouts */
282 if (ahp
->ah_sifstime
!= (u_int
) -1)
283 ar5210SetSifsTime(ah
, ahp
->ah_sifstime
);
284 if (ahp
->ah_slottime
!= (u_int
) -1)
285 ar5210SetSlotTime(ah
, ahp
->ah_slottime
);
286 if (ahp
->ah_acktimeout
!= (u_int
) -1)
287 ar5210SetAckTimeout(ah
, ahp
->ah_acktimeout
);
288 if (ahp
->ah_ctstimeout
!= (u_int
) -1)
289 ar5210SetCTSTimeout(ah
, ahp
->ah_ctstimeout
);
290 if (AH_PRIVATE(ah
)->ah_diagreg
!= 0)
291 OS_REG_WRITE(ah
, AR_DIAG_SW
, AH_PRIVATE(ah
)->ah_diagreg
);
293 AH_PRIVATE(ah
)->ah_opmode
= opmode
; /* record operating mode */
295 HALDEBUG(ah
, HAL_DEBUG_RESET
, "%s: done\n", __func__
);
307 ar5210SetOperatingMode(struct ath_hal
*ah
, int opmode
)
309 struct ath_hal_5210
*ahp
= AH5210(ah
);
312 val
= OS_REG_READ(ah
, AR_STA_ID1
) & 0xffff;
315 OS_REG_WRITE(ah
, AR_STA_ID1
, val
317 | AR_STA_ID1_NO_PSPOLL
318 | AR_STA_ID1_DESC_ANTENNA
319 | ahp
->ah_staId1Defaults
);
322 OS_REG_WRITE(ah
, AR_STA_ID1
, val
324 | AR_STA_ID1_NO_PSPOLL
325 | AR_STA_ID1_DESC_ANTENNA
326 | ahp
->ah_staId1Defaults
);
329 OS_REG_WRITE(ah
, AR_STA_ID1
, val
330 | AR_STA_ID1_NO_PSPOLL
332 | ahp
->ah_staId1Defaults
);
335 OS_REG_WRITE(ah
, AR_STA_ID1
, val
336 | AR_STA_ID1_NO_PSPOLL
337 | ahp
->ah_staId1Defaults
);
343 ar5210SetPCUConfig(struct ath_hal
*ah
)
345 ar5210SetOperatingMode(ah
, AH_PRIVATE(ah
)->ah_opmode
);
349 * Places the PHY and Radio chips into reset. A full reset
350 * must be called to leave this state. The PCI/MAC/PCU are
351 * not placed into reset as we must receive interrupt to
352 * re-enable the hardware.
355 ar5210PhyDisable(struct ath_hal
*ah
)
357 return ar5210SetResetReg(ah
, AR_RC_RPHY
, 10);
361 * Places all of hardware into reset
364 ar5210Disable(struct ath_hal
*ah
)
366 #define AR_RC_HW (AR_RC_RPCU | AR_RC_RDMA | AR_RC_RPHY | AR_RC_RMAC)
367 if (!ar5210SetPowerMode(ah
, HAL_PM_AWAKE
, AH_TRUE
))
371 * Reset the HW - PCI must be reset after the rest of the
372 * device has been reset
374 if (!ar5210SetResetReg(ah
, AR_RC_HW
, AR_RC_SETTLE_TIME
))
377 (void) ar5210SetResetReg(ah
, AR_RC_HW
| AR_RC_RPCI
, AR_RC_SETTLE_TIME
);
378 OS_DELAY(2100); /* 8245 @ 96Mhz hangs with 2000us. */
385 * Places the hardware into reset and then pulls it out of reset
388 ar5210ChipReset(struct ath_hal
*ah
, HAL_CHANNEL
*chan
)
390 #define AR_RC_HW (AR_RC_RPCU | AR_RC_RDMA | AR_RC_RPHY | AR_RC_RMAC)
392 HALDEBUG(ah
, HAL_DEBUG_RESET
, "%s turbo %s\n", __func__
,
393 chan
&& IS_CHAN_TURBO(chan
) ? "enabled" : "disabled");
395 if (!ar5210SetPowerMode(ah
, HAL_PM_AWAKE
, AH_TRUE
))
398 /* Place chip in turbo before reset to cleanly reset clocks */
399 OS_REG_WRITE(ah
, AR_PHY_FRCTL
,
400 chan
&& IS_CHAN_TURBO(chan
) ? AR_PHY_TURBO_MODE
: 0);
404 * PCI must be reset after the rest of the device has been reset.
406 if (!ar5210SetResetReg(ah
, AR_RC_HW
, AR_RC_SETTLE_TIME
))
409 if (!ar5210SetResetReg(ah
, AR_RC_HW
| AR_RC_RPCI
, AR_RC_SETTLE_TIME
))
411 OS_DELAY(2100); /* 8245 @ 96Mhz hangs with 2000us. */
414 * Bring out of sleep mode (AGAIN)
416 * WARNING WARNING WARNING
418 * There is a problem with the chip where it doesn't always indicate
419 * that it's awake, so initializePowerUp() will fail.
421 if (!ar5210SetPowerMode(ah
, HAL_PM_AWAKE
, AH_TRUE
))
424 /* Clear warm reset reg */
425 return ar5210SetResetReg(ah
, 0, 10);
430 FIRPWR_M
= 0x03fc0000,
432 KCOARSEHIGH_M
= 0x003f8000,
434 KCOARSELOW_M
= 0x00007f80,
436 ADCSAT_ICOUNT_M
= 0x0001f800,
437 ADCSAT_ICOUNT_S
= 11,
438 ADCSAT_THRESH_M
= 0x000007e0,
443 * Recalibrate the lower PHY chips to account for temperature/environment
447 ar5210PerCalibrationN(struct ath_hal
*ah
, HAL_CHANNEL
*chan
, u_int chainMask
,
448 HAL_BOOL longCal
, HAL_BOOL
*isCalDone
)
451 uint32_t reg9858
, reg985c
, reg9868
;
452 HAL_CHANNEL_INTERNAL
*ichan
;
454 ichan
= ath_hal_checkchannel(ah
, chan
);
455 if (ichan
== AH_NULL
) {
456 HALDEBUG(ah
, HAL_DEBUG_ANY
,
457 "%s: invalid channel %u/0x%x; no mapping\n",
458 __func__
, chan
->channel
, chan
->channelFlags
);
461 /* Disable tx and rx */
462 OS_REG_WRITE(ah
, AR_DIAG_SW
,
463 OS_REG_READ(ah
, AR_DIAG_SW
) | (AR_DIAG_SW_DIS_TX
| AR_DIAG_SW_DIS_RX
));
465 /* Disable Beacon Enable */
466 regBeacon
= OS_REG_READ(ah
, AR_BEACON
);
467 OS_REG_WRITE(ah
, AR_BEACON
, regBeacon
& ~AR_BEACON_EN
);
469 /* Delay 4ms to ensure that all tx and rx activity has ceased */
472 /* Disable AGC to radio traffic */
473 OS_REG_WRITE(ah
, 0x9808, OS_REG_READ(ah
, 0x9808) | 0x08000000);
474 /* Wait for the AGC traffic to cease. */
477 /* Change Channel to relock synth */
478 if (!ar5210SetChannel(ah
, ichan
))
481 /* wait for the synthesizer lock to stabilize */
484 /* Re-enable AGC to radio traffic */
485 OS_REG_WRITE(ah
, 0x9808, OS_REG_READ(ah
, 0x9808) & (~0x08000000));
488 * Configure the AGC so that it is highly unlikely (if not
489 * impossible) for it to send any gain changes to the analog
490 * chip. We store off the current values so that they can
491 * be rewritten below. Setting the following values:
498 reg9858
= OS_REG_READ(ah
, 0x9858);
499 reg985c
= OS_REG_READ(ah
, 0x985c);
500 reg9868
= OS_REG_READ(ah
, 0x9868);
502 OS_REG_WRITE(ah
, 0x9858, (reg9858
& ~FIRPWR_M
) |
503 ((-1 << FIRPWR_S
) & FIRPWR_M
));
504 OS_REG_WRITE(ah
, 0x985c,
505 (reg985c
& ~(KCOARSEHIGH_M
| KCOARSELOW_M
)) |
506 ((-1 << KCOARSEHIGH_S
) & KCOARSEHIGH_M
) |
507 ((-127 << KCOARSELOW_S
) & KCOARSELOW_M
));
508 OS_REG_WRITE(ah
, 0x9868,
509 (reg9868
& ~(ADCSAT_ICOUNT_M
| ADCSAT_THRESH_M
)) |
510 ((2 << ADCSAT_ICOUNT_S
) & ADCSAT_ICOUNT_M
) |
511 ((12 << ADCSAT_THRESH_S
) & ADCSAT_THRESH_M
));
513 /* Wait for AGC changes to be enacted */
517 * We disable RF mix/gain stages for the PGA to avoid a
518 * race condition that will occur with receiving a frame
519 * and performing the AGC calibration. This will be
520 * re-enabled at the end of offset cal. We turn off AGC
521 * writes during this write as it will go over the analog bus.
523 OS_REG_WRITE(ah
, 0x9808, OS_REG_READ(ah
, 0x9808) | 0x08000000);
524 OS_DELAY(10); /* wait for the AGC traffic to cease */
525 OS_REG_WRITE(ah
, 0x98D4, 0x21);
526 OS_REG_WRITE(ah
, 0x9808, OS_REG_READ(ah
, 0x9808) & (~0x08000000));
528 /* wait to make sure that additional AGC traffic has quiesced */
531 /* AGC calibration (this was added to make the NF threshold check work) */
532 OS_REG_WRITE(ah
, AR_PHY_AGCCTL
,
533 OS_REG_READ(ah
, AR_PHY_AGCCTL
) | AR_PHY_AGC_CAL
);
534 if (!ath_hal_wait(ah
, AR_PHY_AGCCTL
, AR_PHY_AGC_CAL
, 0)) {
535 HALDEBUG(ah
, HAL_DEBUG_ANY
, "%s: AGC calibration timeout\n",
539 /* Rewrite our AGC values we stored off earlier (return AGC to normal operation) */
540 OS_REG_WRITE(ah
, 0x9858, reg9858
);
541 OS_REG_WRITE(ah
, 0x985c, reg985c
);
542 OS_REG_WRITE(ah
, 0x9868, reg9868
);
544 /* Perform noise floor and set status */
545 if (!ar5210CalNoiseFloor(ah
, ichan
)) {
547 * Delay 5ms before retrying the noise floor -
548 * just to make sure. We're in an error
551 HALDEBUG(ah
, HAL_DEBUG_NFCAL
| HAL_DEBUG_PERCAL
,
552 "%s: Performing 2nd Noise Cal\n", __func__
);
554 if (!ar5210CalNoiseFloor(ah
, ichan
))
555 chan
->channelFlags
|= CHANNEL_CW_INT
;
558 /* Clear tx and rx disable bit */
559 OS_REG_WRITE(ah
, AR_DIAG_SW
,
560 OS_REG_READ(ah
, AR_DIAG_SW
) & ~(AR_DIAG_SW_DIS_TX
| AR_DIAG_SW_DIS_RX
));
562 /* Re-enable Beacons */
563 OS_REG_WRITE(ah
, AR_BEACON
, regBeacon
);
565 *isCalDone
= AH_TRUE
;
571 ar5210PerCalibration(struct ath_hal
*ah
, HAL_CHANNEL
*chan
, HAL_BOOL
*isIQdone
)
573 return ar5210PerCalibrationN(ah
, chan
, 0x1, AH_TRUE
, isIQdone
);
577 ar5210ResetCalValid(struct ath_hal
*ah
, HAL_CHANNEL
*chan
)
583 * Writes the given reset bit mask into the reset register
586 ar5210SetResetReg(struct ath_hal
*ah
, uint32_t resetMask
, u_int waitTime
)
588 uint32_t mask
= resetMask
? resetMask
: ~0;
591 OS_REG_WRITE(ah
, AR_RC
, resetMask
);
592 /* need to wait at least 128 clocks when reseting PCI before read */
595 resetMask
&= AR_RC_RPCU
| AR_RC_RDMA
| AR_RC_RPHY
| AR_RC_RMAC
;
596 mask
&= AR_RC_RPCU
| AR_RC_RDMA
| AR_RC_RPHY
| AR_RC_RMAC
;
597 rt
= ath_hal_wait(ah
, AR_RC
, mask
, resetMask
);
598 if ((resetMask
& AR_RC_RMAC
) == 0) {
601 * Set CFG, little-endian for register
602 * and descriptor accesses.
604 mask
= INIT_CONFIG_STATUS
|
605 AR_CFG_SWTD
| AR_CFG_SWRD
| AR_CFG_SWRG
;
606 OS_REG_WRITE(ah
, AR_CFG
, LE_READ_4(&mask
));
608 OS_REG_WRITE(ah
, AR_CFG
, INIT_CONFIG_STATUS
);
615 * Returns: the pcdac value
618 getPcdac(struct ath_hal
*ah
, const struct tpcMap
*pRD
, uint8_t dBm
)
621 int useNextEntry
= AH_FALSE
;
624 for (i
= AR_TP_SCALING_ENTRIES
- 1; i
>= 0; i
--) {
625 /* Check for exact entry */
626 if (dBm
== AR_I2DBM(i
)) {
627 if (pRD
->pcdac
[i
] != 63)
628 return pRD
->pcdac
[i
];
629 useNextEntry
= AH_TRUE
;
630 } else if (dBm
+ 1 == AR_I2DBM(i
) && i
> 0) {
631 /* Interpolate for between entry with a logish scale */
632 if (pRD
->pcdac
[i
] != 63 && pRD
->pcdac
[i
-1] != 63) {
633 interp
= (350 * (pRD
->pcdac
[i
] - pRD
->pcdac
[i
-1])) + 999;
634 interp
= (interp
/ 1000) + pRD
->pcdac
[i
-1];
637 useNextEntry
= AH_TRUE
;
638 } else if (useNextEntry
== AH_TRUE
) {
639 /* Grab the next lowest */
640 if (pRD
->pcdac
[i
] != 63)
641 return pRD
->pcdac
[i
];
645 /* Return the lowest Entry if we haven't returned */
646 for (i
= 0; i
< AR_TP_SCALING_ENTRIES
; i
++)
647 if (pRD
->pcdac
[i
] != 63)
648 return pRD
->pcdac
[i
];
650 /* No value to return from table */
652 ath_hal_printf(ah
, "%s: empty transmit power table?\n", __func__
);
658 * Find or interpolates the gainF value from the table ptr.
661 getGainF(struct ath_hal
*ah
, const struct tpcMap
*pRD
,
662 uint8_t pcdac
, uint8_t *dBm
)
669 for (i
= 0; i
< AR_TP_SCALING_ENTRIES
; i
++) {
670 if(pRD
->pcdac
[i
] == 63)
672 if (pcdac
== pRD
->pcdac
[i
]) {
674 return pRD
->gainF
[i
]; /* Exact Match */
676 if (pcdac
> pRD
->pcdac
[i
])
678 if (pcdac
< pRD
->pcdac
[i
]) {
682 /* PCDAC is lower than lowest setting */
683 return pRD
->gainF
[i
];
688 if (i
>= AR_TP_SCALING_ENTRIES
&& low
== -1) {
689 /* No settings were found */
692 "%s: no valid entries in the pcdac table: %d\n",
697 if (i
>= AR_TP_SCALING_ENTRIES
) {
698 /* PCDAC setting was above the max setting in the table */
699 *dBm
= AR_I2DBM(low
);
700 return pRD
->gainF
[low
];
702 /* Only exact if table has no missing entries */
703 *dBm
= (low
+ high
) + 3;
706 * Perform interpolation between low and high values to find gainF
707 * linearly scale the pcdac between low and high
709 interp
= ((pcdac
- pRD
->pcdac
[low
]) * 1000) /
710 (pRD
->pcdac
[high
] - pRD
->pcdac
[low
]);
712 * Multiply the scale ratio by the gainF difference
713 * (plus a rnd up factor)
715 interp
= ((interp
* (pRD
->gainF
[high
] - pRD
->gainF
[low
])) + 999) / 1000;
717 /* Add ratioed gain_f to low gain_f value */
718 return interp
+ pRD
->gainF
[low
];
722 ar5210SetTxPowerLimit(struct ath_hal
*ah
, uint32_t limit
)
724 AH_PRIVATE(ah
)->ah_powerLimit
= AH_MIN(limit
, AR5210_MAX_RATE_POWER
);
725 /* XXX flush to h/w */
730 * Get TXPower values and set them in the radio
733 setupPowerSettings(struct ath_hal
*ah
, HAL_CHANNEL
*chan
, uint8_t cp
[17])
735 const HAL_EEPROM_v1
*ee
= AH_PRIVATE(ah
)->ah_eeprom
;
736 uint8_t gainFRD
, gainF36
, gainF48
, gainF54
;
737 uint8_t dBmRD
= 0, dBm36
= 0, dBm48
= 0, dBm54
= 0, dontcare
;
739 const struct tpcMap
*pRD
;
741 /* Set OB/DB Values regardless of channel */
742 cp
[15] = (ee
->ee_biasCurrents
>> 4) & 0x7;
743 cp
[16] = ee
->ee_biasCurrents
& 0x7;
745 if (chan
->channel
< 5170 || chan
->channel
> 5320) {
746 HALDEBUG(ah
, HAL_DEBUG_ANY
, "%s: invalid channel %u\n",
747 __func__
, chan
->channel
);
751 HALASSERT(ee
->ee_version
>= AR_EEPROM_VER1
&&
752 ee
->ee_version
< AR_EEPROM_VER3
);
754 /* Match regulatory domain */
755 for (rd
= 0; rd
< AR_REG_DOMAINS_MAX
; rd
++)
756 if (AH_PRIVATE(ah
)->ah_currentRD
== ee
->ee_regDomain
[rd
])
758 if (rd
== AR_REG_DOMAINS_MAX
) {
761 "%s: no calibrated regulatory domain matches the "
762 "current regularly domain (0x%0x)\n", __func__
,
763 AH_PRIVATE(ah
)->ah_currentRD
);
767 group
= ((chan
->channel
- 5170) / 10);
770 /* Pull 5.29 into the 5.27 group */
774 /* Integer divide will set group from 0 to 4 */
776 pRD
= &ee
->ee_tpc
[group
];
778 /* Set PC DAC Values */
779 cp
[14] = pRD
->regdmn
[rd
];
780 cp
[9] = AH_MIN(pRD
->regdmn
[rd
], pRD
->rate36
);
781 cp
[8] = AH_MIN(pRD
->regdmn
[rd
], pRD
->rate48
);
782 cp
[7] = AH_MIN(pRD
->regdmn
[rd
], pRD
->rate54
);
784 /* Find Corresponding gainF values for RD, 36, 48, 54 */
785 gainFRD
= getGainF(ah
, pRD
, pRD
->regdmn
[rd
], &dBmRD
);
786 gainF36
= getGainF(ah
, pRD
, cp
[9], &dBm36
);
787 gainF48
= getGainF(ah
, pRD
, cp
[8], &dBm48
);
788 gainF54
= getGainF(ah
, pRD
, cp
[7], &dBm54
);
790 /* Power Scale if requested */
791 if (AH_PRIVATE(ah
)->ah_tpScale
!= HAL_TP_SCALE_MAX
) {
792 static const uint16_t tpcScaleReductionTable
[5] =
793 { 0, 3, 6, 9, AR5210_MAX_RATE_POWER
};
796 tpScale
= tpcScaleReductionTable
[AH_PRIVATE(ah
)->ah_tpScale
];
797 if (dBmRD
< tpScale
+3)
801 cp
[14] = getPcdac(ah
, pRD
, dBmRD
);
802 gainFRD
= getGainF(ah
, pRD
, cp
[14], &dontcare
);
803 dBm36
= AH_MIN(dBm36
, dBmRD
);
804 cp
[9] = getPcdac(ah
, pRD
, dBm36
);
805 gainF36
= getGainF(ah
, pRD
, cp
[9], &dontcare
);
806 dBm48
= AH_MIN(dBm48
, dBmRD
);
807 cp
[8] = getPcdac(ah
, pRD
, dBm48
);
808 gainF48
= getGainF(ah
, pRD
, cp
[8], &dontcare
);
809 dBm54
= AH_MIN(dBm54
, dBmRD
);
810 cp
[7] = getPcdac(ah
, pRD
, dBm54
);
811 gainF54
= getGainF(ah
, pRD
, cp
[7], &dontcare
);
813 /* Record current dBm at rate 6 */
814 AH_PRIVATE(ah
)->ah_maxPowerLevel
= 2*dBmRD
;
816 cp
[13] = cp
[12] = cp
[11] = cp
[10] = cp
[14];
818 /* Set GainF Values */
819 cp
[0] = gainFRD
- gainF54
;
820 cp
[1] = gainFRD
- gainF48
;
821 cp
[2] = gainFRD
- gainF36
;
822 /* 9, 12, 18, 24 have no gain_delta from 6 */
823 cp
[3] = cp
[4] = cp
[5] = cp
[6] = 0;
828 * Places the device in and out of reset and then places sane
829 * values in the registers based on EEPROM config, initialization
830 * vectors (as determined by the mode), and station configuration
833 ar5210SetTransmitPower(struct ath_hal
*ah
, HAL_CHANNEL
*chan
)
835 #define N(a) (sizeof (a) / sizeof (a[0]))
836 static const uint32_t pwr_regs_start
[17] = {
837 0x00000000, 0x00000000, 0x00000000,
838 0x00000000, 0x00000000, 0xf0000000,
839 0xcc000000, 0x00000000, 0x00000000,
840 0x00000000, 0x0a000000, 0x000000e2,
841 0x0a000020, 0x01000002, 0x01000018,
842 0x40000000, 0x00000418
845 uint8_t cp
[sizeof(ar5k0007_pwrSettings
)];
846 uint32_t pwr_regs
[17];
848 OS_MEMCPY(pwr_regs
, pwr_regs_start
, sizeof(pwr_regs
));
849 OS_MEMCPY(cp
, ar5k0007_pwrSettings
, sizeof(cp
));
851 /* Check the EEPROM tx power calibration settings */
852 if (!setupPowerSettings(ah
, chan
, cp
)) {
854 ath_hal_printf(ah
, "%s: unable to setup power settings\n",
859 if (cp
[15] < 1 || cp
[15] > 5) {
861 ath_hal_printf(ah
, "%s: OB out of range (%u)\n",
866 if (cp
[16] < 1 || cp
[16] > 5) {
868 ath_hal_printf(ah
, "%s: DB out of range (%u)\n",
874 /* reverse bits of the transmit power array */
875 for (i
= 0; i
< 7; i
++)
876 cp
[i
] = ath_hal_reverseBits(cp
[i
], 5);
877 for (i
= 7; i
< 15; i
++)
878 cp
[i
] = ath_hal_reverseBits(cp
[i
], 6);
880 /* merge transmit power values into the register - quite gross */
881 pwr_regs
[0] |= ((cp
[1] << 5) & 0xE0) | (cp
[0] & 0x1F);
882 pwr_regs
[1] |= ((cp
[3] << 7) & 0x80) | ((cp
[2] << 2) & 0x7C) |
883 ((cp
[1] >> 3) & 0x03);
884 pwr_regs
[2] |= ((cp
[4] << 4) & 0xF0) | ((cp
[3] >> 1) & 0x0F);
885 pwr_regs
[3] |= ((cp
[6] << 6) & 0xC0) | ((cp
[5] << 1) & 0x3E) |
886 ((cp
[4] >> 4) & 0x01);
887 pwr_regs
[4] |= ((cp
[7] << 3) & 0xF8) | ((cp
[6] >> 2) & 0x07);
888 pwr_regs
[5] |= ((cp
[9] << 7) & 0x80) | ((cp
[8] << 1) & 0x7E) |
889 ((cp
[7] >> 5) & 0x01);
890 pwr_regs
[6] |= ((cp
[10] << 5) & 0xE0) | ((cp
[9] >> 1) & 0x1F);
891 pwr_regs
[7] |= ((cp
[11] << 3) & 0xF8) | ((cp
[10] >> 3) & 0x07);
892 pwr_regs
[8] |= ((cp
[12] << 1) & 0x7E) | ((cp
[11] >> 5) & 0x01);
893 pwr_regs
[9] |= ((cp
[13] << 5) & 0xE0);
894 pwr_regs
[10] |= ((cp
[14] << 3) & 0xF8) | ((cp
[13] >> 3) & 0x07);
895 pwr_regs
[11] |= ((cp
[14] >> 5) & 0x01);
898 pwr_regs
[8] |= (ath_hal_reverseBits(cp
[15], 3) << 7) & 0x80;
899 pwr_regs
[9] |= (ath_hal_reverseBits(cp
[15], 3) >> 1) & 0x03;
902 pwr_regs
[9] |= (ath_hal_reverseBits(cp
[16], 3) << 2) & 0x1C;
904 /* Write the registers */
905 for (i
= 0; i
< N(pwr_regs
)-1; i
++)
906 OS_REG_WRITE(ah
, 0x0000989c, pwr_regs
[i
]);
907 /* last write is a flush */
908 OS_REG_WRITE(ah
, 0x000098d4, pwr_regs
[i
]);
915 * Takes the MHz channel value and sets the Channel value
917 * ASSUMES: Writes enabled to analog bus before AGC is active
918 * or by disabling the AGC.
921 ar5210SetChannel(struct ath_hal
*ah
, HAL_CHANNEL_INTERNAL
*chan
)
925 /* Set the Channel */
926 data
= ath_hal_reverseBits((chan
->channel
- 5120)/10, 5);
927 data
= (data
<< 1) | 0x41;
928 OS_REG_WRITE(ah
, AR_PHY(0x27), data
);
929 OS_REG_WRITE(ah
, AR_PHY(0x30), 0);
930 AH_PRIVATE(ah
)->ah_curchan
= chan
;
935 ar5210GetNoiseFloor(struct ath_hal
*ah
)
939 nf
= (OS_REG_READ(ah
, AR_PHY(25)) >> 19) & 0x1ff;
941 nf
= 0 - ((nf
^ 0x1ff) + 1);
945 #define NORMAL_NF_THRESH (-72)
947 * Peform the noisefloor calibration and check for
948 * any constant channel interference
950 * Returns: TRUE for a successful noise floor calibration; else FALSE
953 ar5210CalNoiseFloor(struct ath_hal
*ah
, HAL_CHANNEL_INTERNAL
*chan
)
957 /* Calibrate the noise floor */
958 OS_REG_WRITE(ah
, AR_PHY_AGCCTL
,
959 OS_REG_READ(ah
, AR_PHY_AGCCTL
) | AR_PHY_AGC_NF
);
961 /* Do not read noise floor until it has done the first update */
962 if (!ath_hal_wait(ah
, AR_PHY_AGCCTL
, AR_PHY_AGC_NF
, 0)) {
964 ath_hal_printf(ah
, " -PHY NF Reg state: 0x%x\n",
965 OS_REG_READ(ah
, AR_PHY_AGCCTL
));
966 ath_hal_printf(ah
, " -MAC Reset Reg state: 0x%x\n",
967 OS_REG_READ(ah
, AR_RC
));
968 ath_hal_printf(ah
, " -PHY Active Reg state: 0x%x\n",
969 OS_REG_READ(ah
, AR_PHY_ACTIVE
));
970 #endif /* ATH_HAL_DEBUG */
975 /* Keep checking until the floor is below the threshold or the nf is done */
976 for (nfLoops
= 0; ((nfLoops
< 21) && (nf
> NORMAL_NF_THRESH
)); nfLoops
++) {
977 OS_DELAY(1000); /* Sleep for 1 ms */
978 nf
= ar5210GetNoiseFloor(ah
);
981 if (nf
> NORMAL_NF_THRESH
) {
982 HALDEBUG(ah
, HAL_DEBUG_ANY
, "%s: Bad noise cal %d\n",
984 chan
->rawNoiseFloor
= 0;
987 chan
->rawNoiseFloor
= nf
;
992 * Adjust NF based on statistical values for 5GHz frequencies.
995 ar5210GetNfAdjust(struct ath_hal
*ah
, const HAL_CHANNEL_INTERNAL
*c
)
1001 ar5210GetRfgain(struct ath_hal
*ah
)
1003 return HAL_RFGAIN_INACTIVE
;