2 * Copyright (c) 2013 Adrian Chadd <adrian@FreeBSD.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer,
10 * without modification.
11 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
12 * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
13 * redistribution must be conditioned upon including a substantially
14 * similar Disclaimer requirement for further binary redistribution.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
20 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21 * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
22 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGES.
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
35 * This module handles LNA diversity for those chips which implement LNA
36 * mixing (AR9285/AR9485.)
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/sysctl.h>
45 #include <sys/kernel.h>
47 #include <sys/malloc.h>
48 #include <sys/mutex.h>
49 #include <sys/errno.h>
51 #include <machine/bus.h>
52 #include <machine/resource.h>
55 #include <sys/socket.h>
58 #include <net/if_var.h>
59 #include <net/if_media.h>
60 #include <net/if_arp.h>
61 #include <net/ethernet.h> /* XXX for ether_sprintf */
63 #include <net80211/ieee80211_var.h>
68 #include <netinet/in.h>
69 #include <netinet/if_ether.h>
72 #include <dev/ath/if_athvar.h>
73 #include <dev/ath/if_ath_debug.h>
74 #include <dev/ath/if_ath_lna_div.h>
76 /* Linux compability macros */
78 * XXX these don't handle rounding, underflow, overflow, wrapping!
80 #define msecs_to_jiffies(a) ( (a) * hz / 1000 )
83 * Methods which are required
87 * Attach the LNA diversity to the given interface
90 ath_lna_div_attach(struct ath_softc *sc)
92 struct if_ath_ant_comb_state *ss;
93 HAL_ANT_COMB_CONFIG div_ant_conf;
95 /* Only do this if diversity is enabled */
96 if (! ath_hal_hasdivantcomb(sc->sc_ah))
99 ss = malloc(sizeof(struct if_ath_ant_comb_state),
100 M_TEMP, M_WAITOK | M_ZERO);
102 device_printf(sc->sc_dev, "%s: failed to allocate\n",
104 /* Don't fail at this point */
108 /* Fetch the hardware configuration */
109 OS_MEMZERO(&div_ant_conf, sizeof(div_ant_conf));
110 ath_hal_div_comb_conf_get(sc->sc_ah, &div_ant_conf);
112 /* Figure out what the hardware specific bits should be */
113 if ((div_ant_conf.antdiv_configgroup == HAL_ANTDIV_CONFIG_GROUP_1) ||
114 (div_ant_conf.antdiv_configgroup == HAL_ANTDIV_CONFIG_GROUP_2)) {
115 ss->lna1_lna2_delta = -9;
117 ss->lna1_lna2_delta = -3;
120 /* Let's flip this on */
128 * Detach the LNA diversity state from the given interface
131 ath_lna_div_detach(struct ath_softc *sc)
133 if (sc->sc_lna_div != NULL) {
134 free(sc->sc_lna_div, M_TEMP);
135 sc->sc_lna_div = NULL;
142 * Enable LNA diversity on the current channel if it's required.
145 ath_lna_div_enable(struct ath_softc *sc, const struct ieee80211_channel *chan)
152 * Handle ioctl requests from the diagnostic interface.
154 * The initial part of this code resembles ath_ioctl_diag();
155 * it's likely a good idea to reduce duplication between
156 * these two routines.
159 ath_lna_div_ioctl(struct ath_softc *sc, struct ath_diag *ad)
161 unsigned int id = ad->ad_id & ATH_DIAG_ID;
163 void *outdata = NULL;
164 u_int32_t insize = ad->ad_in_size;
165 u_int32_t outsize = ad->ad_out_size;
169 if (ad->ad_id & ATH_DIAG_IN) {
173 indata = malloc(insize, M_TEMP, M_NOWAIT);
174 if (indata == NULL) {
178 error = copyin(ad->ad_in_data, indata, insize);
182 if (ad->ad_id & ATH_DIAG_DYN) {
184 * Allocate a buffer for the results (otherwise the HAL
185 * returns a pointer to a buffer where we can read the
186 * results). Note that we depend on the HAL leaving this
187 * pointer for us to use below in reclaiming the buffer;
188 * may want to be more defensive.
190 outdata = malloc(outsize, M_TEMP, M_NOWAIT);
191 if (outdata == NULL) {
200 if (outsize < ad->ad_out_size)
201 ad->ad_out_size = outsize;
202 if (outdata && copyout(outdata, ad->ad_out_data, ad->ad_out_size))
205 if ((ad->ad_id & ATH_DIAG_IN) && indata != NULL)
206 free(indata, M_TEMP);
207 if ((ad->ad_id & ATH_DIAG_DYN) && outdata != NULL)
208 free(outdata, M_TEMP);
213 ath_is_alt_ant_ratio_better(int alt_ratio, int maxdelta, int mindelta,
214 int main_rssi_avg, int alt_rssi_avg, int pkt_count)
216 return (((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) &&
217 (alt_rssi_avg > main_rssi_avg + maxdelta)) ||
218 (alt_rssi_avg > main_rssi_avg + mindelta)) && (pkt_count > 50);
222 ath_lnaconf_alt_good_scan(struct if_ath_ant_comb_state *antcomb,
223 HAL_ANT_COMB_CONFIG *ant_conf, int main_rssi_avg)
225 antcomb->quick_scan_cnt = 0;
227 if (ant_conf->main_lna_conf == HAL_ANT_DIV_COMB_LNA2)
228 antcomb->rssi_lna2 = main_rssi_avg;
229 else if (ant_conf->main_lna_conf == HAL_ANT_DIV_COMB_LNA1)
230 antcomb->rssi_lna1 = main_rssi_avg;
232 switch ((ant_conf->main_lna_conf << 4) | ant_conf->alt_lna_conf) {
233 case (0x10): /* LNA2 A-B */
234 antcomb->main_conf = HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2;
235 antcomb->first_quick_scan_conf =
236 HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2;
237 antcomb->second_quick_scan_conf = HAL_ANT_DIV_COMB_LNA1;
239 case (0x20): /* LNA1 A-B */
240 antcomb->main_conf = HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2;
241 antcomb->first_quick_scan_conf =
242 HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2;
243 antcomb->second_quick_scan_conf = HAL_ANT_DIV_COMB_LNA2;
245 case (0x21): /* LNA1 LNA2 */
246 antcomb->main_conf = HAL_ANT_DIV_COMB_LNA2;
247 antcomb->first_quick_scan_conf =
248 HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2;
249 antcomb->second_quick_scan_conf =
250 HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2;
252 case (0x12): /* LNA2 LNA1 */
253 antcomb->main_conf = HAL_ANT_DIV_COMB_LNA1;
254 antcomb->first_quick_scan_conf =
255 HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2;
256 antcomb->second_quick_scan_conf =
257 HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2;
259 case (0x13): /* LNA2 A+B */
260 antcomb->main_conf = HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2;
261 antcomb->first_quick_scan_conf =
262 HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2;
263 antcomb->second_quick_scan_conf = HAL_ANT_DIV_COMB_LNA1;
265 case (0x23): /* LNA1 A+B */
266 antcomb->main_conf = HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2;
267 antcomb->first_quick_scan_conf =
268 HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2;
269 antcomb->second_quick_scan_conf = HAL_ANT_DIV_COMB_LNA2;
277 ath_select_ant_div_from_quick_scan(struct if_ath_ant_comb_state *antcomb,
278 HAL_ANT_COMB_CONFIG *div_ant_conf, int main_rssi_avg,
279 int alt_rssi_avg, int alt_ratio)
282 switch (antcomb->quick_scan_cnt) {
284 /* set alt to main, and alt to first conf */
285 div_ant_conf->main_lna_conf = antcomb->main_conf;
286 div_ant_conf->alt_lna_conf = antcomb->first_quick_scan_conf;
289 /* set alt to main, and alt to first conf */
290 div_ant_conf->main_lna_conf = antcomb->main_conf;
291 div_ant_conf->alt_lna_conf = antcomb->second_quick_scan_conf;
292 antcomb->rssi_first = main_rssi_avg;
293 antcomb->rssi_second = alt_rssi_avg;
295 if (antcomb->main_conf == HAL_ANT_DIV_COMB_LNA1) {
297 if (ath_is_alt_ant_ratio_better(alt_ratio,
298 ATH_ANT_DIV_COMB_LNA1_DELTA_HI,
299 ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
300 main_rssi_avg, alt_rssi_avg,
301 antcomb->total_pkt_count))
302 antcomb->first_ratio = AH_TRUE;
304 antcomb->first_ratio = AH_FALSE;
305 } else if (antcomb->main_conf == HAL_ANT_DIV_COMB_LNA2) {
306 if (ath_is_alt_ant_ratio_better(alt_ratio,
307 ATH_ANT_DIV_COMB_LNA1_DELTA_MID,
308 ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
309 main_rssi_avg, alt_rssi_avg,
310 antcomb->total_pkt_count))
311 antcomb->first_ratio = AH_TRUE;
313 antcomb->first_ratio = AH_FALSE;
315 if ((((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) &&
316 (alt_rssi_avg > main_rssi_avg +
317 ATH_ANT_DIV_COMB_LNA1_DELTA_HI)) ||
318 (alt_rssi_avg > main_rssi_avg)) &&
319 (antcomb->total_pkt_count > 50))
320 antcomb->first_ratio = AH_TRUE;
322 antcomb->first_ratio = AH_FALSE;
326 antcomb->alt_good = AH_FALSE;
327 antcomb->scan_not_start = AH_FALSE;
328 antcomb->scan = AH_FALSE;
329 antcomb->rssi_first = main_rssi_avg;
330 antcomb->rssi_third = alt_rssi_avg;
332 if (antcomb->second_quick_scan_conf == HAL_ANT_DIV_COMB_LNA1)
333 antcomb->rssi_lna1 = alt_rssi_avg;
334 else if (antcomb->second_quick_scan_conf ==
335 HAL_ANT_DIV_COMB_LNA2)
336 antcomb->rssi_lna2 = alt_rssi_avg;
337 else if (antcomb->second_quick_scan_conf ==
338 HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2) {
339 if (antcomb->main_conf == HAL_ANT_DIV_COMB_LNA2)
340 antcomb->rssi_lna2 = main_rssi_avg;
341 else if (antcomb->main_conf == HAL_ANT_DIV_COMB_LNA1)
342 antcomb->rssi_lna1 = main_rssi_avg;
345 if (antcomb->rssi_lna2 > antcomb->rssi_lna1 +
346 ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA)
347 div_ant_conf->main_lna_conf = HAL_ANT_DIV_COMB_LNA2;
349 div_ant_conf->main_lna_conf = HAL_ANT_DIV_COMB_LNA1;
351 if (antcomb->main_conf == HAL_ANT_DIV_COMB_LNA1) {
352 if (ath_is_alt_ant_ratio_better(alt_ratio,
353 ATH_ANT_DIV_COMB_LNA1_DELTA_HI,
354 ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
355 main_rssi_avg, alt_rssi_avg,
356 antcomb->total_pkt_count))
357 antcomb->second_ratio = AH_TRUE;
359 antcomb->second_ratio = AH_FALSE;
360 } else if (antcomb->main_conf == HAL_ANT_DIV_COMB_LNA2) {
361 if (ath_is_alt_ant_ratio_better(alt_ratio,
362 ATH_ANT_DIV_COMB_LNA1_DELTA_MID,
363 ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
364 main_rssi_avg, alt_rssi_avg,
365 antcomb->total_pkt_count))
366 antcomb->second_ratio = AH_TRUE;
368 antcomb->second_ratio = AH_FALSE;
370 if ((((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) &&
371 (alt_rssi_avg > main_rssi_avg +
372 ATH_ANT_DIV_COMB_LNA1_DELTA_HI)) ||
373 (alt_rssi_avg > main_rssi_avg)) &&
374 (antcomb->total_pkt_count > 50))
375 antcomb->second_ratio = AH_TRUE;
377 antcomb->second_ratio = AH_FALSE;
380 /* set alt to the conf with maximun ratio */
381 if (antcomb->first_ratio && antcomb->second_ratio) {
382 if (antcomb->rssi_second > antcomb->rssi_third) {
384 if ((antcomb->first_quick_scan_conf ==
385 HAL_ANT_DIV_COMB_LNA1) ||
386 (antcomb->first_quick_scan_conf ==
387 HAL_ANT_DIV_COMB_LNA2))
388 /* Set alt LNA1 or LNA2*/
389 if (div_ant_conf->main_lna_conf ==
390 HAL_ANT_DIV_COMB_LNA2)
391 div_ant_conf->alt_lna_conf =
392 HAL_ANT_DIV_COMB_LNA1;
394 div_ant_conf->alt_lna_conf =
395 HAL_ANT_DIV_COMB_LNA2;
397 /* Set alt to A+B or A-B */
398 div_ant_conf->alt_lna_conf =
399 antcomb->first_quick_scan_conf;
400 } else if ((antcomb->second_quick_scan_conf ==
401 HAL_ANT_DIV_COMB_LNA1) ||
402 (antcomb->second_quick_scan_conf ==
403 HAL_ANT_DIV_COMB_LNA2)) {
404 /* Set alt LNA1 or LNA2 */
405 if (div_ant_conf->main_lna_conf ==
406 HAL_ANT_DIV_COMB_LNA2)
407 div_ant_conf->alt_lna_conf =
408 HAL_ANT_DIV_COMB_LNA1;
410 div_ant_conf->alt_lna_conf =
411 HAL_ANT_DIV_COMB_LNA2;
413 /* Set alt to A+B or A-B */
414 div_ant_conf->alt_lna_conf =
415 antcomb->second_quick_scan_conf;
417 } else if (antcomb->first_ratio) {
419 if ((antcomb->first_quick_scan_conf ==
420 HAL_ANT_DIV_COMB_LNA1) ||
421 (antcomb->first_quick_scan_conf ==
422 HAL_ANT_DIV_COMB_LNA2))
423 /* Set alt LNA1 or LNA2 */
424 if (div_ant_conf->main_lna_conf ==
425 HAL_ANT_DIV_COMB_LNA2)
426 div_ant_conf->alt_lna_conf =
427 HAL_ANT_DIV_COMB_LNA1;
429 div_ant_conf->alt_lna_conf =
430 HAL_ANT_DIV_COMB_LNA2;
432 /* Set alt to A+B or A-B */
433 div_ant_conf->alt_lna_conf =
434 antcomb->first_quick_scan_conf;
435 } else if (antcomb->second_ratio) {
437 if ((antcomb->second_quick_scan_conf ==
438 HAL_ANT_DIV_COMB_LNA1) ||
439 (antcomb->second_quick_scan_conf ==
440 HAL_ANT_DIV_COMB_LNA2))
441 /* Set alt LNA1 or LNA2 */
442 if (div_ant_conf->main_lna_conf ==
443 HAL_ANT_DIV_COMB_LNA2)
444 div_ant_conf->alt_lna_conf =
445 HAL_ANT_DIV_COMB_LNA1;
447 div_ant_conf->alt_lna_conf =
448 HAL_ANT_DIV_COMB_LNA2;
450 /* Set alt to A+B or A-B */
451 div_ant_conf->alt_lna_conf =
452 antcomb->second_quick_scan_conf;
454 /* main is largest */
455 if ((antcomb->main_conf == HAL_ANT_DIV_COMB_LNA1) ||
456 (antcomb->main_conf == HAL_ANT_DIV_COMB_LNA2))
457 /* Set alt LNA1 or LNA2 */
458 if (div_ant_conf->main_lna_conf ==
459 HAL_ANT_DIV_COMB_LNA2)
460 div_ant_conf->alt_lna_conf =
461 HAL_ANT_DIV_COMB_LNA1;
463 div_ant_conf->alt_lna_conf =
464 HAL_ANT_DIV_COMB_LNA2;
466 /* Set alt to A+B or A-B */
467 div_ant_conf->alt_lna_conf = antcomb->main_conf;
476 ath_ant_adjust_fast_divbias(struct if_ath_ant_comb_state *antcomb,
477 int alt_ratio, int alt_ant_ratio_th, u_int config_group,
478 HAL_ANT_COMB_CONFIG *pdiv_ant_conf)
481 if (config_group == HAL_ANTDIV_CONFIG_GROUP_1) {
482 switch ((pdiv_ant_conf->main_lna_conf << 4)
483 | pdiv_ant_conf->alt_lna_conf) {
484 case (0x01): //A-B LNA2
485 pdiv_ant_conf->fast_div_bias = 0x1;
486 pdiv_ant_conf->main_gaintb = 0;
487 pdiv_ant_conf->alt_gaintb = 0;
489 case (0x02): //A-B LNA1
490 pdiv_ant_conf->fast_div_bias = 0x1;
491 pdiv_ant_conf->main_gaintb = 0;
492 pdiv_ant_conf->alt_gaintb = 0;
494 case (0x03): //A-B A+B
495 pdiv_ant_conf->fast_div_bias = 0x1;
496 pdiv_ant_conf->main_gaintb = 0;
497 pdiv_ant_conf->alt_gaintb = 0;
499 case (0x10): //LNA2 A-B
500 if ((antcomb->scan == 0)
501 && (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) {
502 pdiv_ant_conf->fast_div_bias = 0x3f;
504 pdiv_ant_conf->fast_div_bias = 0x1;
506 pdiv_ant_conf->main_gaintb = 0;
507 pdiv_ant_conf->alt_gaintb = 0;
509 case (0x12): //LNA2 LNA1
510 pdiv_ant_conf->fast_div_bias = 0x1;
511 pdiv_ant_conf->main_gaintb = 0;
512 pdiv_ant_conf->alt_gaintb = 0;
514 case (0x13): //LNA2 A+B
515 if ((antcomb->scan == 0)
516 && (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) {
517 pdiv_ant_conf->fast_div_bias = 0x3f;
519 pdiv_ant_conf->fast_div_bias = 0x1;
521 pdiv_ant_conf->main_gaintb = 0;
522 pdiv_ant_conf->alt_gaintb = 0;
524 case (0x20): //LNA1 A-B
525 if ((antcomb->scan == 0)
526 && (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) {
527 pdiv_ant_conf->fast_div_bias = 0x3f;
529 pdiv_ant_conf->fast_div_bias = 0x1;
531 pdiv_ant_conf->main_gaintb = 0;
532 pdiv_ant_conf->alt_gaintb = 0;
534 case (0x21): //LNA1 LNA2
535 pdiv_ant_conf->fast_div_bias = 0x1;
536 pdiv_ant_conf->main_gaintb = 0;
537 pdiv_ant_conf->alt_gaintb = 0;
539 case (0x23): //LNA1 A+B
540 if ((antcomb->scan == 0)
541 && (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) {
542 pdiv_ant_conf->fast_div_bias = 0x3f;
544 pdiv_ant_conf->fast_div_bias = 0x1;
546 pdiv_ant_conf->main_gaintb = 0;
547 pdiv_ant_conf->alt_gaintb = 0;
549 case (0x30): //A+B A-B
550 pdiv_ant_conf->fast_div_bias = 0x1;
551 pdiv_ant_conf->main_gaintb = 0;
552 pdiv_ant_conf->alt_gaintb = 0;
554 case (0x31): //A+B LNA2
555 pdiv_ant_conf->fast_div_bias = 0x1;
556 pdiv_ant_conf->main_gaintb = 0;
557 pdiv_ant_conf->alt_gaintb = 0;
559 case (0x32): //A+B LNA1
560 pdiv_ant_conf->fast_div_bias = 0x1;
561 pdiv_ant_conf->main_gaintb = 0;
562 pdiv_ant_conf->alt_gaintb = 0;
567 } else if (config_group == HAL_ANTDIV_CONFIG_GROUP_2) {
568 switch ((pdiv_ant_conf->main_lna_conf << 4)
569 | pdiv_ant_conf->alt_lna_conf) {
570 case (0x01): //A-B LNA2
571 pdiv_ant_conf->fast_div_bias = 0x1;
572 pdiv_ant_conf->main_gaintb = 0;
573 pdiv_ant_conf->alt_gaintb = 0;
575 case (0x02): //A-B LNA1
576 pdiv_ant_conf->fast_div_bias = 0x1;
577 pdiv_ant_conf->main_gaintb = 0;
578 pdiv_ant_conf->alt_gaintb = 0;
580 case (0x03): //A-B A+B
581 pdiv_ant_conf->fast_div_bias = 0x1;
582 pdiv_ant_conf->main_gaintb = 0;
583 pdiv_ant_conf->alt_gaintb = 0;
585 case (0x10): //LNA2 A-B
586 if ((antcomb->scan == 0)
587 && (alt_ratio > alt_ant_ratio_th)) {
588 pdiv_ant_conf->fast_div_bias = 0x1;
590 pdiv_ant_conf->fast_div_bias = 0x2;
592 pdiv_ant_conf->main_gaintb = 0;
593 pdiv_ant_conf->alt_gaintb = 0;
595 case (0x12): //LNA2 LNA1
596 pdiv_ant_conf->fast_div_bias = 0x1;
597 pdiv_ant_conf->main_gaintb = 0;
598 pdiv_ant_conf->alt_gaintb = 0;
600 case (0x13): //LNA2 A+B
601 if ((antcomb->scan == 0)
602 && (alt_ratio > alt_ant_ratio_th)) {
603 pdiv_ant_conf->fast_div_bias = 0x1;
605 pdiv_ant_conf->fast_div_bias = 0x2;
607 pdiv_ant_conf->main_gaintb = 0;
608 pdiv_ant_conf->alt_gaintb = 0;
610 case (0x20): //LNA1 A-B
611 if ((antcomb->scan == 0)
612 && (alt_ratio > alt_ant_ratio_th)) {
613 pdiv_ant_conf->fast_div_bias = 0x1;
615 pdiv_ant_conf->fast_div_bias = 0x2;
617 pdiv_ant_conf->main_gaintb = 0;
618 pdiv_ant_conf->alt_gaintb = 0;
620 case (0x21): //LNA1 LNA2
621 pdiv_ant_conf->fast_div_bias = 0x1;
622 pdiv_ant_conf->main_gaintb = 0;
623 pdiv_ant_conf->alt_gaintb = 0;
625 case (0x23): //LNA1 A+B
626 if ((antcomb->scan == 0)
627 && (alt_ratio > alt_ant_ratio_th)) {
628 pdiv_ant_conf->fast_div_bias = 0x1;
630 pdiv_ant_conf->fast_div_bias = 0x2;
632 pdiv_ant_conf->main_gaintb = 0;
633 pdiv_ant_conf->alt_gaintb = 0;
635 case (0x30): //A+B A-B
636 pdiv_ant_conf->fast_div_bias = 0x1;
637 pdiv_ant_conf->main_gaintb = 0;
638 pdiv_ant_conf->alt_gaintb = 0;
640 case (0x31): //A+B LNA2
641 pdiv_ant_conf->fast_div_bias = 0x1;
642 pdiv_ant_conf->main_gaintb = 0;
643 pdiv_ant_conf->alt_gaintb = 0;
645 case (0x32): //A+B LNA1
646 pdiv_ant_conf->fast_div_bias = 0x1;
647 pdiv_ant_conf->main_gaintb = 0;
648 pdiv_ant_conf->alt_gaintb = 0;
653 } else { /* DEFAULT_ANTDIV_CONFIG_GROUP */
654 switch ((pdiv_ant_conf->main_lna_conf << 4) | pdiv_ant_conf->alt_lna_conf) {
655 case (0x01): //A-B LNA2
656 pdiv_ant_conf->fast_div_bias = 0x3b;
658 case (0x02): //A-B LNA1
659 pdiv_ant_conf->fast_div_bias = 0x3d;
661 case (0x03): //A-B A+B
662 pdiv_ant_conf->fast_div_bias = 0x1;
664 case (0x10): //LNA2 A-B
665 pdiv_ant_conf->fast_div_bias = 0x7;
667 case (0x12): //LNA2 LNA1
668 pdiv_ant_conf->fast_div_bias = 0x2;
670 case (0x13): //LNA2 A+B
671 pdiv_ant_conf->fast_div_bias = 0x7;
673 case (0x20): //LNA1 A-B
674 pdiv_ant_conf->fast_div_bias = 0x6;
676 case (0x21): //LNA1 LNA2
677 pdiv_ant_conf->fast_div_bias = 0x0;
679 case (0x23): //LNA1 A+B
680 pdiv_ant_conf->fast_div_bias = 0x6;
682 case (0x30): //A+B A-B
683 pdiv_ant_conf->fast_div_bias = 0x1;
685 case (0x31): //A+B LNA2
686 pdiv_ant_conf->fast_div_bias = 0x3b;
688 case (0x32): //A+B LNA1
689 pdiv_ant_conf->fast_div_bias = 0x3d;
698 * AR9485/AR933x TODO:
699 * + Select a ratio based on whether RSSI is low or not; but I need
700 * to figure out what "low_rssi_th" is sourced from.
701 * + What's ath_ant_div_comb_alt_check() in the reference driver do?
702 * + .. and there's likely a bunch of other things to include in this.
705 /* Antenna diversity and combining */
707 ath_lna_rx_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs,
708 unsigned long ticks, int hz)
710 HAL_ANT_COMB_CONFIG div_ant_conf;
711 struct if_ath_ant_comb_state *antcomb = sc->sc_lna_div;
712 int alt_ratio = 0, alt_rssi_avg = 0, main_rssi_avg = 0, curr_alt_set;
713 int curr_main_set, curr_bias;
714 int main_rssi = rs->rs_rssi_ctl[0];
715 int alt_rssi = rs->rs_rssi_ctl[1];
716 int rx_ant_conf, main_ant_conf, alt_ant_conf;
717 HAL_BOOL short_scan = AH_FALSE;
719 rx_ant_conf = (rs->rs_rssi_ctl[2] >> 4) & ATH_ANT_RX_MASK;
720 main_ant_conf = (rs->rs_rssi_ctl[2] >> 2) & ATH_ANT_RX_MASK;
721 alt_ant_conf = (rs->rs_rssi_ctl[2] >> 0) & ATH_ANT_RX_MASK;
724 DPRINTF(sc, ATH_DEBUG_DIVERSITY,
725 "%s: RSSI %d/%d, conf %x/%x, rxconf %x, LNA: %d; ANT: %d; "
733 !!(rs->rs_rssi_ctl[2] & 0x80),
734 !!(rs->rs_rssi_ctl[2] & 0x40),
735 !!(rs->rs_rssi_ext[2] & 0x40));
739 * If LNA diversity combining isn't enabled, don't run this.
741 if (! sc->sc_dolnadiv)
745 * XXX this is ugly, but the HAL code attaches the
746 * LNA diversity to the TX antenna settings.
749 if (sc->sc_txantenna != HAL_ANT_VARIABLE)
752 /* Record packet only when alt_rssi is positive */
753 if (main_rssi > 0 && alt_rssi > 0) {
754 antcomb->total_pkt_count++;
755 antcomb->main_total_rssi += main_rssi;
756 antcomb->alt_total_rssi += alt_rssi;
757 if (main_ant_conf == rx_ant_conf)
758 antcomb->main_recv_cnt++;
760 antcomb->alt_recv_cnt++;
763 /* Short scan check */
764 if (antcomb->scan && antcomb->alt_good) {
765 if (time_after(ticks, antcomb->scan_start_time +
766 msecs_to_jiffies(ATH_ANT_DIV_COMB_SHORT_SCAN_INTR)))
767 short_scan = AH_TRUE;
769 if (antcomb->total_pkt_count ==
770 ATH_ANT_DIV_COMB_SHORT_SCAN_PKTCOUNT) {
771 alt_ratio = ((antcomb->alt_recv_cnt * 100) /
772 antcomb->total_pkt_count);
773 if (alt_ratio < ATH_ANT_DIV_COMB_ALT_ANT_RATIO)
774 short_scan = AH_TRUE;
779 DPRINTF(sc, ATH_DEBUG_DIVERSITY,
780 "%s: total pkt=%d, aggr=%d, short_scan=%d\n",
782 antcomb->total_pkt_count,
783 !! (rs->rs_moreaggr),
787 if (((antcomb->total_pkt_count < ATH_ANT_DIV_COMB_MAX_PKTCOUNT) ||
788 rs->rs_moreaggr) && !short_scan)
791 if (antcomb->total_pkt_count) {
792 alt_ratio = ((antcomb->alt_recv_cnt * 100) /
793 antcomb->total_pkt_count);
794 main_rssi_avg = (antcomb->main_total_rssi /
795 antcomb->total_pkt_count);
796 alt_rssi_avg = (antcomb->alt_total_rssi /
797 antcomb->total_pkt_count);
800 OS_MEMZERO(&div_ant_conf, sizeof(div_ant_conf));
802 ath_hal_div_comb_conf_get(sc->sc_ah, &div_ant_conf);
803 curr_alt_set = div_ant_conf.alt_lna_conf;
804 curr_main_set = div_ant_conf.main_lna_conf;
805 curr_bias = div_ant_conf.fast_div_bias;
809 if (antcomb->count == ATH_ANT_DIV_COMB_MAX_COUNT) {
810 if (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO) {
811 ath_lnaconf_alt_good_scan(antcomb, &div_ant_conf,
813 antcomb->alt_good = AH_TRUE;
815 antcomb->alt_good = AH_FALSE;
819 antcomb->scan = AH_TRUE;
820 antcomb->scan_not_start = AH_TRUE;
823 if (!antcomb->scan) {
824 if (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO) {
825 if (curr_alt_set == HAL_ANT_DIV_COMB_LNA2) {
826 /* Switch main and alt LNA */
827 div_ant_conf.main_lna_conf =
828 HAL_ANT_DIV_COMB_LNA2;
829 div_ant_conf.alt_lna_conf =
830 HAL_ANT_DIV_COMB_LNA1;
831 } else if (curr_alt_set == HAL_ANT_DIV_COMB_LNA1) {
832 div_ant_conf.main_lna_conf =
833 HAL_ANT_DIV_COMB_LNA1;
834 div_ant_conf.alt_lna_conf =
835 HAL_ANT_DIV_COMB_LNA2;
839 } else if ((curr_alt_set != HAL_ANT_DIV_COMB_LNA1) &&
840 (curr_alt_set != HAL_ANT_DIV_COMB_LNA2)) {
841 /* Set alt to another LNA */
842 if (curr_main_set == HAL_ANT_DIV_COMB_LNA2)
843 div_ant_conf.alt_lna_conf =
844 HAL_ANT_DIV_COMB_LNA1;
845 else if (curr_main_set == HAL_ANT_DIV_COMB_LNA1)
846 div_ant_conf.alt_lna_conf =
847 HAL_ANT_DIV_COMB_LNA2;
852 if ((alt_rssi_avg < (main_rssi_avg +
853 antcomb->lna1_lna2_delta)))
857 if (!antcomb->scan_not_start) {
858 switch (curr_alt_set) {
859 case HAL_ANT_DIV_COMB_LNA2:
860 antcomb->rssi_lna2 = alt_rssi_avg;
861 antcomb->rssi_lna1 = main_rssi_avg;
862 antcomb->scan = AH_TRUE;
864 div_ant_conf.main_lna_conf =
865 HAL_ANT_DIV_COMB_LNA1;
866 div_ant_conf.alt_lna_conf =
867 HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2;
869 case HAL_ANT_DIV_COMB_LNA1:
870 antcomb->rssi_lna1 = alt_rssi_avg;
871 antcomb->rssi_lna2 = main_rssi_avg;
872 antcomb->scan = AH_TRUE;
874 div_ant_conf.main_lna_conf = HAL_ANT_DIV_COMB_LNA2;
875 div_ant_conf.alt_lna_conf =
876 HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2;
878 case HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2:
879 antcomb->rssi_add = alt_rssi_avg;
880 antcomb->scan = AH_TRUE;
882 div_ant_conf.alt_lna_conf =
883 HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2;
885 case HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2:
886 antcomb->rssi_sub = alt_rssi_avg;
887 antcomb->scan = AH_FALSE;
888 if (antcomb->rssi_lna2 >
889 (antcomb->rssi_lna1 +
890 ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA)) {
891 /* use LNA2 as main LNA */
892 if ((antcomb->rssi_add > antcomb->rssi_lna1) &&
893 (antcomb->rssi_add > antcomb->rssi_sub)) {
895 div_ant_conf.main_lna_conf =
896 HAL_ANT_DIV_COMB_LNA2;
897 div_ant_conf.alt_lna_conf =
898 HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2;
899 } else if (antcomb->rssi_sub >
900 antcomb->rssi_lna1) {
902 div_ant_conf.main_lna_conf =
903 HAL_ANT_DIV_COMB_LNA2;
904 div_ant_conf.alt_lna_conf =
905 HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2;
908 div_ant_conf.main_lna_conf =
909 HAL_ANT_DIV_COMB_LNA2;
910 div_ant_conf.alt_lna_conf =
911 HAL_ANT_DIV_COMB_LNA1;
914 /* use LNA1 as main LNA */
915 if ((antcomb->rssi_add > antcomb->rssi_lna2) &&
916 (antcomb->rssi_add > antcomb->rssi_sub)) {
918 div_ant_conf.main_lna_conf =
919 HAL_ANT_DIV_COMB_LNA1;
920 div_ant_conf.alt_lna_conf =
921 HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2;
922 } else if (antcomb->rssi_sub >
923 antcomb->rssi_lna1) {
925 div_ant_conf.main_lna_conf =
926 HAL_ANT_DIV_COMB_LNA1;
927 div_ant_conf.alt_lna_conf =
928 HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2;
931 div_ant_conf.main_lna_conf =
932 HAL_ANT_DIV_COMB_LNA1;
933 div_ant_conf.alt_lna_conf =
934 HAL_ANT_DIV_COMB_LNA2;
942 if (!antcomb->alt_good) {
943 antcomb->scan_not_start = AH_FALSE;
944 /* Set alt to another LNA */
945 if (curr_main_set == HAL_ANT_DIV_COMB_LNA2) {
946 div_ant_conf.main_lna_conf =
947 HAL_ANT_DIV_COMB_LNA2;
948 div_ant_conf.alt_lna_conf =
949 HAL_ANT_DIV_COMB_LNA1;
950 } else if (curr_main_set == HAL_ANT_DIV_COMB_LNA1) {
951 div_ant_conf.main_lna_conf =
952 HAL_ANT_DIV_COMB_LNA1;
953 div_ant_conf.alt_lna_conf =
954 HAL_ANT_DIV_COMB_LNA2;
960 ath_select_ant_div_from_quick_scan(antcomb, &div_ant_conf,
961 main_rssi_avg, alt_rssi_avg,
964 antcomb->quick_scan_cnt++;
968 ath_ant_div_conf_fast_divbias(&div_ant_conf);
971 ath_ant_adjust_fast_divbias(antcomb,
973 ATH_ANT_DIV_COMB_ALT_ANT_RATIO,
974 div_ant_conf.antdiv_configgroup,
977 ath_hal_div_comb_conf_set(sc->sc_ah, &div_ant_conf);
979 DPRINTF(sc, ATH_DEBUG_DIVERSITY, "%s: total_pkt_count=%d\n",
980 __func__, antcomb->total_pkt_count);
982 DPRINTF(sc, ATH_DEBUG_DIVERSITY, "%s: main_total_rssi=%d\n",
983 __func__, antcomb->main_total_rssi);
984 DPRINTF(sc, ATH_DEBUG_DIVERSITY, "%s: alt_total_rssi=%d\n",
985 __func__, antcomb->alt_total_rssi);
987 DPRINTF(sc, ATH_DEBUG_DIVERSITY, "%s: main_rssi_avg=%d\n",
988 __func__, main_rssi_avg);
989 DPRINTF(sc, ATH_DEBUG_DIVERSITY, "%s: alt_alt_rssi_avg=%d\n",
990 __func__, alt_rssi_avg);
992 DPRINTF(sc, ATH_DEBUG_DIVERSITY, "%s: main_recv_cnt=%d\n",
993 __func__, antcomb->main_recv_cnt);
994 DPRINTF(sc, ATH_DEBUG_DIVERSITY, "%s: alt_recv_cnt=%d\n",
995 __func__, antcomb->alt_recv_cnt);
997 // if (curr_alt_set != div_ant_conf.alt_lna_conf)
998 DPRINTF(sc, ATH_DEBUG_DIVERSITY, "%s: lna_conf: %x -> %x\n",
999 __func__, curr_alt_set, div_ant_conf.alt_lna_conf);
1000 // if (curr_main_set != div_ant_conf.main_lna_conf)
1001 DPRINTF(sc, ATH_DEBUG_DIVERSITY, "%s: main_lna_conf: %x -> %x\n",
1002 __func__, curr_main_set, div_ant_conf.main_lna_conf);
1003 // if (curr_bias != div_ant_conf.fast_div_bias)
1004 DPRINTF(sc, ATH_DEBUG_DIVERSITY, "%s: fast_div_bias: %x -> %x\n",
1005 __func__, curr_bias, div_ant_conf.fast_div_bias);
1007 antcomb->scan_start_time = ticks;
1008 antcomb->total_pkt_count = 0;
1009 antcomb->main_total_rssi = 0;
1010 antcomb->alt_total_rssi = 0;
1011 antcomb->main_recv_cnt = 0;
1012 antcomb->alt_recv_cnt = 0;