📄 ar5212_reset.c
字号:
{ if (!ar5212SetPowerMode(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. */ return ar5212SetResetReg(ah, AR_RC_MAC | AR_RC_BB | AR_RC_PCI);}/* * Places the hardware into reset and then pulls it out of reset * * TODO: Only write the PLL if we're changing to or from CCK mode * * WARNING: The order of the PLL and mode registers must be correct. */HAL_BOOLar5212ChipReset(struct ath_hal *ah, HAL_CHANNEL *chan){ OS_MARK(ah, AH_MARK_CHIPRESET, chan ? chan->channel : 0); /* * Reset the HW - PCI must be reset after the rest of the * device has been reset */ if (!ar5212SetResetReg(ah, AR_RC_MAC | AR_RC_BB | AR_RC_PCI)) return AH_FALSE; /* Bring out of sleep mode (AGAIN) */ if (!ar5212SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE)) return AH_FALSE; /* Clear warm reset register */ if (!ar5212SetResetReg(ah, 0)) return AH_FALSE; /* * Perform warm reset before the mode/PLL/turbo registers * are changed in order to deactivate the radio. Mode changes * with an active radio can result in corrupted shifts to the * radio device. */ /* * Set CCK and Turbo modes correctly. */ if (chan != AH_NULL) { /* NB: can be null during attach */ uint32_t rfMode, phyPLL = 0, curPhyPLL, turbo; if (IS_5413(ah)) { /* NB: =>'s 5424 also */ rfMode = AR_PHY_MODE_AR5112; if (IS_CHAN_HALF_RATE(chan)) rfMode |= AR_PHY_MODE_HALF; else if (IS_CHAN_QUARTER_RATE(chan)) rfMode |= AR_PHY_MODE_QUARTER; if (IS_CHAN_CCK(chan) || IS_CHAN_G(chan)) phyPLL = AR_PHY_PLL_CTL_44_5112; else phyPLL = AR_PHY_PLL_CTL_40_5413; } else if (IS_RAD5111(ah)) { rfMode = AR_PHY_MODE_AR5111; if (IS_CHAN_CCK(chan) || IS_CHAN_G(chan)) phyPLL = AR_PHY_PLL_CTL_44; else phyPLL = AR_PHY_PLL_CTL_40; if (IS_CHAN_HALF_RATE(chan)) phyPLL = AR_PHY_PLL_CTL_HALF; else if (IS_CHAN_QUARTER_RATE(chan)) phyPLL = AR_PHY_PLL_CTL_QUARTER; } else { /* 5112, 2413, 2316, 2317 */ rfMode = AR_PHY_MODE_AR5112; if (IS_CHAN_CCK(chan) || IS_CHAN_G(chan)) phyPLL = AR_PHY_PLL_CTL_44_5112; else phyPLL = AR_PHY_PLL_CTL_40_5112; if (IS_CHAN_HALF_RATE(chan)) phyPLL |= AR_PHY_PLL_CTL_HALF; else if (IS_CHAN_QUARTER_RATE(chan)) phyPLL |= AR_PHY_PLL_CTL_QUARTER; } if (IS_CHAN_OFDM(chan) && (IS_CHAN_CCK(chan) || IS_CHAN_G(chan))) rfMode |= AR_PHY_MODE_DYNAMIC; else if (IS_CHAN_OFDM(chan)) rfMode |= AR_PHY_MODE_OFDM; else rfMode |= AR_PHY_MODE_CCK; if (IS_CHAN_5GHZ(chan)) rfMode |= AR_PHY_MODE_RF5GHZ; else rfMode |= AR_PHY_MODE_RF2GHZ; turbo = IS_CHAN_TURBO(chan) ? (AR_PHY_FC_TURBO_MODE | AR_PHY_FC_TURBO_SHORT) : 0; curPhyPLL = OS_REG_READ(ah, AR_PHY_PLL_CTL); /* * PLL, Mode, and Turbo values must be written in the correct * order to ensure: * - The PLL cannot be set to 44 unless the CCK or DYNAMIC * mode bit is set * - Turbo cannot be set at the same time as CCK or DYNAMIC */ if (IS_CHAN_CCK(chan) || IS_CHAN_G(chan)) { OS_REG_WRITE(ah, AR_PHY_TURBO, turbo); OS_REG_WRITE(ah, AR_PHY_MODE, rfMode); if (curPhyPLL != phyPLL) { OS_REG_WRITE(ah, AR_PHY_PLL_CTL, phyPLL); /* Wait for the PLL to settle */ OS_DELAY(PLL_SETTLE_DELAY); } } else { if (curPhyPLL != phyPLL) { OS_REG_WRITE(ah, AR_PHY_PLL_CTL, phyPLL); /* Wait for the PLL to settle */ OS_DELAY(PLL_SETTLE_DELAY); } OS_REG_WRITE(ah, AR_PHY_TURBO, turbo); OS_REG_WRITE(ah, AR_PHY_MODE, rfMode); } } return AH_TRUE;}/* * Recalibrate the lower PHY chips to account for temperature/environment * changes. */HAL_BOOLar5212PerCalibrationN(struct ath_hal *ah, HAL_CHANNEL *chan, u_int chainMask, HAL_BOOL longCal, HAL_BOOL *isCalDone){#define IQ_CAL_TRIES 10 struct ath_hal_5212 *ahp = AH5212(ah); HAL_CHANNEL_INTERNAL *ichan; int32_t qCoff, qCoffDenom; int32_t iqCorrMeas, iCoff, iCoffDenom; uint32_t powerMeasQ, powerMeasI; HAL_BOOL ichan_isBmode = AH_FALSE; HAL_BOOL isBmode = AH_FALSE; OS_MARK(ah, AH_MARK_PERCAL, chan->channel); *isCalDone = AH_FALSE; 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); return AH_FALSE; } SAVE_CCK(ah, ichan, ichan_isBmode); SAVE_CCK(ah, chan, isBmode); if (ahp->ah_bIQCalibration == IQ_CAL_DONE || ahp->ah_bIQCalibration == IQ_CAL_INACTIVE) *isCalDone = AH_TRUE; /* IQ calibration in progress. Check to see if it has finished. */ if (ahp->ah_bIQCalibration == IQ_CAL_RUNNING && !(OS_REG_READ(ah, AR_PHY_TIMING_CTRL4) & AR_PHY_TIMING_CTRL4_DO_IQCAL)) { int i; /* IQ Calibration has finished. */ ahp->ah_bIQCalibration = IQ_CAL_INACTIVE; *isCalDone = AH_TRUE; /* workaround for misgated IQ Cal results */ i = 0; do { /* 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); if (powerMeasI && powerMeasQ) break; /* Do we really need this??? */ OS_REG_WRITE (ah, AR_PHY_TIMING_CTRL4, OS_REG_READ(ah, AR_PHY_TIMING_CTRL4) | AR_PHY_TIMING_CTRL4_DO_IQCAL); } while (++i < IQ_CAL_TRIES); /* * Prescale these values to remove 64-bit operation * requirement at the loss of a little precision. */ iCoffDenom = (powerMeasI / 2 + powerMeasQ / 2) / 128; qCoffDenom = powerMeasQ / 128; /* Protect against divide-by-0 and loss of sign bits. */ if (iCoffDenom != 0 && qCoffDenom >= 2) { iCoff = (int8_t)(-iqCorrMeas) / iCoffDenom; /* IQCORR_Q_I_COFF is a signed 6 bit number */ if (iCoff < -32) { iCoff = -32; } else if (iCoff > 31) { iCoff = 31; } /* IQCORR_Q_Q_COFF is a signed 5 bit number */ qCoff = (powerMeasI / qCoffDenom) - 128; if (qCoff < -16) { qCoff = -16; } else if (qCoff > 15) { qCoff = 15; } HALDEBUG(ah, HAL_DEBUG_PERCAL, "****************** MISGATED IQ CAL! *******************\n"); HALDEBUG(ah, HAL_DEBUG_PERCAL, "time = %d, i = %d, \n", OS_GETUPTIME(ah), i); HALDEBUG(ah, HAL_DEBUG_PERCAL, "powerMeasI = 0x%08x\n", powerMeasI); HALDEBUG(ah, HAL_DEBUG_PERCAL, "powerMeasQ = 0x%08x\n", powerMeasQ); HALDEBUG(ah, HAL_DEBUG_PERCAL, "iqCorrMeas = 0x%08x\n", iqCorrMeas); HALDEBUG(ah, HAL_DEBUG_PERCAL, "iCoff = %d\n", iCoff); HALDEBUG(ah, HAL_DEBUG_PERCAL, "qCoff = %d\n", qCoff); /* Write values and enable correction */ OS_REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4, AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF, iCoff); OS_REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4, AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF, qCoff); OS_REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4, AR_PHY_TIMING_CTRL4_IQCORR_ENABLE); ahp->ah_bIQCalibration = IQ_CAL_DONE; ichan->iqCalValid = AH_TRUE; ichan->iCoff = iCoff; ichan->qCoff = qCoff; } } else if (!IS_CHAN_B(chan) && ahp->ah_bIQCalibration == IQ_CAL_DONE && !ichan->iqCalValid) { /* * Start IQ calibration if configured channel has changed. * Use a magic number of 15 based on default value. */ OS_REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4, AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX, INIT_IQCAL_LOG_COUNT_MAX); OS_REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4, AR_PHY_TIMING_CTRL4_DO_IQCAL); ahp->ah_bIQCalibration = IQ_CAL_RUNNING; } /* XXX EAR */ if (longCal) { /* Check noise floor results */ ar5212GetNf(ah, ichan); if ((ichan->channelFlags & CHANNEL_CW_INT) == 0) { /* Perform cal for 5Ghz channels and any OFDM on 5112 */ if (IS_CHAN_5GHZ(chan) || (IS_RAD5112(ah) && IS_CHAN_OFDM(chan))) ar5212RequestRfgain(ah); } else { /* report up and clear internal state */ chan->channelFlags |= CHANNEL_CW_INT; ichan->channelFlags &= ~CHANNEL_CW_INT; } } RESTORE_CCK(ah, ichan, ichan_isBmode); RESTORE_CCK(ah, chan, isBmode); return AH_TRUE;#undef IQ_CAL_TRIES}HAL_BOOLar5212PerCalibration(struct ath_hal *ah, HAL_CHANNEL *chan, HAL_BOOL *isIQdone){ return ar5212PerCalibrationN(ah, chan, 0x1, AH_TRUE, isIQdone);}HAL_BOOLar5212ResetCalValid(struct ath_hal *ah, HAL_CHANNEL *chan){ /* XXX */ return AH_TRUE;}/* * Write the given reset bit mask into the reset register */static HAL_BOOLar5212SetResetReg(struct ath_hal *ah, uint32_t resetMask){ uint32_t mask = resetMask ? resetMask : ~0; HAL_BOOL rt; /* XXX ar5212MacStop & co. */ if (IS_PCIE(ah)) { resetMask &= ~AR_RC_PCI; } (void) OS_REG_READ(ah, AR_RXDP);/* flush any pending MMR writes */ OS_REG_WRITE(ah, AR_RC, resetMask); OS_DELAY(15); /* need to wait at least 128 clocks when reseting PCI before read */ mask &= (AR_RC_MAC | AR_RC_BB); resetMask &= (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_SWRD | AR_CFG_SWRG;#ifndef AH_NEED_DESC_SWAP mask |= AR_CFG_SWTD;#endif OS_REG_WRITE(ah, AR_CFG, LE_READ_4(&mask)); } else OS_REG_WRITE(ah, AR_CFG, INIT_CONFIG_STATUS); if (ar5212SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE)) (void) OS_REG_READ(ah, AR_ISR_RAC); } /* track PHY power state so we don't try to r/w BB registers */ AH5212(ah)->ah_phyPowerOn = ((resetMask & AR_RC_BB) == 0); return rt;}int16_tar5212GetNoiseFloor(struct ath_hal *ah){ int16_t nf = (OS_REG_READ(ah, AR_PHY(25)) >> 19) & 0x1ff; if (nf & 0x100) nf = 0 - ((nf ^ 0x1ff) + 1); return nf;}static HAL_BOOLgetNoiseFloorThresh(struct ath_hal *ah, const HAL_CHANNEL_INTERNAL *chan, int16_t *nft){ const HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom; HALASSERT(ah->ah_magic == AR5212_MAGIC); switch (chan->channelFlags & CHANNEL_ALL_NOTURBO) { case CHANNEL_A: *nft = ee->ee_noiseFloorThresh[headerInfo11A]; break; case CHANNEL_B: *nft = ee->ee_noiseFloorThresh[headerInfo11B]; break; case CHANNEL_PUREG: *nft = ee->ee_noiseFloorThresh[headerInfo11G]; break; default: HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel flags 0x%x\n", __func__, chan->channelFlags); return AH_FALSE; } return AH_TRUE;}/* * Setup the noise floor cal history buffer. */void ar5212InitNfCalHistBuffer(struct ath_hal *ah){ struct ath_hal_5212 *ahp = AH5212(ah); int i; ahp->ah_nfCalHist.first_run = 1; ahp->ah_nfCalHist.currIndex = 0; ahp->ah_nfCalHist.privNF = AR5212_CCA_MAX_GOOD_VALUE; ahp->ah_nfCalHist.invalidNFcount = AR512_NF_CAL_HIST_MAX; for (i = 0; i < AR512_NF_CAL_HIST_MAX; i ++) ahp->ah_nfCalHist.nfCalBuffer[i] = AR5212_CCA_MAX_GOOD_VALUE;}/* * Add a noise floor value to the ring buffer. */static __inline voidupdateNFHistBuff(struct ar5212NfCalHist *h, int16_t nf){ h->nfCalBuffer[h->currIndex] = nf; if (++h->currIndex >= AR512_NF_CAL_HIST_MAX) h->currIndex = 0;} /* * Return the median noise floor value in the ring buffer. */int16_t ar5212GetNfHistMid(const int16_t calData[AR512_NF_CAL_HIST_MAX]){ int16_t sort[AR512_NF_CAL_HIST_MAX]; int i, j; OS_MEMCPY(sort, calData, AR512_NF_CAL_HIST_MAX*sizeof(int16_t)); for (i = 0; i < AR512_NF_CAL_HIST_MAX-1; i ++) { for (j = 1; j < AR512_NF_CAL_HIST_MAX-i; j ++) { if (sort[j] > sort[j-1]) { int16_t nf = sort[j]; sort[j] = sort[j-1]; sort[j-1] = nf; } } } return sort[(AR512_NF_CAL_HIST_MAX-1)>>1];}/* * Read the NF and check it against the noise floor threshhold */int16_tar5212GetNf(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan){ struct ath_hal_5212 *ahp = AH5212(ah); struct ar5212NfCalHist *h = &ahp->ah_nfCalHist;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -