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