Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9e33a355 authored by Helmut Schaa's avatar Helmut Schaa Committed by John W. Linville
Browse files

rt2x00: Implement tx power temperature compensation



rt2800 devices should adjust their tx power in accordance with the
eeproms temperature calibration values. Add a new driver callback
gain_calibration that is called every 4 seconds.

The rt2800 gain calibration routine simply runs the tx power
configuration that takes care of calculating the temperature
compensation delta.

We don't need to synchronize the calls to rt2800_config_txpower
as they should all happen from mac80211's single threaded workqueue.

Signed-off-by: default avatarHelmut Schaa <helmut.schaa@googlemail.com>
Signed-off-by: default avatarIvo van Doorn <IvDoorn@gmail.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 2f2bb7e8
Loading
Loading
Loading
Loading
+106 −0
Original line number Diff line number Diff line
@@ -2103,6 +2103,59 @@ struct mac_iveiv_entry {
#define EEPROM_TXPOWER_BG_1		FIELD16(0x00ff)
#define EEPROM_TXPOWER_BG_2		FIELD16(0xff00)

/*
 * EEPROM temperature compensation boundaries 802.11BG
 * MINUS4: If the actual TSSI is below this boundary, tx power needs to be
 *         reduced by (agc_step * -4)
 * MINUS3: If the actual TSSI is below this boundary, tx power needs to be
 *         reduced by (agc_step * -3)
 */
#define EEPROM_TSSI_BOUND_BG1		0x0037
#define EEPROM_TSSI_BOUND_BG1_MINUS4	FIELD16(0x00ff)
#define EEPROM_TSSI_BOUND_BG1_MINUS3	FIELD16(0xff00)

/*
 * EEPROM temperature compensation boundaries 802.11BG
 * MINUS2: If the actual TSSI is below this boundary, tx power needs to be
 *         reduced by (agc_step * -2)
 * MINUS1: If the actual TSSI is below this boundary, tx power needs to be
 *         reduced by (agc_step * -1)
 */
#define EEPROM_TSSI_BOUND_BG2		0x0038
#define EEPROM_TSSI_BOUND_BG2_MINUS2	FIELD16(0x00ff)
#define EEPROM_TSSI_BOUND_BG2_MINUS1	FIELD16(0xff00)

/*
 * EEPROM temperature compensation boundaries 802.11BG
 * REF: Reference TSSI value, no tx power changes needed
 * PLUS1: If the actual TSSI is above this boundary, tx power needs to be
 *        increased by (agc_step * 1)
 */
#define EEPROM_TSSI_BOUND_BG3		0x0039
#define EEPROM_TSSI_BOUND_BG3_REF	FIELD16(0x00ff)
#define EEPROM_TSSI_BOUND_BG3_PLUS1	FIELD16(0xff00)

/*
 * EEPROM temperature compensation boundaries 802.11BG
 * PLUS2: If the actual TSSI is above this boundary, tx power needs to be
 *        increased by (agc_step * 2)
 * PLUS3: If the actual TSSI is above this boundary, tx power needs to be
 *        increased by (agc_step * 3)
 */
#define EEPROM_TSSI_BOUND_BG4		0x003a
#define EEPROM_TSSI_BOUND_BG4_PLUS2	FIELD16(0x00ff)
#define EEPROM_TSSI_BOUND_BG4_PLUS3	FIELD16(0xff00)

/*
 * EEPROM temperature compensation boundaries 802.11BG
 * PLUS4: If the actual TSSI is above this boundary, tx power needs to be
 *        increased by (agc_step * 4)
 * AGC_STEP: Temperature compensation step.
 */
#define EEPROM_TSSI_BOUND_BG5		0x003b
#define EEPROM_TSSI_BOUND_BG5_PLUS4	FIELD16(0x00ff)
#define EEPROM_TSSI_BOUND_BG5_AGC_STEP	FIELD16(0xff00)

/*
 * EEPROM TXPOWER 802.11A
 */
@@ -2112,6 +2165,59 @@ struct mac_iveiv_entry {
#define EEPROM_TXPOWER_A_1		FIELD16(0x00ff)
#define EEPROM_TXPOWER_A_2		FIELD16(0xff00)

/*
 * EEPROM temperature compensation boundaries 802.11A
 * MINUS4: If the actual TSSI is below this boundary, tx power needs to be
 *         reduced by (agc_step * -4)
 * MINUS3: If the actual TSSI is below this boundary, tx power needs to be
 *         reduced by (agc_step * -3)
 */
#define EEPROM_TSSI_BOUND_A1		0x006a
#define EEPROM_TSSI_BOUND_A1_MINUS4	FIELD16(0x00ff)
#define EEPROM_TSSI_BOUND_A1_MINUS3	FIELD16(0xff00)

/*
 * EEPROM temperature compensation boundaries 802.11A
 * MINUS2: If the actual TSSI is below this boundary, tx power needs to be
 *         reduced by (agc_step * -2)
 * MINUS1: If the actual TSSI is below this boundary, tx power needs to be
 *         reduced by (agc_step * -1)
 */
#define EEPROM_TSSI_BOUND_A2		0x006b
#define EEPROM_TSSI_BOUND_A2_MINUS2	FIELD16(0x00ff)
#define EEPROM_TSSI_BOUND_A2_MINUS1	FIELD16(0xff00)

/*
 * EEPROM temperature compensation boundaries 802.11A
 * REF: Reference TSSI value, no tx power changes needed
 * PLUS1: If the actual TSSI is above this boundary, tx power needs to be
 *        increased by (agc_step * 1)
 */
#define EEPROM_TSSI_BOUND_A3		0x006c
#define EEPROM_TSSI_BOUND_A3_REF	FIELD16(0x00ff)
#define EEPROM_TSSI_BOUND_A3_PLUS1	FIELD16(0xff00)

/*
 * EEPROM temperature compensation boundaries 802.11A
 * PLUS2: If the actual TSSI is above this boundary, tx power needs to be
 *        increased by (agc_step * 2)
 * PLUS3: If the actual TSSI is above this boundary, tx power needs to be
 *        increased by (agc_step * 3)
 */
#define EEPROM_TSSI_BOUND_A4		0x006d
#define EEPROM_TSSI_BOUND_A4_PLUS2	FIELD16(0x00ff)
#define EEPROM_TSSI_BOUND_A4_PLUS3	FIELD16(0xff00)

/*
 * EEPROM temperature compensation boundaries 802.11A
 * PLUS4: If the actual TSSI is above this boundary, tx power needs to be
 *        increased by (agc_step * 4)
 * AGC_STEP: Temperature compensation step.
 */
#define EEPROM_TSSI_BOUND_A5		0x006e
#define EEPROM_TSSI_BOUND_A5_PLUS4	FIELD16(0x00ff)
#define EEPROM_TSSI_BOUND_A5_AGC_STEP	FIELD16(0xff00)

/*
 * EEPROM TXPOWER by rate: tx power per tx rate for HT20 mode
 */
+128 −5
Original line number Diff line number Diff line
@@ -1813,6 +1813,116 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev,
	rt2800_register_read(rt2x00dev, CH_BUSY_STA_SEC, &reg);
}

static int rt2800_get_gain_calibration_delta(struct rt2x00_dev *rt2x00dev)
{
	u8 tssi_bounds[9];
	u8 current_tssi;
	u16 eeprom;
	u8 step;
	int i;

	/*
	 * Read TSSI boundaries for temperature compensation from
	 * the EEPROM.
	 *
	 * Array idx               0    1    2    3    4    5    6    7    8
	 * Matching Delta value   -4   -3   -2   -1    0   +1   +2   +3   +4
	 * Example TSSI bounds  0xF0 0xD0 0xB5 0xA0 0x88 0x45 0x25 0x15 0x00
	 */
	if (rt2x00dev->curr_band == IEEE80211_BAND_2GHZ) {
		rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_BG1, &eeprom);
		tssi_bounds[0] = rt2x00_get_field16(eeprom,
					EEPROM_TSSI_BOUND_BG1_MINUS4);
		tssi_bounds[1] = rt2x00_get_field16(eeprom,
					EEPROM_TSSI_BOUND_BG1_MINUS3);

		rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_BG2, &eeprom);
		tssi_bounds[2] = rt2x00_get_field16(eeprom,
					EEPROM_TSSI_BOUND_BG2_MINUS2);
		tssi_bounds[3] = rt2x00_get_field16(eeprom,
					EEPROM_TSSI_BOUND_BG2_MINUS1);

		rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_BG3, &eeprom);
		tssi_bounds[4] = rt2x00_get_field16(eeprom,
					EEPROM_TSSI_BOUND_BG3_REF);
		tssi_bounds[5] = rt2x00_get_field16(eeprom,
					EEPROM_TSSI_BOUND_BG3_PLUS1);

		rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_BG4, &eeprom);
		tssi_bounds[6] = rt2x00_get_field16(eeprom,
					EEPROM_TSSI_BOUND_BG4_PLUS2);
		tssi_bounds[7] = rt2x00_get_field16(eeprom,
					EEPROM_TSSI_BOUND_BG4_PLUS3);

		rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_BG5, &eeprom);
		tssi_bounds[8] = rt2x00_get_field16(eeprom,
					EEPROM_TSSI_BOUND_BG5_PLUS4);

		step = rt2x00_get_field16(eeprom,
					  EEPROM_TSSI_BOUND_BG5_AGC_STEP);
	} else {
		rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_A1, &eeprom);
		tssi_bounds[0] = rt2x00_get_field16(eeprom,
					EEPROM_TSSI_BOUND_A1_MINUS4);
		tssi_bounds[1] = rt2x00_get_field16(eeprom,
					EEPROM_TSSI_BOUND_A1_MINUS3);

		rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_A2, &eeprom);
		tssi_bounds[2] = rt2x00_get_field16(eeprom,
					EEPROM_TSSI_BOUND_A2_MINUS2);
		tssi_bounds[3] = rt2x00_get_field16(eeprom,
					EEPROM_TSSI_BOUND_A2_MINUS1);

		rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_A3, &eeprom);
		tssi_bounds[4] = rt2x00_get_field16(eeprom,
					EEPROM_TSSI_BOUND_A3_REF);
		tssi_bounds[5] = rt2x00_get_field16(eeprom,
					EEPROM_TSSI_BOUND_A3_PLUS1);

		rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_A4, &eeprom);
		tssi_bounds[6] = rt2x00_get_field16(eeprom,
					EEPROM_TSSI_BOUND_A4_PLUS2);
		tssi_bounds[7] = rt2x00_get_field16(eeprom,
					EEPROM_TSSI_BOUND_A4_PLUS3);

		rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_A5, &eeprom);
		tssi_bounds[8] = rt2x00_get_field16(eeprom,
					EEPROM_TSSI_BOUND_A5_PLUS4);

		step = rt2x00_get_field16(eeprom,
					  EEPROM_TSSI_BOUND_A5_AGC_STEP);
	}

	/*
	 * Check if temperature compensation is supported.
	 */
	if (tssi_bounds[4] == 0xff)
		return 0;

	/*
	 * Read current TSSI (BBP 49).
	 */
	rt2800_bbp_read(rt2x00dev, 49, &current_tssi);

	/*
	 * Compare TSSI value (BBP49) with the compensation boundaries
	 * from the EEPROM and increase or decrease tx power.
	 */
	for (i = 0; i <= 3; i++) {
		if (current_tssi > tssi_bounds[i])
			break;
	}

	if (i == 4) {
		for (i = 8; i >= 5; i--) {
			if (current_tssi < tssi_bounds[i])
				break;
		}
	}

	return (i - 4) * step;
}

static int rt2800_get_txpower_bw_comp(struct rt2x00_dev *rt2x00dev,
				      enum ieee80211_band band)
{
@@ -1904,7 +2014,8 @@ static u8 rt2800_compensate_txpower(struct rt2x00_dev *rt2x00dev, int is_rate_b,
}

static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev,
				  struct ieee80211_conf *conf)
				  enum ieee80211_band band,
				  int power_level)
{
	u8 txpower;
	u16 eeprom;
@@ -1912,8 +2023,6 @@ static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev,
	u32 reg;
	u8 r1;
	u32 offset;
	enum ieee80211_band band = conf->channel->band;
	int power_level = conf->power_level;
	int delta;

	/*
@@ -1921,6 +2030,11 @@ static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev,
	 */
	delta = rt2800_get_txpower_bw_comp(rt2x00dev, band);

	/*
	 * calculate temperature compensation delta
	 */
	delta += rt2800_get_gain_calibration_delta(rt2x00dev);

	/*
	 * set to normal bbp tx power control mode: +/- 0dBm
	 */
@@ -2041,6 +2155,13 @@ static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev,
	}
}

void rt2800_gain_calibration(struct rt2x00_dev *rt2x00dev)
{
	rt2800_config_txpower(rt2x00dev, rt2x00dev->curr_band,
			      rt2x00dev->tx_power);
}
EXPORT_SYMBOL_GPL(rt2800_gain_calibration);

static void rt2800_config_retry_limit(struct rt2x00_dev *rt2x00dev,
				      struct rt2x00lib_conf *libconf)
{
@@ -2094,10 +2215,12 @@ void rt2800_config(struct rt2x00_dev *rt2x00dev,
	if (flags & IEEE80211_CONF_CHANGE_CHANNEL) {
		rt2800_config_channel(rt2x00dev, libconf->conf,
				      &libconf->rf, &libconf->channel);
		rt2800_config_txpower(rt2x00dev, libconf->conf);
		rt2800_config_txpower(rt2x00dev, libconf->conf->channel->band,
				      libconf->conf->power_level);
	}
	if (flags & IEEE80211_CONF_CHANGE_POWER)
		rt2800_config_txpower(rt2x00dev, libconf->conf);
		rt2800_config_txpower(rt2x00dev, libconf->conf->channel->band,
				      libconf->conf->power_level);
	if (flags & IEEE80211_CONF_CHANGE_RETRY_LIMITS)
		rt2800_config_retry_limit(rt2x00dev, libconf);
	if (flags & IEEE80211_CONF_CHANGE_PS)
+1 −0
Original line number Diff line number Diff line
@@ -181,6 +181,7 @@ void rt2800_link_stats(struct rt2x00_dev *rt2x00dev, struct link_qual *qual);
void rt2800_reset_tuner(struct rt2x00_dev *rt2x00dev, struct link_qual *qual);
void rt2800_link_tuner(struct rt2x00_dev *rt2x00dev, struct link_qual *qual,
		       const u32 count);
void rt2800_gain_calibration(struct rt2x00_dev *rt2x00dev);

int rt2800_enable_radio(struct rt2x00_dev *rt2x00dev);
void rt2800_disable_radio(struct rt2x00_dev *rt2x00dev);
+1 −0
Original line number Diff line number Diff line
@@ -1053,6 +1053,7 @@ static const struct rt2x00lib_ops rt2800pci_rt2x00_ops = {
	.link_stats		= rt2800_link_stats,
	.reset_tuner		= rt2800_reset_tuner,
	.link_tuner		= rt2800_link_tuner,
	.gain_calibration	= rt2800_gain_calibration,
	.start_queue		= rt2800pci_start_queue,
	.kick_queue		= rt2800pci_kick_queue,
	.stop_queue		= rt2800pci_stop_queue,
+1 −0
Original line number Diff line number Diff line
@@ -629,6 +629,7 @@ static const struct rt2x00lib_ops rt2800usb_rt2x00_ops = {
	.link_stats		= rt2800_link_stats,
	.reset_tuner		= rt2800_reset_tuner,
	.link_tuner		= rt2800_link_tuner,
	.gain_calibration	= rt2800_gain_calibration,
	.watchdog		= rt2800usb_watchdog,
	.start_queue		= rt2800usb_start_queue,
	.kick_queue		= rt2x00usb_kick_queue,
Loading