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