ar9285_diversity.c revision 251643
1/* 2 * Copyright (c) 2008-2010 Atheros Communications Inc. 3 * Copyright (c) 2011 Adrian Chadd, Xenion Pty Ltd. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $FreeBSD: head/sys/dev/ath/ath_hal/ar9002/ar9285_diversity.c 251643 2013-06-12 06:01:53Z adrian $ 27 */ 28#include "opt_ah.h" 29 30#include "ah.h" 31#include "ah_desc.h" 32#include "ah_internal.h" 33#include "ah_eeprom_v4k.h" 34 35#include "ar9002/ar9280.h" 36#include "ar9002/ar9285_diversity.h" 37#include "ar9002/ar9285.h" 38#include "ar5416/ar5416reg.h" 39#include "ar5416/ar5416phy.h" 40#include "ar9002/ar9285phy.h" 41#include "ar9002/ar9285_phy.h" 42 43 44/* Linux compability macros */ 45/* 46 * XXX these don't handle rounding, underflow, overflow, wrapping! 47 */ 48#define msecs_to_jiffies(a) ( (a) * hz / 1000 ) 49#define time_after(a, b) ( (long) (b) - (long) (a) < 0 ) 50 51static HAL_BOOL 52ath_is_alt_ant_ratio_better(int alt_ratio, int maxdelta, int mindelta, 53 int main_rssi_avg, int alt_rssi_avg, int pkt_count) 54{ 55 return (((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) && 56 (alt_rssi_avg > main_rssi_avg + maxdelta)) || 57 (alt_rssi_avg > main_rssi_avg + mindelta)) && (pkt_count > 50); 58} 59 60static void 61ath_lnaconf_alt_good_scan(struct ar9285_ant_comb *antcomb, 62 HAL_ANT_COMB_CONFIG *ant_conf, int main_rssi_avg) 63{ 64 antcomb->quick_scan_cnt = 0; 65 66 if (ant_conf->main_lna_conf == HAL_ANT_DIV_COMB_LNA2) 67 antcomb->rssi_lna2 = main_rssi_avg; 68 else if (ant_conf->main_lna_conf == HAL_ANT_DIV_COMB_LNA1) 69 antcomb->rssi_lna1 = main_rssi_avg; 70 71 switch ((ant_conf->main_lna_conf << 4) | ant_conf->alt_lna_conf) { 72 case (0x10): /* LNA2 A-B */ 73 antcomb->main_conf = HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2; 74 antcomb->first_quick_scan_conf = 75 HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2; 76 antcomb->second_quick_scan_conf = HAL_ANT_DIV_COMB_LNA1; 77 break; 78 case (0x20): /* LNA1 A-B */ 79 antcomb->main_conf = HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2; 80 antcomb->first_quick_scan_conf = 81 HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2; 82 antcomb->second_quick_scan_conf = HAL_ANT_DIV_COMB_LNA2; 83 break; 84 case (0x21): /* LNA1 LNA2 */ 85 antcomb->main_conf = HAL_ANT_DIV_COMB_LNA2; 86 antcomb->first_quick_scan_conf = 87 HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2; 88 antcomb->second_quick_scan_conf = 89 HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2; 90 break; 91 case (0x12): /* LNA2 LNA1 */ 92 antcomb->main_conf = HAL_ANT_DIV_COMB_LNA1; 93 antcomb->first_quick_scan_conf = 94 HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2; 95 antcomb->second_quick_scan_conf = 96 HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2; 97 break; 98 case (0x13): /* LNA2 A+B */ 99 antcomb->main_conf = HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2; 100 antcomb->first_quick_scan_conf = 101 HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2; 102 antcomb->second_quick_scan_conf = HAL_ANT_DIV_COMB_LNA1; 103 break; 104 case (0x23): /* LNA1 A+B */ 105 antcomb->main_conf = HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2; 106 antcomb->first_quick_scan_conf = 107 HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2; 108 antcomb->second_quick_scan_conf = HAL_ANT_DIV_COMB_LNA2; 109 break; 110 default: 111 break; 112 } 113} 114 115static void 116ath_select_ant_div_from_quick_scan(struct ar9285_ant_comb *antcomb, 117 HAL_ANT_COMB_CONFIG *div_ant_conf, int main_rssi_avg, 118 int alt_rssi_avg, int alt_ratio) 119{ 120 /* alt_good */ 121 switch (antcomb->quick_scan_cnt) { 122 case 0: 123 /* set alt to main, and alt to first conf */ 124 div_ant_conf->main_lna_conf = antcomb->main_conf; 125 div_ant_conf->alt_lna_conf = antcomb->first_quick_scan_conf; 126 break; 127 case 1: 128 /* set alt to main, and alt to first conf */ 129 div_ant_conf->main_lna_conf = antcomb->main_conf; 130 div_ant_conf->alt_lna_conf = antcomb->second_quick_scan_conf; 131 antcomb->rssi_first = main_rssi_avg; 132 antcomb->rssi_second = alt_rssi_avg; 133 134 if (antcomb->main_conf == HAL_ANT_DIV_COMB_LNA1) { 135 /* main is LNA1 */ 136 if (ath_is_alt_ant_ratio_better(alt_ratio, 137 ATH_ANT_DIV_COMB_LNA1_DELTA_HI, 138 ATH_ANT_DIV_COMB_LNA1_DELTA_LOW, 139 main_rssi_avg, alt_rssi_avg, 140 antcomb->total_pkt_count)) 141 antcomb->first_ratio = AH_TRUE; 142 else 143 antcomb->first_ratio = AH_FALSE; 144 } else if (antcomb->main_conf == HAL_ANT_DIV_COMB_LNA2) { 145 if (ath_is_alt_ant_ratio_better(alt_ratio, 146 ATH_ANT_DIV_COMB_LNA1_DELTA_MID, 147 ATH_ANT_DIV_COMB_LNA1_DELTA_LOW, 148 main_rssi_avg, alt_rssi_avg, 149 antcomb->total_pkt_count)) 150 antcomb->first_ratio = AH_TRUE; 151 else 152 antcomb->first_ratio = AH_FALSE; 153 } else { 154 if ((((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) && 155 (alt_rssi_avg > main_rssi_avg + 156 ATH_ANT_DIV_COMB_LNA1_DELTA_HI)) || 157 (alt_rssi_avg > main_rssi_avg)) && 158 (antcomb->total_pkt_count > 50)) 159 antcomb->first_ratio = AH_TRUE; 160 else 161 antcomb->first_ratio = AH_FALSE; 162 } 163 break; 164 case 2: 165 antcomb->alt_good = AH_FALSE; 166 antcomb->scan_not_start = AH_FALSE; 167 antcomb->scan = AH_FALSE; 168 antcomb->rssi_first = main_rssi_avg; 169 antcomb->rssi_third = alt_rssi_avg; 170 171 if (antcomb->second_quick_scan_conf == HAL_ANT_DIV_COMB_LNA1) 172 antcomb->rssi_lna1 = alt_rssi_avg; 173 else if (antcomb->second_quick_scan_conf == 174 HAL_ANT_DIV_COMB_LNA2) 175 antcomb->rssi_lna2 = alt_rssi_avg; 176 else if (antcomb->second_quick_scan_conf == 177 HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2) { 178 if (antcomb->main_conf == HAL_ANT_DIV_COMB_LNA2) 179 antcomb->rssi_lna2 = main_rssi_avg; 180 else if (antcomb->main_conf == HAL_ANT_DIV_COMB_LNA1) 181 antcomb->rssi_lna1 = main_rssi_avg; 182 } 183 184 if (antcomb->rssi_lna2 > antcomb->rssi_lna1 + 185 ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA) 186 div_ant_conf->main_lna_conf = HAL_ANT_DIV_COMB_LNA2; 187 else 188 div_ant_conf->main_lna_conf = HAL_ANT_DIV_COMB_LNA1; 189 190 if (antcomb->main_conf == HAL_ANT_DIV_COMB_LNA1) { 191 if (ath_is_alt_ant_ratio_better(alt_ratio, 192 ATH_ANT_DIV_COMB_LNA1_DELTA_HI, 193 ATH_ANT_DIV_COMB_LNA1_DELTA_LOW, 194 main_rssi_avg, alt_rssi_avg, 195 antcomb->total_pkt_count)) 196 antcomb->second_ratio = AH_TRUE; 197 else 198 antcomb->second_ratio = AH_FALSE; 199 } else if (antcomb->main_conf == HAL_ANT_DIV_COMB_LNA2) { 200 if (ath_is_alt_ant_ratio_better(alt_ratio, 201 ATH_ANT_DIV_COMB_LNA1_DELTA_MID, 202 ATH_ANT_DIV_COMB_LNA1_DELTA_LOW, 203 main_rssi_avg, alt_rssi_avg, 204 antcomb->total_pkt_count)) 205 antcomb->second_ratio = AH_TRUE; 206 else 207 antcomb->second_ratio = AH_FALSE; 208 } else { 209 if ((((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) && 210 (alt_rssi_avg > main_rssi_avg + 211 ATH_ANT_DIV_COMB_LNA1_DELTA_HI)) || 212 (alt_rssi_avg > main_rssi_avg)) && 213 (antcomb->total_pkt_count > 50)) 214 antcomb->second_ratio = AH_TRUE; 215 else 216 antcomb->second_ratio = AH_FALSE; 217 } 218 219 /* set alt to the conf with maximun ratio */ 220 if (antcomb->first_ratio && antcomb->second_ratio) { 221 if (antcomb->rssi_second > antcomb->rssi_third) { 222 /* first alt*/ 223 if ((antcomb->first_quick_scan_conf == 224 HAL_ANT_DIV_COMB_LNA1) || 225 (antcomb->first_quick_scan_conf == 226 HAL_ANT_DIV_COMB_LNA2)) 227 /* Set alt LNA1 or LNA2*/ 228 if (div_ant_conf->main_lna_conf == 229 HAL_ANT_DIV_COMB_LNA2) 230 div_ant_conf->alt_lna_conf = 231 HAL_ANT_DIV_COMB_LNA1; 232 else 233 div_ant_conf->alt_lna_conf = 234 HAL_ANT_DIV_COMB_LNA2; 235 else 236 /* Set alt to A+B or A-B */ 237 div_ant_conf->alt_lna_conf = 238 antcomb->first_quick_scan_conf; 239 } else if ((antcomb->second_quick_scan_conf == 240 HAL_ANT_DIV_COMB_LNA1) || 241 (antcomb->second_quick_scan_conf == 242 HAL_ANT_DIV_COMB_LNA2)) { 243 /* Set alt LNA1 or LNA2 */ 244 if (div_ant_conf->main_lna_conf == 245 HAL_ANT_DIV_COMB_LNA2) 246 div_ant_conf->alt_lna_conf = 247 HAL_ANT_DIV_COMB_LNA1; 248 else 249 div_ant_conf->alt_lna_conf = 250 HAL_ANT_DIV_COMB_LNA2; 251 } else { 252 /* Set alt to A+B or A-B */ 253 div_ant_conf->alt_lna_conf = 254 antcomb->second_quick_scan_conf; 255 } 256 } else if (antcomb->first_ratio) { 257 /* first alt */ 258 if ((antcomb->first_quick_scan_conf == 259 HAL_ANT_DIV_COMB_LNA1) || 260 (antcomb->first_quick_scan_conf == 261 HAL_ANT_DIV_COMB_LNA2)) 262 /* Set alt LNA1 or LNA2 */ 263 if (div_ant_conf->main_lna_conf == 264 HAL_ANT_DIV_COMB_LNA2) 265 div_ant_conf->alt_lna_conf = 266 HAL_ANT_DIV_COMB_LNA1; 267 else 268 div_ant_conf->alt_lna_conf = 269 HAL_ANT_DIV_COMB_LNA2; 270 else 271 /* Set alt to A+B or A-B */ 272 div_ant_conf->alt_lna_conf = 273 antcomb->first_quick_scan_conf; 274 } else if (antcomb->second_ratio) { 275 /* second alt */ 276 if ((antcomb->second_quick_scan_conf == 277 HAL_ANT_DIV_COMB_LNA1) || 278 (antcomb->second_quick_scan_conf == 279 HAL_ANT_DIV_COMB_LNA2)) 280 /* Set alt LNA1 or LNA2 */ 281 if (div_ant_conf->main_lna_conf == 282 HAL_ANT_DIV_COMB_LNA2) 283 div_ant_conf->alt_lna_conf = 284 HAL_ANT_DIV_COMB_LNA1; 285 else 286 div_ant_conf->alt_lna_conf = 287 HAL_ANT_DIV_COMB_LNA2; 288 else 289 /* Set alt to A+B or A-B */ 290 div_ant_conf->alt_lna_conf = 291 antcomb->second_quick_scan_conf; 292 } else { 293 /* main is largest */ 294 if ((antcomb->main_conf == HAL_ANT_DIV_COMB_LNA1) || 295 (antcomb->main_conf == HAL_ANT_DIV_COMB_LNA2)) 296 /* Set alt LNA1 or LNA2 */ 297 if (div_ant_conf->main_lna_conf == 298 HAL_ANT_DIV_COMB_LNA2) 299 div_ant_conf->alt_lna_conf = 300 HAL_ANT_DIV_COMB_LNA1; 301 else 302 div_ant_conf->alt_lna_conf = 303 HAL_ANT_DIV_COMB_LNA2; 304 else 305 /* Set alt to A+B or A-B */ 306 div_ant_conf->alt_lna_conf = antcomb->main_conf; 307 } 308 break; 309 default: 310 break; 311 } 312} 313 314static void 315ath_ant_div_conf_fast_divbias(HAL_ANT_COMB_CONFIG *ant_conf) 316{ 317 /* Adjust the fast_div_bias based on main and alt lna conf */ 318 switch ((ant_conf->main_lna_conf << 4) | ant_conf->alt_lna_conf) { 319 case (0x01): /* A-B LNA2 */ 320 ant_conf->fast_div_bias = 0x3b; 321 break; 322 case (0x02): /* A-B LNA1 */ 323 ant_conf->fast_div_bias = 0x3d; 324 break; 325 case (0x03): /* A-B A+B */ 326 ant_conf->fast_div_bias = 0x1; 327 break; 328 case (0x10): /* LNA2 A-B */ 329 ant_conf->fast_div_bias = 0x7; 330 break; 331 case (0x12): /* LNA2 LNA1 */ 332 ant_conf->fast_div_bias = 0x2; 333 break; 334 case (0x13): /* LNA2 A+B */ 335 ant_conf->fast_div_bias = 0x7; 336 break; 337 case (0x20): /* LNA1 A-B */ 338 ant_conf->fast_div_bias = 0x6; 339 break; 340 case (0x21): /* LNA1 LNA2 */ 341 ant_conf->fast_div_bias = 0x0; 342 break; 343 case (0x23): /* LNA1 A+B */ 344 ant_conf->fast_div_bias = 0x6; 345 break; 346 case (0x30): /* A+B A-B */ 347 ant_conf->fast_div_bias = 0x1; 348 break; 349 case (0x31): /* A+B LNA2 */ 350 ant_conf->fast_div_bias = 0x3b; 351 break; 352 case (0x32): /* A+B LNA1 */ 353 ant_conf->fast_div_bias = 0x3d; 354 break; 355 default: 356 break; 357 } 358} 359 360/* Antenna diversity and combining */ 361void 362ar9285_ant_comb_scan(struct ath_hal *ah, struct ath_rx_status *rs, 363 unsigned long ticks, int hz) 364{ 365 HAL_ANT_COMB_CONFIG div_ant_conf; 366 struct ar9285_ant_comb *antcomb = &AH9285(ah)->ant_comb; 367 int alt_ratio = 0, alt_rssi_avg = 0, main_rssi_avg = 0, curr_alt_set; 368 int curr_main_set, curr_bias; 369 int main_rssi = rs->rs_rssi_ctl[0]; 370 int alt_rssi = rs->rs_rssi_ctl[1]; 371 int rx_ant_conf, main_ant_conf, alt_ant_conf; 372 HAL_BOOL short_scan = AH_FALSE; 373 374 rx_ant_conf = (rs->rs_rssi_ctl[2] >> 4) & ATH_ANT_RX_MASK; 375 main_ant_conf = (rs->rs_rssi_ctl[2] >> 2) & ATH_ANT_RX_MASK; 376 alt_ant_conf = (rs->rs_rssi_ctl[2] >> 0) & ATH_ANT_RX_MASK; 377 378#if 0 379 HALDEBUG(ah, HAL_DEBUG_DIVERSITY, "%s: RSSI %d/%d, conf %x/%x, rxconf %x, LNA: %d; ANT: %d; FastDiv: %d\n", 380 __func__, main_rssi, alt_rssi, main_ant_conf,alt_ant_conf, rx_ant_conf, 381 !!(rs->rs_rssi_ctl[2] & 0x80), !!(rs->rs_rssi_ctl[2] & 0x40), !!(rs->rs_rssi_ext[2] & 0x40)); 382#endif 383 384 if (! ar9285_check_div_comb(ah)) 385 return; 386 387 if (AH5212(ah)->ah_diversity == AH_FALSE) 388 return; 389 390#if 0 391 HALDEBUG(ah, HAL_DEBUG_DIVERSITY, "%s: main: %d, alt: %d, rx_ant_conf: %x, main_ant_conf: %x\n", 392 __func__, main_rssi, alt_rssi, rx_ant_conf, main_ant_conf); 393#endif 394 395 /* Record packet only when alt_rssi is positive */ 396 if (main_rssi > 0 && alt_rssi > 0) { 397 antcomb->total_pkt_count++; 398 antcomb->main_total_rssi += main_rssi; 399 antcomb->alt_total_rssi += alt_rssi; 400 if (main_ant_conf == rx_ant_conf) 401 antcomb->main_recv_cnt++; 402 else 403 antcomb->alt_recv_cnt++; 404 } 405 406 /* Short scan check */ 407 if (antcomb->scan && antcomb->alt_good) { 408 if (time_after(ticks, antcomb->scan_start_time + 409 msecs_to_jiffies(ATH_ANT_DIV_COMB_SHORT_SCAN_INTR))) 410 short_scan = AH_TRUE; 411 else 412 if (antcomb->total_pkt_count == 413 ATH_ANT_DIV_COMB_SHORT_SCAN_PKTCOUNT) { 414 alt_ratio = ((antcomb->alt_recv_cnt * 100) / 415 antcomb->total_pkt_count); 416 if (alt_ratio < ATH_ANT_DIV_COMB_ALT_ANT_RATIO) 417 short_scan = AH_TRUE; 418 } 419 } 420 421 if (((antcomb->total_pkt_count < ATH_ANT_DIV_COMB_MAX_PKTCOUNT) || 422 rs->rs_moreaggr) && !short_scan) 423 return; 424 425 if (antcomb->total_pkt_count) { 426 alt_ratio = ((antcomb->alt_recv_cnt * 100) / 427 antcomb->total_pkt_count); 428 main_rssi_avg = (antcomb->main_total_rssi / 429 antcomb->total_pkt_count); 430 alt_rssi_avg = (antcomb->alt_total_rssi / 431 antcomb->total_pkt_count); 432 } 433 434 OS_MEMZERO(&div_ant_conf, sizeof(div_ant_conf)); 435 ar9285_antdiv_comb_conf_get(ah, &div_ant_conf); 436 curr_alt_set = div_ant_conf.alt_lna_conf; 437 curr_main_set = div_ant_conf.main_lna_conf; 438 curr_bias = div_ant_conf.fast_div_bias; 439 440 antcomb->count++; 441 442 if (antcomb->count == ATH_ANT_DIV_COMB_MAX_COUNT) { 443 if (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO) { 444 ath_lnaconf_alt_good_scan(antcomb, &div_ant_conf, 445 main_rssi_avg); 446 antcomb->alt_good = AH_TRUE; 447 } else { 448 antcomb->alt_good = AH_FALSE; 449 } 450 451 antcomb->count = 0; 452 antcomb->scan = AH_TRUE; 453 antcomb->scan_not_start = AH_TRUE; 454 } 455 456 if (!antcomb->scan) { 457 if (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO) { 458 if (curr_alt_set == HAL_ANT_DIV_COMB_LNA2) { 459 /* Switch main and alt LNA */ 460 div_ant_conf.main_lna_conf = 461 HAL_ANT_DIV_COMB_LNA2; 462 div_ant_conf.alt_lna_conf = 463 HAL_ANT_DIV_COMB_LNA1; 464 } else if (curr_alt_set == HAL_ANT_DIV_COMB_LNA1) { 465 div_ant_conf.main_lna_conf = 466 HAL_ANT_DIV_COMB_LNA1; 467 div_ant_conf.alt_lna_conf = 468 HAL_ANT_DIV_COMB_LNA2; 469 } 470 471 goto div_comb_done; 472 } else if ((curr_alt_set != HAL_ANT_DIV_COMB_LNA1) && 473 (curr_alt_set != HAL_ANT_DIV_COMB_LNA2)) { 474 /* Set alt to another LNA */ 475 if (curr_main_set == HAL_ANT_DIV_COMB_LNA2) 476 div_ant_conf.alt_lna_conf = 477 HAL_ANT_DIV_COMB_LNA1; 478 else if (curr_main_set == HAL_ANT_DIV_COMB_LNA1) 479 div_ant_conf.alt_lna_conf = 480 HAL_ANT_DIV_COMB_LNA2; 481 482 goto div_comb_done; 483 } 484 485 if ((alt_rssi_avg < (main_rssi_avg + 486 ATH_ANT_DIV_COMB_LNA1_LNA2_DELTA))) 487 goto div_comb_done; 488 } 489 490 if (!antcomb->scan_not_start) { 491 switch (curr_alt_set) { 492 case HAL_ANT_DIV_COMB_LNA2: 493 antcomb->rssi_lna2 = alt_rssi_avg; 494 antcomb->rssi_lna1 = main_rssi_avg; 495 antcomb->scan = AH_TRUE; 496 /* set to A+B */ 497 div_ant_conf.main_lna_conf = 498 HAL_ANT_DIV_COMB_LNA1; 499 div_ant_conf.alt_lna_conf = 500 HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2; 501 break; 502 case HAL_ANT_DIV_COMB_LNA1: 503 antcomb->rssi_lna1 = alt_rssi_avg; 504 antcomb->rssi_lna2 = main_rssi_avg; 505 antcomb->scan = AH_TRUE; 506 /* set to A+B */ 507 div_ant_conf.main_lna_conf = HAL_ANT_DIV_COMB_LNA2; 508 div_ant_conf.alt_lna_conf = 509 HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2; 510 break; 511 case HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2: 512 antcomb->rssi_add = alt_rssi_avg; 513 antcomb->scan = AH_TRUE; 514 /* set to A-B */ 515 div_ant_conf.alt_lna_conf = 516 HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2; 517 break; 518 case HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2: 519 antcomb->rssi_sub = alt_rssi_avg; 520 antcomb->scan = AH_FALSE; 521 if (antcomb->rssi_lna2 > 522 (antcomb->rssi_lna1 + 523 ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA)) { 524 /* use LNA2 as main LNA */ 525 if ((antcomb->rssi_add > antcomb->rssi_lna1) && 526 (antcomb->rssi_add > antcomb->rssi_sub)) { 527 /* set to A+B */ 528 div_ant_conf.main_lna_conf = 529 HAL_ANT_DIV_COMB_LNA2; 530 div_ant_conf.alt_lna_conf = 531 HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2; 532 } else if (antcomb->rssi_sub > 533 antcomb->rssi_lna1) { 534 /* set to A-B */ 535 div_ant_conf.main_lna_conf = 536 HAL_ANT_DIV_COMB_LNA2; 537 div_ant_conf.alt_lna_conf = 538 HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2; 539 } else { 540 /* set to LNA1 */ 541 div_ant_conf.main_lna_conf = 542 HAL_ANT_DIV_COMB_LNA2; 543 div_ant_conf.alt_lna_conf = 544 HAL_ANT_DIV_COMB_LNA1; 545 } 546 } else { 547 /* use LNA1 as main LNA */ 548 if ((antcomb->rssi_add > antcomb->rssi_lna2) && 549 (antcomb->rssi_add > antcomb->rssi_sub)) { 550 /* set to A+B */ 551 div_ant_conf.main_lna_conf = 552 HAL_ANT_DIV_COMB_LNA1; 553 div_ant_conf.alt_lna_conf = 554 HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2; 555 } else if (antcomb->rssi_sub > 556 antcomb->rssi_lna1) { 557 /* set to A-B */ 558 div_ant_conf.main_lna_conf = 559 HAL_ANT_DIV_COMB_LNA1; 560 div_ant_conf.alt_lna_conf = 561 HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2; 562 } else { 563 /* set to LNA2 */ 564 div_ant_conf.main_lna_conf = 565 HAL_ANT_DIV_COMB_LNA1; 566 div_ant_conf.alt_lna_conf = 567 HAL_ANT_DIV_COMB_LNA2; 568 } 569 } 570 break; 571 default: 572 break; 573 } 574 } else { 575 if (!antcomb->alt_good) { 576 antcomb->scan_not_start = AH_FALSE; 577 /* Set alt to another LNA */ 578 if (curr_main_set == HAL_ANT_DIV_COMB_LNA2) { 579 div_ant_conf.main_lna_conf = 580 HAL_ANT_DIV_COMB_LNA2; 581 div_ant_conf.alt_lna_conf = 582 HAL_ANT_DIV_COMB_LNA1; 583 } else if (curr_main_set == HAL_ANT_DIV_COMB_LNA1) { 584 div_ant_conf.main_lna_conf = 585 HAL_ANT_DIV_COMB_LNA1; 586 div_ant_conf.alt_lna_conf = 587 HAL_ANT_DIV_COMB_LNA2; 588 } 589 goto div_comb_done; 590 } 591 } 592 593 ath_select_ant_div_from_quick_scan(antcomb, &div_ant_conf, 594 main_rssi_avg, alt_rssi_avg, 595 alt_ratio); 596 597 antcomb->quick_scan_cnt++; 598 599div_comb_done: 600 ath_ant_div_conf_fast_divbias(&div_ant_conf); 601 602 ar9285_antdiv_comb_conf_set(ah, &div_ant_conf); 603 604 HALDEBUG(ah, HAL_DEBUG_DIVERSITY, "%s: total_pkt_count=%d\n", 605 __func__, antcomb->total_pkt_count); 606 607 HALDEBUG(ah, HAL_DEBUG_DIVERSITY, "%s: main_total_rssi=%d\n", 608 __func__, antcomb->main_total_rssi); 609 HALDEBUG(ah, HAL_DEBUG_DIVERSITY, "%s: alt_total_rssi=%d\n", 610 __func__, antcomb->alt_total_rssi); 611 612 HALDEBUG(ah, HAL_DEBUG_DIVERSITY, "%s: main_rssi_avg=%d\n", 613 __func__, main_rssi_avg); 614 HALDEBUG(ah, HAL_DEBUG_DIVERSITY, "%s: alt_alt_rssi_avg=%d\n", 615 __func__, alt_rssi_avg); 616 617 HALDEBUG(ah, HAL_DEBUG_DIVERSITY, "%s: main_recv_cnt=%d\n", 618 __func__, antcomb->main_recv_cnt); 619 HALDEBUG(ah, HAL_DEBUG_DIVERSITY, "%s: alt_recv_cnt=%d\n", 620 __func__, antcomb->alt_recv_cnt); 621 622// if (curr_alt_set != div_ant_conf.alt_lna_conf) 623 HALDEBUG(ah, HAL_DEBUG_DIVERSITY, "%s: lna_conf: %x -> %x\n", 624 __func__, curr_alt_set, div_ant_conf.alt_lna_conf); 625// if (curr_main_set != div_ant_conf.main_lna_conf) 626 HALDEBUG(ah, HAL_DEBUG_DIVERSITY, "%s: main_lna_conf: %x -> %x\n", 627 __func__, curr_main_set, div_ant_conf.main_lna_conf); 628// if (curr_bias != div_ant_conf.fast_div_bias) 629 HALDEBUG(ah, HAL_DEBUG_DIVERSITY, "%s: fast_div_bias: %x -> %x\n", 630 __func__, curr_bias, div_ant_conf.fast_div_bias); 631 632 antcomb->scan_start_time = ticks; 633 antcomb->total_pkt_count = 0; 634 antcomb->main_total_rssi = 0; 635 antcomb->alt_total_rssi = 0; 636 antcomb->main_recv_cnt = 0; 637 antcomb->alt_recv_cnt = 0; 638} 639 640/* 641 * Set the antenna switch to control RX antenna diversity. 642 * 643 * If a fixed configuration is used, the LNA and div bias 644 * settings are fixed and the antenna diversity scanning routine 645 * is disabled. 646 * 647 * If a variable configuration is used, a default is programmed 648 * in and sampling commences per RXed packet. 649 * 650 * Since this is called from ar9285SetBoardValues() to setup 651 * diversity, it means that after a reset or scan, any current 652 * software diversity combining settings will be lost and won't 653 * re-appear until after the first successful sample run. 654 * Please keep this in mind if you're seeing weird performance 655 * that happens to relate to scan/diversity timing. 656 */ 657HAL_BOOL 658ar9285SetAntennaSwitch(struct ath_hal *ah, HAL_ANT_SETTING settings) 659{ 660 int regVal; 661 const HAL_EEPROM_v4k *ee = AH_PRIVATE(ah)->ah_eeprom; 662 const MODAL_EEP4K_HEADER *pModal = &ee->ee_base.modalHeader; 663 uint8_t ant_div_control1, ant_div_control2; 664 665 if (pModal->version < 3) { 666 HALDEBUG(ah, HAL_DEBUG_DIVERSITY, "%s: not supported\n", 667 __func__); 668 return AH_FALSE; /* Can't do diversity */ 669 } 670 671 /* Store settings */ 672 AH5212(ah)->ah_antControl = settings; 673 AH5212(ah)->ah_diversity = (settings == HAL_ANT_VARIABLE); 674 675 /* XXX don't fiddle if the PHY is in sleep mode or ! chan */ 676 677 /* Begin setting the relevant registers */ 678 679 ant_div_control1 = pModal->antdiv_ctl1; 680 ant_div_control2 = pModal->antdiv_ctl2; 681 682 regVal = OS_REG_READ(ah, AR_PHY_MULTICHAIN_GAIN_CTL); 683 regVal &= (~(AR_PHY_9285_ANT_DIV_CTL_ALL)); 684 685 /* enable antenna diversity only if diversityControl == HAL_ANT_VARIABLE */ 686 if (settings == HAL_ANT_VARIABLE) 687 regVal |= SM(ant_div_control1, AR_PHY_9285_ANT_DIV_CTL); 688 689 if (settings == HAL_ANT_VARIABLE) { 690 HALDEBUG(ah, HAL_DEBUG_DIVERSITY, "%s: HAL_ANT_VARIABLE\n", 691 __func__); 692 regVal |= SM(ant_div_control2, AR_PHY_9285_ANT_DIV_ALT_LNACONF); 693 regVal |= SM((ant_div_control2 >> 2), AR_PHY_9285_ANT_DIV_MAIN_LNACONF); 694 regVal |= SM((ant_div_control1 >> 1), AR_PHY_9285_ANT_DIV_ALT_GAINTB); 695 regVal |= SM((ant_div_control1 >> 2), AR_PHY_9285_ANT_DIV_MAIN_GAINTB); 696 } else { 697 if (settings == HAL_ANT_FIXED_A) { 698 /* Diversity disabled, RX = LNA1 */ 699 HALDEBUG(ah, HAL_DEBUG_DIVERSITY, "%s: HAL_ANT_FIXED_A\n", 700 __func__); 701 regVal |= SM(HAL_ANT_DIV_COMB_LNA2, AR_PHY_9285_ANT_DIV_ALT_LNACONF); 702 regVal |= SM(HAL_ANT_DIV_COMB_LNA1, AR_PHY_9285_ANT_DIV_MAIN_LNACONF); 703 regVal |= SM(AR_PHY_9285_ANT_DIV_GAINTB_0, AR_PHY_9285_ANT_DIV_ALT_GAINTB); 704 regVal |= SM(AR_PHY_9285_ANT_DIV_GAINTB_1, AR_PHY_9285_ANT_DIV_MAIN_GAINTB); 705 } 706 else if (settings == HAL_ANT_FIXED_B) { 707 /* Diversity disabled, RX = LNA2 */ 708 HALDEBUG(ah, HAL_DEBUG_DIVERSITY, "%s: HAL_ANT_FIXED_B\n", 709 __func__); 710 regVal |= SM(HAL_ANT_DIV_COMB_LNA1, AR_PHY_9285_ANT_DIV_ALT_LNACONF); 711 regVal |= SM(HAL_ANT_DIV_COMB_LNA2, AR_PHY_9285_ANT_DIV_MAIN_LNACONF); 712 regVal |= SM(AR_PHY_9285_ANT_DIV_GAINTB_1, AR_PHY_9285_ANT_DIV_ALT_GAINTB); 713 regVal |= SM(AR_PHY_9285_ANT_DIV_GAINTB_0, AR_PHY_9285_ANT_DIV_MAIN_GAINTB); 714 } 715 } 716 717 OS_REG_WRITE(ah, AR_PHY_MULTICHAIN_GAIN_CTL, regVal); 718 regVal = OS_REG_READ(ah, AR_PHY_MULTICHAIN_GAIN_CTL); 719 regVal = OS_REG_READ(ah, AR_PHY_CCK_DETECT); 720 regVal &= (~AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV); 721 if (settings == HAL_ANT_VARIABLE) 722 regVal |= SM((ant_div_control1 >> 3), AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV); 723 724 OS_REG_WRITE(ah, AR_PHY_CCK_DETECT, regVal); 725 regVal = OS_REG_READ(ah, AR_PHY_CCK_DETECT); 726 727 /* 728 * If Diversity combining is available and the diversity setting 729 * is to allow variable diversity, enable it by default. 730 * 731 * This will be eventually overridden by the software antenna 732 * diversity logic. 733 * 734 * Note that yes, this following section overrides the above 735 * settings for the LNA configuration and fast-bias. 736 */ 737 if (ar9285_check_div_comb(ah) && AH5212(ah)->ah_diversity == AH_TRUE) { 738 // If support DivComb, set MAIN to LNA1 and ALT to LNA2 at the first beginning 739 HALDEBUG(ah, HAL_DEBUG_DIVERSITY, 740 "%s: Enable initial settings for combined diversity\n", 741 __func__); 742 regVal = OS_REG_READ(ah, AR_PHY_MULTICHAIN_GAIN_CTL); 743 regVal &= (~(AR_PHY_9285_ANT_DIV_MAIN_LNACONF | AR_PHY_9285_ANT_DIV_ALT_LNACONF)); 744 regVal |= (HAL_ANT_DIV_COMB_LNA1 << AR_PHY_9285_ANT_DIV_MAIN_LNACONF_S); 745 regVal |= (HAL_ANT_DIV_COMB_LNA2 << AR_PHY_9285_ANT_DIV_ALT_LNACONF_S); 746 regVal &= (~(AR_PHY_9285_FAST_DIV_BIAS)); 747 regVal |= (0 << AR_PHY_9285_FAST_DIV_BIAS_S); 748 OS_REG_WRITE(ah, AR_PHY_MULTICHAIN_GAIN_CTL, regVal); 749 } 750 751 return AH_TRUE; 752} 753