📄 ar5312_reset.c
字号:
/* * Copyright (c) 2002-2004 Sam Leffler, Errno Consulting * Copyright (c) 2002-2004 Atheros Communications, Inc. * All rights reserved. * * $Id: ar5312_reset.c,v 1.1.1.1 2006/09/12 03:45:23 steven Exp $ */#include "opt_ah.h"#ifdef AH_SUPPORT_AR5312#include "ah.h"#include "ah_internal.h"#include "ah_devid.h"#include "ar5312/ar5312.h"#include "ar5312/ar5312reg.h"#include "ar5312/ar5312phy.h"/* Add static register initialization vectors */#define AH_5212_COMMON#include "ar5212/ar5212.ini"/* Additional Time delay to wait after activiting the Base band */#define BASE_ACTIVATE_DELAY 100 /* 100 usec */#define PLL_SETTLE_DELAY 300 /* 300 usec */extern int16_t ar5212GetNf(struct ath_hal *, HAL_CHANNEL_INTERNAL *);extern void ar5212SetRateDurationTable(struct ath_hal *, HAL_CHANNEL *);extern HAL_BOOL ar5212SetTransmitPower(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan, u_int16_t *rfXpdGain);extern void ar5212SetDeltaSlope(struct ath_hal *, HAL_CHANNEL_INTERNAL *);extern void ar5212SetOperatingMode(struct ath_hal *, int );extern void ar5212SetCompRegs(struct ath_hal *);extern void ar5212SetIFSTiming(struct ath_hal *, HAL_CHANNEL *);extern HAL_BOOL ar5212IsSpurChannel(struct ath_hal *, HAL_CHANNEL *);extern HAL_BOOL ar5212ChannelChange(struct ath_hal *, HAL_CHANNEL *);extern void ar5212SetSpurMitigation(struct ath_hal *, HAL_CHANNEL_INTERNAL *);#ifdef AH_SUPPORT_XRextern HAL_BOOL ar5212SetXrMode(struct ath_hal *ah, HAL_OPMODE opmode,HAL_CHANNEL *chan);#endifstatic HAL_BOOL ar5312SetResetReg(struct ath_hal *, u_int32_t resetMask);/* * WAR for bug 6773. OS_DELAY() does a PIO READ on the PCI bus which allows * other cards' DMA reads to complete in the middle of our reset. */#define WAR_6773(x) do { \ if ((++(x) % 64) == 0) \ OS_DELAY(1); \} while (0)#define IS_NO_RESET_TIMER_ADDR(x) \ ( (((x) >= AR_BEACON) && ((x) <= AR_CFP_DUR)) || \ (((x) >= AR_SLEEP1) && ((x) <= AR_SLEEP3)))#define REG_WRITE_ARRAY(regArray, column, regWr) do { \ int r; \ for (r = 0; r < N(regArray); r++) { \ OS_REG_WRITE(ah, (regArray)[r][0], (regArray)[r][(column)]);\ WAR_6773(regWr); \ } \} while (0)/* * 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_BOOLar5312Reset(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_5212 *ahp = AH5212(ah); HAL_CHANNEL_INTERNAL *ichan; u_int32_t saveFrameSeqCount, saveDefAntenna; u_int32_t macStaId1, synthDelay, txFrm2TxDStart; u_int16_t rfXpdGain[2]; int16_t cckOfdmPwrDelta = 0; u_int modesIndex, freqIndex; HAL_STATUS ecode; int i, regWrites = 0; u_int32_t testReg, powerVal, rssiThrReg; int8_t twiceAntennaGain, twiceAntennaReduction; u_int32_t ackTpcPow, ctsTpcPow, chirpTpcPow;#if !( AH_SUPPORT_2316 || AH_SUPPORT_2317) u_int32_t saveLedState;#endif OS_MARK(ah, AH_MARK_RESET, bChannelChange);#define IS(_c,_f) (((_c)->channelFlags & _f) || 0) if ((IS(chan, CHANNEL_2GHZ) ^ IS(chan, CHANNEL_5GHZ)) == 0) { HALDEBUG(ah, "%s: invalid channel %u/0x%x; not marked as " "2GHz or 5GHz\n", __func__, chan->channel, chan->channelFlags); FAIL(HAL_EINVAL); } if ((IS(chan, CHANNEL_OFDM) ^ IS(chan, CHANNEL_CCK)) == 0) { HALDEBUG(ah, "%s: invalid channel %u/0x%x; not marked as " "OFDM or CCK\n", __func__, chan->channel, chan->channelFlags); FAIL(HAL_EINVAL); }#undef IS /* * Map public channel to private. */ ichan = ath_hal_checkchannel(ah, chan); if (ichan == AH_NULL) { HALDEBUG(ah, "%s: invalid channel %u/0x%x; no mapping\n", __func__, chan->channel, chan->channelFlags); 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; } HALASSERT(ahp->ah_eeversion >= AR_EEPROM_VER3); /* Preserve certain DMA hardware registers on a channel change */ if (bChannelChange) { /* * AR5212 WAR * * On Venice, the TSF is almost preserved across a reset; * it requires the WAR of doubling writes to the RESET_TSF * bit in the AR_BEACON register; it also has the quirk * of the TSF going back in time on the station (station * latches onto the last beacon's tsf during a reset 50% * of the times); the latter is not a problem for adhoc * stations since as long as the TSF is behind, it will * get resynchronized on receiving the next beacon; the * TSF going backwards in time could be a problem for the * sleep operation (supported on infrastructure stations * only) - the best and most general fix for this situation * is to resynchronize the various sleep/beacon timers on * the receipt of the next beacon i.e. when the TSF itself * gets resynchronized to the AP's TSF - power save is * needed to be temporarily disabled until that time * * Need to save the sequence number to restore it after * the reset! */ saveFrameSeqCount = OS_REG_READ(ah, AR_D_SEQNUM); ar5212GetNf(ah, ichan); } else saveFrameSeqCount = 0; /* NB: silence compiler */ /* If the channel change is across the same mode - perform a fast channel change */ if ((IS_2413(ah) || IS_5413(ah))) { /* * Channel change can only be used when: * -channel change requested - so it's not the initial reset. * -it's not a change to the current channel - often called when switching modes * on a channel * -the modes of the previous and requested channel are the same - some ugly code for XR */ if (bChannelChange && (AH_PRIVATE(ah)->ah_curchan != AH_NULL) && (chan->channel != AH_PRIVATE(ah)->ah_curchan->channel) && ((chan->channelFlags & CHANNEL_ALL) == (AH_PRIVATE(ah)->ah_curchan->channelFlags & CHANNEL_ALL))) { if (ar5212ChannelChange(ah, chan)) { /* If ChannelChange completed - skip the rest of reset */ return AH_TRUE; } } } /* * Preserve the bmiss rssi threshold and count threshold * across resets */ rssiThrReg = OS_REG_READ(ah, AR_RSSI_THR); /* If reg is zero, first time thru set to default val */ if (rssiThrReg == 0) { rssiThrReg = INIT_RSSI_THR; } /* * Preserve the antenna on a channel change */ saveDefAntenna = OS_REG_READ(ah, AR_DEF_ANTENNA); if (saveDefAntenna == 0) /* XXX magic constants */ saveDefAntenna = 1; /* Save hardware flag before chip reset clears the register */ macStaId1 = OS_REG_READ(ah, AR_STA_ID1) & (AR_STA_ID1_BASE_RATE_11B | AR_STA_ID1_USE_DEFANT);#if !(AH_SUPPORT_2316 || AH_SUPPORT_2317) /* not yet */ /* Save led state from pci config register */ saveLedState = OS_REG_READ(ah, AR531X_PCICFG) & (AR_PCICFG_LEDCTL | AR_PCICFG_LEDMODE | AR_PCICFG_LEDBLINK | AR_PCICFG_LEDSLOW);#endif if (!(IS_5416(ah))) ar5312RestoreClock(ah, opmode); /* move to refclk operation */ /* * Adjust gain parameters before reset if * there's an outstanding gain updated. */ (void) ar5212GetRfgain(ah); if (!ar5312ChipReset(ah, chan)) { HALDEBUG(ah, "%s: chip reset failed\n", __func__); FAIL(HAL_EIO); } /* Restore bmiss rssi & count thresholds */ OS_REG_WRITE(ah, AR_RSSI_THR, rssiThrReg); /* Setup the indices for the next set of register array writes */ switch (chan->channelFlags & CHANNEL_ALL) { case CHANNEL_A: case CHANNEL_XR_A: modesIndex = 1; freqIndex = 1; break; case CHANNEL_T: case CHANNEL_XR_T: modesIndex = 2; freqIndex = 1; break; case CHANNEL_B: modesIndex = 3; freqIndex = 2; break; case CHANNEL_PUREG: case CHANNEL_XR_G: modesIndex = 4; freqIndex = 2; break; case CHANNEL_108G: modesIndex = 5; freqIndex = 2; break; default: HALDEBUG(ah, "%s: invalid channel flags 0x%x\n", __func__, chan->channelFlags); FAIL(HAL_EINVAL); } OS_MARK(ah, AH_MARK_RESET_LINE, __LINE__); /* Set correct Baseband to analog shift setting to access analog chips. */ OS_REG_WRITE(ah, AR_PHY(0), 0x00000007); if (!IS_5416(ah)) { REG_WRITE_ARRAY(ar5212Modes, modesIndex, regWrites); /* Write Common Array Parameters */ for (i = 0; i < N(ar5212Common); i++) { u_int32_t reg = ar5212Common[i][0]; /* XXX timer/beacon setup registers? */ /* On channel change, don't reset the PCU registers */ if (!(bChannelChange && IS_NO_RESET_TIMER_ADDR(reg))) { OS_REG_WRITE(ah, reg, ar5212Common[i][1]); WAR_6773(regWrites); } } } ahp->ah_rfHal.writeRegs(ah, modesIndex, freqIndex, regWrites); OS_MARK(ah, AH_MARK_RESET_LINE, __LINE__); if (IS_CHAN_HALF_RATE(chan) || IS_CHAN_QUARTER_RATE(chan)) { ar5212SetIFSTiming(ah, chan); } /* Overwrite INI values for revised chipsets */ if (AH_PRIVATE(ah)->ah_phyRev >= AR_PHY_CHIP_ID_REV_2) { /* ADC_CTL */ OS_REG_WRITE(ah, AR_PHY_ADC_CTL, SM(2, AR_PHY_ADC_CTL_OFF_INBUFGAIN) | SM(2, AR_PHY_ADC_CTL_ON_INBUFGAIN) | AR_PHY_ADC_CTL_OFF_PWDDAC | AR_PHY_ADC_CTL_OFF_PWDADC); /* TX_PWR_ADJ */ if (chan->channel == 2484) { cckOfdmPwrDelta = SCALE_OC_DELTA(ahp->ah_cckOfdmPwrDelta - ahp->ah_scaledCh14FilterCckDelta); } else { cckOfdmPwrDelta = SCALE_OC_DELTA(ahp->ah_cckOfdmPwrDelta); } if (IS_CHAN_G(chan)) { OS_REG_WRITE(ah, AR_PHY_TXPWRADJ, SM((ahp->ah_cckOfdmPwrDelta*-1), AR_PHY_TXPWRADJ_CCK_GAIN_DELTA) | SM((cckOfdmPwrDelta*-1), AR_PHY_TXPWRADJ_CCK_PCDAC_INDEX)); } else { OS_REG_WRITE(ah, AR_PHY_TXPWRADJ, 0); } /* Add barker RSSI thresh enable as disabled */ OS_REG_CLR_BIT(ah, AR_PHY_DAG_CTRLCCK, AR_PHY_DAG_CTRLCCK_EN_RSSI_THR); OS_REG_RMW_FIELD(ah, AR_PHY_DAG_CTRLCCK, AR_PHY_DAG_CTRLCCK_RSSI_THR, 2); /* Set the mute mask to the correct default */ OS_REG_WRITE(ah, AR_SEQ_MASK, 0x0000000F); } if (AH_PRIVATE(ah)->ah_phyRev >= AR_PHY_CHIP_ID_REV_3) { /* Clear reg to alllow RX_CLEAR line debug */ OS_REG_WRITE(ah, AR_PHY_BLUETOOTH, 0); } if (AH_PRIVATE(ah)->ah_phyRev >= AR_PHY_CHIP_ID_REV_4) {#ifdef notyet /* Enable burst prefetch for the data queues */ OS_REG_RMW_FIELD(ah, AR_D_FPCTL, ... ); /* Enable double-buffering */ OS_REG_CLR_BIT(ah, AR_TXCFG, AR_TXCFG_DBL_BUF_DIS);#endif } if (IS_5312_2_X(ah)) { /* ADC_CTRL */ OS_REG_WRITE(ah, AR_PHY_SIGMA_DELTA, SM(2, AR_PHY_SIGMA_DELTA_ADC_SEL) | SM(4, AR_PHY_SIGMA_DELTA_FILT2) | SM(0x16, AR_PHY_SIGMA_DELTA_FILT1) | SM(0, AR_PHY_SIGMA_DELTA_ADC_CLIP)); if (IS_CHAN_2GHZ(chan)) OS_REG_RMW_FIELD(ah, AR_PHY_RXGAIN, AR_PHY_RXGAIN_TXRX_RF_MAX, 0x0F); /* CCK Short parameter adjustment in 11B mode */ if (IS_CHAN_B(chan)) OS_REG_RMW_FIELD(ah, AR_PHY_CCK_RXCTRL4, AR_PHY_CCK_RXCTRL4_FREQ_EST_SHORT, 12); /* Set ADC/DAC select values */ OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x04); /* Increase 11A AGC Settling */ if ((chan->channelFlags & CHANNEL_ALL) == CHANNEL_A) OS_REG_RMW_FIELD(ah, AR_PHY_SETTLING, AR_PHY_SETTLING_AGC, 32); } else { /* Set ADC/DAC select values */ OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x0e); } /* Setup the transmit power values. */ if (!AH_PRIVATE(ah)->ah_setTransmitPower(ah, ichan, rfXpdGain)) { HALDEBUG(ah, "%s: error init'ing transmit power\n", __func__); FAIL(HAL_EIO); } /* Write the analog registers */ if (!ahp->ah_rfHal.setRfRegs(ah, ichan, (IS_5416(ah) ? freqIndex : modesIndex), rfXpdGain)) { HALDEBUG(ah, "%s: ar5212SetRfRegs failed\n", __func__); FAIL(HAL_EIO); } /* Setup board specific options for EEPROM version 3 */ if (!AH_PRIVATE(ah)->ah_eepromSetBoardValues(ah, ichan)) { HALDEBUG(ah, "%s: error setting board options\n", __func__); FAIL(HAL_EIO); } /* Restore certain DMA hardware registers on a channel change */ if (bChannelChange) OS_REG_WRITE(ah, AR_D_SEQNUM, saveFrameSeqCount); OS_MARK(ah, AH_MARK_RESET_LINE, __LINE__); OS_REG_WRITE(ah, AR_STA_ID0, LE_READ_4(ahp->ah_macaddr)); OS_REG_WRITE(ah, AR_STA_ID1, LE_READ_2(ahp->ah_macaddr + 4) | macStaId1 | AR_STA_ID1_RTS_USE_DEF | ahp->ah_staId1Defaults ); ar5212SetOperatingMode(ah, opmode); /* Set Venice BSSID mask according to current state */ OS_REG_WRITE(ah, AR_BSSMSKL, LE_READ_4(ahp->ah_bssidmask)); OS_REG_WRITE(ah, AR_BSSMSKU, LE_READ_2(ahp->ah_bssidmask + 4));#if !(AH_SUPPORT_2316 || AH_SUPPORT_2317) /* not yet */ /* Restore previous led state */ OS_REG_WRITE(ah, AR531X_PCICFG, OS_REG_READ(ah, AR_PCICFG) | saveLedState);#endif /* Restore previous antenna */ OS_REG_WRITE(ah, AR_DEF_ANTENNA, saveDefAntenna); /* then our BSSID */ 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_ISR, ~0); /* cleared on write */ OS_REG_WRITE(ah, AR_RSSI_THR, INIT_RSSI_THR); if (!ahp->ah_rfHal.setChannel(ah, ichan)) FAIL(HAL_EIO); OS_MARK(ah, AH_MARK_RESET_LINE, __LINE__); ar5212SetCoverageClass(ah, AH_PRIVATE(ah)->ah_coverageClass, 1); ar5212SetRateDurationTable(ah, chan); /* Set Tx frame start to tx data start delay */ if (IS_5112(ah) && (IS_CHAN_HALF_RATE(AH_PRIVATE(ah)->ah_curchan) || IS_CHAN_QUARTER_RATE(AH_PRIVATE(ah)->ah_curchan))) { txFrm2TxDStart = (IS_CHAN_HALF_RATE(AH_PRIVATE(ah)->ah_curchan)) ? TX_FRAME_D_START_HALF_RATE: TX_FRAME_D_START_QUARTER_RATE; OS_REG_RMW_FIELD(ah, AR_PHY_TX_CTL, AR_PHY_TX_FRAME_TO_TX_DATA_START, txFrm2TxDStart); } /* * Setup fast diversity. * Fast diversity can be enabled or disabled via regadd.txt. * Default is enabled. * For reference, * Disable: reg val * 0x00009860 0x00009d18 (if 11a / 11g, else no change) * 0x00009970 0x192bb514 * 0x0000a208 0xd03e4648 * * Enable: 0x00009860 0x00009d10 (if 11a / 11g, else no change) * 0x00009970 0x192fb514 * 0x0000a208 0xd03e6788 */ /* XXX Setup pre PHY ENABLE EAR additions */ /* WAR for bug 11728 - flush SCAL reg */ if (IS_5312_2_X(ah)) { OS_REG_READ(ah, AR_PHY_SLEEP_SCAL); } /* * Wait for the frequency synth to settle (synth goes on * via AR_PHY_ACTIVE_EN). Read the phy active delay register. * Value is in 100ns increments. */ synthDelay = OS_REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY; if (IS_CHAN_CCK(chan)) { synthDelay = (4 * synthDelay) / 22; } else { synthDelay /= 10; } /* Activate the PHY (includes baseband activate and synthesizer on) */ OS_REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN); /* * There is an issue if the AP starts the calibration before * the base band timeout completes. This could result in the * rx_clear false triggering. As a workaround we add delay an * extra BASE_ACTIVATE_DELAY usecs to ensure this condition * does not happen. */ if (IS_CHAN_HALF_RATE(AH_PRIVATE(ah)->ah_curchan)) { OS_DELAY((synthDelay << 1) + BASE_ACTIVATE_DELAY); } else if (IS_CHAN_QUARTER_RATE(AH_PRIVATE(ah)->ah_curchan)) { OS_DELAY((synthDelay << 2) + BASE_ACTIVATE_DELAY); } else { OS_DELAY(synthDelay + BASE_ACTIVATE_DELAY); } /* Calibrate the AGC and start a NF calculation */ OS_REG_WRITE(ah, AR_PHY_AGC_CONTROL, OS_REG_READ(ah, AR_PHY_AGC_CONTROL) | AR_PHY_AGC_CONTROL_CAL | AR_PHY_AGC_CONTROL_NF); if (!IS_CHAN_B(chan) && ahp->ah_bIQCalibration != IQ_CAL_DONE) { /* Start IQ calibration w/ 2^(INIT_IQCAL_LOG_COUNT_MAX+1) samples */ OS_REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -