Commit | Line | Data |
---|---|---|
8da07830 SM |
1 | /* |
2 | * Copyright (c) 2012 Qualcomm Atheros, Inc. | |
3 | * | |
4 | * Permission to use, copy, modify, and/or distribute this software for any | |
5 | * purpose with or without fee is hereby granted, provided that the above | |
6 | * copyright notice and this permission notice appear in all copies. | |
7 | * | |
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
15 | */ | |
16 | ||
17 | #include "ath9k.h" | |
18 | ||
fd7f8387 SM |
19 | /* |
20 | * AR9285 | |
21 | * ====== | |
22 | * | |
23 | * EEPROM has 2 4-bit fields containing the card configuration. | |
24 | * | |
25 | * antdiv_ctl1: | |
26 | * ------------ | |
27 | * bb_enable_ant_div_lnadiv : 1 | |
28 | * bb_ant_div_alt_gaintb : 1 | |
29 | * bb_ant_div_main_gaintb : 1 | |
30 | * bb_enable_ant_fast_div : 1 | |
31 | * | |
32 | * antdiv_ctl2: | |
33 | * ----------- | |
34 | * bb_ant_div_alt_lnaconf : 2 | |
35 | * bb_ant_div_main_lnaconf : 2 | |
36 | * | |
37 | * The EEPROM bits are used as follows: | |
38 | * ------------------------------------ | |
39 | * | |
40 | * bb_enable_ant_div_lnadiv - Enable LNA path rx antenna diversity/combining. | |
41 | * Set in AR_PHY_MULTICHAIN_GAIN_CTL. | |
42 | * | |
43 | * bb_ant_div_[alt/main]_gaintb - 0 -> Antenna config Alt/Main uses gaintable 0 | |
44 | * 1 -> Antenna config Alt/Main uses gaintable 1 | |
45 | * Set in AR_PHY_MULTICHAIN_GAIN_CTL. | |
46 | * | |
47 | * bb_enable_ant_fast_div - Enable fast antenna diversity. | |
48 | * Set in AR_PHY_CCK_DETECT. | |
49 | * | |
50 | * bb_ant_div_[alt/main]_lnaconf - Alt/Main LNA diversity/combining input config. | |
51 | * Set in AR_PHY_MULTICHAIN_GAIN_CTL. | |
52 | * 10=LNA1 | |
53 | * 01=LNA2 | |
54 | * 11=LNA1+LNA2 | |
55 | * 00=LNA1-LNA2 | |
56 | * | |
57 | * AR9485 / AR9565 / AR9331 | |
58 | * ======================== | |
59 | * | |
60 | * The same bits are present in the EEPROM, but the location in the | |
61 | * EEPROM is different (ant_div_control in ar9300_BaseExtension_1). | |
62 | * | |
63 | * ant_div_alt_lnaconf ==> bit 0~1 | |
64 | * ant_div_main_lnaconf ==> bit 2~3 | |
65 | * ant_div_alt_gaintb ==> bit 4 | |
66 | * ant_div_main_gaintb ==> bit 5 | |
67 | * enable_ant_div_lnadiv ==> bit 6 | |
68 | * enable_ant_fast_div ==> bit 7 | |
69 | */ | |
70 | ||
3afa6b4f SM |
71 | static inline bool ath_is_alt_ant_ratio_better(struct ath_ant_comb *antcomb, |
72 | int alt_ratio, int maxdelta, | |
8da07830 SM |
73 | int mindelta, int main_rssi_avg, |
74 | int alt_rssi_avg, int pkt_count) | |
75 | { | |
3afa6b4f SM |
76 | if (pkt_count <= 50) |
77 | return false; | |
78 | ||
79 | if (alt_rssi_avg > main_rssi_avg + mindelta) | |
80 | return true; | |
81 | ||
82 | if (alt_ratio >= antcomb->ant_ratio2 && | |
83 | alt_rssi_avg >= antcomb->low_rssi_thresh && | |
84 | (alt_rssi_avg > main_rssi_avg + maxdelta)) | |
85 | return true; | |
86 | ||
87 | return false; | |
8da07830 SM |
88 | } |
89 | ||
ef999114 | 90 | static inline bool ath_ant_div_comb_alt_check(struct ath_hw_antcomb_conf *conf, |
3afa6b4f | 91 | struct ath_ant_comb *antcomb, |
552bde40 SM |
92 | int alt_ratio, int alt_rssi_avg, |
93 | int main_rssi_avg) | |
8da07830 | 94 | { |
552bde40 SM |
95 | bool result, set1, set2; |
96 | ||
97 | result = set1 = set2 = false; | |
98 | ||
ef999114 SM |
99 | if (conf->main_lna_conf == ATH_ANT_DIV_COMB_LNA2 && |
100 | conf->alt_lna_conf == ATH_ANT_DIV_COMB_LNA1) | |
552bde40 SM |
101 | set1 = true; |
102 | ||
ef999114 SM |
103 | if (conf->main_lna_conf == ATH_ANT_DIV_COMB_LNA1 && |
104 | conf->alt_lna_conf == ATH_ANT_DIV_COMB_LNA2) | |
552bde40 SM |
105 | set2 = true; |
106 | ||
ef999114 | 107 | switch (conf->div_group) { |
8da07830 SM |
108 | case 0: |
109 | if (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO) | |
110 | result = true; | |
111 | break; | |
112 | case 1: | |
113 | case 2: | |
3afa6b4f | 114 | if (alt_rssi_avg < 4 || alt_rssi_avg < antcomb->low_rssi_thresh) |
552bde40 SM |
115 | break; |
116 | ||
117 | if ((set1 && (alt_rssi_avg >= (main_rssi_avg - 5))) || | |
3afa6b4f SM |
118 | (set2 && (alt_rssi_avg >= (main_rssi_avg - 2))) || |
119 | (alt_ratio > antcomb->ant_ratio)) | |
8da07830 | 120 | result = true; |
552bde40 SM |
121 | |
122 | break; | |
123 | case 3: | |
3afa6b4f | 124 | if (alt_rssi_avg < 4 || alt_rssi_avg < antcomb->low_rssi_thresh) |
552bde40 SM |
125 | break; |
126 | ||
127 | if ((set1 && (alt_rssi_avg >= (main_rssi_avg - 3))) || | |
3afa6b4f SM |
128 | (set2 && (alt_rssi_avg >= (main_rssi_avg + 3))) || |
129 | (alt_ratio > antcomb->ant_ratio)) | |
552bde40 SM |
130 | result = true; |
131 | ||
8da07830 SM |
132 | break; |
133 | } | |
134 | ||
135 | return result; | |
136 | } | |
137 | ||
138 | static void ath_lnaconf_alt_good_scan(struct ath_ant_comb *antcomb, | |
139 | struct ath_hw_antcomb_conf ant_conf, | |
140 | int main_rssi_avg) | |
141 | { | |
142 | antcomb->quick_scan_cnt = 0; | |
143 | ||
144 | if (ant_conf.main_lna_conf == ATH_ANT_DIV_COMB_LNA2) | |
145 | antcomb->rssi_lna2 = main_rssi_avg; | |
146 | else if (ant_conf.main_lna_conf == ATH_ANT_DIV_COMB_LNA1) | |
147 | antcomb->rssi_lna1 = main_rssi_avg; | |
148 | ||
149 | switch ((ant_conf.main_lna_conf << 4) | ant_conf.alt_lna_conf) { | |
150 | case 0x10: /* LNA2 A-B */ | |
151 | antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2; | |
152 | antcomb->first_quick_scan_conf = | |
153 | ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2; | |
154 | antcomb->second_quick_scan_conf = ATH_ANT_DIV_COMB_LNA1; | |
155 | break; | |
156 | case 0x20: /* LNA1 A-B */ | |
157 | antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2; | |
158 | antcomb->first_quick_scan_conf = | |
159 | ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2; | |
160 | antcomb->second_quick_scan_conf = ATH_ANT_DIV_COMB_LNA2; | |
161 | break; | |
162 | case 0x21: /* LNA1 LNA2 */ | |
163 | antcomb->main_conf = ATH_ANT_DIV_COMB_LNA2; | |
164 | antcomb->first_quick_scan_conf = | |
165 | ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2; | |
166 | antcomb->second_quick_scan_conf = | |
167 | ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2; | |
168 | break; | |
169 | case 0x12: /* LNA2 LNA1 */ | |
170 | antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1; | |
171 | antcomb->first_quick_scan_conf = | |
172 | ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2; | |
173 | antcomb->second_quick_scan_conf = | |
174 | ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2; | |
175 | break; | |
176 | case 0x13: /* LNA2 A+B */ | |
177 | antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2; | |
178 | antcomb->first_quick_scan_conf = | |
179 | ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2; | |
180 | antcomb->second_quick_scan_conf = ATH_ANT_DIV_COMB_LNA1; | |
181 | break; | |
182 | case 0x23: /* LNA1 A+B */ | |
183 | antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2; | |
184 | antcomb->first_quick_scan_conf = | |
185 | ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2; | |
186 | antcomb->second_quick_scan_conf = ATH_ANT_DIV_COMB_LNA2; | |
187 | break; | |
188 | default: | |
189 | break; | |
190 | } | |
191 | } | |
192 | ||
37133002 SM |
193 | static void ath_ant_set_alt_ratio(struct ath_ant_comb *antcomb, |
194 | struct ath_hw_antcomb_conf *conf) | |
195 | { | |
196 | /* set alt to the conf with maximun ratio */ | |
197 | if (antcomb->first_ratio && antcomb->second_ratio) { | |
198 | if (antcomb->rssi_second > antcomb->rssi_third) { | |
199 | /* first alt*/ | |
200 | if ((antcomb->first_quick_scan_conf == ATH_ANT_DIV_COMB_LNA1) || | |
201 | (antcomb->first_quick_scan_conf == ATH_ANT_DIV_COMB_LNA2)) | |
202 | /* Set alt LNA1 or LNA2*/ | |
203 | if (conf->main_lna_conf == ATH_ANT_DIV_COMB_LNA2) | |
204 | conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1; | |
205 | else | |
206 | conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2; | |
207 | else | |
208 | /* Set alt to A+B or A-B */ | |
209 | conf->alt_lna_conf = | |
210 | antcomb->first_quick_scan_conf; | |
211 | } else if ((antcomb->second_quick_scan_conf == ATH_ANT_DIV_COMB_LNA1) || | |
212 | (antcomb->second_quick_scan_conf == ATH_ANT_DIV_COMB_LNA2)) { | |
213 | /* Set alt LNA1 or LNA2 */ | |
214 | if (conf->main_lna_conf == ATH_ANT_DIV_COMB_LNA2) | |
215 | conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1; | |
216 | else | |
217 | conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2; | |
218 | } else { | |
219 | /* Set alt to A+B or A-B */ | |
220 | conf->alt_lna_conf = antcomb->second_quick_scan_conf; | |
221 | } | |
222 | } else if (antcomb->first_ratio) { | |
223 | /* first alt */ | |
224 | if ((antcomb->first_quick_scan_conf == ATH_ANT_DIV_COMB_LNA1) || | |
225 | (antcomb->first_quick_scan_conf == ATH_ANT_DIV_COMB_LNA2)) | |
226 | /* Set alt LNA1 or LNA2 */ | |
227 | if (conf->main_lna_conf == ATH_ANT_DIV_COMB_LNA2) | |
228 | conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1; | |
229 | else | |
230 | conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2; | |
231 | else | |
232 | /* Set alt to A+B or A-B */ | |
233 | conf->alt_lna_conf = antcomb->first_quick_scan_conf; | |
234 | } else if (antcomb->second_ratio) { | |
235 | /* second alt */ | |
236 | if ((antcomb->second_quick_scan_conf == ATH_ANT_DIV_COMB_LNA1) || | |
237 | (antcomb->second_quick_scan_conf == ATH_ANT_DIV_COMB_LNA2)) | |
238 | /* Set alt LNA1 or LNA2 */ | |
239 | if (conf->main_lna_conf == ATH_ANT_DIV_COMB_LNA2) | |
240 | conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1; | |
241 | else | |
242 | conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2; | |
243 | else | |
244 | /* Set alt to A+B or A-B */ | |
245 | conf->alt_lna_conf = antcomb->second_quick_scan_conf; | |
246 | } else { | |
247 | /* main is largest */ | |
248 | if ((antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) || | |
249 | (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2)) | |
250 | /* Set alt LNA1 or LNA2 */ | |
251 | if (conf->main_lna_conf == ATH_ANT_DIV_COMB_LNA2) | |
252 | conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1; | |
253 | else | |
254 | conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2; | |
255 | else | |
256 | /* Set alt to A+B or A-B */ | |
257 | conf->alt_lna_conf = antcomb->main_conf; | |
258 | } | |
259 | } | |
260 | ||
8da07830 SM |
261 | static void ath_select_ant_div_from_quick_scan(struct ath_ant_comb *antcomb, |
262 | struct ath_hw_antcomb_conf *div_ant_conf, | |
263 | int main_rssi_avg, int alt_rssi_avg, | |
264 | int alt_ratio) | |
265 | { | |
266 | /* alt_good */ | |
267 | switch (antcomb->quick_scan_cnt) { | |
268 | case 0: | |
269 | /* set alt to main, and alt to first conf */ | |
270 | div_ant_conf->main_lna_conf = antcomb->main_conf; | |
271 | div_ant_conf->alt_lna_conf = antcomb->first_quick_scan_conf; | |
272 | break; | |
273 | case 1: | |
274 | /* set alt to main, and alt to first conf */ | |
275 | div_ant_conf->main_lna_conf = antcomb->main_conf; | |
276 | div_ant_conf->alt_lna_conf = antcomb->second_quick_scan_conf; | |
277 | antcomb->rssi_first = main_rssi_avg; | |
278 | antcomb->rssi_second = alt_rssi_avg; | |
279 | ||
280 | if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) { | |
281 | /* main is LNA1 */ | |
3afa6b4f | 282 | if (ath_is_alt_ant_ratio_better(antcomb, alt_ratio, |
8da07830 SM |
283 | ATH_ANT_DIV_COMB_LNA1_DELTA_HI, |
284 | ATH_ANT_DIV_COMB_LNA1_DELTA_LOW, | |
285 | main_rssi_avg, alt_rssi_avg, | |
286 | antcomb->total_pkt_count)) | |
287 | antcomb->first_ratio = true; | |
288 | else | |
289 | antcomb->first_ratio = false; | |
290 | } else if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2) { | |
3afa6b4f | 291 | if (ath_is_alt_ant_ratio_better(antcomb, alt_ratio, |
8da07830 SM |
292 | ATH_ANT_DIV_COMB_LNA1_DELTA_MID, |
293 | ATH_ANT_DIV_COMB_LNA1_DELTA_LOW, | |
294 | main_rssi_avg, alt_rssi_avg, | |
295 | antcomb->total_pkt_count)) | |
296 | antcomb->first_ratio = true; | |
297 | else | |
298 | antcomb->first_ratio = false; | |
299 | } else { | |
3afa6b4f | 300 | if (ath_is_alt_ant_ratio_better(antcomb, alt_ratio, |
9ddf0301 SM |
301 | ATH_ANT_DIV_COMB_LNA1_DELTA_HI, |
302 | 0, | |
303 | main_rssi_avg, alt_rssi_avg, | |
304 | antcomb->total_pkt_count)) | |
8da07830 SM |
305 | antcomb->first_ratio = true; |
306 | else | |
307 | antcomb->first_ratio = false; | |
308 | } | |
309 | break; | |
310 | case 2: | |
311 | antcomb->alt_good = false; | |
312 | antcomb->scan_not_start = false; | |
313 | antcomb->scan = false; | |
314 | antcomb->rssi_first = main_rssi_avg; | |
315 | antcomb->rssi_third = alt_rssi_avg; | |
316 | ||
37133002 SM |
317 | switch(antcomb->second_quick_scan_conf) { |
318 | case ATH_ANT_DIV_COMB_LNA1: | |
8da07830 | 319 | antcomb->rssi_lna1 = alt_rssi_avg; |
37133002 SM |
320 | break; |
321 | case ATH_ANT_DIV_COMB_LNA2: | |
8da07830 | 322 | antcomb->rssi_lna2 = alt_rssi_avg; |
37133002 SM |
323 | break; |
324 | case ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2: | |
8da07830 SM |
325 | if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2) |
326 | antcomb->rssi_lna2 = main_rssi_avg; | |
327 | else if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) | |
328 | antcomb->rssi_lna1 = main_rssi_avg; | |
37133002 SM |
329 | break; |
330 | default: | |
331 | break; | |
8da07830 SM |
332 | } |
333 | ||
334 | if (antcomb->rssi_lna2 > antcomb->rssi_lna1 + | |
f96bd2ad | 335 | div_ant_conf->lna1_lna2_switch_delta) |
8da07830 SM |
336 | div_ant_conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2; |
337 | else | |
338 | div_ant_conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1; | |
339 | ||
340 | if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) { | |
3afa6b4f | 341 | if (ath_is_alt_ant_ratio_better(antcomb, alt_ratio, |
8da07830 SM |
342 | ATH_ANT_DIV_COMB_LNA1_DELTA_HI, |
343 | ATH_ANT_DIV_COMB_LNA1_DELTA_LOW, | |
344 | main_rssi_avg, alt_rssi_avg, | |
345 | antcomb->total_pkt_count)) | |
346 | antcomb->second_ratio = true; | |
347 | else | |
348 | antcomb->second_ratio = false; | |
349 | } else if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2) { | |
3afa6b4f | 350 | if (ath_is_alt_ant_ratio_better(antcomb, alt_ratio, |
8da07830 SM |
351 | ATH_ANT_DIV_COMB_LNA1_DELTA_MID, |
352 | ATH_ANT_DIV_COMB_LNA1_DELTA_LOW, | |
353 | main_rssi_avg, alt_rssi_avg, | |
354 | antcomb->total_pkt_count)) | |
355 | antcomb->second_ratio = true; | |
356 | else | |
357 | antcomb->second_ratio = false; | |
358 | } else { | |
3afa6b4f | 359 | if (ath_is_alt_ant_ratio_better(antcomb, alt_ratio, |
9ddf0301 SM |
360 | ATH_ANT_DIV_COMB_LNA1_DELTA_HI, |
361 | 0, | |
362 | main_rssi_avg, alt_rssi_avg, | |
363 | antcomb->total_pkt_count)) | |
8da07830 SM |
364 | antcomb->second_ratio = true; |
365 | else | |
366 | antcomb->second_ratio = false; | |
367 | } | |
368 | ||
37133002 SM |
369 | ath_ant_set_alt_ratio(antcomb, div_ant_conf); |
370 | ||
8da07830 SM |
371 | break; |
372 | default: | |
373 | break; | |
374 | } | |
375 | } | |
376 | ||
377 | static void ath_ant_div_conf_fast_divbias(struct ath_hw_antcomb_conf *ant_conf, | |
378 | struct ath_ant_comb *antcomb, | |
379 | int alt_ratio) | |
380 | { | |
d85ed419 SM |
381 | ant_conf->main_gaintb = 0; |
382 | ant_conf->alt_gaintb = 0; | |
383 | ||
8da07830 SM |
384 | if (ant_conf->div_group == 0) { |
385 | /* Adjust the fast_div_bias based on main and alt lna conf */ | |
386 | switch ((ant_conf->main_lna_conf << 4) | | |
387 | ant_conf->alt_lna_conf) { | |
388 | case 0x01: /* A-B LNA2 */ | |
389 | ant_conf->fast_div_bias = 0x3b; | |
390 | break; | |
391 | case 0x02: /* A-B LNA1 */ | |
392 | ant_conf->fast_div_bias = 0x3d; | |
393 | break; | |
394 | case 0x03: /* A-B A+B */ | |
395 | ant_conf->fast_div_bias = 0x1; | |
396 | break; | |
397 | case 0x10: /* LNA2 A-B */ | |
398 | ant_conf->fast_div_bias = 0x7; | |
399 | break; | |
400 | case 0x12: /* LNA2 LNA1 */ | |
401 | ant_conf->fast_div_bias = 0x2; | |
402 | break; | |
403 | case 0x13: /* LNA2 A+B */ | |
404 | ant_conf->fast_div_bias = 0x7; | |
405 | break; | |
406 | case 0x20: /* LNA1 A-B */ | |
407 | ant_conf->fast_div_bias = 0x6; | |
408 | break; | |
409 | case 0x21: /* LNA1 LNA2 */ | |
410 | ant_conf->fast_div_bias = 0x0; | |
411 | break; | |
412 | case 0x23: /* LNA1 A+B */ | |
413 | ant_conf->fast_div_bias = 0x6; | |
414 | break; | |
415 | case 0x30: /* A+B A-B */ | |
416 | ant_conf->fast_div_bias = 0x1; | |
417 | break; | |
418 | case 0x31: /* A+B LNA2 */ | |
419 | ant_conf->fast_div_bias = 0x3b; | |
420 | break; | |
421 | case 0x32: /* A+B LNA1 */ | |
422 | ant_conf->fast_div_bias = 0x3d; | |
423 | break; | |
424 | default: | |
425 | break; | |
426 | } | |
427 | } else if (ant_conf->div_group == 1) { | |
428 | /* Adjust the fast_div_bias based on main and alt_lna_conf */ | |
429 | switch ((ant_conf->main_lna_conf << 4) | | |
430 | ant_conf->alt_lna_conf) { | |
431 | case 0x01: /* A-B LNA2 */ | |
432 | ant_conf->fast_div_bias = 0x1; | |
8da07830 SM |
433 | break; |
434 | case 0x02: /* A-B LNA1 */ | |
435 | ant_conf->fast_div_bias = 0x1; | |
8da07830 SM |
436 | break; |
437 | case 0x03: /* A-B A+B */ | |
438 | ant_conf->fast_div_bias = 0x1; | |
8da07830 SM |
439 | break; |
440 | case 0x10: /* LNA2 A-B */ | |
441 | if (!(antcomb->scan) && | |
442 | (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) | |
443 | ant_conf->fast_div_bias = 0x3f; | |
444 | else | |
445 | ant_conf->fast_div_bias = 0x1; | |
8da07830 SM |
446 | break; |
447 | case 0x12: /* LNA2 LNA1 */ | |
448 | ant_conf->fast_div_bias = 0x1; | |
8da07830 SM |
449 | break; |
450 | case 0x13: /* LNA2 A+B */ | |
451 | if (!(antcomb->scan) && | |
452 | (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) | |
453 | ant_conf->fast_div_bias = 0x3f; | |
454 | else | |
455 | ant_conf->fast_div_bias = 0x1; | |
8da07830 SM |
456 | break; |
457 | case 0x20: /* LNA1 A-B */ | |
458 | if (!(antcomb->scan) && | |
459 | (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) | |
460 | ant_conf->fast_div_bias = 0x3f; | |
461 | else | |
462 | ant_conf->fast_div_bias = 0x1; | |
8da07830 SM |
463 | break; |
464 | case 0x21: /* LNA1 LNA2 */ | |
465 | ant_conf->fast_div_bias = 0x1; | |
8da07830 SM |
466 | break; |
467 | case 0x23: /* LNA1 A+B */ | |
468 | if (!(antcomb->scan) && | |
469 | (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) | |
470 | ant_conf->fast_div_bias = 0x3f; | |
471 | else | |
472 | ant_conf->fast_div_bias = 0x1; | |
8da07830 SM |
473 | break; |
474 | case 0x30: /* A+B A-B */ | |
475 | ant_conf->fast_div_bias = 0x1; | |
8da07830 SM |
476 | break; |
477 | case 0x31: /* A+B LNA2 */ | |
478 | ant_conf->fast_div_bias = 0x1; | |
8da07830 SM |
479 | break; |
480 | case 0x32: /* A+B LNA1 */ | |
481 | ant_conf->fast_div_bias = 0x1; | |
8da07830 SM |
482 | break; |
483 | default: | |
484 | break; | |
485 | } | |
486 | } else if (ant_conf->div_group == 2) { | |
487 | /* Adjust the fast_div_bias based on main and alt_lna_conf */ | |
488 | switch ((ant_conf->main_lna_conf << 4) | | |
489 | ant_conf->alt_lna_conf) { | |
490 | case 0x01: /* A-B LNA2 */ | |
491 | ant_conf->fast_div_bias = 0x1; | |
8da07830 SM |
492 | break; |
493 | case 0x02: /* A-B LNA1 */ | |
494 | ant_conf->fast_div_bias = 0x1; | |
8da07830 SM |
495 | break; |
496 | case 0x03: /* A-B A+B */ | |
497 | ant_conf->fast_div_bias = 0x1; | |
8da07830 SM |
498 | break; |
499 | case 0x10: /* LNA2 A-B */ | |
3afa6b4f | 500 | if (!antcomb->scan && (alt_ratio > antcomb->ant_ratio)) |
8da07830 SM |
501 | ant_conf->fast_div_bias = 0x1; |
502 | else | |
503 | ant_conf->fast_div_bias = 0x2; | |
8da07830 SM |
504 | break; |
505 | case 0x12: /* LNA2 LNA1 */ | |
506 | ant_conf->fast_div_bias = 0x1; | |
8da07830 SM |
507 | break; |
508 | case 0x13: /* LNA2 A+B */ | |
3afa6b4f | 509 | if (!antcomb->scan && (alt_ratio > antcomb->ant_ratio)) |
8da07830 SM |
510 | ant_conf->fast_div_bias = 0x1; |
511 | else | |
512 | ant_conf->fast_div_bias = 0x2; | |
8da07830 SM |
513 | break; |
514 | case 0x20: /* LNA1 A-B */ | |
3afa6b4f | 515 | if (!antcomb->scan && (alt_ratio > antcomb->ant_ratio)) |
8da07830 SM |
516 | ant_conf->fast_div_bias = 0x1; |
517 | else | |
518 | ant_conf->fast_div_bias = 0x2; | |
8da07830 SM |
519 | break; |
520 | case 0x21: /* LNA1 LNA2 */ | |
521 | ant_conf->fast_div_bias = 0x1; | |
8da07830 SM |
522 | break; |
523 | case 0x23: /* LNA1 A+B */ | |
3afa6b4f | 524 | if (!antcomb->scan && (alt_ratio > antcomb->ant_ratio)) |
8da07830 SM |
525 | ant_conf->fast_div_bias = 0x1; |
526 | else | |
527 | ant_conf->fast_div_bias = 0x2; | |
8da07830 SM |
528 | break; |
529 | case 0x30: /* A+B A-B */ | |
530 | ant_conf->fast_div_bias = 0x1; | |
8da07830 SM |
531 | break; |
532 | case 0x31: /* A+B LNA2 */ | |
533 | ant_conf->fast_div_bias = 0x1; | |
8da07830 SM |
534 | break; |
535 | case 0x32: /* A+B LNA1 */ | |
536 | ant_conf->fast_div_bias = 0x1; | |
8da07830 SM |
537 | break; |
538 | default: | |
539 | break; | |
540 | } | |
3afa6b4f SM |
541 | |
542 | if (antcomb->fast_div_bias) | |
543 | ant_conf->fast_div_bias = antcomb->fast_div_bias; | |
5317c9c3 SM |
544 | } else if (ant_conf->div_group == 3) { |
545 | switch ((ant_conf->main_lna_conf << 4) | | |
546 | ant_conf->alt_lna_conf) { | |
547 | case 0x01: /* A-B LNA2 */ | |
548 | ant_conf->fast_div_bias = 0x1; | |
549 | break; | |
550 | case 0x02: /* A-B LNA1 */ | |
551 | ant_conf->fast_div_bias = 0x39; | |
552 | break; | |
553 | case 0x03: /* A-B A+B */ | |
554 | ant_conf->fast_div_bias = 0x1; | |
555 | break; | |
556 | case 0x10: /* LNA2 A-B */ | |
f96bd2ad | 557 | ant_conf->fast_div_bias = 0x2; |
5317c9c3 SM |
558 | break; |
559 | case 0x12: /* LNA2 LNA1 */ | |
f96bd2ad | 560 | ant_conf->fast_div_bias = 0x3f; |
5317c9c3 SM |
561 | break; |
562 | case 0x13: /* LNA2 A+B */ | |
f96bd2ad | 563 | ant_conf->fast_div_bias = 0x2; |
5317c9c3 SM |
564 | break; |
565 | case 0x20: /* LNA1 A-B */ | |
f96bd2ad | 566 | ant_conf->fast_div_bias = 0x3; |
5317c9c3 SM |
567 | break; |
568 | case 0x21: /* LNA1 LNA2 */ | |
f96bd2ad | 569 | ant_conf->fast_div_bias = 0x3; |
5317c9c3 SM |
570 | break; |
571 | case 0x23: /* LNA1 A+B */ | |
f96bd2ad | 572 | ant_conf->fast_div_bias = 0x3; |
5317c9c3 SM |
573 | break; |
574 | case 0x30: /* A+B A-B */ | |
575 | ant_conf->fast_div_bias = 0x1; | |
576 | break; | |
577 | case 0x31: /* A+B LNA2 */ | |
578 | ant_conf->fast_div_bias = 0x6; | |
579 | break; | |
580 | case 0x32: /* A+B LNA1 */ | |
581 | ant_conf->fast_div_bias = 0x1; | |
582 | break; | |
583 | default: | |
584 | break; | |
585 | } | |
8da07830 SM |
586 | } |
587 | } | |
588 | ||
5f800ffb SM |
589 | static void ath_ant_try_scan(struct ath_ant_comb *antcomb, |
590 | struct ath_hw_antcomb_conf *conf, | |
591 | int curr_alt_set, int alt_rssi_avg, | |
592 | int main_rssi_avg) | |
593 | { | |
594 | switch (curr_alt_set) { | |
595 | case ATH_ANT_DIV_COMB_LNA2: | |
596 | antcomb->rssi_lna2 = alt_rssi_avg; | |
597 | antcomb->rssi_lna1 = main_rssi_avg; | |
598 | antcomb->scan = true; | |
599 | /* set to A+B */ | |
600 | conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1; | |
601 | conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2; | |
602 | break; | |
603 | case ATH_ANT_DIV_COMB_LNA1: | |
604 | antcomb->rssi_lna1 = alt_rssi_avg; | |
605 | antcomb->rssi_lna2 = main_rssi_avg; | |
606 | antcomb->scan = true; | |
607 | /* set to A+B */ | |
608 | conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2; | |
609 | conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2; | |
610 | break; | |
611 | case ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2: | |
612 | antcomb->rssi_add = alt_rssi_avg; | |
613 | antcomb->scan = true; | |
614 | /* set to A-B */ | |
615 | conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2; | |
616 | break; | |
617 | case ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2: | |
618 | antcomb->rssi_sub = alt_rssi_avg; | |
619 | antcomb->scan = false; | |
620 | if (antcomb->rssi_lna2 > | |
f96bd2ad | 621 | (antcomb->rssi_lna1 + conf->lna1_lna2_switch_delta)) { |
5f800ffb SM |
622 | /* use LNA2 as main LNA */ |
623 | if ((antcomb->rssi_add > antcomb->rssi_lna1) && | |
624 | (antcomb->rssi_add > antcomb->rssi_sub)) { | |
625 | /* set to A+B */ | |
626 | conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2; | |
627 | conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2; | |
628 | } else if (antcomb->rssi_sub > | |
629 | antcomb->rssi_lna1) { | |
630 | /* set to A-B */ | |
631 | conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2; | |
632 | conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2; | |
633 | } else { | |
634 | /* set to LNA1 */ | |
635 | conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2; | |
636 | conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1; | |
637 | } | |
638 | } else { | |
639 | /* use LNA1 as main LNA */ | |
640 | if ((antcomb->rssi_add > antcomb->rssi_lna2) && | |
641 | (antcomb->rssi_add > antcomb->rssi_sub)) { | |
642 | /* set to A+B */ | |
643 | conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1; | |
644 | conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2; | |
645 | } else if (antcomb->rssi_sub > | |
646 | antcomb->rssi_lna1) { | |
647 | /* set to A-B */ | |
648 | conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1; | |
649 | conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2; | |
650 | } else { | |
651 | /* set to LNA2 */ | |
652 | conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1; | |
653 | conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2; | |
654 | } | |
655 | } | |
656 | break; | |
657 | default: | |
658 | break; | |
659 | } | |
660 | } | |
661 | ||
ef999114 | 662 | static bool ath_ant_try_switch(struct ath_hw_antcomb_conf *div_ant_conf, |
3afa6b4f | 663 | struct ath_ant_comb *antcomb, |
ef999114 SM |
664 | int alt_ratio, int alt_rssi_avg, |
665 | int main_rssi_avg, int curr_main_set, | |
666 | int curr_alt_set) | |
667 | { | |
668 | bool ret = false; | |
669 | ||
3afa6b4f | 670 | if (ath_ant_div_comb_alt_check(div_ant_conf, antcomb, alt_ratio, |
ef999114 SM |
671 | alt_rssi_avg, main_rssi_avg)) { |
672 | if (curr_alt_set == ATH_ANT_DIV_COMB_LNA2) { | |
673 | /* | |
674 | * Switch main and alt LNA. | |
675 | */ | |
676 | div_ant_conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2; | |
677 | div_ant_conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1; | |
678 | } else if (curr_alt_set == ATH_ANT_DIV_COMB_LNA1) { | |
679 | div_ant_conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1; | |
680 | div_ant_conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2; | |
681 | } | |
682 | ||
683 | ret = true; | |
684 | } else if ((curr_alt_set != ATH_ANT_DIV_COMB_LNA1) && | |
685 | (curr_alt_set != ATH_ANT_DIV_COMB_LNA2)) { | |
686 | /* | |
687 | Set alt to another LNA. | |
688 | */ | |
689 | if (curr_main_set == ATH_ANT_DIV_COMB_LNA2) | |
690 | div_ant_conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1; | |
691 | else if (curr_main_set == ATH_ANT_DIV_COMB_LNA1) | |
692 | div_ant_conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2; | |
693 | ||
694 | ret = true; | |
695 | } | |
696 | ||
697 | return ret; | |
698 | } | |
699 | ||
9383be42 SM |
700 | static bool ath_ant_short_scan_check(struct ath_ant_comb *antcomb) |
701 | { | |
702 | int alt_ratio; | |
703 | ||
704 | if (!antcomb->scan || !antcomb->alt_good) | |
705 | return false; | |
706 | ||
707 | if (time_after(jiffies, antcomb->scan_start_time + | |
708 | msecs_to_jiffies(ATH_ANT_DIV_COMB_SHORT_SCAN_INTR))) | |
709 | return true; | |
710 | ||
711 | if (antcomb->total_pkt_count == ATH_ANT_DIV_COMB_SHORT_SCAN_PKTCOUNT) { | |
712 | alt_ratio = ((antcomb->alt_recv_cnt * 100) / | |
713 | antcomb->total_pkt_count); | |
3afa6b4f | 714 | if (alt_ratio < antcomb->ant_ratio) |
9383be42 SM |
715 | return true; |
716 | } | |
717 | ||
718 | return false; | |
719 | } | |
720 | ||
8da07830 SM |
721 | void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs) |
722 | { | |
723 | struct ath_hw_antcomb_conf div_ant_conf; | |
724 | struct ath_ant_comb *antcomb = &sc->ant_comb; | |
725 | int alt_ratio = 0, alt_rssi_avg = 0, main_rssi_avg = 0, curr_alt_set; | |
726 | int curr_main_set; | |
e45e91d8 FF |
727 | int main_rssi = rs->rs_rssi_ctl[0]; |
728 | int alt_rssi = rs->rs_rssi_ctl[1]; | |
8da07830 | 729 | int rx_ant_conf, main_ant_conf; |
ef999114 | 730 | bool short_scan = false, ret; |
8da07830 | 731 | |
e45e91d8 | 732 | rx_ant_conf = (rs->rs_rssi_ctl[2] >> ATH_ANT_RX_CURRENT_SHIFT) & |
8da07830 | 733 | ATH_ANT_RX_MASK; |
e45e91d8 | 734 | main_ant_conf = (rs->rs_rssi_ctl[2] >> ATH_ANT_RX_MAIN_SHIFT) & |
8da07830 SM |
735 | ATH_ANT_RX_MASK; |
736 | ||
3afa6b4f SM |
737 | if (alt_rssi >= antcomb->low_rssi_thresh) { |
738 | antcomb->ant_ratio = ATH_ANT_DIV_COMB_ALT_ANT_RATIO; | |
739 | antcomb->ant_ratio2 = ATH_ANT_DIV_COMB_ALT_ANT_RATIO2; | |
740 | } else { | |
741 | antcomb->ant_ratio = ATH_ANT_DIV_COMB_ALT_ANT_RATIO_LOW_RSSI; | |
742 | antcomb->ant_ratio2 = ATH_ANT_DIV_COMB_ALT_ANT_RATIO2_LOW_RSSI; | |
743 | } | |
744 | ||
8da07830 SM |
745 | /* Record packet only when both main_rssi and alt_rssi is positive */ |
746 | if (main_rssi > 0 && alt_rssi > 0) { | |
747 | antcomb->total_pkt_count++; | |
748 | antcomb->main_total_rssi += main_rssi; | |
749 | antcomb->alt_total_rssi += alt_rssi; | |
3fbaf4c5 | 750 | |
e3d52914 | 751 | if (main_ant_conf == rx_ant_conf) |
8da07830 | 752 | antcomb->main_recv_cnt++; |
e3d52914 | 753 | else |
8da07830 | 754 | antcomb->alt_recv_cnt++; |
e3d52914 SM |
755 | } |
756 | ||
757 | if (main_ant_conf == rx_ant_conf) { | |
758 | ANT_STAT_INC(ANT_MAIN, recv_cnt); | |
759 | ANT_LNA_INC(ANT_MAIN, rx_ant_conf); | |
760 | } else { | |
761 | ANT_STAT_INC(ANT_ALT, recv_cnt); | |
762 | ANT_LNA_INC(ANT_ALT, rx_ant_conf); | |
8da07830 SM |
763 | } |
764 | ||
765 | /* Short scan check */ | |
9383be42 | 766 | short_scan = ath_ant_short_scan_check(antcomb); |
8da07830 SM |
767 | |
768 | if (((antcomb->total_pkt_count < ATH_ANT_DIV_COMB_MAX_PKTCOUNT) || | |
9383be42 | 769 | rs->rs_moreaggr) && !short_scan) |
8da07830 SM |
770 | return; |
771 | ||
772 | if (antcomb->total_pkt_count) { | |
773 | alt_ratio = ((antcomb->alt_recv_cnt * 100) / | |
774 | antcomb->total_pkt_count); | |
775 | main_rssi_avg = (antcomb->main_total_rssi / | |
776 | antcomb->total_pkt_count); | |
777 | alt_rssi_avg = (antcomb->alt_total_rssi / | |
778 | antcomb->total_pkt_count); | |
779 | } | |
780 | ||
8da07830 SM |
781 | ath9k_hw_antdiv_comb_conf_get(sc->sc_ah, &div_ant_conf); |
782 | curr_alt_set = div_ant_conf.alt_lna_conf; | |
783 | curr_main_set = div_ant_conf.main_lna_conf; | |
8da07830 SM |
784 | antcomb->count++; |
785 | ||
786 | if (antcomb->count == ATH_ANT_DIV_COMB_MAX_COUNT) { | |
3afa6b4f | 787 | if (alt_ratio > antcomb->ant_ratio) { |
8da07830 SM |
788 | ath_lnaconf_alt_good_scan(antcomb, div_ant_conf, |
789 | main_rssi_avg); | |
790 | antcomb->alt_good = true; | |
791 | } else { | |
792 | antcomb->alt_good = false; | |
793 | } | |
794 | ||
795 | antcomb->count = 0; | |
796 | antcomb->scan = true; | |
797 | antcomb->scan_not_start = true; | |
798 | } | |
799 | ||
800 | if (!antcomb->scan) { | |
3afa6b4f | 801 | ret = ath_ant_try_switch(&div_ant_conf, antcomb, alt_ratio, |
ef999114 SM |
802 | alt_rssi_avg, main_rssi_avg, |
803 | curr_main_set, curr_alt_set); | |
804 | if (ret) | |
8da07830 SM |
805 | goto div_comb_done; |
806 | } | |
807 | ||
ef999114 SM |
808 | if (!antcomb->scan && |
809 | (alt_rssi_avg < (main_rssi_avg + div_ant_conf.lna1_lna2_delta))) | |
810 | goto div_comb_done; | |
811 | ||
8da07830 | 812 | if (!antcomb->scan_not_start) { |
5f800ffb SM |
813 | ath_ant_try_scan(antcomb, &div_ant_conf, curr_alt_set, |
814 | alt_rssi_avg, main_rssi_avg); | |
8da07830 SM |
815 | } else { |
816 | if (!antcomb->alt_good) { | |
817 | antcomb->scan_not_start = false; | |
818 | /* Set alt to another LNA */ | |
819 | if (curr_main_set == ATH_ANT_DIV_COMB_LNA2) { | |
820 | div_ant_conf.main_lna_conf = | |
5f800ffb | 821 | ATH_ANT_DIV_COMB_LNA2; |
8da07830 | 822 | div_ant_conf.alt_lna_conf = |
5f800ffb | 823 | ATH_ANT_DIV_COMB_LNA1; |
8da07830 SM |
824 | } else if (curr_main_set == ATH_ANT_DIV_COMB_LNA1) { |
825 | div_ant_conf.main_lna_conf = | |
5f800ffb | 826 | ATH_ANT_DIV_COMB_LNA1; |
8da07830 | 827 | div_ant_conf.alt_lna_conf = |
5f800ffb | 828 | ATH_ANT_DIV_COMB_LNA2; |
8da07830 SM |
829 | } |
830 | goto div_comb_done; | |
831 | } | |
3fbaf4c5 SM |
832 | ath_select_ant_div_from_quick_scan(antcomb, &div_ant_conf, |
833 | main_rssi_avg, alt_rssi_avg, | |
834 | alt_ratio); | |
835 | antcomb->quick_scan_cnt++; | |
8da07830 SM |
836 | } |
837 | ||
8da07830 SM |
838 | div_comb_done: |
839 | ath_ant_div_conf_fast_divbias(&div_ant_conf, antcomb, alt_ratio); | |
840 | ath9k_hw_antdiv_comb_conf_set(sc->sc_ah, &div_ant_conf); | |
e3d52914 | 841 | ath9k_debug_stat_ant(sc, &div_ant_conf, main_rssi_avg, alt_rssi_avg); |
8da07830 SM |
842 | |
843 | antcomb->scan_start_time = jiffies; | |
844 | antcomb->total_pkt_count = 0; | |
845 | antcomb->main_total_rssi = 0; | |
846 | antcomb->alt_total_rssi = 0; | |
847 | antcomb->main_recv_cnt = 0; | |
848 | antcomb->alt_recv_cnt = 0; | |
849 | } |