ar9285_diversity.c revision 221694
1193323Sed/* 2193323Sed * Copyright (c) 2008-2010 Atheros Communications Inc. 3193323Sed * Copyright (c) 2011 Adrian Chadd, Xenion Pty Ltd. 4193323Sed * 5193323Sed * Redistribution and use in source and binary forms, with or without 6193323Sed * modification, are permitted provided that the following conditions 7193323Sed * are met: 8193323Sed * 1. Redistributions of source code must retain the above copyright 9193323Sed * notice, this list of conditions and the following disclaimer. 10193323Sed * 2. Redistributions in binary form must reproduce the above copyright 11193323Sed * notice, this list of conditions and the following disclaimer in the 12193323Sed * documentation and/or other materials provided with the distribution. 13193323Sed * 14193323Sed * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15193323Sed * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16193323Sed * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17193323Sed * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18193323Sed * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19193323Sed * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20193323Sed * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21193323Sed * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22193323Sed * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23193323Sed * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24193323Sed * SUCH DAMAGE. 25193323Sed * 26193323Sed * $FreeBSD: head/sys/dev/ath/ath_hal/ar9002/ar9285_diversity.c 221694 2011-05-09 15:19:49Z adrian $ 27193323Sed */ 28193323Sed#include "opt_ah.h" 29193323Sed 30193323Sed#include "ah.h" 31193323Sed#include "ah_desc.h" 32193323Sed#include "ah_internal.h" 33193323Sed#include "ah_eeprom_v4k.h" 34193323Sed 35193323Sed#include "ar9002/ar9280.h" 36193323Sed#include "ar9002/ar9285_diversity.h" 37193323Sed#include "ar9002/ar9285.h" 38193323Sed#include "ar5416/ar5416reg.h" 39193323Sed#include "ar5416/ar5416phy.h" 40193323Sed#include "ar9002/ar9285phy.h" 41193323Sed#include "ar9002/ar9285_phy.h" 42193323Sed 43193323Sed 44193323Sed/* Linux compability macros */ 45193323Sed/* 46193323Sed * XXX these don't handle rounding, underflow, overflow, wrapping! 47193323Sed */ 48193323Sed#define msecs_to_jiffies(a) ( (a) * hz / 1000 ) 49193323Sed#define time_after(a, b) ( (long) (b) - (long) (a) < 0 ) 50193323Sed 51193323Sedstatic HAL_BOOL 52193323Sedath_is_alt_ant_ratio_better(int alt_ratio, int maxdelta, int mindelta, 53193323Sed int main_rssi_avg, int alt_rssi_avg, int pkt_count) 54193323Sed{ 55193323Sed return (((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) && 56193323Sed (alt_rssi_avg > main_rssi_avg + maxdelta)) || 57193323Sed (alt_rssi_avg > main_rssi_avg + mindelta)) && (pkt_count > 50); 58193323Sed} 59194710Sed 60194710Sedstatic void 61194710Sedath_lnaconf_alt_good_scan(struct ar9285_ant_comb *antcomb, 62194710Sed struct ar9285_antcomb_conf ant_conf, int main_rssi_avg) 63194710Sed{ 64194710Sed antcomb->quick_scan_cnt = 0; 65194710Sed 66194710Sed if (ant_conf.main_lna_conf == ATH_ANT_DIV_COMB_LNA2) 67194710Sed antcomb->rssi_lna2 = main_rssi_avg; 68194710Sed else if (ant_conf.main_lna_conf == ATH_ANT_DIV_COMB_LNA1) 69194710Sed antcomb->rssi_lna1 = main_rssi_avg; 70194710Sed 71194710Sed switch ((ant_conf.main_lna_conf << 4) | ant_conf.alt_lna_conf) { 72194710Sed case (0x10): /* LNA2 A-B */ 73194710Sed antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2; 74194710Sed antcomb->first_quick_scan_conf = 75194710Sed ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2; 76194710Sed antcomb->second_quick_scan_conf = ATH_ANT_DIV_COMB_LNA1; 77194710Sed break; 78194710Sed case (0x20): /* LNA1 A-B */ 79194710Sed antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2; 80194710Sed antcomb->first_quick_scan_conf = 81194710Sed ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2; 82194710Sed antcomb->second_quick_scan_conf = ATH_ANT_DIV_COMB_LNA2; 83194710Sed break; 84194710Sed case (0x21): /* LNA1 LNA2 */ 85194710Sed antcomb->main_conf = ATH_ANT_DIV_COMB_LNA2; 86194710Sed antcomb->first_quick_scan_conf = 87194710Sed ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2; 88194710Sed antcomb->second_quick_scan_conf = 89194710Sed ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2; 90194710Sed break; 91194710Sed case (0x12): /* LNA2 LNA1 */ 92194710Sed antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1; 93194710Sed antcomb->first_quick_scan_conf = 94194710Sed ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2; 95194710Sed antcomb->second_quick_scan_conf = 96194710Sed ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2; 97194710Sed break; 98194710Sed case (0x13): /* LNA2 A+B */ 99194710Sed antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2; 100194710Sed antcomb->first_quick_scan_conf = 101194710Sed ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2; 102194710Sed antcomb->second_quick_scan_conf = ATH_ANT_DIV_COMB_LNA1; 103194710Sed break; 104194710Sed case (0x23): /* LNA1 A+B */ 105193323Sed antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2; 106193323Sed antcomb->first_quick_scan_conf = 107193323Sed ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2; 108193323Sed antcomb->second_quick_scan_conf = ATH_ANT_DIV_COMB_LNA2; 109193323Sed break; 110193323Sed default: 111193323Sed break; 112193323Sed } 113193323Sed} 114193323Sed 115193323Sedstatic void 116193323Sedath_select_ant_div_from_quick_scan(struct ar9285_ant_comb *antcomb, 117193323Sed struct ar9285_antcomb_conf *div_ant_conf, int main_rssi_avg, 118193323Sed int alt_rssi_avg, int alt_ratio) 119193323Sed{ 120193323Sed /* alt_good */ 121193323Sed switch (antcomb->quick_scan_cnt) { 122193323Sed case 0: 123193323Sed /* set alt to main, and alt to first conf */ 124193323Sed div_ant_conf->main_lna_conf = antcomb->main_conf; 125193323Sed div_ant_conf->alt_lna_conf = antcomb->first_quick_scan_conf; 126193323Sed break; 127193323Sed case 1: 128193323Sed /* set alt to main, and alt to first conf */ 129193323Sed div_ant_conf->main_lna_conf = antcomb->main_conf; 130193323Sed div_ant_conf->alt_lna_conf = antcomb->second_quick_scan_conf; 131193323Sed antcomb->rssi_first = main_rssi_avg; 132193323Sed antcomb->rssi_second = alt_rssi_avg; 133193323Sed 134193323Sed if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) { 135193323Sed /* main is LNA1 */ 136193323Sed if (ath_is_alt_ant_ratio_better(alt_ratio, 137193323Sed ATH_ANT_DIV_COMB_LNA1_DELTA_HI, 138193323Sed ATH_ANT_DIV_COMB_LNA1_DELTA_LOW, 139193323Sed main_rssi_avg, alt_rssi_avg, 140193323Sed antcomb->total_pkt_count)) 141193323Sed antcomb->first_ratio = AH_TRUE; 142193323Sed else 143193323Sed antcomb->first_ratio = AH_FALSE; 144193323Sed } else if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2) { 145193323Sed if (ath_is_alt_ant_ratio_better(alt_ratio, 146193323Sed ATH_ANT_DIV_COMB_LNA1_DELTA_MID, 147193323Sed ATH_ANT_DIV_COMB_LNA1_DELTA_LOW, 148193323Sed main_rssi_avg, alt_rssi_avg, 149193323Sed antcomb->total_pkt_count)) 150193323Sed antcomb->first_ratio = AH_TRUE; 151193323Sed else 152193323Sed antcomb->first_ratio = AH_FALSE; 153193323Sed } else { 154193323Sed if ((((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) && 155193323Sed (alt_rssi_avg > main_rssi_avg + 156193323Sed ATH_ANT_DIV_COMB_LNA1_DELTA_HI)) || 157193323Sed (alt_rssi_avg > main_rssi_avg)) && 158193323Sed (antcomb->total_pkt_count > 50)) 159193323Sed antcomb->first_ratio = AH_TRUE; 160193323Sed else 161193323Sed antcomb->first_ratio = AH_FALSE; 162193323Sed } 163193323Sed break; 164193323Sed case 2: 165193323Sed antcomb->alt_good = AH_FALSE; 166193323Sed antcomb->scan_not_start = AH_FALSE; 167193323Sed antcomb->scan = AH_FALSE; 168193323Sed antcomb->rssi_first = main_rssi_avg; 169193323Sed antcomb->rssi_third = alt_rssi_avg; 170193323Sed 171193323Sed if (antcomb->second_quick_scan_conf == ATH_ANT_DIV_COMB_LNA1) 172193323Sed antcomb->rssi_lna1 = alt_rssi_avg; 173193323Sed else if (antcomb->second_quick_scan_conf == 174193323Sed ATH_ANT_DIV_COMB_LNA2) 175193323Sed antcomb->rssi_lna2 = alt_rssi_avg; 176193323Sed else if (antcomb->second_quick_scan_conf == 177193323Sed ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2) { 178193323Sed if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2) 179193323Sed antcomb->rssi_lna2 = main_rssi_avg; 180193323Sed else if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) 181193323Sed antcomb->rssi_lna1 = main_rssi_avg; 182193323Sed } 183193323Sed 184193323Sed if (antcomb->rssi_lna2 > antcomb->rssi_lna1 + 185193323Sed ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA) 186193323Sed div_ant_conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2; 187193323Sed else 188193323Sed div_ant_conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1; 189193323Sed 190193323Sed if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) { 191193323Sed if (ath_is_alt_ant_ratio_better(alt_ratio, 192193323Sed ATH_ANT_DIV_COMB_LNA1_DELTA_HI, 193193323Sed ATH_ANT_DIV_COMB_LNA1_DELTA_LOW, 194193323Sed main_rssi_avg, alt_rssi_avg, 195193323Sed antcomb->total_pkt_count)) 196193323Sed antcomb->second_ratio = AH_TRUE; 197193323Sed else 198193323Sed antcomb->second_ratio = AH_FALSE; 199193323Sed } else if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2) { 200193323Sed if (ath_is_alt_ant_ratio_better(alt_ratio, 201194710Sed ATH_ANT_DIV_COMB_LNA1_DELTA_MID, 202194710Sed ATH_ANT_DIV_COMB_LNA1_DELTA_LOW, 203194710Sed main_rssi_avg, alt_rssi_avg, 204194710Sed antcomb->total_pkt_count)) 205194710Sed antcomb->second_ratio = AH_TRUE; 206194710Sed else 207194710Sed antcomb->second_ratio = AH_FALSE; 208194710Sed } else { 209194710Sed if ((((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) && 210194710Sed (alt_rssi_avg > main_rssi_avg + 211194710Sed ATH_ANT_DIV_COMB_LNA1_DELTA_HI)) || 212194710Sed (alt_rssi_avg > main_rssi_avg)) && 213194710Sed (antcomb->total_pkt_count > 50)) 214194710Sed antcomb->second_ratio = AH_TRUE; 215194710Sed else 216194710Sed antcomb->second_ratio = AH_FALSE; 217194710Sed } 218194710Sed 219194710Sed /* set alt to the conf with maximun ratio */ 220194710Sed if (antcomb->first_ratio && antcomb->second_ratio) { 221194710Sed if (antcomb->rssi_second > antcomb->rssi_third) { 222194710Sed /* first alt*/ 223194710Sed if ((antcomb->first_quick_scan_conf == 224194710Sed ATH_ANT_DIV_COMB_LNA1) || 225193323Sed (antcomb->first_quick_scan_conf == 226193323Sed ATH_ANT_DIV_COMB_LNA2)) 227193323Sed /* Set alt LNA1 or LNA2*/ 228193323Sed if (div_ant_conf->main_lna_conf == 229193323Sed ATH_ANT_DIV_COMB_LNA2) 230193323Sed div_ant_conf->alt_lna_conf = 231193323Sed ATH_ANT_DIV_COMB_LNA1; 232193323Sed else 233193323Sed div_ant_conf->alt_lna_conf = 234193323Sed ATH_ANT_DIV_COMB_LNA2; 235193323Sed else 236193323Sed /* Set alt to A+B or A-B */ 237193323Sed div_ant_conf->alt_lna_conf = 238193323Sed antcomb->first_quick_scan_conf; 239193323Sed } else if ((antcomb->second_quick_scan_conf == 240193323Sed ATH_ANT_DIV_COMB_LNA1) || 241193323Sed (antcomb->second_quick_scan_conf == 242193323Sed ATH_ANT_DIV_COMB_LNA2)) { 243193323Sed /* Set alt LNA1 or LNA2 */ 244193323Sed if (div_ant_conf->main_lna_conf == 245193323Sed ATH_ANT_DIV_COMB_LNA2) 246193323Sed div_ant_conf->alt_lna_conf = 247193323Sed ATH_ANT_DIV_COMB_LNA1; 248193323Sed else 249193323Sed div_ant_conf->alt_lna_conf = 250193323Sed ATH_ANT_DIV_COMB_LNA2; 251193323Sed } else { 252193323Sed /* Set alt to A+B or A-B */ 253193323Sed div_ant_conf->alt_lna_conf = 254193323Sed antcomb->second_quick_scan_conf; 255193323Sed } 256193323Sed } else if (antcomb->first_ratio) { 257193323Sed /* first alt */ 258193323Sed if ((antcomb->first_quick_scan_conf == 259193323Sed ATH_ANT_DIV_COMB_LNA1) || 260193323Sed (antcomb->first_quick_scan_conf == 261193323Sed ATH_ANT_DIV_COMB_LNA2)) 262193323Sed /* Set alt LNA1 or LNA2 */ 263193323Sed if (div_ant_conf->main_lna_conf == 264193323Sed ATH_ANT_DIV_COMB_LNA2) 265193323Sed div_ant_conf->alt_lna_conf = 266193323Sed ATH_ANT_DIV_COMB_LNA1; 267193323Sed else 268193323Sed div_ant_conf->alt_lna_conf = 269195098Sed ATH_ANT_DIV_COMB_LNA2; 270193323Sed else 271193323Sed /* Set alt to A+B or A-B */ 272193323Sed div_ant_conf->alt_lna_conf = 273193323Sed antcomb->first_quick_scan_conf; 274193323Sed } else if (antcomb->second_ratio) { 275193323Sed /* second alt */ 276193323Sed if ((antcomb->second_quick_scan_conf == 277193323Sed ATH_ANT_DIV_COMB_LNA1) || 278193323Sed (antcomb->second_quick_scan_conf == 279193323Sed ATH_ANT_DIV_COMB_LNA2)) 280193323Sed /* Set alt LNA1 or LNA2 */ 281193323Sed if (div_ant_conf->main_lna_conf == 282193323Sed ATH_ANT_DIV_COMB_LNA2) 283193323Sed div_ant_conf->alt_lna_conf = 284193323Sed ATH_ANT_DIV_COMB_LNA1; 285193323Sed else 286193323Sed div_ant_conf->alt_lna_conf = 287193323Sed ATH_ANT_DIV_COMB_LNA2; 288193323Sed else 289193323Sed /* Set alt to A+B or A-B */ 290193323Sed div_ant_conf->alt_lna_conf = 291193323Sed antcomb->second_quick_scan_conf; 292193323Sed } else { 293193323Sed /* main is largest */ 294193323Sed if ((antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) || 295193323Sed (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2)) 296193323Sed /* Set alt LNA1 or LNA2 */ 297193323Sed if (div_ant_conf->main_lna_conf == 298193323Sed ATH_ANT_DIV_COMB_LNA2) 299193323Sed div_ant_conf->alt_lna_conf = 300193323Sed ATH_ANT_DIV_COMB_LNA1; 301193323Sed else 302193323Sed div_ant_conf->alt_lna_conf = 303193323Sed ATH_ANT_DIV_COMB_LNA2; 304193323Sed else 305193323Sed /* Set alt to A+B or A-B */ 306193323Sed div_ant_conf->alt_lna_conf = antcomb->main_conf; 307193323Sed } 308193323Sed break; 309193323Sed default: 310193323Sed break; 311193323Sed } 312193323Sed} 313193323Sed 314193323Sedstatic void 315193323Sedath_ant_div_conf_fast_divbias(struct ar9285_antcomb_conf *ant_conf) 316193323Sed{ 317193323Sed /* Adjust the fast_div_bias based on main and alt lna conf */ 318193323Sed switch ((ant_conf->main_lna_conf << 4) | ant_conf->alt_lna_conf) { 319193323Sed case (0x01): /* A-B LNA2 */ 320193323Sed ant_conf->fast_div_bias = 0x3b; 321193323Sed break; 322193323Sed case (0x02): /* A-B LNA1 */ 323193323Sed ant_conf->fast_div_bias = 0x3d; 324193323Sed break; 325193323Sed case (0x03): /* A-B A+B */ 326193323Sed ant_conf->fast_div_bias = 0x1; 327193323Sed break; 328193323Sed case (0x10): /* LNA2 A-B */ 329193323Sed ant_conf->fast_div_bias = 0x7; 330193323Sed break; 331193323Sed case (0x12): /* LNA2 LNA1 */ 332193323Sed ant_conf->fast_div_bias = 0x2; 333193323Sed break; 334193323Sed case (0x13): /* LNA2 A+B */ 335193323Sed ant_conf->fast_div_bias = 0x7; 336193323Sed break; 337193323Sed case (0x20): /* LNA1 A-B */ 338193323Sed ant_conf->fast_div_bias = 0x6; 339193323Sed break; 340193323Sed case (0x21): /* LNA1 LNA2 */ 341193323Sed ant_conf->fast_div_bias = 0x0; 342193323Sed break; 343193323Sed case (0x23): /* LNA1 A+B */ 344193323Sed ant_conf->fast_div_bias = 0x6; 345193323Sed break; 346193323Sed case (0x30): /* A+B A-B */ 347193323Sed ant_conf->fast_div_bias = 0x1; 348193323Sed break; 349193323Sed case (0x31): /* A+B LNA2 */ 350193323Sed ant_conf->fast_div_bias = 0x3b; 351193323Sed break; 352193323Sed case (0x32): /* A+B LNA1 */ 353193323Sed ant_conf->fast_div_bias = 0x3d; 354193323Sed break; 355193323Sed default: 356193323Sed break; 357193323Sed } 358193323Sed} 359193323Sed 360193323Sed/* Antenna diversity and combining */ 361193323Sedvoid 362193323Sedar9285_ant_comb_scan(struct ath_hal *ah, struct ath_rx_status *rs, 363193323Sed unsigned long ticks, int hz) 364193323Sed{ 365194612Sed struct ar9285_antcomb_conf div_ant_conf; 366194612Sed struct ar9285_ant_comb *antcomb = &AH9285(ah)->ant_comb; 367194612Sed int alt_ratio = 0, alt_rssi_avg = 0, main_rssi_avg = 0, curr_alt_set; 368194612Sed int curr_main_set, curr_bias; 369194612Sed int main_rssi = rs->rs_rssi_ctl[0]; 370194612Sed int alt_rssi = rs->rs_rssi_ctl[1]; 371194612Sed int rx_ant_conf, main_ant_conf; 372194612Sed HAL_BOOL short_scan = AH_FALSE; 373194612Sed 374194612Sed if (! ar9285_check_div_comb(ah)) 375194612Sed return; 376194612Sed 377194612Sed if (AH5212(ah)->ah_diversity == AH_FALSE) 378194612Sed return; 379194612Sed 380194612Sed rx_ant_conf = (rs->rs_rssi_ctl[2] >> ATH_ANT_RX_CURRENT_SHIFT) & 381194612Sed ATH_ANT_RX_MASK; 382194612Sed main_ant_conf = (rs->rs_rssi_ctl[2] >> ATH_ANT_RX_MAIN_SHIFT) & 383194612Sed ATH_ANT_RX_MASK; 384193323Sed 385193323Sed#if 0 386193323Sed HALDEBUG(ah, HAL_DEBUG_DIVERSITY, "%s: main: %d, alt: %d, rx_ant_conf: %x, main_ant_conf: %x\n", 387193323Sed __func__, main_rssi, alt_rssi, rx_ant_conf, main_ant_conf); 388193323Sed#endif 389193323Sed 390193323Sed /* Record packet only when alt_rssi is positive */ 391193323Sed if (alt_rssi > 0) { 392193323Sed antcomb->total_pkt_count++; 393193323Sed antcomb->main_total_rssi += main_rssi; 394193323Sed antcomb->alt_total_rssi += alt_rssi; 395193323Sed if (main_ant_conf == rx_ant_conf) 396193323Sed antcomb->main_recv_cnt++; 397193323Sed else 398193323Sed antcomb->alt_recv_cnt++; 399193323Sed } 400193323Sed 401193323Sed /* Short scan check */ 402193323Sed if (antcomb->scan && antcomb->alt_good) { 403193323Sed if (time_after(ticks, antcomb->scan_start_time + 404193323Sed msecs_to_jiffies(ATH_ANT_DIV_COMB_SHORT_SCAN_INTR))) 405193323Sed short_scan = AH_TRUE; 406193323Sed else 407193323Sed if (antcomb->total_pkt_count == 408193323Sed ATH_ANT_DIV_COMB_SHORT_SCAN_PKTCOUNT) { 409193323Sed alt_ratio = ((antcomb->alt_recv_cnt * 100) / 410193323Sed antcomb->total_pkt_count); 411193323Sed if (alt_ratio < ATH_ANT_DIV_COMB_ALT_ANT_RATIO) 412193323Sed short_scan = AH_TRUE; 413193323Sed } 414193323Sed } 415193323Sed 416193323Sed if (((antcomb->total_pkt_count < ATH_ANT_DIV_COMB_MAX_PKTCOUNT) || 417193323Sed rs->rs_moreaggr) && !short_scan) 418193323Sed return; 419193323Sed 420193323Sed if (antcomb->total_pkt_count) { 421193323Sed alt_ratio = ((antcomb->alt_recv_cnt * 100) / 422193323Sed antcomb->total_pkt_count); 423193323Sed main_rssi_avg = (antcomb->main_total_rssi / 424193323Sed antcomb->total_pkt_count); 425194710Sed alt_rssi_avg = (antcomb->alt_total_rssi / 426194710Sed antcomb->total_pkt_count); 427194710Sed } 428194710Sed 429194710Sed ar9285_antdiv_comb_conf_get(ah, &div_ant_conf); 430194710Sed curr_alt_set = div_ant_conf.alt_lna_conf; 431194710Sed curr_main_set = div_ant_conf.main_lna_conf; 432194710Sed curr_bias = div_ant_conf.fast_div_bias; 433194710Sed 434194710Sed antcomb->count++; 435194710Sed 436194710Sed if (antcomb->count == ATH_ANT_DIV_COMB_MAX_COUNT) { 437194710Sed if (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO) { 438194710Sed ath_lnaconf_alt_good_scan(antcomb, div_ant_conf, 439194710Sed main_rssi_avg); 440194710Sed antcomb->alt_good = AH_TRUE; 441194710Sed } else { 442194710Sed antcomb->alt_good = AH_FALSE; 443194710Sed } 444194710Sed 445194710Sed antcomb->count = 0; 446194710Sed antcomb->scan = AH_TRUE; 447194710Sed antcomb->scan_not_start = AH_TRUE; 448194710Sed } 449194710Sed 450194710Sed if (!antcomb->scan) { 451194710Sed if (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO) { 452194710Sed if (curr_alt_set == ATH_ANT_DIV_COMB_LNA2) { 453194710Sed /* Switch main and alt LNA */ 454194710Sed div_ant_conf.main_lna_conf = 455193323Sed ATH_ANT_DIV_COMB_LNA2; 456193323Sed div_ant_conf.alt_lna_conf = 457193323Sed ATH_ANT_DIV_COMB_LNA1; 458193323Sed } else if (curr_alt_set == ATH_ANT_DIV_COMB_LNA1) { 459193323Sed div_ant_conf.main_lna_conf = 460193323Sed ATH_ANT_DIV_COMB_LNA1; 461193323Sed div_ant_conf.alt_lna_conf = 462193323Sed ATH_ANT_DIV_COMB_LNA2; 463193323Sed } 464193323Sed 465193323Sed goto div_comb_done; 466193323Sed } else if ((curr_alt_set != ATH_ANT_DIV_COMB_LNA1) && 467193323Sed (curr_alt_set != ATH_ANT_DIV_COMB_LNA2)) { 468193323Sed /* Set alt to another LNA */ 469193323Sed if (curr_main_set == ATH_ANT_DIV_COMB_LNA2) 470193323Sed div_ant_conf.alt_lna_conf = 471193323Sed ATH_ANT_DIV_COMB_LNA1; 472193323Sed else if (curr_main_set == ATH_ANT_DIV_COMB_LNA1) 473193323Sed div_ant_conf.alt_lna_conf = 474193323Sed ATH_ANT_DIV_COMB_LNA2; 475193323Sed 476193323Sed goto div_comb_done; 477193323Sed } 478193323Sed 479193323Sed if ((alt_rssi_avg < (main_rssi_avg + 480193323Sed ATH_ANT_DIV_COMB_LNA1_LNA2_DELTA))) 481193323Sed goto div_comb_done; 482193323Sed } 483193323Sed 484193323Sed if (!antcomb->scan_not_start) { 485193323Sed switch (curr_alt_set) { 486193323Sed case ATH_ANT_DIV_COMB_LNA2: 487193323Sed antcomb->rssi_lna2 = alt_rssi_avg; 488193323Sed antcomb->rssi_lna1 = main_rssi_avg; 489193323Sed antcomb->scan = AH_TRUE; 490193323Sed /* set to A+B */ 491193323Sed div_ant_conf.main_lna_conf = 492193323Sed ATH_ANT_DIV_COMB_LNA1; 493193323Sed div_ant_conf.alt_lna_conf = 494193323Sed ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2; 495193323Sed break; 496193323Sed case ATH_ANT_DIV_COMB_LNA1: 497193323Sed antcomb->rssi_lna1 = alt_rssi_avg; 498193323Sed antcomb->rssi_lna2 = main_rssi_avg; 499193323Sed antcomb->scan = AH_TRUE; 500193323Sed /* set to A+B */ 501193323Sed div_ant_conf.main_lna_conf = ATH_ANT_DIV_COMB_LNA2; 502193323Sed div_ant_conf.alt_lna_conf = 503193323Sed ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2; 504193323Sed break; 505193323Sed case ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2: 506193323Sed antcomb->rssi_add = alt_rssi_avg; 507193323Sed antcomb->scan = AH_TRUE; 508193323Sed /* set to A-B */ 509193323Sed div_ant_conf.alt_lna_conf = 510193323Sed ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2; 511193323Sed break; 512193323Sed case ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2: 513193323Sed antcomb->rssi_sub = alt_rssi_avg; 514193323Sed antcomb->scan = AH_FALSE; 515193323Sed if (antcomb->rssi_lna2 > 516193323Sed (antcomb->rssi_lna1 + 517193323Sed ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA)) { 518193323Sed /* use LNA2 as main LNA */ 519193323Sed if ((antcomb->rssi_add > antcomb->rssi_lna1) && 520193323Sed (antcomb->rssi_add > antcomb->rssi_sub)) { 521193323Sed /* set to A+B */ 522193323Sed div_ant_conf.main_lna_conf = 523193323Sed ATH_ANT_DIV_COMB_LNA2; 524193323Sed div_ant_conf.alt_lna_conf = 525193323Sed ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2; 526194710Sed } else if (antcomb->rssi_sub > 527194710Sed antcomb->rssi_lna1) { 528194710Sed /* set to A-B */ 529194710Sed div_ant_conf.main_lna_conf = 530193323Sed ATH_ANT_DIV_COMB_LNA2; 531194710Sed div_ant_conf.alt_lna_conf = 532194710Sed ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2; 533194710Sed } else { 534194710Sed /* set to LNA1 */ 535194710Sed div_ant_conf.main_lna_conf = 536194710Sed ATH_ANT_DIV_COMB_LNA2; 537194710Sed div_ant_conf.alt_lna_conf = 538193323Sed ATH_ANT_DIV_COMB_LNA1; 539194710Sed } 540194710Sed } else { 541194710Sed /* use LNA1 as main LNA */ 542194710Sed if ((antcomb->rssi_add > antcomb->rssi_lna2) && 543194710Sed (antcomb->rssi_add > antcomb->rssi_sub)) { 544194710Sed /* set to A+B */ 545193323Sed div_ant_conf.main_lna_conf = 546194710Sed ATH_ANT_DIV_COMB_LNA1; 547194710Sed div_ant_conf.alt_lna_conf = 548194710Sed ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2; 549193323Sed } else if (antcomb->rssi_sub > 550193323Sed antcomb->rssi_lna1) { 551193323Sed /* set to A-B */ 552194710Sed div_ant_conf.main_lna_conf = 553194710Sed ATH_ANT_DIV_COMB_LNA1; 554194710Sed div_ant_conf.alt_lna_conf = 555194710Sed ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2; 556194710Sed } else { 557194710Sed /* set to LNA2 */ 558194710Sed div_ant_conf.main_lna_conf = 559194710Sed ATH_ANT_DIV_COMB_LNA1; 560194710Sed div_ant_conf.alt_lna_conf = 561194710Sed ATH_ANT_DIV_COMB_LNA2; 562194710Sed } 563194710Sed } 564194710Sed break; 565193323Sed default: 566193323Sed break; 567193323Sed } 568193323Sed } else { 569194710Sed if (!antcomb->alt_good) { 570194710Sed antcomb->scan_not_start = AH_FALSE; 571194710Sed /* Set alt to another LNA */ 572193323Sed if (curr_main_set == ATH_ANT_DIV_COMB_LNA2) { 573193323Sed div_ant_conf.main_lna_conf = 574193323Sed ATH_ANT_DIV_COMB_LNA2; 575193323Sed div_ant_conf.alt_lna_conf = 576194710Sed ATH_ANT_DIV_COMB_LNA1; 577194710Sed } else if (curr_main_set == ATH_ANT_DIV_COMB_LNA1) { 578194710Sed div_ant_conf.main_lna_conf = 579194710Sed ATH_ANT_DIV_COMB_LNA1; 580193323Sed div_ant_conf.alt_lna_conf = 581194710Sed ATH_ANT_DIV_COMB_LNA2; 582194710Sed } 583194710Sed goto div_comb_done; 584194710Sed } 585194710Sed } 586194710Sed 587194710Sed ath_select_ant_div_from_quick_scan(antcomb, &div_ant_conf, 588193323Sed main_rssi_avg, alt_rssi_avg, 589193323Sed alt_ratio); 590193323Sed 591193323Sed antcomb->quick_scan_cnt++; 592193323Sed 593194710Seddiv_comb_done: 594193323Sed ath_ant_div_conf_fast_divbias(&div_ant_conf); 595194710Sed 596194710Sed ar9285_antdiv_comb_conf_set(ah, &div_ant_conf); 597194710Sed 598194710Sed HALDEBUG(ah, HAL_DEBUG_DIVERSITY, "%s: total_pkt_count=%d\n", 599194710Sed __func__, antcomb->total_pkt_count); 600194710Sed 601194710Sed HALDEBUG(ah, HAL_DEBUG_DIVERSITY, "%s: main_total_rssi=%d\n", 602194710Sed __func__, antcomb->main_total_rssi); 603194710Sed HALDEBUG(ah, HAL_DEBUG_DIVERSITY, "%s: alt_total_rssi=%d\n", 604194710Sed __func__, antcomb->alt_total_rssi); 605194710Sed 606194710Sed HALDEBUG(ah, HAL_DEBUG_DIVERSITY, "%s: main_rssi_avg=%d\n", 607194710Sed __func__, main_rssi_avg); 608193323Sed HALDEBUG(ah, HAL_DEBUG_DIVERSITY, "%s: alt_alt_rssi_avg=%d\n", 609193323Sed __func__, alt_rssi_avg); 610193323Sed 611194710Sed HALDEBUG(ah, HAL_DEBUG_DIVERSITY, "%s: main_recv_cnt=%d\n", 612194710Sed __func__, antcomb->main_recv_cnt); 613193323Sed HALDEBUG(ah, HAL_DEBUG_DIVERSITY, "%s: alt_recv_cnt=%d\n", 614193323Sed __func__, antcomb->alt_recv_cnt); 615193323Sed 616193323Sed if (curr_alt_set != div_ant_conf.alt_lna_conf) 617193323Sed HALDEBUG(ah, HAL_DEBUG_DIVERSITY, "%s: lna_conf: %x -> %x\n", 618193323Sed __func__, curr_alt_set, div_ant_conf.alt_lna_conf); 619193323Sed if (curr_main_set != div_ant_conf.main_lna_conf) 620193323Sed HALDEBUG(ah, HAL_DEBUG_DIVERSITY, "%s: main_lna_conf: %x -> %x\n", 621193323Sed __func__, curr_main_set, div_ant_conf.main_lna_conf); 622193323Sed if (curr_bias != div_ant_conf.fast_div_bias) 623193323Sed HALDEBUG(ah, HAL_DEBUG_DIVERSITY, "%s: fast_div_bias: %x -> %x\n", 624193323Sed __func__, curr_bias, div_ant_conf.fast_div_bias); 625194710Sed 626193323Sed antcomb->scan_start_time = ticks; 627194710Sed antcomb->total_pkt_count = 0; 628194710Sed antcomb->main_total_rssi = 0; 629194710Sed antcomb->alt_total_rssi = 0; 630194710Sed antcomb->main_recv_cnt = 0; 631194710Sed antcomb->alt_recv_cnt = 0; 632194710Sed} 633194710Sed 634194710Sed/* 635194710Sed * Set the antenna switch to control RX antenna diversity. 636194710Sed * 637194710Sed * If a fixed configuration is used, the LNA and div bias 638194710Sed * settings are fixed and the antenna diversity scanning routine 639193323Sed * is disabled. 640193323Sed * 641193323Sed * If a variable configuration is used, a default is programmed 642193323Sed * in and sampling commences per RXed packet. 643193323Sed * 644193323Sed * Since this is called from ar9285SetBoardValues() to setup 645193323Sed * diversity, it means that after a reset or scan, any current 646193323Sed * software diversity combining settings will be lost and won't 647193323Sed * re-appear until after the first successful sample run. 648193323Sed * Please keep this in mind if you're seeing weird performance 649193323Sed * that happens to relate to scan/diversity timing. 650194612Sed */ 651194612SedHAL_BOOL 652194612Sedar9285SetAntennaSwitch(struct ath_hal *ah, HAL_ANT_SETTING settings) 653194612Sed{ 654194612Sed int regVal; 655194612Sed const HAL_EEPROM_v4k *ee = AH_PRIVATE(ah)->ah_eeprom; 656194612Sed const MODAL_EEP4K_HEADER *pModal = &ee->ee_base.modalHeader; 657194612Sed uint8_t ant_div_control1, ant_div_control2; 658194612Sed 659194612Sed if (pModal->version < 3) { 660194612Sed HALDEBUG(ah, HAL_DEBUG_DIVERSITY, "%s: not supported\n", 661194612Sed __func__); 662194612Sed return AH_FALSE; /* Can't do diversity */ 663194612Sed } 664194612Sed 665194612Sed /* Store settings */ 666194612Sed AH5212(ah)->ah_antControl = settings; 667194612Sed AH5212(ah)->ah_diversity = (settings == HAL_ANT_VARIABLE); 668194612Sed 669194612Sed /* XXX don't fiddle if the PHY is in sleep mode or ! chan */ 670194612Sed 671194612Sed /* Begin setting the relevant registers */ 672194612Sed 673194612Sed ant_div_control1 = pModal->antdiv_ctl1; 674194612Sed ant_div_control2 = pModal->antdiv_ctl2; 675194612Sed 676194612Sed regVal = OS_REG_READ(ah, AR_PHY_MULTICHAIN_GAIN_CTL); 677193323Sed regVal &= (~(AR_PHY_9285_ANT_DIV_CTL_ALL)); 678193323Sed 679193323Sed /* enable antenna diversity only if diversityControl == HAL_ANT_VARIABLE */ 680193323Sed if (settings == HAL_ANT_VARIABLE) 681193323Sed regVal |= SM(ant_div_control1, AR_PHY_9285_ANT_DIV_CTL); 682193323Sed 683193323Sed if (settings == HAL_ANT_VARIABLE) { 684193323Sed HALDEBUG(ah, HAL_DEBUG_DIVERSITY, "%s: HAL_ANT_VARIABLE\n", 685193323Sed __func__); 686193323Sed regVal |= SM(ant_div_control2, AR_PHY_9285_ANT_DIV_ALT_LNACONF); 687193323Sed regVal |= SM((ant_div_control2 >> 2), AR_PHY_9285_ANT_DIV_MAIN_LNACONF); 688193323Sed regVal |= SM((ant_div_control1 >> 1), AR_PHY_9285_ANT_DIV_ALT_GAINTB); 689193323Sed regVal |= SM((ant_div_control1 >> 2), AR_PHY_9285_ANT_DIV_MAIN_GAINTB); 690193323Sed } else { 691194612Sed if (settings == HAL_ANT_FIXED_A) { 692194612Sed /* Diversity disabled, RX = LNA1 */ 693193323Sed HALDEBUG(ah, HAL_DEBUG_DIVERSITY, "%s: HAL_ANT_FIXED_A\n", 694193323Sed __func__); 695193323Sed regVal |= SM(ATH_ANT_DIV_COMB_LNA2, AR_PHY_9285_ANT_DIV_ALT_LNACONF); 696193323Sed regVal |= SM(ATH_ANT_DIV_COMB_LNA1, AR_PHY_9285_ANT_DIV_MAIN_LNACONF); 697193323Sed regVal |= SM(AR_PHY_9285_ANT_DIV_GAINTB_0, AR_PHY_9285_ANT_DIV_ALT_GAINTB); 698193323Sed regVal |= SM(AR_PHY_9285_ANT_DIV_GAINTB_1, AR_PHY_9285_ANT_DIV_MAIN_GAINTB); 699193323Sed } 700193323Sed else if (settings == HAL_ANT_FIXED_B) { 701193323Sed /* Diversity disabled, RX = LNA2 */ 702194710Sed HALDEBUG(ah, HAL_DEBUG_DIVERSITY, "%s: HAL_ANT_FIXED_B\n", 703193323Sed __func__); 704193323Sed regVal |= SM(ATH_ANT_DIV_COMB_LNA1, AR_PHY_9285_ANT_DIV_ALT_LNACONF); 705193323Sed regVal |= SM(ATH_ANT_DIV_COMB_LNA2, AR_PHY_9285_ANT_DIV_MAIN_LNACONF); 706193323Sed regVal |= SM(AR_PHY_9285_ANT_DIV_GAINTB_1, AR_PHY_9285_ANT_DIV_ALT_GAINTB); 707193323Sed regVal |= SM(AR_PHY_9285_ANT_DIV_GAINTB_0, AR_PHY_9285_ANT_DIV_MAIN_GAINTB); 708193323Sed } 709193323Sed } 710193323Sed 711193323Sed OS_REG_WRITE(ah, AR_PHY_MULTICHAIN_GAIN_CTL, regVal); 712193323Sed regVal = OS_REG_READ(ah, AR_PHY_MULTICHAIN_GAIN_CTL); 713194710Sed regVal = OS_REG_READ(ah, AR_PHY_CCK_DETECT); 714194710Sed regVal &= (~AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV); 715194710Sed if (settings == HAL_ANT_VARIABLE) 716194710Sed regVal |= SM((ant_div_control1 >> 3), AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV); 717194710Sed 718194710Sed OS_REG_WRITE(ah, AR_PHY_CCK_DETECT, regVal); 719194710Sed regVal = OS_REG_READ(ah, AR_PHY_CCK_DETECT); 720194710Sed 721194710Sed /* 722194710Sed * If Diversity combining is available and the diversity setting 723194710Sed * is to allow variable diversity, enable it by default. 724194710Sed * 725194710Sed * This will be eventually overridden by the software antenna 726194710Sed * diversity logic. 727194710Sed * 728194710Sed * Note that yes, this following section overrides the above 729194710Sed * settings for the LNA configuration and fast-bias. 730194710Sed */ 731193323Sed if (ar9285_check_div_comb(ah) && AH5212(ah)->ah_diversity == AH_TRUE) { 732193323Sed // If support DivComb, set MAIN to LNA1 and ALT to LNA2 at the first beginning 733193323Sed HALDEBUG(ah, HAL_DEBUG_DIVERSITY, 734193323Sed "%s: Enable initial settings for combined diversity\n", 735193323Sed __func__); 736193323Sed regVal = OS_REG_READ(ah, AR_PHY_MULTICHAIN_GAIN_CTL); 737193323Sed regVal &= (~(AR_PHY_9285_ANT_DIV_MAIN_LNACONF | AR_PHY_9285_ANT_DIV_ALT_LNACONF)); 738193323Sed regVal |= (ATH_ANT_DIV_COMB_LNA1 << AR_PHY_9285_ANT_DIV_MAIN_LNACONF_S); 739193323Sed regVal |= (ATH_ANT_DIV_COMB_LNA2 << AR_PHY_9285_ANT_DIV_ALT_LNACONF_S); 740193323Sed regVal &= (~(AR_PHY_9285_FAST_DIV_BIAS)); 741193323Sed regVal |= (0 << AR_PHY_9285_FAST_DIV_BIAS_S); 742193323Sed OS_REG_WRITE(ah, AR_PHY_MULTICHAIN_GAIN_CTL, regVal); 743193323Sed } 744193323Sed 745193323Sed return AH_TRUE; 746193323Sed} 747193323Sed