Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: ISC
0002 /*
0003  * Copyright (c) 2010 Broadcom Corporation
0004  */
0005 #include <linux/kernel.h>
0006 #include <linux/delay.h>
0007 #include <linux/bitops.h>
0008 
0009 #include <brcm_hw_ids.h>
0010 #include <chipcommon.h>
0011 #include <aiutils.h>
0012 #include <d11.h>
0013 #include <phy_shim.h>
0014 #include "phy_hal.h"
0015 #include "phy_int.h"
0016 #include "phy_radio.h"
0017 #include "phy_lcn.h"
0018 #include "phyreg_n.h"
0019 
0020 #define VALID_N_RADIO(radioid) ((radioid == BCM2055_ID) || \
0021                  (radioid == BCM2056_ID) || \
0022                  (radioid == BCM2057_ID))
0023 
0024 #define VALID_LCN_RADIO(radioid)    (radioid == BCM2064_ID)
0025 
0026 #define VALID_RADIO(pi, radioid)        ( \
0027         (ISNPHY(pi) ? VALID_N_RADIO(radioid) : false) || \
0028         (ISLCNPHY(pi) ? VALID_LCN_RADIO(radioid) : false))
0029 
0030 /* basic mux operation - can be optimized on several architectures */
0031 #define MUX(pred, true, false) ((pred) ? (true) : (false))
0032 
0033 /* modulo inc/dec - assumes x E [0, bound - 1] */
0034 #define MODINC(x, bound) MUX((x) == (bound) - 1, 0, (x) + 1)
0035 
0036 /* modulo inc/dec, bound = 2^k */
0037 #define MODDEC_POW2(x, bound) (((x) - 1) & ((bound) - 1))
0038 #define MODINC_POW2(x, bound) (((x) + 1) & ((bound) - 1))
0039 
0040 struct chan_info_basic {
0041     u16 chan;
0042     u16 freq;
0043 };
0044 
0045 static const struct chan_info_basic chan_info_all[] = {
0046     {1, 2412},
0047     {2, 2417},
0048     {3, 2422},
0049     {4, 2427},
0050     {5, 2432},
0051     {6, 2437},
0052     {7, 2442},
0053     {8, 2447},
0054     {9, 2452},
0055     {10, 2457},
0056     {11, 2462},
0057     {12, 2467},
0058     {13, 2472},
0059     {14, 2484},
0060 
0061     {34, 5170},
0062     {38, 5190},
0063     {42, 5210},
0064     {46, 5230},
0065 
0066     {36, 5180},
0067     {40, 5200},
0068     {44, 5220},
0069     {48, 5240},
0070     {52, 5260},
0071     {56, 5280},
0072     {60, 5300},
0073     {64, 5320},
0074 
0075     {100, 5500},
0076     {104, 5520},
0077     {108, 5540},
0078     {112, 5560},
0079     {116, 5580},
0080     {120, 5600},
0081     {124, 5620},
0082     {128, 5640},
0083     {132, 5660},
0084     {136, 5680},
0085     {140, 5700},
0086 
0087     {149, 5745},
0088     {153, 5765},
0089     {157, 5785},
0090     {161, 5805},
0091     {165, 5825},
0092 
0093     {184, 4920},
0094     {188, 4940},
0095     {192, 4960},
0096     {196, 4980},
0097     {200, 5000},
0098     {204, 5020},
0099     {208, 5040},
0100     {212, 5060},
0101     {216, 5080}
0102 };
0103 
0104 static const u8 ofdm_rate_lookup[] = {
0105 
0106     BRCM_RATE_48M,
0107     BRCM_RATE_24M,
0108     BRCM_RATE_12M,
0109     BRCM_RATE_6M,
0110     BRCM_RATE_54M,
0111     BRCM_RATE_36M,
0112     BRCM_RATE_18M,
0113     BRCM_RATE_9M
0114 };
0115 
0116 #define PHY_WREG_LIMIT  24
0117 
0118 void wlc_phyreg_enter(struct brcms_phy_pub *pih)
0119 {
0120     struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
0121     wlapi_bmac_ucode_wake_override_phyreg_set(pi->sh->physhim);
0122 }
0123 
0124 void wlc_phyreg_exit(struct brcms_phy_pub *pih)
0125 {
0126     struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
0127     wlapi_bmac_ucode_wake_override_phyreg_clear(pi->sh->physhim);
0128 }
0129 
0130 void wlc_radioreg_enter(struct brcms_phy_pub *pih)
0131 {
0132     struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
0133     wlapi_bmac_mctrl(pi->sh->physhim, MCTL_LOCK_RADIO, MCTL_LOCK_RADIO);
0134 
0135     udelay(10);
0136 }
0137 
0138 void wlc_radioreg_exit(struct brcms_phy_pub *pih)
0139 {
0140     struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
0141 
0142     (void)bcma_read16(pi->d11core, D11REGOFFS(phyversion));
0143     pi->phy_wreg = 0;
0144     wlapi_bmac_mctrl(pi->sh->physhim, MCTL_LOCK_RADIO, 0);
0145 }
0146 
0147 u16 read_radio_reg(struct brcms_phy *pi, u16 addr)
0148 {
0149     u16 data;
0150 
0151     if (addr == RADIO_IDCODE)
0152         return 0xffff;
0153 
0154     switch (pi->pubpi.phy_type) {
0155     case PHY_TYPE_N:
0156         if (!CONF_HAS(PHYTYPE, PHY_TYPE_N))
0157             break;
0158         if (NREV_GE(pi->pubpi.phy_rev, 7))
0159             addr |= RADIO_2057_READ_OFF;
0160         else
0161             addr |= RADIO_2055_READ_OFF;
0162         break;
0163 
0164     case PHY_TYPE_LCN:
0165         if (!CONF_HAS(PHYTYPE, PHY_TYPE_LCN))
0166             break;
0167         addr |= RADIO_2064_READ_OFF;
0168         break;
0169 
0170     default:
0171         break;
0172     }
0173 
0174     if ((D11REV_GE(pi->sh->corerev, 24)) ||
0175         (D11REV_IS(pi->sh->corerev, 22)
0176          && (pi->pubpi.phy_type != PHY_TYPE_SSN))) {
0177         bcma_wflush16(pi->d11core, D11REGOFFS(radioregaddr), addr);
0178         data = bcma_read16(pi->d11core, D11REGOFFS(radioregdata));
0179     } else {
0180         bcma_wflush16(pi->d11core, D11REGOFFS(phy4waddr), addr);
0181         data = bcma_read16(pi->d11core, D11REGOFFS(phy4wdatalo));
0182     }
0183     pi->phy_wreg = 0;
0184 
0185     return data;
0186 }
0187 
0188 void write_radio_reg(struct brcms_phy *pi, u16 addr, u16 val)
0189 {
0190     if ((D11REV_GE(pi->sh->corerev, 24)) ||
0191         (D11REV_IS(pi->sh->corerev, 22)
0192          && (pi->pubpi.phy_type != PHY_TYPE_SSN))) {
0193 
0194         bcma_wflush16(pi->d11core, D11REGOFFS(radioregaddr), addr);
0195         bcma_write16(pi->d11core, D11REGOFFS(radioregdata), val);
0196     } else {
0197         bcma_wflush16(pi->d11core, D11REGOFFS(phy4waddr), addr);
0198         bcma_write16(pi->d11core, D11REGOFFS(phy4wdatalo), val);
0199     }
0200 
0201     if ((pi->d11core->bus->hosttype == BCMA_HOSTTYPE_PCI) &&
0202         (++pi->phy_wreg >= pi->phy_wreg_limit)) {
0203         (void)bcma_read32(pi->d11core, D11REGOFFS(maccontrol));
0204         pi->phy_wreg = 0;
0205     }
0206 }
0207 
0208 static u32 read_radio_id(struct brcms_phy *pi)
0209 {
0210     u32 id;
0211 
0212     if (D11REV_GE(pi->sh->corerev, 24)) {
0213         u32 b0, b1, b2;
0214 
0215         bcma_wflush16(pi->d11core, D11REGOFFS(radioregaddr), 0);
0216         b0 = (u32) bcma_read16(pi->d11core, D11REGOFFS(radioregdata));
0217         bcma_wflush16(pi->d11core, D11REGOFFS(radioregaddr), 1);
0218         b1 = (u32) bcma_read16(pi->d11core, D11REGOFFS(radioregdata));
0219         bcma_wflush16(pi->d11core, D11REGOFFS(radioregaddr), 2);
0220         b2 = (u32) bcma_read16(pi->d11core, D11REGOFFS(radioregdata));
0221 
0222         id = ((b0 & 0xf) << 28) | (((b2 << 8) | b1) << 12) | ((b0 >> 4)
0223                                       & 0xf);
0224     } else {
0225         bcma_wflush16(pi->d11core, D11REGOFFS(phy4waddr), RADIO_IDCODE);
0226         id = (u32) bcma_read16(pi->d11core, D11REGOFFS(phy4wdatalo));
0227         id |= (u32) bcma_read16(pi->d11core,
0228                     D11REGOFFS(phy4wdatahi)) << 16;
0229     }
0230     pi->phy_wreg = 0;
0231     return id;
0232 }
0233 
0234 void and_radio_reg(struct brcms_phy *pi, u16 addr, u16 val)
0235 {
0236     u16 rval;
0237 
0238     rval = read_radio_reg(pi, addr);
0239     write_radio_reg(pi, addr, (rval & val));
0240 }
0241 
0242 void or_radio_reg(struct brcms_phy *pi, u16 addr, u16 val)
0243 {
0244     u16 rval;
0245 
0246     rval = read_radio_reg(pi, addr);
0247     write_radio_reg(pi, addr, (rval | val));
0248 }
0249 
0250 void xor_radio_reg(struct brcms_phy *pi, u16 addr, u16 mask)
0251 {
0252     u16 rval;
0253 
0254     rval = read_radio_reg(pi, addr);
0255     write_radio_reg(pi, addr, (rval ^ mask));
0256 }
0257 
0258 void mod_radio_reg(struct brcms_phy *pi, u16 addr, u16 mask, u16 val)
0259 {
0260     u16 rval;
0261 
0262     rval = read_radio_reg(pi, addr);
0263     write_radio_reg(pi, addr, (rval & ~mask) | (val & mask));
0264 }
0265 
0266 void write_phy_channel_reg(struct brcms_phy *pi, uint val)
0267 {
0268     bcma_write16(pi->d11core, D11REGOFFS(phychannel), val);
0269 }
0270 
0271 u16 read_phy_reg(struct brcms_phy *pi, u16 addr)
0272 {
0273     bcma_wflush16(pi->d11core, D11REGOFFS(phyregaddr), addr);
0274 
0275     pi->phy_wreg = 0;
0276     return bcma_read16(pi->d11core, D11REGOFFS(phyregdata));
0277 }
0278 
0279 void write_phy_reg(struct brcms_phy *pi, u16 addr, u16 val)
0280 {
0281 #ifdef CONFIG_BCM47XX
0282     bcma_wflush16(pi->d11core, D11REGOFFS(phyregaddr), addr);
0283     bcma_write16(pi->d11core, D11REGOFFS(phyregdata), val);
0284     if (addr == 0x72)
0285         (void)bcma_read16(pi->d11core, D11REGOFFS(phyregdata));
0286 #else
0287     bcma_write32(pi->d11core, D11REGOFFS(phyregaddr), addr | (val << 16));
0288     if ((pi->d11core->bus->hosttype == BCMA_HOSTTYPE_PCI) &&
0289         (++pi->phy_wreg >= pi->phy_wreg_limit)) {
0290         pi->phy_wreg = 0;
0291         (void)bcma_read16(pi->d11core, D11REGOFFS(phyversion));
0292     }
0293 #endif
0294 }
0295 
0296 void and_phy_reg(struct brcms_phy *pi, u16 addr, u16 val)
0297 {
0298     bcma_wflush16(pi->d11core, D11REGOFFS(phyregaddr), addr);
0299     bcma_mask16(pi->d11core, D11REGOFFS(phyregdata), val);
0300     pi->phy_wreg = 0;
0301 }
0302 
0303 void or_phy_reg(struct brcms_phy *pi, u16 addr, u16 val)
0304 {
0305     bcma_wflush16(pi->d11core, D11REGOFFS(phyregaddr), addr);
0306     bcma_set16(pi->d11core, D11REGOFFS(phyregdata), val);
0307     pi->phy_wreg = 0;
0308 }
0309 
0310 void mod_phy_reg(struct brcms_phy *pi, u16 addr, u16 mask, u16 val)
0311 {
0312     val &= mask;
0313     bcma_wflush16(pi->d11core, D11REGOFFS(phyregaddr), addr);
0314     bcma_maskset16(pi->d11core, D11REGOFFS(phyregdata), ~mask, val);
0315     pi->phy_wreg = 0;
0316 }
0317 
0318 static void wlc_set_phy_uninitted(struct brcms_phy *pi)
0319 {
0320     int i, j;
0321 
0322     pi->initialized = false;
0323 
0324     pi->tx_vos = 0xffff;
0325     pi->nrssi_table_delta = 0x7fffffff;
0326     pi->rc_cal = 0xffff;
0327     pi->mintxbias = 0xffff;
0328     pi->txpwridx = -1;
0329     if (ISNPHY(pi)) {
0330         pi->phy_spuravoid = SPURAVOID_DISABLE;
0331 
0332         if (NREV_GE(pi->pubpi.phy_rev, 3)
0333             && NREV_LT(pi->pubpi.phy_rev, 7))
0334             pi->phy_spuravoid = SPURAVOID_AUTO;
0335 
0336         pi->nphy_papd_skip = 0;
0337         pi->nphy_papd_epsilon_offset[0] = 0xf588;
0338         pi->nphy_papd_epsilon_offset[1] = 0xf588;
0339         pi->nphy_txpwr_idx[0] = 128;
0340         pi->nphy_txpwr_idx[1] = 128;
0341         pi->nphy_txpwrindex[0].index_internal = 40;
0342         pi->nphy_txpwrindex[1].index_internal = 40;
0343         pi->phy_pabias = 0;
0344     } else {
0345         pi->phy_spuravoid = SPURAVOID_AUTO;
0346     }
0347     pi->radiopwr = 0xffff;
0348     for (i = 0; i < STATIC_NUM_RF; i++) {
0349         for (j = 0; j < STATIC_NUM_BB; j++)
0350             pi->stats_11b_txpower[i][j] = -1;
0351     }
0352 }
0353 
0354 struct shared_phy *wlc_phy_shared_attach(struct shared_phy_params *shp)
0355 {
0356     struct shared_phy *sh;
0357 
0358     sh = kzalloc(sizeof(struct shared_phy), GFP_ATOMIC);
0359     if (sh == NULL)
0360         return NULL;
0361 
0362     sh->physhim = shp->physhim;
0363     sh->unit = shp->unit;
0364     sh->corerev = shp->corerev;
0365 
0366     sh->vid = shp->vid;
0367     sh->did = shp->did;
0368     sh->chip = shp->chip;
0369     sh->chiprev = shp->chiprev;
0370     sh->chippkg = shp->chippkg;
0371     sh->sromrev = shp->sromrev;
0372     sh->boardtype = shp->boardtype;
0373     sh->boardrev = shp->boardrev;
0374     sh->boardflags = shp->boardflags;
0375     sh->boardflags2 = shp->boardflags2;
0376 
0377     sh->fast_timer = PHY_SW_TIMER_FAST;
0378     sh->slow_timer = PHY_SW_TIMER_SLOW;
0379     sh->glacial_timer = PHY_SW_TIMER_GLACIAL;
0380 
0381     sh->rssi_mode = RSSI_ANT_MERGE_MAX;
0382 
0383     return sh;
0384 }
0385 
0386 static void wlc_phy_timercb_phycal(struct brcms_phy *pi)
0387 {
0388     uint delay = 5;
0389 
0390     if (PHY_PERICAL_MPHASE_PENDING(pi)) {
0391         if (!pi->sh->up) {
0392             wlc_phy_cal_perical_mphase_reset(pi);
0393             return;
0394         }
0395 
0396         if (SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi)) {
0397 
0398             delay = 1000;
0399             wlc_phy_cal_perical_mphase_restart(pi);
0400         } else
0401             wlc_phy_cal_perical_nphy_run(pi, PHY_PERICAL_AUTO);
0402         wlapi_add_timer(pi->phycal_timer, delay, 0);
0403         return;
0404     }
0405 
0406 }
0407 
0408 static u32 wlc_phy_get_radio_ver(struct brcms_phy *pi)
0409 {
0410     u32 ver;
0411 
0412     ver = read_radio_id(pi);
0413 
0414     return ver;
0415 }
0416 
0417 struct brcms_phy_pub *
0418 wlc_phy_attach(struct shared_phy *sh, struct bcma_device *d11core,
0419            int bandtype, struct wiphy *wiphy)
0420 {
0421     struct brcms_phy *pi;
0422     u32 sflags = 0;
0423     uint phyversion;
0424     u32 idcode;
0425     int i;
0426 
0427     if (D11REV_IS(sh->corerev, 4))
0428         sflags = SISF_2G_PHY | SISF_5G_PHY;
0429     else
0430         sflags = bcma_aread32(d11core, BCMA_IOST);
0431 
0432     if (bandtype == BRCM_BAND_5G) {
0433         if ((sflags & (SISF_5G_PHY | SISF_DB_PHY)) == 0)
0434             return NULL;
0435     }
0436 
0437     pi = sh->phy_head;
0438     if ((sflags & SISF_DB_PHY) && pi) {
0439         wlapi_bmac_corereset(pi->sh->physhim, pi->pubpi.coreflags);
0440         pi->refcnt++;
0441         return &pi->pubpi_ro;
0442     }
0443 
0444     pi = kzalloc(sizeof(struct brcms_phy), GFP_ATOMIC);
0445     if (pi == NULL)
0446         return NULL;
0447     pi->wiphy = wiphy;
0448     pi->d11core = d11core;
0449     pi->sh = sh;
0450     pi->phy_init_por = true;
0451     pi->phy_wreg_limit = PHY_WREG_LIMIT;
0452 
0453     pi->txpwr_percent = 100;
0454 
0455     pi->do_initcal = true;
0456 
0457     pi->phycal_tempdelta = 0;
0458 
0459     if (bandtype == BRCM_BAND_2G && (sflags & SISF_2G_PHY))
0460         pi->pubpi.coreflags = SICF_GMODE;
0461 
0462     wlapi_bmac_corereset(pi->sh->physhim, pi->pubpi.coreflags);
0463     phyversion = bcma_read16(pi->d11core, D11REGOFFS(phyversion));
0464 
0465     pi->pubpi.phy_type = PHY_TYPE(phyversion);
0466     pi->pubpi.phy_rev = phyversion & PV_PV_MASK;
0467 
0468     if (pi->pubpi.phy_type == PHY_TYPE_LCNXN) {
0469         pi->pubpi.phy_type = PHY_TYPE_N;
0470         pi->pubpi.phy_rev += LCNXN_BASEREV;
0471     }
0472     pi->pubpi.phy_corenum = PHY_CORE_NUM_2;
0473     pi->pubpi.ana_rev = (phyversion & PV_AV_MASK) >> PV_AV_SHIFT;
0474 
0475     if (pi->pubpi.phy_type != PHY_TYPE_N &&
0476         pi->pubpi.phy_type != PHY_TYPE_LCN)
0477         goto err;
0478 
0479     if (bandtype == BRCM_BAND_5G) {
0480         if (!ISNPHY(pi))
0481             goto err;
0482     } else if (!ISNPHY(pi) && !ISLCNPHY(pi)) {
0483         goto err;
0484     }
0485 
0486     wlc_phy_anacore((struct brcms_phy_pub *) pi, ON);
0487 
0488     idcode = wlc_phy_get_radio_ver(pi);
0489     pi->pubpi.radioid =
0490         (idcode & IDCODE_ID_MASK) >> IDCODE_ID_SHIFT;
0491     pi->pubpi.radiorev =
0492         (idcode & IDCODE_REV_MASK) >> IDCODE_REV_SHIFT;
0493     pi->pubpi.radiover =
0494         (idcode & IDCODE_VER_MASK) >> IDCODE_VER_SHIFT;
0495     if (!VALID_RADIO(pi, pi->pubpi.radioid))
0496         goto err;
0497 
0498     wlc_phy_switch_radio((struct brcms_phy_pub *) pi, OFF);
0499 
0500     wlc_set_phy_uninitted(pi);
0501 
0502     pi->bw = WL_CHANSPEC_BW_20;
0503     pi->radio_chanspec = (bandtype == BRCM_BAND_2G) ?
0504                  ch20mhz_chspec(1) : ch20mhz_chspec(36);
0505 
0506     pi->rxiq_samps = PHY_NOISE_SAMPLE_LOG_NUM_NPHY;
0507     pi->rxiq_antsel = ANT_RX_DIV_DEF;
0508 
0509     pi->watchdog_override = true;
0510 
0511     pi->cal_type_override = PHY_PERICAL_AUTO;
0512 
0513     pi->nphy_saved_noisevars.bufcount = 0;
0514 
0515     if (ISNPHY(pi))
0516         pi->min_txpower = PHY_TXPWR_MIN_NPHY;
0517     else
0518         pi->min_txpower = PHY_TXPWR_MIN;
0519 
0520     pi->sh->phyrxchain = 0x3;
0521 
0522     pi->rx2tx_biasentry = -1;
0523 
0524     pi->phy_txcore_disable_temp = PHY_CHAIN_TX_DISABLE_TEMP;
0525     pi->phy_txcore_enable_temp =
0526         PHY_CHAIN_TX_DISABLE_TEMP - PHY_HYSTERESIS_DELTATEMP;
0527     pi->phy_tempsense_offset = 0;
0528     pi->phy_txcore_heatedup = false;
0529 
0530     pi->nphy_lastcal_temp = -50;
0531 
0532     pi->phynoise_polling = true;
0533     if (ISNPHY(pi) || ISLCNPHY(pi))
0534         pi->phynoise_polling = false;
0535 
0536     for (i = 0; i < TXP_NUM_RATES; i++) {
0537         pi->txpwr_limit[i] = BRCMS_TXPWR_MAX;
0538         pi->txpwr_env_limit[i] = BRCMS_TXPWR_MAX;
0539         pi->tx_user_target[i] = BRCMS_TXPWR_MAX;
0540     }
0541 
0542     pi->radiopwr_override = RADIOPWR_OVERRIDE_DEF;
0543 
0544     pi->user_txpwr_at_rfport = false;
0545 
0546     if (ISNPHY(pi)) {
0547 
0548         pi->phycal_timer = wlapi_init_timer(pi->sh->physhim,
0549                             wlc_phy_timercb_phycal,
0550                             pi, "phycal");
0551         if (!pi->phycal_timer)
0552             goto err;
0553 
0554         if (!wlc_phy_attach_nphy(pi))
0555             goto err;
0556 
0557     } else if (ISLCNPHY(pi)) {
0558         if (!wlc_phy_attach_lcnphy(pi))
0559             goto err;
0560 
0561     }
0562 
0563     pi->refcnt++;
0564     pi->next = pi->sh->phy_head;
0565     sh->phy_head = pi;
0566 
0567     memcpy(&pi->pubpi_ro, &pi->pubpi, sizeof(struct brcms_phy_pub));
0568 
0569     return &pi->pubpi_ro;
0570 
0571 err:
0572     kfree(pi);
0573     return NULL;
0574 }
0575 
0576 void wlc_phy_detach(struct brcms_phy_pub *pih)
0577 {
0578     struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
0579 
0580     if (pih) {
0581         if (--pi->refcnt)
0582             return;
0583 
0584         if (pi->phycal_timer) {
0585             wlapi_free_timer(pi->phycal_timer);
0586             pi->phycal_timer = NULL;
0587         }
0588 
0589         if (pi->sh->phy_head == pi)
0590             pi->sh->phy_head = pi->next;
0591         else if (pi->sh->phy_head->next == pi)
0592             pi->sh->phy_head->next = NULL;
0593 
0594         if (pi->pi_fptr.detach)
0595             (pi->pi_fptr.detach)(pi);
0596 
0597         kfree(pi);
0598     }
0599 }
0600 
0601 bool
0602 wlc_phy_get_phyversion(struct brcms_phy_pub *pih, u16 *phytype, u16 *phyrev,
0603                u16 *radioid, u16 *radiover)
0604 {
0605     struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
0606     *phytype = (u16) pi->pubpi.phy_type;
0607     *phyrev = (u16) pi->pubpi.phy_rev;
0608     *radioid = pi->pubpi.radioid;
0609     *radiover = pi->pubpi.radiorev;
0610 
0611     return true;
0612 }
0613 
0614 bool wlc_phy_get_encore(struct brcms_phy_pub *pih)
0615 {
0616     struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
0617     return pi->pubpi.abgphy_encore;
0618 }
0619 
0620 u32 wlc_phy_get_coreflags(struct brcms_phy_pub *pih)
0621 {
0622     struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
0623     return pi->pubpi.coreflags;
0624 }
0625 
0626 void wlc_phy_anacore(struct brcms_phy_pub *pih, bool on)
0627 {
0628     struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
0629 
0630     if (ISNPHY(pi)) {
0631         if (on) {
0632             if (NREV_GE(pi->pubpi.phy_rev, 3)) {
0633                 write_phy_reg(pi, 0xa6, 0x0d);
0634                 write_phy_reg(pi, 0x8f, 0x0);
0635                 write_phy_reg(pi, 0xa7, 0x0d);
0636                 write_phy_reg(pi, 0xa5, 0x0);
0637             } else {
0638                 write_phy_reg(pi, 0xa5, 0x0);
0639             }
0640         } else {
0641             if (NREV_GE(pi->pubpi.phy_rev, 3)) {
0642                 write_phy_reg(pi, 0x8f, 0x07ff);
0643                 write_phy_reg(pi, 0xa6, 0x0fd);
0644                 write_phy_reg(pi, 0xa5, 0x07ff);
0645                 write_phy_reg(pi, 0xa7, 0x0fd);
0646             } else {
0647                 write_phy_reg(pi, 0xa5, 0x7fff);
0648             }
0649         }
0650     } else if (ISLCNPHY(pi)) {
0651         if (on) {
0652             and_phy_reg(pi, 0x43b,
0653                     ~((0x1 << 0) | (0x1 << 1) | (0x1 << 2)));
0654         } else {
0655             or_phy_reg(pi, 0x43c,
0656                    (0x1 << 0) | (0x1 << 1) | (0x1 << 2));
0657             or_phy_reg(pi, 0x43b,
0658                    (0x1 << 0) | (0x1 << 1) | (0x1 << 2));
0659         }
0660     }
0661 }
0662 
0663 u32 wlc_phy_clk_bwbits(struct brcms_phy_pub *pih)
0664 {
0665     struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
0666 
0667     u32 phy_bw_clkbits = 0;
0668 
0669     if (pi && (ISNPHY(pi) || ISLCNPHY(pi))) {
0670         switch (pi->bw) {
0671         case WL_CHANSPEC_BW_10:
0672             phy_bw_clkbits = SICF_BW10;
0673             break;
0674         case WL_CHANSPEC_BW_20:
0675             phy_bw_clkbits = SICF_BW20;
0676             break;
0677         case WL_CHANSPEC_BW_40:
0678             phy_bw_clkbits = SICF_BW40;
0679             break;
0680         default:
0681             break;
0682         }
0683     }
0684 
0685     return phy_bw_clkbits;
0686 }
0687 
0688 void wlc_phy_por_inform(struct brcms_phy_pub *ppi)
0689 {
0690     struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
0691 
0692     pi->phy_init_por = true;
0693 }
0694 
0695 void wlc_phy_edcrs_lock(struct brcms_phy_pub *pih, bool lock)
0696 {
0697     struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
0698 
0699     pi->edcrs_threshold_lock = lock;
0700 
0701     write_phy_reg(pi, 0x22c, 0x46b);
0702     write_phy_reg(pi, 0x22d, 0x46b);
0703     write_phy_reg(pi, 0x22e, 0x3c0);
0704     write_phy_reg(pi, 0x22f, 0x3c0);
0705 }
0706 
0707 void wlc_phy_initcal_enable(struct brcms_phy_pub *pih, bool initcal)
0708 {
0709     struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
0710 
0711     pi->do_initcal = initcal;
0712 }
0713 
0714 void wlc_phy_hw_clk_state_upd(struct brcms_phy_pub *pih, bool newstate)
0715 {
0716     struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
0717 
0718     if (!pi || !pi->sh)
0719         return;
0720 
0721     pi->sh->clk = newstate;
0722 }
0723 
0724 void wlc_phy_hw_state_upd(struct brcms_phy_pub *pih, bool newstate)
0725 {
0726     struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
0727 
0728     if (!pi || !pi->sh)
0729         return;
0730 
0731     pi->sh->up = newstate;
0732 }
0733 
0734 void wlc_phy_init(struct brcms_phy_pub *pih, u16 chanspec)
0735 {
0736     u32 mc;
0737     void (*phy_init)(struct brcms_phy *) = NULL;
0738     struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
0739 
0740     if (pi->init_in_progress)
0741         return;
0742 
0743     pi->init_in_progress = true;
0744 
0745     pi->radio_chanspec = chanspec;
0746 
0747     mc = bcma_read32(pi->d11core, D11REGOFFS(maccontrol));
0748     if (WARN(mc & MCTL_EN_MAC, "HW error MAC running on init"))
0749         return;
0750 
0751     if (!(pi->measure_hold & PHY_HOLD_FOR_SCAN))
0752         pi->measure_hold |= PHY_HOLD_FOR_NOT_ASSOC;
0753 
0754     if (WARN(!(bcma_aread32(pi->d11core, BCMA_IOST) & SISF_FCLKA),
0755          "HW error SISF_FCLKA\n"))
0756         return;
0757 
0758     phy_init = pi->pi_fptr.init;
0759 
0760     if (phy_init == NULL)
0761         return;
0762 
0763     wlc_phy_anacore(pih, ON);
0764 
0765     if (CHSPEC_BW(pi->radio_chanspec) != pi->bw)
0766         wlapi_bmac_bw_set(pi->sh->physhim,
0767                   CHSPEC_BW(pi->radio_chanspec));
0768 
0769     pi->nphy_gain_boost = true;
0770 
0771     wlc_phy_switch_radio((struct brcms_phy_pub *) pi, ON);
0772 
0773     (*phy_init)(pi);
0774 
0775     pi->phy_init_por = false;
0776 
0777     if (D11REV_IS(pi->sh->corerev, 11) || D11REV_IS(pi->sh->corerev, 12))
0778         wlc_phy_do_dummy_tx(pi, true, OFF);
0779 
0780     if (!(ISNPHY(pi)))
0781         wlc_phy_txpower_update_shm(pi);
0782 
0783     wlc_phy_ant_rxdiv_set((struct brcms_phy_pub *) pi, pi->sh->rx_antdiv);
0784 
0785     pi->init_in_progress = false;
0786 }
0787 
0788 void wlc_phy_cal_init(struct brcms_phy_pub *pih)
0789 {
0790     struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
0791     void (*cal_init)(struct brcms_phy *) = NULL;
0792 
0793     if (WARN((bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) &
0794           MCTL_EN_MAC) != 0, "HW error: MAC enabled during phy cal\n"))
0795         return;
0796 
0797     if (!pi->initialized) {
0798         cal_init = pi->pi_fptr.calinit;
0799         if (cal_init)
0800             (*cal_init)(pi);
0801 
0802         pi->initialized = true;
0803     }
0804 }
0805 
0806 int wlc_phy_down(struct brcms_phy_pub *pih)
0807 {
0808     struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
0809     int callbacks = 0;
0810 
0811     if (pi->phycal_timer
0812         && !wlapi_del_timer(pi->phycal_timer))
0813         callbacks++;
0814 
0815     pi->nphy_iqcal_chanspec_2G = 0;
0816     pi->nphy_iqcal_chanspec_5G = 0;
0817 
0818     return callbacks;
0819 }
0820 
0821 void
0822 wlc_phy_table_addr(struct brcms_phy *pi, uint tbl_id, uint tbl_offset,
0823            u16 tblAddr, u16 tblDataHi, u16 tblDataLo)
0824 {
0825     write_phy_reg(pi, tblAddr, (tbl_id << 10) | tbl_offset);
0826 
0827     pi->tbl_data_hi = tblDataHi;
0828     pi->tbl_data_lo = tblDataLo;
0829 
0830     if (pi->sh->chip == BCMA_CHIP_ID_BCM43224 &&
0831         pi->sh->chiprev == 1) {
0832         pi->tbl_addr = tblAddr;
0833         pi->tbl_save_id = tbl_id;
0834         pi->tbl_save_offset = tbl_offset;
0835     }
0836 }
0837 
0838 void wlc_phy_table_data_write(struct brcms_phy *pi, uint width, u32 val)
0839 {
0840     if ((pi->sh->chip == BCMA_CHIP_ID_BCM43224) &&
0841         (pi->sh->chiprev == 1) &&
0842         (pi->tbl_save_id == NPHY_TBL_ID_ANTSWCTRLLUT)) {
0843         read_phy_reg(pi, pi->tbl_data_lo);
0844 
0845         write_phy_reg(pi, pi->tbl_addr,
0846                   (pi->tbl_save_id << 10) | pi->tbl_save_offset);
0847         pi->tbl_save_offset++;
0848     }
0849 
0850     if (width == 32) {
0851         write_phy_reg(pi, pi->tbl_data_hi, (u16) (val >> 16));
0852         write_phy_reg(pi, pi->tbl_data_lo, (u16) val);
0853     } else {
0854         write_phy_reg(pi, pi->tbl_data_lo, (u16) val);
0855     }
0856 }
0857 
0858 void
0859 wlc_phy_write_table(struct brcms_phy *pi, const struct phytbl_info *ptbl_info,
0860             u16 tblAddr, u16 tblDataHi, u16 tblDataLo)
0861 {
0862     uint idx;
0863     uint tbl_id = ptbl_info->tbl_id;
0864     uint tbl_offset = ptbl_info->tbl_offset;
0865     uint tbl_width = ptbl_info->tbl_width;
0866     const u8 *ptbl_8b = (const u8 *)ptbl_info->tbl_ptr;
0867     const u16 *ptbl_16b = (const u16 *)ptbl_info->tbl_ptr;
0868     const u32 *ptbl_32b = (const u32 *)ptbl_info->tbl_ptr;
0869 
0870     write_phy_reg(pi, tblAddr, (tbl_id << 10) | tbl_offset);
0871 
0872     for (idx = 0; idx < ptbl_info->tbl_len; idx++) {
0873 
0874         if ((pi->sh->chip == BCMA_CHIP_ID_BCM43224) &&
0875             (pi->sh->chiprev == 1) &&
0876             (tbl_id == NPHY_TBL_ID_ANTSWCTRLLUT)) {
0877             read_phy_reg(pi, tblDataLo);
0878 
0879             write_phy_reg(pi, tblAddr,
0880                       (tbl_id << 10) | (tbl_offset + idx));
0881         }
0882 
0883         if (tbl_width == 32) {
0884             write_phy_reg(pi, tblDataHi,
0885                       (u16) (ptbl_32b[idx] >> 16));
0886             write_phy_reg(pi, tblDataLo, (u16) ptbl_32b[idx]);
0887         } else if (tbl_width == 16) {
0888             write_phy_reg(pi, tblDataLo, ptbl_16b[idx]);
0889         } else {
0890             write_phy_reg(pi, tblDataLo, ptbl_8b[idx]);
0891         }
0892     }
0893 }
0894 
0895 void
0896 wlc_phy_read_table(struct brcms_phy *pi, const struct phytbl_info *ptbl_info,
0897            u16 tblAddr, u16 tblDataHi, u16 tblDataLo)
0898 {
0899     uint idx;
0900     uint tbl_id = ptbl_info->tbl_id;
0901     uint tbl_offset = ptbl_info->tbl_offset;
0902     uint tbl_width = ptbl_info->tbl_width;
0903     u8 *ptbl_8b = (u8 *)ptbl_info->tbl_ptr;
0904     u16 *ptbl_16b = (u16 *)ptbl_info->tbl_ptr;
0905     u32 *ptbl_32b = (u32 *)ptbl_info->tbl_ptr;
0906 
0907     write_phy_reg(pi, tblAddr, (tbl_id << 10) | tbl_offset);
0908 
0909     for (idx = 0; idx < ptbl_info->tbl_len; idx++) {
0910 
0911         if ((pi->sh->chip == BCMA_CHIP_ID_BCM43224) &&
0912             (pi->sh->chiprev == 1)) {
0913             (void)read_phy_reg(pi, tblDataLo);
0914 
0915             write_phy_reg(pi, tblAddr,
0916                       (tbl_id << 10) | (tbl_offset + idx));
0917         }
0918 
0919         if (tbl_width == 32) {
0920             ptbl_32b[idx] = read_phy_reg(pi, tblDataLo);
0921             ptbl_32b[idx] |= (read_phy_reg(pi, tblDataHi) << 16);
0922         } else if (tbl_width == 16) {
0923             ptbl_16b[idx] = read_phy_reg(pi, tblDataLo);
0924         } else {
0925             ptbl_8b[idx] = (u8) read_phy_reg(pi, tblDataLo);
0926         }
0927     }
0928 }
0929 
0930 uint
0931 wlc_phy_init_radio_regs_allbands(struct brcms_phy *pi,
0932                  struct radio_20xx_regs *radioregs)
0933 {
0934     uint i = 0;
0935 
0936     do {
0937         if (radioregs[i].do_init)
0938             write_radio_reg(pi, radioregs[i].address,
0939                     (u16) radioregs[i].init);
0940 
0941         i++;
0942     } while (radioregs[i].address != 0xffff);
0943 
0944     return i;
0945 }
0946 
0947 uint
0948 wlc_phy_init_radio_regs(struct brcms_phy *pi,
0949             const struct radio_regs *radioregs,
0950             u16 core_offset)
0951 {
0952     uint i = 0;
0953     uint count = 0;
0954 
0955     do {
0956         if (CHSPEC_IS5G(pi->radio_chanspec)) {
0957             if (radioregs[i].do_init_a) {
0958                 write_radio_reg(pi,
0959                         radioregs[i].
0960                         address | core_offset,
0961                         (u16) radioregs[i].init_a);
0962                 if (ISNPHY(pi) && (++count % 4 == 0))
0963                     BRCMS_PHY_WAR_PR51571(pi);
0964             }
0965         } else {
0966             if (radioregs[i].do_init_g) {
0967                 write_radio_reg(pi,
0968                         radioregs[i].
0969                         address | core_offset,
0970                         (u16) radioregs[i].init_g);
0971                 if (ISNPHY(pi) && (++count % 4 == 0))
0972                     BRCMS_PHY_WAR_PR51571(pi);
0973             }
0974         }
0975 
0976         i++;
0977     } while (radioregs[i].address != 0xffff);
0978 
0979     return i;
0980 }
0981 
0982 void wlc_phy_do_dummy_tx(struct brcms_phy *pi, bool ofdm, bool pa_on)
0983 {
0984 #define DUMMY_PKT_LEN   20
0985     struct bcma_device *core = pi->d11core;
0986     int i, count;
0987     u8 ofdmpkt[DUMMY_PKT_LEN] = {
0988         0xcc, 0x01, 0x02, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00,
0989         0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00
0990     };
0991     u8 cckpkt[DUMMY_PKT_LEN] = {
0992         0x6e, 0x84, 0x0b, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00,
0993         0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00
0994     };
0995     u32 *dummypkt;
0996 
0997     dummypkt = (u32 *) (ofdm ? ofdmpkt : cckpkt);
0998     wlapi_bmac_write_template_ram(pi->sh->physhim, 0, DUMMY_PKT_LEN,
0999                       dummypkt);
1000 
1001     bcma_write16(core, D11REGOFFS(xmtsel), 0);
1002 
1003     if (D11REV_GE(pi->sh->corerev, 11))
1004         bcma_write16(core, D11REGOFFS(wepctl), 0x100);
1005     else
1006         bcma_write16(core, D11REGOFFS(wepctl), 0);
1007 
1008     bcma_write16(core, D11REGOFFS(txe_phyctl),
1009              (ofdm ? 1 : 0) | PHY_TXC_ANT_0);
1010     if (ISNPHY(pi) || ISLCNPHY(pi))
1011         bcma_write16(core, D11REGOFFS(txe_phyctl1), 0x1A02);
1012 
1013     bcma_write16(core, D11REGOFFS(txe_wm_0), 0);
1014     bcma_write16(core, D11REGOFFS(txe_wm_1), 0);
1015 
1016     bcma_write16(core, D11REGOFFS(xmttplatetxptr), 0);
1017     bcma_write16(core, D11REGOFFS(xmttxcnt), DUMMY_PKT_LEN);
1018 
1019     bcma_write16(core, D11REGOFFS(xmtsel),
1020              ((8 << 8) | (1 << 5) | (1 << 2) | 2));
1021 
1022     bcma_write16(core, D11REGOFFS(txe_ctl), 0);
1023 
1024     if (!pa_on) {
1025         if (ISNPHY(pi))
1026             wlc_phy_pa_override_nphy(pi, OFF);
1027     }
1028 
1029     if (ISNPHY(pi) || ISLCNPHY(pi))
1030         bcma_write16(core, D11REGOFFS(txe_aux), 0xD0);
1031     else
1032         bcma_write16(core, D11REGOFFS(txe_aux), ((1 << 5) | (1 << 4)));
1033 
1034     (void)bcma_read16(core, D11REGOFFS(txe_aux));
1035 
1036     i = 0;
1037     count = ofdm ? 30 : 250;
1038     while ((i++ < count)
1039            && (bcma_read16(core, D11REGOFFS(txe_status)) & (1 << 7)))
1040         udelay(10);
1041 
1042     i = 0;
1043 
1044     while ((i++ < 10) &&
1045            ((bcma_read16(core, D11REGOFFS(txe_status)) & (1 << 10)) == 0))
1046         udelay(10);
1047 
1048     i = 0;
1049 
1050     while ((i++ < 10) &&
1051            ((bcma_read16(core, D11REGOFFS(ifsstat)) & (1 << 8))))
1052         udelay(10);
1053 
1054     if (!pa_on) {
1055         if (ISNPHY(pi))
1056             wlc_phy_pa_override_nphy(pi, ON);
1057     }
1058 }
1059 
1060 void wlc_phy_hold_upd(struct brcms_phy_pub *pih, u32 id, bool set)
1061 {
1062     struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
1063 
1064     if (set)
1065         mboolset(pi->measure_hold, id);
1066     else
1067         mboolclr(pi->measure_hold, id);
1068 
1069     return;
1070 }
1071 
1072 void wlc_phy_mute_upd(struct brcms_phy_pub *pih, bool mute, u32 flags)
1073 {
1074     struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
1075 
1076     if (mute)
1077         mboolset(pi->measure_hold, PHY_HOLD_FOR_MUTE);
1078     else
1079         mboolclr(pi->measure_hold, PHY_HOLD_FOR_MUTE);
1080 
1081     if (!mute && (flags & PHY_MUTE_FOR_PREISM))
1082         pi->nphy_perical_last = pi->sh->now - pi->sh->glacial_timer;
1083     return;
1084 }
1085 
1086 void wlc_phy_clear_tssi(struct brcms_phy_pub *pih)
1087 {
1088     struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
1089 
1090     if (ISNPHY(pi)) {
1091         return;
1092     } else {
1093         wlapi_bmac_write_shm(pi->sh->physhim, M_B_TSSI_0, NULL_TSSI_W);
1094         wlapi_bmac_write_shm(pi->sh->physhim, M_B_TSSI_1, NULL_TSSI_W);
1095         wlapi_bmac_write_shm(pi->sh->physhim, M_G_TSSI_0, NULL_TSSI_W);
1096         wlapi_bmac_write_shm(pi->sh->physhim, M_G_TSSI_1, NULL_TSSI_W);
1097     }
1098 }
1099 
1100 static bool wlc_phy_cal_txpower_recalc_sw(struct brcms_phy *pi)
1101 {
1102     return false;
1103 }
1104 
1105 void wlc_phy_switch_radio(struct brcms_phy_pub *pih, bool on)
1106 {
1107     struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
1108     (void)bcma_read32(pi->d11core, D11REGOFFS(maccontrol));
1109 
1110     if (ISNPHY(pi)) {
1111         wlc_phy_switch_radio_nphy(pi, on);
1112     } else if (ISLCNPHY(pi)) {
1113         if (on) {
1114             and_phy_reg(pi, 0x44c,
1115                     ~((0x1 << 8) |
1116                       (0x1 << 9) |
1117                       (0x1 << 10) | (0x1 << 11) | (0x1 << 12)));
1118             and_phy_reg(pi, 0x4b0, ~((0x1 << 3) | (0x1 << 11)));
1119             and_phy_reg(pi, 0x4f9, ~(0x1 << 3));
1120         } else {
1121             and_phy_reg(pi, 0x44d,
1122                     ~((0x1 << 10) |
1123                       (0x1 << 11) |
1124                       (0x1 << 12) | (0x1 << 13) | (0x1 << 14)));
1125             or_phy_reg(pi, 0x44c,
1126                    (0x1 << 8) |
1127                    (0x1 << 9) |
1128                    (0x1 << 10) | (0x1 << 11) | (0x1 << 12));
1129 
1130             and_phy_reg(pi, 0x4b7, ~((0x7f << 8)));
1131             and_phy_reg(pi, 0x4b1, ~((0x1 << 13)));
1132             or_phy_reg(pi, 0x4b0, (0x1 << 3) | (0x1 << 11));
1133             and_phy_reg(pi, 0x4fa, ~((0x1 << 3)));
1134             or_phy_reg(pi, 0x4f9, (0x1 << 3));
1135         }
1136     }
1137 }
1138 
1139 u16 wlc_phy_bw_state_get(struct brcms_phy_pub *ppi)
1140 {
1141     struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
1142 
1143     return pi->bw;
1144 }
1145 
1146 void wlc_phy_bw_state_set(struct brcms_phy_pub *ppi, u16 bw)
1147 {
1148     struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
1149 
1150     pi->bw = bw;
1151 }
1152 
1153 void wlc_phy_chanspec_radio_set(struct brcms_phy_pub *ppi, u16 newch)
1154 {
1155     struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
1156     pi->radio_chanspec = newch;
1157 
1158 }
1159 
1160 u16 wlc_phy_chanspec_get(struct brcms_phy_pub *ppi)
1161 {
1162     struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
1163 
1164     return pi->radio_chanspec;
1165 }
1166 
1167 void wlc_phy_chanspec_set(struct brcms_phy_pub *ppi, u16 chanspec)
1168 {
1169     struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
1170     u16 m_cur_channel;
1171     void (*chanspec_set)(struct brcms_phy *, u16) = NULL;
1172     m_cur_channel = CHSPEC_CHANNEL(chanspec);
1173     if (CHSPEC_IS5G(chanspec))
1174         m_cur_channel |= D11_CURCHANNEL_5G;
1175     if (CHSPEC_IS40(chanspec))
1176         m_cur_channel |= D11_CURCHANNEL_40;
1177     wlapi_bmac_write_shm(pi->sh->physhim, M_CURCHANNEL, m_cur_channel);
1178 
1179     chanspec_set = pi->pi_fptr.chanset;
1180     if (chanspec_set)
1181         (*chanspec_set)(pi, chanspec);
1182 
1183 }
1184 
1185 int wlc_phy_chanspec_freq2bandrange_lpssn(uint freq)
1186 {
1187     int range = -1;
1188 
1189     if (freq < 2500)
1190         range = WL_CHAN_FREQ_RANGE_2G;
1191     else if (freq <= 5320)
1192         range = WL_CHAN_FREQ_RANGE_5GL;
1193     else if (freq <= 5700)
1194         range = WL_CHAN_FREQ_RANGE_5GM;
1195     else
1196         range = WL_CHAN_FREQ_RANGE_5GH;
1197 
1198     return range;
1199 }
1200 
1201 int wlc_phy_chanspec_bandrange_get(struct brcms_phy *pi, u16 chanspec)
1202 {
1203     int range = -1;
1204     uint channel = CHSPEC_CHANNEL(chanspec);
1205     uint freq = wlc_phy_channel2freq(channel);
1206 
1207     if (ISNPHY(pi))
1208         range = wlc_phy_get_chan_freq_range_nphy(pi, channel);
1209     else if (ISLCNPHY(pi))
1210         range = wlc_phy_chanspec_freq2bandrange_lpssn(freq);
1211 
1212     return range;
1213 }
1214 
1215 void wlc_phy_chanspec_ch14_widefilter_set(struct brcms_phy_pub *ppi,
1216                       bool wide_filter)
1217 {
1218     struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
1219 
1220     pi->channel_14_wide_filter = wide_filter;
1221 
1222 }
1223 
1224 int wlc_phy_channel2freq(uint channel)
1225 {
1226     uint i;
1227 
1228     for (i = 0; i < ARRAY_SIZE(chan_info_all); i++)
1229         if (chan_info_all[i].chan == channel)
1230             return chan_info_all[i].freq;
1231     return 0;
1232 }
1233 
1234 void
1235 wlc_phy_chanspec_band_validch(struct brcms_phy_pub *ppi, uint band,
1236                   struct brcms_chanvec *channels)
1237 {
1238     struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
1239     uint i;
1240     uint channel;
1241 
1242     memset(channels, 0, sizeof(struct brcms_chanvec));
1243 
1244     for (i = 0; i < ARRAY_SIZE(chan_info_all); i++) {
1245         channel = chan_info_all[i].chan;
1246 
1247         if ((pi->a_band_high_disable) && (channel >= FIRST_REF5_CHANNUM)
1248             && (channel <= LAST_REF5_CHANNUM))
1249             continue;
1250 
1251         if ((band == BRCM_BAND_2G && channel <= CH_MAX_2G_CHANNEL) ||
1252             (band == BRCM_BAND_5G && channel > CH_MAX_2G_CHANNEL))
1253             setbit(channels->vec, channel);
1254     }
1255 }
1256 
1257 u16 wlc_phy_chanspec_band_firstch(struct brcms_phy_pub *ppi, uint band)
1258 {
1259     struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
1260     uint i;
1261     uint channel;
1262     u16 chspec;
1263 
1264     for (i = 0; i < ARRAY_SIZE(chan_info_all); i++) {
1265         channel = chan_info_all[i].chan;
1266 
1267         if (ISNPHY(pi) && pi->bw == WL_CHANSPEC_BW_40) {
1268             uint j;
1269 
1270             for (j = 0; j < ARRAY_SIZE(chan_info_all); j++) {
1271                 if (chan_info_all[j].chan ==
1272                     channel + CH_10MHZ_APART)
1273                     break;
1274             }
1275 
1276             if (j == ARRAY_SIZE(chan_info_all))
1277                 continue;
1278 
1279             channel = upper_20_sb(channel);
1280             chspec =  channel | WL_CHANSPEC_BW_40 |
1281                   WL_CHANSPEC_CTL_SB_LOWER;
1282             if (band == BRCM_BAND_2G)
1283                 chspec |= WL_CHANSPEC_BAND_2G;
1284             else
1285                 chspec |= WL_CHANSPEC_BAND_5G;
1286         } else
1287             chspec = ch20mhz_chspec(channel);
1288 
1289         if ((pi->a_band_high_disable) && (channel >= FIRST_REF5_CHANNUM)
1290             && (channel <= LAST_REF5_CHANNUM))
1291             continue;
1292 
1293         if ((band == BRCM_BAND_2G && channel <= CH_MAX_2G_CHANNEL) ||
1294             (band == BRCM_BAND_5G && channel > CH_MAX_2G_CHANNEL))
1295             return chspec;
1296     }
1297 
1298     return (u16) INVCHANSPEC;
1299 }
1300 
1301 int wlc_phy_txpower_get(struct brcms_phy_pub *ppi, uint *qdbm, bool *override)
1302 {
1303     struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
1304 
1305     *qdbm = pi->tx_user_target[0];
1306     if (override != NULL)
1307         *override = pi->txpwroverride;
1308     return 0;
1309 }
1310 
1311 void wlc_phy_txpower_target_set(struct brcms_phy_pub *ppi,
1312                 struct txpwr_limits *txpwr)
1313 {
1314     bool mac_enabled = false;
1315     struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
1316 
1317     memcpy(&pi->tx_user_target[TXP_FIRST_CCK],
1318            &txpwr->cck[0], BRCMS_NUM_RATES_CCK);
1319 
1320     memcpy(&pi->tx_user_target[TXP_FIRST_OFDM],
1321            &txpwr->ofdm[0], BRCMS_NUM_RATES_OFDM);
1322     memcpy(&pi->tx_user_target[TXP_FIRST_OFDM_20_CDD],
1323            &txpwr->ofdm_cdd[0], BRCMS_NUM_RATES_OFDM);
1324 
1325     memcpy(&pi->tx_user_target[TXP_FIRST_OFDM_40_SISO],
1326            &txpwr->ofdm_40_siso[0], BRCMS_NUM_RATES_OFDM);
1327     memcpy(&pi->tx_user_target[TXP_FIRST_OFDM_40_CDD],
1328            &txpwr->ofdm_40_cdd[0], BRCMS_NUM_RATES_OFDM);
1329 
1330     memcpy(&pi->tx_user_target[TXP_FIRST_MCS_20_SISO],
1331            &txpwr->mcs_20_siso[0], BRCMS_NUM_RATES_MCS_1_STREAM);
1332     memcpy(&pi->tx_user_target[TXP_FIRST_MCS_20_CDD],
1333            &txpwr->mcs_20_cdd[0], BRCMS_NUM_RATES_MCS_1_STREAM);
1334     memcpy(&pi->tx_user_target[TXP_FIRST_MCS_20_STBC],
1335            &txpwr->mcs_20_stbc[0], BRCMS_NUM_RATES_MCS_1_STREAM);
1336     memcpy(&pi->tx_user_target[TXP_FIRST_MCS_20_SDM],
1337            &txpwr->mcs_20_mimo[0], BRCMS_NUM_RATES_MCS_2_STREAM);
1338 
1339     memcpy(&pi->tx_user_target[TXP_FIRST_MCS_40_SISO],
1340            &txpwr->mcs_40_siso[0], BRCMS_NUM_RATES_MCS_1_STREAM);
1341     memcpy(&pi->tx_user_target[TXP_FIRST_MCS_40_CDD],
1342            &txpwr->mcs_40_cdd[0], BRCMS_NUM_RATES_MCS_1_STREAM);
1343     memcpy(&pi->tx_user_target[TXP_FIRST_MCS_40_STBC],
1344            &txpwr->mcs_40_stbc[0], BRCMS_NUM_RATES_MCS_1_STREAM);
1345     memcpy(&pi->tx_user_target[TXP_FIRST_MCS_40_SDM],
1346            &txpwr->mcs_40_mimo[0], BRCMS_NUM_RATES_MCS_2_STREAM);
1347 
1348     if (bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) & MCTL_EN_MAC)
1349         mac_enabled = true;
1350 
1351     if (mac_enabled)
1352         wlapi_suspend_mac_and_wait(pi->sh->physhim);
1353 
1354     wlc_phy_txpower_recalc_target(pi);
1355     wlc_phy_cal_txpower_recalc_sw(pi);
1356 
1357     if (mac_enabled)
1358         wlapi_enable_mac(pi->sh->physhim);
1359 }
1360 
1361 int wlc_phy_txpower_set(struct brcms_phy_pub *ppi, uint qdbm, bool override)
1362 {
1363     struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
1364     int i;
1365 
1366     if (qdbm > 127)
1367         return -EINVAL;
1368 
1369     for (i = 0; i < TXP_NUM_RATES; i++)
1370         pi->tx_user_target[i] = (u8) qdbm;
1371 
1372     pi->txpwroverride = false;
1373 
1374     if (pi->sh->up) {
1375         if (!SCAN_INPROG_PHY(pi)) {
1376             bool suspend;
1377 
1378             suspend = (0 == (bcma_read32(pi->d11core,
1379                              D11REGOFFS(maccontrol)) &
1380                      MCTL_EN_MAC));
1381 
1382             if (!suspend)
1383                 wlapi_suspend_mac_and_wait(pi->sh->physhim);
1384 
1385             wlc_phy_txpower_recalc_target(pi);
1386             wlc_phy_cal_txpower_recalc_sw(pi);
1387 
1388             if (!suspend)
1389                 wlapi_enable_mac(pi->sh->physhim);
1390         }
1391     }
1392     return 0;
1393 }
1394 
1395 void
1396 wlc_phy_txpower_sromlimit(struct brcms_phy_pub *ppi, uint channel, u8 *min_pwr,
1397               u8 *max_pwr, int txp_rate_idx)
1398 {
1399     struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
1400     uint i;
1401 
1402     *min_pwr = pi->min_txpower * BRCMS_TXPWR_DB_FACTOR;
1403 
1404     if (ISNPHY(pi)) {
1405         if (txp_rate_idx < 0)
1406             txp_rate_idx = TXP_FIRST_CCK;
1407         wlc_phy_txpower_sromlimit_get_nphy(pi, channel, max_pwr,
1408                            (u8) txp_rate_idx);
1409 
1410     } else if ((channel <= CH_MAX_2G_CHANNEL)) {
1411         if (txp_rate_idx < 0)
1412             txp_rate_idx = TXP_FIRST_CCK;
1413         *max_pwr = pi->tx_srom_max_rate_2g[txp_rate_idx];
1414     } else {
1415 
1416         *max_pwr = BRCMS_TXPWR_MAX;
1417 
1418         if (txp_rate_idx < 0)
1419             txp_rate_idx = TXP_FIRST_OFDM;
1420 
1421         for (i = 0; i < ARRAY_SIZE(chan_info_all); i++) {
1422             if (channel == chan_info_all[i].chan)
1423                 break;
1424         }
1425 
1426         if (pi->hwtxpwr) {
1427             *max_pwr = pi->hwtxpwr[i];
1428         } else {
1429 
1430             if ((i >= FIRST_MID_5G_CHAN) && (i <= LAST_MID_5G_CHAN))
1431                 *max_pwr =
1432                     pi->tx_srom_max_rate_5g_mid[txp_rate_idx];
1433             if ((i >= FIRST_HIGH_5G_CHAN)
1434                 && (i <= LAST_HIGH_5G_CHAN))
1435                 *max_pwr =
1436                     pi->tx_srom_max_rate_5g_hi[txp_rate_idx];
1437             if ((i >= FIRST_LOW_5G_CHAN) && (i <= LAST_LOW_5G_CHAN))
1438                 *max_pwr =
1439                     pi->tx_srom_max_rate_5g_low[txp_rate_idx];
1440         }
1441     }
1442 }
1443 
1444 void
1445 wlc_phy_txpower_sromlimit_max_get(struct brcms_phy_pub *ppi, uint chan,
1446                   u8 *max_txpwr, u8 *min_txpwr)
1447 {
1448     struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
1449     u8 tx_pwr_max = 0;
1450     u8 tx_pwr_min = 255;
1451     u8 max_num_rate;
1452     u8 maxtxpwr, mintxpwr, rate, pactrl;
1453 
1454     pactrl = 0;
1455 
1456     max_num_rate = ISNPHY(pi) ? TXP_NUM_RATES :
1457                ISLCNPHY(pi) ? (TXP_LAST_SISO_MCS_20 +
1458                        1) : (TXP_LAST_OFDM + 1);
1459 
1460     for (rate = 0; rate < max_num_rate; rate++) {
1461 
1462         wlc_phy_txpower_sromlimit(ppi, chan, &mintxpwr, &maxtxpwr,
1463                       rate);
1464 
1465         maxtxpwr = (maxtxpwr > pactrl) ? (maxtxpwr - pactrl) : 0;
1466 
1467         maxtxpwr = (maxtxpwr > 6) ? (maxtxpwr - 6) : 0;
1468 
1469         tx_pwr_max = max(tx_pwr_max, maxtxpwr);
1470         tx_pwr_min = min(tx_pwr_min, maxtxpwr);
1471     }
1472     *max_txpwr = tx_pwr_max;
1473     *min_txpwr = tx_pwr_min;
1474 }
1475 
1476 void
1477 wlc_phy_txpower_boardlimit_band(struct brcms_phy_pub *ppi, uint bandunit,
1478                 s32 *max_pwr, s32 *min_pwr, u32 *step_pwr)
1479 {
1480     return;
1481 }
1482 
1483 u8 wlc_phy_txpower_get_target_min(struct brcms_phy_pub *ppi)
1484 {
1485     struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
1486 
1487     return pi->tx_power_min;
1488 }
1489 
1490 u8 wlc_phy_txpower_get_target_max(struct brcms_phy_pub *ppi)
1491 {
1492     struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
1493 
1494     return pi->tx_power_max;
1495 }
1496 
1497 static s8 wlc_phy_env_measure_vbat(struct brcms_phy *pi)
1498 {
1499     if (ISLCNPHY(pi))
1500         return wlc_lcnphy_vbatsense(pi, 0);
1501     else
1502         return 0;
1503 }
1504 
1505 static s8 wlc_phy_env_measure_temperature(struct brcms_phy *pi)
1506 {
1507     if (ISLCNPHY(pi))
1508         return wlc_lcnphy_tempsense_degree(pi, 0);
1509     else
1510         return 0;
1511 }
1512 
1513 static void wlc_phy_upd_env_txpwr_rate_limits(struct brcms_phy *pi, u32 band)
1514 {
1515     u8 i;
1516 
1517     for (i = 0; i < TXP_NUM_RATES; i++)
1518         pi->txpwr_env_limit[i] = BRCMS_TXPWR_MAX;
1519 
1520     wlc_phy_env_measure_vbat(pi);
1521     wlc_phy_env_measure_temperature(pi);
1522 }
1523 
1524 static s8
1525 wlc_user_txpwr_antport_to_rfport(struct brcms_phy *pi, uint chan, u32 band,
1526                  u8 rate)
1527 {
1528     return 0;
1529 }
1530 
1531 void wlc_phy_txpower_recalc_target(struct brcms_phy *pi)
1532 {
1533     u8 maxtxpwr, mintxpwr, rate, pactrl;
1534     uint target_chan;
1535     u8 tx_pwr_target[TXP_NUM_RATES];
1536     u8 tx_pwr_max = 0;
1537     u8 tx_pwr_min = 255;
1538     u8 tx_pwr_max_rate_ind = 0;
1539     u8 max_num_rate;
1540     u8 start_rate = 0;
1541     u16 chspec;
1542     u32 band = CHSPEC2BAND(pi->radio_chanspec);
1543     void (*txpwr_recalc_fn)(struct brcms_phy *) = NULL;
1544 
1545     chspec = pi->radio_chanspec;
1546     if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_NONE)
1547         target_chan = CHSPEC_CHANNEL(chspec);
1548     else if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_UPPER)
1549         target_chan = upper_20_sb(CHSPEC_CHANNEL(chspec));
1550     else
1551         target_chan = lower_20_sb(CHSPEC_CHANNEL(chspec));
1552 
1553     pactrl = 0;
1554     if (ISLCNPHY(pi)) {
1555         u32 offset_mcs, i;
1556 
1557         if (CHSPEC_IS40(pi->radio_chanspec)) {
1558             offset_mcs = pi->mcs40_po;
1559             for (i = TXP_FIRST_SISO_MCS_20;
1560                  i <= TXP_LAST_SISO_MCS_20; i++) {
1561                 pi->tx_srom_max_rate_2g[i - 8] =
1562                     pi->tx_srom_max_2g -
1563                     ((offset_mcs & 0xf) * 2);
1564                 offset_mcs >>= 4;
1565             }
1566         } else {
1567             offset_mcs = pi->mcs20_po;
1568             for (i = TXP_FIRST_SISO_MCS_20;
1569                  i <= TXP_LAST_SISO_MCS_20; i++) {
1570                 pi->tx_srom_max_rate_2g[i - 8] =
1571                     pi->tx_srom_max_2g -
1572                     ((offset_mcs & 0xf) * 2);
1573                 offset_mcs >>= 4;
1574             }
1575         }
1576     }
1577 
1578     max_num_rate = ((ISNPHY(pi)) ? (TXP_NUM_RATES) :
1579             ((ISLCNPHY(pi)) ?
1580              (TXP_LAST_SISO_MCS_20 + 1) : (TXP_LAST_OFDM + 1)));
1581 
1582     wlc_phy_upd_env_txpwr_rate_limits(pi, band);
1583 
1584     for (rate = start_rate; rate < max_num_rate; rate++) {
1585 
1586         tx_pwr_target[rate] = pi->tx_user_target[rate];
1587 
1588         if (pi->user_txpwr_at_rfport)
1589             tx_pwr_target[rate] +=
1590                 wlc_user_txpwr_antport_to_rfport(pi,
1591                                  target_chan,
1592                                  band,
1593                                  rate);
1594 
1595         wlc_phy_txpower_sromlimit((struct brcms_phy_pub *) pi,
1596                       target_chan,
1597                       &mintxpwr, &maxtxpwr, rate);
1598 
1599         maxtxpwr = min(maxtxpwr, pi->txpwr_limit[rate]);
1600 
1601         maxtxpwr = (maxtxpwr > pactrl) ? (maxtxpwr - pactrl) : 0;
1602 
1603         maxtxpwr = (maxtxpwr > 6) ? (maxtxpwr - 6) : 0;
1604 
1605         maxtxpwr = min(maxtxpwr, tx_pwr_target[rate]);
1606 
1607         if (pi->txpwr_percent <= 100)
1608             maxtxpwr = (maxtxpwr * pi->txpwr_percent) / 100;
1609 
1610         tx_pwr_target[rate] = max(maxtxpwr, mintxpwr);
1611 
1612         tx_pwr_target[rate] =
1613             min(tx_pwr_target[rate], pi->txpwr_env_limit[rate]);
1614 
1615         if (tx_pwr_target[rate] > tx_pwr_max)
1616             tx_pwr_max_rate_ind = rate;
1617 
1618         tx_pwr_max = max(tx_pwr_max, tx_pwr_target[rate]);
1619         tx_pwr_min = min(tx_pwr_min, tx_pwr_target[rate]);
1620     }
1621 
1622     memset(pi->tx_power_offset, 0, sizeof(pi->tx_power_offset));
1623     pi->tx_power_max = tx_pwr_max;
1624     pi->tx_power_min = tx_pwr_min;
1625     pi->tx_power_max_rate_ind = tx_pwr_max_rate_ind;
1626     for (rate = 0; rate < max_num_rate; rate++) {
1627 
1628         pi->tx_power_target[rate] = tx_pwr_target[rate];
1629 
1630         if (!pi->hwpwrctrl || ISNPHY(pi))
1631             pi->tx_power_offset[rate] =
1632                 pi->tx_power_max - pi->tx_power_target[rate];
1633         else
1634             pi->tx_power_offset[rate] =
1635                 pi->tx_power_target[rate] - pi->tx_power_min;
1636     }
1637 
1638     txpwr_recalc_fn = pi->pi_fptr.txpwrrecalc;
1639     if (txpwr_recalc_fn)
1640         (*txpwr_recalc_fn)(pi);
1641 }
1642 
1643 static void
1644 wlc_phy_txpower_reg_limit_calc(struct brcms_phy *pi, struct txpwr_limits *txpwr,
1645                    u16 chanspec)
1646 {
1647     u8 tmp_txpwr_limit[2 * BRCMS_NUM_RATES_OFDM];
1648     u8 *txpwr_ptr1 = NULL, *txpwr_ptr2 = NULL;
1649     int rate_start_index = 0, rate1, rate2, k;
1650 
1651     for (rate1 = WL_TX_POWER_CCK_FIRST, rate2 = 0;
1652          rate2 < WL_TX_POWER_CCK_NUM; rate1++, rate2++)
1653         pi->txpwr_limit[rate1] = txpwr->cck[rate2];
1654 
1655     for (rate1 = WL_TX_POWER_OFDM_FIRST, rate2 = 0;
1656          rate2 < WL_TX_POWER_OFDM_NUM; rate1++, rate2++)
1657         pi->txpwr_limit[rate1] = txpwr->ofdm[rate2];
1658 
1659     if (ISNPHY(pi)) {
1660 
1661         for (k = 0; k < 4; k++) {
1662             switch (k) {
1663             case 0:
1664 
1665                 txpwr_ptr1 = txpwr->mcs_20_siso;
1666                 txpwr_ptr2 = txpwr->ofdm;
1667                 rate_start_index = WL_TX_POWER_OFDM_FIRST;
1668                 break;
1669             case 1:
1670 
1671                 txpwr_ptr1 = txpwr->mcs_20_cdd;
1672                 txpwr_ptr2 = txpwr->ofdm_cdd;
1673                 rate_start_index = WL_TX_POWER_OFDM20_CDD_FIRST;
1674                 break;
1675             case 2:
1676 
1677                 txpwr_ptr1 = txpwr->mcs_40_siso;
1678                 txpwr_ptr2 = txpwr->ofdm_40_siso;
1679                 rate_start_index =
1680                     WL_TX_POWER_OFDM40_SISO_FIRST;
1681                 break;
1682             case 3:
1683 
1684                 txpwr_ptr1 = txpwr->mcs_40_cdd;
1685                 txpwr_ptr2 = txpwr->ofdm_40_cdd;
1686                 rate_start_index = WL_TX_POWER_OFDM40_CDD_FIRST;
1687                 break;
1688             }
1689 
1690             for (rate2 = 0; rate2 < BRCMS_NUM_RATES_OFDM;
1691                  rate2++) {
1692                 tmp_txpwr_limit[rate2] = 0;
1693                 tmp_txpwr_limit[BRCMS_NUM_RATES_OFDM + rate2] =
1694                     txpwr_ptr1[rate2];
1695             }
1696             wlc_phy_mcs_to_ofdm_powers_nphy(
1697                 tmp_txpwr_limit, 0,
1698                 BRCMS_NUM_RATES_OFDM -
1699                 1, BRCMS_NUM_RATES_OFDM);
1700             for (rate1 = rate_start_index, rate2 = 0;
1701                  rate2 < BRCMS_NUM_RATES_OFDM; rate1++, rate2++)
1702                 pi->txpwr_limit[rate1] =
1703                     min(txpwr_ptr2[rate2],
1704                         tmp_txpwr_limit[rate2]);
1705         }
1706 
1707         for (k = 0; k < 4; k++) {
1708             switch (k) {
1709             case 0:
1710 
1711                 txpwr_ptr1 = txpwr->ofdm;
1712                 txpwr_ptr2 = txpwr->mcs_20_siso;
1713                 rate_start_index = WL_TX_POWER_MCS20_SISO_FIRST;
1714                 break;
1715             case 1:
1716 
1717                 txpwr_ptr1 = txpwr->ofdm_cdd;
1718                 txpwr_ptr2 = txpwr->mcs_20_cdd;
1719                 rate_start_index = WL_TX_POWER_MCS20_CDD_FIRST;
1720                 break;
1721             case 2:
1722 
1723                 txpwr_ptr1 = txpwr->ofdm_40_siso;
1724                 txpwr_ptr2 = txpwr->mcs_40_siso;
1725                 rate_start_index = WL_TX_POWER_MCS40_SISO_FIRST;
1726                 break;
1727             case 3:
1728 
1729                 txpwr_ptr1 = txpwr->ofdm_40_cdd;
1730                 txpwr_ptr2 = txpwr->mcs_40_cdd;
1731                 rate_start_index = WL_TX_POWER_MCS40_CDD_FIRST;
1732                 break;
1733             }
1734             for (rate2 = 0; rate2 < BRCMS_NUM_RATES_OFDM;
1735                  rate2++) {
1736                 tmp_txpwr_limit[rate2] = 0;
1737                 tmp_txpwr_limit[BRCMS_NUM_RATES_OFDM + rate2] =
1738                     txpwr_ptr1[rate2];
1739             }
1740             wlc_phy_ofdm_to_mcs_powers_nphy(
1741                 tmp_txpwr_limit, 0,
1742                 BRCMS_NUM_RATES_OFDM -
1743                 1, BRCMS_NUM_RATES_OFDM);
1744             for (rate1 = rate_start_index, rate2 = 0;
1745                  rate2 < BRCMS_NUM_RATES_MCS_1_STREAM;
1746                  rate1++, rate2++)
1747                 pi->txpwr_limit[rate1] =
1748                     min(txpwr_ptr2[rate2],
1749                         tmp_txpwr_limit[rate2]);
1750         }
1751 
1752         for (k = 0; k < 2; k++) {
1753             switch (k) {
1754             case 0:
1755 
1756                 rate_start_index = WL_TX_POWER_MCS20_STBC_FIRST;
1757                 txpwr_ptr1 = txpwr->mcs_20_stbc;
1758                 break;
1759             case 1:
1760 
1761                 rate_start_index = WL_TX_POWER_MCS40_STBC_FIRST;
1762                 txpwr_ptr1 = txpwr->mcs_40_stbc;
1763                 break;
1764             }
1765             for (rate1 = rate_start_index, rate2 = 0;
1766                  rate2 < BRCMS_NUM_RATES_MCS_1_STREAM;
1767                  rate1++, rate2++)
1768                 pi->txpwr_limit[rate1] = txpwr_ptr1[rate2];
1769         }
1770 
1771         for (k = 0; k < 2; k++) {
1772             switch (k) {
1773             case 0:
1774 
1775                 rate_start_index = WL_TX_POWER_MCS20_SDM_FIRST;
1776                 txpwr_ptr1 = txpwr->mcs_20_mimo;
1777                 break;
1778             case 1:
1779 
1780                 rate_start_index = WL_TX_POWER_MCS40_SDM_FIRST;
1781                 txpwr_ptr1 = txpwr->mcs_40_mimo;
1782                 break;
1783             }
1784             for (rate1 = rate_start_index, rate2 = 0;
1785                  rate2 < BRCMS_NUM_RATES_MCS_2_STREAM;
1786                  rate1++, rate2++)
1787                 pi->txpwr_limit[rate1] = txpwr_ptr1[rate2];
1788         }
1789 
1790         pi->txpwr_limit[WL_TX_POWER_MCS_32] = txpwr->mcs32;
1791 
1792         pi->txpwr_limit[WL_TX_POWER_MCS40_CDD_FIRST] =
1793             min(pi->txpwr_limit[WL_TX_POWER_MCS40_CDD_FIRST],
1794                 pi->txpwr_limit[WL_TX_POWER_MCS_32]);
1795         pi->txpwr_limit[WL_TX_POWER_MCS_32] =
1796             pi->txpwr_limit[WL_TX_POWER_MCS40_CDD_FIRST];
1797     }
1798 }
1799 
1800 void wlc_phy_txpwr_percent_set(struct brcms_phy_pub *ppi, u8 txpwr_percent)
1801 {
1802     struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
1803 
1804     pi->txpwr_percent = txpwr_percent;
1805 }
1806 
1807 void wlc_phy_machwcap_set(struct brcms_phy_pub *ppi, u32 machwcap)
1808 {
1809     struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
1810 
1811     pi->sh->machwcap = machwcap;
1812 }
1813 
1814 void wlc_phy_runbist_config(struct brcms_phy_pub *ppi, bool start_end)
1815 {
1816     struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
1817     u16 rxc;
1818     rxc = 0;
1819 
1820     if (start_end == ON) {
1821         if (!ISNPHY(pi))
1822             return;
1823 
1824         if (NREV_IS(pi->pubpi.phy_rev, 3)
1825             || NREV_IS(pi->pubpi.phy_rev, 4)) {
1826             bcma_wflush16(pi->d11core, D11REGOFFS(phyregaddr),
1827                       0xa0);
1828             bcma_set16(pi->d11core, D11REGOFFS(phyregdata),
1829                    0x1 << 15);
1830         }
1831     } else {
1832         if (NREV_IS(pi->pubpi.phy_rev, 3)
1833             || NREV_IS(pi->pubpi.phy_rev, 4)) {
1834             bcma_wflush16(pi->d11core, D11REGOFFS(phyregaddr),
1835                       0xa0);
1836             bcma_write16(pi->d11core, D11REGOFFS(phyregdata), rxc);
1837         }
1838 
1839         wlc_phy_por_inform(ppi);
1840     }
1841 }
1842 
1843 void
1844 wlc_phy_txpower_limit_set(struct brcms_phy_pub *ppi, struct txpwr_limits *txpwr,
1845               u16 chanspec)
1846 {
1847     struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
1848 
1849     wlc_phy_txpower_reg_limit_calc(pi, txpwr, chanspec);
1850 
1851     if (ISLCNPHY(pi)) {
1852         int i, j;
1853         for (i = TXP_FIRST_OFDM_20_CDD, j = 0;
1854              j < BRCMS_NUM_RATES_MCS_1_STREAM; i++, j++) {
1855             if (txpwr->mcs_20_siso[j])
1856                 pi->txpwr_limit[i] = txpwr->mcs_20_siso[j];
1857             else
1858                 pi->txpwr_limit[i] = txpwr->ofdm[j];
1859         }
1860     }
1861 
1862     wlapi_suspend_mac_and_wait(pi->sh->physhim);
1863 
1864     wlc_phy_txpower_recalc_target(pi);
1865     wlc_phy_cal_txpower_recalc_sw(pi);
1866     wlapi_enable_mac(pi->sh->physhim);
1867 }
1868 
1869 void wlc_phy_ofdm_rateset_war(struct brcms_phy_pub *pih, bool war)
1870 {
1871     struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
1872 
1873     pi->ofdm_rateset_war = war;
1874 }
1875 
1876 void wlc_phy_bf_preempt_enable(struct brcms_phy_pub *pih, bool bf_preempt)
1877 {
1878     struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
1879 
1880     pi->bf_preempt_4306 = bf_preempt;
1881 }
1882 
1883 void wlc_phy_txpower_update_shm(struct brcms_phy *pi)
1884 {
1885     int j;
1886     if (ISNPHY(pi))
1887         return;
1888 
1889     if (!pi->sh->clk)
1890         return;
1891 
1892     if (pi->hwpwrctrl) {
1893         u16 offset;
1894 
1895         wlapi_bmac_write_shm(pi->sh->physhim, M_TXPWR_MAX, 63);
1896         wlapi_bmac_write_shm(pi->sh->physhim, M_TXPWR_N,
1897                      1 << NUM_TSSI_FRAMES);
1898 
1899         wlapi_bmac_write_shm(pi->sh->physhim, M_TXPWR_TARGET,
1900                      pi->tx_power_min << NUM_TSSI_FRAMES);
1901 
1902         wlapi_bmac_write_shm(pi->sh->physhim, M_TXPWR_CUR,
1903                      pi->hwpwr_txcur);
1904 
1905         for (j = TXP_FIRST_OFDM; j <= TXP_LAST_OFDM; j++) {
1906             static const u8 ucode_ofdm_rates[] = {
1907                 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c
1908             };
1909             offset = wlapi_bmac_rate_shm_offset(
1910                 pi->sh->physhim,
1911                 ucode_ofdm_rates[j - TXP_FIRST_OFDM]);
1912             wlapi_bmac_write_shm(pi->sh->physhim, offset + 6,
1913                          pi->tx_power_offset[j]);
1914             wlapi_bmac_write_shm(pi->sh->physhim, offset + 14,
1915                          -(pi->tx_power_offset[j] / 2));
1916         }
1917 
1918         wlapi_bmac_mhf(pi->sh->physhim, MHF2, MHF2_HWPWRCTL,
1919                    MHF2_HWPWRCTL, BRCM_BAND_ALL);
1920     } else {
1921         int i;
1922 
1923         for (i = TXP_FIRST_OFDM; i <= TXP_LAST_OFDM; i++)
1924             pi->tx_power_offset[i] =
1925                 (u8) roundup(pi->tx_power_offset[i], 8);
1926         wlapi_bmac_write_shm(pi->sh->physhim, M_OFDM_OFFSET,
1927                      (u16)
1928                      ((pi->tx_power_offset[TXP_FIRST_OFDM]
1929                        + 7) >> 3));
1930     }
1931 }
1932 
1933 bool wlc_phy_txpower_hw_ctrl_get(struct brcms_phy_pub *ppi)
1934 {
1935     struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
1936 
1937     if (ISNPHY(pi))
1938         return pi->nphy_txpwrctrl;
1939     else
1940         return pi->hwpwrctrl;
1941 }
1942 
1943 void wlc_phy_txpower_hw_ctrl_set(struct brcms_phy_pub *ppi, bool hwpwrctrl)
1944 {
1945     struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
1946     bool suspend;
1947 
1948     if (!pi->hwpwrctrl_capable)
1949         return;
1950 
1951     pi->hwpwrctrl = hwpwrctrl;
1952     pi->nphy_txpwrctrl = hwpwrctrl;
1953     pi->txpwrctrl = hwpwrctrl;
1954 
1955     if (ISNPHY(pi)) {
1956         suspend = (0 == (bcma_read32(pi->d11core,
1957                          D11REGOFFS(maccontrol)) &
1958                  MCTL_EN_MAC));
1959         if (!suspend)
1960             wlapi_suspend_mac_and_wait(pi->sh->physhim);
1961 
1962         wlc_phy_txpwrctrl_enable_nphy(pi, pi->nphy_txpwrctrl);
1963         if (pi->nphy_txpwrctrl == PHY_TPC_HW_OFF)
1964             wlc_phy_txpwr_fixpower_nphy(pi);
1965         else
1966             mod_phy_reg(pi, 0x1e7, (0x7f << 0),
1967                     pi->saved_txpwr_idx);
1968 
1969         if (!suspend)
1970             wlapi_enable_mac(pi->sh->physhim);
1971     }
1972 }
1973 
1974 void wlc_phy_txpower_ipa_upd(struct brcms_phy *pi)
1975 {
1976 
1977     if (NREV_GE(pi->pubpi.phy_rev, 3)) {
1978         pi->ipa2g_on = (pi->srom_fem2g.extpagain == 2);
1979         pi->ipa5g_on = (pi->srom_fem5g.extpagain == 2);
1980     } else {
1981         pi->ipa2g_on = false;
1982         pi->ipa5g_on = false;
1983     }
1984 }
1985 
1986 static u32 wlc_phy_txpower_est_power_nphy(struct brcms_phy *pi)
1987 {
1988     s16 tx0_status, tx1_status;
1989     u16 estPower1, estPower2;
1990     u8 pwr0, pwr1, adj_pwr0, adj_pwr1;
1991     u32 est_pwr;
1992 
1993     estPower1 = read_phy_reg(pi, 0x118);
1994     estPower2 = read_phy_reg(pi, 0x119);
1995 
1996     if ((estPower1 & (0x1 << 8)) == (0x1 << 8))
1997         pwr0 = (u8) (estPower1 & (0xff << 0)) >> 0;
1998     else
1999         pwr0 = 0x80;
2000 
2001     if ((estPower2 & (0x1 << 8)) == (0x1 << 8))
2002         pwr1 = (u8) (estPower2 & (0xff << 0)) >> 0;
2003     else
2004         pwr1 = 0x80;
2005 
2006     tx0_status = read_phy_reg(pi, 0x1ed);
2007     tx1_status = read_phy_reg(pi, 0x1ee);
2008 
2009     if ((tx0_status & (0x1 << 15)) == (0x1 << 15))
2010         adj_pwr0 = (u8) (tx0_status & (0xff << 0)) >> 0;
2011     else
2012         adj_pwr0 = 0x80;
2013     if ((tx1_status & (0x1 << 15)) == (0x1 << 15))
2014         adj_pwr1 = (u8) (tx1_status & (0xff << 0)) >> 0;
2015     else
2016         adj_pwr1 = 0x80;
2017 
2018     est_pwr = (u32) ((pwr0 << 24) | (pwr1 << 16) | (adj_pwr0 << 8) |
2019              adj_pwr1);
2020 
2021     return est_pwr;
2022 }
2023 
2024 void
2025 wlc_phy_txpower_get_current(struct brcms_phy_pub *ppi, struct tx_power *power,
2026                 uint channel)
2027 {
2028     struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
2029     uint rate, num_rates;
2030     u8 min_pwr, max_pwr;
2031 
2032 #if WL_TX_POWER_RATES != TXP_NUM_RATES
2033 #error "struct tx_power out of sync with this fn"
2034 #endif
2035 
2036     if (ISNPHY(pi)) {
2037         power->rf_cores = 2;
2038         power->flags |= (WL_TX_POWER_F_MIMO);
2039         if (pi->nphy_txpwrctrl == PHY_TPC_HW_ON)
2040             power->flags |=
2041                 (WL_TX_POWER_F_ENABLED | WL_TX_POWER_F_HW);
2042     } else if (ISLCNPHY(pi)) {
2043         power->rf_cores = 1;
2044         power->flags |= (WL_TX_POWER_F_SISO);
2045         if (pi->radiopwr_override == RADIOPWR_OVERRIDE_DEF)
2046             power->flags |= WL_TX_POWER_F_ENABLED;
2047         if (pi->hwpwrctrl)
2048             power->flags |= WL_TX_POWER_F_HW;
2049     }
2050 
2051     num_rates = ((ISNPHY(pi)) ? (TXP_NUM_RATES) :
2052              ((ISLCNPHY(pi)) ?
2053               (TXP_LAST_OFDM_20_CDD + 1) : (TXP_LAST_OFDM + 1)));
2054 
2055     for (rate = 0; rate < num_rates; rate++) {
2056         power->user_limit[rate] = pi->tx_user_target[rate];
2057         wlc_phy_txpower_sromlimit(ppi, channel, &min_pwr, &max_pwr,
2058                       rate);
2059         power->board_limit[rate] = (u8) max_pwr;
2060         power->target[rate] = pi->tx_power_target[rate];
2061     }
2062 
2063     if (ISNPHY(pi)) {
2064         u32 est_pout;
2065 
2066         wlapi_suspend_mac_and_wait(pi->sh->physhim);
2067         wlc_phyreg_enter((struct brcms_phy_pub *) pi);
2068         est_pout = wlc_phy_txpower_est_power_nphy(pi);
2069         wlc_phyreg_exit((struct brcms_phy_pub *) pi);
2070         wlapi_enable_mac(pi->sh->physhim);
2071 
2072         power->est_Pout[0] = (est_pout >> 8) & 0xff;
2073         power->est_Pout[1] = est_pout & 0xff;
2074 
2075         power->est_Pout_act[0] = est_pout >> 24;
2076         power->est_Pout_act[1] = (est_pout >> 16) & 0xff;
2077 
2078         if (power->est_Pout[0] == 0x80)
2079             power->est_Pout[0] = 0;
2080         if (power->est_Pout[1] == 0x80)
2081             power->est_Pout[1] = 0;
2082 
2083         if (power->est_Pout_act[0] == 0x80)
2084             power->est_Pout_act[0] = 0;
2085         if (power->est_Pout_act[1] == 0x80)
2086             power->est_Pout_act[1] = 0;
2087 
2088         power->est_Pout_cck = 0;
2089 
2090         power->tx_power_max[0] = pi->tx_power_max;
2091         power->tx_power_max[1] = pi->tx_power_max;
2092 
2093         power->tx_power_max_rate_ind[0] = pi->tx_power_max_rate_ind;
2094         power->tx_power_max_rate_ind[1] = pi->tx_power_max_rate_ind;
2095     } else if (pi->hwpwrctrl && pi->sh->up) {
2096 
2097         wlc_phyreg_enter(ppi);
2098         if (ISLCNPHY(pi)) {
2099 
2100             power->tx_power_max[0] = pi->tx_power_max;
2101             power->tx_power_max[1] = pi->tx_power_max;
2102 
2103             power->tx_power_max_rate_ind[0] =
2104                 pi->tx_power_max_rate_ind;
2105             power->tx_power_max_rate_ind[1] =
2106                 pi->tx_power_max_rate_ind;
2107 
2108             if (wlc_phy_tpc_isenabled_lcnphy(pi))
2109                 power->flags |=
2110                     (WL_TX_POWER_F_HW |
2111                      WL_TX_POWER_F_ENABLED);
2112             else
2113                 power->flags &=
2114                     ~(WL_TX_POWER_F_HW |
2115                       WL_TX_POWER_F_ENABLED);
2116 
2117             wlc_lcnphy_get_tssi(pi, (s8 *) &power->est_Pout[0],
2118                         (s8 *) &power->est_Pout_cck);
2119         }
2120         wlc_phyreg_exit(ppi);
2121     }
2122 }
2123 
2124 void wlc_phy_antsel_type_set(struct brcms_phy_pub *ppi, u8 antsel_type)
2125 {
2126     struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
2127 
2128     pi->antsel_type = antsel_type;
2129 }
2130 
2131 bool wlc_phy_test_ison(struct brcms_phy_pub *ppi)
2132 {
2133     struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
2134 
2135     return pi->phytest_on;
2136 }
2137 
2138 void wlc_phy_ant_rxdiv_set(struct brcms_phy_pub *ppi, u8 val)
2139 {
2140     struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
2141     bool suspend;
2142 
2143     pi->sh->rx_antdiv = val;
2144 
2145     if (!(ISNPHY(pi) && D11REV_IS(pi->sh->corerev, 16))) {
2146         if (val > ANT_RX_DIV_FORCE_1)
2147             wlapi_bmac_mhf(pi->sh->physhim, MHF1, MHF1_ANTDIV,
2148                        MHF1_ANTDIV, BRCM_BAND_ALL);
2149         else
2150             wlapi_bmac_mhf(pi->sh->physhim, MHF1, MHF1_ANTDIV, 0,
2151                        BRCM_BAND_ALL);
2152     }
2153 
2154     if (ISNPHY(pi))
2155         return;
2156 
2157     if (!pi->sh->clk)
2158         return;
2159 
2160     suspend = (0 == (bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) &
2161              MCTL_EN_MAC));
2162     if (!suspend)
2163         wlapi_suspend_mac_and_wait(pi->sh->physhim);
2164 
2165     if (ISLCNPHY(pi)) {
2166         if (val > ANT_RX_DIV_FORCE_1) {
2167             mod_phy_reg(pi, 0x410, (0x1 << 1), 0x01 << 1);
2168             mod_phy_reg(pi, 0x410,
2169                     (0x1 << 0),
2170                     ((ANT_RX_DIV_START_1 == val) ? 1 : 0) << 0);
2171         } else {
2172             mod_phy_reg(pi, 0x410, (0x1 << 1), 0x00 << 1);
2173             mod_phy_reg(pi, 0x410, (0x1 << 0), (u16) val << 0);
2174         }
2175     }
2176 
2177     if (!suspend)
2178         wlapi_enable_mac(pi->sh->physhim);
2179 
2180     return;
2181 }
2182 
2183 static bool
2184 wlc_phy_noise_calc_phy(struct brcms_phy *pi, u32 *cmplx_pwr, s8 *pwr_ant)
2185 {
2186     s8 cmplx_pwr_dbm[PHY_CORE_MAX];
2187     u8 i;
2188 
2189     memset((u8 *) cmplx_pwr_dbm, 0, sizeof(cmplx_pwr_dbm));
2190     wlc_phy_compute_dB(cmplx_pwr, cmplx_pwr_dbm, pi->pubpi.phy_corenum);
2191 
2192     for (i = 0; i < pi->pubpi.phy_corenum; i++) {
2193         if (NREV_GE(pi->pubpi.phy_rev, 3))
2194             cmplx_pwr_dbm[i] += (s8) PHY_NOISE_OFFSETFACT_4322;
2195         else
2196 
2197             cmplx_pwr_dbm[i] += (s8) (16 - (15) * 3 - 70);
2198     }
2199 
2200     for (i = 0; i < pi->pubpi.phy_corenum; i++) {
2201         pi->nphy_noise_win[i][pi->nphy_noise_index] = cmplx_pwr_dbm[i];
2202         pwr_ant[i] = cmplx_pwr_dbm[i];
2203     }
2204     pi->nphy_noise_index =
2205         MODINC_POW2(pi->nphy_noise_index, PHY_NOISE_WINDOW_SZ);
2206     return true;
2207 }
2208 
2209 static void wlc_phy_noise_cb(struct brcms_phy *pi, u8 channel, s8 noise_dbm)
2210 {
2211     if (!pi->phynoise_state)
2212         return;
2213 
2214     if (pi->phynoise_state & PHY_NOISE_STATE_MON) {
2215         if (pi->phynoise_chan_watchdog == channel) {
2216             pi->sh->phy_noise_window[pi->sh->phy_noise_index] =
2217                 noise_dbm;
2218             pi->sh->phy_noise_index =
2219                 MODINC(pi->sh->phy_noise_index, MA_WINDOW_SZ);
2220         }
2221         pi->phynoise_state &= ~PHY_NOISE_STATE_MON;
2222     }
2223 
2224     if (pi->phynoise_state & PHY_NOISE_STATE_EXTERNAL)
2225         pi->phynoise_state &= ~PHY_NOISE_STATE_EXTERNAL;
2226 
2227 }
2228 
2229 static s8 wlc_phy_noise_read_shmem(struct brcms_phy *pi)
2230 {
2231     u32 cmplx_pwr[PHY_CORE_MAX];
2232     s8 noise_dbm_ant[PHY_CORE_MAX];
2233     u16 lo, hi;
2234     u32 cmplx_pwr_tot = 0;
2235     s8 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;
2236     u8 idx, core;
2237 
2238     memset((u8 *) cmplx_pwr, 0, sizeof(cmplx_pwr));
2239     memset((u8 *) noise_dbm_ant, 0, sizeof(noise_dbm_ant));
2240 
2241     for (idx = 0, core = 0; core < pi->pubpi.phy_corenum; idx += 2,
2242          core++) {
2243         lo = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP(idx));
2244         hi = wlapi_bmac_read_shm(pi->sh->physhim,
2245                      M_PWRIND_MAP(idx + 1));
2246         cmplx_pwr[core] = (hi << 16) + lo;
2247         cmplx_pwr_tot += cmplx_pwr[core];
2248         if (cmplx_pwr[core] == 0)
2249             noise_dbm_ant[core] = PHY_NOISE_FIXED_VAL_NPHY;
2250         else
2251             cmplx_pwr[core] >>= PHY_NOISE_SAMPLE_LOG_NUM_UCODE;
2252     }
2253 
2254     if (cmplx_pwr_tot != 0)
2255         wlc_phy_noise_calc_phy(pi, cmplx_pwr, noise_dbm_ant);
2256 
2257     for (core = 0; core < pi->pubpi.phy_corenum; core++) {
2258         pi->nphy_noise_win[core][pi->nphy_noise_index] =
2259             noise_dbm_ant[core];
2260 
2261         if (noise_dbm_ant[core] > noise_dbm)
2262             noise_dbm = noise_dbm_ant[core];
2263     }
2264     pi->nphy_noise_index =
2265         MODINC_POW2(pi->nphy_noise_index, PHY_NOISE_WINDOW_SZ);
2266 
2267     return noise_dbm;
2268 
2269 }
2270 
2271 void wlc_phy_noise_sample_intr(struct brcms_phy_pub *pih)
2272 {
2273     struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
2274     u16 jssi_aux;
2275     u8 channel = 0;
2276     s8 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;
2277 
2278     if (ISLCNPHY(pi)) {
2279         u32 cmplx_pwr, cmplx_pwr0, cmplx_pwr1;
2280         u16 lo, hi;
2281         s32 pwr_offset_dB, gain_dB;
2282         u16 status_0, status_1;
2283 
2284         jssi_aux = wlapi_bmac_read_shm(pi->sh->physhim, M_JSSI_AUX);
2285         channel = jssi_aux & D11_CURCHANNEL_MAX;
2286 
2287         lo = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP0);
2288         hi = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP1);
2289         cmplx_pwr0 = (hi << 16) + lo;
2290 
2291         lo = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP2);
2292         hi = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP3);
2293         cmplx_pwr1 = (hi << 16) + lo;
2294         cmplx_pwr = (cmplx_pwr0 + cmplx_pwr1) >> 6;
2295 
2296         status_0 = 0x44;
2297         status_1 = wlapi_bmac_read_shm(pi->sh->physhim, M_JSSI_0);
2298         if ((cmplx_pwr > 0 && cmplx_pwr < 500)
2299             && ((status_1 & 0xc000) == 0x4000)) {
2300 
2301             wlc_phy_compute_dB(&cmplx_pwr, &noise_dbm,
2302                        pi->pubpi.phy_corenum);
2303             pwr_offset_dB = (read_phy_reg(pi, 0x434) & 0xFF);
2304             if (pwr_offset_dB > 127)
2305                 pwr_offset_dB -= 256;
2306 
2307             noise_dbm += (s8) (pwr_offset_dB - 30);
2308 
2309             gain_dB = (status_0 & 0x1ff);
2310             noise_dbm -= (s8) (gain_dB);
2311         } else {
2312             noise_dbm = PHY_NOISE_FIXED_VAL_LCNPHY;
2313         }
2314     } else if (ISNPHY(pi)) {
2315 
2316         jssi_aux = wlapi_bmac_read_shm(pi->sh->physhim, M_JSSI_AUX);
2317         channel = jssi_aux & D11_CURCHANNEL_MAX;
2318 
2319         noise_dbm = wlc_phy_noise_read_shmem(pi);
2320     }
2321 
2322     wlc_phy_noise_cb(pi, channel, noise_dbm);
2323 
2324 }
2325 
2326 static void
2327 wlc_phy_noise_sample_request(struct brcms_phy_pub *pih, u8 reason, u8 ch)
2328 {
2329     struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
2330     s8 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;
2331     bool sampling_in_progress = (pi->phynoise_state != 0);
2332     bool wait_for_intr = true;
2333 
2334     switch (reason) {
2335     case PHY_NOISE_SAMPLE_MON:
2336         pi->phynoise_chan_watchdog = ch;
2337         pi->phynoise_state |= PHY_NOISE_STATE_MON;
2338         break;
2339 
2340     case PHY_NOISE_SAMPLE_EXTERNAL:
2341         pi->phynoise_state |= PHY_NOISE_STATE_EXTERNAL;
2342         break;
2343 
2344     default:
2345         break;
2346     }
2347 
2348     if (sampling_in_progress)
2349         return;
2350 
2351     pi->phynoise_now = pi->sh->now;
2352 
2353     if (pi->phy_fixed_noise) {
2354         if (ISNPHY(pi)) {
2355             pi->nphy_noise_win[WL_ANT_IDX_1][pi->nphy_noise_index] =
2356                 PHY_NOISE_FIXED_VAL_NPHY;
2357             pi->nphy_noise_win[WL_ANT_IDX_2][pi->nphy_noise_index] =
2358                 PHY_NOISE_FIXED_VAL_NPHY;
2359             pi->nphy_noise_index = MODINC_POW2(pi->nphy_noise_index,
2360                                PHY_NOISE_WINDOW_SZ);
2361             noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;
2362         } else {
2363             noise_dbm = PHY_NOISE_FIXED_VAL;
2364         }
2365 
2366         wait_for_intr = false;
2367         goto done;
2368     }
2369 
2370     if (ISLCNPHY(pi)) {
2371         if (!pi->phynoise_polling
2372             || (reason == PHY_NOISE_SAMPLE_EXTERNAL)) {
2373             wlapi_bmac_write_shm(pi->sh->physhim, M_JSSI_0, 0);
2374             wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP0, 0);
2375             wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP1, 0);
2376             wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP2, 0);
2377             wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP3, 0);
2378 
2379             bcma_set32(pi->d11core, D11REGOFFS(maccommand),
2380                    MCMD_BG_NOISE);
2381         } else {
2382             wlapi_suspend_mac_and_wait(pi->sh->physhim);
2383             wlc_lcnphy_deaf_mode(pi, (bool) 0);
2384             noise_dbm = (s8) wlc_lcnphy_rx_signal_power(pi, 20);
2385             wlc_lcnphy_deaf_mode(pi, (bool) 1);
2386             wlapi_enable_mac(pi->sh->physhim);
2387             wait_for_intr = false;
2388         }
2389     } else if (ISNPHY(pi)) {
2390         if (!pi->phynoise_polling
2391             || (reason == PHY_NOISE_SAMPLE_EXTERNAL)) {
2392 
2393             wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP0, 0);
2394             wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP1, 0);
2395             wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP2, 0);
2396             wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP3, 0);
2397 
2398             bcma_set32(pi->d11core, D11REGOFFS(maccommand),
2399                    MCMD_BG_NOISE);
2400         } else {
2401             struct phy_iq_est est[PHY_CORE_MAX];
2402             u32 cmplx_pwr[PHY_CORE_MAX];
2403             s8 noise_dbm_ant[PHY_CORE_MAX];
2404             u16 log_num_samps, num_samps, classif_state = 0;
2405             u8 wait_time = 32;
2406             u8 wait_crs = 0;
2407             u8 i;
2408 
2409             memset((u8 *) est, 0, sizeof(est));
2410             memset((u8 *) cmplx_pwr, 0, sizeof(cmplx_pwr));
2411             memset((u8 *) noise_dbm_ant, 0, sizeof(noise_dbm_ant));
2412 
2413             log_num_samps = PHY_NOISE_SAMPLE_LOG_NUM_NPHY;
2414             num_samps = 1 << log_num_samps;
2415 
2416             wlapi_suspend_mac_and_wait(pi->sh->physhim);
2417             classif_state = wlc_phy_classifier_nphy(pi, 0, 0);
2418             wlc_phy_classifier_nphy(pi, 3, 0);
2419             wlc_phy_rx_iq_est_nphy(pi, est, num_samps, wait_time,
2420                            wait_crs);
2421             wlc_phy_classifier_nphy(pi, (0x7 << 0), classif_state);
2422             wlapi_enable_mac(pi->sh->physhim);
2423 
2424             for (i = 0; i < pi->pubpi.phy_corenum; i++)
2425                 cmplx_pwr[i] = (est[i].i_pwr + est[i].q_pwr) >>
2426                            log_num_samps;
2427 
2428             wlc_phy_noise_calc_phy(pi, cmplx_pwr, noise_dbm_ant);
2429 
2430             for (i = 0; i < pi->pubpi.phy_corenum; i++) {
2431                 pi->nphy_noise_win[i][pi->nphy_noise_index] =
2432                     noise_dbm_ant[i];
2433 
2434                 if (noise_dbm_ant[i] > noise_dbm)
2435                     noise_dbm = noise_dbm_ant[i];
2436             }
2437             pi->nphy_noise_index = MODINC_POW2(pi->nphy_noise_index,
2438                                PHY_NOISE_WINDOW_SZ);
2439 
2440             wait_for_intr = false;
2441         }
2442     }
2443 
2444 done:
2445 
2446     if (!wait_for_intr)
2447         wlc_phy_noise_cb(pi, ch, noise_dbm);
2448 
2449 }
2450 
2451 void wlc_phy_noise_sample_request_external(struct brcms_phy_pub *pih)
2452 {
2453     u8 channel;
2454 
2455     channel = CHSPEC_CHANNEL(wlc_phy_chanspec_get(pih));
2456 
2457     wlc_phy_noise_sample_request(pih, PHY_NOISE_SAMPLE_EXTERNAL, channel);
2458 }
2459 
2460 static const s8 lcnphy_gain_index_offset_for_pkt_rssi[] = {
2461     8,
2462     8,
2463     8,
2464     8,
2465     8,
2466     8,
2467     8,
2468     9,
2469     10,
2470     8,
2471     8,
2472     7,
2473     7,
2474     1,
2475     2,
2476     2,
2477     2,
2478     2,
2479     2,
2480     2,
2481     2,
2482     2,
2483     2,
2484     2,
2485     2,
2486     2,
2487     2,
2488     2,
2489     2,
2490     2,
2491     2,
2492     2,
2493     1,
2494     1,
2495     0,
2496     0,
2497     0,
2498     0
2499 };
2500 
2501 void wlc_phy_compute_dB(u32 *cmplx_pwr, s8 *p_cmplx_pwr_dB, u8 core)
2502 {
2503     u8 msb, secondmsb, i;
2504     u32 tmp;
2505 
2506     for (i = 0; i < core; i++) {
2507         secondmsb = 0;
2508         tmp = cmplx_pwr[i];
2509         msb = fls(tmp);
2510         if (msb)
2511             secondmsb = (u8) ((tmp >> (--msb - 1)) & 1);
2512         p_cmplx_pwr_dB[i] = (s8) (3 * msb + 2 * secondmsb);
2513     }
2514 }
2515 
2516 int wlc_phy_rssi_compute(struct brcms_phy_pub *pih,
2517              struct d11rxhdr *rxh)
2518 {
2519     int rssi = rxh->PhyRxStatus_1 & PRXS1_JSSI_MASK;
2520     uint radioid = pih->radioid;
2521     struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
2522 
2523     if ((pi->sh->corerev >= 11)
2524         && !(rxh->RxStatus2 & RXS_PHYRXST_VALID)) {
2525         rssi = BRCMS_RSSI_INVALID;
2526         goto end;
2527     }
2528 
2529     if (ISLCNPHY(pi)) {
2530         u8 gidx = (rxh->PhyRxStatus_2 & 0xFC00) >> 10;
2531         struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
2532 
2533         if (rssi > 127)
2534             rssi -= 256;
2535 
2536         rssi = rssi + lcnphy_gain_index_offset_for_pkt_rssi[gidx];
2537         if ((rssi > -46) && (gidx > 18))
2538             rssi = rssi + 7;
2539 
2540         rssi = rssi + pi_lcn->lcnphy_pkteng_rssi_slope;
2541 
2542         rssi = rssi + 2;
2543 
2544     }
2545 
2546     if (ISLCNPHY(pi)) {
2547         if (rssi > 127)
2548             rssi -= 256;
2549     } else if (radioid == BCM2055_ID || radioid == BCM2056_ID
2550            || radioid == BCM2057_ID) {
2551         rssi = wlc_phy_rssi_compute_nphy(pi, rxh);
2552     }
2553 
2554 end:
2555     return rssi;
2556 }
2557 
2558 void wlc_phy_freqtrack_start(struct brcms_phy_pub *pih)
2559 {
2560     return;
2561 }
2562 
2563 void wlc_phy_freqtrack_end(struct brcms_phy_pub *pih)
2564 {
2565     return;
2566 }
2567 
2568 void wlc_phy_set_deaf(struct brcms_phy_pub *ppi, bool user_flag)
2569 {
2570     struct brcms_phy *pi;
2571     pi = (struct brcms_phy *) ppi;
2572 
2573     if (ISLCNPHY(pi))
2574         wlc_lcnphy_deaf_mode(pi, true);
2575     else if (ISNPHY(pi))
2576         wlc_nphy_deaf_mode(pi, true);
2577 }
2578 
2579 void wlc_phy_watchdog(struct brcms_phy_pub *pih)
2580 {
2581     struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
2582     bool delay_phy_cal = false;
2583     pi->sh->now++;
2584 
2585     if (!pi->watchdog_override)
2586         return;
2587 
2588     if (!(SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi)))
2589         wlc_phy_noise_sample_request((struct brcms_phy_pub *) pi,
2590                          PHY_NOISE_SAMPLE_MON,
2591                          CHSPEC_CHANNEL(pi->
2592                                 radio_chanspec));
2593 
2594     if (pi->phynoise_state && (pi->sh->now - pi->phynoise_now) > 5)
2595         pi->phynoise_state = 0;
2596 
2597     if ((!pi->phycal_txpower) ||
2598         ((pi->sh->now - pi->phycal_txpower) >= pi->sh->fast_timer)) {
2599 
2600         if (!SCAN_INPROG_PHY(pi) && wlc_phy_cal_txpower_recalc_sw(pi))
2601             pi->phycal_txpower = pi->sh->now;
2602     }
2603 
2604     if ((SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi)
2605          || ASSOC_INPROG_PHY(pi)))
2606         return;
2607 
2608     if (ISNPHY(pi) && !pi->disable_percal && !delay_phy_cal) {
2609 
2610         if ((pi->nphy_perical != PHY_PERICAL_DISABLE) &&
2611             (pi->nphy_perical != PHY_PERICAL_MANUAL) &&
2612             ((pi->sh->now - pi->nphy_perical_last) >=
2613              pi->sh->glacial_timer))
2614             wlc_phy_cal_perical((struct brcms_phy_pub *) pi,
2615                         PHY_PERICAL_WATCHDOG);
2616 
2617         wlc_phy_txpwr_papd_cal_nphy(pi);
2618     }
2619 
2620     if (ISLCNPHY(pi)) {
2621         if (pi->phy_forcecal ||
2622             ((pi->sh->now - pi->phy_lastcal) >=
2623              pi->sh->glacial_timer)) {
2624             if (!(SCAN_RM_IN_PROGRESS(pi) || ASSOC_INPROG_PHY(pi)))
2625                 wlc_lcnphy_calib_modes(
2626                     pi,
2627                     LCNPHY_PERICAL_TEMPBASED_TXPWRCTRL);
2628             if (!
2629                 (SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi)
2630                  || ASSOC_INPROG_PHY(pi)
2631                  || pi->carrier_suppr_disable
2632                  || pi->disable_percal))
2633                 wlc_lcnphy_calib_modes(pi,
2634                                PHY_PERICAL_WATCHDOG);
2635         }
2636     }
2637 }
2638 
2639 void wlc_phy_BSSinit(struct brcms_phy_pub *pih, bool bonlyap, int rssi)
2640 {
2641     struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
2642     uint i;
2643     uint k;
2644 
2645     for (i = 0; i < MA_WINDOW_SZ; i++)
2646         pi->sh->phy_noise_window[i] = (s8) (rssi & 0xff);
2647     if (ISLCNPHY(pi)) {
2648         for (i = 0; i < MA_WINDOW_SZ; i++)
2649             pi->sh->phy_noise_window[i] =
2650                 PHY_NOISE_FIXED_VAL_LCNPHY;
2651     }
2652     pi->sh->phy_noise_index = 0;
2653 
2654     for (i = 0; i < PHY_NOISE_WINDOW_SZ; i++) {
2655         for (k = WL_ANT_IDX_1; k < WL_ANT_RX_MAX; k++)
2656             pi->nphy_noise_win[k][i] = PHY_NOISE_FIXED_VAL_NPHY;
2657     }
2658     pi->nphy_noise_index = 0;
2659 }
2660 
2661 void
2662 wlc_phy_papd_decode_epsilon(u32 epsilon, s32 *eps_real, s32 *eps_imag)
2663 {
2664     *eps_imag = (epsilon >> 13);
2665     if (*eps_imag > 0xfff)
2666         *eps_imag -= 0x2000;
2667 
2668     *eps_real = (epsilon & 0x1fff);
2669     if (*eps_real > 0xfff)
2670         *eps_real -= 0x2000;
2671 }
2672 
2673 void wlc_phy_cal_perical_mphase_reset(struct brcms_phy *pi)
2674 {
2675     wlapi_del_timer(pi->phycal_timer);
2676 
2677     pi->cal_type_override = PHY_PERICAL_AUTO;
2678     pi->mphase_cal_phase_id = MPHASE_CAL_STATE_IDLE;
2679     pi->mphase_txcal_cmdidx = 0;
2680 }
2681 
2682 static void
2683 wlc_phy_cal_perical_mphase_schedule(struct brcms_phy *pi, uint delay)
2684 {
2685 
2686     if ((pi->nphy_perical != PHY_PERICAL_MPHASE) &&
2687         (pi->nphy_perical != PHY_PERICAL_MANUAL))
2688         return;
2689 
2690     wlapi_del_timer(pi->phycal_timer);
2691 
2692     pi->mphase_cal_phase_id = MPHASE_CAL_STATE_INIT;
2693     wlapi_add_timer(pi->phycal_timer, delay, 0);
2694 }
2695 
2696 void wlc_phy_cal_perical(struct brcms_phy_pub *pih, u8 reason)
2697 {
2698     s16 nphy_currtemp = 0;
2699     s16 delta_temp = 0;
2700     bool do_periodic_cal = true;
2701     struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
2702 
2703     if (!ISNPHY(pi))
2704         return;
2705 
2706     if ((pi->nphy_perical == PHY_PERICAL_DISABLE) ||
2707         (pi->nphy_perical == PHY_PERICAL_MANUAL))
2708         return;
2709 
2710     switch (reason) {
2711     case PHY_PERICAL_DRIVERUP:
2712         break;
2713 
2714     case PHY_PERICAL_PHYINIT:
2715         if (pi->nphy_perical == PHY_PERICAL_MPHASE) {
2716             if (PHY_PERICAL_MPHASE_PENDING(pi))
2717                 wlc_phy_cal_perical_mphase_reset(pi);
2718 
2719             wlc_phy_cal_perical_mphase_schedule(
2720                 pi,
2721                 PHY_PERICAL_INIT_DELAY);
2722         }
2723         break;
2724 
2725     case PHY_PERICAL_JOIN_BSS:
2726     case PHY_PERICAL_START_IBSS:
2727     case PHY_PERICAL_UP_BSS:
2728         if ((pi->nphy_perical == PHY_PERICAL_MPHASE) &&
2729             PHY_PERICAL_MPHASE_PENDING(pi))
2730             wlc_phy_cal_perical_mphase_reset(pi);
2731 
2732         pi->first_cal_after_assoc = true;
2733 
2734         pi->cal_type_override = PHY_PERICAL_FULL;
2735 
2736         if (pi->phycal_tempdelta)
2737             pi->nphy_lastcal_temp = wlc_phy_tempsense_nphy(pi);
2738 
2739         wlc_phy_cal_perical_nphy_run(pi, PHY_PERICAL_FULL);
2740         break;
2741 
2742     case PHY_PERICAL_WATCHDOG:
2743         if (pi->phycal_tempdelta) {
2744             nphy_currtemp = wlc_phy_tempsense_nphy(pi);
2745             delta_temp =
2746                 (nphy_currtemp > pi->nphy_lastcal_temp) ?
2747                 nphy_currtemp - pi->nphy_lastcal_temp :
2748                 pi->nphy_lastcal_temp - nphy_currtemp;
2749 
2750             if ((delta_temp < (s16) pi->phycal_tempdelta) &&
2751                 (pi->nphy_txiqlocal_chanspec ==
2752                  pi->radio_chanspec))
2753                 do_periodic_cal = false;
2754             else
2755                 pi->nphy_lastcal_temp = nphy_currtemp;
2756         }
2757 
2758         if (do_periodic_cal) {
2759             if (pi->nphy_perical == PHY_PERICAL_MPHASE) {
2760                 if (!PHY_PERICAL_MPHASE_PENDING(pi))
2761                     wlc_phy_cal_perical_mphase_schedule(
2762                         pi,
2763                         PHY_PERICAL_WDOG_DELAY);
2764             } else if (pi->nphy_perical == PHY_PERICAL_SPHASE)
2765                 wlc_phy_cal_perical_nphy_run(pi,
2766                                  PHY_PERICAL_AUTO);
2767         }
2768         break;
2769     default:
2770         break;
2771     }
2772 }
2773 
2774 void wlc_phy_cal_perical_mphase_restart(struct brcms_phy *pi)
2775 {
2776     pi->mphase_cal_phase_id = MPHASE_CAL_STATE_INIT;
2777     pi->mphase_txcal_cmdidx = 0;
2778 }
2779 
2780 u8 wlc_phy_nbits(s32 value)
2781 {
2782     s32 abs_val;
2783     u8 nbits = 0;
2784 
2785     abs_val = abs(value);
2786     while ((abs_val >> nbits) > 0)
2787         nbits++;
2788 
2789     return nbits;
2790 }
2791 
2792 void wlc_phy_stf_chain_init(struct brcms_phy_pub *pih, u8 txchain, u8 rxchain)
2793 {
2794     struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
2795 
2796     pi->sh->hw_phytxchain = txchain;
2797     pi->sh->hw_phyrxchain = rxchain;
2798     pi->sh->phytxchain = txchain;
2799     pi->sh->phyrxchain = rxchain;
2800     pi->pubpi.phy_corenum = (u8)hweight8(pi->sh->phyrxchain);
2801 }
2802 
2803 void wlc_phy_stf_chain_set(struct brcms_phy_pub *pih, u8 txchain, u8 rxchain)
2804 {
2805     struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
2806 
2807     pi->sh->phytxchain = txchain;
2808 
2809     if (ISNPHY(pi))
2810         wlc_phy_rxcore_setstate_nphy(pih, rxchain);
2811 
2812     pi->pubpi.phy_corenum = (u8)hweight8(pi->sh->phyrxchain);
2813 }
2814 
2815 void wlc_phy_stf_chain_get(struct brcms_phy_pub *pih, u8 *txchain, u8 *rxchain)
2816 {
2817     struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
2818 
2819     *txchain = pi->sh->phytxchain;
2820     *rxchain = pi->sh->phyrxchain;
2821 }
2822 
2823 u8 wlc_phy_stf_chain_active_get(struct brcms_phy_pub *pih)
2824 {
2825     s16 nphy_currtemp;
2826     u8 active_bitmap;
2827     struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
2828 
2829     active_bitmap = (pi->phy_txcore_heatedup) ? 0x31 : 0x33;
2830 
2831     if (!pi->watchdog_override)
2832         return active_bitmap;
2833 
2834     if (NREV_GE(pi->pubpi.phy_rev, 6)) {
2835         wlapi_suspend_mac_and_wait(pi->sh->physhim);
2836         nphy_currtemp = wlc_phy_tempsense_nphy(pi);
2837         wlapi_enable_mac(pi->sh->physhim);
2838 
2839         if (!pi->phy_txcore_heatedup) {
2840             if (nphy_currtemp >= pi->phy_txcore_disable_temp) {
2841                 active_bitmap &= 0xFD;
2842                 pi->phy_txcore_heatedup = true;
2843             }
2844         } else {
2845             if (nphy_currtemp <= pi->phy_txcore_enable_temp) {
2846                 active_bitmap |= 0x2;
2847                 pi->phy_txcore_heatedup = false;
2848             }
2849         }
2850     }
2851 
2852     return active_bitmap;
2853 }
2854 
2855 s8 wlc_phy_stf_ssmode_get(struct brcms_phy_pub *pih, u16 chanspec)
2856 {
2857     struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
2858     u8 siso_mcs_id, cdd_mcs_id;
2859 
2860     siso_mcs_id =
2861         (CHSPEC_IS40(chanspec)) ? TXP_FIRST_MCS_40_SISO :
2862         TXP_FIRST_MCS_20_SISO;
2863     cdd_mcs_id =
2864         (CHSPEC_IS40(chanspec)) ? TXP_FIRST_MCS_40_CDD :
2865         TXP_FIRST_MCS_20_CDD;
2866 
2867     if (pi->tx_power_target[siso_mcs_id] >
2868         (pi->tx_power_target[cdd_mcs_id] + 12))
2869         return PHY_TXC1_MODE_SISO;
2870     else
2871         return PHY_TXC1_MODE_CDD;
2872 }
2873 
2874 const u8 *wlc_phy_get_ofdm_rate_lookup(void)
2875 {
2876     return ofdm_rate_lookup;
2877 }
2878 
2879 void wlc_lcnphy_epa_switch(struct brcms_phy *pi, bool mode)
2880 {
2881     if ((pi->sh->chip == BCMA_CHIP_ID_BCM4313) &&
2882         (pi->sh->boardflags & BFL_FEM)) {
2883         if (mode) {
2884             u16 txant = 0;
2885             txant = wlapi_bmac_get_txant(pi->sh->physhim);
2886             if (txant == 1) {
2887                 mod_phy_reg(pi, 0x44d, (0x1 << 2), (1) << 2);
2888 
2889                 mod_phy_reg(pi, 0x44c, (0x1 << 2), (1) << 2);
2890 
2891             }
2892 
2893             bcma_chipco_gpio_control(&pi->d11core->bus->drv_cc,
2894                          0x0, 0x0);
2895             bcma_chipco_gpio_out(&pi->d11core->bus->drv_cc,
2896                          ~0x40, 0x40);
2897             bcma_chipco_gpio_outen(&pi->d11core->bus->drv_cc,
2898                            ~0x40, 0x40);
2899         } else {
2900             mod_phy_reg(pi, 0x44c, (0x1 << 2), (0) << 2);
2901 
2902             mod_phy_reg(pi, 0x44d, (0x1 << 2), (0) << 2);
2903 
2904             bcma_chipco_gpio_out(&pi->d11core->bus->drv_cc,
2905                          ~0x40, 0x00);
2906             bcma_chipco_gpio_outen(&pi->d11core->bus->drv_cc,
2907                            ~0x40, 0x00);
2908             bcma_chipco_gpio_control(&pi->d11core->bus->drv_cc,
2909                          0x0, 0x40);
2910         }
2911     }
2912 }
2913 
2914 void wlc_phy_ldpc_override_set(struct brcms_phy_pub *ppi, bool ldpc)
2915 {
2916     return;
2917 }
2918 
2919 void
2920 wlc_phy_get_pwrdet_offsets(struct brcms_phy *pi, s8 *cckoffset, s8 *ofdmoffset)
2921 {
2922     *cckoffset = 0;
2923     *ofdmoffset = 0;
2924 }
2925 
2926 s8 wlc_phy_upd_rssi_offset(struct brcms_phy *pi, s8 rssi, u16 chanspec)
2927 {
2928 
2929     return rssi;
2930 }
2931 
2932 bool wlc_phy_txpower_ipa_ison(struct brcms_phy_pub *ppi)
2933 {
2934     struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
2935 
2936     if (ISNPHY(pi))
2937         return wlc_phy_n_txpower_ipa_ison(pi);
2938     else
2939         return false;
2940 }