📄 ar5211_reset.c
字号:
/* * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting * Copyright (c) 2002-2005 Atheros Communications, Inc. * All rights reserved. * * $Id: ar5211_reset.c,v 1.1.1.1 2006/09/12 03:45:24 steven Exp $ */#include "opt_ah.h"#ifdef AH_SUPPORT_AR5211/* * Chips specific device attachment and device info collection * Connects Init Reg Vectors, EEPROM Data, and device Functions. */#include "ah.h"#include "ah_internal.h"#include "ah_devid.h"#include "ar5211/ar5211.h"#include "ar5211/ar5211reg.h"#include "ar5211/ar5211phy.h"/* Add static register initialization vectors */#include "ar5211/boss.ini"/* * Structure to hold 11b tuning information for Beanie/Sombrero * 16 MHz mode, divider ratio = 198 = NP+S. N=16, S=4 or 6, P=12 */typedef struct { u_int32_t refClkSel; /* reference clock, 1 for 16 MHz */ u_int32_t channelSelect; /* P[7:4]S[3:0] bits */ u_int16_t channel5111; /* 11a channel for 5111 */} CHAN_INFO_2GHZ;#define CI_2GHZ_INDEX_CORRECTION 19const static CHAN_INFO_2GHZ chan2GHzData[] = { { 1, 0x46, 96 }, /* 2312 -19 */ { 1, 0x46, 97 }, /* 2317 -18 */ { 1, 0x46, 98 }, /* 2322 -17 */ { 1, 0x46, 99 }, /* 2327 -16 */ { 1, 0x46, 100 }, /* 2332 -15 */ { 1, 0x46, 101 }, /* 2337 -14 */ { 1, 0x46, 102 }, /* 2342 -13 */ { 1, 0x46, 103 }, /* 2347 -12 */ { 1, 0x46, 104 }, /* 2352 -11 */ { 1, 0x46, 105 }, /* 2357 -10 */ { 1, 0x46, 106 }, /* 2362 -9 */ { 1, 0x46, 107 }, /* 2367 -8 */ { 1, 0x46, 108 }, /* 2372 -7 */ /* index -6 to 0 are pad to make this a nolookup table */ { 1, 0x46, 116 }, /* -6 */ { 1, 0x46, 116 }, /* -5 */ { 1, 0x46, 116 }, /* -4 */ { 1, 0x46, 116 }, /* -3 */ { 1, 0x46, 116 }, /* -2 */ { 1, 0x46, 116 }, /* -1 */ { 1, 0x46, 116 }, /* 0 */ { 1, 0x46, 116 }, /* 2412 1 */ { 1, 0x46, 117 }, /* 2417 2 */ { 1, 0x46, 118 }, /* 2422 3 */ { 1, 0x46, 119 }, /* 2427 4 */ { 1, 0x46, 120 }, /* 2432 5 */ { 1, 0x46, 121 }, /* 2437 6 */ { 1, 0x46, 122 }, /* 2442 7 */ { 1, 0x46, 123 }, /* 2447 8 */ { 1, 0x46, 124 }, /* 2452 9 */ { 1, 0x46, 125 }, /* 2457 10 */ { 1, 0x46, 126 }, /* 2462 11 */ { 1, 0x46, 127 }, /* 2467 12 */ { 1, 0x46, 128 }, /* 2472 13 */ { 1, 0x44, 124 }, /* 2484 14 */ { 1, 0x46, 136 }, /* 2512 15 */ { 1, 0x46, 140 }, /* 2532 16 */ { 1, 0x46, 144 }, /* 2552 17 */ { 1, 0x46, 148 }, /* 2572 18 */ { 1, 0x46, 152 }, /* 2592 19 */ { 1, 0x46, 156 }, /* 2612 20 */ { 1, 0x46, 160 }, /* 2632 21 */ { 1, 0x46, 164 }, /* 2652 22 */ { 1, 0x46, 168 }, /* 2672 23 */ { 1, 0x46, 172 }, /* 2692 24 */ { 1, 0x46, 176 }, /* 2712 25 */ { 1, 0x46, 180 } /* 2732 26 */};/* Power timeouts in usec to wait for chip to wake-up. */#define POWER_UP_TIME 2000#define DELAY_PLL_SETTLE 300 /* 300 us */#define DELAY_BASE_ACTIVATE 100 /* 100 us */#define NUM_RATES 8static HAL_BOOL ar5211SetResetReg(struct ath_hal *ah, u_int32_t resetMask);static HAL_BOOL ar5211SetChannel(struct ath_hal *, HAL_CHANNEL_INTERNAL *);static int16_t ar5211RunNoiseFloor(struct ath_hal *, u_int8_t runTime, int16_t startingNF);static HAL_BOOL ar5211IsNfGood(struct ath_hal *, HAL_CHANNEL *chan);static HAL_BOOL ar5211SetRf6and7(struct ath_hal *, HAL_CHANNEL *chan);static HAL_BOOL ar5211SetBoardValues(struct ath_hal *, HAL_CHANNEL *chan);static void ar5211SetPowerTable(struct ath_hal *, PCDACS_EEPROM *pSrcStruct, u_int16_t channel);static void ar5211SetRateTable(struct ath_hal *, RD_EDGES_POWER *pRdEdgesPower, TRGT_POWER_INFO *pPowerInfo, u_int16_t numChannels, HAL_CHANNEL *chan);static u_int16_t ar5211GetScaledPower(u_int16_t channel, u_int16_t pcdacValue, PCDACS_EEPROM *pSrcStruct);static HAL_BOOL ar5211FindValueInList(u_int16_t channel, u_int16_t pcdacValue, PCDACS_EEPROM *pSrcStruct, u_int16_t *powerValue);static u_int16_t ar5211GetInterpolatedValue(u_int16_t target, u_int16_t srcLeft, u_int16_t srcRight, u_int16_t targetLeft, u_int16_t targetRight, HAL_BOOL scaleUp);static void ar5211GetLowerUpperValues(u_int16_t value, u_int16_t *pList, u_int16_t listSize, u_int16_t *pLowerValue, u_int16_t *pUpperValue);static void ar5211GetLowerUpperPcdacs(u_int16_t pcdac, u_int16_t channel, PCDACS_EEPROM *pSrcStruct, u_int16_t *pLowerPcdac, u_int16_t *pUpperPcdac);static void ar5211SetRfgain(struct ath_hal *, const GAIN_VALUES *);;static void ar5211RequestRfgain(struct ath_hal *);static HAL_BOOL ar5211InvalidGainReadback(struct ath_hal *, GAIN_VALUES *);static HAL_BOOL ar5211IsGainAdjustNeeded(struct ath_hal *, const GAIN_VALUES *);static int32_t ar5211AdjustGain(struct ath_hal *, GAIN_VALUES *);/* * 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_BOOLar5211Reset(struct ath_hal *ah, HAL_OPMODE opmode, HAL_CHANNEL *chan, HAL_BOOL bChannelChange, HAL_STATUS *status){u_int32_t softLedCfg, softLedState;#define N(a) (sizeof (a) /sizeof (a[0]))#define FAIL(_code) do { ecode = _code; goto bad; } while (0) struct ath_hal_5211 *ahp = AH5211(ah); HAL_CHANNEL_INTERNAL *ichan; u_int32_t i, ledstate; HAL_STATUS ecode; int q; u_int32_t data, synthDelay; u_int32_t macStaId1; u_int16_t modesIndex = 0, freqIndex = 0; u_int32_t saveFrameSeqCount[AR_NUM_DCU]; u_int32_t saveTsfLow = 0, saveTsfHigh = 0; u_int32_t saveDefAntenna; HALDEBUG(ah, "%s: opmode %u channel %u/0x%x %s channel\n", __func__, opmode, chan->channel, chan->channelFlags, bChannelChange ? "change" : "same"); 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) { /* * AR5211 WAR * Need to save/restore the TSF because of a hardware bug * that accelerates the TSF during a chip reset. * * We could use system timer routines to more * accurately restore the TSF, but * 1. Timer routines on certain platforms are * not accurate enough (e.g. 1 ms resolution). * 2. It would still not be accurate. * * The most important aspect of this workaround, * is that, after reset, the TSF is behind * other STAs TSFs (see bug 4127). This will * allow the STA to properly resynchronize its * TSF in adhoc mode. */ saveTsfLow = OS_REG_READ(ah, AR_TSF_L32); saveTsfHigh = OS_REG_READ(ah, AR_TSF_U32); /* Read frame sequence count */ if (AH_PRIVATE(ah)->ah_macVersion >= AR_SREV_VERSION_OAHU) { saveFrameSeqCount[0] = OS_REG_READ(ah, AR_D0_SEQNUM); } else { for (i = 0; i < AR_NUM_DCU; i++) saveFrameSeqCount[i] = OS_REG_READ(ah, AR_DSEQNUM(i)); } if (!(ichan->channelFlags & CHANNEL_DFS)) ichan->privFlags &= ~CHANNEL_INTERFERENCE; chan->channelFlags = ichan->channelFlags; chan->privFlags = ichan->privFlags; } /* * Preserve the antenna on a channel change */ saveDefAntenna = OS_REG_READ(ah, AR_DEF_ANTENNA); if (saveDefAntenna == 0) 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; /* Save led state from pci config register */ ledstate = OS_REG_READ(ah, AR_PCICFG) & (AR_PCICFG_LEDCTL | AR_PCICFG_LEDMODE | AR_PCICFG_LEDBLINK | AR_PCICFG_LEDSLOW); softLedCfg = OS_REG_READ(ah, AR_GPIOCR); softLedState = OS_REG_READ(ah, AR_GPIODO); if (!ar5211ChipReset(ah, chan->channelFlags)) { HALDEBUG(ah, "%s: chip reset failed\n", __func__); FAIL(HAL_EIO); } /* Setup the indices for the next set of register array writes */ switch (chan->channelFlags & CHANNEL_ALL) { case CHANNEL_A: modesIndex = 1; freqIndex = 1; break; case CHANNEL_T: modesIndex = 2; freqIndex = 1; break; case CHANNEL_B: modesIndex = 3; freqIndex = 2; break; case CHANNEL_PUREG: modesIndex = 4; freqIndex = 2; break; default: /* Ah, a new wireless mode */ HALASSERT(0); break; } /* Set correct Baseband to analog shift setting to access analog chips. */ if (AH_PRIVATE(ah)->ah_macVersion >= AR_SREV_VERSION_OAHU) { OS_REG_WRITE(ah, AR_PHY_BASE, 0x00000007); } else { OS_REG_WRITE(ah, AR_PHY_BASE, 0x00000047); } /* Write parameters specific to AR5211 */ if (AH_PRIVATE(ah)->ah_macVersion >= AR_SREV_VERSION_OAHU) { if (IS_CHAN_2GHZ(chan) && ahp->ah_eeversion >= AR_EEPROM_VER3_1) { u_int32_t ob2GHz, db2GHz; if (IS_CHAN_CCK(chan)) { ob2GHz = ahp->ah_ob2GHz[0]; db2GHz = ahp->ah_db2GHz[0]; } else { ob2GHz = ahp->ah_ob2GHz[1]; db2GHz = ahp->ah_db2GHz[1]; } ob2GHz = ath_hal_reverseBits(ob2GHz, 3); db2GHz = ath_hal_reverseBits(db2GHz, 3); ar5211Mode2_4[25][freqIndex] = (ar5211Mode2_4[25][freqIndex] & ~0xC0) | ((ob2GHz << 6) & 0xC0); ar5211Mode2_4[26][freqIndex] = (ar5211Mode2_4[26][freqIndex] & ~0x0F) | (((ob2GHz >> 2) & 0x1) | ((db2GHz << 1) & 0x0E)); } for (i = 0; i < N(ar5211Mode2_4); i++) OS_REG_WRITE(ah, ar5211Mode2_4[i][0], ar5211Mode2_4[i][freqIndex]); } /* Write the analog registers 6 and 7 before other config */ ar5211SetRf6and7(ah, chan); /* Write registers that vary across all modes */ for (i = 0; i < N(ar5211Modes); i++) OS_REG_WRITE(ah, ar5211Modes[i][0], ar5211Modes[i][modesIndex]); /* Write RFGain Parameters that differ between 2.4 and 5 GHz */ for (i = 0; i < N(ar5211BB_RfGain); i++) OS_REG_WRITE(ah, ar5211BB_RfGain[i][0], ar5211BB_RfGain[i][freqIndex]); /* Write Common Array Parameters */ for (i = 0; i < N(ar5211Common); i++) { u_int32_t reg = ar5211Common[i][0]; /* On channel change, don't reset the PCU registers */ if (!(bChannelChange && (0x8000 <= reg && reg < 0x9000))) OS_REG_WRITE(ah, reg, ar5211Common[i][1]); } /* Fix pre-AR5211 register values, this includes AR5311s. */ if (AH_PRIVATE(ah)->ah_macVersion < AR_SREV_VERSION_OAHU) { /* * The TX and RX latency values have changed locations * within the USEC register in AR5211. Since they're * set via the .ini, for both AR5211 and AR5311, they * are written properly here for AR5311. */ data = OS_REG_READ(ah, AR_USEC); /* Must be 0 for proper write in AR5311 */ HALASSERT((data & 0x00700000) == 0); OS_REG_WRITE(ah, AR_USEC, (data & (AR_USEC_M | AR_USEC_32_M | AR5311_USEC_TX_LAT_M)) | ((29 << AR5311_USEC_RX_LAT_S) & AR5311_USEC_RX_LAT_M)); /* The following registers exist only on AR5311. */ OS_REG_WRITE(ah, AR5311_QDCLKGATE, 0); /* Set proper ADC & DAC delays for AR5311. */ OS_REG_WRITE(ah, 0x00009878, 0x00000008); /* Enable the PCU FIFO corruption ECO on AR5311. */ OS_REG_WRITE(ah, AR_DIAG_SW, OS_REG_READ(ah, AR_DIAG_SW) | AR5311_DIAG_SW_USE_ECO); } /* Restore certain DMA hardware registers on a channel change */ if (bChannelChange) { /* AR5211 WAR - Restore TSF */ OS_REG_WRITE(ah, AR_TSF_L32, saveTsfLow); OS_REG_WRITE(ah, AR_TSF_U32, saveTsfHigh); if (AH_PRIVATE(ah)->ah_macVersion >= AR_SREV_VERSION_OAHU) { OS_REG_WRITE(ah, AR_D0_SEQNUM, saveFrameSeqCount[0]); } else { for (i = 0; i < AR_NUM_DCU; i++) OS_REG_WRITE(ah, AR_DSEQNUM(i), saveFrameSeqCount[i]); } } 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) | macStaId1 | AR_STA_ID1_STA_AP | AR_STA_ID1_RTS_USE_DEF); break; case HAL_M_IBSS: /* * Set the IBSS mode only if we were configured to be so. * If bssType is ANY_BSS then the scan will determine what * mode we finally end up in. */ OS_REG_WRITE(ah, AR_STA_ID1, LE_READ_2(ahp->ah_macaddr + 4) | AR_STA_ID1_ADHOC | AR_STA_ID1_RTS_USE_DEF); break; case HAL_M_STA: OS_REG_WRITE(ah, AR_STA_ID1, LE_READ_2(ahp->ah_macaddr + 4) | AR_STA_ID1_DEFAULT_ANTENNA); break; case HAL_M_MONITOR: OS_REG_WRITE(ah, AR_STA_ID1, LE_READ_2(ahp->ah_macaddr + 4) | macStaId1 | AR_STA_ID1_DEFAULT_ANTENNA); break; } /* Restore previous led state */ OS_REG_WRITE(ah, AR_PCICFG, OS_REG_READ(ah, AR_PCICFG) | ledstate); OS_REG_WRITE(ah, AR_GPIOCR, softLedCfg); OS_REG_WRITE(ah, AR_GPIODO, softLedState); /* Restore previous antenna */ OS_REG_WRITE(ah, AR_DEF_ANTENNA, saveDefAntenna); 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 */ /* * AR5211 WAR - pre-Production Oahu only. * Disable clock gating in all DMA blocks. This is a workaround for * a hardware problem seen with 11B and AES. * This workaround will result in higher power consumption. */ if (AH_PRIVATE(ah)->ah_macVersion == AR_SREV_VERSION_OAHU && AH_PRIVATE(ah)->ah_macRev < AR_SREV_OAHU_PROD) { OS_REG_WRITE(ah, AR_CFG, OS_REG_READ(ah, AR_CFG) | AR_CFG_CLK_GATE_DIS); } OS_REG_WRITE(ah, AR_RSSI_THR, INIT_RSSI_THR); /* Setup the transmit power values. */ if (!ar5211SetTransmitPower(ah, chan)) { HALDEBUG(ah, "%s: error init'ing transmit power\n", __func__); FAIL(HAL_EIO); } /* Setup board specific options for EEPROM version 3 */ ar5211SetBoardValues(ah, chan); if (!ar5211SetChannel(ah, ichan)) { HALDEBUG(ah, "%s: unable to set channel\n", __func__); FAIL(HAL_EIO); } /* Activate the PHY */ if (AH_PRIVATE(ah)->ah_devid == AR5211_FPGA11B && IS_CHAN_2GHZ(chan)) OS_REG_WRITE(ah, 0xd808, 0x502); /* required for FPGA */ OS_REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN); /* * 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. */ data = OS_REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_M; if (IS_CHAN_CCK(chan)) { synthDelay = (4 * data) / 22; } else { synthDelay = data / 10; } /* * There is an issue if the AP starts the calibration before * the baseband timeout completes. This could result in the * rxclear false triggering. Add an extra delay to ensure this * this does not happen. */ OS_DELAY(synthDelay + DELAY_BASE_ACTIVATE); /* Calibrate the AGC and wait for completion. */ OS_REG_WRITE(ah, AR_PHY_AGC_CONTROL, OS_REG_READ(ah, AR_PHY_AGC_CONTROL) | AR_PHY_AGC_CONTROL_CAL); (void) ath_hal_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 0); /* Perform noise floor and set status */ if (!ar5211CalNoiseFloor(ah, chan)) { if (!IS_CHAN_CCK(chan)) chan->channelFlags |= CHANNEL_CW_INT; HALDEBUG(ah, "%s: noise floor calibration failed\n", __func__); FAIL(HAL_EIO); } /* Start IQ calibration w/ 2^(INIT_IQCAL_LOG_COUNT_MAX+1) samples */ if (ahp->ah_calibrationTime != 0) { OS_REG_WRITE(ah, AR_PHY_TIMING_CTRL4, AR_PHY_TIMING_CTRL4_DO_IQCAL | (INIT_IQCAL_LOG_COUNT_MAX << AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX_S)); ahp->ah_bIQCalibration = AH_TRUE; } /* set 1:1 QCU to DCU mapping for all queues */ for (q = 0; q < AR_NUM_DCU; q++) OS_REG_WRITE(ah, AR_DQCUMASK(q), 1<<q); for (q = 0; q < HAL_NUM_TX_QUEUES; q++) ar5211ResetTxQueue(ah, q); /* Setup QCU0 transmit interrupt masks (TX_ERR, TX_OK, TX_DESC, TX_URN) */ OS_REG_WRITE(ah, AR_IMR_S0, (AR_IMR_S0_QCU_TXOK & AR_QCU_0) | (AR_IMR_S0_QCU_TXDESC & (AR_QCU_0<<AR_IMR_S0_QCU_TXDESC_S)));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -