/* * ADC GAIN/DC offset calibration is for calibrating two ADCs that * are acting as one by interleaving incoming symbols. This isn't * relevant for 2.4GHz 20MHz wide modes because, as far as I can tell, * the secondary ADC is never enabled. It is enabled however for * 5GHz modes. * * It hasn't been confirmed whether doing this calibration is needed * at all in the above modes and/or whether it's actually harmful. * So for now, let's leave it enabled and just remember to get * confirmation that it needs to be clarified. * * See US Patent No: US 7,541,952 B1: * " Method and Apparatus for Offset and Gain Compensation for * Analog-to-Digital Converters." */ static OS_INLINE HAL_BOOL ar5416IsCalSupp(struct ath_hal *ah, const struct ieee80211_channel *chan, HAL_CAL_TYPE calType) { struct ar5416PerCal *cal = &AH5416(ah)->ah_cal; switch (calType & cal->suppCals) { case IQ_MISMATCH_CAL: /* Run IQ Mismatch for non-CCK only */ return !IEEE80211_IS_CHAN_B(chan); case ADC_GAIN_CAL: case ADC_DC_CAL: /* * Run ADC Gain Cal for either 5ghz any or 2ghz HT40. * * Don't run ADC calibrations for 5ghz fast clock mode * in HT20 - only one ADC is used. */ if (IEEE80211_IS_CHAN_HT20(chan) && (IS_5GHZ_FAST_CLOCK_EN(ah, chan))) return AH_FALSE; if (IEEE80211_IS_CHAN_5GHZ(chan)) return AH_TRUE; if (IEEE80211_IS_CHAN_HT40(chan)) return AH_TRUE; return AH_FALSE; } return AH_FALSE; }
static void ath_rx_tap(struct ifnet *ifp, struct mbuf *m, const struct ath_rx_status *rs, u_int64_t tsf, int16_t nf) { #define CHAN_HT20 htole32(IEEE80211_CHAN_HT20) #define CHAN_HT40U htole32(IEEE80211_CHAN_HT40U) #define CHAN_HT40D htole32(IEEE80211_CHAN_HT40D) #define CHAN_HT (CHAN_HT20|CHAN_HT40U|CHAN_HT40D) struct ath_softc *sc = ifp->if_softc; const HAL_RATE_TABLE *rt; uint8_t rix; rt = sc->sc_currates; KASSERT(rt != NULL, ("no rate table, mode %u", sc->sc_curmode)); rix = rt->rateCodeToIndex[rs->rs_rate]; sc->sc_rx_th.wr_rate = sc->sc_hwmap[rix].ieeerate; sc->sc_rx_th.wr_flags = sc->sc_hwmap[rix].rxflags; #ifdef AH_SUPPORT_AR5416 sc->sc_rx_th.wr_chan_flags &= ~CHAN_HT; if (rs->rs_status & HAL_RXERR_PHY) { /* * PHY error - make sure the channel flags * reflect the actual channel configuration, * not the received frame. */ if (IEEE80211_IS_CHAN_HT40U(sc->sc_curchan)) sc->sc_rx_th.wr_chan_flags |= CHAN_HT40U; else if (IEEE80211_IS_CHAN_HT40D(sc->sc_curchan)) sc->sc_rx_th.wr_chan_flags |= CHAN_HT40D; else if (IEEE80211_IS_CHAN_HT20(sc->sc_curchan)) sc->sc_rx_th.wr_chan_flags |= CHAN_HT20; } else if (sc->sc_rx_th.wr_rate & IEEE80211_RATE_MCS) { /* HT rate */ struct ieee80211com *ic = ifp->if_l2com; if ((rs->rs_flags & HAL_RX_2040) == 0) sc->sc_rx_th.wr_chan_flags |= CHAN_HT20; else if (IEEE80211_IS_CHAN_HT40U(ic->ic_curchan)) sc->sc_rx_th.wr_chan_flags |= CHAN_HT40U; else sc->sc_rx_th.wr_chan_flags |= CHAN_HT40D; if ((rs->rs_flags & HAL_RX_GI) == 0) sc->sc_rx_th.wr_flags |= IEEE80211_RADIOTAP_F_SHORTGI; } #endif sc->sc_rx_th.wr_tsf = htole64(ath_extend_tsf(sc, rs->rs_tstamp, tsf)); if (rs->rs_status & HAL_RXERR_CRC) sc->sc_rx_th.wr_flags |= IEEE80211_RADIOTAP_F_BADFCS; /* XXX propagate other error flags from descriptor */ sc->sc_rx_th.wr_antnoise = nf; sc->sc_rx_th.wr_antsignal = nf + rs->rs_rssi; sc->sc_rx_th.wr_antenna = rs->rs_antenna; #undef CHAN_HT #undef CHAN_HT20 #undef CHAN_HT40U #undef CHAN_HT40D }
/* * Determine if calibration is supported by device and channel flags */ static OS_INLINE HAL_BOOL ar5416IsCalSupp(struct ath_hal *ah, const struct ieee80211_channel *chan, HAL_CAL_TYPE calType) { struct ar5416PerCal *cal = &AH5416(ah)->ah_cal; switch (calType & cal->suppCals) { case IQ_MISMATCH_CAL: /* Run IQ Mismatch for non-CCK only */ return !IEEE80211_IS_CHAN_B(chan); case ADC_GAIN_CAL: case ADC_DC_CAL: /* Run ADC Gain Cal for non-CCK & non 2GHz-HT20 only */ return !IEEE80211_IS_CHAN_B(chan) && !(IEEE80211_IS_CHAN_2GHZ(chan) && IEEE80211_IS_CHAN_HT20(chan)); } return AH_FALSE; }
/* Carrier leakage Calibration fix */ static HAL_BOOL ar9285_hw_cl_cal(struct ath_hal *ah, const struct ieee80211_channel *chan) { OS_REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE); if (IEEE80211_IS_CHAN_HT20(chan)) { OS_REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_PARALLEL_CAL_ENABLE); OS_REG_SET_BIT(ah, AR_PHY_TURBO, AR_PHY_FC_DYN2040_EN); OS_REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL); OS_REG_CLR_BIT(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_CAL_ENABLE); OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL); if (!ath_hal_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 0)) { HALDEBUG(ah, HAL_DEBUG_PERCAL, "offset calibration failed to complete in 1ms; noisy environment?\n"); return AH_FALSE; } OS_REG_CLR_BIT(ah, AR_PHY_TURBO, AR_PHY_FC_DYN2040_EN); OS_REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_PARALLEL_CAL_ENABLE); OS_REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE); } 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_TPCRG1, AR_PHY_TPCRG1_PD_CAL_ENABLE); OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL); if (!ath_hal_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 0)) { HALDEBUG(ah, HAL_DEBUG_PERCAL, "offset calibration failed to complete in 1ms; noisy environment?\n"); return AH_FALSE; } OS_REG_SET_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC); OS_REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE); OS_REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL); return AH_TRUE; }
/* * rt2860_rf_set_chan */ void rt2860_rf_set_chan(struct rt2860_softc *sc, struct ieee80211_channel *c) { struct ifnet *ifp; struct ieee80211com *ic; const struct rt2860_rf_prog *prog; uint32_t r1, r2, r3, r4; int8_t txpow1, txpow2; int i, chan; if (sc->mac_rev == 0x28720200) { rt2872_rf_set_chan(sc, c); return; } ifp = sc->ifp; ic = ifp->if_l2com; prog = rt2860_rf_2850; /* get central channel position */ chan = ieee80211_chan2ieee(ic, c); if ((sc->mac_rev & 0xffff0000) >= 0x30710000) { rt3090_set_chan(sc, chan); return; } if (IEEE80211_IS_CHAN_HT40U(c)) chan += 2; else if (IEEE80211_IS_CHAN_HT40D(c)) chan -= 2; RT2860_DPRINTF(sc, RT2860_DEBUG_CHAN, "%s: RF set channel: channel=%u, HT%s%s\n", device_get_nameunit(sc->dev), ieee80211_chan2ieee(ic, c), !IEEE80211_IS_CHAN_HT(c) ? " disabled" : IEEE80211_IS_CHAN_HT20(c) ? "20": IEEE80211_IS_CHAN_HT40U(c) ? "40U" : "40D", (ic->ic_flags & IEEE80211_F_SCAN) ? ", scanning" : ""); if (chan == 0 || chan == IEEE80211_CHAN_ANY) return; for (i = 0; prog[i].chan != chan; i++); r1 = prog[i].r1; r2 = prog[i].r2; r3 = prog[i].r3; r4 = prog[i].r4; txpow1 = sc->txpow1[i]; txpow2 = sc->txpow2[i]; if (sc->ntxpath == 1) r2 |= (1 << 14); if (sc->nrxpath == 2) r2 |= (1 << 6); else if (sc->nrxpath == 1) r2 |= (1 << 17) | (1 << 6); if (IEEE80211_IS_CHAN_2GHZ(c)) { r3 = (r3 & 0xffffc1ff) | (txpow1 << 9); r4 = (r4 & ~0x001f87c0) | (sc->rf_freq_off << 15) | (txpow2 << 6); } else { r3 = r3 & 0xffffc1ff; r4 = (r4 & ~0x001f87c0) | (sc->rf_freq_off << 15); if (txpow1 >= RT2860_EEPROM_TXPOW_5GHZ_MIN && txpow1 < 0) { txpow1 = (-RT2860_EEPROM_TXPOW_5GHZ_MIN + txpow1); if (txpow1 > RT2860_EEPROM_TXPOW_5GHZ_MAX) txpow1 = RT2860_EEPROM_TXPOW_5GHZ_MAX; r3 |= (txpow1 << 10); } else { if (txpow1 > RT2860_EEPROM_TXPOW_5GHZ_MAX) txpow1 = RT2860_EEPROM_TXPOW_5GHZ_MAX; r3 |= (txpow1 << 10) | (1 << 9); } if (txpow2 >= RT2860_EEPROM_TXPOW_5GHZ_MIN && txpow2 < 0) { txpow2 = (-RT2860_EEPROM_TXPOW_5GHZ_MIN + txpow2); if (txpow2 > RT2860_EEPROM_TXPOW_5GHZ_MAX) txpow2 = RT2860_EEPROM_TXPOW_5GHZ_MAX; r4 |= (txpow2 << 7); } else { if (txpow2 > RT2860_EEPROM_TXPOW_5GHZ_MAX) txpow2 = RT2860_EEPROM_TXPOW_5GHZ_MAX; r4 |= (txpow2 << 7) | (1 << 6); } } if (!(ic->ic_flags & IEEE80211_F_SCAN) && IEEE80211_IS_CHAN_HT40(c)) r4 |= (1 << 21); rt2860_io_rf_write(sc, RT2860_REG_RF_R1, r1); rt2860_io_rf_write(sc, RT2860_REG_RF_R2, r2); rt2860_io_rf_write(sc, RT2860_REG_RF_R3, r3 & ~(1 << 2)); rt2860_io_rf_write(sc, RT2860_REG_RF_R4, r4); DELAY(200); rt2860_io_rf_write(sc, RT2860_REG_RF_R1, r1); rt2860_io_rf_write(sc, RT2860_REG_RF_R2, r2); rt2860_io_rf_write(sc, RT2860_REG_RF_R3, r3 | (1 << 2)); rt2860_io_rf_write(sc, RT2860_REG_RF_R4, r4); DELAY(200); rt2860_io_rf_write(sc, RT2860_REG_RF_R1, r1); rt2860_io_rf_write(sc, RT2860_REG_RF_R2, r2); rt2860_io_rf_write(sc, RT2860_REG_RF_R3, r3 & ~(1 << 2)); rt2860_io_rf_write(sc, RT2860_REG_RF_R4, r4); rt2860_rf_select_chan_group(sc, c); DELAY(1000); }
/* * rt2872_rf_set_chan */ static void rt2872_rf_set_chan(struct rt2860_softc *sc, struct ieee80211_channel *c) { struct ifnet *ifp; struct ieee80211com *ic; const struct rt2860_rf_prog *prog; uint32_t r1, r2, r3, r4; uint32_t r6, r7, r12, r13, r23, r24; int8_t txpow1, txpow2; int i, chan; ifp = sc->ifp; ic = ifp->if_l2com; prog = rt2860_rf_2850; /* get central channel position */ chan = ieee80211_chan2ieee(ic, c); if (IEEE80211_IS_CHAN_HT40U(c)) chan += 2; else if (IEEE80211_IS_CHAN_HT40D(c)) chan -= 2; RT2860_DPRINTF(sc, RT2860_DEBUG_CHAN, "%s: RF set channel: channel=%u, HT%s%s\n", device_get_nameunit(sc->dev), ieee80211_chan2ieee(ic, c), !IEEE80211_IS_CHAN_HT(c) ? " disabled" : IEEE80211_IS_CHAN_HT20(c) ? "20": IEEE80211_IS_CHAN_HT40U(c) ? "40U" : "40D", (ic->ic_flags & IEEE80211_F_SCAN) ? ", scanning" : ""); if (chan == 0 || chan == IEEE80211_CHAN_ANY) return; for (i = 0; prog[i].chan != chan; i++); r1 = prog[i].r1; r2 = prog[i].r2; r3 = prog[i].r3; r4 = prog[i].r4; txpow1 = sc->txpow1[i]; txpow2 = sc->txpow2[i]; for (i = 0; rt2860_rf_fi3020[i].channel != chan; i++); /* Programm channel parameters */ r2 = rt2860_rf_fi3020[i].n; rt2860_io_rf_write(sc, 2 , r2 ); r3 = rt2860_rf_fi3020[i].k; rt2860_io_rf_write(sc, 3 , r3 ); r6 = (rt3052_rf_default[6] & 0xFC) | (rt2860_rf_fi3020[i].r & 0x03); rt2860_io_rf_write(sc, 6 , r6 ); /* Set Tx Power */ r12 = (rt3052_rf_default[12] & 0xE0) | (txpow1 & 0x1f); rt2860_io_rf_write(sc, 12, r12); /* Set Tx1 Power */ r13 = (rt3052_rf_default[13] & 0xE0) | (txpow2 & 0x1f); rt2860_io_rf_write(sc, 13, r13); /* Set RF offset */ r23 = (rt3052_rf_default[23] & 0x80) | (sc->rf_freq_off); rt2860_io_rf_write(sc, 23, r23); /* Set BW */ r24 = (rt3052_rf_default[24] & 0xDF); if (!(ic->ic_flags & IEEE80211_F_SCAN) && IEEE80211_IS_CHAN_HT40(c)) r24 |= 0x20; rt2860_io_rf_write(sc, 24, r24); /* Enable RF tuning */ r7 = (rt3052_rf_default[7]) | 1; rt2860_io_rf_write(sc, 7 , r7 ); /* Antenna */ r1 = (rt3052_rf_default[1] & 0xab) | ((sc->nrxpath == 1)?0x10:0) | ((sc->ntxpath == 1)?0x20:0); rt2860_io_rf_write(sc, 1 , r1 ); DELAY(200); rt2860_rf_select_chan_group(sc, c); DELAY(1000); }