ath9k: fix a few issues with pa predistortion on ar9003
[openwrt/svn-archive/archive.git] / package / mac80211 / patches / 532-ath9k_paprd_training_power.patch
1 --- a/drivers/net/wireless/ath/ath9k/ar9003_paprd.c
2 +++ b/drivers/net/wireless/ath/ath9k/ar9003_paprd.c
3 @@ -30,9 +30,66 @@ void ar9003_paprd_enable(struct ath_hw *
4 }
5 EXPORT_SYMBOL(ar9003_paprd_enable);
6
7 -static void ar9003_paprd_setup_single_table(struct ath_hw *ah)
8 +static int ar9003_get_training_power_2g(struct ath_hw *ah)
9 {
10 struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
11 + struct ar9300_modal_eep_header *hdr = &eep->modalHeader2G;
12 + unsigned int power, scale, delta;
13 +
14 + scale = MS(hdr->papdRateMaskHt20, AR9300_PAPRD_SCALE_1);
15 + power = REG_READ_FIELD(ah, AR_PHY_POWERTX_RATE5,
16 + AR_PHY_POWERTX_RATE5_POWERTXHT20_0);
17 +
18 + delta = abs((int) ah->paprd_target_power - (int) power);
19 + if (delta > scale)
20 + return -1;
21 +
22 + if (delta < 4)
23 + power -= 4 - delta;
24 +
25 + return power;
26 +}
27 +
28 +static int get_streams(int mask)
29 +{
30 + return !!(mask & BIT(0)) + !!(mask & BIT(1)) + !!(mask & BIT(2));
31 +}
32 +
33 +static int ar9003_get_training_power_5g(struct ath_hw *ah)
34 +{
35 + struct ath_common *common = ath9k_hw_common(ah);
36 + struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
37 + struct ar9300_modal_eep_header *hdr = &eep->modalHeader5G;
38 + struct ath9k_channel *chan = ah->curchan;
39 + unsigned int power, scale, delta;
40 +
41 + if (chan->channel >= 5700)
42 + scale = MS(hdr->papdRateMaskHt20, AR9300_PAPRD_SCALE_1);
43 + else if (chan->channel >= 5400)
44 + scale = MS(hdr->papdRateMaskHt40, AR9300_PAPRD_SCALE_2);
45 + else
46 + scale = MS(hdr->papdRateMaskHt40, AR9300_PAPRD_SCALE_1);
47 +
48 + if (IS_CHAN_HT40(chan))
49 + power = REG_READ_FIELD(ah, AR_PHY_POWERTX_RATE8,
50 + AR_PHY_POWERTX_RATE8_POWERTXHT40_5);
51 + else
52 + power = REG_READ_FIELD(ah, AR_PHY_POWERTX_RATE6,
53 + AR_PHY_POWERTX_RATE6_POWERTXHT20_5);
54 +
55 + power += scale;
56 + delta = abs((int) ah->paprd_target_power - (int) power);
57 + if (delta > scale)
58 + return -1;
59 +
60 + power += 2 * get_streams(common->tx_chainmask);
61 + return power;
62 +}
63 +
64 +static int ar9003_paprd_setup_single_table(struct ath_hw *ah)
65 +{
66 + struct ath_common *common = ath9k_hw_common(ah);
67 + struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
68 struct ar9300_modal_eep_header *hdr;
69 static const u32 ctrl0[3] = {
70 AR_PHY_PAPRD_CTRL0_B0,
71 @@ -45,6 +102,7 @@ static void ar9003_paprd_setup_single_ta
72 AR_PHY_PAPRD_CTRL1_B2
73 };
74 u32 am_mask, ht40_mask;
75 + int training_power;
76 int i;
77
78 if (ah->curchan && IS_CHAN_5GHZ(ah->curchan))
79 @@ -55,11 +113,25 @@ static void ar9003_paprd_setup_single_ta
80 am_mask = le32_to_cpu(hdr->papdRateMaskHt20) & AR9300_PAPRD_RATE_MASK;
81 ht40_mask = le32_to_cpu(hdr->papdRateMaskHt40) & AR9300_PAPRD_RATE_MASK;
82
83 + if (IS_CHAN_2GHZ(ah->curchan))
84 + training_power = ar9003_get_training_power_2g(ah);
85 + else
86 + training_power = ar9003_get_training_power_5g(ah);
87 +
88 + if (training_power < 0) {
89 + ath_dbg(common, ATH_DBG_CALIBRATE,
90 + "PAPRD target power delta out of range");
91 + return -ERANGE;
92 + }
93 + ah->paprd_training_power = training_power;
94 + ath_dbg(common, ATH_DBG_CALIBRATE,
95 + "Training power: %d, Target power: %d\n",
96 + ah->paprd_training_power, ah->paprd_target_power);
97 +
98 REG_RMW_FIELD(ah, AR_PHY_PAPRD_AM2AM, AR_PHY_PAPRD_AM2AM_MASK, am_mask);
99 REG_RMW_FIELD(ah, AR_PHY_PAPRD_AM2PM, AR_PHY_PAPRD_AM2PM_MASK, am_mask);
100 REG_RMW_FIELD(ah, AR_PHY_PAPRD_HT40, AR_PHY_PAPRD_HT40_MASK, ht40_mask);
101
102 -
103 for (i = 0; i < ah->caps.max_txchains; i++) {
104 REG_RMW_FIELD(ah, ctrl0[i],
105 AR_PHY_PAPRD_CTRL0_USE_SINGLE_TABLE_MASK, 1);
106 @@ -141,6 +213,7 @@ static void ar9003_paprd_setup_single_ta
107 AR_PHY_PAPRD_PRE_POST_SCALING, 185706);
108 REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_7_B0,
109 AR_PHY_PAPRD_PRE_POST_SCALING, 175487);
110 + return 0;
111 }
112
113 static void ar9003_paprd_get_gain_table(struct ath_hw *ah)
114 @@ -595,15 +668,10 @@ void ar9003_paprd_populate_single_table(
115 {
116 u32 *paprd_table_val = caldata->pa_table[chain];
117 u32 small_signal_gain = caldata->small_signal_gain[chain];
118 - u32 training_power;
119 + u32 training_power = ah->paprd_training_power;
120 u32 reg = 0;
121 int i;
122
123 - training_power =
124 - REG_READ_FIELD(ah, AR_PHY_POWERTX_RATE5,
125 - AR_PHY_POWERTX_RATE5_POWERTXHT20_0);
126 - training_power -= 4;
127 -
128 if (chain == 0)
129 reg = AR_PHY_PAPRD_MEM_TAB_B0;
130 else if (chain == 1)
131 @@ -643,14 +711,8 @@ EXPORT_SYMBOL(ar9003_paprd_populate_sing
132
133 int ar9003_paprd_setup_gain_table(struct ath_hw *ah, int chain)
134 {
135 -
136 unsigned int i, desired_gain, gain_index;
137 - unsigned int train_power;
138 -
139 - train_power = REG_READ_FIELD(ah, AR_PHY_POWERTX_RATE5,
140 - AR_PHY_POWERTX_RATE5_POWERTXHT20_0);
141 -
142 - train_power = train_power - 4;
143 + unsigned int train_power = ah->paprd_training_power;
144
145 desired_gain = ar9003_get_desired_gain(ah, chain, train_power);
146
147 @@ -716,7 +778,12 @@ EXPORT_SYMBOL(ar9003_paprd_create_curve)
148
149 int ar9003_paprd_init_table(struct ath_hw *ah)
150 {
151 - ar9003_paprd_setup_single_table(ah);
152 + int ret;
153 +
154 + ret = ar9003_paprd_setup_single_table(ah);
155 + if (ret < 0)
156 + return ret;
157 +
158 ar9003_paprd_get_gain_table(ah);
159 return 0;
160 }
161 --- a/drivers/net/wireless/ath/ath9k/hw.h
162 +++ b/drivers/net/wireless/ath/ath9k/hw.h
163 @@ -835,6 +835,8 @@ struct ath_hw {
164 u32 bb_watchdog_last_status;
165 u32 bb_watchdog_timeout_ms; /* in ms, 0 to disable */
166
167 + unsigned int paprd_target_power;
168 + unsigned int paprd_training_power;
169 u32 paprd_gain_table_entries[PAPRD_GAIN_TABLE_ENTRIES];
170 u8 paprd_gain_table_index[PAPRD_GAIN_TABLE_ENTRIES];
171 /*
172 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.h
173 +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.h
174 @@ -1090,6 +1090,14 @@
175 #define AR_PHY_POWERTX_RATE5_POWERTXHT20_0 0x3F
176 #define AR_PHY_POWERTX_RATE5_POWERTXHT20_0_S 0
177
178 +#define AR_PHY_POWERTX_RATE6 (AR_SM_BASE + 0x1d4)
179 +#define AR_PHY_POWERTX_RATE6_POWERTXHT20_5 0x3F00
180 +#define AR_PHY_POWERTX_RATE6_POWERTXHT20_5_S 8
181 +
182 +#define AR_PHY_POWERTX_RATE8 (AR_SM_BASE + 0x1dc)
183 +#define AR_PHY_POWERTX_RATE8_POWERTXHT40_5 0x3F00
184 +#define AR_PHY_POWERTX_RATE8_POWERTXHT40_5_S 8
185 +
186 void ar9003_hw_set_chain_masks(struct ath_hw *ah, u8 rx, u8 tx);
187
188 #endif /* AR9003_PHY_H */
189 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
190 +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
191 @@ -4798,6 +4798,14 @@ static void ath9k_hw_ar9300_set_txpower(
192 /* Write target power array to registers */
193 ar9003_hw_tx_power_regwrite(ah, targetPowerValT2);
194 ar9003_hw_calibration_apply(ah, chan->channel);
195 +
196 + if (IS_CHAN_2GHZ(chan))
197 + i = ALL_TARGET_HT20_0_8_16;
198 + else if (IS_CHAN_HT40(chan))
199 + i = ALL_TARGET_HT40_7;
200 + else
201 + i = ALL_TARGET_HT20_7;
202 + ah->paprd_target_power = targetPowerValT2[i];
203 }
204
205 static u16 ath9k_hw_ar9300_get_spur_channel(struct ath_hw *ah,
206 --- a/drivers/net/wireless/ath/ath9k/main.c
207 +++ b/drivers/net/wireless/ath/ath9k/main.c
208 @@ -373,6 +373,9 @@ void ath_paprd_calibrate(struct work_str
209 if (!caldata)
210 return;
211
212 + if (ar9003_paprd_init_table(ah) < 0)
213 + return;
214 +
215 skb = alloc_skb(len, GFP_KERNEL);
216 if (!skb)
217 return;
218 @@ -388,7 +391,6 @@ void ath_paprd_calibrate(struct work_str
219 memcpy(hdr->addr3, hw->wiphy->perm_addr, ETH_ALEN);
220
221 ath9k_ps_wakeup(sc);
222 - ar9003_paprd_init_table(ah);
223 for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) {
224 if (!(common->tx_chainmask & BIT(chain)))
225 continue;