0001
0002
0003
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
0031 #define MUX(pred, true, false) ((pred) ? (true) : (false))
0032
0033
0034 #define MODINC(x, bound) MUX((x) == (bound) - 1, 0, (x) + 1)
0035
0036
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 }