Static void
ar9287_set_txpower(struct athn_softc *sc, struct ieee80211_channel *c,
    struct ieee80211_channel *extc)
{
	const struct ar9287_eeprom *eep = sc->sc_eep;
	const struct ar9287_modal_eep_header *modal = &eep->modalHeader;
	uint8_t tpow_cck[4], tpow_ofdm[4];
#ifndef IEEE80211_NO_HT
	uint8_t tpow_cck_ext[4], tpow_ofdm_ext[4];
	uint8_t tpow_ht20[8], tpow_ht40[8];
	uint8_t ht40inc;
#endif
	int16_t pwr = 0, max_ant_gain, power[ATHN_POWER_COUNT];
	int i;

	ar9287_set_power_calib(sc, c);

	/* Compute transmit power reduction due to antenna gain. */
	max_ant_gain = MAX(modal->antennaGainCh[0], modal->antennaGainCh[1]);
	/* XXX */

	/*
	 * Reduce scaled power by number of active chains to get per-chain
	 * transmit power level.
	 */
	if (sc->sc_ntxchains == 2)
		pwr -= AR_PWR_DECREASE_FOR_2_CHAIN;
	if (pwr < 0)
		pwr = 0;

	/* Get CCK target powers. */
	ar5008_get_lg_tpow(sc, c, AR_CTL_11B, eep->calTargetPowerCck,
	    AR9287_NUM_2G_CCK_TARGET_POWERS, tpow_cck);

	/* Get OFDM target powers. */
	ar5008_get_lg_tpow(sc, c, AR_CTL_11G, eep->calTargetPower2G,
	    AR9287_NUM_2G_20_TARGET_POWERS, tpow_ofdm);

#ifndef IEEE80211_NO_HT
	/* Get HT-20 target powers. */
	ar5008_get_ht_tpow(sc, c, AR_CTL_2GHT20, eep->calTargetPower2GHT20,
	    AR9287_NUM_2G_20_TARGET_POWERS, tpow_ht20);

	if (extc != NULL) {
		/* Get HT-40 target powers. */
		ar5008_get_ht_tpow(sc, c, AR_CTL_2GHT40,
		    eep->calTargetPower2GHT40, AR9287_NUM_2G_40_TARGET_POWERS,
		    tpow_ht40);

		/* Get secondary channel CCK target powers. */
		ar5008_get_lg_tpow(sc, extc, AR_CTL_11B,
		    eep->calTargetPowerCck, AR9287_NUM_2G_CCK_TARGET_POWERS,
		    tpow_cck_ext);

		/* Get secondary channel OFDM target powers. */
		ar5008_get_lg_tpow(sc, extc, AR_CTL_11G,
		    eep->calTargetPower2G, AR9287_NUM_2G_20_TARGET_POWERS,
		    tpow_ofdm_ext);
	}
#endif

	memset(power, 0, sizeof(power));
	/* Shuffle target powers accross transmit rates. */
	power[ATHN_POWER_OFDM6   ] =
	power[ATHN_POWER_OFDM9   ] =
	power[ATHN_POWER_OFDM12  ] =
	power[ATHN_POWER_OFDM18  ] =
	power[ATHN_POWER_OFDM24  ] = tpow_ofdm[0];
	power[ATHN_POWER_OFDM36  ] = tpow_ofdm[1];
	power[ATHN_POWER_OFDM48  ] = tpow_ofdm[2];
	power[ATHN_POWER_OFDM54  ] = tpow_ofdm[3];
	power[ATHN_POWER_XR      ] = tpow_ofdm[0];
	power[ATHN_POWER_CCK1_LP ] = tpow_cck[0];
	power[ATHN_POWER_CCK2_LP ] =
	power[ATHN_POWER_CCK2_SP ] = tpow_cck[1];
	power[ATHN_POWER_CCK55_LP] =
	power[ATHN_POWER_CCK55_SP] = tpow_cck[2];
	power[ATHN_POWER_CCK11_LP] =
	power[ATHN_POWER_CCK11_SP] = tpow_cck[3];
#ifndef IEEE80211_NO_HT
	for (i = 0; i < nitems(tpow_ht20); i++)
		power[ATHN_POWER_HT20(i)] = tpow_ht20[i];
	if (extc != NULL) {
		/* Correct PAR difference between HT40 and HT20/Legacy. */
		if (sc->sc_eep_rev >= AR_EEP_MINOR_VER_2)
			ht40inc = modal->ht40PowerIncForPdadc;
		else
			ht40inc = AR_HT40_POWER_INC_FOR_PDADC;
		for (i = 0; i < nitems(tpow_ht40); i++)
			power[ATHN_POWER_HT40(i)] = tpow_ht40[i] + ht40inc;
		power[ATHN_POWER_OFDM_DUP] = tpow_ht40[0];
		power[ATHN_POWER_CCK_DUP ] = tpow_ht40[0];
		power[ATHN_POWER_OFDM_EXT] = tpow_ofdm_ext[0];
		if (IEEE80211_IS_CHAN_2GHZ(c))
			power[ATHN_POWER_CCK_EXT] = tpow_cck_ext[0];
	}
#endif

	for (i = 0; i < ATHN_POWER_COUNT; i++) {
		power[i] -= AR_PWR_TABLE_OFFSET_DB * 2;	/* In half dB. */
		if (power[i] > AR_MAX_RATE_POWER)
			power[i] = AR_MAX_RATE_POWER;
	}
	/* Commit transmit power values to hardware. */
	ar5008_write_txpower(sc, power);
}
Exemple #2
0
void
ar9380_set_txpower(struct athn_softc *sc, struct ieee80211_channel *c,
    struct ieee80211_channel *extc)
{
	const struct ar9380_eeprom *eep = sc->eep;
	uint8_t tpow_cck[4], tpow_ofdm[4];
	uint8_t tpow_ht20[14], tpow_ht40[14];
	int16_t power[ATHN_POWER_COUNT];

	if (IEEE80211_IS_CHAN_2GHZ(c)) {
		/* Get CCK target powers. */
		ar9003_get_lg_tpow(sc, c, AR_CTL_11B,
		    eep->calTargetFbinCck, eep->calTargetPowerCck,
		    AR9380_NUM_2G_CCK_TARGET_POWERS, tpow_cck);

		/* Get OFDM target powers. */
		ar9003_get_lg_tpow(sc, c, AR_CTL_11G,
		    eep->calTargetFbin2G, eep->calTargetPower2G,
		    AR9380_NUM_2G_20_TARGET_POWERS, tpow_ofdm);

		/* Get HT-20 target powers. */
		ar9003_get_ht_tpow(sc, c, AR_CTL_2GHT20,
		    eep->calTargetFbin2GHT20, eep->calTargetPower2GHT20,
		    AR9380_NUM_2G_20_TARGET_POWERS, tpow_ht20);

		if (extc != NULL) {
			/* Get HT-40 target powers. */
			ar9003_get_ht_tpow(sc, c, AR_CTL_2GHT40,
			    eep->calTargetFbin2GHT40,
			    eep->calTargetPower2GHT40,
			    AR9380_NUM_2G_40_TARGET_POWERS, tpow_ht40);
		}
	} else {
		/* Get OFDM target powers. */
		ar9003_get_lg_tpow(sc, c, AR_CTL_11A,
		    eep->calTargetFbin5G, eep->calTargetPower5G,
		    AR9380_NUM_5G_20_TARGET_POWERS, tpow_ofdm);

		/* Get HT-20 target powers. */
		ar9003_get_ht_tpow(sc, c, AR_CTL_5GHT20,
		    eep->calTargetFbin5GHT20, eep->calTargetPower5GHT20,
		    AR9380_NUM_5G_20_TARGET_POWERS, tpow_ht20);

		if (extc != NULL) {
			/* Get HT-40 target powers. */
			ar9003_get_ht_tpow(sc, c, AR_CTL_5GHT40,
			    eep->calTargetFbin5GHT40,
			    eep->calTargetPower5GHT40,
			    AR9380_NUM_5G_40_TARGET_POWERS, tpow_ht40);
		}
	}

	memset(power, 0, sizeof(power));
	/* Shuffle target powers accross transmit rates. */
	power[ATHN_POWER_OFDM6 ] =
	power[ATHN_POWER_OFDM9 ] =
	power[ATHN_POWER_OFDM12] =
	power[ATHN_POWER_OFDM18] =
	power[ATHN_POWER_OFDM24] = tpow_ofdm[0];
	power[ATHN_POWER_OFDM36] = tpow_ofdm[1];
	power[ATHN_POWER_OFDM48] = tpow_ofdm[2];
	power[ATHN_POWER_OFDM54] = tpow_ofdm[3];
	if (IEEE80211_IS_CHAN_2GHZ(c)) {
		power[ATHN_POWER_CCK1_LP ] =
		power[ATHN_POWER_CCK2_LP ] =
		power[ATHN_POWER_CCK2_SP ] =
		power[ATHN_POWER_CCK55_LP] = tpow_cck[0];
		power[ATHN_POWER_CCK55_SP] = tpow_cck[1];
		power[ATHN_POWER_CCK11_LP] = tpow_cck[2];
		power[ATHN_POWER_CCK11_SP] = tpow_cck[3];
	}
	/* Next entry covers MCS0, MCS8 and MCS16. */
	power[ATHN_POWER_HT20( 0)] = tpow_ht20[ 0];
	/* Next entry covers MCS1-3, MCS9-11 and MCS17-19. */
	power[ATHN_POWER_HT20( 1)] = tpow_ht20[ 1];
	power[ATHN_POWER_HT20( 4)] = tpow_ht20[ 2];
	power[ATHN_POWER_HT20( 5)] = tpow_ht20[ 3];
	power[ATHN_POWER_HT20( 6)] = tpow_ht20[ 4];
	power[ATHN_POWER_HT20( 7)] = tpow_ht20[ 5];
	power[ATHN_POWER_HT20(12)] = tpow_ht20[ 6];
	power[ATHN_POWER_HT20(13)] = tpow_ht20[ 7];
	power[ATHN_POWER_HT20(14)] = tpow_ht20[ 8];
	power[ATHN_POWER_HT20(15)] = tpow_ht20[ 9];
	power[ATHN_POWER_HT20(20)] = tpow_ht20[10];
	power[ATHN_POWER_HT20(21)] = tpow_ht20[11];
	power[ATHN_POWER_HT20(22)] = tpow_ht20[12];
	power[ATHN_POWER_HT20(23)] = tpow_ht20[13];
	if (extc != NULL) {
		/* Next entry covers MCS0, MCS8 and MCS16. */
		power[ATHN_POWER_HT40( 0)] = tpow_ht40[ 0];
		/* Next entry covers MCS1-3, MCS9-11 and MCS17-19. */
		power[ATHN_POWER_HT40( 1)] = tpow_ht40[ 1];
		power[ATHN_POWER_HT40( 4)] = tpow_ht40[ 2];
		power[ATHN_POWER_HT40( 5)] = tpow_ht40[ 3];
		power[ATHN_POWER_HT40( 6)] = tpow_ht40[ 4];
		power[ATHN_POWER_HT40( 7)] = tpow_ht40[ 5];
		power[ATHN_POWER_HT40(12)] = tpow_ht40[ 6];
		power[ATHN_POWER_HT40(13)] = tpow_ht40[ 7];
		power[ATHN_POWER_HT40(14)] = tpow_ht40[ 8];
		power[ATHN_POWER_HT40(15)] = tpow_ht40[ 9];
		power[ATHN_POWER_HT40(20)] = tpow_ht40[10];
		power[ATHN_POWER_HT40(21)] = tpow_ht40[11];
		power[ATHN_POWER_HT40(22)] = tpow_ht40[12];
		power[ATHN_POWER_HT40(23)] = tpow_ht40[13];
	}

	/* Write transmit power values to hardware. */
	ar9003_write_txpower(sc, power);

	/* Apply transmit power correction. */
	ar9380_set_correction(sc, c);
}