📄 ar5211_reset.c.svn-base
字号:
/* * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting * Copyright (c) 2002-2006 Atheros Communications, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * $Id: ar5211_reset.c,v 1.9 2008/11/27 22:29:52 sam Exp $ */#include "opt_ah.h"/* * 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"#include "ah_eeprom_v3.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 { uint32_t refClkSel; /* reference clock, 1 for 16 MHz */ uint32_t channelSelect; /* P[7:4]S[3:0] bits */ uint16_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, uint32_t resetMask);static HAL_BOOL ar5211SetChannel(struct ath_hal *, HAL_CHANNEL_INTERNAL *);static int16_t ar5211RunNoiseFloor(struct ath_hal *, uint8_t runTime, int16_t startingNF);static HAL_BOOL ar5211IsNfGood(struct ath_hal *, HAL_CHANNEL_INTERNAL *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, uint16_t channel);static void ar5211SetRateTable(struct ath_hal *, RD_EDGES_POWER *pRdEdgesPower, TRGT_POWER_INFO *pPowerInfo, uint16_t numChannels, HAL_CHANNEL *chan);static uint16_t ar5211GetScaledPower(uint16_t channel, uint16_t pcdacValue, const PCDACS_EEPROM *pSrcStruct);static HAL_BOOL ar5211FindValueInList(uint16_t channel, uint16_t pcdacValue, const PCDACS_EEPROM *pSrcStruct, uint16_t *powerValue);static uint16_t ar5211GetInterpolatedValue(uint16_t target, uint16_t srcLeft, uint16_t srcRight, uint16_t targetLeft, uint16_t targetRight, HAL_BOOL scaleUp);static void ar5211GetLowerUpperValues(uint16_t value, const uint16_t *pList, uint16_t listSize, uint16_t *pLowerValue, uint16_t *pUpperValue);static void ar5211GetLowerUpperPcdacs(uint16_t pcdac, uint16_t channel, const PCDACS_EEPROM *pSrcStruct, uint16_t *pLowerPcdac, uint16_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 *);static void ar5211SetOperatingMode(struct ath_hal *, int opmode);/* * 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){uint32_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; uint32_t i, ledstate; HAL_STATUS ecode; int q; uint32_t data, synthDelay; uint32_t macStaId1; uint16_t modesIndex = 0, freqIndex = 0; uint32_t saveFrameSeqCount[AR_NUM_DCU]; uint32_t saveTsfLow = 0, saveTsfHigh = 0; uint32_t saveDefAntenna; HALDEBUG(ah, HAL_DEBUG_RESET, "%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, HAL_DEBUG_ANY, "%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, HAL_DEBUG_ANY, "%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, HAL_DEBUG_ANY, "%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, HAL_DEBUG_ANY, "%s: invalid operating mode %u\n", __func__, opmode); FAIL(HAL_EINVAL); break; } HALASSERT(AH_PRIVATE(ah)->ah_eeversion >= AR_EEPROM_VER3); /* Preserve certain DMA hardware registers on a channel change */ if (bChannelChange) { /* * Need to save/restore the TSF because of an issue * 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. 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->privFlags & 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, HAL_DEBUG_ANY, "%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) && AH_PRIVATE(ah)->ah_eeversion >= AR_EEPROM_VER3_1) { HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom; uint32_t ob2GHz, db2GHz; if (IS_CHAN_CCK(chan)) { ob2GHz = ee->ee_ob2GHz[0]; db2GHz = ee->ee_db2GHz[0]; } else { ob2GHz = ee->ee_ob2GHz[1]; db2GHz = ee->ee_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++) { uint32_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) { /* 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)); OS_REG_WRITE(ah, AR_STA_ID1, LE_READ_2(ahp->ah_macaddr + 4) | macStaId1 ); ar5211SetOperatingMode(ah, opmode); /* 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)); /* Restore bmiss rssi & count thresholds */ OS_REG_WRITE(ah, AR_RSSI_THR, ahp->ah_rssiThr); OS_REG_WRITE(ah, AR_ISR, ~0); /* cleared on write */ /* * for pre-Production Oahu only. * Disable clock gating in all DMA blocks. Helps when using * 11B and AES but results 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); } /* Setup the transmit power values. */ if (!ar5211SetTransmitPower(ah, chan)) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: error init'ing transmit power\n", __func__); FAIL(HAL_EIO); } /* * Configurable OFDM spoofing for 11n compatibility; used * only when operating in station mode. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -