aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath/ath9k
diff options
context:
space:
mode:
authorFelix Fietkau <nbd@openwrt.org>2010-12-13 02:40:54 -0500
committerJohn W. Linville <linville@tuxdriver.com>2010-12-13 15:23:33 -0500
commit1bf38661822049931a0ab8d2b43153b26cc919f6 (patch)
treebea1bec029d0c8fa879dfef06a40798408c8f6dd /drivers/net/wireless/ath/ath9k
parent1782352d4908c79d195b43e0c1b6b109e0d93d05 (diff)
ath9k_hw: fix PA predistortion training power selection
The EEPROM contains scale factors for the tx power, which define the range of allowable difference between target power and training power. If the difference is too big, PA predistortion cannot be used. For 2.4 GHz there is only one scale factor, for 5 GHz there are three, depending on the specific frequency range. Signed-off-by: Felix Fietkau <nbd@openwrt.org> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/ath/ath9k')
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_eeprom.c13
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_paprd.c102
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_phy.h8
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.h2
-rw-r--r--drivers/net/wireless/ath/ath9k/main.c4
5 files changed, 112 insertions, 17 deletions
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
index 5ad37d05a85d..4149ffb6d54a 100644
--- 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(struct ath_hw *ah,
4798 /* Write target power array to registers */ 4798 /* Write target power array to registers */
4799 ar9003_hw_tx_power_regwrite(ah, targetPowerValT2); 4799 ar9003_hw_tx_power_regwrite(ah, targetPowerValT2);
4800 ar9003_hw_calibration_apply(ah, chan->channel); 4800 ar9003_hw_calibration_apply(ah, chan->channel);
4801
4802 if (IS_CHAN_2GHZ(chan)) {
4803 if (IS_CHAN_HT40(chan))
4804 i = ALL_TARGET_HT40_0_8_16;
4805 else
4806 i = ALL_TARGET_HT20_0_8_16;
4807 } else {
4808 if (IS_CHAN_HT40(chan))
4809 i = ALL_TARGET_HT40_7;
4810 else
4811 i = ALL_TARGET_HT20_7;
4812 }
4813 ah->paprd_target_power = targetPowerValT2[i];
4801} 4814}
4802 4815
4803static u16 ath9k_hw_ar9300_get_spur_channel(struct ath_hw *ah, 4816static u16 ath9k_hw_ar9300_get_spur_channel(struct ath_hw *ah,
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_paprd.c b/drivers/net/wireless/ath/ath9k/ar9003_paprd.c
index cdca4c3265b9..69f779237d28 100644
--- 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 *ah, bool val)
30} 30}
31EXPORT_SYMBOL(ar9003_paprd_enable); 31EXPORT_SYMBOL(ar9003_paprd_enable);
32 32
33static void ar9003_paprd_setup_single_table(struct ath_hw *ah) 33static int ar9003_get_training_power_2g(struct ath_hw *ah)
34{ 34{
35 struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep; 35 struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
36 struct ar9300_modal_eep_header *hdr = &eep->modalHeader2G;
37 unsigned int power, scale, delta;
38
39 scale = MS(le32_to_cpu(hdr->papdRateMaskHt20), AR9300_PAPRD_SCALE_1);
40 power = REG_READ_FIELD(ah, AR_PHY_POWERTX_RATE5,
41 AR_PHY_POWERTX_RATE5_POWERTXHT20_0);
42
43 delta = abs((int) ah->paprd_target_power - (int) power);
44 if (delta > scale)
45 return -1;
46
47 if (delta < 4)
48 power -= 4 - delta;
49
50 return power;
51}
52
53static int get_streams(int mask)
54{
55 return !!(mask & BIT(0)) + !!(mask & BIT(1)) + !!(mask & BIT(2));
56}
57
58static int ar9003_get_training_power_5g(struct ath_hw *ah)
59{
60 struct ath_common *common = ath9k_hw_common(ah);
61 struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
62 struct ar9300_modal_eep_header *hdr = &eep->modalHeader5G;
63 struct ath9k_channel *chan = ah->curchan;
64 unsigned int power, scale, delta;
65
66 if (chan->channel >= 5700)
67 scale = MS(le32_to_cpu(hdr->papdRateMaskHt20),
68 AR9300_PAPRD_SCALE_1);
69 else if (chan->channel >= 5400)
70 scale = MS(le32_to_cpu(hdr->papdRateMaskHt40),
71 AR9300_PAPRD_SCALE_2);
72 else
73 scale = MS(le32_to_cpu(hdr->papdRateMaskHt40),
74 AR9300_PAPRD_SCALE_1);
75
76 if (IS_CHAN_HT40(chan))
77 power = REG_READ_FIELD(ah, AR_PHY_POWERTX_RATE8,
78 AR_PHY_POWERTX_RATE8_POWERTXHT40_5);
79 else
80 power = REG_READ_FIELD(ah, AR_PHY_POWERTX_RATE6,
81 AR_PHY_POWERTX_RATE6_POWERTXHT20_5);
82
83 power += scale;
84 delta = abs((int) ah->paprd_target_power - (int) power);
85 if (delta > scale)
86 return -1;
87
88 power += 2 * get_streams(common->tx_chainmask);
89 return power;
90}
91
92static int ar9003_paprd_setup_single_table(struct ath_hw *ah)
93{
94 struct ath_common *common = ath9k_hw_common(ah);
95 struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
36 struct ar9300_modal_eep_header *hdr; 96 struct ar9300_modal_eep_header *hdr;
37 static const u32 ctrl0[3] = { 97 static const u32 ctrl0[3] = {
38 AR_PHY_PAPRD_CTRL0_B0, 98 AR_PHY_PAPRD_CTRL0_B0,
@@ -45,6 +105,7 @@ static void ar9003_paprd_setup_single_table(struct ath_hw *ah)
45 AR_PHY_PAPRD_CTRL1_B2 105 AR_PHY_PAPRD_CTRL1_B2
46 }; 106 };
47 u32 am_mask, ht40_mask; 107 u32 am_mask, ht40_mask;
108 int training_power;
48 int i; 109 int i;
49 110
50 if (ah->curchan && IS_CHAN_5GHZ(ah->curchan)) 111 if (ah->curchan && IS_CHAN_5GHZ(ah->curchan))
@@ -55,11 +116,25 @@ static void ar9003_paprd_setup_single_table(struct ath_hw *ah)
55 am_mask = le32_to_cpu(hdr->papdRateMaskHt20) & AR9300_PAPRD_RATE_MASK; 116 am_mask = le32_to_cpu(hdr->papdRateMaskHt20) & AR9300_PAPRD_RATE_MASK;
56 ht40_mask = le32_to_cpu(hdr->papdRateMaskHt40) & AR9300_PAPRD_RATE_MASK; 117 ht40_mask = le32_to_cpu(hdr->papdRateMaskHt40) & AR9300_PAPRD_RATE_MASK;
57 118
119 if (IS_CHAN_2GHZ(ah->curchan))
120 training_power = ar9003_get_training_power_2g(ah);
121 else
122 training_power = ar9003_get_training_power_5g(ah);
123
124 if (training_power < 0) {
125 ath_dbg(common, ATH_DBG_CALIBRATE,
126 "PAPRD target power delta out of range");
127 return -ERANGE;
128 }
129 ah->paprd_training_power = training_power;
130 ath_dbg(common, ATH_DBG_CALIBRATE,
131 "Training power: %d, Target power: %d\n",
132 ah->paprd_training_power, ah->paprd_target_power);
133
58 REG_RMW_FIELD(ah, AR_PHY_PAPRD_AM2AM, AR_PHY_PAPRD_AM2AM_MASK, am_mask); 134 REG_RMW_FIELD(ah, AR_PHY_PAPRD_AM2AM, AR_PHY_PAPRD_AM2AM_MASK, am_mask);
59 REG_RMW_FIELD(ah, AR_PHY_PAPRD_AM2PM, AR_PHY_PAPRD_AM2PM_MASK, am_mask); 135 REG_RMW_FIELD(ah, AR_PHY_PAPRD_AM2PM, AR_PHY_PAPRD_AM2PM_MASK, am_mask);
60 REG_RMW_FIELD(ah, AR_PHY_PAPRD_HT40, AR_PHY_PAPRD_HT40_MASK, ht40_mask); 136 REG_RMW_FIELD(ah, AR_PHY_PAPRD_HT40, AR_PHY_PAPRD_HT40_MASK, ht40_mask);
61 137
62
63 for (i = 0; i < ah->caps.max_txchains; i++) { 138 for (i = 0; i < ah->caps.max_txchains; i++) {
64 REG_RMW_FIELD(ah, ctrl0[i], 139 REG_RMW_FIELD(ah, ctrl0[i],
65 AR_PHY_PAPRD_CTRL0_USE_SINGLE_TABLE_MASK, 1); 140 AR_PHY_PAPRD_CTRL0_USE_SINGLE_TABLE_MASK, 1);
@@ -141,6 +216,7 @@ static void ar9003_paprd_setup_single_table(struct ath_hw *ah)
141 AR_PHY_PAPRD_PRE_POST_SCALING, 185706); 216 AR_PHY_PAPRD_PRE_POST_SCALING, 185706);
142 REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_7_B0, 217 REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_7_B0,
143 AR_PHY_PAPRD_PRE_POST_SCALING, 175487); 218 AR_PHY_PAPRD_PRE_POST_SCALING, 175487);
219 return 0;
144} 220}
145 221
146static void ar9003_paprd_get_gain_table(struct ath_hw *ah) 222static void ar9003_paprd_get_gain_table(struct ath_hw *ah)
@@ -595,15 +671,10 @@ void ar9003_paprd_populate_single_table(struct ath_hw *ah,
595{ 671{
596 u32 *paprd_table_val = caldata->pa_table[chain]; 672 u32 *paprd_table_val = caldata->pa_table[chain];
597 u32 small_signal_gain = caldata->small_signal_gain[chain]; 673 u32 small_signal_gain = caldata->small_signal_gain[chain];
598 u32 training_power; 674 u32 training_power = ah->paprd_training_power;
599 u32 reg = 0; 675 u32 reg = 0;
600 int i; 676 int i;
601 677
602 training_power =
603 REG_READ_FIELD(ah, AR_PHY_POWERTX_RATE5,
604 AR_PHY_POWERTX_RATE5_POWERTXHT20_0);
605 training_power -= 4;
606
607 if (chain == 0) 678 if (chain == 0)
608 reg = AR_PHY_PAPRD_MEM_TAB_B0; 679 reg = AR_PHY_PAPRD_MEM_TAB_B0;
609 else if (chain == 1) 680 else if (chain == 1)
@@ -643,14 +714,8 @@ EXPORT_SYMBOL(ar9003_paprd_populate_single_table);
643 714
644int ar9003_paprd_setup_gain_table(struct ath_hw *ah, int chain) 715int ar9003_paprd_setup_gain_table(struct ath_hw *ah, int chain)
645{ 716{
646
647 unsigned int i, desired_gain, gain_index; 717 unsigned int i, desired_gain, gain_index;
648 unsigned int train_power; 718 unsigned int train_power = ah->paprd_training_power;
649
650 train_power = REG_READ_FIELD(ah, AR_PHY_POWERTX_RATE5,
651 AR_PHY_POWERTX_RATE5_POWERTXHT20_0);
652
653 train_power = train_power - 4;
654 719
655 desired_gain = ar9003_get_desired_gain(ah, chain, train_power); 720 desired_gain = ar9003_get_desired_gain(ah, chain, train_power);
656 721
@@ -716,7 +781,12 @@ EXPORT_SYMBOL(ar9003_paprd_create_curve);
716 781
717int ar9003_paprd_init_table(struct ath_hw *ah) 782int ar9003_paprd_init_table(struct ath_hw *ah)
718{ 783{
719 ar9003_paprd_setup_single_table(ah); 784 int ret;
785
786 ret = ar9003_paprd_setup_single_table(ah);
787 if (ret < 0)
788 return ret;
789
720 ar9003_paprd_get_gain_table(ah); 790 ar9003_paprd_get_gain_table(ah);
721 return 0; 791 return 0;
722} 792}
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.h b/drivers/net/wireless/ath/ath9k/ar9003_phy.h
index 6f811c7ada05..59bab6bd8a74 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.h
+++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.h
@@ -1090,6 +1090,14 @@
1090#define AR_PHY_POWERTX_RATE5_POWERTXHT20_0 0x3F 1090#define AR_PHY_POWERTX_RATE5_POWERTXHT20_0 0x3F
1091#define AR_PHY_POWERTX_RATE5_POWERTXHT20_0_S 0 1091#define AR_PHY_POWERTX_RATE5_POWERTXHT20_0_S 0
1092 1092
1093#define AR_PHY_POWERTX_RATE6 (AR_SM_BASE + 0x1d4)
1094#define AR_PHY_POWERTX_RATE6_POWERTXHT20_5 0x3F00
1095#define AR_PHY_POWERTX_RATE6_POWERTXHT20_5_S 8
1096
1097#define AR_PHY_POWERTX_RATE8 (AR_SM_BASE + 0x1dc)
1098#define AR_PHY_POWERTX_RATE8_POWERTXHT40_5 0x3F00
1099#define AR_PHY_POWERTX_RATE8_POWERTXHT40_5_S 8
1100
1093void ar9003_hw_set_chain_masks(struct ath_hw *ah, u8 rx, u8 tx); 1101void ar9003_hw_set_chain_masks(struct ath_hw *ah, u8 rx, u8 tx);
1094 1102
1095#endif /* AR9003_PHY_H */ 1103#endif /* AR9003_PHY_H */
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h
index c20e0476ee44..97f22c428603 100644
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
@@ -833,6 +833,8 @@ struct ath_hw {
833 u32 bb_watchdog_last_status; 833 u32 bb_watchdog_last_status;
834 u32 bb_watchdog_timeout_ms; /* in ms, 0 to disable */ 834 u32 bb_watchdog_timeout_ms; /* in ms, 0 to disable */
835 835
836 unsigned int paprd_target_power;
837 unsigned int paprd_training_power;
836 u32 paprd_gain_table_entries[PAPRD_GAIN_TABLE_ENTRIES]; 838 u32 paprd_gain_table_entries[PAPRD_GAIN_TABLE_ENTRIES];
837 u8 paprd_gain_table_index[PAPRD_GAIN_TABLE_ENTRIES]; 839 u8 paprd_gain_table_index[PAPRD_GAIN_TABLE_ENTRIES];
838 /* 840 /*
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index d49dacbc96a7..c68205dea1fa 100644
--- 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_struct *work)
373 if (!caldata) 373 if (!caldata)
374 return; 374 return;
375 375
376 if (ar9003_paprd_init_table(ah) < 0)
377 return;
378
376 skb = alloc_skb(len, GFP_KERNEL); 379 skb = alloc_skb(len, GFP_KERNEL);
377 if (!skb) 380 if (!skb)
378 return; 381 return;
@@ -388,7 +391,6 @@ void ath_paprd_calibrate(struct work_struct *work)
388 memcpy(hdr->addr3, hw->wiphy->perm_addr, ETH_ALEN); 391 memcpy(hdr->addr3, hw->wiphy->perm_addr, ETH_ALEN);
389 392
390 ath9k_ps_wakeup(sc); 393 ath9k_ps_wakeup(sc);
391 ar9003_paprd_init_table(ah);
392 for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) { 394 for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) {
393 if (!(common->tx_chainmask & BIT(chain))) 395 if (!(common->tx_chainmask & BIT(chain)))
394 continue; 396 continue;