1/* 2 * Copyright (c) 2010 Broadcom Corporation 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 ANY 11 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 13 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 14 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 */ 16#include <linux/kernel.h> 17#include <linux/delay.h> 18#include <linux/bitops.h> 19 20#include <brcm_hw_ids.h> 21#include <chipcommon.h> 22#include <aiutils.h> 23#include <d11.h> 24#include <phy_shim.h> 25#include "phy_hal.h" 26#include "phy_int.h" 27#include "phy_radio.h" 28#include "phy_lcn.h" 29#include "phyreg_n.h" 30 31#define VALID_N_RADIO(radioid) ((radioid == BCM2055_ID) || \ 32 (radioid == BCM2056_ID) || \ 33 (radioid == BCM2057_ID)) 34 35#define VALID_LCN_RADIO(radioid) (radioid == BCM2064_ID) 36 37#define VALID_RADIO(pi, radioid) ( \ 38 (ISNPHY(pi) ? VALID_N_RADIO(radioid) : false) || \ 39 (ISLCNPHY(pi) ? VALID_LCN_RADIO(radioid) : false)) 40 41/* basic mux operation - can be optimized on several architectures */ 42#define MUX(pred, true, false) ((pred) ? (true) : (false)) 43 44/* modulo inc/dec - assumes x E [0, bound - 1] */ 45#define MODINC(x, bound) MUX((x) == (bound) - 1, 0, (x) + 1) 46 47/* modulo inc/dec, bound = 2^k */ 48#define MODDEC_POW2(x, bound) (((x) - 1) & ((bound) - 1)) 49#define MODINC_POW2(x, bound) (((x) + 1) & ((bound) - 1)) 50 51struct chan_info_basic { 52 u16 chan; 53 u16 freq; 54}; 55 56static const struct chan_info_basic chan_info_all[] = { 57 {1, 2412}, 58 {2, 2417}, 59 {3, 2422}, 60 {4, 2427}, 61 {5, 2432}, 62 {6, 2437}, 63 {7, 2442}, 64 {8, 2447}, 65 {9, 2452}, 66 {10, 2457}, 67 {11, 2462}, 68 {12, 2467}, 69 {13, 2472}, 70 {14, 2484}, 71 72 {34, 5170}, 73 {38, 5190}, 74 {42, 5210}, 75 {46, 5230}, 76 77 {36, 5180}, 78 {40, 5200}, 79 {44, 5220}, 80 {48, 5240}, 81 {52, 5260}, 82 {56, 5280}, 83 {60, 5300}, 84 {64, 5320}, 85 86 {100, 5500}, 87 {104, 5520}, 88 {108, 5540}, 89 {112, 5560}, 90 {116, 5580}, 91 {120, 5600}, 92 {124, 5620}, 93 {128, 5640}, 94 {132, 5660}, 95 {136, 5680}, 96 {140, 5700}, 97 98 {149, 5745}, 99 {153, 5765}, 100 {157, 5785}, 101 {161, 5805}, 102 {165, 5825}, 103 104 {184, 4920}, 105 {188, 4940}, 106 {192, 4960}, 107 {196, 4980}, 108 {200, 5000}, 109 {204, 5020}, 110 {208, 5040}, 111 {212, 5060}, 112 {216, 5080} 113}; 114 115static const u8 ofdm_rate_lookup[] = { 116 117 BRCM_RATE_48M, 118 BRCM_RATE_24M, 119 BRCM_RATE_12M, 120 BRCM_RATE_6M, 121 BRCM_RATE_54M, 122 BRCM_RATE_36M, 123 BRCM_RATE_18M, 124 BRCM_RATE_9M 125}; 126 127#define PHY_WREG_LIMIT 24 128 129void wlc_phyreg_enter(struct brcms_phy_pub *pih) 130{ 131 struct brcms_phy *pi = (struct brcms_phy *) pih; 132 wlapi_bmac_ucode_wake_override_phyreg_set(pi->sh->physhim); 133} 134 135void wlc_phyreg_exit(struct brcms_phy_pub *pih) 136{ 137 struct brcms_phy *pi = (struct brcms_phy *) pih; 138 wlapi_bmac_ucode_wake_override_phyreg_clear(pi->sh->physhim); 139} 140 141void wlc_radioreg_enter(struct brcms_phy_pub *pih) 142{ 143 struct brcms_phy *pi = (struct brcms_phy *) pih; 144 wlapi_bmac_mctrl(pi->sh->physhim, MCTL_LOCK_RADIO, MCTL_LOCK_RADIO); 145 146 udelay(10); 147} 148 149void wlc_radioreg_exit(struct brcms_phy_pub *pih) 150{ 151 struct brcms_phy *pi = (struct brcms_phy *) pih; 152 153 (void)bcma_read16(pi->d11core, D11REGOFFS(phyversion)); 154 pi->phy_wreg = 0; 155 wlapi_bmac_mctrl(pi->sh->physhim, MCTL_LOCK_RADIO, 0); 156} 157 158u16 read_radio_reg(struct brcms_phy *pi, u16 addr) 159{ 160 u16 data; 161 162 if ((addr == RADIO_IDCODE)) 163 return 0xffff; 164 165 switch (pi->pubpi.phy_type) { 166 case PHY_TYPE_N: 167 if (!CONF_HAS(PHYTYPE, PHY_TYPE_N)) 168 break; 169 if (NREV_GE(pi->pubpi.phy_rev, 7)) 170 addr |= RADIO_2057_READ_OFF; 171 else 172 addr |= RADIO_2055_READ_OFF; 173 break; 174 175 case PHY_TYPE_LCN: 176 if (!CONF_HAS(PHYTYPE, PHY_TYPE_LCN)) 177 break; 178 addr |= RADIO_2064_READ_OFF; 179 break; 180 181 default: 182 break; 183 } 184 185 if ((D11REV_GE(pi->sh->corerev, 24)) || 186 (D11REV_IS(pi->sh->corerev, 22) 187 && (pi->pubpi.phy_type != PHY_TYPE_SSN))) { 188 bcma_wflush16(pi->d11core, D11REGOFFS(radioregaddr), addr); 189 data = bcma_read16(pi->d11core, D11REGOFFS(radioregdata)); 190 } else { 191 bcma_wflush16(pi->d11core, D11REGOFFS(phy4waddr), addr); 192 data = bcma_read16(pi->d11core, D11REGOFFS(phy4wdatalo)); 193 } 194 pi->phy_wreg = 0; 195 196 return data; 197} 198 199void write_radio_reg(struct brcms_phy *pi, u16 addr, u16 val) 200{ 201 if ((D11REV_GE(pi->sh->corerev, 24)) || 202 (D11REV_IS(pi->sh->corerev, 22) 203 && (pi->pubpi.phy_type != PHY_TYPE_SSN))) { 204 205 bcma_wflush16(pi->d11core, D11REGOFFS(radioregaddr), addr); 206 bcma_write16(pi->d11core, D11REGOFFS(radioregdata), val); 207 } else { 208 bcma_wflush16(pi->d11core, D11REGOFFS(phy4waddr), addr); 209 bcma_write16(pi->d11core, D11REGOFFS(phy4wdatalo), val); 210 } 211 212 if (++pi->phy_wreg >= pi->phy_wreg_limit) { 213 (void)bcma_read32(pi->d11core, D11REGOFFS(maccontrol)); 214 pi->phy_wreg = 0; 215 } 216} 217 218static u32 read_radio_id(struct brcms_phy *pi) 219{ 220 u32 id; 221 222 if (D11REV_GE(pi->sh->corerev, 24)) { 223 u32 b0, b1, b2; 224 225 bcma_wflush16(pi->d11core, D11REGOFFS(radioregaddr), 0); 226 b0 = (u32) bcma_read16(pi->d11core, D11REGOFFS(radioregdata)); 227 bcma_wflush16(pi->d11core, D11REGOFFS(radioregaddr), 1); 228 b1 = (u32) bcma_read16(pi->d11core, D11REGOFFS(radioregdata)); 229 bcma_wflush16(pi->d11core, D11REGOFFS(radioregaddr), 2); 230 b2 = (u32) bcma_read16(pi->d11core, D11REGOFFS(radioregdata)); 231 232 id = ((b0 & 0xf) << 28) | (((b2 << 8) | b1) << 12) | ((b0 >> 4) 233 & 0xf); 234 } else { 235 bcma_wflush16(pi->d11core, D11REGOFFS(phy4waddr), RADIO_IDCODE); 236 id = (u32) bcma_read16(pi->d11core, D11REGOFFS(phy4wdatalo)); 237 id |= (u32) bcma_read16(pi->d11core, 238 D11REGOFFS(phy4wdatahi)) << 16; 239 } 240 pi->phy_wreg = 0; 241 return id; 242} 243 244void and_radio_reg(struct brcms_phy *pi, u16 addr, u16 val) 245{ 246 u16 rval; 247 248 rval = read_radio_reg(pi, addr); 249 write_radio_reg(pi, addr, (rval & val)); 250} 251 252void or_radio_reg(struct brcms_phy *pi, u16 addr, u16 val) 253{ 254 u16 rval; 255 256 rval = read_radio_reg(pi, addr); 257 write_radio_reg(pi, addr, (rval | val)); 258} 259 260void xor_radio_reg(struct brcms_phy *pi, u16 addr, u16 mask) 261{ 262 u16 rval; 263 264 rval = read_radio_reg(pi, addr); 265 write_radio_reg(pi, addr, (rval ^ mask)); 266} 267 268void mod_radio_reg(struct brcms_phy *pi, u16 addr, u16 mask, u16 val) 269{ 270 u16 rval; 271 272 rval = read_radio_reg(pi, addr); 273 write_radio_reg(pi, addr, (rval & ~mask) | (val & mask)); 274} 275 276void write_phy_channel_reg(struct brcms_phy *pi, uint val) 277{ 278 bcma_write16(pi->d11core, D11REGOFFS(phychannel), val); 279} 280 281u16 read_phy_reg(struct brcms_phy *pi, u16 addr) 282{ 283 bcma_wflush16(pi->d11core, D11REGOFFS(phyregaddr), addr); 284 285 pi->phy_wreg = 0; 286 return bcma_read16(pi->d11core, D11REGOFFS(phyregdata)); 287} 288 289void write_phy_reg(struct brcms_phy *pi, u16 addr, u16 val) 290{ 291#ifdef CONFIG_BCM47XX 292 bcma_wflush16(pi->d11core, D11REGOFFS(phyregaddr), addr); 293 bcma_write16(pi->d11core, D11REGOFFS(phyregdata), val); 294 if (addr == 0x72) 295 (void)bcma_read16(pi->d11core, D11REGOFFS(phyversion)); 296#else 297 bcma_write32(pi->d11core, D11REGOFFS(phyregaddr), addr | (val << 16)); 298 if (++pi->phy_wreg >= pi->phy_wreg_limit) { 299 pi->phy_wreg = 0; 300 (void)bcma_read16(pi->d11core, D11REGOFFS(phyversion)); 301 } 302#endif 303} 304 305void and_phy_reg(struct brcms_phy *pi, u16 addr, u16 val) 306{ 307 bcma_wflush16(pi->d11core, D11REGOFFS(phyregaddr), addr); 308 bcma_mask16(pi->d11core, D11REGOFFS(phyregdata), val); 309 pi->phy_wreg = 0; 310} 311 312void or_phy_reg(struct brcms_phy *pi, u16 addr, u16 val) 313{ 314 bcma_wflush16(pi->d11core, D11REGOFFS(phyregaddr), addr); 315 bcma_set16(pi->d11core, D11REGOFFS(phyregdata), val); 316 pi->phy_wreg = 0; 317} 318 319void mod_phy_reg(struct brcms_phy *pi, u16 addr, u16 mask, u16 val) 320{ 321 val &= mask; 322 bcma_wflush16(pi->d11core, D11REGOFFS(phyregaddr), addr); 323 bcma_maskset16(pi->d11core, D11REGOFFS(phyregdata), ~mask, val); 324 pi->phy_wreg = 0; 325} 326 327static void wlc_set_phy_uninitted(struct brcms_phy *pi) 328{ 329 int i, j; 330 331 pi->initialized = false; 332 333 pi->tx_vos = 0xffff; 334 pi->nrssi_table_delta = 0x7fffffff; 335 pi->rc_cal = 0xffff; 336 pi->mintxbias = 0xffff; 337 pi->txpwridx = -1; 338 if (ISNPHY(pi)) { 339 pi->phy_spuravoid = SPURAVOID_DISABLE; 340 341 if (NREV_GE(pi->pubpi.phy_rev, 3) 342 && NREV_LT(pi->pubpi.phy_rev, 7)) 343 pi->phy_spuravoid = SPURAVOID_AUTO; 344 345 pi->nphy_papd_skip = 0; 346 pi->nphy_papd_epsilon_offset[0] = 0xf588; 347 pi->nphy_papd_epsilon_offset[1] = 0xf588; 348 pi->nphy_txpwr_idx[0] = 128; 349 pi->nphy_txpwr_idx[1] = 128; 350 pi->nphy_txpwrindex[0].index_internal = 40; 351 pi->nphy_txpwrindex[1].index_internal = 40; 352 pi->phy_pabias = 0; 353 } else { 354 pi->phy_spuravoid = SPURAVOID_AUTO; 355 } 356 pi->radiopwr = 0xffff; 357 for (i = 0; i < STATIC_NUM_RF; i++) { 358 for (j = 0; j < STATIC_NUM_BB; j++) 359 pi->stats_11b_txpower[i][j] = -1; 360 } 361} 362 363struct shared_phy *wlc_phy_shared_attach(struct shared_phy_params *shp) 364{ 365 struct shared_phy *sh; 366 367 sh = kzalloc(sizeof(struct shared_phy), GFP_ATOMIC); 368 if (sh == NULL) 369 return NULL; 370 371 sh->sih = shp->sih; 372 sh->physhim = shp->physhim; 373 sh->unit = shp->unit; 374 sh->corerev = shp->corerev; 375 376 sh->vid = shp->vid; 377 sh->did = shp->did; 378 sh->chip = shp->chip; 379 sh->chiprev = shp->chiprev; 380 sh->chippkg = shp->chippkg; 381 sh->sromrev = shp->sromrev; 382 sh->boardtype = shp->boardtype; 383 sh->boardrev = shp->boardrev; 384 sh->boardflags = shp->boardflags; 385 sh->boardflags2 = shp->boardflags2; 386 387 sh->fast_timer = PHY_SW_TIMER_FAST; 388 sh->slow_timer = PHY_SW_TIMER_SLOW; 389 sh->glacial_timer = PHY_SW_TIMER_GLACIAL; 390 391 sh->rssi_mode = RSSI_ANT_MERGE_MAX; 392 393 return sh; 394} 395 396static void wlc_phy_timercb_phycal(struct brcms_phy *pi) 397{ 398 uint delay = 5; 399 400 if (PHY_PERICAL_MPHASE_PENDING(pi)) { 401 if (!pi->sh->up) { 402 wlc_phy_cal_perical_mphase_reset(pi); 403 return; 404 } 405 406 if (SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi)) { 407 408 delay = 1000; 409 wlc_phy_cal_perical_mphase_restart(pi); 410 } else 411 wlc_phy_cal_perical_nphy_run(pi, PHY_PERICAL_AUTO); 412 wlapi_add_timer(pi->phycal_timer, delay, 0); 413 return; 414 } 415 416} 417 418static u32 wlc_phy_get_radio_ver(struct brcms_phy *pi) 419{ 420 u32 ver; 421 422 ver = read_radio_id(pi); 423 424 return ver; 425} 426 427struct brcms_phy_pub * 428wlc_phy_attach(struct shared_phy *sh, struct bcma_device *d11core, 429 int bandtype, struct wiphy *wiphy) 430{ 431 struct brcms_phy *pi; 432 u32 sflags = 0; 433 uint phyversion; 434 u32 idcode; 435 int i; 436 437 if (D11REV_IS(sh->corerev, 4)) 438 sflags = SISF_2G_PHY | SISF_5G_PHY; 439 else 440 sflags = bcma_aread32(d11core, BCMA_IOST); 441 442 if (bandtype == BRCM_BAND_5G) { 443 if ((sflags & (SISF_5G_PHY | SISF_DB_PHY)) == 0) 444 return NULL; 445 } 446 447 pi = sh->phy_head; 448 if ((sflags & SISF_DB_PHY) && pi) { 449 wlapi_bmac_corereset(pi->sh->physhim, pi->pubpi.coreflags); 450 pi->refcnt++; 451 return &pi->pubpi_ro; 452 } 453 454 pi = kzalloc(sizeof(struct brcms_phy), GFP_ATOMIC); 455 if (pi == NULL) 456 return NULL; 457 pi->wiphy = wiphy; 458 pi->d11core = d11core; 459 pi->sh = sh; 460 pi->phy_init_por = true; 461 pi->phy_wreg_limit = PHY_WREG_LIMIT; 462 463 pi->txpwr_percent = 100; 464 465 pi->do_initcal = true; 466 467 pi->phycal_tempdelta = 0; 468 469 if (bandtype == BRCM_BAND_2G && (sflags & SISF_2G_PHY)) 470 pi->pubpi.coreflags = SICF_GMODE; 471 472 wlapi_bmac_corereset(pi->sh->physhim, pi->pubpi.coreflags); 473 phyversion = bcma_read16(pi->d11core, D11REGOFFS(phyversion)); 474 475 pi->pubpi.phy_type = PHY_TYPE(phyversion); 476 pi->pubpi.phy_rev = phyversion & PV_PV_MASK; 477 478 if (pi->pubpi.phy_type == PHY_TYPE_LCNXN) { 479 pi->pubpi.phy_type = PHY_TYPE_N; 480 pi->pubpi.phy_rev += LCNXN_BASEREV; 481 } 482 pi->pubpi.phy_corenum = PHY_CORE_NUM_2; 483 pi->pubpi.ana_rev = (phyversion & PV_AV_MASK) >> PV_AV_SHIFT; 484 485 if (pi->pubpi.phy_type != PHY_TYPE_N && 486 pi->pubpi.phy_type != PHY_TYPE_LCN) 487 goto err; 488 489 if (bandtype == BRCM_BAND_5G) { 490 if (!ISNPHY(pi)) 491 goto err; 492 } else if (!ISNPHY(pi) && !ISLCNPHY(pi)) { 493 goto err; 494 } 495 496 wlc_phy_anacore((struct brcms_phy_pub *) pi, ON); 497 498 idcode = wlc_phy_get_radio_ver(pi); 499 pi->pubpi.radioid = 500 (idcode & IDCODE_ID_MASK) >> IDCODE_ID_SHIFT; 501 pi->pubpi.radiorev = 502 (idcode & IDCODE_REV_MASK) >> IDCODE_REV_SHIFT; 503 pi->pubpi.radiover = 504 (idcode & IDCODE_VER_MASK) >> IDCODE_VER_SHIFT; 505 if (!VALID_RADIO(pi, pi->pubpi.radioid)) 506 goto err; 507 508 wlc_phy_switch_radio((struct brcms_phy_pub *) pi, OFF); 509 510 wlc_set_phy_uninitted(pi); 511 512 pi->bw = WL_CHANSPEC_BW_20; 513 pi->radio_chanspec = (bandtype == BRCM_BAND_2G) ? 514 ch20mhz_chspec(1) : ch20mhz_chspec(36); 515 516 pi->rxiq_samps = PHY_NOISE_SAMPLE_LOG_NUM_NPHY; 517 pi->rxiq_antsel = ANT_RX_DIV_DEF; 518 519 pi->watchdog_override = true; 520 521 pi->cal_type_override = PHY_PERICAL_AUTO; 522 523 pi->nphy_saved_noisevars.bufcount = 0; 524 525 if (ISNPHY(pi)) 526 pi->min_txpower = PHY_TXPWR_MIN_NPHY; 527 else 528 pi->min_txpower = PHY_TXPWR_MIN; 529 530 pi->sh->phyrxchain = 0x3; 531 532 pi->rx2tx_biasentry = -1; 533 534 pi->phy_txcore_disable_temp = PHY_CHAIN_TX_DISABLE_TEMP; 535 pi->phy_txcore_enable_temp = 536 PHY_CHAIN_TX_DISABLE_TEMP - PHY_HYSTERESIS_DELTATEMP; 537 pi->phy_tempsense_offset = 0; 538 pi->phy_txcore_heatedup = false; 539 540 pi->nphy_lastcal_temp = -50; 541 542 pi->phynoise_polling = true; 543 if (ISNPHY(pi) || ISLCNPHY(pi)) 544 pi->phynoise_polling = false; 545 546 for (i = 0; i < TXP_NUM_RATES; i++) { 547 pi->txpwr_limit[i] = BRCMS_TXPWR_MAX; 548 pi->txpwr_env_limit[i] = BRCMS_TXPWR_MAX; 549 pi->tx_user_target[i] = BRCMS_TXPWR_MAX; 550 } 551 552 pi->radiopwr_override = RADIOPWR_OVERRIDE_DEF; 553 554 pi->user_txpwr_at_rfport = false; 555 556 if (ISNPHY(pi)) { 557 558 pi->phycal_timer = wlapi_init_timer(pi->sh->physhim, 559 wlc_phy_timercb_phycal, 560 pi, "phycal"); 561 if (!pi->phycal_timer) 562 goto err; 563 564 if (!wlc_phy_attach_nphy(pi)) 565 goto err; 566 567 } else if (ISLCNPHY(pi)) { 568 if (!wlc_phy_attach_lcnphy(pi)) 569 goto err; 570 571 } 572 573 pi->refcnt++; 574 pi->next = pi->sh->phy_head; 575 sh->phy_head = pi; 576 577 memcpy(&pi->pubpi_ro, &pi->pubpi, sizeof(struct brcms_phy_pub)); 578 579 return &pi->pubpi_ro; 580 581err: 582 kfree(pi); 583 return NULL; 584} 585 586void wlc_phy_detach(struct brcms_phy_pub *pih) 587{ 588 struct brcms_phy *pi = (struct brcms_phy *) pih; 589 590 if (pih) { 591 if (--pi->refcnt) 592 return; 593 594 if (pi->phycal_timer) { 595 wlapi_free_timer(pi->phycal_timer); 596 pi->phycal_timer = NULL; 597 } 598 599 if (pi->sh->phy_head == pi) 600 pi->sh->phy_head = pi->next; 601 else if (pi->sh->phy_head->next == pi) 602 pi->sh->phy_head->next = NULL; 603 604 if (pi->pi_fptr.detach) 605 (pi->pi_fptr.detach)(pi); 606 607 kfree(pi); 608 } 609} 610 611bool 612wlc_phy_get_phyversion(struct brcms_phy_pub *pih, u16 *phytype, u16 *phyrev, 613 u16 *radioid, u16 *radiover) 614{ 615 struct brcms_phy *pi = (struct brcms_phy *) pih; 616 *phytype = (u16) pi->pubpi.phy_type; 617 *phyrev = (u16) pi->pubpi.phy_rev; 618 *radioid = pi->pubpi.radioid; 619 *radiover = pi->pubpi.radiorev; 620 621 return true; 622} 623 624bool wlc_phy_get_encore(struct brcms_phy_pub *pih) 625{ 626 struct brcms_phy *pi = (struct brcms_phy *) pih; 627 return pi->pubpi.abgphy_encore; 628} 629 630u32 wlc_phy_get_coreflags(struct brcms_phy_pub *pih) 631{ 632 struct brcms_phy *pi = (struct brcms_phy *) pih; 633 return pi->pubpi.coreflags; 634} 635 636void wlc_phy_anacore(struct brcms_phy_pub *pih, bool on) 637{ 638 struct brcms_phy *pi = (struct brcms_phy *) pih; 639 640 if (ISNPHY(pi)) { 641 if (on) { 642 if (NREV_GE(pi->pubpi.phy_rev, 3)) { 643 write_phy_reg(pi, 0xa6, 0x0d); 644 write_phy_reg(pi, 0x8f, 0x0); 645 write_phy_reg(pi, 0xa7, 0x0d); 646 write_phy_reg(pi, 0xa5, 0x0); 647 } else { 648 write_phy_reg(pi, 0xa5, 0x0); 649 } 650 } else { 651 if (NREV_GE(pi->pubpi.phy_rev, 3)) { 652 write_phy_reg(pi, 0x8f, 0x07ff); 653 write_phy_reg(pi, 0xa6, 0x0fd); 654 write_phy_reg(pi, 0xa5, 0x07ff); 655 write_phy_reg(pi, 0xa7, 0x0fd); 656 } else { 657 write_phy_reg(pi, 0xa5, 0x7fff); 658 } 659 } 660 } else if (ISLCNPHY(pi)) { 661 if (on) { 662 and_phy_reg(pi, 0x43b, 663 ~((0x1 << 0) | (0x1 << 1) | (0x1 << 2))); 664 } else { 665 or_phy_reg(pi, 0x43c, 666 (0x1 << 0) | (0x1 << 1) | (0x1 << 2)); 667 or_phy_reg(pi, 0x43b, 668 (0x1 << 0) | (0x1 << 1) | (0x1 << 2)); 669 } 670 } 671} 672 673u32 wlc_phy_clk_bwbits(struct brcms_phy_pub *pih) 674{ 675 struct brcms_phy *pi = (struct brcms_phy *) pih; 676 677 u32 phy_bw_clkbits = 0; 678 679 if (pi && (ISNPHY(pi) || ISLCNPHY(pi))) { 680 switch (pi->bw) { 681 case WL_CHANSPEC_BW_10: 682 phy_bw_clkbits = SICF_BW10; 683 break; 684 case WL_CHANSPEC_BW_20: 685 phy_bw_clkbits = SICF_BW20; 686 break; 687 case WL_CHANSPEC_BW_40: 688 phy_bw_clkbits = SICF_BW40; 689 break; 690 default: 691 break; 692 } 693 } 694 695 return phy_bw_clkbits; 696} 697 698void wlc_phy_por_inform(struct brcms_phy_pub *ppi) 699{ 700 struct brcms_phy *pi = (struct brcms_phy *) ppi; 701 702 pi->phy_init_por = true; 703} 704 705void wlc_phy_edcrs_lock(struct brcms_phy_pub *pih, bool lock) 706{ 707 struct brcms_phy *pi = (struct brcms_phy *) pih; 708 709 pi->edcrs_threshold_lock = lock; 710 711 write_phy_reg(pi, 0x22c, 0x46b); 712 write_phy_reg(pi, 0x22d, 0x46b); 713 write_phy_reg(pi, 0x22e, 0x3c0); 714 write_phy_reg(pi, 0x22f, 0x3c0); 715} 716 717void wlc_phy_initcal_enable(struct brcms_phy_pub *pih, bool initcal) 718{ 719 struct brcms_phy *pi = (struct brcms_phy *) pih; 720 721 pi->do_initcal = initcal; 722} 723 724void wlc_phy_hw_clk_state_upd(struct brcms_phy_pub *pih, bool newstate) 725{ 726 struct brcms_phy *pi = (struct brcms_phy *) pih; 727 728 if (!pi || !pi->sh) 729 return; 730 731 pi->sh->clk = newstate; 732} 733 734void wlc_phy_hw_state_upd(struct brcms_phy_pub *pih, bool newstate) 735{ 736 struct brcms_phy *pi = (struct brcms_phy *) pih; 737 738 if (!pi || !pi->sh) 739 return; 740 741 pi->sh->up = newstate; 742} 743 744void wlc_phy_init(struct brcms_phy_pub *pih, u16 chanspec) 745{ 746 u32 mc; 747 void (*phy_init)(struct brcms_phy *) = NULL; 748 struct brcms_phy *pi = (struct brcms_phy *) pih; 749 750 if (pi->init_in_progress) 751 return; 752 753 pi->init_in_progress = true; 754 755 pi->radio_chanspec = chanspec; 756 757 mc = bcma_read32(pi->d11core, D11REGOFFS(maccontrol)); 758 if (WARN(mc & MCTL_EN_MAC, "HW error MAC running on init")) 759 return; 760 761 if (!(pi->measure_hold & PHY_HOLD_FOR_SCAN)) 762 pi->measure_hold |= PHY_HOLD_FOR_NOT_ASSOC; 763 764 if (WARN(!(bcma_aread32(pi->d11core, BCMA_IOST) & SISF_FCLKA), 765 "HW error SISF_FCLKA\n")) 766 return; 767 768 phy_init = pi->pi_fptr.init; 769 770 if (phy_init == NULL) 771 return; 772 773 wlc_phy_anacore(pih, ON); 774 775 if (CHSPEC_BW(pi->radio_chanspec) != pi->bw) 776 wlapi_bmac_bw_set(pi->sh->physhim, 777 CHSPEC_BW(pi->radio_chanspec)); 778 779 pi->nphy_gain_boost = true; 780 781 wlc_phy_switch_radio((struct brcms_phy_pub *) pi, ON); 782 783 (*phy_init)(pi); 784 785 pi->phy_init_por = false; 786 787 if (D11REV_IS(pi->sh->corerev, 11) || D11REV_IS(pi->sh->corerev, 12)) 788 wlc_phy_do_dummy_tx(pi, true, OFF); 789 790 if (!(ISNPHY(pi))) 791 wlc_phy_txpower_update_shm(pi); 792 793 wlc_phy_ant_rxdiv_set((struct brcms_phy_pub *) pi, pi->sh->rx_antdiv); 794 795 pi->init_in_progress = false; 796} 797 798void wlc_phy_cal_init(struct brcms_phy_pub *pih) 799{ 800 struct brcms_phy *pi = (struct brcms_phy *) pih; 801 void (*cal_init)(struct brcms_phy *) = NULL; 802 803 if (WARN((bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) & 804 MCTL_EN_MAC) != 0, "HW error: MAC enabled during phy cal\n")) 805 return; 806 807 if (!pi->initialized) { 808 cal_init = pi->pi_fptr.calinit; 809 if (cal_init) 810 (*cal_init)(pi); 811 812 pi->initialized = true; 813 } 814} 815 816int wlc_phy_down(struct brcms_phy_pub *pih) 817{ 818 struct brcms_phy *pi = (struct brcms_phy *) pih; 819 int callbacks = 0; 820 821 if (pi->phycal_timer 822 && !wlapi_del_timer(pi->phycal_timer)) 823 callbacks++; 824 825 pi->nphy_iqcal_chanspec_2G = 0; 826 pi->nphy_iqcal_chanspec_5G = 0; 827 828 return callbacks; 829} 830 831void 832wlc_phy_table_addr(struct brcms_phy *pi, uint tbl_id, uint tbl_offset, 833 u16 tblAddr, u16 tblDataHi, u16 tblDataLo) 834{ 835 write_phy_reg(pi, tblAddr, (tbl_id << 10) | tbl_offset); 836 837 pi->tbl_data_hi = tblDataHi; 838 pi->tbl_data_lo = tblDataLo; 839 840 if (pi->sh->chip == BCM43224_CHIP_ID && 841 pi->sh->chiprev == 1) { 842 pi->tbl_addr = tblAddr; 843 pi->tbl_save_id = tbl_id; 844 pi->tbl_save_offset = tbl_offset; 845 } 846} 847 848void wlc_phy_table_data_write(struct brcms_phy *pi, uint width, u32 val) 849{ 850 if ((pi->sh->chip == BCM43224_CHIP_ID) && 851 (pi->sh->chiprev == 1) && 852 (pi->tbl_save_id == NPHY_TBL_ID_ANTSWCTRLLUT)) { 853 read_phy_reg(pi, pi->tbl_data_lo); 854 855 write_phy_reg(pi, pi->tbl_addr, 856 (pi->tbl_save_id << 10) | pi->tbl_save_offset); 857 pi->tbl_save_offset++; 858 } 859 860 if (width == 32) { 861 write_phy_reg(pi, pi->tbl_data_hi, (u16) (val >> 16)); 862 write_phy_reg(pi, pi->tbl_data_lo, (u16) val); 863 } else { 864 write_phy_reg(pi, pi->tbl_data_lo, (u16) val); 865 } 866} 867 868void 869wlc_phy_write_table(struct brcms_phy *pi, const struct phytbl_info *ptbl_info, 870 u16 tblAddr, u16 tblDataHi, u16 tblDataLo) 871{ 872 uint idx; 873 uint tbl_id = ptbl_info->tbl_id; 874 uint tbl_offset = ptbl_info->tbl_offset; 875 uint tbl_width = ptbl_info->tbl_width; 876 const u8 *ptbl_8b = (const u8 *)ptbl_info->tbl_ptr; 877 const u16 *ptbl_16b = (const u16 *)ptbl_info->tbl_ptr; 878 const u32 *ptbl_32b = (const u32 *)ptbl_info->tbl_ptr; 879 880 write_phy_reg(pi, tblAddr, (tbl_id << 10) | tbl_offset); 881 882 for (idx = 0; idx < ptbl_info->tbl_len; idx++) { 883 884 if ((pi->sh->chip == BCM43224_CHIP_ID) && 885 (pi->sh->chiprev == 1) && 886 (tbl_id == NPHY_TBL_ID_ANTSWCTRLLUT)) { 887 read_phy_reg(pi, tblDataLo); 888 889 write_phy_reg(pi, tblAddr, 890 (tbl_id << 10) | (tbl_offset + idx)); 891 } 892 893 if (tbl_width == 32) { 894 write_phy_reg(pi, tblDataHi, 895 (u16) (ptbl_32b[idx] >> 16)); 896 write_phy_reg(pi, tblDataLo, (u16) ptbl_32b[idx]); 897 } else if (tbl_width == 16) { 898 write_phy_reg(pi, tblDataLo, ptbl_16b[idx]); 899 } else { 900 write_phy_reg(pi, tblDataLo, ptbl_8b[idx]); 901 } 902 } 903} 904 905void 906wlc_phy_read_table(struct brcms_phy *pi, const struct phytbl_info *ptbl_info, 907 u16 tblAddr, u16 tblDataHi, u16 tblDataLo) 908{ 909 uint idx; 910 uint tbl_id = ptbl_info->tbl_id; 911 uint tbl_offset = ptbl_info->tbl_offset; 912 uint tbl_width = ptbl_info->tbl_width; 913 u8 *ptbl_8b = (u8 *)ptbl_info->tbl_ptr; 914 u16 *ptbl_16b = (u16 *)ptbl_info->tbl_ptr; 915 u32 *ptbl_32b = (u32 *)ptbl_info->tbl_ptr; 916 917 write_phy_reg(pi, tblAddr, (tbl_id << 10) | tbl_offset); 918 919 for (idx = 0; idx < ptbl_info->tbl_len; idx++) { 920 921 if ((pi->sh->chip == BCM43224_CHIP_ID) && 922 (pi->sh->chiprev == 1)) { 923 (void)read_phy_reg(pi, tblDataLo); 924 925 write_phy_reg(pi, tblAddr, 926 (tbl_id << 10) | (tbl_offset + idx)); 927 } 928 929 if (tbl_width == 32) { 930 ptbl_32b[idx] = read_phy_reg(pi, tblDataLo); 931 ptbl_32b[idx] |= (read_phy_reg(pi, tblDataHi) << 16); 932 } else if (tbl_width == 16) { 933 ptbl_16b[idx] = read_phy_reg(pi, tblDataLo); 934 } else { 935 ptbl_8b[idx] = (u8) read_phy_reg(pi, tblDataLo); 936 } 937 } 938} 939 940uint 941wlc_phy_init_radio_regs_allbands(struct brcms_phy *pi, 942 struct radio_20xx_regs *radioregs) 943{ 944 uint i = 0; 945 946 do { 947 if (radioregs[i].do_init) 948 write_radio_reg(pi, radioregs[i].address, 949 (u16) radioregs[i].init); 950 951 i++; 952 } while (radioregs[i].address != 0xffff); 953 954 return i; 955} 956 957uint 958wlc_phy_init_radio_regs(struct brcms_phy *pi, 959 const struct radio_regs *radioregs, 960 u16 core_offset) 961{ 962 uint i = 0; 963 uint count = 0; 964 965 do { 966 if (CHSPEC_IS5G(pi->radio_chanspec)) { 967 if (radioregs[i].do_init_a) { 968 write_radio_reg(pi, 969 radioregs[i]. 970 address | core_offset, 971 (u16) radioregs[i].init_a); 972 if (ISNPHY(pi) && (++count % 4 == 0)) 973 BRCMS_PHY_WAR_PR51571(pi); 974 } 975 } else { 976 if (radioregs[i].do_init_g) { 977 write_radio_reg(pi, 978 radioregs[i]. 979 address | core_offset, 980 (u16) radioregs[i].init_g); 981 if (ISNPHY(pi) && (++count % 4 == 0)) 982 BRCMS_PHY_WAR_PR51571(pi); 983 } 984 } 985 986 i++; 987 } while (radioregs[i].address != 0xffff); 988 989 return i; 990} 991 992void wlc_phy_do_dummy_tx(struct brcms_phy *pi, bool ofdm, bool pa_on) 993{ 994#define DUMMY_PKT_LEN 20 995 struct bcma_device *core = pi->d11core; 996 int i, count; 997 u8 ofdmpkt[DUMMY_PKT_LEN] = { 998 0xcc, 0x01, 0x02, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00, 999 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00 1000 }; 1001 u8 cckpkt[DUMMY_PKT_LEN] = { 1002 0x6e, 0x84, 0x0b, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00, 1003 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00 1004 }; 1005 u32 *dummypkt; 1006 1007 dummypkt = (u32 *) (ofdm ? ofdmpkt : cckpkt); 1008 wlapi_bmac_write_template_ram(pi->sh->physhim, 0, DUMMY_PKT_LEN, 1009 dummypkt); 1010 1011 bcma_write16(core, D11REGOFFS(xmtsel), 0); 1012 1013 if (D11REV_GE(pi->sh->corerev, 11)) 1014 bcma_write16(core, D11REGOFFS(wepctl), 0x100); 1015 else 1016 bcma_write16(core, D11REGOFFS(wepctl), 0); 1017 1018 bcma_write16(core, D11REGOFFS(txe_phyctl), 1019 (ofdm ? 1 : 0) | PHY_TXC_ANT_0); 1020 if (ISNPHY(pi) || ISLCNPHY(pi)) 1021 bcma_write16(core, D11REGOFFS(txe_phyctl1), 0x1A02); 1022 1023 bcma_write16(core, D11REGOFFS(txe_wm_0), 0); 1024 bcma_write16(core, D11REGOFFS(txe_wm_1), 0); 1025 1026 bcma_write16(core, D11REGOFFS(xmttplatetxptr), 0); 1027 bcma_write16(core, D11REGOFFS(xmttxcnt), DUMMY_PKT_LEN); 1028 1029 bcma_write16(core, D11REGOFFS(xmtsel), 1030 ((8 << 8) | (1 << 5) | (1 << 2) | 2)); 1031 1032 bcma_write16(core, D11REGOFFS(txe_ctl), 0); 1033 1034 if (!pa_on) { 1035 if (ISNPHY(pi)) 1036 wlc_phy_pa_override_nphy(pi, OFF); 1037 } 1038 1039 if (ISNPHY(pi) || ISLCNPHY(pi)) 1040 bcma_write16(core, D11REGOFFS(txe_aux), 0xD0); 1041 else 1042 bcma_write16(core, D11REGOFFS(txe_aux), ((1 << 5) | (1 << 4))); 1043 1044 (void)bcma_read16(core, D11REGOFFS(txe_aux)); 1045 1046 i = 0; 1047 count = ofdm ? 30 : 250; 1048 while ((i++ < count) 1049 && (bcma_read16(core, D11REGOFFS(txe_status)) & (1 << 7))) 1050 udelay(10); 1051 1052 i = 0; 1053 1054 while ((i++ < 10) && 1055 ((bcma_read16(core, D11REGOFFS(txe_status)) & (1 << 10)) == 0)) 1056 udelay(10); 1057 1058 i = 0; 1059 1060 while ((i++ < 10) && 1061 ((bcma_read16(core, D11REGOFFS(ifsstat)) & (1 << 8)))) 1062 udelay(10); 1063 1064 if (!pa_on) { 1065 if (ISNPHY(pi)) 1066 wlc_phy_pa_override_nphy(pi, ON); 1067 } 1068} 1069 1070void wlc_phy_hold_upd(struct brcms_phy_pub *pih, u32 id, bool set) 1071{ 1072 struct brcms_phy *pi = (struct brcms_phy *) pih; 1073 1074 if (set) 1075 mboolset(pi->measure_hold, id); 1076 else 1077 mboolclr(pi->measure_hold, id); 1078 1079 return; 1080} 1081 1082void wlc_phy_mute_upd(struct brcms_phy_pub *pih, bool mute, u32 flags) 1083{ 1084 struct brcms_phy *pi = (struct brcms_phy *) pih; 1085 1086 if (mute) 1087 mboolset(pi->measure_hold, PHY_HOLD_FOR_MUTE); 1088 else 1089 mboolclr(pi->measure_hold, PHY_HOLD_FOR_MUTE); 1090 1091 if (!mute && (flags & PHY_MUTE_FOR_PREISM)) 1092 pi->nphy_perical_last = pi->sh->now - pi->sh->glacial_timer; 1093 return; 1094} 1095 1096void wlc_phy_clear_tssi(struct brcms_phy_pub *pih) 1097{ 1098 struct brcms_phy *pi = (struct brcms_phy *) pih; 1099 1100 if (ISNPHY(pi)) { 1101 return; 1102 } else { 1103 wlapi_bmac_write_shm(pi->sh->physhim, M_B_TSSI_0, NULL_TSSI_W); 1104 wlapi_bmac_write_shm(pi->sh->physhim, M_B_TSSI_1, NULL_TSSI_W); 1105 wlapi_bmac_write_shm(pi->sh->physhim, M_G_TSSI_0, NULL_TSSI_W); 1106 wlapi_bmac_write_shm(pi->sh->physhim, M_G_TSSI_1, NULL_TSSI_W); 1107 } 1108} 1109 1110static bool wlc_phy_cal_txpower_recalc_sw(struct brcms_phy *pi) 1111{ 1112 return false; 1113} 1114 1115void wlc_phy_switch_radio(struct brcms_phy_pub *pih, bool on) 1116{ 1117 struct brcms_phy *pi = (struct brcms_phy *) pih; 1118 (void)bcma_read32(pi->d11core, D11REGOFFS(maccontrol)); 1119 1120 if (ISNPHY(pi)) { 1121 wlc_phy_switch_radio_nphy(pi, on); 1122 } else if (ISLCNPHY(pi)) { 1123 if (on) { 1124 and_phy_reg(pi, 0x44c, 1125 ~((0x1 << 8) | 1126 (0x1 << 9) | 1127 (0x1 << 10) | (0x1 << 11) | (0x1 << 12))); 1128 and_phy_reg(pi, 0x4b0, ~((0x1 << 3) | (0x1 << 11))); 1129 and_phy_reg(pi, 0x4f9, ~(0x1 << 3)); 1130 } else { 1131 and_phy_reg(pi, 0x44d, 1132 ~((0x1 << 10) | 1133 (0x1 << 11) | 1134 (0x1 << 12) | (0x1 << 13) | (0x1 << 14))); 1135 or_phy_reg(pi, 0x44c, 1136 (0x1 << 8) | 1137 (0x1 << 9) | 1138 (0x1 << 10) | (0x1 << 11) | (0x1 << 12)); 1139 1140 and_phy_reg(pi, 0x4b7, ~((0x7f << 8))); 1141 and_phy_reg(pi, 0x4b1, ~((0x1 << 13))); 1142 or_phy_reg(pi, 0x4b0, (0x1 << 3) | (0x1 << 11)); 1143 and_phy_reg(pi, 0x4fa, ~((0x1 << 3))); 1144 or_phy_reg(pi, 0x4f9, (0x1 << 3)); 1145 } 1146 } 1147} 1148 1149u16 wlc_phy_bw_state_get(struct brcms_phy_pub *ppi) 1150{ 1151 struct brcms_phy *pi = (struct brcms_phy *) ppi; 1152 1153 return pi->bw; 1154} 1155 1156void wlc_phy_bw_state_set(struct brcms_phy_pub *ppi, u16 bw) 1157{ 1158 struct brcms_phy *pi = (struct brcms_phy *) ppi; 1159 1160 pi->bw = bw; 1161} 1162 1163void wlc_phy_chanspec_radio_set(struct brcms_phy_pub *ppi, u16 newch) 1164{ 1165 struct brcms_phy *pi = (struct brcms_phy *) ppi; 1166 pi->radio_chanspec = newch; 1167 1168} 1169 1170u16 wlc_phy_chanspec_get(struct brcms_phy_pub *ppi) 1171{ 1172 struct brcms_phy *pi = (struct brcms_phy *) ppi; 1173 1174 return pi->radio_chanspec; 1175} 1176 1177void wlc_phy_chanspec_set(struct brcms_phy_pub *ppi, u16 chanspec) 1178{ 1179 struct brcms_phy *pi = (struct brcms_phy *) ppi; 1180 u16 m_cur_channel; 1181 void (*chanspec_set)(struct brcms_phy *, u16) = NULL; 1182 m_cur_channel = CHSPEC_CHANNEL(chanspec); 1183 if (CHSPEC_IS5G(chanspec)) 1184 m_cur_channel |= D11_CURCHANNEL_5G; 1185 if (CHSPEC_IS40(chanspec)) 1186 m_cur_channel |= D11_CURCHANNEL_40; 1187 wlapi_bmac_write_shm(pi->sh->physhim, M_CURCHANNEL, m_cur_channel); 1188 1189 chanspec_set = pi->pi_fptr.chanset; 1190 if (chanspec_set) 1191 (*chanspec_set)(pi, chanspec); 1192 1193} 1194 1195int wlc_phy_chanspec_freq2bandrange_lpssn(uint freq) 1196{ 1197 int range = -1; 1198 1199 if (freq < 2500) 1200 range = WL_CHAN_FREQ_RANGE_2G; 1201 else if (freq <= 5320) 1202 range = WL_CHAN_FREQ_RANGE_5GL; 1203 else if (freq <= 5700) 1204 range = WL_CHAN_FREQ_RANGE_5GM; 1205 else 1206 range = WL_CHAN_FREQ_RANGE_5GH; 1207 1208 return range; 1209} 1210 1211int wlc_phy_chanspec_bandrange_get(struct brcms_phy *pi, u16 chanspec) 1212{ 1213 int range = -1; 1214 uint channel = CHSPEC_CHANNEL(chanspec); 1215 uint freq = wlc_phy_channel2freq(channel); 1216 1217 if (ISNPHY(pi)) 1218 range = wlc_phy_get_chan_freq_range_nphy(pi, channel); 1219 else if (ISLCNPHY(pi)) 1220 range = wlc_phy_chanspec_freq2bandrange_lpssn(freq); 1221 1222 return range; 1223} 1224 1225void wlc_phy_chanspec_ch14_widefilter_set(struct brcms_phy_pub *ppi, 1226 bool wide_filter) 1227{ 1228 struct brcms_phy *pi = (struct brcms_phy *) ppi; 1229 1230 pi->channel_14_wide_filter = wide_filter; 1231 1232} 1233 1234int wlc_phy_channel2freq(uint channel) 1235{ 1236 uint i; 1237 1238 for (i = 0; i < ARRAY_SIZE(chan_info_all); i++) 1239 if (chan_info_all[i].chan == channel) 1240 return chan_info_all[i].freq; 1241 return 0; 1242} 1243 1244void 1245wlc_phy_chanspec_band_validch(struct brcms_phy_pub *ppi, uint band, 1246 struct brcms_chanvec *channels) 1247{ 1248 struct brcms_phy *pi = (struct brcms_phy *) ppi; 1249 uint i; 1250 uint channel; 1251 1252 memset(channels, 0, sizeof(struct brcms_chanvec)); 1253 1254 for (i = 0; i < ARRAY_SIZE(chan_info_all); i++) { 1255 channel = chan_info_all[i].chan; 1256 1257 if ((pi->a_band_high_disable) && (channel >= FIRST_REF5_CHANNUM) 1258 && (channel <= LAST_REF5_CHANNUM)) 1259 continue; 1260 1261 if ((band == BRCM_BAND_2G && channel <= CH_MAX_2G_CHANNEL) || 1262 (band == BRCM_BAND_5G && channel > CH_MAX_2G_CHANNEL)) 1263 setbit(channels->vec, channel); 1264 } 1265} 1266 1267u16 wlc_phy_chanspec_band_firstch(struct brcms_phy_pub *ppi, uint band) 1268{ 1269 struct brcms_phy *pi = (struct brcms_phy *) ppi; 1270 uint i; 1271 uint channel; 1272 u16 chspec; 1273 1274 for (i = 0; i < ARRAY_SIZE(chan_info_all); i++) { 1275 channel = chan_info_all[i].chan; 1276 1277 if (ISNPHY(pi) && pi->bw == WL_CHANSPEC_BW_40) { 1278 uint j; 1279 1280 for (j = 0; j < ARRAY_SIZE(chan_info_all); j++) { 1281 if (chan_info_all[j].chan == 1282 channel + CH_10MHZ_APART) 1283 break; 1284 } 1285 1286 if (j == ARRAY_SIZE(chan_info_all)) 1287 continue; 1288 1289 channel = upper_20_sb(channel); 1290 chspec = channel | WL_CHANSPEC_BW_40 | 1291 WL_CHANSPEC_CTL_SB_LOWER; 1292 if (band == BRCM_BAND_2G) 1293 chspec |= WL_CHANSPEC_BAND_2G; 1294 else 1295 chspec |= WL_CHANSPEC_BAND_5G; 1296 } else 1297 chspec = ch20mhz_chspec(channel); 1298 1299 if ((pi->a_band_high_disable) && (channel >= FIRST_REF5_CHANNUM) 1300 && (channel <= LAST_REF5_CHANNUM)) 1301 continue; 1302 1303 if ((band == BRCM_BAND_2G && channel <= CH_MAX_2G_CHANNEL) || 1304 (band == BRCM_BAND_5G && channel > CH_MAX_2G_CHANNEL)) 1305 return chspec; 1306 } 1307 1308 return (u16) INVCHANSPEC; 1309} 1310 1311int wlc_phy_txpower_get(struct brcms_phy_pub *ppi, uint *qdbm, bool *override) 1312{ 1313 struct brcms_phy *pi = (struct brcms_phy *) ppi; 1314 1315 *qdbm = pi->tx_user_target[0]; 1316 if (override != NULL) 1317 *override = pi->txpwroverride; 1318 return 0; 1319} 1320 1321void wlc_phy_txpower_target_set(struct brcms_phy_pub *ppi, 1322 struct txpwr_limits *txpwr) 1323{ 1324 bool mac_enabled = false; 1325 struct brcms_phy *pi = (struct brcms_phy *) ppi; 1326 1327 memcpy(&pi->tx_user_target[TXP_FIRST_CCK], 1328 &txpwr->cck[0], BRCMS_NUM_RATES_CCK); 1329 1330 memcpy(&pi->tx_user_target[TXP_FIRST_OFDM], 1331 &txpwr->ofdm[0], BRCMS_NUM_RATES_OFDM); 1332 memcpy(&pi->tx_user_target[TXP_FIRST_OFDM_20_CDD], 1333 &txpwr->ofdm_cdd[0], BRCMS_NUM_RATES_OFDM); 1334 1335 memcpy(&pi->tx_user_target[TXP_FIRST_OFDM_40_SISO], 1336 &txpwr->ofdm_40_siso[0], BRCMS_NUM_RATES_OFDM); 1337 memcpy(&pi->tx_user_target[TXP_FIRST_OFDM_40_CDD], 1338 &txpwr->ofdm_40_cdd[0], BRCMS_NUM_RATES_OFDM); 1339 1340 memcpy(&pi->tx_user_target[TXP_FIRST_MCS_20_SISO], 1341 &txpwr->mcs_20_siso[0], BRCMS_NUM_RATES_MCS_1_STREAM); 1342 memcpy(&pi->tx_user_target[TXP_FIRST_MCS_20_CDD], 1343 &txpwr->mcs_20_cdd[0], BRCMS_NUM_RATES_MCS_1_STREAM); 1344 memcpy(&pi->tx_user_target[TXP_FIRST_MCS_20_STBC], 1345 &txpwr->mcs_20_stbc[0], BRCMS_NUM_RATES_MCS_1_STREAM); 1346 memcpy(&pi->tx_user_target[TXP_FIRST_MCS_20_SDM], 1347 &txpwr->mcs_20_mimo[0], BRCMS_NUM_RATES_MCS_2_STREAM); 1348 1349 memcpy(&pi->tx_user_target[TXP_FIRST_MCS_40_SISO], 1350 &txpwr->mcs_40_siso[0], BRCMS_NUM_RATES_MCS_1_STREAM); 1351 memcpy(&pi->tx_user_target[TXP_FIRST_MCS_40_CDD], 1352 &txpwr->mcs_40_cdd[0], BRCMS_NUM_RATES_MCS_1_STREAM); 1353 memcpy(&pi->tx_user_target[TXP_FIRST_MCS_40_STBC], 1354 &txpwr->mcs_40_stbc[0], BRCMS_NUM_RATES_MCS_1_STREAM); 1355 memcpy(&pi->tx_user_target[TXP_FIRST_MCS_40_SDM], 1356 &txpwr->mcs_40_mimo[0], BRCMS_NUM_RATES_MCS_2_STREAM); 1357 1358 if (bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) & MCTL_EN_MAC) 1359 mac_enabled = true; 1360 1361 if (mac_enabled) 1362 wlapi_suspend_mac_and_wait(pi->sh->physhim); 1363 1364 wlc_phy_txpower_recalc_target(pi); 1365 wlc_phy_cal_txpower_recalc_sw(pi); 1366 1367 if (mac_enabled) 1368 wlapi_enable_mac(pi->sh->physhim); 1369} 1370 1371int wlc_phy_txpower_set(struct brcms_phy_pub *ppi, uint qdbm, bool override) 1372{ 1373 struct brcms_phy *pi = (struct brcms_phy *) ppi; 1374 int i; 1375 1376 if (qdbm > 127) 1377 return -EINVAL; 1378 1379 for (i = 0; i < TXP_NUM_RATES; i++) 1380 pi->tx_user_target[i] = (u8) qdbm; 1381 1382 pi->txpwroverride = false; 1383 1384 if (pi->sh->up) { 1385 if (!SCAN_INPROG_PHY(pi)) { 1386 bool suspend; 1387 1388 suspend = (0 == (bcma_read32(pi->d11core, 1389 D11REGOFFS(maccontrol)) & 1390 MCTL_EN_MAC)); 1391 1392 if (!suspend) 1393 wlapi_suspend_mac_and_wait(pi->sh->physhim); 1394 1395 wlc_phy_txpower_recalc_target(pi); 1396 wlc_phy_cal_txpower_recalc_sw(pi); 1397 1398 if (!suspend) 1399 wlapi_enable_mac(pi->sh->physhim); 1400 } 1401 } 1402 return 0; 1403} 1404 1405void 1406wlc_phy_txpower_sromlimit(struct brcms_phy_pub *ppi, uint channel, u8 *min_pwr, 1407 u8 *max_pwr, int txp_rate_idx) 1408{ 1409 struct brcms_phy *pi = (struct brcms_phy *) ppi; 1410 uint i; 1411 1412 *min_pwr = pi->min_txpower * BRCMS_TXPWR_DB_FACTOR; 1413 1414 if (ISNPHY(pi)) { 1415 if (txp_rate_idx < 0) 1416 txp_rate_idx = TXP_FIRST_CCK; 1417 wlc_phy_txpower_sromlimit_get_nphy(pi, channel, max_pwr, 1418 (u8) txp_rate_idx); 1419 1420 } else if ((channel <= CH_MAX_2G_CHANNEL)) { 1421 if (txp_rate_idx < 0) 1422 txp_rate_idx = TXP_FIRST_CCK; 1423 *max_pwr = pi->tx_srom_max_rate_2g[txp_rate_idx]; 1424 } else { 1425 1426 *max_pwr = BRCMS_TXPWR_MAX; 1427 1428 if (txp_rate_idx < 0) 1429 txp_rate_idx = TXP_FIRST_OFDM; 1430 1431 for (i = 0; i < ARRAY_SIZE(chan_info_all); i++) { 1432 if (channel == chan_info_all[i].chan) 1433 break; 1434 } 1435 1436 if (pi->hwtxpwr) { 1437 *max_pwr = pi->hwtxpwr[i]; 1438 } else { 1439 1440 if ((i >= FIRST_MID_5G_CHAN) && (i <= LAST_MID_5G_CHAN)) 1441 *max_pwr = 1442 pi->tx_srom_max_rate_5g_mid[txp_rate_idx]; 1443 if ((i >= FIRST_HIGH_5G_CHAN) 1444 && (i <= LAST_HIGH_5G_CHAN)) 1445 *max_pwr = 1446 pi->tx_srom_max_rate_5g_hi[txp_rate_idx]; 1447 if ((i >= FIRST_LOW_5G_CHAN) && (i <= LAST_LOW_5G_CHAN)) 1448 *max_pwr = 1449 pi->tx_srom_max_rate_5g_low[txp_rate_idx]; 1450 } 1451 } 1452} 1453 1454void 1455wlc_phy_txpower_sromlimit_max_get(struct brcms_phy_pub *ppi, uint chan, 1456 u8 *max_txpwr, u8 *min_txpwr) 1457{ 1458 struct brcms_phy *pi = (struct brcms_phy *) ppi; 1459 u8 tx_pwr_max = 0; 1460 u8 tx_pwr_min = 255; 1461 u8 max_num_rate; 1462 u8 maxtxpwr, mintxpwr, rate, pactrl; 1463 1464 pactrl = 0; 1465 1466 max_num_rate = ISNPHY(pi) ? TXP_NUM_RATES : 1467 ISLCNPHY(pi) ? (TXP_LAST_SISO_MCS_20 + 1468 1) : (TXP_LAST_OFDM + 1); 1469 1470 for (rate = 0; rate < max_num_rate; rate++) { 1471 1472 wlc_phy_txpower_sromlimit(ppi, chan, &mintxpwr, &maxtxpwr, 1473 rate); 1474 1475 maxtxpwr = (maxtxpwr > pactrl) ? (maxtxpwr - pactrl) : 0; 1476 1477 maxtxpwr = (maxtxpwr > 6) ? (maxtxpwr - 6) : 0; 1478 1479 tx_pwr_max = max(tx_pwr_max, maxtxpwr); 1480 tx_pwr_min = min(tx_pwr_min, maxtxpwr); 1481 } 1482 *max_txpwr = tx_pwr_max; 1483 *min_txpwr = tx_pwr_min; 1484} 1485 1486void 1487wlc_phy_txpower_boardlimit_band(struct brcms_phy_pub *ppi, uint bandunit, 1488 s32 *max_pwr, s32 *min_pwr, u32 *step_pwr) 1489{ 1490 return; 1491} 1492 1493u8 wlc_phy_txpower_get_target_min(struct brcms_phy_pub *ppi) 1494{ 1495 struct brcms_phy *pi = (struct brcms_phy *) ppi; 1496 1497 return pi->tx_power_min; 1498} 1499 1500u8 wlc_phy_txpower_get_target_max(struct brcms_phy_pub *ppi) 1501{ 1502 struct brcms_phy *pi = (struct brcms_phy *) ppi; 1503 1504 return pi->tx_power_max; 1505} 1506 1507static s8 wlc_phy_env_measure_vbat(struct brcms_phy *pi) 1508{ 1509 if (ISLCNPHY(pi)) 1510 return wlc_lcnphy_vbatsense(pi, 0); 1511 else 1512 return 0; 1513} 1514 1515static s8 wlc_phy_env_measure_temperature(struct brcms_phy *pi) 1516{ 1517 if (ISLCNPHY(pi)) 1518 return wlc_lcnphy_tempsense_degree(pi, 0); 1519 else 1520 return 0; 1521} 1522 1523static void wlc_phy_upd_env_txpwr_rate_limits(struct brcms_phy *pi, u32 band) 1524{ 1525 u8 i; 1526 s8 temp, vbat; 1527 1528 for (i = 0; i < TXP_NUM_RATES; i++) 1529 pi->txpwr_env_limit[i] = BRCMS_TXPWR_MAX; 1530 1531 vbat = wlc_phy_env_measure_vbat(pi); 1532 temp = wlc_phy_env_measure_temperature(pi); 1533 1534} 1535 1536static s8 1537wlc_user_txpwr_antport_to_rfport(struct brcms_phy *pi, uint chan, u32 band, 1538 u8 rate) 1539{ 1540 s8 offset = 0; 1541 1542 if (!pi->user_txpwr_at_rfport) 1543 return offset; 1544 return offset; 1545} 1546 1547void wlc_phy_txpower_recalc_target(struct brcms_phy *pi) 1548{ 1549 u8 maxtxpwr, mintxpwr, rate, pactrl; 1550 uint target_chan; 1551 u8 tx_pwr_target[TXP_NUM_RATES]; 1552 u8 tx_pwr_max = 0; 1553 u8 tx_pwr_min = 255; 1554 u8 tx_pwr_max_rate_ind = 0; 1555 u8 max_num_rate; 1556 u8 start_rate = 0; 1557 u16 chspec; 1558 u32 band = CHSPEC2BAND(pi->radio_chanspec); 1559 void (*txpwr_recalc_fn)(struct brcms_phy *) = NULL; 1560 1561 chspec = pi->radio_chanspec; 1562 if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_NONE) 1563 target_chan = CHSPEC_CHANNEL(chspec); 1564 else if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_UPPER) 1565 target_chan = upper_20_sb(CHSPEC_CHANNEL(chspec)); 1566 else 1567 target_chan = lower_20_sb(CHSPEC_CHANNEL(chspec)); 1568 1569 pactrl = 0; 1570 if (ISLCNPHY(pi)) { 1571 u32 offset_mcs, i; 1572 1573 if (CHSPEC_IS40(pi->radio_chanspec)) { 1574 offset_mcs = pi->mcs40_po; 1575 for (i = TXP_FIRST_SISO_MCS_20; 1576 i <= TXP_LAST_SISO_MCS_20; i++) { 1577 pi->tx_srom_max_rate_2g[i - 8] = 1578 pi->tx_srom_max_2g - 1579 ((offset_mcs & 0xf) * 2); 1580 offset_mcs >>= 4; 1581 } 1582 } else { 1583 offset_mcs = pi->mcs20_po; 1584 for (i = TXP_FIRST_SISO_MCS_20; 1585 i <= TXP_LAST_SISO_MCS_20; i++) { 1586 pi->tx_srom_max_rate_2g[i - 8] = 1587 pi->tx_srom_max_2g - 1588 ((offset_mcs & 0xf) * 2); 1589 offset_mcs >>= 4; 1590 } 1591 } 1592 } 1593 1594 max_num_rate = ((ISNPHY(pi)) ? (TXP_NUM_RATES) : 1595 ((ISLCNPHY(pi)) ? 1596 (TXP_LAST_SISO_MCS_20 + 1) : (TXP_LAST_OFDM + 1))); 1597 1598 wlc_phy_upd_env_txpwr_rate_limits(pi, band); 1599 1600 for (rate = start_rate; rate < max_num_rate; rate++) { 1601 1602 tx_pwr_target[rate] = pi->tx_user_target[rate]; 1603 1604 if (pi->user_txpwr_at_rfport) 1605 tx_pwr_target[rate] += 1606 wlc_user_txpwr_antport_to_rfport(pi, 1607 target_chan, 1608 band, 1609 rate); 1610 1611 wlc_phy_txpower_sromlimit((struct brcms_phy_pub *) pi, 1612 target_chan, 1613 &mintxpwr, &maxtxpwr, rate); 1614 1615 maxtxpwr = min(maxtxpwr, pi->txpwr_limit[rate]); 1616 1617 maxtxpwr = (maxtxpwr > pactrl) ? (maxtxpwr - pactrl) : 0; 1618 1619 maxtxpwr = (maxtxpwr > 6) ? (maxtxpwr - 6) : 0; 1620 1621 maxtxpwr = min(maxtxpwr, tx_pwr_target[rate]); 1622 1623 if (pi->txpwr_percent <= 100) 1624 maxtxpwr = (maxtxpwr * pi->txpwr_percent) / 100; 1625 1626 tx_pwr_target[rate] = max(maxtxpwr, mintxpwr); 1627 1628 tx_pwr_target[rate] = 1629 min(tx_pwr_target[rate], pi->txpwr_env_limit[rate]); 1630 1631 if (tx_pwr_target[rate] > tx_pwr_max) 1632 tx_pwr_max_rate_ind = rate; 1633 1634 tx_pwr_max = max(tx_pwr_max, tx_pwr_target[rate]); 1635 tx_pwr_min = min(tx_pwr_min, tx_pwr_target[rate]); 1636 } 1637 1638 memset(pi->tx_power_offset, 0, sizeof(pi->tx_power_offset)); 1639 pi->tx_power_max = tx_pwr_max; 1640 pi->tx_power_min = tx_pwr_min; 1641 pi->tx_power_max_rate_ind = tx_pwr_max_rate_ind; 1642 for (rate = 0; rate < max_num_rate; rate++) { 1643 1644 pi->tx_power_target[rate] = tx_pwr_target[rate]; 1645 1646 if (!pi->hwpwrctrl || ISNPHY(pi)) 1647 pi->tx_power_offset[rate] = 1648 pi->tx_power_max - pi->tx_power_target[rate]; 1649 else 1650 pi->tx_power_offset[rate] = 1651 pi->tx_power_target[rate] - pi->tx_power_min; 1652 } 1653 1654 txpwr_recalc_fn = pi->pi_fptr.txpwrrecalc; 1655 if (txpwr_recalc_fn) 1656 (*txpwr_recalc_fn)(pi); 1657} 1658 1659static void 1660wlc_phy_txpower_reg_limit_calc(struct brcms_phy *pi, struct txpwr_limits *txpwr, 1661 u16 chanspec) 1662{ 1663 u8 tmp_txpwr_limit[2 * BRCMS_NUM_RATES_OFDM]; 1664 u8 *txpwr_ptr1 = NULL, *txpwr_ptr2 = NULL; 1665 int rate_start_index = 0, rate1, rate2, k; 1666 1667 for (rate1 = WL_TX_POWER_CCK_FIRST, rate2 = 0; 1668 rate2 < WL_TX_POWER_CCK_NUM; rate1++, rate2++) 1669 pi->txpwr_limit[rate1] = txpwr->cck[rate2]; 1670 1671 for (rate1 = WL_TX_POWER_OFDM_FIRST, rate2 = 0; 1672 rate2 < WL_TX_POWER_OFDM_NUM; rate1++, rate2++) 1673 pi->txpwr_limit[rate1] = txpwr->ofdm[rate2]; 1674 1675 if (ISNPHY(pi)) { 1676 1677 for (k = 0; k < 4; k++) { 1678 switch (k) { 1679 case 0: 1680 1681 txpwr_ptr1 = txpwr->mcs_20_siso; 1682 txpwr_ptr2 = txpwr->ofdm; 1683 rate_start_index = WL_TX_POWER_OFDM_FIRST; 1684 break; 1685 case 1: 1686 1687 txpwr_ptr1 = txpwr->mcs_20_cdd; 1688 txpwr_ptr2 = txpwr->ofdm_cdd; 1689 rate_start_index = WL_TX_POWER_OFDM20_CDD_FIRST; 1690 break; 1691 case 2: 1692 1693 txpwr_ptr1 = txpwr->mcs_40_siso; 1694 txpwr_ptr2 = txpwr->ofdm_40_siso; 1695 rate_start_index = 1696 WL_TX_POWER_OFDM40_SISO_FIRST; 1697 break; 1698 case 3: 1699 1700 txpwr_ptr1 = txpwr->mcs_40_cdd; 1701 txpwr_ptr2 = txpwr->ofdm_40_cdd; 1702 rate_start_index = WL_TX_POWER_OFDM40_CDD_FIRST; 1703 break; 1704 } 1705 1706 for (rate2 = 0; rate2 < BRCMS_NUM_RATES_OFDM; 1707 rate2++) { 1708 tmp_txpwr_limit[rate2] = 0; 1709 tmp_txpwr_limit[BRCMS_NUM_RATES_OFDM + rate2] = 1710 txpwr_ptr1[rate2]; 1711 } 1712 wlc_phy_mcs_to_ofdm_powers_nphy( 1713 tmp_txpwr_limit, 0, 1714 BRCMS_NUM_RATES_OFDM - 1715 1, BRCMS_NUM_RATES_OFDM); 1716 for (rate1 = rate_start_index, rate2 = 0; 1717 rate2 < BRCMS_NUM_RATES_OFDM; rate1++, rate2++) 1718 pi->txpwr_limit[rate1] = 1719 min(txpwr_ptr2[rate2], 1720 tmp_txpwr_limit[rate2]); 1721 } 1722 1723 for (k = 0; k < 4; k++) { 1724 switch (k) { 1725 case 0: 1726 1727 txpwr_ptr1 = txpwr->ofdm; 1728 txpwr_ptr2 = txpwr->mcs_20_siso; 1729 rate_start_index = WL_TX_POWER_MCS20_SISO_FIRST; 1730 break; 1731 case 1: 1732 1733 txpwr_ptr1 = txpwr->ofdm_cdd; 1734 txpwr_ptr2 = txpwr->mcs_20_cdd; 1735 rate_start_index = WL_TX_POWER_MCS20_CDD_FIRST; 1736 break; 1737 case 2: 1738 1739 txpwr_ptr1 = txpwr->ofdm_40_siso; 1740 txpwr_ptr2 = txpwr->mcs_40_siso; 1741 rate_start_index = WL_TX_POWER_MCS40_SISO_FIRST; 1742 break; 1743 case 3: 1744 1745 txpwr_ptr1 = txpwr->ofdm_40_cdd; 1746 txpwr_ptr2 = txpwr->mcs_40_cdd; 1747 rate_start_index = WL_TX_POWER_MCS40_CDD_FIRST; 1748 break; 1749 } 1750 for (rate2 = 0; rate2 < BRCMS_NUM_RATES_OFDM; 1751 rate2++) { 1752 tmp_txpwr_limit[rate2] = 0; 1753 tmp_txpwr_limit[BRCMS_NUM_RATES_OFDM + rate2] = 1754 txpwr_ptr1[rate2]; 1755 } 1756 wlc_phy_ofdm_to_mcs_powers_nphy( 1757 tmp_txpwr_limit, 0, 1758 BRCMS_NUM_RATES_OFDM - 1759 1, BRCMS_NUM_RATES_OFDM); 1760 for (rate1 = rate_start_index, rate2 = 0; 1761 rate2 < BRCMS_NUM_RATES_MCS_1_STREAM; 1762 rate1++, rate2++) 1763 pi->txpwr_limit[rate1] = 1764 min(txpwr_ptr2[rate2], 1765 tmp_txpwr_limit[rate2]); 1766 } 1767 1768 for (k = 0; k < 2; k++) { 1769 switch (k) { 1770 case 0: 1771 1772 rate_start_index = WL_TX_POWER_MCS20_STBC_FIRST; 1773 txpwr_ptr1 = txpwr->mcs_20_stbc; 1774 break; 1775 case 1: 1776 1777 rate_start_index = WL_TX_POWER_MCS40_STBC_FIRST; 1778 txpwr_ptr1 = txpwr->mcs_40_stbc; 1779 break; 1780 } 1781 for (rate1 = rate_start_index, rate2 = 0; 1782 rate2 < BRCMS_NUM_RATES_MCS_1_STREAM; 1783 rate1++, rate2++) 1784 pi->txpwr_limit[rate1] = txpwr_ptr1[rate2]; 1785 } 1786 1787 for (k = 0; k < 2; k++) { 1788 switch (k) { 1789 case 0: 1790 1791 rate_start_index = WL_TX_POWER_MCS20_SDM_FIRST; 1792 txpwr_ptr1 = txpwr->mcs_20_mimo; 1793 break; 1794 case 1: 1795 1796 rate_start_index = WL_TX_POWER_MCS40_SDM_FIRST; 1797 txpwr_ptr1 = txpwr->mcs_40_mimo; 1798 break; 1799 } 1800 for (rate1 = rate_start_index, rate2 = 0; 1801 rate2 < BRCMS_NUM_RATES_MCS_2_STREAM; 1802 rate1++, rate2++) 1803 pi->txpwr_limit[rate1] = txpwr_ptr1[rate2]; 1804 } 1805 1806 pi->txpwr_limit[WL_TX_POWER_MCS_32] = txpwr->mcs32; 1807 1808 pi->txpwr_limit[WL_TX_POWER_MCS40_CDD_FIRST] = 1809 min(pi->txpwr_limit[WL_TX_POWER_MCS40_CDD_FIRST], 1810 pi->txpwr_limit[WL_TX_POWER_MCS_32]); 1811 pi->txpwr_limit[WL_TX_POWER_MCS_32] = 1812 pi->txpwr_limit[WL_TX_POWER_MCS40_CDD_FIRST]; 1813 } 1814} 1815 1816void wlc_phy_txpwr_percent_set(struct brcms_phy_pub *ppi, u8 txpwr_percent) 1817{ 1818 struct brcms_phy *pi = (struct brcms_phy *) ppi; 1819 1820 pi->txpwr_percent = txpwr_percent; 1821} 1822 1823void wlc_phy_machwcap_set(struct brcms_phy_pub *ppi, u32 machwcap) 1824{ 1825 struct brcms_phy *pi = (struct brcms_phy *) ppi; 1826 1827 pi->sh->machwcap = machwcap; 1828} 1829 1830void wlc_phy_runbist_config(struct brcms_phy_pub *ppi, bool start_end) 1831{ 1832 struct brcms_phy *pi = (struct brcms_phy *) ppi; 1833 u16 rxc; 1834 rxc = 0; 1835 1836 if (start_end == ON) { 1837 if (!ISNPHY(pi)) 1838 return; 1839 1840 if (NREV_IS(pi->pubpi.phy_rev, 3) 1841 || NREV_IS(pi->pubpi.phy_rev, 4)) { 1842 bcma_wflush16(pi->d11core, D11REGOFFS(phyregaddr), 1843 0xa0); 1844 bcma_set16(pi->d11core, D11REGOFFS(phyregdata), 1845 0x1 << 15); 1846 } 1847 } else { 1848 if (NREV_IS(pi->pubpi.phy_rev, 3) 1849 || NREV_IS(pi->pubpi.phy_rev, 4)) { 1850 bcma_wflush16(pi->d11core, D11REGOFFS(phyregaddr), 1851 0xa0); 1852 bcma_write16(pi->d11core, D11REGOFFS(phyregdata), rxc); 1853 } 1854 1855 wlc_phy_por_inform(ppi); 1856 } 1857} 1858 1859void 1860wlc_phy_txpower_limit_set(struct brcms_phy_pub *ppi, struct txpwr_limits *txpwr, 1861 u16 chanspec) 1862{ 1863 struct brcms_phy *pi = (struct brcms_phy *) ppi; 1864 1865 wlc_phy_txpower_reg_limit_calc(pi, txpwr, chanspec); 1866 1867 if (ISLCNPHY(pi)) { 1868 int i, j; 1869 for (i = TXP_FIRST_OFDM_20_CDD, j = 0; 1870 j < BRCMS_NUM_RATES_MCS_1_STREAM; i++, j++) { 1871 if (txpwr->mcs_20_siso[j]) 1872 pi->txpwr_limit[i] = txpwr->mcs_20_siso[j]; 1873 else 1874 pi->txpwr_limit[i] = txpwr->ofdm[j]; 1875 } 1876 } 1877 1878 wlapi_suspend_mac_and_wait(pi->sh->physhim); 1879 1880 wlc_phy_txpower_recalc_target(pi); 1881 wlc_phy_cal_txpower_recalc_sw(pi); 1882 wlapi_enable_mac(pi->sh->physhim); 1883} 1884 1885void wlc_phy_ofdm_rateset_war(struct brcms_phy_pub *pih, bool war) 1886{ 1887 struct brcms_phy *pi = (struct brcms_phy *) pih; 1888 1889 pi->ofdm_rateset_war = war; 1890} 1891 1892void wlc_phy_bf_preempt_enable(struct brcms_phy_pub *pih, bool bf_preempt) 1893{ 1894 struct brcms_phy *pi = (struct brcms_phy *) pih; 1895 1896 pi->bf_preempt_4306 = bf_preempt; 1897} 1898 1899void wlc_phy_txpower_update_shm(struct brcms_phy *pi) 1900{ 1901 int j; 1902 if (ISNPHY(pi)) 1903 return; 1904 1905 if (!pi->sh->clk) 1906 return; 1907 1908 if (pi->hwpwrctrl) { 1909 u16 offset; 1910 1911 wlapi_bmac_write_shm(pi->sh->physhim, M_TXPWR_MAX, 63); 1912 wlapi_bmac_write_shm(pi->sh->physhim, M_TXPWR_N, 1913 1 << NUM_TSSI_FRAMES); 1914 1915 wlapi_bmac_write_shm(pi->sh->physhim, M_TXPWR_TARGET, 1916 pi->tx_power_min << NUM_TSSI_FRAMES); 1917 1918 wlapi_bmac_write_shm(pi->sh->physhim, M_TXPWR_CUR, 1919 pi->hwpwr_txcur); 1920 1921 for (j = TXP_FIRST_OFDM; j <= TXP_LAST_OFDM; j++) { 1922 const u8 ucode_ofdm_rates[] = { 1923 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c 1924 }; 1925 offset = wlapi_bmac_rate_shm_offset( 1926 pi->sh->physhim, 1927 ucode_ofdm_rates[j - TXP_FIRST_OFDM]); 1928 wlapi_bmac_write_shm(pi->sh->physhim, offset + 6, 1929 pi->tx_power_offset[j]); 1930 wlapi_bmac_write_shm(pi->sh->physhim, offset + 14, 1931 -(pi->tx_power_offset[j] / 2)); 1932 } 1933 1934 wlapi_bmac_mhf(pi->sh->physhim, MHF2, MHF2_HWPWRCTL, 1935 MHF2_HWPWRCTL, BRCM_BAND_ALL); 1936 } else { 1937 int i; 1938 1939 for (i = TXP_FIRST_OFDM; i <= TXP_LAST_OFDM; i++) 1940 pi->tx_power_offset[i] = 1941 (u8) roundup(pi->tx_power_offset[i], 8); 1942 wlapi_bmac_write_shm(pi->sh->physhim, M_OFDM_OFFSET, 1943 (u16) 1944 ((pi->tx_power_offset[TXP_FIRST_OFDM] 1945 + 7) >> 3)); 1946 } 1947} 1948 1949bool wlc_phy_txpower_hw_ctrl_get(struct brcms_phy_pub *ppi) 1950{ 1951 struct brcms_phy *pi = (struct brcms_phy *) ppi; 1952 1953 if (ISNPHY(pi)) 1954 return pi->nphy_txpwrctrl; 1955 else 1956 return pi->hwpwrctrl; 1957} 1958 1959void wlc_phy_txpower_hw_ctrl_set(struct brcms_phy_pub *ppi, bool hwpwrctrl) 1960{ 1961 struct brcms_phy *pi = (struct brcms_phy *) ppi; 1962 bool suspend; 1963 1964 if (!pi->hwpwrctrl_capable) 1965 return; 1966 1967 pi->hwpwrctrl = hwpwrctrl; 1968 pi->nphy_txpwrctrl = hwpwrctrl; 1969 pi->txpwrctrl = hwpwrctrl; 1970 1971 if (ISNPHY(pi)) { 1972 suspend = (0 == (bcma_read32(pi->d11core, 1973 D11REGOFFS(maccontrol)) & 1974 MCTL_EN_MAC)); 1975 if (!suspend) 1976 wlapi_suspend_mac_and_wait(pi->sh->physhim); 1977 1978 wlc_phy_txpwrctrl_enable_nphy(pi, pi->nphy_txpwrctrl); 1979 if (pi->nphy_txpwrctrl == PHY_TPC_HW_OFF) 1980 wlc_phy_txpwr_fixpower_nphy(pi); 1981 else 1982 mod_phy_reg(pi, 0x1e7, (0x7f << 0), 1983 pi->saved_txpwr_idx); 1984 1985 if (!suspend) 1986 wlapi_enable_mac(pi->sh->physhim); 1987 } 1988} 1989 1990void wlc_phy_txpower_ipa_upd(struct brcms_phy *pi) 1991{ 1992 1993 if (NREV_GE(pi->pubpi.phy_rev, 3)) { 1994 pi->ipa2g_on = (pi->srom_fem2g.extpagain == 2); 1995 pi->ipa5g_on = (pi->srom_fem5g.extpagain == 2); 1996 } else { 1997 pi->ipa2g_on = false; 1998 pi->ipa5g_on = false; 1999 } 2000} 2001 2002static u32 wlc_phy_txpower_est_power_nphy(struct brcms_phy *pi) 2003{ 2004 s16 tx0_status, tx1_status; 2005 u16 estPower1, estPower2; 2006 u8 pwr0, pwr1, adj_pwr0, adj_pwr1; 2007 u32 est_pwr; 2008 2009 estPower1 = read_phy_reg(pi, 0x118); 2010 estPower2 = read_phy_reg(pi, 0x119); 2011 2012 if ((estPower1 & (0x1 << 8)) == (0x1 << 8)) 2013 pwr0 = (u8) (estPower1 & (0xff << 0)) >> 0; 2014 else 2015 pwr0 = 0x80; 2016 2017 if ((estPower2 & (0x1 << 8)) == (0x1 << 8)) 2018 pwr1 = (u8) (estPower2 & (0xff << 0)) >> 0; 2019 else 2020 pwr1 = 0x80; 2021 2022 tx0_status = read_phy_reg(pi, 0x1ed); 2023 tx1_status = read_phy_reg(pi, 0x1ee); 2024 2025 if ((tx0_status & (0x1 << 15)) == (0x1 << 15)) 2026 adj_pwr0 = (u8) (tx0_status & (0xff << 0)) >> 0; 2027 else 2028 adj_pwr0 = 0x80; 2029 if ((tx1_status & (0x1 << 15)) == (0x1 << 15)) 2030 adj_pwr1 = (u8) (tx1_status & (0xff << 0)) >> 0; 2031 else 2032 adj_pwr1 = 0x80; 2033 2034 est_pwr = (u32) ((pwr0 << 24) | (pwr1 << 16) | (adj_pwr0 << 8) | 2035 adj_pwr1); 2036 2037 return est_pwr; 2038} 2039 2040void 2041wlc_phy_txpower_get_current(struct brcms_phy_pub *ppi, struct tx_power *power, 2042 uint channel) 2043{ 2044 struct brcms_phy *pi = (struct brcms_phy *) ppi; 2045 uint rate, num_rates; 2046 u8 min_pwr, max_pwr; 2047 2048#if WL_TX_POWER_RATES != TXP_NUM_RATES 2049#error "struct tx_power out of sync with this fn" 2050#endif 2051 2052 if (ISNPHY(pi)) { 2053 power->rf_cores = 2; 2054 power->flags |= (WL_TX_POWER_F_MIMO); 2055 if (pi->nphy_txpwrctrl == PHY_TPC_HW_ON) 2056 power->flags |= 2057 (WL_TX_POWER_F_ENABLED | WL_TX_POWER_F_HW); 2058 } else if (ISLCNPHY(pi)) { 2059 power->rf_cores = 1; 2060 power->flags |= (WL_TX_POWER_F_SISO); 2061 if (pi->radiopwr_override == RADIOPWR_OVERRIDE_DEF) 2062 power->flags |= WL_TX_POWER_F_ENABLED; 2063 if (pi->hwpwrctrl) 2064 power->flags |= WL_TX_POWER_F_HW; 2065 } 2066 2067 num_rates = ((ISNPHY(pi)) ? (TXP_NUM_RATES) : 2068 ((ISLCNPHY(pi)) ? 2069 (TXP_LAST_OFDM_20_CDD + 1) : (TXP_LAST_OFDM + 1))); 2070 2071 for (rate = 0; rate < num_rates; rate++) { 2072 power->user_limit[rate] = pi->tx_user_target[rate]; 2073 wlc_phy_txpower_sromlimit(ppi, channel, &min_pwr, &max_pwr, 2074 rate); 2075 power->board_limit[rate] = (u8) max_pwr; 2076 power->target[rate] = pi->tx_power_target[rate]; 2077 } 2078 2079 if (ISNPHY(pi)) { 2080 u32 est_pout; 2081 2082 wlapi_suspend_mac_and_wait(pi->sh->physhim); 2083 wlc_phyreg_enter((struct brcms_phy_pub *) pi); 2084 est_pout = wlc_phy_txpower_est_power_nphy(pi); 2085 wlc_phyreg_exit((struct brcms_phy_pub *) pi); 2086 wlapi_enable_mac(pi->sh->physhim); 2087 2088 power->est_Pout[0] = (est_pout >> 8) & 0xff; 2089 power->est_Pout[1] = est_pout & 0xff; 2090 2091 power->est_Pout_act[0] = est_pout >> 24; 2092 power->est_Pout_act[1] = (est_pout >> 16) & 0xff; 2093 2094 if (power->est_Pout[0] == 0x80) 2095 power->est_Pout[0] = 0; 2096 if (power->est_Pout[1] == 0x80) 2097 power->est_Pout[1] = 0; 2098 2099 if (power->est_Pout_act[0] == 0x80) 2100 power->est_Pout_act[0] = 0; 2101 if (power->est_Pout_act[1] == 0x80) 2102 power->est_Pout_act[1] = 0; 2103 2104 power->est_Pout_cck = 0; 2105 2106 power->tx_power_max[0] = pi->tx_power_max; 2107 power->tx_power_max[1] = pi->tx_power_max; 2108 2109 power->tx_power_max_rate_ind[0] = pi->tx_power_max_rate_ind; 2110 power->tx_power_max_rate_ind[1] = pi->tx_power_max_rate_ind; 2111 } else if (pi->hwpwrctrl && pi->sh->up) { 2112 2113 wlc_phyreg_enter(ppi); 2114 if (ISLCNPHY(pi)) { 2115 2116 power->tx_power_max[0] = pi->tx_power_max; 2117 power->tx_power_max[1] = pi->tx_power_max; 2118 2119 power->tx_power_max_rate_ind[0] = 2120 pi->tx_power_max_rate_ind; 2121 power->tx_power_max_rate_ind[1] = 2122 pi->tx_power_max_rate_ind; 2123 2124 if (wlc_phy_tpc_isenabled_lcnphy(pi)) 2125 power->flags |= 2126 (WL_TX_POWER_F_HW | 2127 WL_TX_POWER_F_ENABLED); 2128 else 2129 power->flags &= 2130 ~(WL_TX_POWER_F_HW | 2131 WL_TX_POWER_F_ENABLED); 2132 2133 wlc_lcnphy_get_tssi(pi, (s8 *) &power->est_Pout[0], 2134 (s8 *) &power->est_Pout_cck); 2135 } 2136 wlc_phyreg_exit(ppi); 2137 } 2138} 2139 2140void wlc_phy_antsel_type_set(struct brcms_phy_pub *ppi, u8 antsel_type) 2141{ 2142 struct brcms_phy *pi = (struct brcms_phy *) ppi; 2143 2144 pi->antsel_type = antsel_type; 2145} 2146 2147bool wlc_phy_test_ison(struct brcms_phy_pub *ppi) 2148{ 2149 struct brcms_phy *pi = (struct brcms_phy *) ppi; 2150 2151 return pi->phytest_on; 2152} 2153 2154void wlc_phy_ant_rxdiv_set(struct brcms_phy_pub *ppi, u8 val) 2155{ 2156 struct brcms_phy *pi = (struct brcms_phy *) ppi; 2157 bool suspend; 2158 2159 pi->sh->rx_antdiv = val; 2160 2161 if (!(ISNPHY(pi) && D11REV_IS(pi->sh->corerev, 16))) { 2162 if (val > ANT_RX_DIV_FORCE_1) 2163 wlapi_bmac_mhf(pi->sh->physhim, MHF1, MHF1_ANTDIV, 2164 MHF1_ANTDIV, BRCM_BAND_ALL); 2165 else 2166 wlapi_bmac_mhf(pi->sh->physhim, MHF1, MHF1_ANTDIV, 0, 2167 BRCM_BAND_ALL); 2168 } 2169 2170 if (ISNPHY(pi)) 2171 return; 2172 2173 if (!pi->sh->clk) 2174 return; 2175 2176 suspend = (0 == (bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) & 2177 MCTL_EN_MAC)); 2178 if (!suspend) 2179 wlapi_suspend_mac_and_wait(pi->sh->physhim); 2180 2181 if (ISLCNPHY(pi)) { 2182 if (val > ANT_RX_DIV_FORCE_1) { 2183 mod_phy_reg(pi, 0x410, (0x1 << 1), 0x01 << 1); 2184 mod_phy_reg(pi, 0x410, 2185 (0x1 << 0), 2186 ((ANT_RX_DIV_START_1 == val) ? 1 : 0) << 0); 2187 } else { 2188 mod_phy_reg(pi, 0x410, (0x1 << 1), 0x00 << 1); 2189 mod_phy_reg(pi, 0x410, (0x1 << 0), (u16) val << 0); 2190 } 2191 } 2192 2193 if (!suspend) 2194 wlapi_enable_mac(pi->sh->physhim); 2195 2196 return; 2197} 2198 2199static bool 2200wlc_phy_noise_calc_phy(struct brcms_phy *pi, u32 *cmplx_pwr, s8 *pwr_ant) 2201{ 2202 s8 cmplx_pwr_dbm[PHY_CORE_MAX]; 2203 u8 i; 2204 2205 memset((u8 *) cmplx_pwr_dbm, 0, sizeof(cmplx_pwr_dbm)); 2206 wlc_phy_compute_dB(cmplx_pwr, cmplx_pwr_dbm, pi->pubpi.phy_corenum); 2207 2208 for (i = 0; i < pi->pubpi.phy_corenum; i++) { 2209 if (NREV_GE(pi->pubpi.phy_rev, 3)) 2210 cmplx_pwr_dbm[i] += (s8) PHY_NOISE_OFFSETFACT_4322; 2211 else 2212 2213 cmplx_pwr_dbm[i] += (s8) (16 - (15) * 3 - 70); 2214 } 2215 2216 for (i = 0; i < pi->pubpi.phy_corenum; i++) { 2217 pi->nphy_noise_win[i][pi->nphy_noise_index] = cmplx_pwr_dbm[i]; 2218 pwr_ant[i] = cmplx_pwr_dbm[i]; 2219 } 2220 pi->nphy_noise_index = 2221 MODINC_POW2(pi->nphy_noise_index, PHY_NOISE_WINDOW_SZ); 2222 return true; 2223} 2224 2225static void wlc_phy_noise_cb(struct brcms_phy *pi, u8 channel, s8 noise_dbm) 2226{ 2227 if (!pi->phynoise_state) 2228 return; 2229 2230 if (pi->phynoise_state & PHY_NOISE_STATE_MON) { 2231 if (pi->phynoise_chan_watchdog == channel) { 2232 pi->sh->phy_noise_window[pi->sh->phy_noise_index] = 2233 noise_dbm; 2234 pi->sh->phy_noise_index = 2235 MODINC(pi->sh->phy_noise_index, MA_WINDOW_SZ); 2236 } 2237 pi->phynoise_state &= ~PHY_NOISE_STATE_MON; 2238 } 2239 2240 if (pi->phynoise_state & PHY_NOISE_STATE_EXTERNAL) 2241 pi->phynoise_state &= ~PHY_NOISE_STATE_EXTERNAL; 2242 2243} 2244 2245static s8 wlc_phy_noise_read_shmem(struct brcms_phy *pi) 2246{ 2247 u32 cmplx_pwr[PHY_CORE_MAX]; 2248 s8 noise_dbm_ant[PHY_CORE_MAX]; 2249 u16 lo, hi; 2250 u32 cmplx_pwr_tot = 0; 2251 s8 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY; 2252 u8 idx, core; 2253 2254 memset((u8 *) cmplx_pwr, 0, sizeof(cmplx_pwr)); 2255 memset((u8 *) noise_dbm_ant, 0, sizeof(noise_dbm_ant)); 2256 2257 for (idx = 0, core = 0; core < pi->pubpi.phy_corenum; idx += 2, 2258 core++) { 2259 lo = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP(idx)); 2260 hi = wlapi_bmac_read_shm(pi->sh->physhim, 2261 M_PWRIND_MAP(idx + 1)); 2262 cmplx_pwr[core] = (hi << 16) + lo; 2263 cmplx_pwr_tot += cmplx_pwr[core]; 2264 if (cmplx_pwr[core] == 0) 2265 noise_dbm_ant[core] = PHY_NOISE_FIXED_VAL_NPHY; 2266 else 2267 cmplx_pwr[core] >>= PHY_NOISE_SAMPLE_LOG_NUM_UCODE; 2268 } 2269 2270 if (cmplx_pwr_tot != 0) 2271 wlc_phy_noise_calc_phy(pi, cmplx_pwr, noise_dbm_ant); 2272 2273 for (core = 0; core < pi->pubpi.phy_corenum; core++) { 2274 pi->nphy_noise_win[core][pi->nphy_noise_index] = 2275 noise_dbm_ant[core]; 2276 2277 if (noise_dbm_ant[core] > noise_dbm) 2278 noise_dbm = noise_dbm_ant[core]; 2279 } 2280 pi->nphy_noise_index = 2281 MODINC_POW2(pi->nphy_noise_index, PHY_NOISE_WINDOW_SZ); 2282 2283 return noise_dbm; 2284 2285} 2286 2287void wlc_phy_noise_sample_intr(struct brcms_phy_pub *pih) 2288{ 2289 struct brcms_phy *pi = (struct brcms_phy *) pih; 2290 u16 jssi_aux; 2291 u8 channel = 0; 2292 s8 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY; 2293 2294 if (ISLCNPHY(pi)) { 2295 u32 cmplx_pwr, cmplx_pwr0, cmplx_pwr1; 2296 u16 lo, hi; 2297 s32 pwr_offset_dB, gain_dB; 2298 u16 status_0, status_1; 2299 2300 jssi_aux = wlapi_bmac_read_shm(pi->sh->physhim, M_JSSI_AUX); 2301 channel = jssi_aux & D11_CURCHANNEL_MAX; 2302 2303 lo = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP0); 2304 hi = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP1); 2305 cmplx_pwr0 = (hi << 16) + lo; 2306 2307 lo = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP2); 2308 hi = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP3); 2309 cmplx_pwr1 = (hi << 16) + lo; 2310 cmplx_pwr = (cmplx_pwr0 + cmplx_pwr1) >> 6; 2311 2312 status_0 = 0x44; 2313 status_1 = wlapi_bmac_read_shm(pi->sh->physhim, M_JSSI_0); 2314 if ((cmplx_pwr > 0 && cmplx_pwr < 500) 2315 && ((status_1 & 0xc000) == 0x4000)) { 2316 2317 wlc_phy_compute_dB(&cmplx_pwr, &noise_dbm, 2318 pi->pubpi.phy_corenum); 2319 pwr_offset_dB = (read_phy_reg(pi, 0x434) & 0xFF); 2320 if (pwr_offset_dB > 127) 2321 pwr_offset_dB -= 256; 2322 2323 noise_dbm += (s8) (pwr_offset_dB - 30); 2324 2325 gain_dB = (status_0 & 0x1ff); 2326 noise_dbm -= (s8) (gain_dB); 2327 } else { 2328 noise_dbm = PHY_NOISE_FIXED_VAL_LCNPHY; 2329 } 2330 } else if (ISNPHY(pi)) { 2331 2332 jssi_aux = wlapi_bmac_read_shm(pi->sh->physhim, M_JSSI_AUX); 2333 channel = jssi_aux & D11_CURCHANNEL_MAX; 2334 2335 noise_dbm = wlc_phy_noise_read_shmem(pi); 2336 } 2337 2338 wlc_phy_noise_cb(pi, channel, noise_dbm); 2339 2340} 2341 2342static void 2343wlc_phy_noise_sample_request(struct brcms_phy_pub *pih, u8 reason, u8 ch) 2344{ 2345 struct brcms_phy *pi = (struct brcms_phy *) pih; 2346 s8 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY; 2347 bool sampling_in_progress = (pi->phynoise_state != 0); 2348 bool wait_for_intr = true; 2349 2350 switch (reason) { 2351 case PHY_NOISE_SAMPLE_MON: 2352 pi->phynoise_chan_watchdog = ch; 2353 pi->phynoise_state |= PHY_NOISE_STATE_MON; 2354 break; 2355 2356 case PHY_NOISE_SAMPLE_EXTERNAL: 2357 pi->phynoise_state |= PHY_NOISE_STATE_EXTERNAL; 2358 break; 2359 2360 default: 2361 break; 2362 } 2363 2364 if (sampling_in_progress) 2365 return; 2366 2367 pi->phynoise_now = pi->sh->now; 2368 2369 if (pi->phy_fixed_noise) { 2370 if (ISNPHY(pi)) { 2371 pi->nphy_noise_win[WL_ANT_IDX_1][pi->nphy_noise_index] = 2372 PHY_NOISE_FIXED_VAL_NPHY; 2373 pi->nphy_noise_win[WL_ANT_IDX_2][pi->nphy_noise_index] = 2374 PHY_NOISE_FIXED_VAL_NPHY; 2375 pi->nphy_noise_index = MODINC_POW2(pi->nphy_noise_index, 2376 PHY_NOISE_WINDOW_SZ); 2377 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY; 2378 } else { 2379 noise_dbm = PHY_NOISE_FIXED_VAL; 2380 } 2381 2382 wait_for_intr = false; 2383 goto done; 2384 } 2385 2386 if (ISLCNPHY(pi)) { 2387 if (!pi->phynoise_polling 2388 || (reason == PHY_NOISE_SAMPLE_EXTERNAL)) { 2389 wlapi_bmac_write_shm(pi->sh->physhim, M_JSSI_0, 0); 2390 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP0, 0); 2391 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP1, 0); 2392 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP2, 0); 2393 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP3, 0); 2394 2395 bcma_set32(pi->d11core, D11REGOFFS(maccommand), 2396 MCMD_BG_NOISE); 2397 } else { 2398 wlapi_suspend_mac_and_wait(pi->sh->physhim); 2399 wlc_lcnphy_deaf_mode(pi, (bool) 0); 2400 noise_dbm = (s8) wlc_lcnphy_rx_signal_power(pi, 20); 2401 wlc_lcnphy_deaf_mode(pi, (bool) 1); 2402 wlapi_enable_mac(pi->sh->physhim); 2403 wait_for_intr = false; 2404 } 2405 } else if (ISNPHY(pi)) { 2406 if (!pi->phynoise_polling 2407 || (reason == PHY_NOISE_SAMPLE_EXTERNAL)) { 2408 2409 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP0, 0); 2410 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP1, 0); 2411 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP2, 0); 2412 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP3, 0); 2413 2414 bcma_set32(pi->d11core, D11REGOFFS(maccommand), 2415 MCMD_BG_NOISE); 2416 } else { 2417 struct phy_iq_est est[PHY_CORE_MAX]; 2418 u32 cmplx_pwr[PHY_CORE_MAX]; 2419 s8 noise_dbm_ant[PHY_CORE_MAX]; 2420 u16 log_num_samps, num_samps, classif_state = 0; 2421 u8 wait_time = 32; 2422 u8 wait_crs = 0; 2423 u8 i; 2424 2425 memset((u8 *) est, 0, sizeof(est)); 2426 memset((u8 *) cmplx_pwr, 0, sizeof(cmplx_pwr)); 2427 memset((u8 *) noise_dbm_ant, 0, sizeof(noise_dbm_ant)); 2428 2429 log_num_samps = PHY_NOISE_SAMPLE_LOG_NUM_NPHY; 2430 num_samps = 1 << log_num_samps; 2431 2432 wlapi_suspend_mac_and_wait(pi->sh->physhim); 2433 classif_state = wlc_phy_classifier_nphy(pi, 0, 0); 2434 wlc_phy_classifier_nphy(pi, 3, 0); 2435 wlc_phy_rx_iq_est_nphy(pi, est, num_samps, wait_time, 2436 wait_crs); 2437 wlc_phy_classifier_nphy(pi, (0x7 << 0), classif_state); 2438 wlapi_enable_mac(pi->sh->physhim); 2439 2440 for (i = 0; i < pi->pubpi.phy_corenum; i++) 2441 cmplx_pwr[i] = (est[i].i_pwr + est[i].q_pwr) >> 2442 log_num_samps; 2443 2444 wlc_phy_noise_calc_phy(pi, cmplx_pwr, noise_dbm_ant); 2445 2446 for (i = 0; i < pi->pubpi.phy_corenum; i++) { 2447 pi->nphy_noise_win[i][pi->nphy_noise_index] = 2448 noise_dbm_ant[i]; 2449 2450 if (noise_dbm_ant[i] > noise_dbm) 2451 noise_dbm = noise_dbm_ant[i]; 2452 } 2453 pi->nphy_noise_index = MODINC_POW2(pi->nphy_noise_index, 2454 PHY_NOISE_WINDOW_SZ); 2455 2456 wait_for_intr = false; 2457 } 2458 } 2459 2460done: 2461 2462 if (!wait_for_intr) 2463 wlc_phy_noise_cb(pi, ch, noise_dbm); 2464 2465} 2466 2467void wlc_phy_noise_sample_request_external(struct brcms_phy_pub *pih) 2468{ 2469 u8 channel; 2470 2471 channel = CHSPEC_CHANNEL(wlc_phy_chanspec_get(pih)); 2472 2473 wlc_phy_noise_sample_request(pih, PHY_NOISE_SAMPLE_EXTERNAL, channel); 2474} 2475 2476static const s8 lcnphy_gain_index_offset_for_pkt_rssi[] = { 2477 8, 2478 8, 2479 8, 2480 8, 2481 8, 2482 8, 2483 8, 2484 9, 2485 10, 2486 8, 2487 8, 2488 7, 2489 7, 2490 1, 2491 2, 2492 2, 2493 2, 2494 2, 2495 2, 2496 2, 2497 2, 2498 2, 2499 2, 2500 2, 2501 2, 2502 2, 2503 2, 2504 2, 2505 2, 2506 2, 2507 2, 2508 2, 2509 1, 2510 1, 2511 0, 2512 0, 2513 0, 2514 0 2515}; 2516 2517void wlc_phy_compute_dB(u32 *cmplx_pwr, s8 *p_cmplx_pwr_dB, u8 core) 2518{ 2519 u8 msb, secondmsb, i; 2520 u32 tmp; 2521 2522 for (i = 0; i < core; i++) { 2523 secondmsb = 0; 2524 tmp = cmplx_pwr[i]; 2525 msb = fls(tmp); 2526 if (msb) 2527 secondmsb = (u8) ((tmp >> (--msb - 1)) & 1); 2528 p_cmplx_pwr_dB[i] = (s8) (3 * msb + 2 * secondmsb); 2529 } 2530} 2531 2532int wlc_phy_rssi_compute(struct brcms_phy_pub *pih, 2533 struct d11rxhdr *rxh) 2534{ 2535 int rssi = rxh->PhyRxStatus_1 & PRXS1_JSSI_MASK; 2536 uint radioid = pih->radioid; 2537 struct brcms_phy *pi = (struct brcms_phy *) pih; 2538 2539 if ((pi->sh->corerev >= 11) 2540 && !(rxh->RxStatus2 & RXS_PHYRXST_VALID)) { 2541 rssi = BRCMS_RSSI_INVALID; 2542 goto end; 2543 } 2544 2545 if (ISLCNPHY(pi)) { 2546 u8 gidx = (rxh->PhyRxStatus_2 & 0xFC00) >> 10; 2547 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; 2548 2549 if (rssi > 127) 2550 rssi -= 256; 2551 2552 rssi = rssi + lcnphy_gain_index_offset_for_pkt_rssi[gidx]; 2553 if ((rssi > -46) && (gidx > 18)) 2554 rssi = rssi + 7; 2555 2556 rssi = rssi + pi_lcn->lcnphy_pkteng_rssi_slope; 2557 2558 rssi = rssi + 2; 2559 2560 } 2561 2562 if (ISLCNPHY(pi)) { 2563 if (rssi > 127) 2564 rssi -= 256; 2565 } else if (radioid == BCM2055_ID || radioid == BCM2056_ID 2566 || radioid == BCM2057_ID) { 2567 rssi = wlc_phy_rssi_compute_nphy(pi, rxh); 2568 } 2569 2570end: 2571 return rssi; 2572} 2573 2574void wlc_phy_freqtrack_start(struct brcms_phy_pub *pih) 2575{ 2576 return; 2577} 2578 2579void wlc_phy_freqtrack_end(struct brcms_phy_pub *pih) 2580{ 2581 return; 2582} 2583 2584void wlc_phy_set_deaf(struct brcms_phy_pub *ppi, bool user_flag) 2585{ 2586 struct brcms_phy *pi; 2587 pi = (struct brcms_phy *) ppi; 2588 2589 if (ISLCNPHY(pi)) 2590 wlc_lcnphy_deaf_mode(pi, true); 2591 else if (ISNPHY(pi)) 2592 wlc_nphy_deaf_mode(pi, true); 2593} 2594 2595void wlc_phy_watchdog(struct brcms_phy_pub *pih) 2596{ 2597 struct brcms_phy *pi = (struct brcms_phy *) pih; 2598 bool delay_phy_cal = false; 2599 pi->sh->now++; 2600 2601 if (!pi->watchdog_override) 2602 return; 2603 2604 if (!(SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi))) 2605 wlc_phy_noise_sample_request((struct brcms_phy_pub *) pi, 2606 PHY_NOISE_SAMPLE_MON, 2607 CHSPEC_CHANNEL(pi-> 2608 radio_chanspec)); 2609 2610 if (pi->phynoise_state && (pi->sh->now - pi->phynoise_now) > 5) 2611 pi->phynoise_state = 0; 2612 2613 if ((!pi->phycal_txpower) || 2614 ((pi->sh->now - pi->phycal_txpower) >= pi->sh->fast_timer)) { 2615 2616 if (!SCAN_INPROG_PHY(pi) && wlc_phy_cal_txpower_recalc_sw(pi)) 2617 pi->phycal_txpower = pi->sh->now; 2618 } 2619 2620 if ((SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi) 2621 || ASSOC_INPROG_PHY(pi))) 2622 return; 2623 2624 if (ISNPHY(pi) && !pi->disable_percal && !delay_phy_cal) { 2625 2626 if ((pi->nphy_perical != PHY_PERICAL_DISABLE) && 2627 (pi->nphy_perical != PHY_PERICAL_MANUAL) && 2628 ((pi->sh->now - pi->nphy_perical_last) >= 2629 pi->sh->glacial_timer)) 2630 wlc_phy_cal_perical((struct brcms_phy_pub *) pi, 2631 PHY_PERICAL_WATCHDOG); 2632 2633 wlc_phy_txpwr_papd_cal_nphy(pi); 2634 } 2635 2636 if (ISLCNPHY(pi)) { 2637 if (pi->phy_forcecal || 2638 ((pi->sh->now - pi->phy_lastcal) >= 2639 pi->sh->glacial_timer)) { 2640 if (!(SCAN_RM_IN_PROGRESS(pi) || ASSOC_INPROG_PHY(pi))) 2641 wlc_lcnphy_calib_modes( 2642 pi, 2643 LCNPHY_PERICAL_TEMPBASED_TXPWRCTRL); 2644 if (! 2645 (SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi) 2646 || ASSOC_INPROG_PHY(pi) 2647 || pi->carrier_suppr_disable 2648 || pi->disable_percal)) 2649 wlc_lcnphy_calib_modes(pi, 2650 PHY_PERICAL_WATCHDOG); 2651 } 2652 } 2653} 2654 2655void wlc_phy_BSSinit(struct brcms_phy_pub *pih, bool bonlyap, int rssi) 2656{ 2657 struct brcms_phy *pi = (struct brcms_phy *) pih; 2658 uint i; 2659 uint k; 2660 2661 for (i = 0; i < MA_WINDOW_SZ; i++) 2662 pi->sh->phy_noise_window[i] = (s8) (rssi & 0xff); 2663 if (ISLCNPHY(pi)) { 2664 for (i = 0; i < MA_WINDOW_SZ; i++) 2665 pi->sh->phy_noise_window[i] = 2666 PHY_NOISE_FIXED_VAL_LCNPHY; 2667 } 2668 pi->sh->phy_noise_index = 0; 2669 2670 for (i = 0; i < PHY_NOISE_WINDOW_SZ; i++) { 2671 for (k = WL_ANT_IDX_1; k < WL_ANT_RX_MAX; k++) 2672 pi->nphy_noise_win[k][i] = PHY_NOISE_FIXED_VAL_NPHY; 2673 } 2674 pi->nphy_noise_index = 0; 2675} 2676 2677void 2678wlc_phy_papd_decode_epsilon(u32 epsilon, s32 *eps_real, s32 *eps_imag) 2679{ 2680 *eps_imag = (epsilon >> 13); 2681 if (*eps_imag > 0xfff) 2682 *eps_imag -= 0x2000; 2683 2684 *eps_real = (epsilon & 0x1fff); 2685 if (*eps_real > 0xfff) 2686 *eps_real -= 0x2000; 2687} 2688 2689void wlc_phy_cal_perical_mphase_reset(struct brcms_phy *pi) 2690{ 2691 wlapi_del_timer(pi->phycal_timer); 2692 2693 pi->cal_type_override = PHY_PERICAL_AUTO; 2694 pi->mphase_cal_phase_id = MPHASE_CAL_STATE_IDLE; 2695 pi->mphase_txcal_cmdidx = 0; 2696} 2697 2698static void 2699wlc_phy_cal_perical_mphase_schedule(struct brcms_phy *pi, uint delay) 2700{ 2701 2702 if ((pi->nphy_perical != PHY_PERICAL_MPHASE) && 2703 (pi->nphy_perical != PHY_PERICAL_MANUAL)) 2704 return; 2705 2706 wlapi_del_timer(pi->phycal_timer); 2707 2708 pi->mphase_cal_phase_id = MPHASE_CAL_STATE_INIT; 2709 wlapi_add_timer(pi->phycal_timer, delay, 0); 2710} 2711 2712void wlc_phy_cal_perical(struct brcms_phy_pub *pih, u8 reason) 2713{ 2714 s16 nphy_currtemp = 0; 2715 s16 delta_temp = 0; 2716 bool do_periodic_cal = true; 2717 struct brcms_phy *pi = (struct brcms_phy *) pih; 2718 2719 if (!ISNPHY(pi)) 2720 return; 2721 2722 if ((pi->nphy_perical == PHY_PERICAL_DISABLE) || 2723 (pi->nphy_perical == PHY_PERICAL_MANUAL)) 2724 return; 2725 2726 switch (reason) { 2727 case PHY_PERICAL_DRIVERUP: 2728 break; 2729 2730 case PHY_PERICAL_PHYINIT: 2731 if (pi->nphy_perical == PHY_PERICAL_MPHASE) { 2732 if (PHY_PERICAL_MPHASE_PENDING(pi)) 2733 wlc_phy_cal_perical_mphase_reset(pi); 2734 2735 wlc_phy_cal_perical_mphase_schedule( 2736 pi, 2737 PHY_PERICAL_INIT_DELAY); 2738 } 2739 break; 2740 2741 case PHY_PERICAL_JOIN_BSS: 2742 case PHY_PERICAL_START_IBSS: 2743 case PHY_PERICAL_UP_BSS: 2744 if ((pi->nphy_perical == PHY_PERICAL_MPHASE) && 2745 PHY_PERICAL_MPHASE_PENDING(pi)) 2746 wlc_phy_cal_perical_mphase_reset(pi); 2747 2748 pi->first_cal_after_assoc = true; 2749 2750 pi->cal_type_override = PHY_PERICAL_FULL; 2751 2752 if (pi->phycal_tempdelta) 2753 pi->nphy_lastcal_temp = wlc_phy_tempsense_nphy(pi); 2754 2755 wlc_phy_cal_perical_nphy_run(pi, PHY_PERICAL_FULL); 2756 break; 2757 2758 case PHY_PERICAL_WATCHDOG: 2759 if (pi->phycal_tempdelta) { 2760 nphy_currtemp = wlc_phy_tempsense_nphy(pi); 2761 delta_temp = 2762 (nphy_currtemp > pi->nphy_lastcal_temp) ? 2763 nphy_currtemp - pi->nphy_lastcal_temp : 2764 pi->nphy_lastcal_temp - nphy_currtemp; 2765 2766 if ((delta_temp < (s16) pi->phycal_tempdelta) && 2767 (pi->nphy_txiqlocal_chanspec == 2768 pi->radio_chanspec)) 2769 do_periodic_cal = false; 2770 else 2771 pi->nphy_lastcal_temp = nphy_currtemp; 2772 } 2773 2774 if (do_periodic_cal) { 2775 if (pi->nphy_perical == PHY_PERICAL_MPHASE) { 2776 if (!PHY_PERICAL_MPHASE_PENDING(pi)) 2777 wlc_phy_cal_perical_mphase_schedule( 2778 pi, 2779 PHY_PERICAL_WDOG_DELAY); 2780 } else if (pi->nphy_perical == PHY_PERICAL_SPHASE) 2781 wlc_phy_cal_perical_nphy_run(pi, 2782 PHY_PERICAL_AUTO); 2783 } 2784 break; 2785 default: 2786 break; 2787 } 2788} 2789 2790void wlc_phy_cal_perical_mphase_restart(struct brcms_phy *pi) 2791{ 2792 pi->mphase_cal_phase_id = MPHASE_CAL_STATE_INIT; 2793 pi->mphase_txcal_cmdidx = 0; 2794} 2795 2796u8 wlc_phy_nbits(s32 value) 2797{ 2798 s32 abs_val; 2799 u8 nbits = 0; 2800 2801 abs_val = abs(value); 2802 while ((abs_val >> nbits) > 0) 2803 nbits++; 2804 2805 return nbits; 2806} 2807 2808void wlc_phy_stf_chain_init(struct brcms_phy_pub *pih, u8 txchain, u8 rxchain) 2809{ 2810 struct brcms_phy *pi = (struct brcms_phy *) pih; 2811 2812 pi->sh->hw_phytxchain = txchain; 2813 pi->sh->hw_phyrxchain = rxchain; 2814 pi->sh->phytxchain = txchain; 2815 pi->sh->phyrxchain = rxchain; 2816 pi->pubpi.phy_corenum = (u8)hweight8(pi->sh->phyrxchain); 2817} 2818 2819void wlc_phy_stf_chain_set(struct brcms_phy_pub *pih, u8 txchain, u8 rxchain) 2820{ 2821 struct brcms_phy *pi = (struct brcms_phy *) pih; 2822 2823 pi->sh->phytxchain = txchain; 2824 2825 if (ISNPHY(pi)) 2826 wlc_phy_rxcore_setstate_nphy(pih, rxchain); 2827 2828 pi->pubpi.phy_corenum = (u8)hweight8(pi->sh->phyrxchain); 2829} 2830 2831void wlc_phy_stf_chain_get(struct brcms_phy_pub *pih, u8 *txchain, u8 *rxchain) 2832{ 2833 struct brcms_phy *pi = (struct brcms_phy *) pih; 2834 2835 *txchain = pi->sh->phytxchain; 2836 *rxchain = pi->sh->phyrxchain; 2837} 2838 2839u8 wlc_phy_stf_chain_active_get(struct brcms_phy_pub *pih) 2840{ 2841 s16 nphy_currtemp; 2842 u8 active_bitmap; 2843 struct brcms_phy *pi = (struct brcms_phy *) pih; 2844 2845 active_bitmap = (pi->phy_txcore_heatedup) ? 0x31 : 0x33; 2846 2847 if (!pi->watchdog_override) 2848 return active_bitmap; 2849 2850 if (NREV_GE(pi->pubpi.phy_rev, 6)) { 2851 wlapi_suspend_mac_and_wait(pi->sh->physhim); 2852 nphy_currtemp = wlc_phy_tempsense_nphy(pi); 2853 wlapi_enable_mac(pi->sh->physhim); 2854 2855 if (!pi->phy_txcore_heatedup) { 2856 if (nphy_currtemp >= pi->phy_txcore_disable_temp) { 2857 active_bitmap &= 0xFD; 2858 pi->phy_txcore_heatedup = true; 2859 } 2860 } else { 2861 if (nphy_currtemp <= pi->phy_txcore_enable_temp) { 2862 active_bitmap |= 0x2; 2863 pi->phy_txcore_heatedup = false; 2864 } 2865 } 2866 } 2867 2868 return active_bitmap; 2869} 2870 2871s8 wlc_phy_stf_ssmode_get(struct brcms_phy_pub *pih, u16 chanspec) 2872{ 2873 struct brcms_phy *pi = (struct brcms_phy *) pih; 2874 u8 siso_mcs_id, cdd_mcs_id; 2875 2876 siso_mcs_id = 2877 (CHSPEC_IS40(chanspec)) ? TXP_FIRST_MCS_40_SISO : 2878 TXP_FIRST_MCS_20_SISO; 2879 cdd_mcs_id = 2880 (CHSPEC_IS40(chanspec)) ? TXP_FIRST_MCS_40_CDD : 2881 TXP_FIRST_MCS_20_CDD; 2882 2883 if (pi->tx_power_target[siso_mcs_id] > 2884 (pi->tx_power_target[cdd_mcs_id] + 12)) 2885 return PHY_TXC1_MODE_SISO; 2886 else 2887 return PHY_TXC1_MODE_CDD; 2888} 2889 2890const u8 *wlc_phy_get_ofdm_rate_lookup(void) 2891{ 2892 return ofdm_rate_lookup; 2893} 2894 2895void wlc_lcnphy_epa_switch(struct brcms_phy *pi, bool mode) 2896{ 2897 if ((pi->sh->chip == BCM4313_CHIP_ID) && 2898 (pi->sh->boardflags & BFL_FEM)) { 2899 if (mode) { 2900 u16 txant = 0; 2901 txant = wlapi_bmac_get_txant(pi->sh->physhim); 2902 if (txant == 1) { 2903 mod_phy_reg(pi, 0x44d, (0x1 << 2), (1) << 2); 2904 2905 mod_phy_reg(pi, 0x44c, (0x1 << 2), (1) << 2); 2906 2907 } 2908 ai_cc_reg(pi->sh->sih, 2909 offsetof(struct chipcregs, gpiocontrol), 2910 ~0x0, 0x0); 2911 ai_cc_reg(pi->sh->sih, 2912 offsetof(struct chipcregs, gpioout), 2913 0x40, 0x40); 2914 ai_cc_reg(pi->sh->sih, 2915 offsetof(struct chipcregs, gpioouten), 2916 0x40, 0x40); 2917 } else { 2918 mod_phy_reg(pi, 0x44c, (0x1 << 2), (0) << 2); 2919 2920 mod_phy_reg(pi, 0x44d, (0x1 << 2), (0) << 2); 2921 2922 ai_cc_reg(pi->sh->sih, 2923 offsetof(struct chipcregs, gpioout), 2924 0x40, 0x00); 2925 ai_cc_reg(pi->sh->sih, 2926 offsetof(struct chipcregs, gpioouten), 2927 0x40, 0x0); 2928 ai_cc_reg(pi->sh->sih, 2929 offsetof(struct chipcregs, gpiocontrol), 2930 ~0x0, 0x40); 2931 } 2932 } 2933} 2934 2935void wlc_phy_ldpc_override_set(struct brcms_phy_pub *ppi, bool ldpc) 2936{ 2937 return; 2938} 2939 2940void 2941wlc_phy_get_pwrdet_offsets(struct brcms_phy *pi, s8 *cckoffset, s8 *ofdmoffset) 2942{ 2943 *cckoffset = 0; 2944 *ofdmoffset = 0; 2945} 2946 2947s8 wlc_phy_upd_rssi_offset(struct brcms_phy *pi, s8 rssi, u16 chanspec) 2948{ 2949 2950 return rssi; 2951} 2952 2953bool wlc_phy_txpower_ipa_ison(struct brcms_phy_pub *ppi) 2954{ 2955 struct brcms_phy *pi = (struct brcms_phy *) ppi; 2956 2957 if (ISNPHY(pi)) 2958 return wlc_phy_n_txpower_ipa_ison(pi); 2959 else 2960 return 0; 2961} 2962