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