Пример #1
0
/*
 * Return the phy mode for with the specified channel so the
 * caller can select a rate set.  This is problematic and the
 * work here assumes how things work elsewhere in this code.
 *
 * XXX never returns turbo modes -dcy
 */
enum ieee80211_phymode
ieee80211_chan2mode(struct ieee80211com *ic,
    const struct ieee80211_channel *chan)
{
	/*
	 * NB: this assumes the channel would not be supplied to us
	 *     unless it was already compatible with the current mode.
	 */
	if (ic->ic_curmode != IEEE80211_MODE_AUTO ||
	    chan == IEEE80211_CHAN_ANYC)
		return ic->ic_curmode;
	/*
	 * In autoselect mode; deduce a mode based on the channel
	 * characteristics.  We assume that turbo-only channels
	 * are not considered when the channel set is constructed.
	 */
	if (IEEE80211_IS_CHAN_T(chan))
		return IEEE80211_MODE_TURBO;
	else if (IEEE80211_IS_CHAN_5GHZ(chan))
		return IEEE80211_MODE_11A;
	else if (chan->ic_flags & (IEEE80211_CHAN_OFDM|IEEE80211_CHAN_DYN))
		return IEEE80211_MODE_11G;
	else
		return IEEE80211_MODE_11B;
}
Пример #2
0
/*
 * 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;
}
Пример #3
0
static int
iwm_mvm_scan_skip_channel(struct ieee80211_channel *c)
{
	if (IEEE80211_IS_CHAN_2GHZ(c) && IEEE80211_IS_CHAN_B(c))
		return 0;
	else if (IEEE80211_IS_CHAN_5GHZ(c) && IEEE80211_IS_CHAN_A(c))
		return 0;
	else
		return 1;
}
Пример #4
0
void
ar9380_set_correction(struct athn_softc *sc, struct ieee80211_channel *c)
{
	const struct ar9380_eeprom *eep = sc->eep;
	const struct ar9380_modal_eep_header *modal;
	uint32_t reg;
	int8_t slope;
	int i, corr, temp, temp0;

	if (IEEE80211_IS_CHAN_2GHZ(c))
		modal = &eep->modalHeader2G;
	else
		modal = &eep->modalHeader5G;

	for (i = 0; i < AR9380_MAX_CHAINS; i++) {
		ar9380_get_correction(sc, c, i, &corr, &temp);
		if (i == 0)
			temp0 = temp;

		reg = AR_READ(sc, AR_PHY_TPC_11_B(i));
		reg = RW(reg, AR_PHY_TPC_11_OLPC_GAIN_DELTA, corr);
		AR_WRITE(sc, AR_PHY_TPC_11_B(i), reg);

		/* Enable open loop power control. */
		reg = AR_READ(sc, AR_PHY_TPC_6_B(i));
		reg = RW(reg, AR_PHY_TPC_6_ERROR_EST_MODE, 3);
		AR_WRITE(sc, AR_PHY_TPC_6_B(i), reg);
	}

	/* Enable temperature compensation. */
	if (IEEE80211_IS_CHAN_5GHZ(c) &&
	    eep->base_ext2.tempSlopeLow != 0) {
		if (c->ic_freq <= 5500) {
			slope = athn_interpolate(c->ic_freq,
			    5180, eep->base_ext2.tempSlopeLow,
			    5500, modal->tempSlope);
		} else {
			slope = athn_interpolate(c->ic_freq,
			    5500, modal->tempSlope,
			    5785, eep->base_ext2.tempSlopeHigh);
		}
	} else
		slope = modal->tempSlope;

	reg = AR_READ(sc, AR_PHY_TPC_19);
	reg = RW(reg, AR_PHY_TPC_19_ALPHA_THERM, slope);
	AR_WRITE(sc, AR_PHY_TPC_19, reg);

	reg = AR_READ(sc, AR_PHY_TPC_18);
	reg = RW(reg, AR_PHY_TPC_18_THERM_CAL, temp0);
	AR_WRITE(sc, AR_PHY_TPC_18, reg);
	AR_WRITE_BARRIER(sc);
}
Пример #5
0
void
ar9130InitPLL(struct ath_hal *ah, const struct ieee80211_channel *chan)
{

	uint32_t pll;

	if (chan && IEEE80211_IS_CHAN_5GHZ(chan))
		pll = 0x1450;
	else
		pll = 0x1458;

	OS_REG_WRITE(ah, AR_RTC_PLL_CONTROL, pll);
	OS_DELAY(RTC_PLL_SETTLE_DELAY);
	OS_REG_WRITE(ah, AR_RTC_SLEEP_CLK, AR_RTC_SLEEP_DERIVED_CLK);
}
Пример #6
0
static void
ar9160AniSetup(struct ath_hal *ah)
{
	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 void 
ar9160InitPLL(struct ath_hal *ah, const struct ieee80211_channel *chan)
{
	uint32_t pll = SM(0x5, AR_RTC_SOWL_PLL_REFDIV);
	if (chan != AH_NULL) {
		if (IEEE80211_IS_CHAN_HALF(chan))
			pll |= SM(0x1, AR_RTC_SOWL_PLL_CLKSEL);
		else if (IEEE80211_IS_CHAN_QUARTER(chan))
			pll |= SM(0x2, AR_RTC_SOWL_PLL_CLKSEL);

		if (IEEE80211_IS_CHAN_5GHZ(chan))
			pll |= SM(0x50, AR_RTC_SOWL_PLL_DIV);
		else
			pll |= SM(0x58, AR_RTC_SOWL_PLL_DIV);
	} else
		pll |= SM(0x58, AR_RTC_SOWL_PLL_DIV);

	OS_REG_WRITE(ah, AR_RTC_PLL_CONTROL, pll);
	OS_DELAY(RTC_PLL_SETTLE_DELAY);
	OS_REG_WRITE(ah, AR_RTC_SLEEP_CLK, AR_RTC_SLEEP_DERIVED_CLK);
}
Пример #7
0
static HAL_BOOL
ar5416GetEepromNoiseFloorThresh(struct ath_hal *ah,
	const struct ieee80211_channel *chan, int16_t *nft)
{
	if (IEEE80211_IS_CHAN_5GHZ(chan)) {
		ath_hal_eepromGet(ah, AR_EEP_NFTHRESH_5, nft);
		return AH_TRUE;
	}
	if (IEEE80211_IS_CHAN_2GHZ(chan)) {
		ath_hal_eepromGet(ah, AR_EEP_NFTHRESH_2, nft);
		return AH_TRUE;
	}
	HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel flags 0x%x\n",
	    __func__, chan->ic_flags);
	return AH_FALSE;
}
Пример #8
0
static uint8_t
iwm_mvm_lmac_scan_fill_channels(struct iwm_softc *sc,
    struct iwm_scan_channel_cfg_lmac *chan, int n_ssids)
{
	struct ieee80211com *ic = &sc->sc_ic;
	struct ieee80211_scan_state *ss = ic->ic_scan;
	struct ieee80211_channel *c;
	uint8_t nchan;
	int j;

	for (nchan = j = 0;
	    j < ss->ss_last && nchan < sc->ucode_capa.n_scan_channels; j++) {
		c = ss->ss_chans[j];
		/*
		 * Catch other channels, in case we have 900MHz channels or
		 * something in the chanlist.
		 */
		if (!IEEE80211_IS_CHAN_2GHZ(c) && !IEEE80211_IS_CHAN_5GHZ(c)) {
			IWM_DPRINTF(sc, IWM_DEBUG_RESET | IWM_DEBUG_EEPROM,
			    "%s: skipping channel (freq=%d, ieee=%d, flags=0x%08x)\n",
			    __func__, c->ic_freq, c->ic_ieee, c->ic_flags);
			continue;
		}

		IWM_DPRINTF(sc, IWM_DEBUG_RESET | IWM_DEBUG_EEPROM,
		    "Adding channel %d (%d Mhz) to the list\n",
		    nchan, c->ic_freq);
		chan->channel_num = htole16(ieee80211_mhz2ieee(c->ic_freq, 0));
		chan->iter_count = htole16(1);
		chan->iter_interval = htole32(0);
		chan->flags = htole32(IWM_UNIFIED_SCAN_CHANNEL_PARTIAL);
		chan->flags |= htole32(IWM_SCAN_CHANNEL_NSSIDS(n_ssids));
		/* XXX IEEE80211_SCAN_NOBCAST flag is never set. */
		if (!IEEE80211_IS_CHAN_PASSIVE(c) &&
		    (!(ss->ss_flags & IEEE80211_SCAN_NOBCAST) || n_ssids != 0))
			chan->flags |= htole32(IWM_SCAN_CHANNEL_TYPE_ACTIVE);
		chan++;
		nchan++;
	}

	return nchan;
}
Пример #9
0
static void
setchannelflags(struct ieee80211_channel *c, REG_DMN_FREQ_BAND *fband,
    REG_DOMAIN *rd)
{
	if (fband->usePassScan & rd->pscan)
		c->ic_flags |= IEEE80211_CHAN_PASSIVE;
	if (fband->useDfs & rd->dfsMask)
		c->ic_flags |= IEEE80211_CHAN_DFS;
	if (IEEE80211_IS_CHAN_5GHZ(c) && (rd->flags & DISALLOW_ADHOC_11A))
		c->ic_flags |= IEEE80211_CHAN_NOADHOC;
	if (IEEE80211_IS_CHAN_TURBO(c) &&
	    (rd->flags & DISALLOW_ADHOC_11A_TURB))
		c->ic_flags |= IEEE80211_CHAN_NOADHOC;
	if (rd->flags & NO_HOSTAP)
		c->ic_flags |= IEEE80211_CHAN_NOHOSTAP;
	if (rd->flags & LIMIT_FRAME_4MS)
		c->ic_flags |= IEEE80211_CHAN_4MSXMIT;
	if (rd->flags & NEED_NFC)
		c->ic_flags |= CHANNEL_NFCREQUIRED;
}
Пример #10
0
/*
 * Return the phy mode for with the specified channel so the
 * caller can select a rate set.  This is problematic for channels
 * where multiple operating modes are possible (e.g. 11g+11b).
 * In those cases we defer to the current operating mode when set.
 */
enum ieee80211_phymode
ieee80211_chan2mode(struct ieee80211com *ic, struct ieee80211_channel *chan)
{
	if (IEEE80211_IS_CHAN_T(chan)) {
		return IEEE80211_MODE_TURBO_A;
	} else if (IEEE80211_IS_CHAN_5GHZ(chan)) {
		return IEEE80211_MODE_11A;
	} else if (IEEE80211_IS_CHAN_FHSS(chan))
		return IEEE80211_MODE_FH;
	else if (chan->ic_flags & (IEEE80211_CHAN_OFDM|IEEE80211_CHAN_DYN)) {
		/*
		 * This assumes all 11g channels are also usable
		 * for 11b, which is currently true.
		 */
		if (ic->ic_curmode == IEEE80211_MODE_TURBO_G)
			return IEEE80211_MODE_TURBO_G;
		if (ic->ic_curmode == IEEE80211_MODE_11B)
			return IEEE80211_MODE_11B;
		return IEEE80211_MODE_11G;
	} else
		return IEEE80211_MODE_11B;
}
Пример #11
0
static struct wifi_channels *list_channelsext(const char *ifname, int allchans)
{
    struct ieee80211req_chaninfo chans;
    struct ieee80211req_chaninfo achans;
    const struct ieee80211_channel *c;
    int i;

    fprintf(stderr, "list channels for %s\n", ifname);
    if (do80211priv
            (ifname, IEEE80211_IOCTL_GETCHANINFO, &chans, sizeof(chans)) < 0) {
        fprintf(stderr, "unable to get channel information\n");
        return NULL;
    }
    if (!allchans) {
        uint8_t active[64];

        if (do80211priv
                (ifname, IEEE80211_IOCTL_GETCHANLIST, &active,
                 sizeof(active)) < 0) {
            fprintf(stderr, "unable to get active channel list\n");
            return NULL;
        }
        memset(&achans, 0, sizeof(achans));
        for (i = 0; i < chans.ic_nchans; i++) {
            c = &chans.ic_chans[i];
            if (isset(active, c->ic_ieee) || allchans)
                achans.ic_chans[achans.ic_nchans++] = *c;
        }
    } else
        achans = chans;

    struct wifi_channels *list =
        (struct wifi_channels *)safe_malloc(sizeof(struct wifi_channels) *
                                            (achans.ic_nchans + 1));
    (void)memset(list, 0, (sizeof(struct wifi_channels)*((achans.ic_nchans + 1))));

    char wl_mode[16];
    char wl_turbo[16];

    sprintf(wl_mode, "%s_net_mode", ifname);
    sprintf(wl_turbo, "%s_channelbw", ifname);
    int l = 0;
    int up = 0;
    char sb[32];
    sprintf(sb, "%s_nctrlsb", ifname);
    if (nvram_match(sb, "upper"))
        up = 1;

    for (i = 0; i < achans.ic_nchans; i++) {
#ifdef HAVE_BUFFALO
        if (achans.ic_chans[i].ic_flags & IEEE80211_CHAN_RADARFOUND) //filter channels with detected radar
            continue;
#endif
        // filter out A channels if mode isnt A-Only or mixed
        if (IEEE80211_IS_CHAN_5GHZ(&achans.ic_chans[i])) {
            if (nvram_invmatch(wl_mode, "a-only")
                    && nvram_invmatch(wl_mode, "mixed")
                    && nvram_invmatch(wl_mode, "n5-only")
                    && nvram_invmatch(wl_mode, "na-only")) {
//                              fprintf(stderr,"5 Ghz %d is not compatible to a-only/mixed/na-only %X\n",achans.ic_chans[i].ic_freq,achans.ic_chans[i].ic_flags);
                continue;
            }
            if (nvram_match(wl_turbo, "40")
                    && (nvram_match(wl_mode, "n5-only")
                        || nvram_match(wl_mode, "mixed")
                        || nvram_match(wl_mode, "na-only"))) {
                if (up
                        &&
                        !IEEE80211_IS_CHAN_11NA_HT40PLUS
                        (&achans.ic_chans[i]))
                    continue;
                if (!up
                        &&
                        !IEEE80211_IS_CHAN_11NA_HT40MINUS
                        (&achans.ic_chans[i]))
                    continue;
            }
        }
        // filter out B/G channels if mode isnt g-only, b-only or mixed
        if (IEEE80211_IS_CHAN_2GHZ(&achans.ic_chans[i])) {
            if (nvram_invmatch(wl_mode, "g-only")
                    && nvram_invmatch(wl_mode, "mixed")
                    && nvram_invmatch(wl_mode, "b-only")
                    && nvram_invmatch(wl_mode, "n2-only")
                    && nvram_invmatch(wl_mode, "bg-mixed")
                    && nvram_invmatch(wl_mode, "ng-only")) {
                fprintf(stderr, "%s:%d\n", __func__, __LINE__);
                continue;
            }
#ifdef HAVE_BUFFALO_SA
            if(nvram_default_match("region", "SA", "")
                    && (!strcmp(getUEnv("region"), "AP") || !strcmp(getUEnv("region"), "US"))
                    && achans.ic_chans[i].ic_ieee > 11 && achans.ic_chans[i].ic_ieee <= 14)
                continue;
#endif
            if (nvram_match(wl_turbo, "40")
                    && (nvram_match(wl_mode, "n2-only")
                        || nvram_match(wl_mode, "mixed")
                        || nvram_match(wl_mode, "ng-only"))) {
                if (up
                        &&
                        !IEEE80211_IS_CHAN_11NG_HT40PLUS
                        (&achans.ic_chans[i])) {
                    fprintf(stderr, "%s:%d\n", __func__,
                            __LINE__);
                    continue;
                }
                if (!up
                        &&
                        !IEEE80211_IS_CHAN_11NG_HT40MINUS
                        (&achans.ic_chans[i])) {
                    fprintf(stderr, "%s:%d\n", __func__,
                            __LINE__);
                    continue;
                }
            }
        }

        list[l].channel = achans.ic_chans[i].ic_ieee;
        list[l].freq = achans.ic_chans[i].ic_freq;
        list[l].noise = -95;	// achans.ic_chans[i].ic_noise;
        l++;
    }

    list[l].freq = -1;
    return list;
}
Пример #12
0
/*
 * Sets the transmit power in the baseband for the given
 * operating channel and mode.
 */
static HAL_BOOL
setRateTable(struct ath_hal *ah, const struct ieee80211_channel *chan, 
		   int16_t tpcScaleReduction, int16_t powerLimit,
                   int16_t *pMinPower, int16_t *pMaxPower)
{
	u_int16_t ratesArray[16];
	u_int16_t *rpow = ratesArray;
	u_int16_t twiceMaxRDPower, twiceMaxEdgePower, twiceMaxEdgePowerCck;
	int8_t twiceAntennaGain, twiceAntennaReduction;
	TRGT_POWER_INFO targetPowerOfdm, targetPowerCck;
	RD_EDGES_POWER *rep;
	int16_t scaledPower;
	u_int8_t cfgCtl;

	twiceMaxRDPower = chan->ic_maxregpower * 2;
	*pMaxPower = -MAX_RATE_POWER;
	*pMinPower = MAX_RATE_POWER;

	/* Get conformance test limit maximum for this channel */
	cfgCtl = ath_hal_getctl(ah, chan);
	rep = findEdgePower(ah, cfgCtl);
	if (rep != AH_NULL)
		twiceMaxEdgePower = ar5212GetMaxEdgePower(chan->ic_freq, rep);
	else
		twiceMaxEdgePower = MAX_RATE_POWER;

	if (IEEE80211_IS_CHAN_G(chan)) {
		/* Check for a CCK CTL for 11G CCK powers */
		cfgCtl = (cfgCtl & 0xFC) | 0x01;
		rep = findEdgePower(ah, cfgCtl);
		if (rep != AH_NULL)
			twiceMaxEdgePowerCck = ar5212GetMaxEdgePower(chan->ic_freq, rep);
		else
			twiceMaxEdgePowerCck = MAX_RATE_POWER;
	} else {
		/* Set the 11B cck edge power to the one found before */
		twiceMaxEdgePowerCck = twiceMaxEdgePower;
	}

	/* Get Antenna Gain reduction */
	if (IEEE80211_IS_CHAN_5GHZ(chan)) {
		twiceAntennaGain = antennaGainMax[0];
	} else {
		twiceAntennaGain = antennaGainMax[1];
	}
	twiceAntennaReduction =
		ath_hal_getantennareduction(ah, chan, twiceAntennaGain);

	if (IEEE80211_IS_CHAN_OFDM(chan)) {
		/* Get final OFDM target powers */
		if (IEEE80211_IS_CHAN_G(chan)) { 
			/* TODO - add Turbo 2.4 to this mode check */
			ar5212GetTargetPowers(ah, chan, trgtPwr_11g,
				numTargetPwr_11g, &targetPowerOfdm);
		} else {
			ar5212GetTargetPowers(ah, chan, trgtPwr_11a,
				numTargetPwr_11a, &targetPowerOfdm);
		}

		/* Get Maximum OFDM power */
		/* Minimum of target and edge powers */
		scaledPower = AH_MIN(twiceMaxEdgePower,
				twiceMaxRDPower - twiceAntennaReduction);

		/*
		 * If turbo is set, reduce power to keep power
		 * consumption under 2 Watts.  Note that we always do
		 * this unless specially configured.  Then we limit
		 * power only for non-AP operation.
		 */
		if (IEEE80211_IS_CHAN_TURBO(chan)
#ifdef AH_ENABLE_AP_SUPPORT
		    && AH_PRIVATE(ah)->ah_opmode != HAL_M_HOSTAP
#endif
		) {
			/*
			 * If turbo is set, reduce power to keep power
			 * consumption under 2 Watts
			 */
			if (eeversion >= AR_EEPROM_VER3_1)
				scaledPower = AH_MIN(scaledPower,
					turbo2WMaxPower5);
			/*
			 * EEPROM version 4.0 added an additional
			 * constraint on 2.4GHz channels.
			 */
			if (eeversion >= AR_EEPROM_VER4_0 &&
			    IEEE80211_IS_CHAN_2GHZ(chan))
				scaledPower = AH_MIN(scaledPower,
					turbo2WMaxPower2);
		}
		/* Reduce power by max regulatory domain allowed restrictions */
		scaledPower -= (tpcScaleReduction * 2);
		scaledPower = (scaledPower < 0) ? 0 : scaledPower;
		scaledPower = AH_MIN(scaledPower, powerLimit);

		scaledPower = AH_MIN(scaledPower, targetPowerOfdm.twicePwr6_24);

		/* Set OFDM rates 9, 12, 18, 24, 36, 48, 54, XR */
		rpow[0] = rpow[1] = rpow[2] = rpow[3] = rpow[4] = scaledPower;
		rpow[5] = AH_MIN(rpow[0], targetPowerOfdm.twicePwr36);
		rpow[6] = AH_MIN(rpow[0], targetPowerOfdm.twicePwr48);
		rpow[7] = AH_MIN(rpow[0], targetPowerOfdm.twicePwr54);

#ifdef notyet
		if (eeversion >= AR_EEPROM_VER4_0) {
			/* Setup XR target power from EEPROM */
			rpow[15] = AH_MIN(scaledPower, IS_CHAN_2GHZ(chan) ?
				xrTargetPower2 : xrTargetPower5);
		} else {
			/* XR uses 6mb power */
			rpow[15] = rpow[0];
		}
#else
		rpow[15] = rpow[0];
#endif

		*pMinPower = rpow[7];
		*pMaxPower = rpow[0];

#if 0
		ahp->ah_ofdmTxPower = rpow[0];
#endif

		HALDEBUG(ah, HAL_DEBUG_ANY,
		    "%s: MaxRD: %d TurboMax: %d MaxCTL: %d "
		    "TPC_Reduction %d\n", __func__,
		    twiceMaxRDPower, turbo2WMaxPower5,
		    twiceMaxEdgePower, tpcScaleReduction * 2);
	}

	if (IEEE80211_IS_CHAN_CCK(chan)) {
		/* Get final CCK target powers */
		ar5212GetTargetPowers(ah, chan, trgtPwr_11b,
			numTargetPwr_11b, &targetPowerCck);

		/* Reduce power by max regulatory domain allowed restrictions */
		scaledPower = AH_MIN(twiceMaxEdgePowerCck,
			twiceMaxRDPower - twiceAntennaReduction);

		scaledPower -= (tpcScaleReduction * 2);
		scaledPower = (scaledPower < 0) ? 0 : scaledPower;
		scaledPower = AH_MIN(scaledPower, powerLimit);

		rpow[8] = (scaledPower < 1) ? 1 : scaledPower;

		/* Set CCK rates 2L, 2S, 5.5L, 5.5S, 11L, 11S */
		rpow[8]  = AH_MIN(scaledPower, targetPowerCck.twicePwr6_24);
		rpow[9]  = AH_MIN(scaledPower, targetPowerCck.twicePwr36);
		rpow[10] = rpow[9];
		rpow[11] = AH_MIN(scaledPower, targetPowerCck.twicePwr48);
		rpow[12] = rpow[11];
		rpow[13] = AH_MIN(scaledPower, targetPowerCck.twicePwr54);
		rpow[14] = rpow[13];

		/* Set min/max power based off OFDM values or initialization */
		if (rpow[13] < *pMinPower)
		    *pMinPower = rpow[13];
		if (rpow[9] > *pMaxPower)
		    *pMaxPower = rpow[9];

	}
#if 0
	ahp->ah_tx6PowerInHalfDbm = *pMaxPower;
#endif
	return AH_TRUE;
}
Пример #13
0
/*
 * Construct the channel list for the specified regulatory config.
 */
static HAL_STATUS
getchannels(struct ath_hal *ah,
    struct ieee80211_channel chans[], u_int maxchans, int *nchans,
    u_int modeSelect, HAL_CTRY_CODE cc, HAL_REG_DOMAIN regDmn,
    HAL_BOOL enableExtendedChannels,
    COUNTRY_CODE_TO_ENUM_RD **pcountry,
    REG_DOMAIN **prd2GHz, REG_DOMAIN **prd5GHz)
{
#define CHANNEL_HALF_BW		10
#define CHANNEL_QUARTER_BW	5
#define	HAL_MODE_11A_ALL \
	(HAL_MODE_11A | HAL_MODE_11A_TURBO | HAL_MODE_TURBO | \
	 HAL_MODE_11A_QUARTER_RATE | HAL_MODE_11A_HALF_RATE)
	REG_DOMAIN *rd5GHz, *rd2GHz;
	u_int modesAvail;
	const struct cmode *cm;
	struct ieee80211_channel *ic;
	int next, b;
	HAL_STATUS status;

	HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, "%s: cc %u regDmn 0x%x mode 0x%x%s\n",
	    __func__, cc, regDmn, modeSelect, 
	    enableExtendedChannels ? " ecm" : "");

	status = getregstate(ah, cc, regDmn, pcountry, &rd2GHz, &rd5GHz);
	if (status != HAL_OK)
		return status;

	/* get modes that HW is capable of */
	modesAvail = ath_hal_getWirelessModes(ah);
	/* optimize work below if no 11a channels */
	if (isChanBitMaskZero(rd5GHz->chan11a) &&
	    (modesAvail & HAL_MODE_11A_ALL)) {
		HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
		    "%s: disallow all 11a\n", __func__);
		modesAvail &= ~HAL_MODE_11A_ALL;
	}

	next = 0;
	ic = &chans[0];
	for (cm = modes; cm < &modes[N(modes)]; cm++) {
		uint16_t c, c_hi, c_lo;
		uint64_t *channelBM = AH_NULL;
		REG_DMN_FREQ_BAND *fband = AH_NULL,*freqs;
		int low_adj, hi_adj, channelSep, lastc;
		uint32_t rdflags;
		uint64_t dfsMask;
		uint64_t pscan;

		if ((cm->mode & modeSelect) == 0) {
			HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
			    "%s: skip mode 0x%x flags 0x%x\n",
			    __func__, cm->mode, cm->flags);
			continue;
		}
		if ((cm->mode & modesAvail) == 0) {
			HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
			    "%s: !avail mode 0x%x (0x%x) flags 0x%x\n",
			    __func__, modesAvail, cm->mode, cm->flags);
			continue;
		}
		if (!ath_hal_getChannelEdges(ah, cm->flags, &c_lo, &c_hi)) {
			/* channel not supported by hardware, skip it */
			HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
			    "%s: channels 0x%x not supported by hardware\n",
			    __func__,cm->flags);
			continue;
		}
		switch (cm->mode) {
		case HAL_MODE_TURBO:
		case HAL_MODE_11A_TURBO:
			rdflags = rd5GHz->flags;
			dfsMask = rd5GHz->dfsMask;
			pscan = rd5GHz->pscan;
			if (cm->mode == HAL_MODE_TURBO)
				channelBM = rd5GHz->chan11a_turbo;
			else
				channelBM = rd5GHz->chan11a_dyn_turbo;
			freqs = &regDmn5GhzTurboFreq[0];
			break;
		case HAL_MODE_11G_TURBO:
			rdflags = rd2GHz->flags;
			dfsMask = rd2GHz->dfsMask;
			pscan = rd2GHz->pscan;
			channelBM = rd2GHz->chan11g_turbo;
			freqs = &regDmn2Ghz11gTurboFreq[0];
			break;
		case HAL_MODE_11A:
		case HAL_MODE_11A_HALF_RATE:
		case HAL_MODE_11A_QUARTER_RATE:
		case HAL_MODE_11NA_HT20:
		case HAL_MODE_11NA_HT40PLUS:
		case HAL_MODE_11NA_HT40MINUS:
			rdflags = rd5GHz->flags;
			dfsMask = rd5GHz->dfsMask;
			pscan = rd5GHz->pscan;
			if (cm->mode == HAL_MODE_11A_HALF_RATE)
				channelBM = rd5GHz->chan11a_half;
			else if (cm->mode == HAL_MODE_11A_QUARTER_RATE)
				channelBM = rd5GHz->chan11a_quarter;
			else
				channelBM = rd5GHz->chan11a;
			freqs = &regDmn5GhzFreq[0];
			break;
		case HAL_MODE_11B:
		case HAL_MODE_11G:
		case HAL_MODE_11G_HALF_RATE:
		case HAL_MODE_11G_QUARTER_RATE:
		case HAL_MODE_11NG_HT20:
		case HAL_MODE_11NG_HT40PLUS:
		case HAL_MODE_11NG_HT40MINUS:
			rdflags = rd2GHz->flags;
			dfsMask = rd2GHz->dfsMask;
			pscan = rd2GHz->pscan;
			if (cm->mode == HAL_MODE_11G_HALF_RATE)
				channelBM = rd2GHz->chan11g_half;
			else if (cm->mode == HAL_MODE_11G_QUARTER_RATE)
				channelBM = rd2GHz->chan11g_quarter;
			else if (cm->mode == HAL_MODE_11B)
				channelBM = rd2GHz->chan11b;
			else
				channelBM = rd2GHz->chan11g;
			if (cm->mode == HAL_MODE_11B)
				freqs = &regDmn2GhzFreq[0];
			else
				freqs = &regDmn2Ghz11gFreq[0];
			break;
		default:
			HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
			    "%s: Unkonwn HAL mode 0x%x\n", __func__, cm->mode);
			continue;
		}
		if (isChanBitMaskZero(channelBM))
			continue;
		/*
		 * Setup special handling for HT40 channels; e.g.
		 * 5G HT40 channels require 40Mhz channel separation.
		 */
		hi_adj = (cm->mode == HAL_MODE_11NA_HT40PLUS ||
		    cm->mode == HAL_MODE_11NG_HT40PLUS) ? -20 : 0;
		low_adj = (cm->mode == HAL_MODE_11NA_HT40MINUS || 
		    cm->mode == HAL_MODE_11NG_HT40MINUS) ? 20 : 0;
		channelSep = (cm->mode == HAL_MODE_11NA_HT40PLUS ||
		    cm->mode == HAL_MODE_11NA_HT40MINUS) ? 40 : 0;

		for (b = 0; b < 64*BMLEN; b++) {
			if (!IS_BIT_SET(b, channelBM))
				continue;
			fband = &freqs[b];
			lastc = 0;

			for (c = fband->lowChannel + low_adj;
			     c <= fband->highChannel + hi_adj;
			     c += fband->channelSep) {
				if (!(c_lo <= c && c <= c_hi)) {
					HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
					    "%s: c %u out of range [%u..%u]\n",
					    __func__, c, c_lo, c_hi);
					continue;
				}
				if (next >= maxchans){
					HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
					    "%s: too many channels for channel table\n",
					    __func__);
					goto done;
				}
				if ((fband->usePassScan & IS_ECM_CHAN) &&
				    !enableExtendedChannels) {
					HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
					    "skip ecm channel\n");
					continue;
				}
#if 0
				if ((fband->useDfs & dfsMask) && 
				    (cm->flags & IEEE80211_CHAN_HT40)) {
					/* NB: DFS and HT40 don't mix */
					HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
					    "skip HT40 chan, DFS required\n");
					continue;
				}
#endif
				/*
				 * Make sure that channel separation
				 * meets the requirement.
				 */
				if (lastc && channelSep &&
				    (c-lastc) < channelSep)
					continue;
				lastc = c;

				OS_MEMZERO(ic, sizeof(*ic));
				ic->ic_freq = c;
				ic->ic_flags = cm->flags;
				ic->ic_maxregpower = fband->powerDfs;
				ath_hal_getpowerlimits(ah, ic);
				ic->ic_maxantgain = fband->antennaMax;
				if (fband->usePassScan & pscan)
					ic->ic_flags |= IEEE80211_CHAN_PASSIVE;
				if (fband->useDfs & dfsMask)
					ic->ic_flags |= IEEE80211_CHAN_DFS;
				if (IEEE80211_IS_CHAN_5GHZ(ic) &&
				    (rdflags & DISALLOW_ADHOC_11A))
					ic->ic_flags |= IEEE80211_CHAN_NOADHOC;
				if (IEEE80211_IS_CHAN_TURBO(ic) &&
				    (rdflags & DISALLOW_ADHOC_11A_TURB))
					ic->ic_flags |= IEEE80211_CHAN_NOADHOC;
				if (rdflags & NO_HOSTAP)
					ic->ic_flags |= IEEE80211_CHAN_NOHOSTAP;
				if (rdflags & LIMIT_FRAME_4MS)
					ic->ic_flags |= IEEE80211_CHAN_4MSXMIT;
				if (rdflags & NEED_NFC)
					ic->ic_flags |= CHANNEL_NFCREQUIRED;

				ic++, next++;
			}
		}
	}
done:
	*nchans = next;
	/* NB: pcountry set above by getregstate */
	if (prd2GHz != AH_NULL)
		*prd2GHz = rd2GHz;
	if (prd5GHz != AH_NULL)
		*prd5GHz = rd5GHz;
	return HAL_OK;
#undef HAL_MODE_11A_ALL
#undef CHANNEL_HALF_BW
#undef CHANNEL_QUARTER_BW
}
Пример #14
0
static void
ar9280AniSetup(struct ath_hal *ah)
{
	/*
	 * These are the parameters from the AR5416 ANI code;
	 * they likely need quite a bit of adjustment for the
	 * AR9280.
	 */
        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   = 2,
                .cycPwrThr1             = { 2, 4, 6 },
                .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);

        /* NB: ANI is not enabled yet */
        ar5416AniAttach(ah, &aniparams, &aniparams, AH_TRUE);
}

void
ar9280InitPLL(struct ath_hal *ah, const struct ieee80211_channel *chan)
{
	uint32_t pll = SM(0x5, AR_RTC_SOWL_PLL_REFDIV);

	if (AR_SREV_MERLIN_20(ah) &&
	    chan != AH_NULL && IEEE80211_IS_CHAN_5GHZ(chan)) {
		/*
		 * PLL WAR for Merlin 2.0/2.1
		 * When doing fast clock, set PLL to 0x142c
		 * Else, set PLL to 0x2850 to prevent reset-to-reset variation 
		 */
		pll = IS_5GHZ_FAST_CLOCK_EN(ah, chan) ? 0x142c : 0x2850;
	} else if (AR_SREV_MERLIN_10_OR_LATER(ah)) {
		pll = SM(0x5, AR_RTC_SOWL_PLL_REFDIV);
		if (chan != AH_NULL) {
			if (IEEE80211_IS_CHAN_HALF(chan))
				pll |= SM(0x1, AR_RTC_SOWL_PLL_CLKSEL);
			else if (IEEE80211_IS_CHAN_QUARTER(chan))
				pll |= SM(0x2, AR_RTC_SOWL_PLL_CLKSEL);
			if (IEEE80211_IS_CHAN_5GHZ(chan))
				pll |= SM(0x28, AR_RTC_SOWL_PLL_DIV);
			else
				pll |= SM(0x2c, AR_RTC_SOWL_PLL_DIV);
		} else
			pll |= SM(0x2c, AR_RTC_SOWL_PLL_DIV);
	}

	OS_REG_WRITE(ah, AR_RTC_PLL_CONTROL, pll);
	OS_DELAY(RTC_PLL_SETTLE_DELAY);
	OS_REG_WRITE(ah, AR_RTC_SLEEP_CLK, AR_RTC_SLEEP_DERIVED_CLK);
}
Пример #15
0
/*
 * Places the hardware into reset and then pulls it out of reset
 *
 * TODO: Only write the PLL if we're changing to or from CCK mode
 * 
 * WARNING: The order of the PLL and mode registers must be correct.
 */
HAL_BOOL
ar5312ChipReset(struct ath_hal *ah, const struct ieee80211_channel *chan)
{

	OS_MARK(ah, AH_MARK_CHIPRESET, chan ? chan->ic_freq : 0);

	/*
	 * Reset the HW 
	 */
	if (!ar5312SetResetReg(ah, AR_RC_MAC | AR_RC_BB)) {
		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: ar5312SetResetReg failed\n",
		    __func__);
		return AH_FALSE;
	}

	/* Bring out of sleep mode (AGAIN) */
	if (!ar5312SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE)) {
		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: ar5312SetPowerMode failed\n",
		    __func__);
		return AH_FALSE;
	}

	/* Clear warm reset register */
	if (!ar5312SetResetReg(ah, 0)) {
		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: ar5312SetResetReg failed\n",
		    __func__);
		return AH_FALSE;
	}

	/*
	 * Perform warm reset before the mode/PLL/turbo registers
	 * are changed in order to deactivate the radio.  Mode changes
	 * with an active radio can result in corrupted shifts to the
	 * radio device.
	 */

	/*
	 * Set CCK and Turbo modes correctly.
	 */
	if (chan != AH_NULL) {		/* NB: can be null during attach */
		uint32_t rfMode, phyPLL = 0, curPhyPLL, turbo;

		if (IS_RAD5112_ANY(ah)) {
			rfMode = AR_PHY_MODE_AR5112;
			if (!IS_5315(ah)) {
				if (IEEE80211_IS_CHAN_CCK(chan)) {
					phyPLL = AR_PHY_PLL_CTL_44_5312;
				} else {
					if (IEEE80211_IS_CHAN_HALF(chan)) {
						phyPLL = AR_PHY_PLL_CTL_40_5312_HALF;
					} else if (IEEE80211_IS_CHAN_QUARTER(chan)) {
						phyPLL = AR_PHY_PLL_CTL_40_5312_QUARTER;
					} else {
						phyPLL = AR_PHY_PLL_CTL_40_5312;
					}
				}
			} else {
				if (IEEE80211_IS_CHAN_CCK(chan))
					phyPLL = AR_PHY_PLL_CTL_44_5112;
				else
					phyPLL = AR_PHY_PLL_CTL_40_5112;
				if (IEEE80211_IS_CHAN_HALF(chan))
					phyPLL |= AR_PHY_PLL_CTL_HALF;
				else if (IEEE80211_IS_CHAN_QUARTER(chan))
					phyPLL |= AR_PHY_PLL_CTL_QUARTER;
			}
		} else {
			rfMode = AR_PHY_MODE_AR5111;
			if (IEEE80211_IS_CHAN_CCK(chan))
				phyPLL = AR_PHY_PLL_CTL_44;
			else
				phyPLL = AR_PHY_PLL_CTL_40;
			if (IEEE80211_IS_CHAN_HALF(chan))
				phyPLL = AR_PHY_PLL_CTL_HALF;
			else if (IEEE80211_IS_CHAN_QUARTER(chan))
				phyPLL = AR_PHY_PLL_CTL_QUARTER;
		}
		if (IEEE80211_IS_CHAN_G(chan))
			rfMode |= AR_PHY_MODE_DYNAMIC;
		else if (IEEE80211_IS_CHAN_OFDM(chan))
			rfMode |= AR_PHY_MODE_OFDM;
		else
			rfMode |= AR_PHY_MODE_CCK;
		if (IEEE80211_IS_CHAN_5GHZ(chan))
			rfMode |= AR_PHY_MODE_RF5GHZ;
		else
			rfMode |= AR_PHY_MODE_RF2GHZ;
		turbo = IEEE80211_IS_CHAN_TURBO(chan) ?
			(AR_PHY_FC_TURBO_MODE | AR_PHY_FC_TURBO_SHORT) : 0;
		curPhyPLL = OS_REG_READ(ah, AR_PHY_PLL_CTL);
		/*
		 * PLL, Mode, and Turbo values must be written in the correct
		 * order to ensure:
		 * - The PLL cannot be set to 44 unless the CCK or DYNAMIC
		 *   mode bit is set
		 * - Turbo cannot be set at the same time as CCK or DYNAMIC
		 */
		if (IEEE80211_IS_CHAN_CCK(chan)) {
			OS_REG_WRITE(ah, AR_PHY_TURBO, turbo);
			OS_REG_WRITE(ah, AR_PHY_MODE, rfMode);
			if (curPhyPLL != phyPLL) {
				OS_REG_WRITE(ah,  AR_PHY_PLL_CTL,  phyPLL);
				/* Wait for the PLL to settle */
				OS_DELAY(PLL_SETTLE_DELAY);
			}
		} else {
			if (curPhyPLL != phyPLL) {
				OS_REG_WRITE(ah,  AR_PHY_PLL_CTL,  phyPLL);
				/* Wait for the PLL to settle */
				OS_DELAY(PLL_SETTLE_DELAY);
			}
			OS_REG_WRITE(ah, AR_PHY_TURBO, turbo);
			OS_REG_WRITE(ah, AR_PHY_MODE, rfMode);
		}
	}
	return AH_TRUE;
}
Пример #16
0
void
ar9280_init_from_rom(struct athn_softc *sc, struct ieee80211_channel *c,
    struct ieee80211_channel *extc)
{
	static const uint32_t chainoffset[] = { 0x0000, 0x2000, 0x1000 };
	const struct ar5416_eeprom *eep = sc->eep;
	const struct ar5416_modal_eep_header *modal;
	uint32_t reg, offset;
	uint8_t txRxAtten;
	int i;

	modal = &eep->modalHeader[IEEE80211_IS_CHAN_2GHZ(c)];

	AR_WRITE(sc, AR_PHY_SWITCH_COM, modal->antCtrlCommon);

	for (i = 0; i < AR9280_MAX_CHAINS; i++) {
		if (sc->rxchainmask == 0x5 || sc->txchainmask == 0x5)
			offset = chainoffset[i];
		else
			offset = i * 0x1000;

		AR_WRITE(sc, AR_PHY_SWITCH_CHAIN_0 + offset,
		    modal->antCtrlChain[i]);

		reg = AR_READ(sc, AR_PHY_TIMING_CTRL4_0 + offset);
		reg = RW(reg, AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF,
		    modal->iqCalICh[i]);
		reg = RW(reg, AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF,
		    modal->iqCalQCh[i]);
		AR_WRITE(sc, AR_PHY_TIMING_CTRL4_0 + offset, reg);

		if (sc->eep_rev >= AR_EEP_MINOR_VER_3) {
			reg = AR_READ(sc, AR_PHY_GAIN_2GHZ + offset);
			reg = RW(reg, AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN,
			    modal->bswMargin[i]);
			reg = RW(reg, AR_PHY_GAIN_2GHZ_XATTEN1_DB,
			    modal->bswAtten[i]);
			reg = RW(reg, AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN,
			    modal->xatten2Margin[i]);
			reg = RW(reg, AR_PHY_GAIN_2GHZ_XATTEN2_DB,
			    modal->xatten2Db[i]);
			AR_WRITE(sc, AR_PHY_GAIN_2GHZ + offset, reg);
		}
		if (sc->eep_rev >= AR_EEP_MINOR_VER_3)
			txRxAtten = modal->txRxAttenCh[i];
		else	/* Workaround for ROM versions < 14.3. */
			txRxAtten = IEEE80211_IS_CHAN_2GHZ(c) ? 23 : 44;
		reg = AR_READ(sc, AR_PHY_RXGAIN + offset);
		reg = RW(reg, AR9280_PHY_RXGAIN_TXRX_ATTEN,
		    txRxAtten);
		reg = RW(reg, AR9280_PHY_RXGAIN_TXRX_MARGIN,
		    modal->rxTxMarginCh[i]);
		AR_WRITE(sc, AR_PHY_RXGAIN + offset, reg);
	}
	if (IEEE80211_IS_CHAN_2GHZ(c)) {
		reg = AR_READ(sc, AR_AN_RF2G1_CH0);
		reg = RW(reg, AR_AN_RF2G1_CH0_OB, modal->ob);
		reg = RW(reg, AR_AN_RF2G1_CH0_DB, modal->db);
		AR_WRITE(sc, AR_AN_RF2G1_CH0, reg);
		AR_WRITE_BARRIER(sc);
		DELAY(100);

		reg = AR_READ(sc, AR_AN_RF2G1_CH1);
		reg = RW(reg, AR_AN_RF2G1_CH1_OB, modal->ob_ch1);
		reg = RW(reg, AR_AN_RF2G1_CH1_DB, modal->db_ch1);
		AR_WRITE(sc, AR_AN_RF2G1_CH1, reg);
		AR_WRITE_BARRIER(sc);
		DELAY(100);
	} else {
		reg = AR_READ(sc, AR_AN_RF5G1_CH0);
		reg = RW(reg, AR_AN_RF5G1_CH0_OB5, modal->ob);
		reg = RW(reg, AR_AN_RF5G1_CH0_DB5, modal->db);
		AR_WRITE(sc, AR_AN_RF5G1_CH0, reg);
		AR_WRITE_BARRIER(sc);
		DELAY(100);

		reg = AR_READ(sc, AR_AN_RF5G1_CH1);
		reg = RW(reg, AR_AN_RF5G1_CH1_OB5, modal->ob_ch1);
		reg = RW(reg, AR_AN_RF5G1_CH1_DB5, modal->db_ch1);
		AR_WRITE(sc, AR_AN_RF5G1_CH1, reg);
		AR_WRITE_BARRIER(sc);
		DELAY(100);
	}
	reg = AR_READ(sc, AR_AN_TOP2);
	if ((sc->flags & ATHN_FLAG_USB) && IEEE80211_IS_CHAN_5GHZ(c)) {
		/*
		 * Hardcode the output voltage of x-PA bias LDO to the
		 * lowest value for UB94 such that the card doesn't get
		 * too hot.
		 */
		reg = RW(reg, AR_AN_TOP2_XPABIAS_LVL, 0);
	} else
		reg = RW(reg, AR_AN_TOP2_XPABIAS_LVL, modal->xpaBiasLvl);
	if (modal->flagBits & AR5416_EEP_FLAG_LOCALBIAS)
		reg |= AR_AN_TOP2_LOCALBIAS;
	else
		reg &= ~AR_AN_TOP2_LOCALBIAS;
	AR_WRITE(sc, AR_AN_TOP2, reg);
	AR_WRITE_BARRIER(sc);
	DELAY(100);

	reg = AR_READ(sc, AR_PHY_XPA_CFG);
	if (modal->flagBits & AR5416_EEP_FLAG_FORCEXPAON)
		reg |= AR_PHY_FORCE_XPA_CFG;
	else
		reg &= ~AR_PHY_FORCE_XPA_CFG;
	AR_WRITE(sc, AR_PHY_XPA_CFG, reg);

	reg = AR_READ(sc, AR_PHY_SETTLING);
	reg = RW(reg, AR_PHY_SETTLING_SWITCH, modal->switchSettling);
	AR_WRITE(sc, AR_PHY_SETTLING, reg);

	reg = AR_READ(sc, AR_PHY_DESIRED_SZ);
	reg = RW(reg, AR_PHY_DESIRED_SZ_ADC, modal->adcDesiredSize);
	AR_WRITE(sc, AR_PHY_DESIRED_SZ, reg);

	reg =  SM(AR_PHY_RF_CTL4_TX_END_XPAA_OFF, modal->txEndToXpaOff);
	reg |= SM(AR_PHY_RF_CTL4_TX_END_XPAB_OFF, modal->txEndToXpaOff);
	reg |= SM(AR_PHY_RF_CTL4_FRAME_XPAA_ON, modal->txFrameToXpaOn);
	reg |= SM(AR_PHY_RF_CTL4_FRAME_XPAB_ON, modal->txFrameToXpaOn);
	AR_WRITE(sc, AR_PHY_RF_CTL4, reg);

	reg = AR_READ(sc, AR_PHY_RF_CTL3);
	reg = RW(reg, AR_PHY_TX_END_TO_A2_RX_ON, modal->txEndToRxOn);
	AR_WRITE(sc, AR_PHY_RF_CTL3, reg);

	reg = AR_READ(sc, AR_PHY_CCA(0));
	reg = RW(reg, AR9280_PHY_CCA_THRESH62, modal->thresh62);
	AR_WRITE(sc, AR_PHY_CCA(0), reg);

	reg = AR_READ(sc, AR_PHY_EXT_CCA0);
	reg = RW(reg, AR_PHY_EXT_CCA0_THRESH62, modal->thresh62);
	AR_WRITE(sc, AR_PHY_EXT_CCA0, reg);

	if (sc->eep_rev >= AR_EEP_MINOR_VER_2) {
		reg = AR_READ(sc, AR_PHY_RF_CTL2);
		reg = RW(reg, AR_PHY_TX_END_DATA_START,
		    modal->txFrameToDataStart);
		reg = RW(reg, AR_PHY_TX_END_PA_ON, modal->txFrameToPaOn);
		AR_WRITE(sc, AR_PHY_RF_CTL2, reg);
	}
#ifndef IEEE80211_NO_HT
	if (sc->eep_rev >= AR_EEP_MINOR_VER_3 && extc != NULL) {
		/* Overwrite switch settling with HT-40 value. */
		reg = AR_READ(sc, AR_PHY_SETTLING);
		reg = RW(reg, AR_PHY_SETTLING_SWITCH, modal->swSettleHt40);
		AR_WRITE(sc, AR_PHY_SETTLING, reg);
	}
#endif
	if (sc->eep_rev >= AR_EEP_MINOR_VER_19) {
		reg = AR_READ(sc, AR_PHY_CCK_TX_CTRL);
		reg = RW(reg, AR_PHY_CCK_TX_CTRL_TX_DAC_SCALE_CCK,
		    MS(modal->miscBits, AR5416_EEP_MISC_TX_DAC_SCALE_CCK));
		AR_WRITE(sc, AR_PHY_CCK_TX_CTRL, reg);
	}
	if (AR_SREV_9280_20(sc) &&
	    sc->eep_rev >= AR_EEP_MINOR_VER_20) {
		reg = AR_READ(sc, AR_AN_TOP1);
		if (eep->baseEepHeader.dacLpMode &&
		    (IEEE80211_IS_CHAN_2GHZ(c) ||
		     !eep->baseEepHeader.dacHiPwrMode_5G))
			reg |= AR_AN_TOP1_DACLPMODE;
		else
			reg &= ~AR_AN_TOP1_DACLPMODE;
		AR_WRITE(sc, AR_AN_TOP1, reg);
		AR_WRITE_BARRIER(sc);
		DELAY(100);

		reg = AR_READ(sc, AR_PHY_FRAME_CTL);
		reg = RW(reg, AR_PHY_FRAME_CTL_TX_CLIP,
		    MS(modal->miscBits, AR5416_EEP_MISC_TX_CLIP));
		AR_WRITE(sc, AR_PHY_FRAME_CTL, reg);

		reg = AR_READ(sc, AR_PHY_TX_PWRCTRL9);
		reg = RW(reg, AR_PHY_TX_DESIRED_SCALE_CCK,
		    eep->baseEepHeader.desiredScaleCCK);
		AR_WRITE(sc, AR_PHY_TX_PWRCTRL9, reg);
	}
	AR_WRITE_BARRIER(sc);
}
Пример #17
0
void
ar9380_init_from_rom(struct athn_softc *sc, struct ieee80211_channel *c,
    struct ieee80211_channel *extc)
{
	const struct ar9380_eeprom *eep = sc->eep;
	const struct ar9380_modal_eep_header *modal;
	uint8_t db, margin, ant_div_ctrl;
	uint32_t reg;
	int i, maxchains;

	if (IEEE80211_IS_CHAN_2GHZ(c))
		modal = &eep->modalHeader2G;
	else
		modal = &eep->modalHeader5G;

	/* Apply XPA bias level. */
	if (AR_SREV_9485(sc)) {
		reg = AR_READ(sc, AR9485_PHY_65NM_CH0_TOP2);
		reg = RW(reg, AR9485_PHY_65NM_CH0_TOP2_XPABIASLVL,
		    modal->xpaBiasLvl);
		AR_WRITE(sc, AR9485_PHY_65NM_CH0_TOP2, reg);
	} else {
		reg = AR_READ(sc, AR_PHY_65NM_CH0_TOP);
		reg = RW(reg, AR_PHY_65NM_CH0_TOP_XPABIASLVL,
		    modal->xpaBiasLvl & 0x3);
		AR_WRITE(sc, AR_PHY_65NM_CH0_TOP, reg);
		reg = AR_READ(sc, AR_PHY_65NM_CH0_THERM);
		reg = RW(reg, AR_PHY_65NM_CH0_THERM_XPABIASLVL_MSB,
		    modal->xpaBiasLvl >> 2);
		reg |= AR_PHY_65NM_CH0_THERM_XPASHORT2GND;
		AR_WRITE(sc, AR_PHY_65NM_CH0_THERM, reg);
	}

	/* Apply antenna control. */
	reg = AR_READ(sc, AR_PHY_SWITCH_COM);
	reg = RW(reg, AR_SWITCH_TABLE_COM_ALL, modal->antCtrlCommon);
	AR_WRITE(sc, AR_PHY_SWITCH_COM, reg);
	reg = AR_READ(sc, AR_PHY_SWITCH_COM_2);
	reg = RW(reg, AR_SWITCH_TABLE_COM_2_ALL, modal->antCtrlCommon2);
	AR_WRITE(sc, AR_PHY_SWITCH_COM_2, reg);

	maxchains = AR_SREV_9485(sc) ? 1 : AR9380_MAX_CHAINS;
	for (i = 0; i < maxchains; i++) {
		reg = AR_READ(sc, AR_PHY_SWITCH_CHAIN(i));
		reg = RW(reg, AR_SWITCH_TABLE_ALL, modal->antCtrlChain[i]);
		AR_WRITE(sc, AR_PHY_SWITCH_CHAIN(i), reg);
	}

	if (AR_SREV_9485(sc)) {
		ant_div_ctrl = eep->base_ext1.ant_div_control;
		reg = AR_READ(sc, AR_PHY_MC_GAIN_CTRL);
		reg = RW(reg, AR_PHY_MC_GAIN_CTRL_ANT_DIV_CTRL_ALL,
		    MS(ant_div_ctrl, AR_EEP_ANT_DIV_CTRL_ALL));
		if (ant_div_ctrl & AR_EEP_ANT_DIV_CTRL_ANT_DIV)
			reg |= AR_PHY_MC_GAIN_CTRL_ENABLE_ANT_DIV;
		else
			reg &= ~AR_PHY_MC_GAIN_CTRL_ENABLE_ANT_DIV;
		AR_WRITE(sc, AR_PHY_MC_GAIN_CTRL, reg);
		reg = AR_READ(sc, AR_PHY_CCK_DETECT);
		if (ant_div_ctrl & AR_EEP_ANT_DIV_CTRL_FAST_DIV)
			reg |= AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV;
		else
			reg &= ~AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV;
		AR_WRITE(sc, AR_PHY_CCK_DETECT, reg);
	}

	if (eep->baseEepHeader.miscConfiguration & AR_EEP_DRIVE_STRENGTH) {
		/* Apply drive strength. */
		reg = AR_READ(sc, AR_PHY_65NM_CH0_BIAS1);
		reg = RW(reg, AR_PHY_65NM_CH0_BIAS1_0, 5);
		reg = RW(reg, AR_PHY_65NM_CH0_BIAS1_1, 5);
		reg = RW(reg, AR_PHY_65NM_CH0_BIAS1_2, 5);
		reg = RW(reg, AR_PHY_65NM_CH0_BIAS1_3, 5);
		reg = RW(reg, AR_PHY_65NM_CH0_BIAS1_4, 5);
		reg = RW(reg, AR_PHY_65NM_CH0_BIAS1_5, 5);
		AR_WRITE(sc, AR_PHY_65NM_CH0_BIAS1, reg);

		reg = AR_READ(sc, AR_PHY_65NM_CH0_BIAS2);
		reg = RW(reg, AR_PHY_65NM_CH0_BIAS2_0, 5);
		reg = RW(reg, AR_PHY_65NM_CH0_BIAS2_1, 5);
		reg = RW(reg, AR_PHY_65NM_CH0_BIAS2_2, 5);
		reg = RW(reg, AR_PHY_65NM_CH0_BIAS2_3, 5);
		reg = RW(reg, AR_PHY_65NM_CH0_BIAS2_4, 5);
		reg = RW(reg, AR_PHY_65NM_CH0_BIAS2_5, 5);
		reg = RW(reg, AR_PHY_65NM_CH0_BIAS2_6, 5);
		reg = RW(reg, AR_PHY_65NM_CH0_BIAS2_7, 5);
		reg = RW(reg, AR_PHY_65NM_CH0_BIAS2_8, 5);
		AR_WRITE(sc, AR_PHY_65NM_CH0_BIAS2, reg);

		reg = AR_READ(sc, AR_PHY_65NM_CH0_BIAS4);
		reg = RW(reg, AR_PHY_65NM_CH0_BIAS4_0, 5);
		reg = RW(reg, AR_PHY_65NM_CH0_BIAS4_1, 5);
		reg = RW(reg, AR_PHY_65NM_CH0_BIAS4_2, 5);
		AR_WRITE(sc, AR_PHY_65NM_CH0_BIAS4, reg);
	}

	/* Apply attenuation settings. */
	maxchains = AR_SREV_9485(sc) ? 1 : AR9380_MAX_CHAINS;
	for (i = 0; i < maxchains; i++) {
		if (IEEE80211_IS_CHAN_5GHZ(c) &&
		    eep->base_ext2.xatten1DBLow[i] != 0) {
			if (c->ic_freq <= 5500) {
				db = athn_interpolate(c->ic_freq,
				    5180, eep->base_ext2.xatten1DBLow[i],
				    5500, modal->xatten1DB[i]);
			} else {
				db = athn_interpolate(c->ic_freq,
				    5500, modal->xatten1DB[i],
				    5785, eep->base_ext2.xatten1DBHigh[i]);
			}
		} else
			db = modal->xatten1DB[i];
		if (IEEE80211_IS_CHAN_5GHZ(c) &&
		    eep->base_ext2.xatten1MarginLow[i] != 0) {
			if (c->ic_freq <= 5500) {
				margin = athn_interpolate(c->ic_freq,
				    5180, eep->base_ext2.xatten1MarginLow[i],
				    5500, modal->xatten1Margin[i]);
			} else {
				margin = athn_interpolate(c->ic_freq,
				    5500, modal->xatten1Margin[i],
				    5785, eep->base_ext2.xatten1MarginHigh[i]);
			}
		} else
			margin = modal->xatten1Margin[i];
		reg = AR_READ(sc, AR_PHY_EXT_ATTEN_CTL(i));
		reg = RW(reg, AR_PHY_EXT_ATTEN_CTL_XATTEN1_DB, db);
		reg = RW(reg, AR_PHY_EXT_ATTEN_CTL_XATTEN1_MARGIN, margin);
		AR_WRITE(sc, AR_PHY_EXT_ATTEN_CTL(i), reg);
	}

	/* Initialize switching regulator. */
	if (AR_SREV_9485(sc))
		ar9485_init_swreg(sc);
	else
		ar9485_init_swreg(sc);

	/* Apply tuning capabilities. */
	if (AR_SREV_9485(sc) &&
	    (eep->baseEepHeader.featureEnable & AR_EEP_TUNING_CAPS)) {
		reg = AR_READ(sc, AR9485_PHY_CH0_XTAL);
		reg = RW(reg, AR9485_PHY_CH0_XTAL_CAPINDAC,
		    eep->baseEepHeader.params_for_tuning_caps[0]);
		reg = RW(reg, AR9485_PHY_CH0_XTAL_CAPOUTDAC,
		    eep->baseEepHeader.params_for_tuning_caps[0]);
		AR_WRITE(sc, AR9485_PHY_CH0_XTAL, reg);
	}
	AR_WRITE_BARRIER(sc);
}