📄 ar5211_reset.c
字号:
OS_REG_WRITE(ah, AR_IMR_S1, (AR_IMR_S1_QCU_TXERR & AR_QCU_0)); OS_REG_WRITE(ah, AR_IMR_S2, (AR_IMR_S2_QCU_TXURN & AR_QCU_0)); /* * DPD Added 4/19 from mainline: * AR5211 WAR - GBL_EIFS must always be written after writing * to any QCUMASK register. */ OS_REG_WRITE(ah, AR_D_GBL_IFS_EIFS, OS_REG_READ(ah, AR_D_GBL_IFS_EIFS)); /* Now set up the Interrupt Mask Register and save it for future use */ OS_REG_WRITE(ah, AR_IMR, INIT_INTERRUPT_MASK); ahp->ah_maskReg = INIT_INTERRUPT_MASK; /* Enable bus error interrupts */ OS_REG_WRITE(ah, AR_IMR_S2, OS_REG_READ(ah, AR_IMR_S2) | AR_IMR_S2_MCABT | AR_IMR_S2_SSERR | AR_IMR_S2_DPERR); /* Enable interrupts specific to AP */ if (opmode == HAL_M_HOSTAP) { OS_REG_WRITE(ah, AR_IMR, OS_REG_READ(ah, AR_IMR) | AR_IMR_MIB); ahp->ah_maskReg |= AR_IMR_MIB; } if (ar5211GetRfKill(ah)) ar5211EnableRfKill(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) ar5211SetSlotTime(ah, ahp->ah_slottime); if (ahp->ah_acktimeout != (u_int) -1) ar5211SetAckTimeout(ah, ahp->ah_acktimeout); if (ahp->ah_ctstimeout != (u_int) -1) ar5211SetCTSTimeout(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}/* * 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_BOOLar5211PhyDisable(struct ath_hal *ah){ return ar5211SetResetReg(ah, AR_RC_BB);}/* * Places all of hardware into reset */HAL_BOOLar5211Disable(struct ath_hal *ah){ if (!ar5211SetPowerMode(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 (!ar5211SetResetReg(ah, AR_RC_MAC | AR_RC_BB | AR_RC_PCI)) return AH_FALSE; OS_DELAY(2100); /* 8245 @ 96Mhz hangs with 2000us. */ return AH_TRUE;}/* * Places the hardware into reset and then pulls it out of reset * * Only write the PLL if we're changing to or from CCK mode * * Attach calls with channelFlags = 0, as the coldreset should have * us in the correct mode and we cannot check the hwchannel flags. */HAL_BOOLar5211ChipReset(struct ath_hal *ah, u_int16_t channelFlags){ if (!ar5211SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE)) return AH_FALSE; /* Set CCK and Turbo modes correctly */ switch (channelFlags & CHANNEL_ALL) { case CHANNEL_2GHZ|CHANNEL_CCK: case CHANNEL_2GHZ|CHANNEL_CCK|CHANNEL_TURBO: OS_REG_WRITE(ah, AR_PHY_TURBO, 0); OS_REG_WRITE(ah, AR5211_PHY_MODE, AR5211_PHY_MODE_CCK | AR5211_PHY_MODE_RF2GHZ); OS_REG_WRITE(ah, AR_PHY_PLL_CTL, AR_PHY_PLL_CTL_44); /* Wait for the PLL to settle */ OS_DELAY(DELAY_PLL_SETTLE); break; case CHANNEL_2GHZ|CHANNEL_OFDM: case CHANNEL_2GHZ|CHANNEL_OFDM|CHANNEL_TURBO: OS_REG_WRITE(ah, AR_PHY_TURBO, 0); if (AH_PRIVATE(ah)->ah_devid == AR5211_DEVID) { OS_REG_WRITE(ah, AR_PHY_PLL_CTL, AR_PHY_PLL_CTL_40); OS_DELAY(DELAY_PLL_SETTLE); OS_REG_WRITE(ah, AR5211_PHY_MODE, AR5211_PHY_MODE_OFDM | AR5211_PHY_MODE_RF2GHZ); } break; case CHANNEL_A: case CHANNEL_T: if (channelFlags & CHANNEL_TURBO) { OS_REG_WRITE(ah, AR_PHY_TURBO, AR_PHY_FC_TURBO_MODE | AR_PHY_FC_TURBO_SHORT); } else { /* 5 GHZ OFDM Mode */ OS_REG_WRITE(ah, AR_PHY_TURBO, 0); } if (AH_PRIVATE(ah)->ah_devid == AR5211_DEVID) { OS_REG_WRITE(ah, AR_PHY_PLL_CTL, AR_PHY_PLL_CTL_40); OS_DELAY(DELAY_PLL_SETTLE); OS_REG_WRITE(ah, AR5211_PHY_MODE, AR5211_PHY_MODE_OFDM | AR5211_PHY_MODE_RF5GHZ); } break; } /* NB: else no flags set - must be attach calling - do nothing */ /* * Reset the HW - PCI must be reset after the rest of the * device has been reset */ if (!ar5211SetResetReg(ah, AR_RC_MAC | AR_RC_BB | AR_RC_PCI)) return AH_FALSE; OS_DELAY(2100); /* 8245 @ 96Mhz hangs with 2000us. */ /* Bring out of sleep mode (AGAIN) */ if (!ar5211SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE)) return AH_FALSE; /* Clear warm reset register */ return ar5211SetResetReg(ah, 0);}/* * Recalibrate the lower PHY chips to account for temperature/environment * changes. */HAL_BOOLar5211PerCalibration(struct ath_hal *ah, HAL_CHANNEL *chan, HAL_BOOL *isIQdone){ struct ath_hal_5211 *ahp = AH5211(ah); int32_t qCoff, qCoffDenom; u_int32_t data; int32_t iqCorrMeas; int32_t iCoff, iCoffDenom; u_int32_t powerMeasQ, powerMeasI; /* IQ calibration in progress. Check to see if it has finished. */ if (ahp->ah_bIQCalibration && !(OS_REG_READ(ah, AR_PHY_TIMING_CTRL4) & AR_PHY_TIMING_CTRL4_DO_IQCAL)) { /* IQ Calibration has finished. */ ahp->ah_bIQCalibration = AH_FALSE; /* Read calibration results. */ powerMeasI = OS_REG_READ(ah, AR_PHY_IQCAL_RES_PWR_MEAS_I); powerMeasQ = OS_REG_READ(ah, AR_PHY_IQCAL_RES_PWR_MEAS_Q); iqCorrMeas = OS_REG_READ(ah, AR_PHY_IQCAL_RES_IQ_CORR_MEAS); /* * Prescale these values to remove 64-bit operation requirement at the loss * of a little precision. */ iCoffDenom = (powerMeasI / 2 + powerMeasQ / 2) / 128; qCoffDenom = powerMeasQ / 64; /* Protect against divide-by-0. */ if (iCoffDenom != 0 && qCoffDenom != 0) { iCoff = (-iqCorrMeas) / iCoffDenom; /* IQCORR_Q_I_COFF is a signed 6 bit number */ iCoff = iCoff & 0x3f; qCoff = ((int32_t)powerMeasI / qCoffDenom) - 64; /* IQCORR_Q_Q_COFF is a signed 5 bit number */ qCoff = qCoff & 0x1f;#ifdef CALIBRATION_DEBUG HALDEBUG(ah, "powerMeasI = 0x%08x\n", powerMeasI); HALDEBUG(ah, "powerMeasQ = 0x%08x\n", powerMeasQ); HALDEBUG(ah, "iqCorrMeas = 0x%08x\n", iqCorrMeas); HALDEBUG(ah, "iCoff = %d\n", iCoff); HALDEBUG(ah, "qCoff = %d\n", qCoff);#endif /* Write IQ */ data = OS_REG_READ(ah, AR_PHY_TIMING_CTRL4) | AR_PHY_TIMING_CTRL4_IQCORR_ENABLE | (((u_int32_t)iCoff) << AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF_S) | ((u_int32_t)qCoff); OS_REG_WRITE(ah, AR_PHY_TIMING_CTRL4, data); } } /* Perform noise floor and set status */ if (!ar5211IsNfGood(ah, chan)) { /* XXX??? */ if (!IS_CHAN_CCK(chan)) chan->channelFlags |= CHANNEL_CW_INT; return AH_FALSE; } if (!ar5211CalNoiseFloor(ah, chan)) { /* * Delay 5ms before retrying the noise floor * just to make sure, as we are in an error * condition here. */ OS_DELAY(5000); if (!ar5211CalNoiseFloor(ah, chan)) { if (!IS_CHAN_CCK(chan)) chan->channelFlags |= CHANNEL_CW_INT; return AH_FALSE; } } ar5211RequestRfgain(ah); *isIQdone = !ahp->ah_bIQCalibration; return AH_TRUE;}/* * Writes the given reset bit mask into the reset register */static HAL_BOOLar5211SetResetReg(struct ath_hal *ah, u_int32_t resetMask){ u_int32_t mask = resetMask ? resetMask : ~0; HAL_BOOL rt; (void) OS_REG_READ(ah, AR_RXDP);/* flush any pending MMR writes */ OS_REG_WRITE(ah, AR_RC, resetMask); /* need to wait at least 128 clocks when reseting PCI before read */ OS_DELAY(15); resetMask &= AR_RC_MAC | AR_RC_BB; mask &= AR_RC_MAC | AR_RC_BB; rt = ath_hal_wait(ah, AR_RC, mask, resetMask); if ((resetMask & AR_RC_MAC) == 0) { if (isBigEndian()) { /* * Set CFG, little-endian for register * and descriptor accesses. */ mask = INIT_CONFIG_STATUS | AR_CFG_SWTD | AR_CFG_SWRD | AR_CFG_SWRG; OS_REG_WRITE(ah, AR_CFG, LE_READ_4(&mask)); } else OS_REG_WRITE(ah, AR_CFG, INIT_CONFIG_STATUS); } return rt;}/* * Takes the MHz channel value and sets the Channel value * * ASSUMES: Writes enabled to analog bus before AGC is active * or by disabling the AGC. */static HAL_BOOLar5211SetChannel(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan){ u_int32_t refClk, reg32, data2111; int16_t chan5111, chanIEEE; chanIEEE = ath_hal_mhz2ieee(ah, chan->channel, chan->channelFlags); if (IS_CHAN_2GHZ(chan)) { const CHAN_INFO_2GHZ* ci = &chan2GHzData[chanIEEE + CI_2GHZ_INDEX_CORRECTION]; data2111 = ((ath_hal_reverseBits(ci->channelSelect, 8) & 0xff) << 5) | (ci->refClkSel << 4); chan5111 = ci->channel5111; } else { data2111 = 0; chan5111 = chanIEEE; } /* Rest of the code is common for 5 GHz and 2.4 GHz. */ if (chan5111 >= 145 || (chan5111 & 0x1)) { reg32 = ath_hal_reverseBits(chan5111 - 24, 8) & 0xFF; refClk = 1; } else { reg32 = ath_hal_reverseBits(((chan5111 - 24) / 2), 8) & 0xFF; refClk = 0; } reg32 = (reg32 << 2) | (refClk << 1) | (1 << 10) | 0x1; OS_REG_WRITE(ah, AR_PHY(0x27), ((data2111 & 0xff) << 8) | (reg32 & 0xff)); reg32 >>= 8; OS_REG_WRITE(ah, AR_PHY(0x34), (data2111 & 0xff00) | (reg32 & 0xff)); AH_PRIVATE(ah)->ah_curchan = chan; return AH_TRUE;}int16_tar5211GetNoiseFloor(struct ath_hal *ah){ int16_t nf; nf = (OS_REG_READ(ah, AR_PHY(25)) >> 19) & 0x1ff; if (nf & 0x100) nf = 0 - ((nf ^ 0x1ff) + 1); return nf;}/* * Peform the noisefloor calibration for the length of time set * in runTime (valid values 1 to 7) * * Returns: The NF value at the end of the given time (or 0 for failure) */int16_tar5211RunNoiseFloor(struct ath_hal *ah, u_int8_t runTime, int16_t startingNF){ int i, searchTime; HALASSERT(runTime <= 7); /* Setup noise floor run time and starting value */ OS_REG_WRITE(ah, AR_PHY(25), (OS_REG_READ(ah, AR_PHY(25)) & ~0xFFF) | ((runTime << 9) & 0xE00) | (startingNF & 0x1FF)); /* Calibrate the noise floor */ OS_REG_WRITE(ah, AR_PHY_AGC_CONTROL, OS_REG_READ(ah, AR_PHY_AGC_CONTROL) | AR_PHY_AGC_CONTROL_NF); /* Compute the required amount of searchTime needed to finish NF */ if (runTime == 0) { /* 8 search windows * 6.4us each */ searchTime = 8 * 7; } else { /* 512 * runtime search windows * 6.4us each */ searchTime = (runTime * 512) * 7; } /* * Do not read noise floor until it has been updated * * As a guesstimate - we may only get 1/60th the time on * the air to see search windows in a heavily congested * network (40 us every 2400 us of time) */ for (i = 0; i < 60; i++) { if ((OS_REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) == 0) break; OS_DELAY(searchTime); } if (i >= 60) {#ifdef AH_DEBUG HALDEBUG(ah, "NF with runTime %d failed to end on channel %d\n", runTime, AH_PRIVATE(ah)->ah_curchan->channel); HALDEBUG(ah, " PHY NF Reg state: 0x%x\n", OS_REG_READ(ah, AR_PHY_AGC_CONTROL)); HALDEBUG(ah, " PHY Active Reg state: 0x%x\n", OS_REG_READ(ah, AR_PHY_ACTIVE));#endif return 0; } return ar5211GetNoiseFloor(ah);}static HAL_BOOLgetNoiseFloorThresh(struct ath_hal *ah, HAL_CHANNEL *chan, int16_t *nft){ struct ath_hal_5211 *ahp = AH5211(ah); switch (chan->channelFlags & CHANNEL_ALL_NOTURBO) { case CHANNEL_A: *nft = ahp->ah_noiseFloorThresh[0]; break; case CHANNEL_CCK|CHANNEL_2GHZ: *nft = ahp->ah_noiseFloorThresh[1]; break; case CHANNEL_OFDM|CHANNEL_2GHZ: *nft = ahp->ah_noiseFloorThresh[2]; break; default: HALDEBUG(ah, "%s: invalid channel flags 0x%x\n", __func__, chan->channelFlags); return AH_FALSE; } return AH_TRUE;}/* * Read the NF and check it against the noise floor threshhold * * Returns: TRUE if the NF is good */static HAL_BOOLar5211IsNfGood(struct ath_hal *ah, HAL_CHANNEL *chan){ int16_t nf, nfThresh; if (!getNoiseFloorThresh(ah, chan, &nfThresh)) return AH_FALSE; if (OS_REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) HALDEBUG(ah, "%s: NF did not complete in calibration window\n", __func__); nf = (OS_REG_READ(ah, AR_PHY(25)) >> 19) & 0x1ff; if (nf & 0x100) nf = 0 - ((nf ^ 0x1ff) + 1); if (nf > nfThresh) HALDEBUG(ah, "%s: noise floor failed; detected %u, " "threshold %u\n", __func__, nf, nfThresh); return (nf <= nfThresh);}/* * Peform the noisefloor calibration and check for any constant channel * interference. * * NOTE: preAR5211 have a lengthy carrier wave detection process - hence * it is if'ed for MKK regulatory domain only. * * Returns: TRUE for a successful noise floor calibration; else FALSE */HAL_BOOLar5211CalNoiseFloor(struct ath_hal *ah, HAL_CHANNEL *chan){#define N(a) (sizeof (a) / sizeof (a[0])) /* Check for Carrier Wave interference in MKK regulatory zone */ if (AH_PRIVATE(ah)->ah_macVersion < AR_SREV_VERSION_OAHU && ath_hal_getnfcheckrequired(ah, chan)) { static const u_int8_t runtime[3] = { 0, 2, 7 }; int16_t nf, nfThresh; int i; if (!getNoiseFloorThresh(ah, chan, &nfThresh)) return AH_FALSE; /* * Run a quick noise floor that will hopefully * complete (decrease delay time). */ for (i = 0; i < N(runtime); i++) { nf = ar5211RunNoiseFloor(ah, runtime[i], 0); if (nf > nfThresh) HALDEBUG(ah, "%s: run failed with %u > " "threshold %u (runtime %u)\n", __func__, nf, nfThresh, runtime[i]); } return (i <= N(runtime)); } else { /* Calibrate the noise floor */ OS_REG_WRITE(ah, AR_PHY_AGC_CONTROL, OS_REG_READ(ah, AR_PHY_AGC_CONTROL) | AR_PHY_AGC_CONTROL_NF); } return AH_TRUE;#undef N}/* * Reads EEPROM header info from device structure and programs * analog registers 6 and 7 * * REQUIRES: Access to the analog device */static HAL_BOOLar5211SetRf6and7(struct ath_hal *ah, HAL_CHANNEL *chan){#define N(a) (sizeof (a) / sizeof (a[0])) struct ath_hal_5211 *ahp = AH5211(ah); u_int16_t rfXpdGain, rfPloSel, rfPwdXpd; u_int16_t tempOB, tempDB; u_int16_t freqIndex; int i;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -