/* * 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_BOOL ar5312Reset(struct ath_hal *ah, HAL_OPMODE opmode, struct ieee80211_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; const HAL_EEPROM *ee; uint32_t saveFrameSeqCount, saveDefAntenna; uint32_t macStaId1, synthDelay, txFrm2TxDStart; uint16_t rfXpdGain[MAX_NUM_PDGAINS_PER_CHANNEL]; int16_t cckOfdmPwrDelta = 0; u_int modesIndex, freqIndex; HAL_STATUS ecode; int i, regWrites = 0; uint32_t testReg; uint32_t saveLedState = 0; HALASSERT(ah->ah_magic == AR5212_MAGIC); ee = AH_PRIVATE(ah)->ah_eeprom; OS_MARK(ah, AH_MARK_RESET, bChannelChange); /* * 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->ic_freq, chan->ic_flags); 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(ahp->ah_eeversion >= AR_EEPROM_VER3); /* Preserve certain DMA hardware registers on a channel change */ if (bChannelChange) { /* * On Venice, the TSF is almost preserved across a reset; * it requires the 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); } 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->ic_freq != AH_PRIVATE(ah)->ah_curchan->ic_freq) && ((chan->ic_flags & IEEE80211_CHAN_ALLTURBO) == (AH_PRIVATE(ah)->ah_curchan->ic_flags & IEEE80211_CHAN_ALLTURBO))) { if (ar5212ChannelChange(ah, chan)) /* If ChannelChange completed - skip the rest of reset */ return AH_TRUE; } } /* * 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); /* Save led state from pci config register */ if (!IS_5315(ah)) saveLedState = OS_REG_READ(ah, AR5312_PCICFG) & (AR_PCICFG_LEDCTL | AR_PCICFG_LEDMODE | AR_PCICFG_LEDBLINK | AR_PCICFG_LEDSLOW); 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, HAL_DEBUG_ANY, "%s: chip reset failed\n", __func__); FAIL(HAL_EIO); } /* Setup the indices for the next set of register array writes */ if (IEEE80211_IS_CHAN_2GHZ(chan)) { freqIndex = 2; modesIndex = IEEE80211_IS_CHAN_108G(chan) ? 5 : IEEE80211_IS_CHAN_G(chan) ? 4 : 3; } else { freqIndex = 1; modesIndex = IEEE80211_IS_CHAN_ST(chan) ? 2 : 1; } 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); regWrites = ath_hal_ini_write(ah, &ahp->ah_ini_modes, modesIndex, 0); regWrites = write_common(ah, &ahp->ah_ini_common, bChannelChange, regWrites); ahp->ah_rfHal->writeRegs(ah, modesIndex, freqIndex, regWrites); OS_MARK(ah, AH_MARK_RESET_LINE, __LINE__); if (IEEE80211_IS_CHAN_HALF(chan) || IEEE80211_IS_CHAN_QUARTER(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(ee->ee_cckOfdmPwrDelta - ee->ee_scaledCh14FilterCckDelta); } else { cckOfdmPwrDelta = SCALE_OC_DELTA(ee->ee_cckOfdmPwrDelta); } if (IEEE80211_IS_CHAN_G(chan)) { OS_REG_WRITE(ah, AR_PHY_TXPWRADJ, SM((ee->ee_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 (IEEE80211_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 (IEEE80211_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 (IEEE80211_IS_CHAN_A(chan)) 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 (!ar5212SetTransmitPower(ah, chan, rfXpdGain)) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: error init'ing transmit power\n", __func__); FAIL(HAL_EIO); } /* Write the analog registers */ if (!ahp->ah_rfHal->setRfRegs(ah, chan, modesIndex, rfXpdGain)) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: ar5212SetRfRegs failed\n", __func__); FAIL(HAL_EIO); } /* Write delta slope for OFDM enabled modes (A, G, Turbo) */ if (IEEE80211_IS_CHAN_OFDM(chan)) { if (IS_5413(ah) || AH_PRIVATE(ah)->ah_eeversion >= AR_EEPROM_VER5_3) ar5212SetSpurMitigation(ah, chan); ar5212SetDeltaSlope(ah, chan); } /* Setup board specific options for EEPROM version 3 */ if (!ar5212SetBoardValues(ah, chan)) { HALDEBUG(ah, HAL_DEBUG_ANY, "%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)); /* Restore previous led state */ if (!IS_5315(ah)) OS_REG_WRITE(ah, AR5312_PCICFG, OS_REG_READ(ah, AR_PCICFG) | saveLedState); /* 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)); /* 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 */ if (!ar5212SetChannel(ah, chan)) 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_RAD5112_ANY(ah) && (IEEE80211_IS_CHAN_HALF(chan) || IEEE80211_IS_CHAN_QUARTER(chan))) { txFrm2TxDStart = IEEE80211_IS_CHAN_HALF(chan) ? 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 */ /* flush SCAL reg */ if (IS_5312_2_X(ah)) { (void) 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 (IEEE80211_IS_CHAN_B(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 (IEEE80211_IS_CHAN_HALF(chan)) { OS_DELAY((synthDelay << 1) + BASE_ACTIVATE_DELAY); } else if (IEEE80211_IS_CHAN_QUARTER(chan)) { OS_DELAY((synthDelay << 2) + BASE_ACTIVATE_DELAY); } else { OS_DELAY(synthDelay + BASE_ACTIVATE_DELAY); } /* * The udelay method is not reliable with notebooks. * Need to check to see if the baseband is ready */ testReg = OS_REG_READ(ah, AR_PHY_TESTCTRL); /* Selects the Tx hold */ OS_REG_WRITE(ah, AR_PHY_TESTCTRL, AR_PHY_TESTCTRL_TXHOLD); i = 0; while ((i++ < 20) && (OS_REG_READ(ah, 0x9c24) & 0x10)) /* test if baseband not ready */ OS_DELAY(200); OS_REG_WRITE(ah, AR_PHY_TESTCTRL, testReg); /* 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 (!IEEE80211_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, 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; } else ahp->ah_bIQCalibration = IQ_CAL_INACTIVE; /* Setup compression registers */ ar5212SetCompRegs(ah); /* Set 1:1 QCU to DCU mapping for all queues */ for (i = 0; i < AR_NUM_DCU; i++) OS_REG_WRITE(ah, AR_DQCUMASK(i), 1 << i); ahp->ah_intrTxqs = 0; for (i = 0; i < AH_PRIVATE(ah)->ah_caps.halTotalQueues; i++) ar5212ResetTxQueue(ah, i); /* * Setup interrupt handling. Note that ar5212ResetTxQueue * manipulates the secondary IMR's as queues are enabled * and disabled. This is done with RMW ops to insure the * settings we make here are preserved. */ ahp->ah_maskReg = AR_IMR_TXOK | AR_IMR_TXERR | AR_IMR_TXURN | AR_IMR_RXOK | AR_IMR_RXERR | AR_IMR_RXORN | AR_IMR_HIUERR ; if (opmode == HAL_M_HOSTAP) ahp->ah_maskReg |= AR_IMR_MIB; OS_REG_WRITE(ah, AR_IMR, ahp->ah_maskReg); /* Enable bus errors that are OR'd to set the HIUERR bit */ 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); if (AH_PRIVATE(ah)->ah_rfkillEnabled) ar5212EnableRfKill(ah); if (!ath_hal_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 0)) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: offset calibration failed to complete in 1ms;" " noisy environment?\n", __func__); } /* * Set clocks back to 32kHz if they had been using refClk, then * use an external 32kHz crystal when sleeping, if one exists. */ ar5312SetupClock(ah, opmode); /* * 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))); /* XXX Setup post reset EAR additions */ /* QoS support */ if (AH_PRIVATE(ah)->ah_macVersion > AR_SREV_VERSION_VENICE || (AH_PRIVATE(ah)->ah_macVersion == AR_SREV_VERSION_VENICE && AH_PRIVATE(ah)->ah_macRev >= AR_SREV_GRIFFIN_LITE)) { OS_REG_WRITE(ah, AR_QOS_CONTROL, 0x100aa); /* XXX magic */ OS_REG_WRITE(ah, AR_QOS_SELECT, 0x3210); /* XXX magic */ } /* Turn on NOACK Support for QoS packets */ OS_REG_WRITE(ah, AR_NOACK, SM(2, AR_NOACK_2BIT_VALUE) | SM(5, AR_NOACK_BIT_OFFSET) | SM(0, AR_NOACK_BYTE_OFFSET)); /* Restore user-specified settings */ if (ahp->ah_miscMode != 0) OS_REG_WRITE(ah, AR_MISC_MODE, ahp->ah_miscMode); if (ahp->ah_slottime != (u_int) -1) ar5212SetSlotTime(ah, ahp->ah_slottime); if (ahp->ah_acktimeout != (u_int) -1) ar5212SetAckTimeout(ah, ahp->ah_acktimeout); if (ahp->ah_ctstimeout != (u_int) -1) ar5212SetCTSTimeout(ah, ahp->ah_ctstimeout); if (ahp->ah_sifstime != (u_int) -1) ar5212SetSifsTime(ah, ahp->ah_sifstime); 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 */ if (bChannelChange && !IEEE80211_IS_CHAN_DFS(chan)) chan->ic_state &= ~IEEE80211_CHANSTATE_CWINT; HALDEBUG(ah, HAL_DEBUG_RESET, "%s: done\n", __func__); OS_MARK(ah, AH_MARK_RESET_DONE, 0); return AH_TRUE; bad: OS_MARK(ah, AH_MARK_RESET_DONE, ecode); if (status != AH_NULL) *status = ecode; return AH_FALSE; #undef FAIL #undef N }
void ar9280SpurMitigate(struct ath_hal *ah, const struct ieee80211_channel *chan) { static const int pilot_mask_reg[4] = { AR_PHY_TIMING7, AR_PHY_TIMING8, AR_PHY_PILOT_MASK_01_30, AR_PHY_PILOT_MASK_31_60 }; static const int chan_mask_reg[4] = { AR_PHY_TIMING9, AR_PHY_TIMING10, AR_PHY_CHANNEL_MASK_01_30, AR_PHY_CHANNEL_MASK_31_60 }; static int inc[4] = { 0, 100, 0, 0 }; int bb_spur = AR_NO_SPUR; int freq; int bin, cur_bin; int bb_spur_off, spur_subchannel_sd; int spur_freq_sd; int spur_delta_phase; int denominator; int upper, lower, cur_vit_mask; int tmp, newVal; int i; CHAN_CENTERS centers; int8_t mask_m[123]; int8_t mask_p[123]; int8_t mask_amt; int tmp_mask; int cur_bb_spur; HAL_BOOL is2GHz = IEEE80211_IS_CHAN_2GHZ(chan); OS_MEMZERO(&mask_m, sizeof(int8_t) * 123); OS_MEMZERO(&mask_p, sizeof(int8_t) * 123); ar5416GetChannelCenters(ah, chan, ¢ers); freq = centers.synth_center; /* * Need to verify range +/- 9.38 for static ht20 and +/- 18.75 for ht40, * otherwise spur is out-of-band and can be ignored. */ for (i = 0; i < AR5416_EEPROM_MODAL_SPURS; i++) { cur_bb_spur = ath_hal_getSpurChan(ah, i, is2GHz); /* Get actual spur freq in MHz from EEPROM read value */ if (is2GHz) { cur_bb_spur = (cur_bb_spur / 10) + AR_BASE_FREQ_2GHZ; } else { cur_bb_spur = (cur_bb_spur / 10) + AR_BASE_FREQ_5GHZ; } if (AR_NO_SPUR == cur_bb_spur) break; cur_bb_spur = cur_bb_spur - freq; if (IEEE80211_IS_CHAN_HT40(chan)) { if ((cur_bb_spur > -AR_SPUR_FEEQ_BOUND_HT40) && (cur_bb_spur < AR_SPUR_FEEQ_BOUND_HT40)) { bb_spur = cur_bb_spur; break; } } else if ((cur_bb_spur > -AR_SPUR_FEEQ_BOUND_HT20) && (cur_bb_spur < AR_SPUR_FEEQ_BOUND_HT20)) { bb_spur = cur_bb_spur; break; } } if (AR_NO_SPUR == bb_spur) { #if 1 /* * MRC CCK can interfere with beacon detection and cause deaf/mute. * Disable MRC CCK for now. */ OS_REG_CLR_BIT(ah, AR_PHY_FORCE_CLKEN_CCK, AR_PHY_FORCE_CLKEN_CCK_MRC_MUX); #else /* Enable MRC CCK if no spur is found in this channel. */ OS_REG_SET_BIT(ah, AR_PHY_FORCE_CLKEN_CCK, AR_PHY_FORCE_CLKEN_CCK_MRC_MUX); #endif return; } else { /* * For Merlin, spur can break CCK MRC algorithm. Disable CCK MRC if spur * is found in this channel. */ OS_REG_CLR_BIT(ah, AR_PHY_FORCE_CLKEN_CCK, AR_PHY_FORCE_CLKEN_CCK_MRC_MUX); } bin = bb_spur * 320; tmp = OS_REG_READ(ah, AR_PHY_TIMING_CTRL4_CHAIN(0)); newVal = tmp | (AR_PHY_TIMING_CTRL4_ENABLE_SPUR_RSSI | AR_PHY_TIMING_CTRL4_ENABLE_SPUR_FILTER | AR_PHY_TIMING_CTRL4_ENABLE_CHAN_MASK | AR_PHY_TIMING_CTRL4_ENABLE_PILOT_MASK); OS_REG_WRITE(ah, AR_PHY_TIMING_CTRL4_CHAIN(0), newVal); newVal = (AR_PHY_SPUR_REG_MASK_RATE_CNTL | AR_PHY_SPUR_REG_ENABLE_MASK_PPM | AR_PHY_SPUR_REG_MASK_RATE_SELECT | AR_PHY_SPUR_REG_ENABLE_VIT_SPUR_RSSI | SM(AR5416_SPUR_RSSI_THRESH, AR_PHY_SPUR_REG_SPUR_RSSI_THRESH)); OS_REG_WRITE(ah, AR_PHY_SPUR_REG, newVal); /* Pick control or extn channel to cancel the spur */ if (IEEE80211_IS_CHAN_HT40(chan)) { if (bb_spur < 0) { spur_subchannel_sd = 1; bb_spur_off = bb_spur + 10; } else { spur_subchannel_sd = 0; bb_spur_off = bb_spur - 10; } } else { spur_subchannel_sd = 0; bb_spur_off = bb_spur; } /* * spur_delta_phase = bb_spur/40 * 2**21 for static ht20, * /80 for dyn2040. */ if (IEEE80211_IS_CHAN_HT40(chan)) spur_delta_phase = ((bb_spur * 262144) / 10) & AR_PHY_TIMING11_SPUR_DELTA_PHASE; else spur_delta_phase = ((bb_spur * 524288) / 10) & AR_PHY_TIMING11_SPUR_DELTA_PHASE; /* * in 11A mode the denominator of spur_freq_sd should be 40 and * it should be 44 in 11G */ denominator = IEEE80211_IS_CHAN_2GHZ(chan) ? 44 : 40; spur_freq_sd = ((bb_spur_off * 2048) / denominator) & 0x3ff; newVal = (AR_PHY_TIMING11_USE_SPUR_IN_AGC | SM(spur_freq_sd, AR_PHY_TIMING11_SPUR_FREQ_SD) | SM(spur_delta_phase, AR_PHY_TIMING11_SPUR_DELTA_PHASE)); OS_REG_WRITE(ah, AR_PHY_TIMING11, newVal); /* Choose to cancel between control and extension channels */ newVal = spur_subchannel_sd << AR_PHY_SFCORR_SPUR_SUBCHNL_SD_S; OS_REG_WRITE(ah, AR_PHY_SFCORR_EXT, newVal); /* * ============================================ * Set Pilot and Channel Masks * * pilot mask 1 [31:0] = +6..-26, no 0 bin * pilot mask 2 [19:0] = +26..+7 * * channel mask 1 [31:0] = +6..-26, no 0 bin * channel mask 2 [19:0] = +26..+7 */ cur_bin = -6000; upper = bin + 100; lower = bin - 100; for (i = 0; i < 4; i++) { int pilot_mask = 0; int chan_mask = 0; int bp = 0; for (bp = 0; bp < 30; bp++) { if ((cur_bin > lower) && (cur_bin < upper)) { pilot_mask = pilot_mask | 0x1 << bp; chan_mask = chan_mask | 0x1 << bp; } cur_bin += 100; } cur_bin += inc[i]; OS_REG_WRITE(ah, pilot_mask_reg[i], pilot_mask); OS_REG_WRITE(ah, chan_mask_reg[i], chan_mask); } /* ================================================= * viterbi mask 1 based on channel magnitude * four levels 0-3 * - mask (-27 to 27) (reg 64,0x9900 to 67,0x990c) * [1 2 2 1] for -9.6 or [1 2 1] for +16 * - enable_mask_ppm, all bins move with freq * * - mask_select, 8 bits for rates (reg 67,0x990c) * - mask_rate_cntl, 8 bits for rates (reg 67,0x990c) * choose which mask to use mask or mask2 */ /* * viterbi mask 2 2nd set for per data rate puncturing * four levels 0-3 * - mask_select, 8 bits for rates (reg 67) * - mask (-27 to 27) (reg 98,0x9988 to 101,0x9994) * [1 2 2 1] for -9.6 or [1 2 1] for +16 */ cur_vit_mask = 6100; upper = bin + 120; lower = bin - 120; for (i = 0; i < 123; i++) { if ((cur_vit_mask > lower) && (cur_vit_mask < upper)) { if ((abs(cur_vit_mask - bin)) < 75) { mask_amt = 1; } else { mask_amt = 0; } if (cur_vit_mask < 0) { mask_m[abs(cur_vit_mask / 100)] = mask_amt; } else { mask_p[cur_vit_mask / 100] = mask_amt; } } cur_vit_mask -= 100; } tmp_mask = (mask_m[46] << 30) | (mask_m[47] << 28) | (mask_m[48] << 26) | (mask_m[49] << 24) | (mask_m[50] << 22) | (mask_m[51] << 20) | (mask_m[52] << 18) | (mask_m[53] << 16) | (mask_m[54] << 14) | (mask_m[55] << 12) | (mask_m[56] << 10) | (mask_m[57] << 8) | (mask_m[58] << 6) | (mask_m[59] << 4) | (mask_m[60] << 2) | (mask_m[61] << 0); OS_REG_WRITE(ah, AR_PHY_BIN_MASK_1, tmp_mask); OS_REG_WRITE(ah, AR_PHY_VIT_MASK2_M_46_61, tmp_mask); tmp_mask = (mask_m[31] << 28) | (mask_m[32] << 26) | (mask_m[33] << 24) | (mask_m[34] << 22) | (mask_m[35] << 20) | (mask_m[36] << 18) | (mask_m[37] << 16) | (mask_m[48] << 14) | (mask_m[39] << 12) | (mask_m[40] << 10) | (mask_m[41] << 8) | (mask_m[42] << 6) | (mask_m[43] << 4) | (mask_m[44] << 2) | (mask_m[45] << 0); OS_REG_WRITE(ah, AR_PHY_BIN_MASK_2, tmp_mask); OS_REG_WRITE(ah, AR_PHY_MASK2_M_31_45, tmp_mask); tmp_mask = (mask_m[16] << 30) | (mask_m[16] << 28) | (mask_m[18] << 26) | (mask_m[18] << 24) | (mask_m[20] << 22) | (mask_m[20] << 20) | (mask_m[22] << 18) | (mask_m[22] << 16) | (mask_m[24] << 14) | (mask_m[24] << 12) | (mask_m[25] << 10) | (mask_m[26] << 8) | (mask_m[27] << 6) | (mask_m[28] << 4) | (mask_m[29] << 2) | (mask_m[30] << 0); OS_REG_WRITE(ah, AR_PHY_BIN_MASK_3, tmp_mask); OS_REG_WRITE(ah, AR_PHY_MASK2_M_16_30, tmp_mask); tmp_mask = (mask_m[ 0] << 30) | (mask_m[ 1] << 28) | (mask_m[ 2] << 26) | (mask_m[ 3] << 24) | (mask_m[ 4] << 22) | (mask_m[ 5] << 20) | (mask_m[ 6] << 18) | (mask_m[ 7] << 16) | (mask_m[ 8] << 14) | (mask_m[ 9] << 12) | (mask_m[10] << 10) | (mask_m[11] << 8) | (mask_m[12] << 6) | (mask_m[13] << 4) | (mask_m[14] << 2) | (mask_m[15] << 0); OS_REG_WRITE(ah, AR_PHY_MASK_CTL, tmp_mask); OS_REG_WRITE(ah, AR_PHY_MASK2_M_00_15, tmp_mask); tmp_mask = (mask_p[15] << 28) | (mask_p[14] << 26) | (mask_p[13] << 24) | (mask_p[12] << 22) | (mask_p[11] << 20) | (mask_p[10] << 18) | (mask_p[ 9] << 16) | (mask_p[ 8] << 14) | (mask_p[ 7] << 12) | (mask_p[ 6] << 10) | (mask_p[ 5] << 8) | (mask_p[ 4] << 6) | (mask_p[ 3] << 4) | (mask_p[ 2] << 2) | (mask_p[ 1] << 0); OS_REG_WRITE(ah, AR_PHY_BIN_MASK2_1, tmp_mask); OS_REG_WRITE(ah, AR_PHY_MASK2_P_15_01, tmp_mask); tmp_mask = (mask_p[30] << 28) | (mask_p[29] << 26) | (mask_p[28] << 24) | (mask_p[27] << 22) | (mask_p[26] << 20) | (mask_p[25] << 18) | (mask_p[24] << 16) | (mask_p[23] << 14) | (mask_p[22] << 12) | (mask_p[21] << 10) | (mask_p[20] << 8) | (mask_p[19] << 6) | (mask_p[18] << 4) | (mask_p[17] << 2) | (mask_p[16] << 0); OS_REG_WRITE(ah, AR_PHY_BIN_MASK2_2, tmp_mask); OS_REG_WRITE(ah, AR_PHY_MASK2_P_30_16, tmp_mask); tmp_mask = (mask_p[45] << 28) | (mask_p[44] << 26) | (mask_p[43] << 24) | (mask_p[42] << 22) | (mask_p[41] << 20) | (mask_p[40] << 18) | (mask_p[39] << 16) | (mask_p[38] << 14) | (mask_p[37] << 12) | (mask_p[36] << 10) | (mask_p[35] << 8) | (mask_p[34] << 6) | (mask_p[33] << 4) | (mask_p[32] << 2) | (mask_p[31] << 0); OS_REG_WRITE(ah, AR_PHY_BIN_MASK2_3, tmp_mask); OS_REG_WRITE(ah, AR_PHY_MASK2_P_45_31, tmp_mask); tmp_mask = (mask_p[61] << 30) | (mask_p[60] << 28) | (mask_p[59] << 26) | (mask_p[58] << 24) | (mask_p[57] << 22) | (mask_p[56] << 20) | (mask_p[55] << 18) | (mask_p[54] << 16) | (mask_p[53] << 14) | (mask_p[52] << 12) | (mask_p[51] << 10) | (mask_p[50] << 8) | (mask_p[49] << 6) | (mask_p[48] << 4) | (mask_p[47] << 2) | (mask_p[46] << 0); OS_REG_WRITE(ah, AR_PHY_BIN_MASK2_4, tmp_mask); OS_REG_WRITE(ah, AR_PHY_MASK2_P_61_45, tmp_mask); }
static void ar9287AniSetup(struct ath_hal *ah) { /* * These are the parameters from the AR5416 ANI code; * they likely need quite a bit of adjustment for the * AR9287. */ static const struct ar5212AniParams aniparams = { .maxNoiseImmunityLevel = 4, /* levels 0..4 */ .totalSizeDesired = { -55, -55, -55, -55, -62 }, .coarseHigh = { -14, -14, -14, -14, -12 }, .coarseLow = { -64, -64, -64, -64, -70 }, .firpwr = { -78, -78, -78, -78, -80 }, .maxSpurImmunityLevel = 7, .cycPwrThr1 = { 2, 4, 6, 8, 10, 12, 14, 16 }, .maxFirstepLevel = 2, /* levels 0..2 */ .firstep = { 0, 4, 8 }, .ofdmTrigHigh = 500, .ofdmTrigLow = 200, .cckTrigHigh = 200, .cckTrigLow = 100, .rssiThrHigh = 40, .rssiThrLow = 7, .period = 100, }; /* NB: disable ANI noise immmunity for reliable RIFS rx */ AH5416(ah)->ah_ani_function &= ~ HAL_ANI_NOISE_IMMUNITY_LEVEL; /* NB: ANI is not enabled yet */ ar5416AniAttach(ah, &aniparams, &aniparams, AH_TRUE); } /* * Attach for an AR9287 part. */ static struct ath_hal * ar9287Attach(uint16_t devid, HAL_SOFTC sc, HAL_BUS_TAG st, HAL_BUS_HANDLE sh, uint16_t *eepromdata, HAL_STATUS *status) { struct ath_hal_9287 *ahp9287; struct ath_hal_5212 *ahp; struct ath_hal *ah; uint32_t val; HAL_STATUS ecode; HAL_BOOL rfStatus; int8_t pwr_table_offset; HALDEBUG(AH_NULL, HAL_DEBUG_ATTACH, "%s: sc %p st %p sh %p\n", __func__, sc, (void*) st, (void*) sh); /* NB: memory is returned zero'd */ ahp9287 = ath_hal_malloc(sizeof (struct ath_hal_9287)); if (ahp9287 == AH_NULL) { HALDEBUG(AH_NULL, HAL_DEBUG_ANY, "%s: cannot allocate memory for state block\n", __func__); *status = HAL_ENOMEM; return AH_NULL; } ahp = AH5212(ahp9287); ah = &ahp->ah_priv.h; ar5416InitState(AH5416(ah), devid, sc, st, sh, status); if (eepromdata != AH_NULL) { AH_PRIVATE(ah)->ah_eepromRead = ath_hal_EepromDataRead; AH_PRIVATE(ah)->ah_eepromWrite = NULL; ah->ah_eepromdata = eepromdata; } /* XXX override with 9280 specific state */ /* override 5416 methods for our needs */ AH5416(ah)->ah_initPLL = ar9280InitPLL; ah->ah_setAntennaSwitch = ar9287SetAntennaSwitch; ah->ah_configPCIE = ar9287ConfigPCIE; ah->ah_disablePCIE = ar9287DisablePCIE; AH5416(ah)->ah_cal.iqCalData.calData = &ar9287_iq_cal; AH5416(ah)->ah_cal.adcGainCalData.calData = &ar9287_adc_gain_cal; AH5416(ah)->ah_cal.adcDcCalData.calData = &ar9287_adc_dc_cal; AH5416(ah)->ah_cal.adcDcCalInitData.calData = &ar9287_adc_init_dc_cal; /* Better performance without ADC Gain Calibration */ AH5416(ah)->ah_cal.suppCals = ADC_DC_CAL | IQ_MISMATCH_CAL; AH5416(ah)->ah_spurMitigate = ar9280SpurMitigate; AH5416(ah)->ah_writeIni = ar9287WriteIni; ah->ah_setTxPower = ar9287SetTransmitPower; ah->ah_setBoardValues = ar9287SetBoardValues; AH5416(ah)->ah_olcInit = ar9287olcInit; AH5416(ah)->ah_olcTempCompensation = ar9287olcTemperatureCompensation; //AH5416(ah)->ah_setPowerCalTable = ar9287SetPowerCalTable; AH5416(ah)->ah_cal_initcal = ar9287InitCalHardware; AH5416(ah)->ah_cal_pacal = ar9287PACal; /* XXX NF calibration */ /* XXX Ini override? (IFS vars - since the kiwi mac clock is faster?) */ /* XXX what else is kiwi-specific in the radio/calibration pathway? */ AH5416(ah)->ah_rx_chainmask = AR9287_DEFAULT_RXCHAINMASK; AH5416(ah)->ah_tx_chainmask = AR9287_DEFAULT_TXCHAINMASK; if (!ar5416SetResetReg(ah, HAL_RESET_POWER_ON)) { /* reset chip */ HALDEBUG(ah, HAL_DEBUG_ANY, "%s: couldn't reset chip\n", __func__); ecode = HAL_EIO; goto bad; } if (!ar5416SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE)) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: couldn't wakeup chip\n", __func__); ecode = HAL_EIO; goto bad; } /* Read Revisions from Chips before taking out of reset */ val = OS_REG_READ(ah, AR_SREV); HALDEBUG(ah, HAL_DEBUG_ATTACH, "%s: ID 0x%x VERSION 0x%x TYPE 0x%x REVISION 0x%x\n", __func__, MS(val, AR_XSREV_ID), MS(val, AR_XSREV_VERSION), MS(val, AR_XSREV_TYPE), MS(val, AR_XSREV_REVISION)); /* NB: include chip type to differentiate from pre-Sowl versions */ AH_PRIVATE(ah)->ah_macVersion = (val & AR_XSREV_VERSION) >> AR_XSREV_TYPE_S; AH_PRIVATE(ah)->ah_macRev = MS(val, AR_XSREV_REVISION); AH_PRIVATE(ah)->ah_ispcie = (val & AR_XSREV_TYPE_HOST_MODE) == 0; /* Don't support Kiwi < 1.2; those are pre-release chips */ if (! AR_SREV_KIWI_12_OR_LATER(ah)) { ath_hal_printf(ah, "[ath]: Kiwi < 1.2 is not supported\n"); ecode = HAL_EIO; goto bad; } /* setup common ini data; rf backends handle remainder */ HAL_INI_INIT(&ahp->ah_ini_modes, ar9287Modes_9287_1_1, 6); HAL_INI_INIT(&ahp->ah_ini_common, ar9287Common_9287_1_1, 2); /* If pcie_clock_req */ HAL_INI_INIT(&AH5416(ah)->ah_ini_pcieserdes, ar9287PciePhy_clkreq_always_on_L1_9287_1_1, 2); /* XXX WoW ini values */ /* Else */ #if 0 HAL_INI_INIT(&AH5416(ah)->ah_ini_pcieserdes, ar9287PciePhy_clkreq_off_L1_9287_1_1, 2); #endif /* Initialise Japan arrays */ HAL_INI_INIT(&ahp9287->ah_ini_cckFirNormal, ar9287Common_normal_cck_fir_coeff_9287_1_1, 2); HAL_INI_INIT(&ahp9287->ah_ini_cckFirJapan2484, ar9287Common_japan_2484_cck_fir_coeff_9287_1_1, 2); ar5416AttachPCIE(ah); ecode = ath_hal_9287EepromAttach(ah); if (ecode != HAL_OK) goto bad; if (!ar5416ChipReset(ah, AH_NULL)) { /* reset chip */ HALDEBUG(ah, HAL_DEBUG_ANY, "%s: chip reset failed\n", __func__); ecode = HAL_EIO; goto bad; } AH_PRIVATE(ah)->ah_phyRev = OS_REG_READ(ah, AR_PHY_CHIP_ID); if (!ar5212ChipTest(ah)) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: hardware self-test failed\n", __func__); ecode = HAL_ESELFTEST; goto bad; } /* * Set correct Baseband to analog shift * setting to access analog chips. */ OS_REG_WRITE(ah, AR_PHY(0), 0x00000007); /* Read Radio Chip Rev Extract */ AH_PRIVATE(ah)->ah_analog5GhzRev = ar5416GetRadioRev(ah); switch (AH_PRIVATE(ah)->ah_analog5GhzRev & AR_RADIO_SREV_MAJOR) { case AR_RAD2133_SREV_MAJOR: /* Sowl: 2G/3x3 */ case AR_RAD5133_SREV_MAJOR: /* Sowl: 2+5G/3x3 */ break; default: if (AH_PRIVATE(ah)->ah_analog5GhzRev == 0) { AH_PRIVATE(ah)->ah_analog5GhzRev = AR_RAD5133_SREV_MAJOR; break; } #ifdef AH_DEBUG HALDEBUG(ah, HAL_DEBUG_ANY, "%s: 5G Radio Chip Rev 0x%02X is not supported by " "this driver\n", __func__, AH_PRIVATE(ah)->ah_analog5GhzRev); ecode = HAL_ENOTSUPP; goto bad; #endif } rfStatus = ar9287RfAttach(ah, &ecode); if (!rfStatus) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: RF setup failed, status %u\n", __func__, ecode); goto bad; } /* * We only implement open-loop TX power control * for the AR9287 in this codebase. */ if (! ath_hal_eepromGetFlag(ah, AR_EEP_OL_PWRCTRL)) { ath_hal_printf(ah, "[ath] AR9287 w/ closed-loop TX power control" " isn't supported.\n"); ecode = HAL_ENOTSUPP; goto bad; } /* * Check whether the power table offset isn't the default. * This can occur with eeprom minor V21 or greater on Merlin. */ (void) ath_hal_eepromGet(ah, AR_EEP_PWR_TABLE_OFFSET, &pwr_table_offset); if (pwr_table_offset != AR5416_PWR_TABLE_OFFSET_DB) ath_hal_printf(ah, "[ath]: default pwr offset: %d dBm != EEPROM pwr offset: %d dBm; curves will be adjusted.\n", AR5416_PWR_TABLE_OFFSET_DB, (int) pwr_table_offset); /* setup rxgain table */ HAL_INI_INIT(&ahp9287->ah_ini_rxgain, ar9287Modes_rx_gain_9287_1_1, 6); /* setup txgain table */ HAL_INI_INIT(&ahp9287->ah_ini_txgain, ar9287Modes_tx_gain_9287_1_1, 6); /* * Got everything we need now to setup the capabilities. */ if (!ar9287FillCapabilityInfo(ah)) { ecode = HAL_EEREAD; goto bad; } ecode = ath_hal_eepromGet(ah, AR_EEP_MACADDR, ahp->ah_macaddr); if (ecode != HAL_OK) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: error getting mac address from EEPROM\n", __func__); goto bad; } /* XXX How about the serial number ? */ /* Read Reg Domain */ AH_PRIVATE(ah)->ah_currentRD = ath_hal_eepromGet(ah, AR_EEP_REGDMN_0, AH_NULL); AH_PRIVATE(ah)->ah_currentRDext = AR9287_RDEXT_DEFAULT; /* * ah_miscMode is populated by ar5416FillCapabilityInfo() * starting from griffin. Set here to make sure that * AR_MISC_MODE_MIC_NEW_LOC_ENABLE is set before a GTK is * placed into hardware. */ if (ahp->ah_miscMode != 0) OS_REG_WRITE(ah, AR_MISC_MODE, OS_REG_READ(ah, AR_MISC_MODE) | ahp->ah_miscMode); ar9287AniSetup(ah); /* Anti Noise Immunity */ /* Setup noise floor min/max/nominal values */ AH5416(ah)->nf_2g.max = AR_PHY_CCA_MAX_GOOD_VAL_9287_2GHZ; AH5416(ah)->nf_2g.min = AR_PHY_CCA_MIN_GOOD_VAL_9287_2GHZ; AH5416(ah)->nf_2g.nominal = AR_PHY_CCA_NOM_VAL_9287_2GHZ; AH5416(ah)->nf_5g.max = AR_PHY_CCA_MAX_GOOD_VAL_9287_5GHZ; AH5416(ah)->nf_5g.min = AR_PHY_CCA_MIN_GOOD_VAL_9287_5GHZ; AH5416(ah)->nf_5g.nominal = AR_PHY_CCA_NOM_VAL_9287_5GHZ; ar5416InitNfHistBuff(AH5416(ah)->ah_cal.nfCalHist); HALDEBUG(ah, HAL_DEBUG_ATTACH, "%s: return\n", __func__); return ah; bad: if (ah != AH_NULL) ah->ah_detach(ah); if (status) *status = ecode; return AH_NULL; } static void ar9287ConfigPCIE(struct ath_hal *ah, HAL_BOOL restore, HAL_BOOL power_off) { if (AH_PRIVATE(ah)->ah_ispcie && !restore) { ath_hal_ini_write(ah, &AH5416(ah)->ah_ini_pcieserdes, 1, 0); OS_DELAY(1000); OS_REG_SET_BIT(ah, AR_PCIE_PM_CTRL, AR_PCIE_PM_CTRL_ENA); /* Yes, Kiwi uses the Kite PCIe PHY WA */ OS_REG_WRITE(ah, AR_WA, AR9285_WA_DEFAULT); } } static void ar9287DisablePCIE(struct ath_hal *ah) { /* XXX TODO */ } static void ar9287WriteIni(struct ath_hal *ah, const struct ieee80211_channel *chan) { u_int modesIndex, freqIndex; int regWrites = 0; /* Setup the indices for the next set of register array writes */ /* XXX Ignore 11n dynamic mode on the AR5416 for the moment */ if (IEEE80211_IS_CHAN_2GHZ(chan)) { freqIndex = 2; if (IEEE80211_IS_CHAN_HT40(chan)) modesIndex = 3; else if (IEEE80211_IS_CHAN_108G(chan)) modesIndex = 5; else modesIndex = 4; } else { freqIndex = 1; if (IEEE80211_IS_CHAN_HT40(chan) || IEEE80211_IS_CHAN_TURBO(chan)) modesIndex = 2; else modesIndex = 1; } /* Set correct Baseband to analog shift setting to access analog chips. */ OS_REG_WRITE(ah, AR_PHY(0), 0x00000007); OS_REG_WRITE(ah, AR_PHY_ADC_SERIAL_CTL, AR_PHY_SEL_INTERNAL_ADDAC); regWrites = ath_hal_ini_write(ah, &AH5212(ah)->ah_ini_modes, modesIndex, regWrites); regWrites = ath_hal_ini_write(ah, &AH9287(ah)->ah_ini_rxgain, modesIndex, regWrites); regWrites = ath_hal_ini_write(ah, &AH9287(ah)->ah_ini_txgain, modesIndex, regWrites); regWrites = ath_hal_ini_write(ah, &AH5212(ah)->ah_ini_common, 1, regWrites); }
/* * Control Adaptive Noise Immunity Parameters */ HAL_BOOL ar5416AniControl(struct ath_hal *ah, HAL_ANI_CMD cmd, int param) { typedef int TABLE[]; struct ath_hal_5212 *ahp = AH5212(ah); struct ar5212AniState *aniState = ahp->ah_curani; const struct ar5212AniParams *params = AH_NULL; /* * This function may be called before there's a current * channel (eg to disable ANI.) */ if (aniState != AH_NULL) params = aniState->params; OS_MARK(ah, AH_MARK_ANI_CONTROL, cmd); /* These commands can't be disabled */ if (cmd == HAL_ANI_PRESENT) return AH_TRUE; if (cmd == HAL_ANI_MODE) { if (param == 0) { ahp->ah_procPhyErr &= ~HAL_ANI_ENA; /* Turn off HW counters if we have them */ ar5416AniDetach(ah); } else { /* normal/auto mode */ /* don't mess with state if already enabled */ if (! (ahp->ah_procPhyErr & HAL_ANI_ENA)) { /* Enable MIB Counters */ /* * XXX use 2.4ghz params if no channel is * available */ enableAniMIBCounters(ah, ahp->ah_curani != AH_NULL ? ahp->ah_curani->params: &ahp->ah_aniParams24); ahp->ah_procPhyErr |= HAL_ANI_ENA; } } return AH_TRUE; } /* Check whether the particular function is enabled */ if (((1 << cmd) & AH5416(ah)->ah_ani_function) == 0) { HALDEBUG(ah, HAL_DEBUG_ANI, "%s: command %d disabled\n", __func__, cmd); HALDEBUG(ah, HAL_DEBUG_ANI, "%s: cmd %d; mask %x\n", __func__, cmd, AH5416(ah)->ah_ani_function); return AH_FALSE; } switch (cmd) { case HAL_ANI_NOISE_IMMUNITY_LEVEL: { u_int level = param; HALDEBUG(ah, HAL_DEBUG_ANI, "%s: HAL_ANI_NOISE_IMMUNITY_LEVEL: set level = %d\n", __func__, level); if (level > params->maxNoiseImmunityLevel) { HALDEBUG(ah, HAL_DEBUG_ANI, "%s: immunity level out of range (%u > %u)\n", __func__, level, params->maxNoiseImmunityLevel); return AH_FALSE; } OS_REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, AR_PHY_DESIRED_SZ_TOT_DES, params->totalSizeDesired[level]); OS_REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1, AR_PHY_AGC_CTL1_COARSE_LOW, params->coarseLow[level]); OS_REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1, AR_PHY_AGC_CTL1_COARSE_HIGH, params->coarseHigh[level]); OS_REG_RMW_FIELD(ah, AR_PHY_FIND_SIG, AR_PHY_FIND_SIG_FIRPWR, params->firpwr[level]); if (level > aniState->noiseImmunityLevel) ahp->ah_stats.ast_ani_niup++; else if (level < aniState->noiseImmunityLevel) ahp->ah_stats.ast_ani_nidown++; aniState->noiseImmunityLevel = level; break; } case HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION: { static const TABLE m1ThreshLow = { 127, 50 }; static const TABLE m2ThreshLow = { 127, 40 }; static const TABLE m1Thresh = { 127, 0x4d }; static const TABLE m2Thresh = { 127, 0x40 }; static const TABLE m2CountThr = { 31, 16 }; static const TABLE m2CountThrLow = { 63, 48 }; u_int on = param ? 1 : 0; HALDEBUG(ah, HAL_DEBUG_ANI, "%s: HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION: %s\n", __func__, on ? "enabled" : "disabled"); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, AR_PHY_SFCORR_LOW_M1_THRESH_LOW, m1ThreshLow[on]); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, AR_PHY_SFCORR_LOW_M2_THRESH_LOW, m2ThreshLow[on]); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR, AR_PHY_SFCORR_M1_THRESH, m1Thresh[on]); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR, AR_PHY_SFCORR_M2_THRESH, m2Thresh[on]); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR, AR_PHY_SFCORR_M2COUNT_THR, m2CountThr[on]); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW, m2CountThrLow[on]); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, AR_PHY_SFCORR_EXT_M1_THRESH_LOW, m1ThreshLow[on]); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, AR_PHY_SFCORR_EXT_M2_THRESH_LOW, m2ThreshLow[on]); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, AR_PHY_SFCORR_EXT_M1_THRESH, m1Thresh[on]); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, AR_PHY_SFCORR_EXT_M2_THRESH, m2Thresh[on]); if (on) { OS_REG_SET_BIT(ah, AR_PHY_SFCORR_LOW, AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW); } else { OS_REG_CLR_BIT(ah, AR_PHY_SFCORR_LOW, AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW); } if (on) ahp->ah_stats.ast_ani_ofdmon++; else ahp->ah_stats.ast_ani_ofdmoff++; aniState->ofdmWeakSigDetectOff = !on; break; } case HAL_ANI_CCK_WEAK_SIGNAL_THR: { static const TABLE weakSigThrCck = { 8, 6 }; u_int high = param ? 1 : 0; HALDEBUG(ah, HAL_DEBUG_ANI, "%s: HAL_ANI_CCK_WEAK_SIGNAL_THR: %s\n", __func__, high ? "high" : "low"); OS_REG_RMW_FIELD(ah, AR_PHY_CCK_DETECT, AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK, weakSigThrCck[high]); if (high) ahp->ah_stats.ast_ani_cckhigh++; else ahp->ah_stats.ast_ani_ccklow++; aniState->cckWeakSigThreshold = high; break; } case HAL_ANI_FIRSTEP_LEVEL: { u_int level = param; HALDEBUG(ah, HAL_DEBUG_ANI, "%s: HAL_ANI_FIRSTEP_LEVEL: level = %d\n", __func__, level); if (level > params->maxFirstepLevel) { HALDEBUG(ah, HAL_DEBUG_ANI, "%s: firstep level out of range (%u > %u)\n", __func__, level, params->maxFirstepLevel); return AH_FALSE; } OS_REG_RMW_FIELD(ah, AR_PHY_FIND_SIG, AR_PHY_FIND_SIG_FIRSTEP, params->firstep[level]); if (level > aniState->firstepLevel) ahp->ah_stats.ast_ani_stepup++; else if (level < aniState->firstepLevel) ahp->ah_stats.ast_ani_stepdown++; aniState->firstepLevel = level; break; } case HAL_ANI_SPUR_IMMUNITY_LEVEL: { u_int level = param; HALDEBUG(ah, HAL_DEBUG_ANI, "%s: HAL_ANI_SPUR_IMMUNITY_LEVEL: level = %d\n", __func__, level); if (level > params->maxSpurImmunityLevel) { HALDEBUG(ah, HAL_DEBUG_ANI, "%s: spur immunity level out of range (%u > %u)\n", __func__, level, params->maxSpurImmunityLevel); return AH_FALSE; } OS_REG_RMW_FIELD(ah, AR_PHY_TIMING5, AR_PHY_TIMING5_CYCPWR_THR1, params->cycPwrThr1[level]); if (level > aniState->spurImmunityLevel) ahp->ah_stats.ast_ani_spurup++; else if (level < aniState->spurImmunityLevel) ahp->ah_stats.ast_ani_spurdown++; aniState->spurImmunityLevel = level; break; } #ifdef AH_PRIVATE_DIAG case HAL_ANI_PHYERR_RESET: ahp->ah_stats.ast_ani_ofdmerrs = 0; ahp->ah_stats.ast_ani_cckerrs = 0; break; #endif /* AH_PRIVATE_DIAG */ default: HALDEBUG(ah, HAL_DEBUG_ANI, "%s: invalid cmd %u\n", __func__, cmd); return AH_FALSE; } return AH_TRUE; }
static void ar9280ConfigPCIE(struct ath_hal *ah, HAL_BOOL restore, HAL_BOOL power_off) { uint32_t val; if (AH_PRIVATE(ah)->ah_ispcie && !restore) { ath_hal_ini_write(ah, &AH5416(ah)->ah_ini_pcieserdes, 1, 0); OS_DELAY(1000); } /* * Set PCIe workaround bits * * NOTE: * * In Merlin and Kite, bit 14 in WA register (disable L1) should only * be set when device enters D3 and be cleared when device comes back * to D0. */ if (power_off) { /* Power-off */ OS_REG_CLR_BIT(ah, AR_PCIE_PM_CTRL, AR_PCIE_PM_CTRL_ENA); val = OS_REG_READ(ah, AR_WA); /* * Disable bit 6 and 7 before entering D3 to prevent * system hang. */ val &= ~(AR_WA_BIT6 | AR_WA_BIT7); /* * XXX Not sure, is specified in the reference HAL. */ val |= AR_WA_BIT22; /* * See above: set AR_WA_D3_L1_DISABLE when entering D3 state. * * XXX The reference HAL does it this way - it only sets * AR_WA_D3_L1_DISABLE if it's set in AR9280_WA_DEFAULT, * which it (currently) isn't. So the following statement * is currently a NOP. */ if (AR9280_WA_DEFAULT & AR_WA_D3_L1_DISABLE) val |= AR_WA_D3_L1_DISABLE; OS_REG_WRITE(ah, AR_WA, val); } else { /* Power-on */ val = AR9280_WA_DEFAULT; /* * See note above: make sure L1_DISABLE is not set. */ val &= (~AR_WA_D3_L1_DISABLE); OS_REG_WRITE(ah, AR_WA, val); /* set bit 19 to allow forcing of pcie core into L1 state */ OS_REG_SET_BIT(ah, AR_PCIE_PM_CTRL, AR_PCIE_PM_CTRL_ENA); } }
/* * Use HW data to do IQ Mismatch Calibration */ void ar5416IQCalibration(struct ath_hal *ah, uint8_t numChains) { struct ar5416PerCal *cal = &AH5416(ah)->ah_cal; int i; for (i = 0; i < numChains; i++) { uint32_t powerMeasI = cal->totalPowerMeasI(i); uint32_t powerMeasQ = cal->totalPowerMeasQ(i); uint32_t iqCorrMeas = cal->totalIqCorrMeas(i); uint32_t qCoffDenom, iCoffDenom; int iqCorrNeg; HALDEBUG(ah, HAL_DEBUG_PERCAL, "Start IQ Cal and Correction for Chain %d\n", i); HALDEBUG(ah, HAL_DEBUG_PERCAL, "Orignal: iq_corr_meas = 0x%08x\n", iqCorrMeas); iqCorrNeg = 0; /* iqCorrMeas is always negative. */ if (iqCorrMeas > 0x80000000) { iqCorrMeas = (0xffffffff - iqCorrMeas) + 1; iqCorrNeg = 1; } HALDEBUG(ah, HAL_DEBUG_PERCAL, " pwr_meas_i = 0x%08x\n", powerMeasI); HALDEBUG(ah, HAL_DEBUG_PERCAL, " pwr_meas_q = 0x%08x\n", powerMeasQ); HALDEBUG(ah, HAL_DEBUG_PERCAL, " iqCorrNeg is 0x%08x\n", iqCorrNeg); iCoffDenom = (powerMeasI/2 + powerMeasQ/2)/ 128; qCoffDenom = powerMeasQ / 64; /* Protect against divide-by-0 */ if (powerMeasQ != 0) { /* IQ corr_meas is already negated if iqcorr_neg == 1 */ int32_t iCoff = iqCorrMeas/iCoffDenom; int32_t qCoff = powerMeasI/qCoffDenom - 64; HALDEBUG(ah, HAL_DEBUG_PERCAL, " iCoff = 0x%08x\n", iCoff); HALDEBUG(ah, HAL_DEBUG_PERCAL, " qCoff = 0x%08x\n", qCoff); /* Negate iCoff if iqCorrNeg == 0 */ iCoff = iCoff & 0x3f; HALDEBUG(ah, HAL_DEBUG_PERCAL, "New: iCoff = 0x%08x\n", iCoff); if (iqCorrNeg == 0x0) iCoff = 0x40 - iCoff; if (qCoff > 15) qCoff = 15; else if (qCoff <= -16) qCoff = -16; HALDEBUG(ah, HAL_DEBUG_PERCAL, " : iCoff = 0x%x qCoff = 0x%x\n", iCoff, qCoff); OS_REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4_CHAIN(i), AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF, iCoff); OS_REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4_CHAIN(i), AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF, qCoff); HALDEBUG(ah, HAL_DEBUG_PERCAL, "IQ Cal and Correction done for Chain %d\n", i); } } OS_REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4, AR_PHY_TIMING_CTRL4_IQCORR_ENABLE); }
static void ar9285AniSetup(struct ath_hal *ah) { /* * These are the parameters from the AR5416 ANI code; * they likely need quite a bit of adjustment for the * AR9285. */ static const struct ar5212AniParams aniparams = { .maxNoiseImmunityLevel = 4, /* levels 0..4 */ .totalSizeDesired = { -55, -55, -55, -55, -62 }, .coarseHigh = { -14, -14, -14, -14, -12 }, .coarseLow = { -64, -64, -64, -64, -70 }, .firpwr = { -78, -78, -78, -78, -80 }, .maxSpurImmunityLevel = 7, .cycPwrThr1 = { 2, 4, 6, 8, 10, 12, 14, 16 }, .maxFirstepLevel = 2, /* levels 0..2 */ .firstep = { 0, 4, 8 }, .ofdmTrigHigh = 500, .ofdmTrigLow = 200, .cckTrigHigh = 200, .cckTrigLow = 100, .rssiThrHigh = 40, .rssiThrLow = 7, .period = 100, }; /* NB: disable ANI noise immmunity for reliable RIFS rx */ AH5416(ah)->ah_ani_function &= ~(1 << HAL_ANI_NOISE_IMMUNITY_LEVEL); ar5416AniAttach(ah, &aniparams, &aniparams, AH_TRUE); } static const char * ar9285_lna_conf[] = { "LNA1-LNA2", "LNA2", "LNA1", "LNA1+LNA2", }; static void ar9285_eeprom_print_diversity_settings(struct ath_hal *ah) { const HAL_EEPROM_v4k *ee = AH_PRIVATE(ah)->ah_eeprom; const MODAL_EEP4K_HEADER *pModal = &ee->ee_base.modalHeader; ath_hal_printf(ah, "[ath] AR9285 Main LNA config: %s\n", ar9285_lna_conf[(pModal->antdiv_ctl2 >> 2) & 0x3]); ath_hal_printf(ah, "[ath] AR9285 Alt LNA config: %s\n", ar9285_lna_conf[pModal->antdiv_ctl2 & 0x3]); ath_hal_printf(ah, "[ath] LNA diversity %s, Diversity %s\n", ((pModal->antdiv_ctl1 & 0x1) ? "enabled" : "disabled"), ((pModal->antdiv_ctl1 & 0x8) ? "enabled" : "disabled")); } /* * Attach for an AR9285 part. */ static struct ath_hal * ar9285Attach(uint16_t devid, HAL_SOFTC sc, HAL_BUS_TAG st, HAL_BUS_HANDLE sh, uint16_t *eepromdata, HAL_OPS_CONFIG *ah_config, HAL_STATUS *status) { struct ath_hal_9285 *ahp9285; struct ath_hal_5212 *ahp; struct ath_hal *ah; uint32_t val; HAL_STATUS ecode; HAL_BOOL rfStatus; HALDEBUG(AH_NULL, HAL_DEBUG_ATTACH, "%s: sc %p st %p sh %p\n", __func__, sc, (void*) st, (void*) sh); /* NB: memory is returned zero'd */ ahp9285 = ath_hal_malloc(sizeof (struct ath_hal_9285)); if (ahp9285 == AH_NULL) { HALDEBUG(AH_NULL, HAL_DEBUG_ANY, "%s: cannot allocate memory for state block\n", __func__); *status = HAL_ENOMEM; return AH_NULL; } ahp = AH5212(ahp9285); ah = &ahp->ah_priv.h; ar5416InitState(AH5416(ah), devid, sc, st, sh, status); /* * Use the "local" EEPROM data given to us by the higher layers. * This is a private copy out of system flash. The Linux ath9k * commit for the initial AR9130 support mentions MMIO flash * access is "unreliable." -adrian */ if (eepromdata != AH_NULL) { AH_PRIVATE(ah)->ah_eepromRead = ath_hal_EepromDataRead; AH_PRIVATE(ah)->ah_eepromWrite = NULL; ah->ah_eepromdata = eepromdata; } /* override with 9285 specific state */ AH5416(ah)->ah_initPLL = ar9280InitPLL; AH5416(ah)->ah_btCoexSetDiversity = ar9285BTCoexAntennaDiversity; ah->ah_setAntennaSwitch = ar9285SetAntennaSwitch; ah->ah_configPCIE = ar9285ConfigPCIE; ah->ah_disablePCIE = ar9285DisablePCIE; ah->ah_setTxPower = ar9285SetTransmitPower; ah->ah_setBoardValues = ar9285SetBoardValues; ah->ah_btCoexSetParameter = ar9285BTCoexSetParameter; ah->ah_divLnaConfGet = ar9285_antdiv_comb_conf_get; ah->ah_divLnaConfSet = ar9285_antdiv_comb_conf_set; AH5416(ah)->ah_cal.iqCalData.calData = &ar9280_iq_cal; AH5416(ah)->ah_cal.adcGainCalData.calData = &ar9280_adc_gain_cal; AH5416(ah)->ah_cal.adcDcCalData.calData = &ar9280_adc_dc_cal; AH5416(ah)->ah_cal.adcDcCalInitData.calData = &ar9280_adc_init_dc_cal; AH5416(ah)->ah_cal.suppCals = ADC_GAIN_CAL | ADC_DC_CAL | IQ_MISMATCH_CAL; AH5416(ah)->ah_spurMitigate = ar9280SpurMitigate; AH5416(ah)->ah_writeIni = ar9285WriteIni; AH5416(ah)->ah_rx_chainmask = AR9285_DEFAULT_RXCHAINMASK; AH5416(ah)->ah_tx_chainmask = AR9285_DEFAULT_TXCHAINMASK; ahp->ah_maxTxTrigLev = MAX_TX_FIFO_THRESHOLD >> 1; if (!ar5416SetResetReg(ah, HAL_RESET_POWER_ON)) { /* reset chip */ HALDEBUG(ah, HAL_DEBUG_ANY, "%s: couldn't reset chip\n", __func__); ecode = HAL_EIO; goto bad; } if (!ar5416SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE)) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: couldn't wakeup chip\n", __func__); ecode = HAL_EIO; goto bad; } /* Read Revisions from Chips before taking out of reset */ val = OS_REG_READ(ah, AR_SREV); HALDEBUG(ah, HAL_DEBUG_ATTACH, "%s: ID 0x%x VERSION 0x%x TYPE 0x%x REVISION 0x%x\n", __func__, MS(val, AR_XSREV_ID), MS(val, AR_XSREV_VERSION), MS(val, AR_XSREV_TYPE), MS(val, AR_XSREV_REVISION)); /* NB: include chip type to differentiate from pre-Sowl versions */ AH_PRIVATE(ah)->ah_macVersion = (val & AR_XSREV_VERSION) >> AR_XSREV_TYPE_S; AH_PRIVATE(ah)->ah_macRev = MS(val, AR_XSREV_REVISION); AH_PRIVATE(ah)->ah_ispcie = (val & AR_XSREV_TYPE_HOST_MODE) == 0; /* setup common ini data; rf backends handle remainder */ if (AR_SREV_KITE_12_OR_LATER(ah)) { HAL_INI_INIT(&ahp->ah_ini_modes, ar9285Modes_v2, 6); HAL_INI_INIT(&ahp->ah_ini_common, ar9285Common_v2, 2); HAL_INI_INIT(&AH5416(ah)->ah_ini_pcieserdes, ar9285PciePhy_clkreq_always_on_L1_v2, 2); } else { HAL_INI_INIT(&ahp->ah_ini_modes, ar9285Modes, 6); HAL_INI_INIT(&ahp->ah_ini_common, ar9285Common, 2); HAL_INI_INIT(&AH5416(ah)->ah_ini_pcieserdes, ar9285PciePhy_clkreq_always_on_L1, 2); } ar5416AttachPCIE(ah); /* Attach methods that require MAC version/revision info */ if (AR_SREV_KITE_12_OR_LATER(ah)) AH5416(ah)->ah_cal_initcal = ar9285InitCalHardware; if (AR_SREV_KITE_11_OR_LATER(ah)) AH5416(ah)->ah_cal_pacal = ar9002_hw_pa_cal; ecode = ath_hal_v4kEepromAttach(ah); if (ecode != HAL_OK) goto bad; if (!ar5416ChipReset(ah, AH_NULL)) { /* reset chip */ HALDEBUG(ah, HAL_DEBUG_ANY, "%s: chip reset failed\n", __func__); ecode = HAL_EIO; goto bad; } AH_PRIVATE(ah)->ah_phyRev = OS_REG_READ(ah, AR_PHY_CHIP_ID); if (!ar5212ChipTest(ah)) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: hardware self-test failed\n", __func__); ecode = HAL_ESELFTEST; goto bad; } /* * Set correct Baseband to analog shift * setting to access analog chips. */ OS_REG_WRITE(ah, AR_PHY(0), 0x00000007); /* Read Radio Chip Rev Extract */ AH_PRIVATE(ah)->ah_analog5GhzRev = ar5416GetRadioRev(ah); switch (AH_PRIVATE(ah)->ah_analog5GhzRev & AR_RADIO_SREV_MAJOR) { case AR_RAD2133_SREV_MAJOR: /* Sowl: 2G/3x3 */ case AR_RAD5133_SREV_MAJOR: /* Sowl: 2+5G/3x3 */ break; default: if (AH_PRIVATE(ah)->ah_analog5GhzRev == 0) { AH_PRIVATE(ah)->ah_analog5GhzRev = AR_RAD5133_SREV_MAJOR; break; } #ifdef AH_DEBUG HALDEBUG(ah, HAL_DEBUG_ANY, "%s: 5G Radio Chip Rev 0x%02X is not supported by " "this driver\n", __func__, AH_PRIVATE(ah)->ah_analog5GhzRev); ecode = HAL_ENOTSUPP; goto bad; #endif } rfStatus = ar9285RfAttach(ah, &ecode); if (!rfStatus) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: RF setup failed, status %u\n", __func__, ecode); goto bad; } HAL_INI_INIT(&ahp9285->ah_ini_rxgain, ar9280Modes_original_rxgain_v2, 6); if (AR_SREV_9285E_20(ah)) ath_hal_printf(ah, "[ath] AR9285E_20 detected; using XE TX gain tables\n"); /* setup txgain table */ switch (ath_hal_eepromGet(ah, AR_EEP_TXGAIN_TYPE, AH_NULL)) { case AR5416_EEP_TXGAIN_HIGH_POWER: if (AR_SREV_9285E_20(ah)) HAL_INI_INIT(&ahp9285->ah_ini_txgain, ar9285Modes_XE2_0_high_power, 6); else HAL_INI_INIT(&ahp9285->ah_ini_txgain, ar9285Modes_high_power_tx_gain_v2, 6); break; case AR5416_EEP_TXGAIN_ORIG: if (AR_SREV_9285E_20(ah)) HAL_INI_INIT(&ahp9285->ah_ini_txgain, ar9285Modes_XE2_0_normal_power, 6); else HAL_INI_INIT(&ahp9285->ah_ini_txgain, ar9285Modes_original_tx_gain_v2, 6); break; default: HALASSERT(AH_FALSE); goto bad; /* XXX ? try to continue */ } /* * Got everything we need now to setup the capabilities. */ if (!ar9285FillCapabilityInfo(ah)) { ecode = HAL_EEREAD; goto bad; } /* * Print out the EEPROM antenna configuration mapping. * Some devices have a hard-coded LNA configuration profile; * others enable diversity. */ ar9285_eeprom_print_diversity_settings(ah); /* Print out whether the EEPROM settings enable AR9285 diversity */ if (ar9285_check_div_comb(ah)) { ath_hal_printf(ah, "[ath] Enabling diversity for Kite\n"); } /* Disable 11n for the AR2427 */ if (devid == AR2427_DEVID_PCIE) AH_PRIVATE(ah)->ah_caps.halHTSupport = AH_FALSE; ecode = ath_hal_eepromGet(ah, AR_EEP_MACADDR, ahp->ah_macaddr); if (ecode != HAL_OK) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: error getting mac address from EEPROM\n", __func__); goto bad; } /* XXX How about the serial number ? */ /* Read Reg Domain */ AH_PRIVATE(ah)->ah_currentRD = ath_hal_eepromGet(ah, AR_EEP_REGDMN_0, AH_NULL); /* * For Kite and later chipsets, the following bits are not * programmed in EEPROM and so are set as enabled always. */ AH_PRIVATE(ah)->ah_currentRDext = AR9285_RDEXT_DEFAULT; /* * ah_miscMode is populated by ar5416FillCapabilityInfo() * starting from griffin. Set here to make sure that * AR_MISC_MODE_MIC_NEW_LOC_ENABLE is set before a GTK is * placed into hardware. */ if (ahp->ah_miscMode != 0) OS_REG_WRITE(ah, AR_MISC_MODE, OS_REG_READ(ah, AR_MISC_MODE) | ahp->ah_miscMode); ar9285AniSetup(ah); /* Anti Noise Immunity */ /* Setup noise floor min/max/nominal values */ AH5416(ah)->nf_2g.max = AR_PHY_CCA_MAX_GOOD_VAL_9285_2GHZ; AH5416(ah)->nf_2g.min = AR_PHY_CCA_MIN_GOOD_VAL_9285_2GHZ; AH5416(ah)->nf_2g.nominal = AR_PHY_CCA_NOM_VAL_9285_2GHZ; /* XXX no 5ghz values? */ ar5416InitNfHistBuff(AH5416(ah)->ah_cal.nfCalHist); HALDEBUG(ah, HAL_DEBUG_ATTACH, "%s: return\n", __func__); return ah; bad: if (ah != AH_NULL) ah->ah_detach(ah); if (status) *status = ecode; return AH_NULL; } static void ar9285ConfigPCIE(struct ath_hal *ah, HAL_BOOL restore, HAL_BOOL power_off) { uint32_t val; /* * This workaround needs some integration work with the HAL * config parameters and the if_ath_pci.c glue. * Specifically, read the value of the PCI register 0x70c * (4 byte PCI config space register) and store it in ath_hal_war70c. * Then if it's non-zero, the below WAR would override register * 0x570c upon suspend/resume. */ #if 0 if (AR_SREV_9285E_20(ah)) { val = AH_PRIVATE(ah)->ah_config.ath_hal_war70c; if (val) { val &= 0xffff00ff; val |= 0x6f00; OS_REG_WRITE(ah, 0x570c, val); } } #endif if (AH_PRIVATE(ah)->ah_ispcie && !restore) { ath_hal_ini_write(ah, &AH5416(ah)->ah_ini_pcieserdes, 1, 0); OS_DELAY(1000); } /* * Set PCIe workaround bits * * NOTE: * * In Merlin and Kite, bit 14 in WA register (disable L1) should only * be set when device enters D3 and be cleared when device comes back * to D0. */ if (power_off) { /* Power-off */ OS_REG_CLR_BIT(ah, AR_PCIE_PM_CTRL, AR_PCIE_PM_CTRL_ENA); val = OS_REG_READ(ah, AR_WA); /* * Disable bit 6 and 7 before entering D3 to prevent * system hang. */ val &= ~(AR_WA_BIT6 | AR_WA_BIT7); /* * See above: set AR_WA_D3_L1_DISABLE when entering D3 state. * * XXX The reference HAL does it this way - it only sets * AR_WA_D3_L1_DISABLE if it's set in AR9280_WA_DEFAULT, * which it (currently) isn't. So the following statement * is currently a NOP. */ if (AR9285_WA_DEFAULT & AR_WA_D3_L1_DISABLE) val |= AR_WA_D3_L1_DISABLE; if (AR_SREV_9285E_20(ah)) val |= AR_WA_BIT23; OS_REG_WRITE(ah, AR_WA, val); } else { /* Power-on */ val = AR9285_WA_DEFAULT; /* * See note above: make sure L1_DISABLE is not set. */ val &= (~AR_WA_D3_L1_DISABLE); /* Software workaroud for ASPM system hang. */ val |= (AR_WA_BIT6 | AR_WA_BIT7); if (AR_SREV_9285E_20(ah)) val |= AR_WA_BIT23; OS_REG_WRITE(ah, AR_WA, val); /* set bit 19 to allow forcing of pcie core into L1 state */ OS_REG_SET_BIT(ah, AR_PCIE_PM_CTRL, AR_PCIE_PM_CTRL_ENA); } }
/* * Control Adaptive Noise Immunity Parameters */ HAL_BOOL ar5212AniControl(struct ath_hal *ah, HAL_ANI_CMD cmd, int param) { #define N(a) (sizeof(a)/sizeof(a[0])) typedef int TABLE[]; struct ath_hal_5212 *ahp = AH5212(ah); struct ar5212AniState *aniState = ahp->ah_curani; switch (cmd) { case HAL_ANI_NOISE_IMMUNITY_LEVEL: { u_int level = param; if (level >= N(ahp->ah_totalSizeDesired)) { HALDEBUG(ah, "%s: level out of range (%u > %u)\n", __func__, level, N(ahp->ah_totalSizeDesired)); return AH_FALSE; } OS_REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, AR_PHY_DESIRED_SZ_TOT_DES, ahp->ah_totalSizeDesired[level]); OS_REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1, AR_PHY_AGC_CTL1_COARSE_LOW, ahp->ah_coarseLow[level]); OS_REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1, AR_PHY_AGC_CTL1_COARSE_HIGH, ahp->ah_coarseHigh[level]); OS_REG_RMW_FIELD(ah, AR_PHY_FIND_SIG, AR_PHY_FIND_SIG_FIRPWR, ahp->ah_firpwr[level]); if (level > aniState->noiseImmunityLevel) ahp->ah_stats.ast_ani_niup++; else if (level < aniState->noiseImmunityLevel) ahp->ah_stats.ast_ani_nidown++; aniState->noiseImmunityLevel = level; break; } case HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION: { const TABLE m1ThreshLow = { 127, 50 }; const TABLE m2ThreshLow = { 127, 40 }; const TABLE m1Thresh = { 127, 0x4d }; const TABLE m2Thresh = { 127, 0x40 }; const TABLE m2CountThr = { 31, 16 }; const TABLE m2CountThrLow = { 63, 48 }; u_int on = param ? 1 : 0; OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, AR_PHY_SFCORR_LOW_M1_THRESH_LOW, m1ThreshLow[on]); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, AR_PHY_SFCORR_LOW_M2_THRESH_LOW, m2ThreshLow[on]); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR, AR_PHY_SFCORR_M1_THRESH, m1Thresh[on]); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR, AR_PHY_SFCORR_M2_THRESH, m2Thresh[on]); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR, AR_PHY_SFCORR_M2COUNT_THR, m2CountThr[on]); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW, m2CountThrLow[on]); if (on) { OS_REG_SET_BIT(ah, AR_PHY_SFCORR_LOW, AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW); } else { OS_REG_CLR_BIT(ah, AR_PHY_SFCORR_LOW, AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW); } if (!on != aniState->ofdmWeakSigDetectOff) { if (on) ahp->ah_stats.ast_ani_ofdmon++; else ahp->ah_stats.ast_ani_ofdmoff++; aniState->ofdmWeakSigDetectOff = !on; } break; } case HAL_ANI_CCK_WEAK_SIGNAL_THR: { const TABLE weakSigThrCck = { 8, 6 }; u_int high = param ? 1 : 0; OS_REG_RMW_FIELD(ah, AR_PHY_CCK_DETECT, AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK, weakSigThrCck[high]); if (high != aniState->cckWeakSigThreshold) { if (high) ahp->ah_stats.ast_ani_cckhigh++; else ahp->ah_stats.ast_ani_ccklow++; aniState->cckWeakSigThreshold = high; } break; } case HAL_ANI_FIRSTEP_LEVEL: { const TABLE firstep = { 0, 4, 8 }; u_int level = param; if (level >= N(firstep)) { HALDEBUG(ah, "%s: level out of range (%u > %u)\n", __func__, level, N(firstep)); return AH_FALSE; } OS_REG_RMW_FIELD(ah, AR_PHY_FIND_SIG, AR_PHY_FIND_SIG_FIRSTEP, firstep[level]); if (level > aniState->firstepLevel) ahp->ah_stats.ast_ani_stepup++; else if (level < aniState->firstepLevel) ahp->ah_stats.ast_ani_stepdown++; aniState->firstepLevel = level; break; } case HAL_ANI_SPUR_IMMUNITY_LEVEL: { const TABLE cycpwrThr1 = { 2, 4, 6, 8, 10, 12, 14, 16 }; u_int level = param; if (level >= N(cycpwrThr1)) { HALDEBUG(ah, "%s: level out of range (%u > %u)\n", __func__, level, N(cycpwrThr1)); return AH_FALSE; } OS_REG_RMW_FIELD(ah, AR_PHY_TIMING5, AR_PHY_TIMING5_CYCPWR_THR1, cycpwrThr1[level]); if (level > aniState->spurImmunityLevel) ahp->ah_stats.ast_ani_spurup++; else if (level < aniState->spurImmunityLevel) ahp->ah_stats.ast_ani_spurdown++; aniState->spurImmunityLevel = level; break; } case HAL_ANI_PRESENT: break; #ifdef AH_PRIVATE_DIAG case HAL_ANI_MODE: if (param == 0) { ahp->ah_procPhyErr &= ~HAL_PROCESS_ANI; /* Turn off HW counters if we have them */ ar5212AniDetach(ah); ar5212SetRxFilter(ah, ar5212GetRxFilter(ah) &~ HAL_RX_FILTER_PHYERR); } else { /* normal/auto mode */ ahp->ah_procPhyErr |= HAL_PROCESS_ANI; if (ahp->ah_hasHwPhyCounters) { ar5212SetRxFilter(ah, ar5212GetRxFilter(ah) &~ HAL_RX_FILTER_PHYERR); } else { ar5212SetRxFilter(ah, ar5212GetRxFilter(ah) | HAL_RX_FILTER_PHYERR); } } break; case HAL_ANI_PHYERR_RESET: ahp->ah_stats.ast_ani_ofdmerrs = 0; ahp->ah_stats.ast_ani_cckerrs = 0; break; #endif /* AH_PRIVATE_DIAG */ default: HALDEBUG(ah, "%s: invalid cmd %u\n", __func__, cmd); return AH_FALSE; } return AH_TRUE; #undef N }
void ar5416StopPcuReceive(struct ath_hal *ah) { OS_REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RX_DIS); }
static void ar5416LoadNF(struct ath_hal *ah, const struct ieee80211_channel *chan) { static const uint32_t ar5416_cca_regs[] = { AR_PHY_CCA, AR_PHY_CH1_CCA, AR_PHY_CH2_CCA, AR_PHY_EXT_CCA, AR_PHY_CH1_EXT_CCA, AR_PHY_CH2_EXT_CCA }; struct ar5212NfCalHist *h; int i, j; int32_t val; uint8_t chainmask; /* * Force NF calibration for all chains. */ if (AR_SREV_KITE(ah)) { /* Kite has only one chain */ chainmask = 0x9; } else if (AR_SREV_MERLIN(ah)) { /* Merlin has only two chains */ chainmask = 0x1B; } else { chainmask = 0x3F; } /* * Write filtered NF values into maxCCApwr register parameter * so we can load below. */ h = AH5416(ah)->ah_cal.nfCalHist; for (i = 0; i < AR5416_NUM_NF_READINGS; i ++) if (chainmask & (1 << i)) { val = OS_REG_READ(ah, ar5416_cca_regs[i]); val &= 0xFFFFFE00; val |= (((uint32_t)(h[i].privNF) << 1) & 0x1ff); OS_REG_WRITE(ah, ar5416_cca_regs[i], val); } /* Load software filtered NF value into baseband internal minCCApwr variable. */ OS_REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_ENABLE_NF); OS_REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NO_UPDATE_NF); OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF); /* Wait for load to complete, should be fast, a few 10s of us. */ for (j = 0; j < 1000; j++) { if ((OS_REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) == 0) break; OS_DELAY(10); } /* * Restore maxCCAPower register parameter again so that we're not capped * by the median we just loaded. This will be initial (and max) value * of next noise floor calibration the baseband does. */ for (i = 0; i < AR5416_NUM_NF_READINGS; i ++) if (chainmask & (1 << i)) { val = OS_REG_READ(ah, ar5416_cca_regs[i]); val &= 0xFFFFFE00; val |= (((uint32_t)(-50) << 1) & 0x1ff); OS_REG_WRITE(ah, ar5416_cca_regs[i], val); } }
/* * Control Adaptive Noise Immunity Parameters */ bool ar9300_ani_control(struct ath_hal *ah, HAL_ANI_CMD cmd, int param) { struct ath_hal_9300 *ahp = AH9300(ah); struct ar9300_ani_state *ani_state = ahp->ah_curani; HAL_CHANNEL_INTERNAL *chan = AH_PRIVATE(ah)->ah_curchan; int32_t value, value2; u_int level = param; u_int is_on; if (chan == NULL && cmd != HAL_ANI_MODE) { HDPRINTF(ah, HAL_DBG_UNMASKABLE, "%s: ignoring cmd 0x%02x - no channel\n", __func__, cmd); return false; } switch (cmd & ahp->ah_ani_function) { case HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION: { int m1_thresh_low, m2_thresh_low; int m1_thresh, m2_thresh; int m2_count_thr, m2_count_thr_low; int m1_thresh_low_ext, m2_thresh_low_ext; int m1_thresh_ext, m2_thresh_ext; /* * is_on == 1 means ofdm weak signal detection is ON * (default, less noise imm) * is_on == 0 means ofdm weak signal detection is OFF * (more noise imm) */ is_on = param ? 1 : 0; /* * make register setting for default (weak sig detect ON) * come from INI file */ m1_thresh_low = is_on ? ani_state->ini_def.m1_thresh_low : m1_thresh_low_off; m2_thresh_low = is_on ? ani_state->ini_def.m2_thresh_low : m2_thresh_low_off; m1_thresh = is_on ? ani_state->ini_def.m1_thresh : m1_thresh_off; m2_thresh = is_on ? ani_state->ini_def.m2_thresh : m2_thresh_off; m2_count_thr = is_on ? ani_state->ini_def.m2_count_thr : m2_count_thr_off; m2_count_thr_low = is_on ? ani_state->ini_def.m2_count_thr_low : m2_count_thr_low_off; m1_thresh_low_ext = is_on ? ani_state->ini_def.m1_thresh_low_ext : m1_thresh_low_ext_off; m2_thresh_low_ext = is_on ? ani_state->ini_def.m2_thresh_low_ext : m2_thresh_low_ext_off; m1_thresh_ext = is_on ? ani_state->ini_def.m1_thresh_ext : m1_thresh_ext_off; m2_thresh_ext = is_on ? ani_state->ini_def.m2_thresh_ext : m2_thresh_ext_off; OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, AR_PHY_SFCORR_LOW_M1_THRESH_LOW, m1_thresh_low); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, AR_PHY_SFCORR_LOW_M2_THRESH_LOW, m2_thresh_low); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR, AR_PHY_SFCORR_M1_THRESH, m1_thresh); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR, AR_PHY_SFCORR_M2_THRESH, m2_thresh); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR, AR_PHY_SFCORR_M2COUNT_THR, m2_count_thr); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW, m2_count_thr_low); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, AR_PHY_SFCORR_EXT_M1_THRESH_LOW, m1_thresh_low_ext); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, AR_PHY_SFCORR_EXT_M2_THRESH_LOW, m2_thresh_low_ext); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, AR_PHY_SFCORR_EXT_M1_THRESH, m1_thresh_ext); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, AR_PHY_SFCORR_EXT_M2_THRESH, m2_thresh_ext); if (is_on) { OS_REG_SET_BIT(ah, AR_PHY_SFCORR_LOW, AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW); } else { OS_REG_CLR_BIT(ah, AR_PHY_SFCORR_LOW, AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW); } if (!is_on != ani_state->ofdm_weak_sig_detect_off) { HDPRINTF(ah, HAL_DBG_ANI, "%s: ** ch %d: ofdm weak signal: %s=>%s\n", __func__, chan->channel, !ani_state->ofdm_weak_sig_detect_off ? "on" : "off", is_on ? "on" : "off"); if (is_on) { ahp->ah_stats.ast_ani_ofdmon++; } else { ahp->ah_stats.ast_ani_ofdmoff++; } ani_state->ofdm_weak_sig_detect_off = !is_on; } break; } case HAL_ANI_FIRSTEP_LEVEL: if (level >= ARRAY_LENGTH(firstep_table)) { HDPRINTF(ah, HAL_DBG_UNMASKABLE, "%s: HAL_ANI_FIRSTEP_LEVEL level out of range (%u > %u)\n", __func__, level, (unsigned) ARRAY_LENGTH(firstep_table)); return false; } /* * make register setting relative to default * from INI file & cap value */ value = firstep_table[level] - firstep_table[HAL_ANI_DEF_FIRSTEP_LVL] + ani_state->ini_def.firstep; if (value < HAL_SIG_FIRSTEP_SETTING_MIN) { value = HAL_SIG_FIRSTEP_SETTING_MIN; } if (value > HAL_SIG_FIRSTEP_SETTING_MAX) { value = HAL_SIG_FIRSTEP_SETTING_MAX; } OS_REG_RMW_FIELD(ah, AR_PHY_FIND_SIG, AR_PHY_FIND_SIG_FIRSTEP, value); /* * we need to set first step low register too * make register setting relative to default from INI file & cap value */ value2 = firstep_table[level] - firstep_table[HAL_ANI_DEF_FIRSTEP_LVL] + ani_state->ini_def.firstep_low; if (value2 < HAL_SIG_FIRSTEP_SETTING_MIN) { value2 = HAL_SIG_FIRSTEP_SETTING_MIN; } if (value2 > HAL_SIG_FIRSTEP_SETTING_MAX) { value2 = HAL_SIG_FIRSTEP_SETTING_MAX; } OS_REG_RMW_FIELD(ah, AR_PHY_FIND_SIG_LOW, AR_PHY_FIND_SIG_LOW_FIRSTEP_LOW, value2); if (level != ani_state->firstep_level) { HDPRINTF(ah, HAL_DBG_ANI, "%s: ** ch %d: level %d=>%d[def:%d] firstep[level]=%d ini=%d\n", __func__, chan->channel, ani_state->firstep_level, level, HAL_ANI_DEF_FIRSTEP_LVL, value, ani_state->ini_def.firstep); HDPRINTF(ah, HAL_DBG_ANI, "%s: ** ch %d: level %d=>%d[def:%d] " "firstep_low[level]=%d ini=%d\n", __func__, chan->channel, ani_state->firstep_level, level, HAL_ANI_DEF_FIRSTEP_LVL, value2, ani_state->ini_def.firstep_low); if (level > ani_state->firstep_level) { ahp->ah_stats.ast_ani_stepup++; } else if (level < ani_state->firstep_level) { ahp->ah_stats.ast_ani_stepdown++; } ani_state->firstep_level = level; } break; case HAL_ANI_SPUR_IMMUNITY_LEVEL: if (level >= ARRAY_LENGTH(cycpwr_thr1_table)) { HDPRINTF(ah, HAL_DBG_UNMASKABLE, "%s: HAL_ANI_SPUR_IMMUNITY_LEVEL level " "out of range (%u > %u)\n", __func__, level, (unsigned) ARRAY_LENGTH(cycpwr_thr1_table)); return false; } /* * make register setting relative to default from INI file & cap value */ value = cycpwr_thr1_table[level] - cycpwr_thr1_table[HAL_ANI_DEF_SPUR_IMMUNE_LVL] + ani_state->ini_def.cycpwr_thr1; if (value < HAL_SIG_SPUR_IMM_SETTING_MIN) { value = HAL_SIG_SPUR_IMM_SETTING_MIN; } if (value > HAL_SIG_SPUR_IMM_SETTING_MAX) { value = HAL_SIG_SPUR_IMM_SETTING_MAX; } OS_REG_RMW_FIELD(ah, AR_PHY_TIMING5, AR_PHY_TIMING5_CYCPWR_THR1, value); /* * set AR_PHY_EXT_CCA for extension channel * make register setting relative to default from INI file & cap value */ value2 = cycpwr_thr1_table[level] - cycpwr_thr1_table[HAL_ANI_DEF_SPUR_IMMUNE_LVL] + ani_state->ini_def.cycpwr_thr1_ext; if (value2 < HAL_SIG_SPUR_IMM_SETTING_MIN) { value2 = HAL_SIG_SPUR_IMM_SETTING_MIN; } if (value2 > HAL_SIG_SPUR_IMM_SETTING_MAX) { value2 = HAL_SIG_SPUR_IMM_SETTING_MAX; } OS_REG_RMW_FIELD(ah, AR_PHY_EXT_CCA, AR_PHY_EXT_CYCPWR_THR1, value2); if (level != ani_state->spur_immunity_level) { HDPRINTF(ah, HAL_DBG_ANI, "%s: ** ch %d: level %d=>%d[def:%d] " "cycpwr_thr1[level]=%d ini=%d\n", __func__, chan->channel, ani_state->spur_immunity_level, level, HAL_ANI_DEF_SPUR_IMMUNE_LVL, value, ani_state->ini_def.cycpwr_thr1); HDPRINTF(ah, HAL_DBG_ANI, "%s: ** ch %d: level %d=>%d[def:%d] " "cycpwr_thr1_ext[level]=%d ini=%d\n", __func__, chan->channel, ani_state->spur_immunity_level, level, HAL_ANI_DEF_SPUR_IMMUNE_LVL, value2, ani_state->ini_def.cycpwr_thr1_ext); if (level > ani_state->spur_immunity_level) { ahp->ah_stats.ast_ani_spurup++; } else if (level < ani_state->spur_immunity_level) { ahp->ah_stats.ast_ani_spurdown++; } ani_state->spur_immunity_level = level; } break; case HAL_ANI_MRC_CCK: /* * is_on == 1 means MRC CCK ON (default, less noise imm) * is_on == 0 means MRC CCK is OFF (more noise imm) */ is_on = param ? 1 : 0; if (!AR_SREV_POSEIDON(ah)) { OS_REG_RMW_FIELD(ah, AR_PHY_MRC_CCK_CTRL, AR_PHY_MRC_CCK_ENABLE, is_on); OS_REG_RMW_FIELD(ah, AR_PHY_MRC_CCK_CTRL, AR_PHY_MRC_CCK_MUX_REG, is_on); } if (!is_on != ani_state->mrc_cck_off) { HDPRINTF(ah, HAL_DBG_ANI, "%s: ** ch %d: MRC CCK: %s=>%s\n", __func__, chan->channel, !ani_state->mrc_cck_off ? "on" : "off", is_on ? "on" : "off"); if (is_on) { ahp->ah_stats.ast_ani_ccklow++; } else { ahp->ah_stats.ast_ani_cckhigh++; } ani_state->mrc_cck_off = !is_on; } break; case HAL_ANI_PRESENT: break; #ifdef AH_PRIVATE_DIAG case HAL_ANI_MODE: if (param == 0) { ahp->ah_proc_phy_err &= ~HAL_PROCESS_ANI; /* Turn off HW counters if we have them */ ar9300_ani_detach(ah); if (AH_PRIVATE(ah)->ah_curchan == NULL) { return true; } /* if we're turning off ANI, reset regs back to INI settings */ if (AH_PRIVATE(ah)->ah_config.ath_hal_enable_ani) { HAL_ANI_CMD savefunc = ahp->ah_ani_function; /* temporarly allow all functions so we can reset */ ahp->ah_ani_function = HAL_ANI_ALL; HDPRINTF(ah, HAL_DBG_ANI, "%s: disable all ANI functions\n", __func__); ar9300_ani_set_odfm_noise_immunity_level( ah, HAL_ANI_OFDM_DEF_LEVEL); ar9300_ani_set_cck_noise_immunity_level( ah, HAL_ANI_CCK_DEF_LEVEL); ahp->ah_ani_function = savefunc; } } else { /* normal/auto mode */ HDPRINTF(ah, HAL_DBG_ANI, "%s: enabled\n", __func__); ahp->ah_proc_phy_err |= HAL_PROCESS_ANI; if (AH_PRIVATE(ah)->ah_curchan == NULL) { return true; } ar9300_enable_mib_counters(ah); ar9300_ani_reset(ah, false); ani_state = ahp->ah_curani; } HDPRINTF(ah, HAL_DBG_ANI, "5 ANC: ahp->ah_proc_phy_err %x \n", ahp->ah_proc_phy_err); break; case HAL_ANI_PHYERR_RESET: ahp->ah_stats.ast_ani_ofdmerrs = 0; ahp->ah_stats.ast_ani_cckerrs = 0; break; #endif /* AH_PRIVATE_DIAG */ default: #if HAL_ANI_DEBUG HDPRINTF(ah, HAL_DBG_ANI, "%s: invalid cmd 0x%02x (allowed=0x%02x)\n", __func__, cmd, ahp->ah_ani_function); #endif return false; } #if HAL_ANI_DEBUG HDPRINTF(ah, HAL_DBG_ANI, "%s: ANI parameters: SI=%d, ofdm_ws=%s FS=%d MRCcck=%s listen_time=%d " "CC=%d listen=%d ofdm_errs=%d cck_errs=%d\n", __func__, ani_state->spur_immunity_level, !ani_state->ofdm_weak_sig_detect_off ? "on" : "off", ani_state->firstep_level, !ani_state->mrc_cck_off ? "on" : "off", ani_state->listen_time, ani_state->cycle_count, ani_state->listen_time, ani_state->ofdm_phy_err_count, ani_state->cck_phy_err_count); #endif #ifndef REMOVE_PKT_LOG /* do pktlog */ { struct log_ani log_data; /* Populate the ani log record */ log_data.phy_stats_disable = DO_ANI(ah); log_data.noise_immun_lvl = ani_state->ofdm_noise_immunity_level; log_data.spur_immun_lvl = ani_state->spur_immunity_level; log_data.ofdm_weak_det = ani_state->ofdm_weak_sig_detect_off; log_data.cck_weak_thr = ani_state->cck_noise_immunity_level; log_data.fir_lvl = ani_state->firstep_level; log_data.listen_time = ani_state->listen_time; log_data.cycle_count = ani_state->cycle_count; /* express ofdm_phy_err_count as errors/second */ log_data.ofdm_phy_err_count = ani_state->listen_time ? ani_state->ofdm_phy_err_count * 1000 / ani_state->listen_time : 0; /* express cck_phy_err_count as errors/second */ log_data.cck_phy_err_count = ani_state->listen_time ? ani_state->cck_phy_err_count * 1000 / ani_state->listen_time : 0; log_data.rssi = ani_state->rssi; /* clear interrupt context flag */ ath_hal_log_ani(AH_PRIVATE(ah)->ah_sc, &log_data, 0); } #endif return true; }
/* * Initialize Calibration infrastructure. */ HAL_BOOL ar5416InitCal(struct ath_hal *ah, const struct ieee80211_channel *chan) { struct ar5416PerCal *cal = &AH5416(ah)->ah_cal; HAL_CHANNEL_INTERNAL *ichan; ichan = ath_hal_checkchannel(ah, chan); HALASSERT(ichan != AH_NULL); if (AR_SREV_MERLIN_10_OR_LATER(ah)) { /* Enable Rx Filter Cal */ OS_REG_CLR_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC); OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL); /* Clear the carrier leak cal bit */ OS_REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE); /* kick off the cal */ OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL); /* Poll for offset calibration complete */ if (!ath_hal_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 0)) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: offset calibration failed to complete in 1ms; " "noisy environment?\n", __func__); return AH_FALSE; } /* Set the cl cal bit and rerun the cal a 2nd time */ /* Enable Rx Filter Cal */ OS_REG_CLR_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC); OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL); OS_REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE); } /* Calibrate the AGC */ OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL); /* Poll for offset calibration complete */ if (!ath_hal_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 0)) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: offset calibration did not complete in 1ms; " "noisy environment?\n", __func__); return AH_FALSE; } /* * Do NF calibration after DC offset and other CALs. * Per system engineers, noise floor value can sometimes be 20 dB * higher than normal value if DC offset and noise floor cal are * triggered at the same time. */ OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF); /* Initialize list pointers */ cal->cal_list = cal->cal_last = cal->cal_curr = AH_NULL; /* * Enable IQ, ADC Gain, ADC DC Offset Cals */ if (AR_SREV_SOWL_10_OR_LATER(ah)) { /* Setup all non-periodic, init time only calibrations */ /* XXX: Init DC Offset not working yet */ #if 0 if (ar5416IsCalSupp(ah, chan, ADC_DC_INIT_CAL)) { INIT_CAL(&cal->adcDcCalInitData); INSERT_CAL(cal, &cal->adcDcCalInitData); } /* Initialize current pointer to first element in list */ cal->cal_curr = cal->cal_list; if (cal->ah_cal_curr != AH_NULL && !ar5416RunInitCals(ah, 0)) return AH_FALSE; #endif } /* If Cals are supported, add them to list via INIT/INSERT_CAL */ if (ar5416IsCalSupp(ah, chan, ADC_GAIN_CAL)) { INIT_CAL(&cal->adcGainCalData); INSERT_CAL(cal, &cal->adcGainCalData); HALDEBUG(ah, HAL_DEBUG_PERCAL, "%s: enable ADC Gain Calibration.\n", __func__); } if (ar5416IsCalSupp(ah, chan, ADC_DC_CAL)) { INIT_CAL(&cal->adcDcCalData); INSERT_CAL(cal, &cal->adcDcCalData); HALDEBUG(ah, HAL_DEBUG_PERCAL, "%s: enable ADC DC Calibration.\n", __func__); } if (ar5416IsCalSupp(ah, chan, IQ_MISMATCH_CAL)) { INIT_CAL(&cal->iqCalData); INSERT_CAL(cal, &cal->iqCalData); HALDEBUG(ah, HAL_DEBUG_PERCAL, "%s: enable IQ Calibration.\n", __func__); } /* Initialize current pointer to first element in list */ cal->cal_curr = cal->cal_list; /* Kick off measurements for the first cal */ if (cal->cal_curr != AH_NULL) ar5416ResetMeasurement(ah, cal->cal_curr); /* Mark all calibrations on this channel as being invalid */ ichan->calValid = 0; return AH_TRUE; }
static void ar5416LoadNF(struct ath_hal *ah, const struct ieee80211_channel *chan) { static const uint32_t ar5416_cca_regs[] = { AR_PHY_CCA, AR_PHY_CH1_CCA, AR_PHY_CH2_CCA, AR_PHY_EXT_CCA, AR_PHY_CH1_EXT_CCA, AR_PHY_CH2_EXT_CCA }; struct ar5212NfCalHist *h; int i; int32_t val; uint8_t chainmask; int16_t default_nf = ar5416GetDefaultNF(ah, chan); /* * Force NF calibration for all chains. */ if (AR_SREV_KITE(ah)) { /* Kite has only one chain */ chainmask = 0x9; } else if (AR_SREV_MERLIN(ah) || AR_SREV_KIWI(ah)) { /* Merlin/Kiwi has only two chains */ chainmask = 0x1B; } else { chainmask = 0x3F; } /* * Write filtered NF values into maxCCApwr register parameter * so we can load below. */ h = AH5416(ah)->ah_cal.nfCalHist; HALDEBUG(ah, HAL_DEBUG_NFCAL, "CCA: "); for (i = 0; i < AR5416_NUM_NF_READINGS; i ++) { /* Don't write to EXT radio CCA registers unless in HT/40 mode */ /* XXX this check should really be cleaner! */ if (i > 2 && !IEEE80211_IS_CHAN_HT40(chan)) continue; if (chainmask & (1 << i)) { int16_t nf_val; if (h) nf_val = h[i].privNF; else nf_val = default_nf; val = OS_REG_READ(ah, ar5416_cca_regs[i]); val &= 0xFFFFFE00; val |= (((uint32_t) nf_val << 1) & 0x1ff); HALDEBUG(ah, HAL_DEBUG_NFCAL, "[%d: %d]", i, nf_val); OS_REG_WRITE(ah, ar5416_cca_regs[i], val); } } HALDEBUG(ah, HAL_DEBUG_NFCAL, "\n"); /* Load software filtered NF value into baseband internal minCCApwr variable. */ OS_REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_ENABLE_NF); OS_REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NO_UPDATE_NF); OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF); /* Wait for load to complete, should be fast, a few 10s of us. */ if (! ar5212WaitNFCalComplete(ah, 1000)) { /* * We timed out waiting for the noisefloor to load, probably due to an * in-progress rx. Simply return here and allow the load plenty of time * to complete before the next calibration interval. We need to avoid * trying to load -50 (which happens below) while the previous load is * still in progress as this can cause rx deafness. Instead by returning * here, the baseband nf cal will just be capped by our present * noisefloor until the next calibration timer. */ HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "Timeout while waiting for " "nf to load: AR_PHY_AGC_CONTROL=0x%x\n", OS_REG_READ(ah, AR_PHY_AGC_CONTROL)); return; } /* * Restore maxCCAPower register parameter again so that we're not capped * by the median we just loaded. This will be initial (and max) value * of next noise floor calibration the baseband does. */ for (i = 0; i < AR5416_NUM_NF_READINGS; i ++) /* Don't write to EXT radio CCA registers unless in HT/40 mode */ /* XXX this check should really be cleaner! */ if (i > 2 && !IEEE80211_IS_CHAN_HT40(chan)) continue; if (chainmask & (1 << i)) { val = OS_REG_READ(ah, ar5416_cca_regs[i]); val &= 0xFFFFFE00; val |= (((uint32_t)(-50) << 1) & 0x1ff); OS_REG_WRITE(ah, ar5416_cca_regs[i], val); } }
HAL_BOOL ar5416InitCal(struct ath_hal *ah, const struct ieee80211_channel *chan) { struct ar5416PerCal *cal = &AH5416(ah)->ah_cal; HAL_CHANNEL_INTERNAL *ichan; ichan = ath_hal_checkchannel(ah, chan); HALASSERT(ichan != AH_NULL); /* Do initial chipset-specific calibration */ if (! AH5416(ah)->ah_cal_initcal(ah, chan)) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: initial chipset calibration did " "not complete in time; noisy environment?\n", __func__); return AH_FALSE; } /* If there's PA Cal, do it */ if (AH5416(ah)->ah_cal_pacal) AH5416(ah)->ah_cal_pacal(ah, AH_TRUE); /* * Do NF calibration after DC offset and other CALs. * Per system engineers, noise floor value can sometimes be 20 dB * higher than normal value if DC offset and noise floor cal are * triggered at the same time. */ OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF); /* * This may take a while to run; make sure subsequent * calibration routines check that this has completed * before reading the value and triggering a subsequent * calibration. */ /* Initialize list pointers */ cal->cal_list = cal->cal_last = cal->cal_curr = AH_NULL; /* * Enable IQ, ADC Gain, ADC DC Offset Cals */ if (AR_SREV_HOWL(ah) || AR_SREV_SOWL_10_OR_LATER(ah)) { /* Setup all non-periodic, init time only calibrations */ /* XXX: Init DC Offset not working yet */ #if 0 if (ar5416IsCalSupp(ah, chan, ADC_DC_INIT_CAL)) { INIT_CAL(&cal->adcDcCalInitData); INSERT_CAL(cal, &cal->adcDcCalInitData); } /* Initialize current pointer to first element in list */ cal->cal_curr = cal->cal_list; if (cal->ah_cal_curr != AH_NULL && !ar5416RunInitCals(ah, 0)) return AH_FALSE; #endif } /* If Cals are supported, add them to list via INIT/INSERT_CAL */ if (ar5416IsCalSupp(ah, chan, ADC_GAIN_CAL)) { INIT_CAL(&cal->adcGainCalData); INSERT_CAL(cal, &cal->adcGainCalData); HALDEBUG(ah, HAL_DEBUG_PERCAL, "%s: enable ADC Gain Calibration.\n", __func__); } if (ar5416IsCalSupp(ah, chan, ADC_DC_CAL)) { INIT_CAL(&cal->adcDcCalData); INSERT_CAL(cal, &cal->adcDcCalData); HALDEBUG(ah, HAL_DEBUG_PERCAL, "%s: enable ADC DC Calibration.\n", __func__); } if (ar5416IsCalSupp(ah, chan, IQ_MISMATCH_CAL)) { INIT_CAL(&cal->iqCalData); INSERT_CAL(cal, &cal->iqCalData); HALDEBUG(ah, HAL_DEBUG_PERCAL, "%s: enable IQ Calibration.\n", __func__); } /* Initialize current pointer to first element in list */ cal->cal_curr = cal->cal_list; /* Kick off measurements for the first cal */ if (cal->cal_curr != AH_NULL) ar5416ResetMeasurement(ah, cal->cal_curr); /* Mark all calibrations on this channel as being invalid */ ichan->calValid = 0; return AH_TRUE; #undef MAX_CAL_CHECK }
/* * Control Adaptive Noise Immunity Parameters */ HAL_BOOL ar5212AniControl(struct ath_hal *ah, HAL_ANI_CMD cmd, int param) { typedef int TABLE[]; struct ath_hal_5212 *ahp = AH5212(ah); struct ar5212AniState *aniState = ahp->ah_curani; const struct ar5212AniParams *params = aniState->params; OS_MARK(ah, AH_MARK_ANI_CONTROL, cmd); switch (cmd) { case HAL_ANI_NOISE_IMMUNITY_LEVEL: { u_int level = param; if (level > params->maxNoiseImmunityLevel) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: level out of range (%u > %u)\n", __func__, level, params->maxNoiseImmunityLevel); return AH_FALSE; } OS_REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, AR_PHY_DESIRED_SZ_TOT_DES, params->totalSizeDesired[level]); OS_REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1, AR_PHY_AGC_CTL1_COARSE_LOW, params->coarseLow[level]); OS_REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1, AR_PHY_AGC_CTL1_COARSE_HIGH, params->coarseHigh[level]); OS_REG_RMW_FIELD(ah, AR_PHY_FIND_SIG, AR_PHY_FIND_SIG_FIRPWR, params->firpwr[level]); if (level > aniState->noiseImmunityLevel) ahp->ah_stats.ast_ani_niup++; else if (level < aniState->noiseImmunityLevel) ahp->ah_stats.ast_ani_nidown++; aniState->noiseImmunityLevel = level; break; } case HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION: { static const TABLE m1ThreshLow = { 127, 50 }; static const TABLE m2ThreshLow = { 127, 40 }; static const TABLE m1Thresh = { 127, 0x4d }; static const TABLE m2Thresh = { 127, 0x40 }; static const TABLE m2CountThr = { 31, 16 }; static const TABLE m2CountThrLow = { 63, 48 }; u_int on = param ? 1 : 0; OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, AR_PHY_SFCORR_LOW_M1_THRESH_LOW, m1ThreshLow[on]); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, AR_PHY_SFCORR_LOW_M2_THRESH_LOW, m2ThreshLow[on]); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR, AR_PHY_SFCORR_M1_THRESH, m1Thresh[on]); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR, AR_PHY_SFCORR_M2_THRESH, m2Thresh[on]); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR, AR_PHY_SFCORR_M2COUNT_THR, m2CountThr[on]); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW, m2CountThrLow[on]); if (on) { OS_REG_SET_BIT(ah, AR_PHY_SFCORR_LOW, AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW); } else { OS_REG_CLR_BIT(ah, AR_PHY_SFCORR_LOW, AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW); } if (on) ahp->ah_stats.ast_ani_ofdmon++; else ahp->ah_stats.ast_ani_ofdmoff++; aniState->ofdmWeakSigDetectOff = !on; break; } case HAL_ANI_CCK_WEAK_SIGNAL_THR: { static const TABLE weakSigThrCck = { 8, 6 }; u_int high = param ? 1 : 0; OS_REG_RMW_FIELD(ah, AR_PHY_CCK_DETECT, AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK, weakSigThrCck[high]); if (high) ahp->ah_stats.ast_ani_cckhigh++; else ahp->ah_stats.ast_ani_ccklow++; aniState->cckWeakSigThreshold = high; break; } case HAL_ANI_FIRSTEP_LEVEL: { u_int level = param; if (level > params->maxFirstepLevel) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: level out of range (%u > %u)\n", __func__, level, params->maxFirstepLevel); return AH_FALSE; } OS_REG_RMW_FIELD(ah, AR_PHY_FIND_SIG, AR_PHY_FIND_SIG_FIRSTEP, params->firstep[level]); if (level > aniState->firstepLevel) ahp->ah_stats.ast_ani_stepup++; else if (level < aniState->firstepLevel) ahp->ah_stats.ast_ani_stepdown++; aniState->firstepLevel = level; break; } case HAL_ANI_SPUR_IMMUNITY_LEVEL: { u_int level = param; if (level > params->maxSpurImmunityLevel) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: level out of range (%u > %u)\n", __func__, level, params->maxSpurImmunityLevel); return AH_FALSE; } OS_REG_RMW_FIELD(ah, AR_PHY_TIMING5, AR_PHY_TIMING5_CYCPWR_THR1, params->cycPwrThr1[level]); if (level > aniState->spurImmunityLevel) ahp->ah_stats.ast_ani_spurup++; else if (level < aniState->spurImmunityLevel) ahp->ah_stats.ast_ani_spurdown++; aniState->spurImmunityLevel = level; break; } case HAL_ANI_PRESENT: break; case HAL_ANI_MODE: if (param == 0) { ahp->ah_procPhyErr &= ~HAL_ANI_ENA; /* Turn off HW counters if we have them */ ar5212AniDetach(ah); ar5212SetRxFilter(ah, ar5212GetRxFilter(ah) &~ HAL_RX_FILTER_PHYERR); } else { /* normal/auto mode */ /* don't mess with state if already enabled */ if (ahp->ah_procPhyErr & HAL_ANI_ENA) break; if (ahp->ah_hasHwPhyCounters) { ar5212SetRxFilter(ah, ar5212GetRxFilter(ah) &~ HAL_RX_FILTER_PHYERR); /* Enable MIB Counters */ enableAniMIBCounters(ah, ahp->ah_curani != AH_NULL ? ahp->ah_curani->params: &ahp->ah_aniParams24 /*XXX*/); } else { ar5212SetRxFilter(ah, ar5212GetRxFilter(ah) | HAL_RX_FILTER_PHYERR); } ahp->ah_procPhyErr |= HAL_ANI_ENA; } break; #ifdef AH_PRIVATE_DIAG case HAL_ANI_PHYERR_RESET: ahp->ah_stats.ast_ani_ofdmerrs = 0; ahp->ah_stats.ast_ani_cckerrs = 0; break; #endif /* AH_PRIVATE_DIAG */ default: HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid cmd %u\n", __func__, cmd); return AH_FALSE; } return AH_TRUE; }
/* * Enable radar detection and set the radar parameters per the * values in pe */ void ar5416EnableDfs(struct ath_hal *ah, HAL_PHYERR_PARAM *pe) { uint32_t val; val = OS_REG_READ(ah, AR_PHY_RADAR_0); if (pe->pe_firpwr != HAL_PHYERR_PARAM_NOVAL) { val &= ~AR_PHY_RADAR_0_FIRPWR; val |= SM(pe->pe_firpwr, AR_PHY_RADAR_0_FIRPWR); } if (pe->pe_rrssi != HAL_PHYERR_PARAM_NOVAL) { val &= ~AR_PHY_RADAR_0_RRSSI; val |= SM(pe->pe_rrssi, AR_PHY_RADAR_0_RRSSI); } if (pe->pe_height != HAL_PHYERR_PARAM_NOVAL) { val &= ~AR_PHY_RADAR_0_HEIGHT; val |= SM(pe->pe_height, AR_PHY_RADAR_0_HEIGHT); } if (pe->pe_prssi != HAL_PHYERR_PARAM_NOVAL) { val &= ~AR_PHY_RADAR_0_PRSSI; val |= SM(pe->pe_prssi, AR_PHY_RADAR_0_PRSSI); } if (pe->pe_inband != HAL_PHYERR_PARAM_NOVAL) { val &= ~AR_PHY_RADAR_0_INBAND; val |= SM(pe->pe_inband, AR_PHY_RADAR_0_INBAND); } /*Enable FFT data*/ val |= AR_PHY_RADAR_0_FFT_ENA; OS_REG_WRITE(ah, AR_PHY_RADAR_0, val); /* Implicitly enable */ if (pe->pe_enabled == 1) OS_REG_SET_BIT(ah, AR_PHY_RADAR_0, AR_PHY_RADAR_0_ENA); else if (pe->pe_enabled == 0) OS_REG_CLR_BIT(ah, AR_PHY_RADAR_0, AR_PHY_RADAR_0_ENA); if (pe->pe_usefir128 == 1) OS_REG_SET_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_USE_FIR128); else if (pe->pe_usefir128 == 0) OS_REG_CLR_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_USE_FIR128); if (pe->pe_enmaxrssi == 1) OS_REG_SET_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_MAX_RRSSI); else if (pe->pe_enmaxrssi == 0) OS_REG_CLR_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_MAX_RRSSI); if (pe->pe_blockradar == 1) OS_REG_SET_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_BLOCK_CHECK); else if (pe->pe_blockradar == 0) OS_REG_CLR_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_BLOCK_CHECK); if (pe->pe_relstep != HAL_PHYERR_PARAM_NOVAL) { val = OS_REG_READ(ah, AR_PHY_RADAR_1); val &= ~AR_PHY_RADAR_1_RELSTEP_THRESH; val |= SM(pe->pe_relstep, AR_PHY_RADAR_1_RELSTEP_THRESH); OS_REG_WRITE(ah, AR_PHY_RADAR_1, val); } if (pe->pe_relpwr != HAL_PHYERR_PARAM_NOVAL) { val = OS_REG_READ(ah, AR_PHY_RADAR_1); val &= ~AR_PHY_RADAR_1_RELPWR_THRESH; val |= SM(pe->pe_relpwr, AR_PHY_RADAR_1_RELPWR_THRESH); OS_REG_WRITE(ah, AR_PHY_RADAR_1, val); } if (pe->pe_en_relstep_check == 1) OS_REG_SET_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_RELSTEP_CHECK); else if (pe->pe_en_relstep_check == 0) OS_REG_CLR_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_RELSTEP_CHECK); if (pe->pe_enrelpwr == 1) OS_REG_SET_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_RELPWR_ENA); else if (pe->pe_enrelpwr == 0) OS_REG_CLR_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_RELPWR_ENA); if (pe->pe_maxlen != HAL_PHYERR_PARAM_NOVAL) { val = OS_REG_READ(ah, AR_PHY_RADAR_1); val &= ~AR_PHY_RADAR_1_MAXLEN; val |= SM(pe->pe_maxlen, AR_PHY_RADAR_1_MAXLEN); OS_REG_WRITE(ah, AR_PHY_RADAR_1, val); } /* * Enable HT/40 if the upper layer asks; * it should check the channel is HT/40 and HAL_CAP_EXT_CHAN_DFS * is available. */ if (pe->pe_extchannel == 1) OS_REG_SET_BIT(ah, AR_PHY_RADAR_EXT, AR_PHY_RADAR_EXT_ENA); else if (pe->pe_extchannel == 0) OS_REG_CLR_BIT(ah, AR_PHY_RADAR_EXT, AR_PHY_RADAR_EXT_ENA); }