aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath5k
diff options
context:
space:
mode:
authorNick Kossifidis <mick@madwifi-project.org>2009-02-08 23:03:41 -0500
committerJohn W. Linville <linville@tuxdriver.com>2009-02-13 13:44:43 -0500
commit6f3b414aca060a847e243f676b8601731938eb48 (patch)
tree51345c9930dbb9281d2f3dd0ebf0268870caa357 /drivers/net/wireless/ath5k
parent33a31826b4fe9f26d6b383bad19b7ae522fda006 (diff)
ath5k: Update gain_F calibration code and add documentation
* Update and cleanup rf gain optimization code * Add comments and refferences to docs and use sane function names * Use only step index on ath5k_gain, no need to have a pointer to the current step since we can determine te step from it's index, this also allows us to put all other structs on rfgain.h and cleanup ath5k.h a little * No need for ah_rfgain variable, we use ah_gain.g_state for everything * Tested on RF2112B chip but gain_F calibration is not yet done (we will finish this on the next patch where we'll rewrite rf-buffer handling) * Use initial rf gain settings for 2316 and 2317 SoCs introduced on a previous patch It seems big but it's mostly cleanup, very few functional changes have been made on phy.c Signed-off-by: Nick Kossifidis <mickflemm@gmail.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/ath5k')
-rw-r--r--drivers/net/wireless/ath5k/ath5k.h51
-rw-r--r--drivers/net/wireless/ath5k/attach.c2
-rw-r--r--drivers/net/wireless/ath5k/base.c2
-rw-r--r--drivers/net/wireless/ath5k/phy.c403
-rw-r--r--drivers/net/wireless/ath5k/reset.c5
-rw-r--r--drivers/net/wireless/ath5k/rfbuffer.h3
-rw-r--r--drivers/net/wireless/ath5k/rfgain.h40
7 files changed, 319 insertions, 187 deletions
diff --git a/drivers/net/wireless/ath5k/ath5k.h b/drivers/net/wireless/ath5k/ath5k.h
index 0eda785fe62f..c870e2ae575a 100644
--- a/drivers/net/wireless/ath5k/ath5k.h
+++ b/drivers/net/wireless/ath5k/ath5k.h
@@ -649,49 +649,21 @@ struct ath5k_beacon_state {
649 649
650enum ath5k_rfgain { 650enum ath5k_rfgain {
651 AR5K_RFGAIN_INACTIVE = 0, 651 AR5K_RFGAIN_INACTIVE = 0,
652 AR5K_RFGAIN_ACTIVE,
652 AR5K_RFGAIN_READ_REQUESTED, 653 AR5K_RFGAIN_READ_REQUESTED,
653 AR5K_RFGAIN_NEED_CHANGE, 654 AR5K_RFGAIN_NEED_CHANGE,
654}; 655};
655 656
656#define AR5K_GAIN_CRN_FIX_BITS_5111 4
657#define AR5K_GAIN_CRN_FIX_BITS_5112 7
658#define AR5K_GAIN_CRN_MAX_FIX_BITS AR5K_GAIN_CRN_FIX_BITS_5112
659#define AR5K_GAIN_DYN_ADJUST_HI_MARGIN 15
660#define AR5K_GAIN_DYN_ADJUST_LO_MARGIN 20
661#define AR5K_GAIN_CCK_PROBE_CORR 5
662#define AR5K_GAIN_CCK_OFDM_GAIN_DELTA 15
663#define AR5K_GAIN_STEP_COUNT 10
664#define AR5K_GAIN_PARAM_TX_CLIP 0
665#define AR5K_GAIN_PARAM_PD_90 1
666#define AR5K_GAIN_PARAM_PD_84 2
667#define AR5K_GAIN_PARAM_GAIN_SEL 3
668#define AR5K_GAIN_PARAM_MIX_ORN 0
669#define AR5K_GAIN_PARAM_PD_138 1
670#define AR5K_GAIN_PARAM_PD_137 2
671#define AR5K_GAIN_PARAM_PD_136 3
672#define AR5K_GAIN_PARAM_PD_132 4
673#define AR5K_GAIN_PARAM_PD_131 5
674#define AR5K_GAIN_PARAM_PD_130 6
675#define AR5K_GAIN_CHECK_ADJUST(_g) \
676 ((_g)->g_current <= (_g)->g_low || (_g)->g_current >= (_g)->g_high)
677
678struct ath5k_gain_opt_step {
679 s16 gos_param[AR5K_GAIN_CRN_MAX_FIX_BITS];
680 s32 gos_gain;
681};
682
683struct ath5k_gain { 657struct ath5k_gain {
684 u32 g_step_idx; 658 u8 g_step_idx;
685 u32 g_current; 659 u8 g_current;
686 u32 g_target; 660 u8 g_target;
687 u32 g_low; 661 u8 g_low;
688 u32 g_high; 662 u8 g_high;
689 u32 g_f_corr; 663 u8 g_f_corr;
690 u32 g_active; 664 u8 g_state;
691 const struct ath5k_gain_opt_step *g_step;
692}; 665};
693 666
694
695/********************\ 667/********************\
696 COMMON DEFINITIONS 668 COMMON DEFINITIONS
697\********************/ 669\********************/
@@ -1053,7 +1025,6 @@ struct ath5k_hw {
1053 bool ah_running; 1025 bool ah_running;
1054 bool ah_single_chip; 1026 bool ah_single_chip;
1055 bool ah_combined_mic; 1027 bool ah_combined_mic;
1056 enum ath5k_rfgain ah_rf_gain;
1057 1028
1058 u32 ah_mac_srev; 1029 u32 ah_mac_srev;
1059 u16 ah_mac_version; 1030 u16 ah_mac_version;
@@ -1262,9 +1233,9 @@ extern int ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, bool change_cha
1262 1233
1263/* Initialize RF */ 1234/* Initialize RF */
1264extern int ath5k_hw_rfregs(struct ath5k_hw *ah, struct ieee80211_channel *channel, unsigned int mode); 1235extern int ath5k_hw_rfregs(struct ath5k_hw *ah, struct ieee80211_channel *channel, unsigned int mode);
1265extern int ath5k_hw_rfgain(struct ath5k_hw *ah, unsigned int freq); 1236extern int ath5k_hw_rfgain_init(struct ath5k_hw *ah, unsigned int freq);
1266extern enum ath5k_rfgain ath5k_hw_get_rf_gain(struct ath5k_hw *ah); 1237extern enum ath5k_rfgain ath5k_hw_gainf_calibrate(struct ath5k_hw *ah);
1267extern int ath5k_hw_set_rfgain_opt(struct ath5k_hw *ah); 1238extern int ath5k_hw_rfgain_opt_init(struct ath5k_hw *ah);
1268/* PHY/RF channel functions */ 1239/* PHY/RF channel functions */
1269extern bool ath5k_channel_ok(struct ath5k_hw *ah, u16 freq, unsigned int flags); 1240extern bool ath5k_channel_ok(struct ath5k_hw *ah, u16 freq, unsigned int flags);
1270extern int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel); 1241extern int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel);
diff --git a/drivers/net/wireless/ath5k/attach.c b/drivers/net/wireless/ath5k/attach.c
index dea378f76731..a3f07a4ebf41 100644
--- a/drivers/net/wireless/ath5k/attach.c
+++ b/drivers/net/wireless/ath5k/attach.c
@@ -331,7 +331,7 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version)
331 ath5k_hw_set_associd(ah, ah->ah_bssid, 0); 331 ath5k_hw_set_associd(ah, ah->ah_bssid, 0);
332 ath5k_hw_set_opmode(ah); 332 ath5k_hw_set_opmode(ah);
333 333
334 ath5k_hw_set_rfgain_opt(ah); 334 ath5k_hw_rfgain_opt_init(ah);
335 335
336 return ah; 336 return ah;
337err_free: 337err_free:
diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c
index f9d486ff04f2..4b968a58ac38 100644
--- a/drivers/net/wireless/ath5k/base.c
+++ b/drivers/net/wireless/ath5k/base.c
@@ -2518,7 +2518,7 @@ ath5k_calibrate(unsigned long data)
2518 ieee80211_frequency_to_channel(sc->curchan->center_freq), 2518 ieee80211_frequency_to_channel(sc->curchan->center_freq),
2519 sc->curchan->hw_value); 2519 sc->curchan->hw_value);
2520 2520
2521 if (ath5k_hw_get_rf_gain(ah) == AR5K_RFGAIN_NEED_CHANGE) { 2521 if (ath5k_hw_gainf_calibrate(ah) == AR5K_RFGAIN_NEED_CHANGE) {
2522 /* 2522 /*
2523 * Rfgain is out of bounds, reset the chip 2523 * Rfgain is out of bounds, reset the chip
2524 * to load new gain values. 2524 * to load new gain values.
diff --git a/drivers/net/wireless/ath5k/phy.c b/drivers/net/wireless/ath5k/phy.c
index 5021749a439e..2543a718fe3f 100644
--- a/drivers/net/wireless/ath5k/phy.c
+++ b/drivers/net/wireless/ath5k/phy.c
@@ -78,10 +78,104 @@ static unsigned int ath5k_hw_rfregs_op(u32 *rf, u32 offset, u32 reg, u32 bits,
78 return data; 78 return data;
79} 79}
80 80
81static u32 ath5k_hw_rfregs_gainf_corr(struct ath5k_hw *ah) 81/**********************\
82* RF Gain optimization *
83\**********************/
84
85/*
86 * This code is used to optimize rf gain on different environments
87 * (temprature mostly) based on feedback from a power detector.
88 *
89 * It's only used on RF5111 and RF5112, later RF chips seem to have
90 * auto adjustment on hw -notice they have a much smaller BANK 7 and
91 * no gain optimization ladder-.
92 *
93 * For more infos check out this patent doc
94 * http://www.freepatentsonline.com/7400691.html
95 *
96 * This paper describes power drops as seen on the receiver due to
97 * probe packets
98 * http://www.cnri.dit.ie/publications/ICT08%20-%20Practical%20Issues
99 * %20of%20Power%20Control.pdf
100 *
101 * And this is the MadWiFi bug entry related to the above
102 * http://madwifi-project.org/ticket/1659
103 * with various measurements and diagrams
104 *
105 * TODO: Deal with power drops due to probes by setting an apropriate
106 * tx power on the probe packets ! Make this part of the calibration process.
107 */
108
109/* Initialize ah_gain durring attach */
110int ath5k_hw_rfgain_opt_init(struct ath5k_hw *ah)
111{
112 /* Initialize the gain optimization values */
113 switch (ah->ah_radio) {
114 case AR5K_RF5111:
115 ah->ah_gain.g_step_idx = rfgain_opt_5111.go_default;
116 ah->ah_gain.g_low = 20;
117 ah->ah_gain.g_high = 35;
118 ah->ah_gain.g_state = AR5K_RFGAIN_ACTIVE;
119 break;
120 case AR5K_RF5112:
121 ah->ah_gain.g_step_idx = rfgain_opt_5112.go_default;
122 ah->ah_gain.g_low = 20;
123 ah->ah_gain.g_high = 85;
124 ah->ah_gain.g_state = AR5K_RFGAIN_ACTIVE;
125 break;
126 default:
127 return -EINVAL;
128 }
129
130 return 0;
131}
132
133/* Schedule a gain probe check on the next transmited packet.
134 * That means our next packet is going to be sent with lower
135 * tx power and a Peak to Average Power Detector (PAPD) will try
136 * to measure the gain.
137 *
138 * TODO: Use propper tx power setting for the probe packet so
139 * that we don't observe a serious power drop on the receiver
140 *
141 * XXX: How about forcing a tx packet (bypassing PCU arbitrator etc)
142 * just after we enable the probe so that we don't mess with
143 * standard traffic ? Maybe it's time to use sw interrupts and
144 * a probe tasklet !!!
145 */
146static void ath5k_hw_request_rfgain_probe(struct ath5k_hw *ah)
147{
148
149 /* Skip if gain calibration is inactive or
150 * we already handle a probe request */
151 if (ah->ah_gain.g_state != AR5K_RFGAIN_ACTIVE)
152 return;
153
154 ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txpower.txp_max,
155 AR5K_PHY_PAPD_PROBE_TXPOWER) |
156 AR5K_PHY_PAPD_PROBE_TX_NEXT, AR5K_PHY_PAPD_PROBE);
157
158 ah->ah_gain.g_state = AR5K_RFGAIN_READ_REQUESTED;
159
160}
161
162/* Calculate gain_F measurement correction
163 * based on the current step for RF5112 rev. 2 */
164static u32 ath5k_hw_rf_gainf_corr(struct ath5k_hw *ah)
82{ 165{
83 u32 mix, step; 166 u32 mix, step;
84 u32 *rf; 167 u32 *rf;
168 const struct ath5k_gain_opt *go;
169 const struct ath5k_gain_opt_step *g_step;
170
171 /* Only RF5112 Rev. 2 supports it */
172 if ((ah->ah_radio != AR5K_RF5112) ||
173 (ah->ah_radio_5ghz_revision <= AR5K_SREV_RAD_5112A))
174 return 0;
175
176 go = &rfgain_opt_5112;
177
178 g_step = &go->go_step[ah->ah_gain.g_step_idx];
85 179
86 if (ah->ah_rf_banks == NULL) 180 if (ah->ah_rf_banks == NULL)
87 return 0; 181 return 0;
@@ -89,11 +183,15 @@ static u32 ath5k_hw_rfregs_gainf_corr(struct ath5k_hw *ah)
89 rf = ah->ah_rf_banks; 183 rf = ah->ah_rf_banks;
90 ah->ah_gain.g_f_corr = 0; 184 ah->ah_gain.g_f_corr = 0;
91 185
186 /* No VGA (Variable Gain Amplifier) override, skip */
92 if (ath5k_hw_rfregs_op(rf, ah->ah_offset[7], 0, 1, 36, 0, false) != 1) 187 if (ath5k_hw_rfregs_op(rf, ah->ah_offset[7], 0, 1, 36, 0, false) != 1)
93 return 0; 188 return 0;
94 189
190 /* Mix gain stepping */
95 step = ath5k_hw_rfregs_op(rf, ah->ah_offset[7], 0, 4, 32, 0, false); 191 step = ath5k_hw_rfregs_op(rf, ah->ah_offset[7], 0, 4, 32, 0, false);
96 mix = ah->ah_gain.g_step->gos_param[0]; 192
193 /* Mix gain override */
194 mix = g_step->gos_param[0];
97 195
98 switch (mix) { 196 switch (mix) {
99 case 3: 197 case 3:
@@ -113,9 +211,13 @@ static u32 ath5k_hw_rfregs_gainf_corr(struct ath5k_hw *ah)
113 return ah->ah_gain.g_f_corr; 211 return ah->ah_gain.g_f_corr;
114} 212}
115 213
116static bool ath5k_hw_rfregs_gain_readback(struct ath5k_hw *ah) 214/* Check if current gain_F measurement is in the range of our
215 * power detector windows. If we get a measurement outside range
216 * we know it's not accurate (detectors can't measure anything outside
217 * their detection window) so we must ignore it */
218static bool ath5k_hw_rf_check_gainf_readback(struct ath5k_hw *ah)
117{ 219{
118 u32 step, mix, level[4]; 220 u32 step, mix_ovr, level[4];
119 u32 *rf; 221 u32 *rf;
120 222
121 if (ah->ah_rf_banks == NULL) 223 if (ah->ah_rf_banks == NULL)
@@ -127,20 +229,20 @@ static bool ath5k_hw_rfregs_gain_readback(struct ath5k_hw *ah)
127 step = ath5k_hw_rfregs_op(rf, ah->ah_offset[7], 0, 6, 37, 0, 229 step = ath5k_hw_rfregs_op(rf, ah->ah_offset[7], 0, 6, 37, 0,
128 false); 230 false);
129 level[0] = 0; 231 level[0] = 0;
130 level[1] = (step == 0x3f) ? 0x32 : step + 4; 232 level[1] = (step == 63) ? 50 : step + 4;
131 level[2] = (step != 0x3f) ? 0x40 : level[0]; 233 level[2] = (step != 63) ? 64 : level[0];
132 level[3] = level[2] + 0x32; 234 level[3] = level[2] + 50 ;
133 235
134 ah->ah_gain.g_high = level[3] - 236 ah->ah_gain.g_high = level[3] -
135 (step == 0x3f ? AR5K_GAIN_DYN_ADJUST_HI_MARGIN : -5); 237 (step == 63 ? AR5K_GAIN_DYN_ADJUST_HI_MARGIN : -5);
136 ah->ah_gain.g_low = level[0] + 238 ah->ah_gain.g_low = level[0] +
137 (step == 0x3f ? AR5K_GAIN_DYN_ADJUST_LO_MARGIN : 0); 239 (step == 63 ? AR5K_GAIN_DYN_ADJUST_LO_MARGIN : 0);
138 } else { 240 } else {
139 mix = ath5k_hw_rfregs_op(rf, ah->ah_offset[7], 0, 1, 36, 0, 241 mix_ovr = ath5k_hw_rfregs_op(rf, ah->ah_offset[7], 0, 1, 36, 0,
140 false); 242 false);
141 level[0] = level[2] = 0; 243 level[0] = level[2] = 0;
142 244
143 if (mix == 1) { 245 if (mix_ovr == 1) {
144 level[1] = level[3] = 83; 246 level[1] = level[3] = 83;
145 } else { 247 } else {
146 level[1] = level[3] = 107; 248 level[1] = level[3] = 107;
@@ -154,9 +256,12 @@ static bool ath5k_hw_rfregs_gain_readback(struct ath5k_hw *ah)
154 ah->ah_gain.g_current <= level[3]); 256 ah->ah_gain.g_current <= level[3]);
155} 257}
156 258
157static s32 ath5k_hw_rfregs_gain_adjust(struct ath5k_hw *ah) 259/* Perform gain_F adjustment by choosing the right set
260 * of parameters from rf gain optimization ladder */
261static s8 ath5k_hw_rf_gainf_adjust(struct ath5k_hw *ah)
158{ 262{
159 const struct ath5k_gain_opt *go; 263 const struct ath5k_gain_opt *go;
264 const struct ath5k_gain_opt_step *g_step;
160 int ret = 0; 265 int ret = 0;
161 266
162 switch (ah->ah_radio) { 267 switch (ah->ah_radio) {
@@ -170,35 +275,39 @@ static s32 ath5k_hw_rfregs_gain_adjust(struct ath5k_hw *ah)
170 return 0; 275 return 0;
171 } 276 }
172 277
173 ah->ah_gain.g_step = &go->go_step[ah->ah_gain.g_step_idx]; 278 g_step = &go->go_step[ah->ah_gain.g_step_idx];
174 279
175 if (ah->ah_gain.g_current >= ah->ah_gain.g_high) { 280 if (ah->ah_gain.g_current >= ah->ah_gain.g_high) {
281
282 /* Reached maximum */
176 if (ah->ah_gain.g_step_idx == 0) 283 if (ah->ah_gain.g_step_idx == 0)
177 return -1; 284 return -1;
285
178 for (ah->ah_gain.g_target = ah->ah_gain.g_current; 286 for (ah->ah_gain.g_target = ah->ah_gain.g_current;
179 ah->ah_gain.g_target >= ah->ah_gain.g_high && 287 ah->ah_gain.g_target >= ah->ah_gain.g_high &&
180 ah->ah_gain.g_step_idx > 0; 288 ah->ah_gain.g_step_idx > 0;
181 ah->ah_gain.g_step = 289 g_step = &go->go_step[ah->ah_gain.g_step_idx])
182 &go->go_step[ah->ah_gain.g_step_idx])
183 ah->ah_gain.g_target -= 2 * 290 ah->ah_gain.g_target -= 2 *
184 (go->go_step[--(ah->ah_gain.g_step_idx)].gos_gain - 291 (go->go_step[--(ah->ah_gain.g_step_idx)].gos_gain -
185 ah->ah_gain.g_step->gos_gain); 292 g_step->gos_gain);
186 293
187 ret = 1; 294 ret = 1;
188 goto done; 295 goto done;
189 } 296 }
190 297
191 if (ah->ah_gain.g_current <= ah->ah_gain.g_low) { 298 if (ah->ah_gain.g_current <= ah->ah_gain.g_low) {
299
300 /* Reached minimum */
192 if (ah->ah_gain.g_step_idx == (go->go_steps_count - 1)) 301 if (ah->ah_gain.g_step_idx == (go->go_steps_count - 1))
193 return -2; 302 return -2;
303
194 for (ah->ah_gain.g_target = ah->ah_gain.g_current; 304 for (ah->ah_gain.g_target = ah->ah_gain.g_current;
195 ah->ah_gain.g_target <= ah->ah_gain.g_low && 305 ah->ah_gain.g_target <= ah->ah_gain.g_low &&
196 ah->ah_gain.g_step_idx < go->go_steps_count-1; 306 ah->ah_gain.g_step_idx < go->go_steps_count-1;
197 ah->ah_gain.g_step = 307 g_step = &go->go_step[ah->ah_gain.g_step_idx])
198 &go->go_step[ah->ah_gain.g_step_idx])
199 ah->ah_gain.g_target -= 2 * 308 ah->ah_gain.g_target -= 2 *
200 (go->go_step[++ah->ah_gain.g_step_idx].gos_gain - 309 (go->go_step[++ah->ah_gain.g_step_idx].gos_gain -
201 ah->ah_gain.g_step->gos_gain); 310 g_step->gos_gain);
202 311
203 ret = 2; 312 ret = 2;
204 goto done; 313 goto done;
@@ -213,6 +322,135 @@ done:
213 return ret; 322 return ret;
214} 323}
215 324
325/* Main callback for thermal rf gain calibration engine
326 * Check for a new gain reading and schedule an adjustment
327 * if needed.
328 *
329 * TODO: Use sw interrupt to schedule reset if gain_F needs
330 * adjustment */
331enum ath5k_rfgain ath5k_hw_gainf_calibrate(struct ath5k_hw *ah)
332{
333 u32 data, type;
334 struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
335
336 ATH5K_TRACE(ah->ah_sc);
337
338 if (ah->ah_rf_banks == NULL ||
339 ah->ah_gain.g_state == AR5K_RFGAIN_INACTIVE)
340 return AR5K_RFGAIN_INACTIVE;
341
342 /* No check requested, either engine is inactive
343 * or an adjustment is already requested */
344 if (ah->ah_gain.g_state != AR5K_RFGAIN_READ_REQUESTED)
345 goto done;
346
347 /* Read the PAPD (Peak to Average Power Detector)
348 * register */
349 data = ath5k_hw_reg_read(ah, AR5K_PHY_PAPD_PROBE);
350
351 /* No probe is scheduled, read gain_F measurement */
352 if (!(data & AR5K_PHY_PAPD_PROBE_TX_NEXT)) {
353 ah->ah_gain.g_current = data >> AR5K_PHY_PAPD_PROBE_GAINF_S;
354 type = AR5K_REG_MS(data, AR5K_PHY_PAPD_PROBE_TYPE);
355
356 /* If tx packet is CCK correct the gain_F measurement
357 * by cck ofdm gain delta */
358 if (type == AR5K_PHY_PAPD_PROBE_TYPE_CCK) {
359 if (ah->ah_radio_5ghz_revision >= AR5K_SREV_RAD_5112A)
360 ah->ah_gain.g_current +=
361 ee->ee_cck_ofdm_gain_delta;
362 else
363 ah->ah_gain.g_current +=
364 AR5K_GAIN_CCK_PROBE_CORR;
365 }
366
367 /* Further correct gain_F measurement for
368 * RF5112A radios */
369 if (ah->ah_radio_5ghz_revision >= AR5K_SREV_RAD_5112A) {
370 ath5k_hw_rf_gainf_corr(ah);
371 ah->ah_gain.g_current =
372 ah->ah_gain.g_current >= ah->ah_gain.g_f_corr ?
373 (ah->ah_gain.g_current-ah->ah_gain.g_f_corr) :
374 0;
375 }
376
377 /* Check if measurement is ok and if we need
378 * to adjust gain, schedule a gain adjustment,
379 * else switch back to the acive state */
380 if (ath5k_hw_rf_check_gainf_readback(ah) &&
381 AR5K_GAIN_CHECK_ADJUST(&ah->ah_gain) &&
382 ath5k_hw_rf_gainf_adjust(ah)) {
383 ah->ah_gain.g_state = AR5K_RFGAIN_NEED_CHANGE;
384 } else {
385 ah->ah_gain.g_state = AR5K_RFGAIN_ACTIVE;
386 }
387 }
388
389done:
390 return ah->ah_gain.g_state;
391}
392
393/* Write initial rf gain table to set the RF sensitivity
394 * this one works on all RF chips and has nothing to do
395 * with gain_F calibration */
396int ath5k_hw_rfgain_init(struct ath5k_hw *ah, unsigned int freq)
397{
398 const struct ath5k_ini_rfgain *ath5k_rfg;
399 unsigned int i, size;
400
401 switch (ah->ah_radio) {
402 case AR5K_RF5111:
403 ath5k_rfg = rfgain_5111;
404 size = ARRAY_SIZE(rfgain_5111);
405 break;
406 case AR5K_RF5112:
407 ath5k_rfg = rfgain_5112;
408 size = ARRAY_SIZE(rfgain_5112);
409 break;
410 case AR5K_RF2413:
411 ath5k_rfg = rfgain_2413;
412 size = ARRAY_SIZE(rfgain_2413);
413 break;
414 case AR5K_RF2316:
415 ath5k_rfg = rfgain_2316;
416 size = ARRAY_SIZE(rfgain_2316);
417 break;
418 case AR5K_RF5413:
419 ath5k_rfg = rfgain_5413;
420 size = ARRAY_SIZE(rfgain_5413);
421 break;
422 case AR5K_RF2317:
423 case AR5K_RF2425:
424 ath5k_rfg = rfgain_2425;
425 size = ARRAY_SIZE(rfgain_2425);
426 break;
427 default:
428 return -EINVAL;
429 }
430
431 switch (freq) {
432 case AR5K_INI_RFGAIN_2GHZ:
433 case AR5K_INI_RFGAIN_5GHZ:
434 break;
435 default:
436 return -EINVAL;
437 }
438
439 for (i = 0; i < size; i++) {
440 AR5K_REG_WAIT(i);
441 ath5k_hw_reg_write(ah, ath5k_rfg[i].rfg_value[freq],
442 (u32)ath5k_rfg[i].rfg_register);
443 }
444
445 return 0;
446}
447
448
449
450/********************\
451* RF Registers setup *
452\********************/
453
216/* 454/*
217 * Read EEPROM Calibration data, modify RF Banks and Initialize RF5111 455 * Read EEPROM Calibration data, modify RF Banks and Initialize RF5111
218 */ 456 */
@@ -311,6 +549,8 @@ static int ath5k_hw_rf5111_rfregs(struct ath5k_hw *ah,
311 ath5k_hw_reg_write(ah, rf[i], rfb_5111[i].rfb_ctrl_register); 549 ath5k_hw_reg_write(ah, rf[i], rfb_5111[i].rfb_ctrl_register);
312 } 550 }
313 551
552 ah->ah_gain.g_state = AR5K_RFGAIN_ACTIVE;
553
314 return 0; 554 return 0;
315} 555}
316 556
@@ -407,6 +647,9 @@ static int ath5k_hw_rf5112_rfregs(struct ath5k_hw *ah,
407 for (i = 0; i < rf_size; i++) 647 for (i = 0; i < rf_size; i++)
408 ath5k_hw_reg_write(ah, rf[i], rf_ini[i].rfb_ctrl_register); 648 ath5k_hw_reg_write(ah, rf[i], rf_ini[i].rfb_ctrl_register);
409 649
650
651 ah->ah_gain.g_state = AR5K_RFGAIN_ACTIVE;
652
410 return 0; 653 return 0;
411} 654}
412 655
@@ -536,125 +779,12 @@ int ath5k_hw_rfregs(struct ath5k_hw *ah, struct ieee80211_channel *channel,
536 } 779 }
537 780
538 ret = func(ah, channel, mode); 781 ret = func(ah, channel, mode);
539 if (!ret)
540 ah->ah_rf_gain = AR5K_RFGAIN_INACTIVE;
541 782
542 return ret; 783 return ret;
543} 784}
544 785
545int ath5k_hw_rfgain(struct ath5k_hw *ah, unsigned int freq)
546{
547 const struct ath5k_ini_rfgain *ath5k_rfg;
548 unsigned int i, size;
549 786
550 switch (ah->ah_radio) {
551 case AR5K_RF5111:
552 ath5k_rfg = rfgain_5111;
553 size = ARRAY_SIZE(rfgain_5111);
554 break;
555 case AR5K_RF5112:
556 ath5k_rfg = rfgain_5112;
557 size = ARRAY_SIZE(rfgain_5112);
558 break;
559 case AR5K_RF5413:
560 ath5k_rfg = rfgain_5413;
561 size = ARRAY_SIZE(rfgain_5413);
562 break;
563 case AR5K_RF2413:
564 ath5k_rfg = rfgain_2413;
565 size = ARRAY_SIZE(rfgain_2413);
566 break;
567 case AR5K_RF2425:
568 ath5k_rfg = rfgain_2425;
569 size = ARRAY_SIZE(rfgain_2425);
570 break;
571 default:
572 return -EINVAL;
573 }
574 787
575 switch (freq) {
576 case AR5K_INI_RFGAIN_2GHZ:
577 case AR5K_INI_RFGAIN_5GHZ:
578 break;
579 default:
580 return -EINVAL;
581 }
582
583 for (i = 0; i < size; i++) {
584 AR5K_REG_WAIT(i);
585 ath5k_hw_reg_write(ah, ath5k_rfg[i].rfg_value[freq],
586 (u32)ath5k_rfg[i].rfg_register);
587 }
588
589 return 0;
590}
591
592enum ath5k_rfgain ath5k_hw_get_rf_gain(struct ath5k_hw *ah)
593{
594 u32 data, type;
595
596 ATH5K_TRACE(ah->ah_sc);
597
598 if (ah->ah_rf_banks == NULL || !ah->ah_gain.g_active ||
599 ah->ah_version <= AR5K_AR5211)
600 return AR5K_RFGAIN_INACTIVE;
601
602 if (ah->ah_rf_gain != AR5K_RFGAIN_READ_REQUESTED)
603 goto done;
604
605 data = ath5k_hw_reg_read(ah, AR5K_PHY_PAPD_PROBE);
606
607 if (!(data & AR5K_PHY_PAPD_PROBE_TX_NEXT)) {
608 ah->ah_gain.g_current = data >> AR5K_PHY_PAPD_PROBE_GAINF_S;
609 type = AR5K_REG_MS(data, AR5K_PHY_PAPD_PROBE_TYPE);
610
611 if (type == AR5K_PHY_PAPD_PROBE_TYPE_CCK)
612 ah->ah_gain.g_current += AR5K_GAIN_CCK_PROBE_CORR;
613
614 if (ah->ah_radio >= AR5K_RF5112) {
615 ath5k_hw_rfregs_gainf_corr(ah);
616 ah->ah_gain.g_current =
617 ah->ah_gain.g_current >= ah->ah_gain.g_f_corr ?
618 (ah->ah_gain.g_current-ah->ah_gain.g_f_corr) :
619 0;
620 }
621
622 if (ath5k_hw_rfregs_gain_readback(ah) &&
623 AR5K_GAIN_CHECK_ADJUST(&ah->ah_gain) &&
624 ath5k_hw_rfregs_gain_adjust(ah))
625 ah->ah_rf_gain = AR5K_RFGAIN_NEED_CHANGE;
626 }
627
628done:
629 return ah->ah_rf_gain;
630}
631
632int ath5k_hw_set_rfgain_opt(struct ath5k_hw *ah)
633{
634 /* Initialize the gain optimization values */
635 switch (ah->ah_radio) {
636 case AR5K_RF5111:
637 ah->ah_gain.g_step_idx = rfgain_opt_5111.go_default;
638 ah->ah_gain.g_step =
639 &rfgain_opt_5111.go_step[ah->ah_gain.g_step_idx];
640 ah->ah_gain.g_low = 20;
641 ah->ah_gain.g_high = 35;
642 ah->ah_gain.g_active = 1;
643 break;
644 case AR5K_RF5112:
645 ah->ah_gain.g_step_idx = rfgain_opt_5112.go_default;
646 ah->ah_gain.g_step =
647 &rfgain_opt_5112.go_step[ah->ah_gain.g_step_idx];
648 ah->ah_gain.g_low = 20;
649 ah->ah_gain.g_high = 85;
650 ah->ah_gain.g_active = 1;
651 break;
652 default:
653 return -EINVAL;
654 }
655
656 return 0;
657}
658 788
659/**************************\ 789/**************************\
660 PHY/RF channel functions 790 PHY/RF channel functions
@@ -1176,13 +1306,8 @@ done:
1176 * as often as I/Q calibration.*/ 1306 * as often as I/Q calibration.*/
1177 ath5k_hw_noise_floor_calibration(ah, channel->center_freq); 1307 ath5k_hw_noise_floor_calibration(ah, channel->center_freq);
1178 1308
1179 /* Request RF gain */ 1309 /* Initiate a gain_F calibration */
1180 if (channel->hw_value & CHANNEL_5GHZ) { 1310 ath5k_hw_request_rfgain_probe(ah);
1181 ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txpower.txp_max,
1182 AR5K_PHY_PAPD_PROBE_TXPOWER) |
1183 AR5K_PHY_PAPD_PROBE_TX_NEXT, AR5K_PHY_PAPD_PROBE);
1184 ah->ah_rf_gain = AR5K_RFGAIN_READ_REQUESTED;
1185 }
1186 1311
1187 return 0; 1312 return 0;
1188} 1313}
diff --git a/drivers/net/wireless/ath5k/reset.c b/drivers/net/wireless/ath5k/reset.c
index dc2d7d8bdb7a..f7ce80e67dd4 100644
--- a/drivers/net/wireless/ath5k/reset.c
+++ b/drivers/net/wireless/ath5k/reset.c
@@ -441,9 +441,6 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
441 s_led[1] = ath5k_hw_reg_read(ah, AR5K_GPIOCR); 441 s_led[1] = ath5k_hw_reg_read(ah, AR5K_GPIOCR);
442 s_led[2] = ath5k_hw_reg_read(ah, AR5K_GPIODO); 442 s_led[2] = ath5k_hw_reg_read(ah, AR5K_GPIODO);
443 443
444 if (change_channel && ah->ah_rf_banks != NULL)
445 ath5k_hw_get_rf_gain(ah);
446
447 444
448 /*Wakeup the device*/ 445 /*Wakeup the device*/
449 ret = ath5k_hw_nic_wakeup(ah, channel->hw_value, false); 446 ret = ath5k_hw_nic_wakeup(ah, channel->hw_value, false);
@@ -530,7 +527,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
530 * Write initial RF gain settings 527 * Write initial RF gain settings
531 * This should work for both 5111/5112 528 * This should work for both 5111/5112
532 */ 529 */
533 ret = ath5k_hw_rfgain(ah, freq); 530 ret = ath5k_hw_rfgain_init(ah, freq);
534 if (ret) 531 if (ret)
535 return ret; 532 return ret;
536 533
diff --git a/drivers/net/wireless/ath5k/rfbuffer.h b/drivers/net/wireless/ath5k/rfbuffer.h
index 526cf6cb845f..28b30163c0ee 100644
--- a/drivers/net/wireless/ath5k/rfbuffer.h
+++ b/drivers/net/wireless/ath5k/rfbuffer.h
@@ -111,6 +111,7 @@ enum ath5k_rf_regs_idx {
111#define AR5K_RF5111_GAIN_I { 6, 29, 0 } 111#define AR5K_RF5111_GAIN_I { 6, 29, 0 }
112#define AR5K_RF5111_PLO_SEL { 1, 4, 0 } 112#define AR5K_RF5111_PLO_SEL { 1, 4, 0 }
113#define AR5K_RF5111_RFGAIN_SEL { 1, 36, 0 } 113#define AR5K_RF5111_RFGAIN_SEL { 1, 36, 0 }
114#define AR5K_RF5111_RFGAIN_STEP { 6, 37, 0 }
114/* Only on AR5212 BaseBand and up */ 115/* Only on AR5212 BaseBand and up */
115#define AR5K_RF5111_WAIT_S { 5, 19, 0 } 116#define AR5K_RF5111_WAIT_S { 5, 19, 0 }
116#define AR5K_RF5111_WAIT_I { 5, 24, 0 } 117#define AR5K_RF5111_WAIT_I { 5, 24, 0 }
@@ -235,7 +236,9 @@ static const struct ath5k_ini_rfbuffer rfb_5111[] = {
235 236
236/* BANK 7 (Common) len pos col */ 237/* BANK 7 (Common) len pos col */
237#define AR5K_RF5112X_GAIN_I { 6, 14, 0 } 238#define AR5K_RF5112X_GAIN_I { 6, 14, 0 }
239#define AR5K_RF5112X_MIXVGA_OVR { 1, 36, 0 }
238#define AR5K_RF5112X_MIXGAIN_OVR { 2, 37, 0 } 240#define AR5K_RF5112X_MIXGAIN_OVR { 2, 37, 0 }
241#define AR5K_RF5112X_MIXGAIN_STEP { 4, 32, 0 }
239#define AR5K_RF5112X_PD_DELAY_A { 4, 58, 0 } 242#define AR5K_RF5112X_PD_DELAY_A { 4, 58, 0 }
240#define AR5K_RF5112X_PD_DELAY_B { 4, 62, 0 } 243#define AR5K_RF5112X_PD_DELAY_B { 4, 62, 0 }
241#define AR5K_RF5112X_PD_DELAY_XR { 4, 66, 0 } 244#define AR5K_RF5112X_PD_DELAY_XR { 4, 66, 0 }
diff --git a/drivers/net/wireless/ath5k/rfgain.h b/drivers/net/wireless/ath5k/rfgain.h
index 6dd2ea13ff41..1354d8c392c8 100644
--- a/drivers/net/wireless/ath5k/rfgain.h
+++ b/drivers/net/wireless/ath5k/rfgain.h
@@ -441,12 +441,38 @@ static const struct ath5k_ini_rfgain rfgain_2425[] = {
441 { AR5K_RF_GAIN(63), { 0x00000000, 0x000000f9 } }, 441 { AR5K_RF_GAIN(63), { 0x00000000, 0x000000f9 } },
442}; 442};
443 443
444#define AR5K_GAIN_CRN_FIX_BITS_5111 4
445#define AR5K_GAIN_CRN_FIX_BITS_5112 7
446#define AR5K_GAIN_CRN_MAX_FIX_BITS AR5K_GAIN_CRN_FIX_BITS_5112
447#define AR5K_GAIN_DYN_ADJUST_HI_MARGIN 15
448#define AR5K_GAIN_DYN_ADJUST_LO_MARGIN 20
449#define AR5K_GAIN_CCK_PROBE_CORR 5
450#define AR5K_GAIN_CCK_OFDM_GAIN_DELTA 15
451#define AR5K_GAIN_STEP_COUNT 10
452
453/* Check if our current measurement is inside our
454 * current variable attenuation window */
455#define AR5K_GAIN_CHECK_ADJUST(_g) \
456 ((_g)->g_current <= (_g)->g_low || (_g)->g_current >= (_g)->g_high)
457
458struct ath5k_gain_opt_step {
459 s8 gos_param[AR5K_GAIN_CRN_MAX_FIX_BITS];
460 s8 gos_gain;
461};
462
444struct ath5k_gain_opt { 463struct ath5k_gain_opt {
445 u32 go_default; 464 u8 go_default;
446 u32 go_steps_count; 465 u8 go_steps_count;
447 const struct ath5k_gain_opt_step go_step[AR5K_GAIN_STEP_COUNT]; 466 const struct ath5k_gain_opt_step go_step[AR5K_GAIN_STEP_COUNT];
448}; 467};
449 468
469/*
470 * Parameters on gos_param:
471 * 1) Tx clip PHY register
472 * 2) PWD 90 RF register
473 * 3) PWD 84 RF register
474 * 4) RFGainSel RF register
475 */
450static const struct ath5k_gain_opt rfgain_opt_5111 = { 476static const struct ath5k_gain_opt rfgain_opt_5111 = {
451 4, 477 4,
452 9, 478 9,
@@ -463,6 +489,16 @@ static const struct ath5k_gain_opt rfgain_opt_5111 = {
463 } 489 }
464}; 490};
465 491
492/*
493 * Parameters on gos_param:
494 * 1) Mixgain ovr RF register
495 * 2) PWD 138 RF register
496 * 3) PWD 137 RF register
497 * 4) PWD 136 RF register
498 * 5) PWD 132 RF register
499 * 6) PWD 131 RF register
500 * 7) PWD 130 RF register
501 */
466static const struct ath5k_gain_opt rfgain_opt_5112 = { 502static const struct ath5k_gain_opt rfgain_opt_5112 = {
467 1, 503 1,
468 8, 504 8,