--- a/drivers/net/wireless/ath/ath9k/ar9003_paprd.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_paprd.c @@ -30,9 +30,69 @@ void ar9003_paprd_enable(struct ath_hw * } EXPORT_SYMBOL(ar9003_paprd_enable); -static void ar9003_paprd_setup_single_table(struct ath_hw *ah) +static int ar9003_get_training_power_2g(struct ath_hw *ah) { struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep; + struct ar9300_modal_eep_header *hdr = &eep->modalHeader2G; + unsigned int power, scale, delta; + + scale = MS(le32_to_cpu(hdr->papdRateMaskHt20), AR9300_PAPRD_SCALE_1); + power = REG_READ_FIELD(ah, AR_PHY_POWERTX_RATE5, + AR_PHY_POWERTX_RATE5_POWERTXHT20_0); + + delta = abs((int) ah->paprd_target_power - (int) power); + if (delta > scale) + return -1; + + if (delta < 4) + power -= 4 - delta; + + return power; +} + +static int get_streams(int mask) +{ + return !!(mask & BIT(0)) + !!(mask & BIT(1)) + !!(mask & BIT(2)); +} + +static int ar9003_get_training_power_5g(struct ath_hw *ah) +{ + struct ath_common *common = ath9k_hw_common(ah); + struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep; + struct ar9300_modal_eep_header *hdr = &eep->modalHeader5G; + struct ath9k_channel *chan = ah->curchan; + unsigned int power, scale, delta; + + if (chan->channel >= 5700) + scale = MS(le32_to_cpu(hdr->papdRateMaskHt20), + AR9300_PAPRD_SCALE_1); + else if (chan->channel >= 5400) + scale = MS(le32_to_cpu(hdr->papdRateMaskHt40), + AR9300_PAPRD_SCALE_2); + else + scale = MS(le32_to_cpu(hdr->papdRateMaskHt40), + AR9300_PAPRD_SCALE_1); + + if (IS_CHAN_HT40(chan)) + power = REG_READ_FIELD(ah, AR_PHY_POWERTX_RATE8, + AR_PHY_POWERTX_RATE8_POWERTXHT40_5); + else + power = REG_READ_FIELD(ah, AR_PHY_POWERTX_RATE6, + AR_PHY_POWERTX_RATE6_POWERTXHT20_5); + + power += scale; + delta = abs((int) ah->paprd_target_power - (int) power); + if (delta > scale) + return -1; + + power += 2 * get_streams(common->tx_chainmask); + return power; +} + +static int ar9003_paprd_setup_single_table(struct ath_hw *ah) +{ + struct ath_common *common = ath9k_hw_common(ah); + struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep; struct ar9300_modal_eep_header *hdr; static const u32 ctrl0[3] = { AR_PHY_PAPRD_CTRL0_B0, @@ -45,6 +105,7 @@ static void ar9003_paprd_setup_single_ta AR_PHY_PAPRD_CTRL1_B2 }; u32 am_mask, ht40_mask; + int training_power; int i; if (ah->curchan && IS_CHAN_5GHZ(ah->curchan)) @@ -55,11 +116,25 @@ static void ar9003_paprd_setup_single_ta am_mask = le32_to_cpu(hdr->papdRateMaskHt20) & AR9300_PAPRD_RATE_MASK; ht40_mask = le32_to_cpu(hdr->papdRateMaskHt40) & AR9300_PAPRD_RATE_MASK; + if (IS_CHAN_2GHZ(ah->curchan)) + training_power = ar9003_get_training_power_2g(ah); + else + training_power = ar9003_get_training_power_5g(ah); + + if (training_power < 0) { + ath_dbg(common, ATH_DBG_CALIBRATE, + "PAPRD target power delta out of range"); + return -ERANGE; + } + ah->paprd_training_power = training_power; + ath_dbg(common, ATH_DBG_CALIBRATE, + "Training power: %d, Target power: %d\n", + ah->paprd_training_power, ah->paprd_target_power); + REG_RMW_FIELD(ah, AR_PHY_PAPRD_AM2AM, AR_PHY_PAPRD_AM2AM_MASK, am_mask); REG_RMW_FIELD(ah, AR_PHY_PAPRD_AM2PM, AR_PHY_PAPRD_AM2PM_MASK, am_mask); REG_RMW_FIELD(ah, AR_PHY_PAPRD_HT40, AR_PHY_PAPRD_HT40_MASK, ht40_mask); - for (i = 0; i < ah->caps.max_txchains; i++) { REG_RMW_FIELD(ah, ctrl0[i], AR_PHY_PAPRD_CTRL0_USE_SINGLE_TABLE_MASK, 1); @@ -141,6 +216,7 @@ static void ar9003_paprd_setup_single_ta AR_PHY_PAPRD_PRE_POST_SCALING, 185706); REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_7_B0, AR_PHY_PAPRD_PRE_POST_SCALING, 175487); + return 0; } static void ar9003_paprd_get_gain_table(struct ath_hw *ah) @@ -595,15 +671,10 @@ void ar9003_paprd_populate_single_table( { u32 *paprd_table_val = caldata->pa_table[chain]; u32 small_signal_gain = caldata->small_signal_gain[chain]; - u32 training_power; + u32 training_power = ah->paprd_training_power; u32 reg = 0; int i; - training_power = - REG_READ_FIELD(ah, AR_PHY_POWERTX_RATE5, - AR_PHY_POWERTX_RATE5_POWERTXHT20_0); - training_power -= 4; - if (chain == 0) reg = AR_PHY_PAPRD_MEM_TAB_B0; else if (chain == 1) @@ -643,14 +714,8 @@ EXPORT_SYMBOL(ar9003_paprd_populate_sing int ar9003_paprd_setup_gain_table(struct ath_hw *ah, int chain) { - unsigned int i, desired_gain, gain_index; - unsigned int train_power; - - train_power = REG_READ_FIELD(ah, AR_PHY_POWERTX_RATE5, - AR_PHY_POWERTX_RATE5_POWERTXHT20_0); - - train_power = train_power - 4; + unsigned int train_power = ah->paprd_training_power; desired_gain = ar9003_get_desired_gain(ah, chain, train_power); @@ -716,7 +781,12 @@ EXPORT_SYMBOL(ar9003_paprd_create_curve) int ar9003_paprd_init_table(struct ath_hw *ah) { - ar9003_paprd_setup_single_table(ah); + int ret; + + ret = ar9003_paprd_setup_single_table(ah); + if (ret < 0) + return ret; + ar9003_paprd_get_gain_table(ah); return 0; } --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -835,6 +835,8 @@ struct ath_hw { u32 bb_watchdog_last_status; u32 bb_watchdog_timeout_ms; /* in ms, 0 to disable */ + unsigned int paprd_target_power; + unsigned int paprd_training_power; u32 paprd_gain_table_entries[PAPRD_GAIN_TABLE_ENTRIES]; u8 paprd_gain_table_index[PAPRD_GAIN_TABLE_ENTRIES]; /* --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.h @@ -1090,6 +1090,14 @@ #define AR_PHY_POWERTX_RATE5_POWERTXHT20_0 0x3F #define AR_PHY_POWERTX_RATE5_POWERTXHT20_0_S 0 +#define AR_PHY_POWERTX_RATE6 (AR_SM_BASE + 0x1d4) +#define AR_PHY_POWERTX_RATE6_POWERTXHT20_5 0x3F00 +#define AR_PHY_POWERTX_RATE6_POWERTXHT20_5_S 8 + +#define AR_PHY_POWERTX_RATE8 (AR_SM_BASE + 0x1dc) +#define AR_PHY_POWERTX_RATE8_POWERTXHT40_5 0x3F00 +#define AR_PHY_POWERTX_RATE8_POWERTXHT40_5_S 8 + void ar9003_hw_set_chain_masks(struct ath_hw *ah, u8 rx, u8 tx); #endif /* AR9003_PHY_H */ --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c @@ -4798,6 +4798,19 @@ static void ath9k_hw_ar9300_set_txpower( /* Write target power array to registers */ ar9003_hw_tx_power_regwrite(ah, targetPowerValT2); ar9003_hw_calibration_apply(ah, chan->channel); + + if (IS_CHAN_2GHZ(chan)) { + if (IS_CHAN_HT40(chan)) + i = ALL_TARGET_HT40_0_8_16; + else + i = ALL_TARGET_HT20_0_8_16; + } else { + if (IS_CHAN_HT40(chan)) + i = ALL_TARGET_HT40_7; + else + i = ALL_TARGET_HT20_7; + } + ah->paprd_target_power = targetPowerValT2[i]; } static u16 ath9k_hw_ar9300_get_spur_channel(struct ath_hw *ah, --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -373,6 +373,9 @@ void ath_paprd_calibrate(struct work_str if (!caldata) return; + if (ar9003_paprd_init_table(ah) < 0) + return; + skb = alloc_skb(len, GFP_KERNEL); if (!skb) return; @@ -388,7 +391,6 @@ void ath_paprd_calibrate(struct work_str memcpy(hdr->addr3, hw->wiphy->perm_addr, ETH_ALEN); ath9k_ps_wakeup(sc); - ar9003_paprd_init_table(ah); for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) { if (!(common->tx_chainmask & BIT(chain))) continue;