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