diff options
author | Nick Kossifidis <mick@madwifi-project.org> | 2009-02-08 23:03:41 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-02-13 13:44:43 -0500 |
commit | 6f3b414aca060a847e243f676b8601731938eb48 (patch) | |
tree | 51345c9930dbb9281d2f3dd0ebf0268870caa357 /drivers/net/wireless/ath5k | |
parent | 33a31826b4fe9f26d6b383bad19b7ae522fda006 (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.h | 51 | ||||
-rw-r--r-- | drivers/net/wireless/ath5k/attach.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/ath5k/base.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/ath5k/phy.c | 403 | ||||
-rw-r--r-- | drivers/net/wireless/ath5k/reset.c | 5 | ||||
-rw-r--r-- | drivers/net/wireless/ath5k/rfbuffer.h | 3 | ||||
-rw-r--r-- | drivers/net/wireless/ath5k/rfgain.h | 40 |
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 | ||
650 | enum ath5k_rfgain { | 650 | enum 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 | |||
678 | struct ath5k_gain_opt_step { | ||
679 | s16 gos_param[AR5K_GAIN_CRN_MAX_FIX_BITS]; | ||
680 | s32 gos_gain; | ||
681 | }; | ||
682 | |||
683 | struct ath5k_gain { | 657 | struct 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 */ |
1264 | extern int ath5k_hw_rfregs(struct ath5k_hw *ah, struct ieee80211_channel *channel, unsigned int mode); | 1235 | extern int ath5k_hw_rfregs(struct ath5k_hw *ah, struct ieee80211_channel *channel, unsigned int mode); |
1265 | extern int ath5k_hw_rfgain(struct ath5k_hw *ah, unsigned int freq); | 1236 | extern int ath5k_hw_rfgain_init(struct ath5k_hw *ah, unsigned int freq); |
1266 | extern enum ath5k_rfgain ath5k_hw_get_rf_gain(struct ath5k_hw *ah); | 1237 | extern enum ath5k_rfgain ath5k_hw_gainf_calibrate(struct ath5k_hw *ah); |
1267 | extern int ath5k_hw_set_rfgain_opt(struct ath5k_hw *ah); | 1238 | extern int ath5k_hw_rfgain_opt_init(struct ath5k_hw *ah); |
1268 | /* PHY/RF channel functions */ | 1239 | /* PHY/RF channel functions */ |
1269 | extern bool ath5k_channel_ok(struct ath5k_hw *ah, u16 freq, unsigned int flags); | 1240 | extern bool ath5k_channel_ok(struct ath5k_hw *ah, u16 freq, unsigned int flags); |
1270 | extern int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel); | 1241 | extern 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; |
337 | err_free: | 337 | err_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 | ||
81 | static 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 */ | ||
110 | int 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 | */ | ||
146 | static 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 */ | ||
164 | static 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 | ||
116 | static 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 */ | ||
218 | static 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 | ||
157 | static 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 */ | ||
261 | static 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 */ | ||
331 | enum 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 | |||
389 | done: | ||
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 */ | ||
396 | int 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 | ||
545 | int 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 | |||
592 | enum 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 | |||
628 | done: | ||
629 | return ah->ah_rf_gain; | ||
630 | } | ||
631 | |||
632 | int 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 | |||
458 | struct ath5k_gain_opt_step { | ||
459 | s8 gos_param[AR5K_GAIN_CRN_MAX_FIX_BITS]; | ||
460 | s8 gos_gain; | ||
461 | }; | ||
462 | |||
444 | struct ath5k_gain_opt { | 463 | struct 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 | */ | ||
450 | static const struct ath5k_gain_opt rfgain_opt_5111 = { | 476 | static 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 | */ | ||
466 | static const struct ath5k_gain_opt rfgain_opt_5112 = { | 502 | static const struct ath5k_gain_opt rfgain_opt_5112 = { |
467 | 1, | 503 | 1, |
468 | 8, | 504 | 8, |