📄 ar5210_reset.c
字号:
/* * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting * Copyright (c) 2002-2005 Atheros Communications, Inc. * All rights reserved. * * $Id: ar5210_reset.c,v 1.1.1.1 2006/09/12 03:45:22 steven Exp $ */#include "opt_ah.h"#ifdef AH_SUPPORT_AR5210#include "ah.h"#include "ah_internal.h"#include "ar5210/ar5210.h"#include "ar5210/ar5210reg.h"#include "ar5210/ar5210phy.h"typedef struct { u_int32_t Offset; u_int32_t Value;} REGISTER_VAL;static const REGISTER_VAL ar5k0007_init[] = {#include "ar5210/ar5k_0007.ini"};/* Default Power Settings for channels outside of EEPROM range */static const u_int8_t ar5k0007_pwrSettings[17] = {/* gain delta pc dac *//* 54 48 36 24 18 12 9 54 48 36 24 18 12 9 6 ob db */ 9, 9, 0, 0, 0, 0, 0, 2, 2, 6, 6, 6, 6, 6, 6, 2, 2};/* * The delay, in usecs, between writing AR_RC with a reset * request and waiting for the chip to settle. If this is * too short then the chip does not come out of sleep state. * Note this value was empirically derived and may be dependent * on the host machine (don't know--the problem was identified * on an IBM 570e laptop; 10us delays worked on other systems). */#define AR_RC_SETTLE_TIME 20000static HAL_BOOL ar5210SetResetReg(struct ath_hal *, u_int32_t resetMask, u_int delay);static HAL_BOOL ar5210SetChannel(struct ath_hal *ah, HAL_CHANNEL *chan);/* * Places the device in and out of reset and then places sane * values in the registers based on EEPROM config, initialization * vectors (as determined by the mode), and station configuration * * bChannelChange is used to preserve DMA/PCU registers across * a HW Reset during channel change. */HAL_BOOLar5210Reset(struct ath_hal *ah, HAL_OPMODE opmode, HAL_CHANNEL *chan, HAL_BOOL bChannelChange, HAL_STATUS *status){#define N(a) (sizeof (a) /sizeof (a[0]))#define FAIL(_code) do { ecode = _code; goto bad; } while (0) struct ath_hal_5210 *ahp = AH5210(ah); HAL_STATUS ecode; u_int32_t ledstate; int i, q; HALDEBUG(ah, "%s: opmode %u channel %u/0x%x %s channel\n", __func__, opmode, chan->channel, chan->channelFlags, bChannelChange ? "change" : "same"); if ((chan->channelFlags & CHANNEL_5GHZ) == 0) { /* Only 11a mode */ HALDEBUG(ah, "%s: channel not 5Ghz\n", __func__); FAIL(HAL_EINVAL); } switch (opmode) { case HAL_M_STA: case HAL_M_IBSS: case HAL_M_HOSTAP: case HAL_M_MONITOR: break; default: HALDEBUG(ah, "%s: invalid operating mode %u\n", __func__, opmode); FAIL(HAL_EINVAL); break; } ledstate = OS_REG_READ(ah, AR_PCICFG) & (AR_PCICFG_LED_PEND | AR_PCICFG_LED_ACT); if (!ar5210ChipReset(ah, chan)) { HALDEBUG(ah, "%s: chip reset failed\n", __func__); FAIL(HAL_EIO); } OS_REG_WRITE(ah, AR_STA_ID0, LE_READ_4(ahp->ah_macaddr)); switch (opmode) { case HAL_M_HOSTAP: OS_REG_WRITE(ah, AR_STA_ID1, LE_READ_2(ahp->ah_macaddr + 4) | AR_STA_ID1_AP | AR_STA_ID1_NO_PSPOLL | AR_STA_ID1_DESC_ANTENNA); OS_REG_WRITE(ah, AR_BCR, INIT_BCON_CNTRL_REG); OS_REG_WRITE(ah, AR_PCICFG, AR_PCICFG_LED_ACT | AR_PCICFG_LED_BCTL); break; case HAL_M_IBSS: OS_REG_WRITE(ah, AR_STA_ID1, LE_READ_2(ahp->ah_macaddr + 4) | AR_STA_ID1_ADHOC | AR_STA_ID1_NO_PSPOLL | AR_STA_ID1_DESC_ANTENNA); OS_REG_WRITE(ah, AR_BCR, INIT_BCON_CNTRL_REG | AR_BCR_BCMD); OS_REG_WRITE(ah, AR_PCICFG, AR_PCICFG_CLKRUNEN | AR_PCICFG_LED_PEND | AR_PCICFG_LED_BCTL); break; case HAL_M_STA: OS_REG_WRITE(ah, AR_STA_ID1, LE_READ_2(ahp->ah_macaddr + 4) | AR_STA_ID1_NO_PSPOLL | AR_STA_ID1_PWR_SV); OS_REG_WRITE(ah, AR_BCR, INIT_BCON_CNTRL_REG); OS_REG_WRITE(ah, AR_PCICFG, AR_PCICFG_CLKRUNEN | AR_PCICFG_LED_PEND | AR_PCICFG_LED_BCTL); break; case HAL_M_MONITOR: OS_REG_WRITE(ah, AR_STA_ID1, LE_READ_2(ahp->ah_macaddr + 4) | AR_STA_ID1_NO_PSPOLL); OS_REG_WRITE(ah, AR_BCR, INIT_BCON_CNTRL_REG); OS_REG_WRITE(ah, AR_PCICFG, AR_PCICFG_LED_ACT | AR_PCICFG_LED_BCTL); break; } /* Restore previous led state */ OS_REG_WRITE(ah, AR_PCICFG, OS_REG_READ(ah, AR_PCICFG) | ledstate); OS_REG_WRITE(ah, AR_BSS_ID0, LE_READ_4(ahp->ah_bssid)); OS_REG_WRITE(ah, AR_BSS_ID1, LE_READ_2(ahp->ah_bssid + 4)); OS_REG_WRITE(ah, AR_TXDP0, 0); OS_REG_WRITE(ah, AR_TXDP1, 0); OS_REG_WRITE(ah, AR_RXDP, 0); /* * Initialize interrupt state. */ (void) OS_REG_READ(ah, AR_ISR); /* cleared on read */ OS_REG_WRITE(ah, AR_IMR, 0); OS_REG_WRITE(ah, AR_IER, AR_IER_DISABLE); ahp->ah_maskReg = 0; (void) OS_REG_READ(ah, AR_BSR); /* cleared on read */ OS_REG_WRITE(ah, AR_TXCFG, AR_DMASIZE_128B); OS_REG_WRITE(ah, AR_RXCFG, AR_DMASIZE_128B); OS_REG_WRITE(ah, AR_TOPS, 8); /* timeout prescale */ OS_REG_WRITE(ah, AR_RXNOFRM, 8); /* RX no frame timeout */ OS_REG_WRITE(ah, AR_RPGTO, 0); /* RX frame gap timeout */ OS_REG_WRITE(ah, AR_TXNOFRM, 0); /* TX no frame timeout */ OS_REG_WRITE(ah, AR_SFR, 0); OS_REG_WRITE(ah, AR_MIBC, 0); /* unfreeze ctrs + clr state */ OS_REG_WRITE(ah, AR_RSSI_THR, INIT_RSSI_THR); OS_REG_WRITE(ah, AR_CFP_DUR, 0); ar5210SetRxFilter(ah, 0); /* nothing for now */ OS_REG_WRITE(ah, AR_MCAST_FIL0, 0); /* multicast filter */ OS_REG_WRITE(ah, AR_MCAST_FIL1, 0); /* XXX was 2 */ OS_REG_WRITE(ah, AR_TX_MASK0, 0); OS_REG_WRITE(ah, AR_TX_MASK1, 0); OS_REG_WRITE(ah, AR_CLR_TMASK, 1); OS_REG_WRITE(ah, AR_TRIG_LEV, 1); /* minimum */ OS_REG_WRITE(ah, AR_DIAG_SW, 0); OS_REG_WRITE(ah, AR_CFP_PERIOD, 0); OS_REG_WRITE(ah, AR_TIMER0, 0); /* next beacon time */ OS_REG_WRITE(ah, AR_TSF_L32, 0); /* local clock */ OS_REG_WRITE(ah, AR_TIMER1, ~0); /* next DMA beacon alert */ OS_REG_WRITE(ah, AR_TIMER2, ~0); /* next SW beacon alert */ OS_REG_WRITE(ah, AR_TIMER3, 1); /* next ATIM window */ /* Write the INI values for PHYreg initialization */ for (i = 0; i < N(ar5k0007_init); i++) { u_int32_t reg = ar5k0007_init[i].Offset; /* On channel change, don't reset the PCU registers */ if (!(bChannelChange && (0x8000 <= reg && reg < 0x9000))) OS_REG_WRITE(ah, reg, ar5k0007_init[i].Value); } /* Setup the transmit power values for cards since 0x0[0-2]05 */ if (!ar5210SetTransmitPower(ah, chan)) { HALDEBUG(ah, "%s: error init'ing transmit power\n", __func__); FAIL(HAL_EIO); } OS_REG_WRITE(ah, AR_PHY(10), (OS_REG_READ(ah, AR_PHY(10)) & 0xFFFF00FF) | (ahp->ah_xlnaOn << 8)); OS_REG_WRITE(ah, AR_PHY(13), (ahp->ah_xpaOff << 24) | (ahp->ah_xpaOff << 16) | (ahp->ah_xpaOn << 8) | ahp->ah_xpaOn); OS_REG_WRITE(ah, AR_PHY(17), (OS_REG_READ(ah, AR_PHY(17)) & 0xFFFFC07F) | ((ahp->ah_antenna >> 1) & 0x3F80)); OS_REG_WRITE(ah, AR_PHY(18), (OS_REG_READ(ah, AR_PHY(18)) & 0xFFFC0FFF) | ((ahp->ah_antenna << 10) & 0x3F000)); OS_REG_WRITE(ah, AR_PHY(25), (OS_REG_READ(ah, AR_PHY(25)) & 0xFFF80FFF) | ((ahp->ah_thresh62 << 12) & 0x7F000)); OS_REG_WRITE(ah, AR_PHY(68), (OS_REG_READ(ah, AR_PHY(68)) & 0xFFFFFFFC) | (ahp->ah_antenna & 0x3)); if (!ar5210SetChannel(ah, chan)) { HALDEBUG(ah, "%s: unable to set channel\n", __func__); FAIL(HAL_EIO); } if (bChannelChange) { HAL_CHANNEL_INTERNAL *ichan = AH_PRIVATE(ah)->ah_curchan;; if (!(ichan->channelFlags & CHANNEL_DFS)) ichan->privFlags &= ~CHANNEL_INTERFERENCE; chan->channelFlags = ichan->channelFlags; chan->privFlags = ichan->privFlags; } /* Activate the PHY */ OS_REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ENABLE); OS_DELAY(1000); /* Wait a bit (1 msec) */ /* calibrate the HW and poll the bit going to 0 for completion */ OS_REG_WRITE(ah, AR_PHY_AGCCTL, OS_REG_READ(ah, AR_PHY_AGCCTL) | AR_PHY_AGC_CAL); (void) ath_hal_wait(ah, AR_PHY_AGCCTL, AR_PHY_AGC_CAL, 0); /* Perform noise floor calibration and set status */ if (!ar5210CalNoiseFloor(ah, chan)) { chan->channelFlags |= CHANNEL_CW_INT; HALDEBUG(ah, "%s: noise floor calibration failed\n", __func__); FAIL(HAL_EIO); } for (q = 0; q < HAL_NUM_TX_QUEUES; q++) ar5210ResetTxQueue(ah, q); if (ahp->ah_rfKill) ar5210EnableRfKill(ah); /* * Writing to AR_BEACON will start timers. Hence it should be * the last register to be written. Do not reset tsf, do not * enable beacons at this point, but preserve other values * like beaconInterval. */ OS_REG_WRITE(ah, AR_BEACON, (OS_REG_READ(ah, AR_BEACON) & ~(AR_BEACON_EN | AR_BEACON_RESET_TSF))); /* Restore user-specified slot time and timeouts */ if (ahp->ah_slottime != (u_int) -1) ar5210SetSlotTime(ah, ahp->ah_slottime); if (ahp->ah_acktimeout != (u_int) -1) ar5210SetAckTimeout(ah, ahp->ah_acktimeout); if (ahp->ah_ctstimeout != (u_int) -1) ar5210SetCTSTimeout(ah, ahp->ah_ctstimeout); if (AH_PRIVATE(ah)->ah_diagreg != 0) OS_REG_WRITE(ah, AR_DIAG_SW, AH_PRIVATE(ah)->ah_diagreg); AH_PRIVATE(ah)->ah_opmode = opmode; /* record operating mode */ HALDEBUG(ah, "%s: done\n", __func__); return AH_TRUE;bad: if (*status) *status = ecode; return AH_FALSE;#undef FAIL#undef N}voidar5210SetPCUConfig(struct ath_hal *ah){ u_int32_t val; val = OS_REG_READ(ah, AR_STA_ID1) & 0xffff; switch (AH_PRIVATE(ah)->ah_opmode) { case HAL_M_HOSTAP: OS_REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_AP | AR_STA_ID1_NO_PSPOLL | AR_STA_ID1_DESC_ANTENNA); break; case HAL_M_IBSS: OS_REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_ADHOC | AR_STA_ID1_NO_PSPOLL | AR_STA_ID1_DESC_ANTENNA); break; case HAL_M_STA: OS_REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_NO_PSPOLL | AR_STA_ID1_PWR_SV); break; case HAL_M_MONITOR: OS_REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_NO_PSPOLL); break; }}/* * Places the PHY and Radio chips into reset. A full reset * must be called to leave this state. The PCI/MAC/PCU are * not placed into reset as we must receive interrupt to * re-enable the hardware. */HAL_BOOLar5210PhyDisable(struct ath_hal *ah){ return ar5210SetResetReg(ah, AR_RC_RPHY, 10);}/* * Places all of hardware into reset */HAL_BOOLar5210Disable(struct ath_hal *ah){#define AR_RC_HW (AR_RC_RPCU | AR_RC_RDMA | AR_RC_RPHY | AR_RC_RMAC) if (!ar5210SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE)) return AH_FALSE; /* * Reset the HW - PCI must be reset after the rest of the * device has been reset */ if (!ar5210SetResetReg(ah, AR_RC_HW, AR_RC_SETTLE_TIME)) return AH_FALSE; OS_DELAY(1000); (void) ar5210SetResetReg(ah, AR_RC_HW | AR_RC_RPCI, AR_RC_SETTLE_TIME); OS_DELAY(2100); /* 8245 @ 96Mhz hangs with 2000us. */ return AH_TRUE;#undef AR_RC_HW}/* * Places the hardware into reset and then pulls it out of reset */HAL_BOOLar5210ChipReset(struct ath_hal *ah, HAL_CHANNEL *chan){#define AR_RC_HW (AR_RC_RPCU | AR_RC_RDMA | AR_RC_RPHY | AR_RC_RMAC) HALDEBUG(ah, "%s %p turbo %s\n", __func__, ah, chan && IS_CHAN_TURBO(chan) ? "enabled" : "disabled"); if (!ar5210SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE)) return AH_FALSE; /* Place chip in turbo before reset to cleanly reset clocks */ OS_REG_WRITE(ah, AR_PHY_FRCTL, chan && IS_CHAN_TURBO(chan) ? AR_PHY_TURBO_MODE : 0); /* * Reset the HW. * PCI must be reset after the rest of the device has been reset. */ if (!ar5210SetResetReg(ah, AR_RC_HW, AR_RC_SETTLE_TIME)) return AH_FALSE; OS_DELAY(1000); if (!ar5210SetResetReg(ah, AR_RC_HW | AR_RC_RPCI, AR_RC_SETTLE_TIME)) return AH_FALSE; OS_DELAY(2100); /* 8245 @ 96Mhz hangs with 2000us. */ /* * Bring out of sleep mode (AGAIN) * * WARNING WARNING WARNING * * There is a problem with the chip where it doesn't always indicate * that it's awake, so initializePowerUp() will fail. */ if (!ar5210SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE)) return AH_FALSE; /* Clear warm reset reg */ return ar5210SetResetReg(ah, 0, 10);#undef AR_RC_HW}enum { FIRPWR_M = 0x03fc0000, FIRPWR_S = 18, KCOARSEHIGH_M = 0x003f8000, KCOARSEHIGH_S = 15, KCOARSELOW_M = 0x00007f80, KCOARSELOW_S = 7, ADCSAT_ICOUNT_M = 0x0001f800, ADCSAT_ICOUNT_S = 11, ADCSAT_THRESH_M = 0x000007e0, ADCSAT_THRESH_S = 5};/* * Recalibrate the lower PHY chips to account for temperature/environment * changes. */HAL_BOOLar5210PerCalibration(struct ath_hal *ah, HAL_CHANNEL *chan, HAL_BOOL *isIQdone){ u_int32_t regBeacon; u_int32_t reg9858, reg985c, reg9868; /* Disable tx and rx */ OS_REG_WRITE(ah, AR_DIAG_SW, OS_REG_READ(ah, AR_DIAG_SW) | (AR_DIAG_SW_DIS_TX | AR_DIAG_SW_DIS_RX)); /* Disable Beacon Enable */ regBeacon = OS_REG_READ(ah, AR_BEACON); OS_REG_WRITE(ah, AR_BEACON, regBeacon & ~AR_BEACON_EN); /* Delay 4ms to ensure that all tx and rx activity has ceased */ OS_DELAY(4000); /* Disable AGC to radio traffic */ OS_REG_WRITE(ah, 0x9808, OS_REG_READ(ah, 0x9808) | 0x08000000); /* Wait for the AGC traffic to cease. */ OS_DELAY(10); /* Change Channel to relock synth */ if (!ar5210SetChannel(ah, chan)) return AH_FALSE; /* wait for the synthesizer lock to stabilize */ OS_DELAY(1000); /* Re-enable AGC to radio traffic */ OS_REG_WRITE(ah, 0x9808, OS_REG_READ(ah, 0x9808) & (~0x08000000)); /* * Configure the AGC so that it is highly unlikely (if not * impossible) for it to send any gain changes to the analog * chip. We store off the current values so that they can * be rewritten below. Setting the following values: * firpwr = -1 * Kcoursehigh = -1 * Kcourselow = -127 * ADCsat_icount = 2 * ADCsat_thresh = 12 */ reg9858 = OS_REG_READ(ah, 0x9858); reg985c = OS_REG_READ(ah, 0x985c); reg9868 = OS_REG_READ(ah, 0x9868); OS_REG_WRITE(ah, 0x9858, (reg9858 & ~FIRPWR_M) | ((-1 << FIRPWR_S) & FIRPWR_M)); OS_REG_WRITE(ah, 0x985c, (reg985c & ~(KCOARSEHIGH_M | KCOARSELOW_M)) | ((-1 << KCOARSEHIGH_S) & KCOARSEHIGH_M) | ((-127 << KCOARSELOW_S) & KCOARSELOW_M)); OS_REG_WRITE(ah, 0x9868, (reg9868 & ~(ADCSAT_ICOUNT_M | ADCSAT_THRESH_M)) | ((2 << ADCSAT_ICOUNT_S) & ADCSAT_ICOUNT_M) | ((12 << ADCSAT_THRESH_S) & ADCSAT_THRESH_M));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -