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