2 * Copyright (c) 2010 Broadcom Corporation
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
11 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
13 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 #include <linux/kernel.h>
18 #include <linux/string.h>
19 #include <linux/bitops.h>
20 #include <linux/delay.h>
21 #include <linux/module.h>
22 #include <linux/pci.h>
25 #include <chipcommon.h>
26 #include <brcm_hw_ids.h>
32 #include <phy_radio.h>
35 u32 phyhal_msg_level = PHYHAL_ERROR;
37 typedef struct _chan_info_basic {
42 static chan_info_basic_t chan_info_all[] = {
102 u16 ltrn_list[PHY_LTRN_LIST_LEN] = {
103 0x18f9, 0x0d01, 0x00e4, 0xdef4, 0x06f1, 0x0ffc,
104 0xfa27, 0x1dff, 0x10f0, 0x0918, 0xf20a, 0xe010,
105 0x1417, 0x1104, 0xf114, 0xf2fa, 0xf7db, 0xe2fc,
106 0xe1fb, 0x13ee, 0xff0d, 0xe91c, 0x171a, 0x0318,
107 0xda00, 0x03e8, 0x17e6, 0xe9e4, 0xfff3, 0x1312,
108 0xe105, 0xe204, 0xf725, 0xf206, 0xf1ec, 0x11fc,
109 0x14e9, 0xe0f0, 0xf2f6, 0x09e8, 0x1010, 0x1d01,
110 0xfad9, 0x0f04, 0x060f, 0xde0c, 0x001c, 0x0dff,
111 0x1807, 0xf61a, 0xe40e, 0x0f16, 0x05f9, 0x18ec,
112 0x0a1b, 0xff1e, 0x2600, 0xffe2, 0x0ae5, 0x1814,
113 0x0507, 0x0fea, 0xe4f2, 0xf6e6
116 const u8 ofdm_rate_lookup[] = {
128 #define PHY_WREG_LIMIT 24
130 static void wlc_set_phy_uninitted(phy_info_t *pi);
131 static u32 wlc_phy_get_radio_ver(phy_info_t *pi);
132 static void wlc_phy_timercb_phycal(void *arg);
134 static bool wlc_phy_noise_calc_phy(phy_info_t *pi, u32 *cmplx_pwr,
137 static void wlc_phy_cal_perical_mphase_schedule(phy_info_t *pi, uint delay);
138 static void wlc_phy_noise_cb(phy_info_t *pi, u8 channel, s8 noise_dbm);
139 static void wlc_phy_noise_sample_request(wlc_phy_t *pih, u8 reason,
142 static void wlc_phy_txpower_reg_limit_calc(phy_info_t *pi,
143 struct txpwr_limits *tp, chanspec_t);
144 static bool wlc_phy_cal_txpower_recalc_sw(phy_info_t *pi);
146 static s8 wlc_user_txpwr_antport_to_rfport(phy_info_t *pi, uint chan,
148 static void wlc_phy_upd_env_txpwr_rate_limits(phy_info_t *pi, u32 band);
149 static s8 wlc_phy_env_measure_vbat(phy_info_t *pi);
150 static s8 wlc_phy_env_measure_temperature(phy_info_t *pi);
152 char *phy_getvar(phy_info_t *pi, const char *name)
154 char *vars = pi->vars;
165 for (s = vars; s && *s;) {
166 if ((memcmp(s, name, len) == 0) && (s[len] == '='))
176 int phy_getintvar(phy_info_t *pi, const char *name)
180 val = PHY_GETVAR(pi, name);
184 return simple_strtoul(val, NULL, 0);
187 void wlc_phyreg_enter(wlc_phy_t *pih)
189 phy_info_t *pi = (phy_info_t *) pih;
190 wlapi_bmac_ucode_wake_override_phyreg_set(pi->sh->physhim);
193 void wlc_phyreg_exit(wlc_phy_t *pih)
195 phy_info_t *pi = (phy_info_t *) pih;
196 wlapi_bmac_ucode_wake_override_phyreg_clear(pi->sh->physhim);
199 void wlc_radioreg_enter(wlc_phy_t *pih)
201 phy_info_t *pi = (phy_info_t *) pih;
202 wlapi_bmac_mctrl(pi->sh->physhim, MCTL_LOCK_RADIO, MCTL_LOCK_RADIO);
207 void wlc_radioreg_exit(wlc_phy_t *pih)
209 phy_info_t *pi = (phy_info_t *) pih;
212 dummy = R_REG(&pi->regs->phyversion);
214 wlapi_bmac_mctrl(pi->sh->physhim, MCTL_LOCK_RADIO, 0);
217 u16 read_radio_reg(phy_info_t *pi, u16 addr)
221 if ((addr == RADIO_IDCODE))
224 if (NORADIO_ENAB(pi->pubpi))
225 return NORADIO_IDCODE & 0xffff;
227 switch (pi->pubpi.phy_type) {
229 CASECHECK(PHYTYPE, PHY_TYPE_N);
230 if (NREV_GE(pi->pubpi.phy_rev, 7))
231 addr |= RADIO_2057_READ_OFF;
233 addr |= RADIO_2055_READ_OFF;
237 CASECHECK(PHYTYPE, PHY_TYPE_LCN);
238 addr |= RADIO_2064_READ_OFF;
245 if ((D11REV_GE(pi->sh->corerev, 24)) ||
246 (D11REV_IS(pi->sh->corerev, 22)
247 && (pi->pubpi.phy_type != PHY_TYPE_SSN))) {
248 W_REG_FLUSH(&pi->regs->radioregaddr, addr);
249 data = R_REG(&pi->regs->radioregdata);
251 W_REG_FLUSH(&pi->regs->phy4waddr, addr);
253 #ifdef __ARM_ARCH_4T__
254 __asm__(" .align 4 ");
256 data = R_REG(&pi->regs->phy4wdatalo);
258 data = R_REG(&pi->regs->phy4wdatalo);
267 void write_radio_reg(phy_info_t *pi, u16 addr, u16 val)
269 if (NORADIO_ENAB(pi->pubpi))
272 if ((D11REV_GE(pi->sh->corerev, 24)) ||
273 (D11REV_IS(pi->sh->corerev, 22)
274 && (pi->pubpi.phy_type != PHY_TYPE_SSN))) {
276 W_REG_FLUSH(&pi->regs->radioregaddr, addr);
277 W_REG(&pi->regs->radioregdata, val);
279 W_REG_FLUSH(&pi->regs->phy4waddr, addr);
280 W_REG(&pi->regs->phy4wdatalo, val);
283 if (pi->sh->bustype == PCI_BUS) {
284 if (++pi->phy_wreg >= pi->phy_wreg_limit) {
285 (void)R_REG(&pi->regs->maccontrol);
291 static u32 read_radio_id(phy_info_t *pi)
295 if (NORADIO_ENAB(pi->pubpi))
296 return NORADIO_IDCODE;
298 if (D11REV_GE(pi->sh->corerev, 24)) {
301 W_REG_FLUSH(&pi->regs->radioregaddr, 0);
302 b0 = (u32) R_REG(&pi->regs->radioregdata);
303 W_REG_FLUSH(&pi->regs->radioregaddr, 1);
304 b1 = (u32) R_REG(&pi->regs->radioregdata);
305 W_REG_FLUSH(&pi->regs->radioregaddr, 2);
306 b2 = (u32) R_REG(&pi->regs->radioregdata);
308 id = ((b0 & 0xf) << 28) | (((b2 << 8) | b1) << 12) | ((b0 >> 4)
311 W_REG_FLUSH(&pi->regs->phy4waddr, RADIO_IDCODE);
312 id = (u32) R_REG(&pi->regs->phy4wdatalo);
313 id |= (u32) R_REG(&pi->regs->phy4wdatahi) << 16;
319 void and_radio_reg(phy_info_t *pi, u16 addr, u16 val)
323 if (NORADIO_ENAB(pi->pubpi))
326 rval = read_radio_reg(pi, addr);
327 write_radio_reg(pi, addr, (rval & val));
330 void or_radio_reg(phy_info_t *pi, u16 addr, u16 val)
334 if (NORADIO_ENAB(pi->pubpi))
337 rval = read_radio_reg(pi, addr);
338 write_radio_reg(pi, addr, (rval | val));
341 void xor_radio_reg(phy_info_t *pi, u16 addr, u16 mask)
345 if (NORADIO_ENAB(pi->pubpi))
348 rval = read_radio_reg(pi, addr);
349 write_radio_reg(pi, addr, (rval ^ mask));
352 void mod_radio_reg(phy_info_t *pi, u16 addr, u16 mask, u16 val)
356 if (NORADIO_ENAB(pi->pubpi))
359 rval = read_radio_reg(pi, addr);
360 write_radio_reg(pi, addr, (rval & ~mask) | (val & mask));
363 void write_phy_channel_reg(phy_info_t *pi, uint val)
365 W_REG(&pi->regs->phychannel, val);
368 u16 read_phy_reg(phy_info_t *pi, u16 addr)
374 W_REG_FLUSH(®s->phyregaddr, addr);
377 return R_REG(®s->phyregdata);
380 void write_phy_reg(phy_info_t *pi, u16 addr, u16 val)
387 W_REG_FLUSH(®s->phyregaddr, addr);
388 W_REG(®s->phyregdata, val);
390 (void)R_REG(®s->phyregdata);
392 W_REG((u32 *)(®s->phyregaddr),
394 if (pi->sh->bustype == PCI_BUS) {
395 if (++pi->phy_wreg >= pi->phy_wreg_limit) {
397 (void)R_REG(®s->phyversion);
403 void and_phy_reg(phy_info_t *pi, u16 addr, u16 val)
409 W_REG_FLUSH(®s->phyregaddr, addr);
411 W_REG(®s->phyregdata, (R_REG(®s->phyregdata) & val));
415 void or_phy_reg(phy_info_t *pi, u16 addr, u16 val)
421 W_REG_FLUSH(®s->phyregaddr, addr);
423 W_REG(®s->phyregdata, (R_REG(®s->phyregdata) | val));
427 void mod_phy_reg(phy_info_t *pi, u16 addr, u16 mask, u16 val)
433 W_REG_FLUSH(®s->phyregaddr, addr);
435 W_REG(®s->phyregdata,
436 ((R_REG(®s->phyregdata) & ~mask) | (val & mask)));
440 static void WLBANDINITFN(wlc_set_phy_uninitted) (phy_info_t *pi)
444 pi->initialized = false;
447 pi->nrssi_table_delta = 0x7fffffff;
449 pi->mintxbias = 0xffff;
452 pi->phy_spuravoid = SPURAVOID_DISABLE;
454 if (NREV_GE(pi->pubpi.phy_rev, 3)
455 && NREV_LT(pi->pubpi.phy_rev, 7))
456 pi->phy_spuravoid = SPURAVOID_AUTO;
458 pi->nphy_papd_skip = 0;
459 pi->nphy_papd_epsilon_offset[0] = 0xf588;
460 pi->nphy_papd_epsilon_offset[1] = 0xf588;
461 pi->nphy_txpwr_idx[0] = 128;
462 pi->nphy_txpwr_idx[1] = 128;
463 pi->nphy_txpwrindex[0].index_internal = 40;
464 pi->nphy_txpwrindex[1].index_internal = 40;
467 pi->phy_spuravoid = SPURAVOID_AUTO;
469 pi->radiopwr = 0xffff;
470 for (i = 0; i < STATIC_NUM_RF; i++) {
471 for (j = 0; j < STATIC_NUM_BB; j++) {
472 pi->stats_11b_txpower[i][j] = -1;
477 shared_phy_t *wlc_phy_shared_attach(shared_phy_params_t *shp)
481 sh = kzalloc(sizeof(shared_phy_t), GFP_ATOMIC);
487 sh->physhim = shp->physhim;
488 sh->unit = shp->unit;
489 sh->corerev = shp->corerev;
493 sh->chip = shp->chip;
494 sh->chiprev = shp->chiprev;
495 sh->chippkg = shp->chippkg;
496 sh->sromrev = shp->sromrev;
497 sh->boardtype = shp->boardtype;
498 sh->boardrev = shp->boardrev;
499 sh->boardvendor = shp->boardvendor;
500 sh->boardflags = shp->boardflags;
501 sh->boardflags2 = shp->boardflags2;
502 sh->bustype = shp->bustype;
503 sh->buscorerev = shp->buscorerev;
505 sh->fast_timer = PHY_SW_TIMER_FAST;
506 sh->slow_timer = PHY_SW_TIMER_SLOW;
507 sh->glacial_timer = PHY_SW_TIMER_GLACIAL;
509 sh->rssi_mode = RSSI_ANT_MERGE_MAX;
514 void wlc_phy_shared_detach(shared_phy_t *phy_sh)
521 wlc_phy_t *wlc_phy_attach(shared_phy_t *sh, void *regs, int bandtype,
522 char *vars, struct wiphy *wiphy)
529 if (D11REV_IS(sh->corerev, 4))
530 sflags = SISF_2G_PHY | SISF_5G_PHY;
532 sflags = ai_core_sflags(sh->sih, 0, 0);
534 if (BAND_5G(bandtype)) {
535 if ((sflags & (SISF_5G_PHY | SISF_DB_PHY)) == 0) {
541 if ((sflags & SISF_DB_PHY) && pi) {
543 wlapi_bmac_corereset(pi->sh->physhim, pi->pubpi.coreflags);
545 return &pi->pubpi_ro;
548 pi = kzalloc(sizeof(phy_info_t), GFP_ATOMIC);
553 pi->regs = (d11regs_t *) regs;
555 pi->phy_init_por = true;
556 pi->phy_wreg_limit = PHY_WREG_LIMIT;
560 pi->txpwr_percent = 100;
562 pi->do_initcal = true;
564 pi->phycal_tempdelta = 0;
566 if (BAND_2G(bandtype) && (sflags & SISF_2G_PHY)) {
568 pi->pubpi.coreflags = SICF_GMODE;
571 wlapi_bmac_corereset(pi->sh->physhim, pi->pubpi.coreflags);
572 phyversion = R_REG(&pi->regs->phyversion);
574 pi->pubpi.phy_type = PHY_TYPE(phyversion);
575 pi->pubpi.phy_rev = phyversion & PV_PV_MASK;
577 if (pi->pubpi.phy_type == PHY_TYPE_LCNXN) {
578 pi->pubpi.phy_type = PHY_TYPE_N;
579 pi->pubpi.phy_rev += LCNXN_BASEREV;
581 pi->pubpi.phy_corenum = PHY_CORE_NUM_2;
582 pi->pubpi.ana_rev = (phyversion & PV_AV_MASK) >> PV_AV_SHIFT;
584 if (!VALID_PHYTYPE(pi->pubpi.phy_type)) {
587 if (BAND_5G(bandtype)) {
592 if (!ISNPHY(pi) && !ISLCNPHY(pi)) {
597 if (ISSIM_ENAB(pi->sh->sih)) {
598 pi->pubpi.radioid = NORADIO_ID;
599 pi->pubpi.radiorev = 5;
603 wlc_phy_anacore((wlc_phy_t *) pi, ON);
605 idcode = wlc_phy_get_radio_ver(pi);
607 (idcode & IDCODE_ID_MASK) >> IDCODE_ID_SHIFT;
609 (idcode & IDCODE_REV_MASK) >> IDCODE_REV_SHIFT;
611 (idcode & IDCODE_VER_MASK) >> IDCODE_VER_SHIFT;
612 if (!VALID_RADIO(pi, pi->pubpi.radioid)) {
616 wlc_phy_switch_radio((wlc_phy_t *) pi, OFF);
619 wlc_set_phy_uninitted(pi);
621 pi->bw = WL_CHANSPEC_BW_20;
623 BAND_2G(bandtype) ? CH20MHZ_CHSPEC(1) : CH20MHZ_CHSPEC(36);
625 pi->rxiq_samps = PHY_NOISE_SAMPLE_LOG_NUM_NPHY;
626 pi->rxiq_antsel = ANT_RX_DIV_DEF;
628 pi->watchdog_override = true;
630 pi->cal_type_override = PHY_PERICAL_AUTO;
632 pi->nphy_saved_noisevars.bufcount = 0;
635 pi->min_txpower = PHY_TXPWR_MIN_NPHY;
637 pi->min_txpower = PHY_TXPWR_MIN;
639 pi->sh->phyrxchain = 0x3;
641 pi->rx2tx_biasentry = -1;
643 pi->phy_txcore_disable_temp = PHY_CHAIN_TX_DISABLE_TEMP;
644 pi->phy_txcore_enable_temp =
645 PHY_CHAIN_TX_DISABLE_TEMP - PHY_HYSTERESIS_DELTATEMP;
646 pi->phy_tempsense_offset = 0;
647 pi->phy_txcore_heatedup = false;
649 pi->nphy_lastcal_temp = -50;
651 pi->phynoise_polling = true;
652 if (ISNPHY(pi) || ISLCNPHY(pi))
653 pi->phynoise_polling = false;
655 for (i = 0; i < TXP_NUM_RATES; i++) {
656 pi->txpwr_limit[i] = WLC_TXPWR_MAX;
657 pi->txpwr_env_limit[i] = WLC_TXPWR_MAX;
658 pi->tx_user_target[i] = WLC_TXPWR_MAX;
661 pi->radiopwr_override = RADIOPWR_OVERRIDE_DEF;
663 pi->user_txpwr_at_rfport = false;
667 pi->phycal_timer = wlapi_init_timer(pi->sh->physhim,
668 wlc_phy_timercb_phycal,
670 if (!pi->phycal_timer) {
674 if (!wlc_phy_attach_nphy(pi))
677 } else if (ISLCNPHY(pi)) {
678 if (!wlc_phy_attach_lcnphy(pi))
686 pi->next = pi->sh->phy_head;
689 pi->vars = (char *)&pi->vars;
691 memcpy(&pi->pubpi_ro, &pi->pubpi, sizeof(wlc_phy_t));
693 return &pi->pubpi_ro;
700 void wlc_phy_detach(wlc_phy_t *pih)
702 phy_info_t *pi = (phy_info_t *) pih;
709 if (pi->phycal_timer) {
710 wlapi_free_timer(pi->sh->physhim, pi->phycal_timer);
711 pi->phycal_timer = NULL;
714 if (pi->sh->phy_head == pi)
715 pi->sh->phy_head = pi->next;
716 else if (pi->sh->phy_head->next == pi)
717 pi->sh->phy_head->next = NULL;
719 if (pi->pi_fptr.detach)
720 (pi->pi_fptr.detach) (pi);
727 wlc_phy_get_phyversion(wlc_phy_t *pih, u16 *phytype, u16 *phyrev,
728 u16 *radioid, u16 *radiover)
730 phy_info_t *pi = (phy_info_t *) pih;
731 *phytype = (u16) pi->pubpi.phy_type;
732 *phyrev = (u16) pi->pubpi.phy_rev;
733 *radioid = pi->pubpi.radioid;
734 *radiover = pi->pubpi.radiorev;
739 bool wlc_phy_get_encore(wlc_phy_t *pih)
741 phy_info_t *pi = (phy_info_t *) pih;
742 return pi->pubpi.abgphy_encore;
745 u32 wlc_phy_get_coreflags(wlc_phy_t *pih)
747 phy_info_t *pi = (phy_info_t *) pih;
748 return pi->pubpi.coreflags;
751 static void wlc_phy_timercb_phycal(void *arg)
753 phy_info_t *pi = (phy_info_t *) arg;
756 if (PHY_PERICAL_MPHASE_PENDING(pi)) {
758 wlc_phy_cal_perical_mphase_reset(pi);
762 if (SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi)) {
765 wlc_phy_cal_perical_mphase_restart(pi);
767 wlc_phy_cal_perical_nphy_run(pi, PHY_PERICAL_AUTO);
768 wlapi_add_timer(pi->sh->physhim, pi->phycal_timer, delay, 0);
774 void wlc_phy_anacore(wlc_phy_t *pih, bool on)
776 phy_info_t *pi = (phy_info_t *) pih;
780 if (NREV_GE(pi->pubpi.phy_rev, 3)) {
781 write_phy_reg(pi, 0xa6, 0x0d);
782 write_phy_reg(pi, 0x8f, 0x0);
783 write_phy_reg(pi, 0xa7, 0x0d);
784 write_phy_reg(pi, 0xa5, 0x0);
786 write_phy_reg(pi, 0xa5, 0x0);
789 if (NREV_GE(pi->pubpi.phy_rev, 3)) {
790 write_phy_reg(pi, 0x8f, 0x07ff);
791 write_phy_reg(pi, 0xa6, 0x0fd);
792 write_phy_reg(pi, 0xa5, 0x07ff);
793 write_phy_reg(pi, 0xa7, 0x0fd);
795 write_phy_reg(pi, 0xa5, 0x7fff);
798 } else if (ISLCNPHY(pi)) {
800 and_phy_reg(pi, 0x43b,
801 ~((0x1 << 0) | (0x1 << 1) | (0x1 << 2)));
803 or_phy_reg(pi, 0x43c,
804 (0x1 << 0) | (0x1 << 1) | (0x1 << 2));
805 or_phy_reg(pi, 0x43b,
806 (0x1 << 0) | (0x1 << 1) | (0x1 << 2));
811 u32 wlc_phy_clk_bwbits(wlc_phy_t *pih)
813 phy_info_t *pi = (phy_info_t *) pih;
815 u32 phy_bw_clkbits = 0;
817 if (pi && (ISNPHY(pi) || ISLCNPHY(pi))) {
819 case WL_CHANSPEC_BW_10:
820 phy_bw_clkbits = SICF_BW10;
822 case WL_CHANSPEC_BW_20:
823 phy_bw_clkbits = SICF_BW20;
825 case WL_CHANSPEC_BW_40:
826 phy_bw_clkbits = SICF_BW40;
833 return phy_bw_clkbits;
836 void WLBANDINITFN(wlc_phy_por_inform) (wlc_phy_t *ppi)
838 phy_info_t *pi = (phy_info_t *) ppi;
840 pi->phy_init_por = true;
843 void wlc_phy_edcrs_lock(wlc_phy_t *pih, bool lock)
845 phy_info_t *pi = (phy_info_t *) pih;
847 pi->edcrs_threshold_lock = lock;
849 write_phy_reg(pi, 0x22c, 0x46b);
850 write_phy_reg(pi, 0x22d, 0x46b);
851 write_phy_reg(pi, 0x22e, 0x3c0);
852 write_phy_reg(pi, 0x22f, 0x3c0);
855 void wlc_phy_initcal_enable(wlc_phy_t *pih, bool initcal)
857 phy_info_t *pi = (phy_info_t *) pih;
859 pi->do_initcal = initcal;
862 void wlc_phy_hw_clk_state_upd(wlc_phy_t *pih, bool newstate)
864 phy_info_t *pi = (phy_info_t *) pih;
869 pi->sh->clk = newstate;
872 void wlc_phy_hw_state_upd(wlc_phy_t *pih, bool newstate)
874 phy_info_t *pi = (phy_info_t *) pih;
879 pi->sh->up = newstate;
882 void WLBANDINITFN(wlc_phy_init) (wlc_phy_t *pih, chanspec_t chanspec)
885 initfn_t phy_init = NULL;
886 phy_info_t *pi = (phy_info_t *) pih;
888 if (pi->init_in_progress)
891 pi->init_in_progress = true;
893 pi->radio_chanspec = chanspec;
895 mc = R_REG(&pi->regs->maccontrol);
896 if (WARN(mc & MCTL_EN_MAC, "HW error MAC running on init"))
899 if (!(pi->measure_hold & PHY_HOLD_FOR_SCAN)) {
900 pi->measure_hold |= PHY_HOLD_FOR_NOT_ASSOC;
903 if (WARN(!(ai_core_sflags(pi->sh->sih, 0, 0) & SISF_FCLKA),
904 "HW error SISF_FCLKA\n"))
907 phy_init = pi->pi_fptr.init;
909 if (phy_init == NULL) {
913 wlc_phy_anacore(pih, ON);
915 if (CHSPEC_BW(pi->radio_chanspec) != pi->bw)
916 wlapi_bmac_bw_set(pi->sh->physhim,
917 CHSPEC_BW(pi->radio_chanspec));
919 pi->nphy_gain_boost = true;
921 wlc_phy_switch_radio((wlc_phy_t *) pi, ON);
925 pi->phy_init_por = false;
927 if (D11REV_IS(pi->sh->corerev, 11) || D11REV_IS(pi->sh->corerev, 12))
928 wlc_phy_do_dummy_tx(pi, true, OFF);
931 wlc_phy_txpower_update_shm(pi);
933 wlc_phy_ant_rxdiv_set((wlc_phy_t *) pi, pi->sh->rx_antdiv);
935 pi->init_in_progress = false;
938 void wlc_phy_cal_init(wlc_phy_t *pih)
940 phy_info_t *pi = (phy_info_t *) pih;
941 initfn_t cal_init = NULL;
943 if (WARN((R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC) != 0,
944 "HW error: MAC enabled during phy cal\n"))
947 if (!pi->initialized) {
948 cal_init = pi->pi_fptr.calinit;
952 pi->initialized = true;
956 int wlc_phy_down(wlc_phy_t *pih)
958 phy_info_t *pi = (phy_info_t *) pih;
962 && !wlapi_del_timer(pi->sh->physhim, pi->phycal_timer))
965 pi->nphy_iqcal_chanspec_2G = 0;
966 pi->nphy_iqcal_chanspec_5G = 0;
971 static u32 wlc_phy_get_radio_ver(phy_info_t *pi)
975 ver = read_radio_id(pi);
981 wlc_phy_table_addr(phy_info_t *pi, uint tbl_id, uint tbl_offset,
982 u16 tblAddr, u16 tblDataHi, u16 tblDataLo)
984 write_phy_reg(pi, tblAddr, (tbl_id << 10) | tbl_offset);
986 pi->tbl_data_hi = tblDataHi;
987 pi->tbl_data_lo = tblDataLo;
989 if ((pi->sh->chip == BCM43224_CHIP_ID ||
990 pi->sh->chip == BCM43421_CHIP_ID) &&
991 (pi->sh->chiprev == 1)) {
992 pi->tbl_addr = tblAddr;
993 pi->tbl_save_id = tbl_id;
994 pi->tbl_save_offset = tbl_offset;
998 void wlc_phy_table_data_write(phy_info_t *pi, uint width, u32 val)
1000 if ((pi->sh->chip == BCM43224_CHIP_ID ||
1001 pi->sh->chip == BCM43421_CHIP_ID) &&
1002 (pi->sh->chiprev == 1) &&
1003 (pi->tbl_save_id == NPHY_TBL_ID_ANTSWCTRLLUT)) {
1004 read_phy_reg(pi, pi->tbl_data_lo);
1006 write_phy_reg(pi, pi->tbl_addr,
1007 (pi->tbl_save_id << 10) | pi->tbl_save_offset);
1008 pi->tbl_save_offset++;
1013 write_phy_reg(pi, pi->tbl_data_hi, (u16) (val >> 16));
1014 write_phy_reg(pi, pi->tbl_data_lo, (u16) val);
1017 write_phy_reg(pi, pi->tbl_data_lo, (u16) val);
1022 wlc_phy_write_table(phy_info_t *pi, const phytbl_info_t *ptbl_info,
1023 u16 tblAddr, u16 tblDataHi, u16 tblDataLo)
1026 uint tbl_id = ptbl_info->tbl_id;
1027 uint tbl_offset = ptbl_info->tbl_offset;
1028 uint tbl_width = ptbl_info->tbl_width;
1029 const u8 *ptbl_8b = (const u8 *)ptbl_info->tbl_ptr;
1030 const u16 *ptbl_16b = (const u16 *)ptbl_info->tbl_ptr;
1031 const u32 *ptbl_32b = (const u32 *)ptbl_info->tbl_ptr;
1033 write_phy_reg(pi, tblAddr, (tbl_id << 10) | tbl_offset);
1035 for (idx = 0; idx < ptbl_info->tbl_len; idx++) {
1037 if ((pi->sh->chip == BCM43224_CHIP_ID ||
1038 pi->sh->chip == BCM43421_CHIP_ID) &&
1039 (pi->sh->chiprev == 1) &&
1040 (tbl_id == NPHY_TBL_ID_ANTSWCTRLLUT)) {
1041 read_phy_reg(pi, tblDataLo);
1043 write_phy_reg(pi, tblAddr,
1044 (tbl_id << 10) | (tbl_offset + idx));
1047 if (tbl_width == 32) {
1049 write_phy_reg(pi, tblDataHi,
1050 (u16) (ptbl_32b[idx] >> 16));
1051 write_phy_reg(pi, tblDataLo, (u16) ptbl_32b[idx]);
1052 } else if (tbl_width == 16) {
1054 write_phy_reg(pi, tblDataLo, ptbl_16b[idx]);
1057 write_phy_reg(pi, tblDataLo, ptbl_8b[idx]);
1063 wlc_phy_read_table(phy_info_t *pi, const phytbl_info_t *ptbl_info,
1064 u16 tblAddr, u16 tblDataHi, u16 tblDataLo)
1067 uint tbl_id = ptbl_info->tbl_id;
1068 uint tbl_offset = ptbl_info->tbl_offset;
1069 uint tbl_width = ptbl_info->tbl_width;
1070 u8 *ptbl_8b = (u8 *)ptbl_info->tbl_ptr;
1071 u16 *ptbl_16b = (u16 *)ptbl_info->tbl_ptr;
1072 u32 *ptbl_32b = (u32 *)ptbl_info->tbl_ptr;
1074 write_phy_reg(pi, tblAddr, (tbl_id << 10) | tbl_offset);
1076 for (idx = 0; idx < ptbl_info->tbl_len; idx++) {
1078 if ((pi->sh->chip == BCM43224_CHIP_ID ||
1079 pi->sh->chip == BCM43421_CHIP_ID) &&
1080 (pi->sh->chiprev == 1)) {
1081 (void)read_phy_reg(pi, tblDataLo);
1083 write_phy_reg(pi, tblAddr,
1084 (tbl_id << 10) | (tbl_offset + idx));
1087 if (tbl_width == 32) {
1089 ptbl_32b[idx] = read_phy_reg(pi, tblDataLo);
1090 ptbl_32b[idx] |= (read_phy_reg(pi, tblDataHi) << 16);
1091 } else if (tbl_width == 16) {
1093 ptbl_16b[idx] = read_phy_reg(pi, tblDataLo);
1096 ptbl_8b[idx] = (u8) read_phy_reg(pi, tblDataLo);
1102 wlc_phy_init_radio_regs_allbands(phy_info_t *pi, radio_20xx_regs_t *radioregs)
1107 if (radioregs[i].do_init) {
1108 write_radio_reg(pi, radioregs[i].address,
1109 (u16) radioregs[i].init);
1113 } while (radioregs[i].address != 0xffff);
1119 wlc_phy_init_radio_regs(phy_info_t *pi, radio_regs_t *radioregs,
1126 if (CHSPEC_IS5G(pi->radio_chanspec)) {
1127 if (radioregs[i].do_init_a) {
1130 address | core_offset,
1131 (u16) radioregs[i].init_a);
1132 if (ISNPHY(pi) && (++count % 4 == 0))
1133 WLC_PHY_WAR_PR51571(pi);
1136 if (radioregs[i].do_init_g) {
1139 address | core_offset,
1140 (u16) radioregs[i].init_g);
1141 if (ISNPHY(pi) && (++count % 4 == 0))
1142 WLC_PHY_WAR_PR51571(pi);
1147 } while (radioregs[i].address != 0xffff);
1152 void wlc_phy_do_dummy_tx(phy_info_t *pi, bool ofdm, bool pa_on)
1154 #define DUMMY_PKT_LEN 20
1155 d11regs_t *regs = pi->regs;
1157 u8 ofdmpkt[DUMMY_PKT_LEN] = {
1158 0xcc, 0x01, 0x02, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00,
1159 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00
1161 u8 cckpkt[DUMMY_PKT_LEN] = {
1162 0x6e, 0x84, 0x0b, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00,
1163 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00
1167 dummypkt = (u32 *) (ofdm ? ofdmpkt : cckpkt);
1168 wlapi_bmac_write_template_ram(pi->sh->physhim, 0, DUMMY_PKT_LEN,
1171 W_REG(®s->xmtsel, 0);
1173 if (D11REV_GE(pi->sh->corerev, 11))
1174 W_REG(®s->wepctl, 0x100);
1176 W_REG(®s->wepctl, 0);
1178 W_REG(®s->txe_phyctl, (ofdm ? 1 : 0) | PHY_TXC_ANT_0);
1179 if (ISNPHY(pi) || ISLCNPHY(pi)) {
1180 W_REG(®s->txe_phyctl1, 0x1A02);
1183 W_REG(®s->txe_wm_0, 0);
1184 W_REG(®s->txe_wm_1, 0);
1186 W_REG(®s->xmttplatetxptr, 0);
1187 W_REG(®s->xmttxcnt, DUMMY_PKT_LEN);
1189 W_REG(®s->xmtsel, ((8 << 8) | (1 << 5) | (1 << 2) | 2));
1191 W_REG(®s->txe_ctl, 0);
1195 wlc_phy_pa_override_nphy(pi, OFF);
1198 if (ISNPHY(pi) || ISLCNPHY(pi))
1199 W_REG(®s->txe_aux, 0xD0);
1201 W_REG(®s->txe_aux, ((1 << 5) | (1 << 4)));
1203 (void)R_REG(®s->txe_aux);
1206 count = ofdm ? 30 : 250;
1208 if (ISSIM_ENAB(pi->sh->sih)) {
1212 while ((i++ < count)
1213 && (R_REG(®s->txe_status) & (1 << 7))) {
1220 && ((R_REG(®s->txe_status) & (1 << 10)) == 0)) {
1226 while ((i++ < 10) && ((R_REG(®s->ifsstat) & (1 << 8))))
1231 wlc_phy_pa_override_nphy(pi, ON);
1235 void wlc_phy_hold_upd(wlc_phy_t *pih, mbool id, bool set)
1237 phy_info_t *pi = (phy_info_t *) pih;
1240 mboolset(pi->measure_hold, id);
1242 mboolclr(pi->measure_hold, id);
1248 void wlc_phy_mute_upd(wlc_phy_t *pih, bool mute, mbool flags)
1250 phy_info_t *pi = (phy_info_t *) pih;
1253 mboolset(pi->measure_hold, PHY_HOLD_FOR_MUTE);
1255 mboolclr(pi->measure_hold, PHY_HOLD_FOR_MUTE);
1258 if (!mute && (flags & PHY_MUTE_FOR_PREISM))
1259 pi->nphy_perical_last = pi->sh->now - pi->sh->glacial_timer;
1263 void wlc_phy_clear_tssi(wlc_phy_t *pih)
1265 phy_info_t *pi = (phy_info_t *) pih;
1270 wlapi_bmac_write_shm(pi->sh->physhim, M_B_TSSI_0, NULL_TSSI_W);
1271 wlapi_bmac_write_shm(pi->sh->physhim, M_B_TSSI_1, NULL_TSSI_W);
1272 wlapi_bmac_write_shm(pi->sh->physhim, M_G_TSSI_0, NULL_TSSI_W);
1273 wlapi_bmac_write_shm(pi->sh->physhim, M_G_TSSI_1, NULL_TSSI_W);
1277 static bool wlc_phy_cal_txpower_recalc_sw(phy_info_t *pi)
1282 void wlc_phy_switch_radio(wlc_phy_t *pih, bool on)
1284 phy_info_t *pi = (phy_info_t *) pih;
1286 if (NORADIO_ENAB(pi->pubpi))
1292 mc = R_REG(&pi->regs->maccontrol);
1296 wlc_phy_switch_radio_nphy(pi, on);
1298 } else if (ISLCNPHY(pi)) {
1300 and_phy_reg(pi, 0x44c,
1303 (0x1 << 10) | (0x1 << 11) | (0x1 << 12)));
1304 and_phy_reg(pi, 0x4b0, ~((0x1 << 3) | (0x1 << 11)));
1305 and_phy_reg(pi, 0x4f9, ~(0x1 << 3));
1307 and_phy_reg(pi, 0x44d,
1310 (0x1 << 12) | (0x1 << 13) | (0x1 << 14)));
1311 or_phy_reg(pi, 0x44c,
1314 (0x1 << 10) | (0x1 << 11) | (0x1 << 12));
1316 and_phy_reg(pi, 0x4b7, ~((0x7f << 8)));
1317 and_phy_reg(pi, 0x4b1, ~((0x1 << 13)));
1318 or_phy_reg(pi, 0x4b0, (0x1 << 3) | (0x1 << 11));
1319 and_phy_reg(pi, 0x4fa, ~((0x1 << 3)));
1320 or_phy_reg(pi, 0x4f9, (0x1 << 3));
1325 u16 wlc_phy_bw_state_get(wlc_phy_t *ppi)
1327 phy_info_t *pi = (phy_info_t *) ppi;
1332 void wlc_phy_bw_state_set(wlc_phy_t *ppi, u16 bw)
1334 phy_info_t *pi = (phy_info_t *) ppi;
1339 void wlc_phy_chanspec_radio_set(wlc_phy_t *ppi, chanspec_t newch)
1341 phy_info_t *pi = (phy_info_t *) ppi;
1342 pi->radio_chanspec = newch;
1346 chanspec_t wlc_phy_chanspec_get(wlc_phy_t *ppi)
1348 phy_info_t *pi = (phy_info_t *) ppi;
1350 return pi->radio_chanspec;
1353 void wlc_phy_chanspec_set(wlc_phy_t *ppi, chanspec_t chanspec)
1355 phy_info_t *pi = (phy_info_t *) ppi;
1357 chansetfn_t chanspec_set = NULL;
1359 m_cur_channel = CHSPEC_CHANNEL(chanspec);
1360 if (CHSPEC_IS5G(chanspec))
1361 m_cur_channel |= D11_CURCHANNEL_5G;
1362 if (CHSPEC_IS40(chanspec))
1363 m_cur_channel |= D11_CURCHANNEL_40;
1364 wlapi_bmac_write_shm(pi->sh->physhim, M_CURCHANNEL, m_cur_channel);
1366 chanspec_set = pi->pi_fptr.chanset;
1368 (*chanspec_set) (pi, chanspec);
1372 int wlc_phy_chanspec_freq2bandrange_lpssn(uint freq)
1377 range = WL_CHAN_FREQ_RANGE_2G;
1378 else if (freq <= 5320)
1379 range = WL_CHAN_FREQ_RANGE_5GL;
1380 else if (freq <= 5700)
1381 range = WL_CHAN_FREQ_RANGE_5GM;
1383 range = WL_CHAN_FREQ_RANGE_5GH;
1388 int wlc_phy_chanspec_bandrange_get(phy_info_t *pi, chanspec_t chanspec)
1391 uint channel = CHSPEC_CHANNEL(chanspec);
1392 uint freq = wlc_phy_channel2freq(channel);
1395 range = wlc_phy_get_chan_freq_range_nphy(pi, channel);
1396 } else if (ISLCNPHY(pi)) {
1397 range = wlc_phy_chanspec_freq2bandrange_lpssn(freq);
1403 void wlc_phy_chanspec_ch14_widefilter_set(wlc_phy_t *ppi, bool wide_filter)
1405 phy_info_t *pi = (phy_info_t *) ppi;
1407 pi->channel_14_wide_filter = wide_filter;
1411 int wlc_phy_channel2freq(uint channel)
1415 for (i = 0; i < ARRAY_SIZE(chan_info_all); i++)
1416 if (chan_info_all[i].chan == channel)
1417 return chan_info_all[i].freq;
1422 wlc_phy_chanspec_band_validch(wlc_phy_t *ppi, uint band, chanvec_t *channels)
1424 phy_info_t *pi = (phy_info_t *) ppi;
1428 memset(channels, 0, sizeof(chanvec_t));
1430 for (i = 0; i < ARRAY_SIZE(chan_info_all); i++) {
1431 channel = chan_info_all[i].chan;
1433 if ((pi->a_band_high_disable) && (channel >= FIRST_REF5_CHANNUM)
1434 && (channel <= LAST_REF5_CHANNUM))
1437 if (((band == WLC_BAND_2G) && (channel <= CH_MAX_2G_CHANNEL)) ||
1438 ((band == WLC_BAND_5G) && (channel > CH_MAX_2G_CHANNEL)))
1439 setbit(channels->vec, channel);
1443 chanspec_t wlc_phy_chanspec_band_firstch(wlc_phy_t *ppi, uint band)
1445 phy_info_t *pi = (phy_info_t *) ppi;
1450 for (i = 0; i < ARRAY_SIZE(chan_info_all); i++) {
1451 channel = chan_info_all[i].chan;
1453 if (ISNPHY(pi) && IS40MHZ(pi)) {
1456 for (j = 0; j < ARRAY_SIZE(chan_info_all); j++) {
1457 if (chan_info_all[j].chan ==
1458 channel + CH_10MHZ_APART)
1462 if (j == ARRAY_SIZE(chan_info_all))
1465 channel = UPPER_20_SB(channel);
1467 channel | WL_CHANSPEC_BW_40 |
1468 WL_CHANSPEC_CTL_SB_LOWER;
1469 if (band == WLC_BAND_2G)
1470 chspec |= WL_CHANSPEC_BAND_2G;
1472 chspec |= WL_CHANSPEC_BAND_5G;
1474 chspec = CH20MHZ_CHSPEC(channel);
1476 if ((pi->a_band_high_disable) && (channel >= FIRST_REF5_CHANNUM)
1477 && (channel <= LAST_REF5_CHANNUM))
1480 if (((band == WLC_BAND_2G) && (channel <= CH_MAX_2G_CHANNEL)) ||
1481 ((band == WLC_BAND_5G) && (channel > CH_MAX_2G_CHANNEL)))
1485 return (chanspec_t) INVCHANSPEC;
1488 int wlc_phy_txpower_get(wlc_phy_t *ppi, uint *qdbm, bool *override)
1490 phy_info_t *pi = (phy_info_t *) ppi;
1492 *qdbm = pi->tx_user_target[0];
1493 if (override != NULL)
1494 *override = pi->txpwroverride;
1498 void wlc_phy_txpower_target_set(wlc_phy_t *ppi, struct txpwr_limits *txpwr)
1500 bool mac_enabled = false;
1501 phy_info_t *pi = (phy_info_t *) ppi;
1503 memcpy(&pi->tx_user_target[TXP_FIRST_CCK],
1504 &txpwr->cck[0], WLC_NUM_RATES_CCK);
1506 memcpy(&pi->tx_user_target[TXP_FIRST_OFDM],
1507 &txpwr->ofdm[0], WLC_NUM_RATES_OFDM);
1508 memcpy(&pi->tx_user_target[TXP_FIRST_OFDM_20_CDD],
1509 &txpwr->ofdm_cdd[0], WLC_NUM_RATES_OFDM);
1511 memcpy(&pi->tx_user_target[TXP_FIRST_OFDM_40_SISO],
1512 &txpwr->ofdm_40_siso[0], WLC_NUM_RATES_OFDM);
1513 memcpy(&pi->tx_user_target[TXP_FIRST_OFDM_40_CDD],
1514 &txpwr->ofdm_40_cdd[0], WLC_NUM_RATES_OFDM);
1516 memcpy(&pi->tx_user_target[TXP_FIRST_MCS_20_SISO],
1517 &txpwr->mcs_20_siso[0], WLC_NUM_RATES_MCS_1_STREAM);
1518 memcpy(&pi->tx_user_target[TXP_FIRST_MCS_20_CDD],
1519 &txpwr->mcs_20_cdd[0], WLC_NUM_RATES_MCS_1_STREAM);
1520 memcpy(&pi->tx_user_target[TXP_FIRST_MCS_20_STBC],
1521 &txpwr->mcs_20_stbc[0], WLC_NUM_RATES_MCS_1_STREAM);
1522 memcpy(&pi->tx_user_target[TXP_FIRST_MCS_20_SDM],
1523 &txpwr->mcs_20_mimo[0], WLC_NUM_RATES_MCS_2_STREAM);
1525 memcpy(&pi->tx_user_target[TXP_FIRST_MCS_40_SISO],
1526 &txpwr->mcs_40_siso[0], WLC_NUM_RATES_MCS_1_STREAM);
1527 memcpy(&pi->tx_user_target[TXP_FIRST_MCS_40_CDD],
1528 &txpwr->mcs_40_cdd[0], WLC_NUM_RATES_MCS_1_STREAM);
1529 memcpy(&pi->tx_user_target[TXP_FIRST_MCS_40_STBC],
1530 &txpwr->mcs_40_stbc[0], WLC_NUM_RATES_MCS_1_STREAM);
1531 memcpy(&pi->tx_user_target[TXP_FIRST_MCS_40_SDM],
1532 &txpwr->mcs_40_mimo[0], WLC_NUM_RATES_MCS_2_STREAM);
1534 if (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC)
1538 wlapi_suspend_mac_and_wait(pi->sh->physhim);
1540 wlc_phy_txpower_recalc_target(pi);
1541 wlc_phy_cal_txpower_recalc_sw(pi);
1544 wlapi_enable_mac(pi->sh->physhim);
1547 int wlc_phy_txpower_set(wlc_phy_t *ppi, uint qdbm, bool override)
1549 phy_info_t *pi = (phy_info_t *) ppi;
1555 for (i = 0; i < TXP_NUM_RATES; i++)
1556 pi->tx_user_target[i] = (u8) qdbm;
1558 pi->txpwroverride = false;
1561 if (!SCAN_INPROG_PHY(pi)) {
1566 (R_REG(&pi->regs->maccontrol) &
1570 wlapi_suspend_mac_and_wait(pi->sh->physhim);
1572 wlc_phy_txpower_recalc_target(pi);
1573 wlc_phy_cal_txpower_recalc_sw(pi);
1576 wlapi_enable_mac(pi->sh->physhim);
1583 wlc_phy_txpower_sromlimit(wlc_phy_t *ppi, uint channel, u8 *min_pwr,
1584 u8 *max_pwr, int txp_rate_idx)
1586 phy_info_t *pi = (phy_info_t *) ppi;
1589 *min_pwr = pi->min_txpower * WLC_TXPWR_DB_FACTOR;
1592 if (txp_rate_idx < 0)
1593 txp_rate_idx = TXP_FIRST_CCK;
1594 wlc_phy_txpower_sromlimit_get_nphy(pi, channel, max_pwr,
1597 } else if ((channel <= CH_MAX_2G_CHANNEL)) {
1598 if (txp_rate_idx < 0)
1599 txp_rate_idx = TXP_FIRST_CCK;
1600 *max_pwr = pi->tx_srom_max_rate_2g[txp_rate_idx];
1603 *max_pwr = WLC_TXPWR_MAX;
1605 if (txp_rate_idx < 0)
1606 txp_rate_idx = TXP_FIRST_OFDM;
1608 for (i = 0; i < ARRAY_SIZE(chan_info_all); i++) {
1609 if (channel == chan_info_all[i].chan) {
1615 *max_pwr = pi->hwtxpwr[i];
1618 if ((i >= FIRST_MID_5G_CHAN) && (i <= LAST_MID_5G_CHAN))
1620 pi->tx_srom_max_rate_5g_mid[txp_rate_idx];
1621 if ((i >= FIRST_HIGH_5G_CHAN)
1622 && (i <= LAST_HIGH_5G_CHAN))
1624 pi->tx_srom_max_rate_5g_hi[txp_rate_idx];
1625 if ((i >= FIRST_LOW_5G_CHAN) && (i <= LAST_LOW_5G_CHAN))
1627 pi->tx_srom_max_rate_5g_low[txp_rate_idx];
1633 wlc_phy_txpower_sromlimit_max_get(wlc_phy_t *ppi, uint chan, u8 *max_txpwr,
1636 phy_info_t *pi = (phy_info_t *) ppi;
1638 u8 tx_pwr_min = 255;
1640 u8 maxtxpwr, mintxpwr, rate, pactrl;
1644 max_num_rate = ISNPHY(pi) ? TXP_NUM_RATES :
1645 ISLCNPHY(pi) ? (TXP_LAST_SISO_MCS_20 + 1) : (TXP_LAST_OFDM + 1);
1647 for (rate = 0; rate < max_num_rate; rate++) {
1649 wlc_phy_txpower_sromlimit(ppi, chan, &mintxpwr, &maxtxpwr,
1652 maxtxpwr = (maxtxpwr > pactrl) ? (maxtxpwr - pactrl) : 0;
1654 maxtxpwr = (maxtxpwr > 6) ? (maxtxpwr - 6) : 0;
1656 tx_pwr_max = max(tx_pwr_max, maxtxpwr);
1657 tx_pwr_min = min(tx_pwr_min, maxtxpwr);
1659 *max_txpwr = tx_pwr_max;
1660 *min_txpwr = tx_pwr_min;
1664 wlc_phy_txpower_boardlimit_band(wlc_phy_t *ppi, uint bandunit, s32 *max_pwr,
1665 s32 *min_pwr, u32 *step_pwr)
1670 u8 wlc_phy_txpower_get_target_min(wlc_phy_t *ppi)
1672 phy_info_t *pi = (phy_info_t *) ppi;
1674 return pi->tx_power_min;
1677 u8 wlc_phy_txpower_get_target_max(wlc_phy_t *ppi)
1679 phy_info_t *pi = (phy_info_t *) ppi;
1681 return pi->tx_power_max;
1684 void wlc_phy_txpower_recalc_target(phy_info_t *pi)
1686 u8 maxtxpwr, mintxpwr, rate, pactrl;
1688 u8 tx_pwr_target[TXP_NUM_RATES];
1690 u8 tx_pwr_min = 255;
1691 u8 tx_pwr_max_rate_ind = 0;
1695 u32 band = CHSPEC2WLC_BAND(pi->radio_chanspec);
1696 initfn_t txpwr_recalc_fn = NULL;
1698 chspec = pi->radio_chanspec;
1699 if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_NONE)
1700 target_chan = CHSPEC_CHANNEL(chspec);
1701 else if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_UPPER)
1702 target_chan = UPPER_20_SB(CHSPEC_CHANNEL(chspec));
1704 target_chan = LOWER_20_SB(CHSPEC_CHANNEL(chspec));
1710 if (CHSPEC_IS40(pi->radio_chanspec)) {
1711 offset_mcs = pi->mcs40_po;
1712 for (i = TXP_FIRST_SISO_MCS_20;
1713 i <= TXP_LAST_SISO_MCS_20; i++) {
1714 pi->tx_srom_max_rate_2g[i - 8] =
1715 pi->tx_srom_max_2g -
1716 ((offset_mcs & 0xf) * 2);
1720 offset_mcs = pi->mcs20_po;
1721 for (i = TXP_FIRST_SISO_MCS_20;
1722 i <= TXP_LAST_SISO_MCS_20; i++) {
1723 pi->tx_srom_max_rate_2g[i - 8] =
1724 pi->tx_srom_max_2g -
1725 ((offset_mcs & 0xf) * 2);
1731 max_num_rate = ((ISNPHY(pi)) ? (TXP_NUM_RATES) :
1733 (TXP_LAST_SISO_MCS_20 + 1) : (TXP_LAST_OFDM + 1)));
1735 max_num_rate = ((ISNPHY(pi)) ? (TXP_NUM_RATES) : (TXP_LAST_OFDM + 1));
1738 wlc_phy_upd_env_txpwr_rate_limits(pi, band);
1740 for (rate = start_rate; rate < max_num_rate; rate++) {
1742 tx_pwr_target[rate] = pi->tx_user_target[rate];
1744 if (pi->user_txpwr_at_rfport) {
1745 tx_pwr_target[rate] +=
1746 wlc_user_txpwr_antport_to_rfport(pi, target_chan,
1752 wlc_phy_txpower_sromlimit((wlc_phy_t *) pi, target_chan,
1753 &mintxpwr, &maxtxpwr, rate);
1755 maxtxpwr = min(maxtxpwr, pi->txpwr_limit[rate]);
1758 (maxtxpwr > pactrl) ? (maxtxpwr - pactrl) : 0;
1760 maxtxpwr = (maxtxpwr > 6) ? (maxtxpwr - 6) : 0;
1762 maxtxpwr = min(maxtxpwr, tx_pwr_target[rate]);
1764 if (pi->txpwr_percent <= 100)
1765 maxtxpwr = (maxtxpwr * pi->txpwr_percent) / 100;
1767 tx_pwr_target[rate] = max(maxtxpwr, mintxpwr);
1770 tx_pwr_target[rate] =
1771 min(tx_pwr_target[rate], pi->txpwr_env_limit[rate]);
1773 if (tx_pwr_target[rate] > tx_pwr_max)
1774 tx_pwr_max_rate_ind = rate;
1776 tx_pwr_max = max(tx_pwr_max, tx_pwr_target[rate]);
1777 tx_pwr_min = min(tx_pwr_min, tx_pwr_target[rate]);
1780 memset(pi->tx_power_offset, 0, sizeof(pi->tx_power_offset));
1781 pi->tx_power_max = tx_pwr_max;
1782 pi->tx_power_min = tx_pwr_min;
1783 pi->tx_power_max_rate_ind = tx_pwr_max_rate_ind;
1784 for (rate = 0; rate < max_num_rate; rate++) {
1786 pi->tx_power_target[rate] = tx_pwr_target[rate];
1788 if (!pi->hwpwrctrl || ISNPHY(pi)) {
1789 pi->tx_power_offset[rate] =
1790 pi->tx_power_max - pi->tx_power_target[rate];
1792 pi->tx_power_offset[rate] =
1793 pi->tx_power_target[rate] - pi->tx_power_min;
1797 txpwr_recalc_fn = pi->pi_fptr.txpwrrecalc;
1798 if (txpwr_recalc_fn)
1799 (*txpwr_recalc_fn) (pi);
1803 wlc_phy_txpower_reg_limit_calc(phy_info_t *pi, struct txpwr_limits *txpwr,
1804 chanspec_t chanspec)
1806 u8 tmp_txpwr_limit[2 * WLC_NUM_RATES_OFDM];
1807 u8 *txpwr_ptr1 = NULL, *txpwr_ptr2 = NULL;
1808 int rate_start_index = 0, rate1, rate2, k;
1810 for (rate1 = WL_TX_POWER_CCK_FIRST, rate2 = 0;
1811 rate2 < WL_TX_POWER_CCK_NUM; rate1++, rate2++)
1812 pi->txpwr_limit[rate1] = txpwr->cck[rate2];
1814 for (rate1 = WL_TX_POWER_OFDM_FIRST, rate2 = 0;
1815 rate2 < WL_TX_POWER_OFDM_NUM; rate1++, rate2++)
1816 pi->txpwr_limit[rate1] = txpwr->ofdm[rate2];
1820 for (k = 0; k < 4; k++) {
1824 txpwr_ptr1 = txpwr->mcs_20_siso;
1825 txpwr_ptr2 = txpwr->ofdm;
1826 rate_start_index = WL_TX_POWER_OFDM_FIRST;
1830 txpwr_ptr1 = txpwr->mcs_20_cdd;
1831 txpwr_ptr2 = txpwr->ofdm_cdd;
1832 rate_start_index = WL_TX_POWER_OFDM20_CDD_FIRST;
1836 txpwr_ptr1 = txpwr->mcs_40_siso;
1837 txpwr_ptr2 = txpwr->ofdm_40_siso;
1839 WL_TX_POWER_OFDM40_SISO_FIRST;
1843 txpwr_ptr1 = txpwr->mcs_40_cdd;
1844 txpwr_ptr2 = txpwr->ofdm_40_cdd;
1845 rate_start_index = WL_TX_POWER_OFDM40_CDD_FIRST;
1849 for (rate2 = 0; rate2 < WLC_NUM_RATES_OFDM; rate2++) {
1850 tmp_txpwr_limit[rate2] = 0;
1851 tmp_txpwr_limit[WLC_NUM_RATES_OFDM + rate2] =
1854 wlc_phy_mcs_to_ofdm_powers_nphy(tmp_txpwr_limit, 0,
1855 WLC_NUM_RATES_OFDM - 1,
1856 WLC_NUM_RATES_OFDM);
1857 for (rate1 = rate_start_index, rate2 = 0;
1858 rate2 < WLC_NUM_RATES_OFDM; rate1++, rate2++)
1859 pi->txpwr_limit[rate1] =
1860 min(txpwr_ptr2[rate2],
1861 tmp_txpwr_limit[rate2]);
1864 for (k = 0; k < 4; k++) {
1868 txpwr_ptr1 = txpwr->ofdm;
1869 txpwr_ptr2 = txpwr->mcs_20_siso;
1870 rate_start_index = WL_TX_POWER_MCS20_SISO_FIRST;
1874 txpwr_ptr1 = txpwr->ofdm_cdd;
1875 txpwr_ptr2 = txpwr->mcs_20_cdd;
1876 rate_start_index = WL_TX_POWER_MCS20_CDD_FIRST;
1880 txpwr_ptr1 = txpwr->ofdm_40_siso;
1881 txpwr_ptr2 = txpwr->mcs_40_siso;
1882 rate_start_index = WL_TX_POWER_MCS40_SISO_FIRST;
1886 txpwr_ptr1 = txpwr->ofdm_40_cdd;
1887 txpwr_ptr2 = txpwr->mcs_40_cdd;
1888 rate_start_index = WL_TX_POWER_MCS40_CDD_FIRST;
1891 for (rate2 = 0; rate2 < WLC_NUM_RATES_OFDM; rate2++) {
1892 tmp_txpwr_limit[rate2] = 0;
1893 tmp_txpwr_limit[WLC_NUM_RATES_OFDM + rate2] =
1896 wlc_phy_ofdm_to_mcs_powers_nphy(tmp_txpwr_limit, 0,
1897 WLC_NUM_RATES_OFDM - 1,
1898 WLC_NUM_RATES_OFDM);
1899 for (rate1 = rate_start_index, rate2 = 0;
1900 rate2 < WLC_NUM_RATES_MCS_1_STREAM;
1902 pi->txpwr_limit[rate1] =
1903 min(txpwr_ptr2[rate2],
1904 tmp_txpwr_limit[rate2]);
1907 for (k = 0; k < 2; k++) {
1911 rate_start_index = WL_TX_POWER_MCS20_STBC_FIRST;
1912 txpwr_ptr1 = txpwr->mcs_20_stbc;
1916 rate_start_index = WL_TX_POWER_MCS40_STBC_FIRST;
1917 txpwr_ptr1 = txpwr->mcs_40_stbc;
1920 for (rate1 = rate_start_index, rate2 = 0;
1921 rate2 < WLC_NUM_RATES_MCS_1_STREAM;
1923 pi->txpwr_limit[rate1] = txpwr_ptr1[rate2];
1926 for (k = 0; k < 2; k++) {
1930 rate_start_index = WL_TX_POWER_MCS20_SDM_FIRST;
1931 txpwr_ptr1 = txpwr->mcs_20_mimo;
1935 rate_start_index = WL_TX_POWER_MCS40_SDM_FIRST;
1936 txpwr_ptr1 = txpwr->mcs_40_mimo;
1939 for (rate1 = rate_start_index, rate2 = 0;
1940 rate2 < WLC_NUM_RATES_MCS_2_STREAM;
1942 pi->txpwr_limit[rate1] = txpwr_ptr1[rate2];
1945 pi->txpwr_limit[WL_TX_POWER_MCS_32] = txpwr->mcs32;
1947 pi->txpwr_limit[WL_TX_POWER_MCS40_CDD_FIRST] =
1948 min(pi->txpwr_limit[WL_TX_POWER_MCS40_CDD_FIRST],
1949 pi->txpwr_limit[WL_TX_POWER_MCS_32]);
1950 pi->txpwr_limit[WL_TX_POWER_MCS_32] =
1951 pi->txpwr_limit[WL_TX_POWER_MCS40_CDD_FIRST];
1955 void wlc_phy_txpwr_percent_set(wlc_phy_t *ppi, u8 txpwr_percent)
1957 phy_info_t *pi = (phy_info_t *) ppi;
1959 pi->txpwr_percent = txpwr_percent;
1962 void wlc_phy_machwcap_set(wlc_phy_t *ppi, u32 machwcap)
1964 phy_info_t *pi = (phy_info_t *) ppi;
1966 pi->sh->machwcap = machwcap;
1969 void wlc_phy_runbist_config(wlc_phy_t *ppi, bool start_end)
1971 phy_info_t *pi = (phy_info_t *) ppi;
1975 if (start_end == ON) {
1979 if (NREV_IS(pi->pubpi.phy_rev, 3)
1980 || NREV_IS(pi->pubpi.phy_rev, 4)) {
1981 W_REG(&pi->regs->phyregaddr, 0xa0);
1982 (void)R_REG(&pi->regs->phyregaddr);
1983 rxc = R_REG(&pi->regs->phyregdata);
1984 W_REG(&pi->regs->phyregdata,
1988 if (NREV_IS(pi->pubpi.phy_rev, 3)
1989 || NREV_IS(pi->pubpi.phy_rev, 4)) {
1990 W_REG(&pi->regs->phyregaddr, 0xa0);
1991 (void)R_REG(&pi->regs->phyregaddr);
1992 W_REG(&pi->regs->phyregdata, rxc);
1995 wlc_phy_por_inform(ppi);
2000 wlc_phy_txpower_limit_set(wlc_phy_t *ppi, struct txpwr_limits *txpwr,
2001 chanspec_t chanspec)
2003 phy_info_t *pi = (phy_info_t *) ppi;
2005 wlc_phy_txpower_reg_limit_calc(pi, txpwr, chanspec);
2009 for (i = TXP_FIRST_OFDM_20_CDD, j = 0;
2010 j < WLC_NUM_RATES_MCS_1_STREAM; i++, j++) {
2011 if (txpwr->mcs_20_siso[j])
2012 pi->txpwr_limit[i] = txpwr->mcs_20_siso[j];
2014 pi->txpwr_limit[i] = txpwr->ofdm[j];
2018 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2020 wlc_phy_txpower_recalc_target(pi);
2021 wlc_phy_cal_txpower_recalc_sw(pi);
2022 wlapi_enable_mac(pi->sh->physhim);
2025 void wlc_phy_ofdm_rateset_war(wlc_phy_t *pih, bool war)
2027 phy_info_t *pi = (phy_info_t *) pih;
2029 pi->ofdm_rateset_war = war;
2032 void wlc_phy_bf_preempt_enable(wlc_phy_t *pih, bool bf_preempt)
2034 phy_info_t *pi = (phy_info_t *) pih;
2036 pi->bf_preempt_4306 = bf_preempt;
2039 void wlc_phy_txpower_update_shm(phy_info_t *pi)
2049 if (pi->hwpwrctrl) {
2052 wlapi_bmac_write_shm(pi->sh->physhim, M_TXPWR_MAX, 63);
2053 wlapi_bmac_write_shm(pi->sh->physhim, M_TXPWR_N,
2054 1 << NUM_TSSI_FRAMES);
2056 wlapi_bmac_write_shm(pi->sh->physhim, M_TXPWR_TARGET,
2057 pi->tx_power_min << NUM_TSSI_FRAMES);
2059 wlapi_bmac_write_shm(pi->sh->physhim, M_TXPWR_CUR,
2062 for (j = TXP_FIRST_OFDM; j <= TXP_LAST_OFDM; j++) {
2063 const u8 ucode_ofdm_rates[] = {
2064 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c
2066 offset = wlapi_bmac_rate_shm_offset(pi->sh->physhim,
2067 ucode_ofdm_rates[j -
2069 wlapi_bmac_write_shm(pi->sh->physhim, offset + 6,
2070 pi->tx_power_offset[j]);
2071 wlapi_bmac_write_shm(pi->sh->physhim, offset + 14,
2072 -(pi->tx_power_offset[j] / 2));
2075 wlapi_bmac_mhf(pi->sh->physhim, MHF2, MHF2_HWPWRCTL,
2076 MHF2_HWPWRCTL, WLC_BAND_ALL);
2080 for (i = TXP_FIRST_OFDM; i <= TXP_LAST_OFDM; i++)
2081 pi->tx_power_offset[i] =
2082 (u8) roundup(pi->tx_power_offset[i], 8);
2083 wlapi_bmac_write_shm(pi->sh->physhim, M_OFDM_OFFSET,
2085 tx_power_offset[TXP_FIRST_OFDM]
2090 bool wlc_phy_txpower_hw_ctrl_get(wlc_phy_t *ppi)
2092 phy_info_t *pi = (phy_info_t *) ppi;
2095 return pi->nphy_txpwrctrl;
2097 return pi->hwpwrctrl;
2101 void wlc_phy_txpower_hw_ctrl_set(wlc_phy_t *ppi, bool hwpwrctrl)
2103 phy_info_t *pi = (phy_info_t *) ppi;
2104 bool cur_hwpwrctrl = pi->hwpwrctrl;
2107 if (!pi->hwpwrctrl_capable) {
2111 pi->hwpwrctrl = hwpwrctrl;
2112 pi->nphy_txpwrctrl = hwpwrctrl;
2113 pi->txpwrctrl = hwpwrctrl;
2118 (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC));
2120 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2122 wlc_phy_txpwrctrl_enable_nphy(pi, pi->nphy_txpwrctrl);
2123 if (pi->nphy_txpwrctrl == PHY_TPC_HW_OFF) {
2124 wlc_phy_txpwr_fixpower_nphy(pi);
2127 mod_phy_reg(pi, 0x1e7, (0x7f << 0),
2128 pi->saved_txpwr_idx);
2132 wlapi_enable_mac(pi->sh->physhim);
2133 } else if (hwpwrctrl != cur_hwpwrctrl) {
2139 void wlc_phy_txpower_ipa_upd(phy_info_t *pi)
2142 if (NREV_GE(pi->pubpi.phy_rev, 3)) {
2143 pi->ipa2g_on = (pi->srom_fem2g.extpagain == 2);
2144 pi->ipa5g_on = (pi->srom_fem5g.extpagain == 2);
2146 pi->ipa2g_on = false;
2147 pi->ipa5g_on = false;
2151 static u32 wlc_phy_txpower_est_power_nphy(phy_info_t *pi);
2153 static u32 wlc_phy_txpower_est_power_nphy(phy_info_t *pi)
2155 s16 tx0_status, tx1_status;
2156 u16 estPower1, estPower2;
2157 u8 pwr0, pwr1, adj_pwr0, adj_pwr1;
2160 estPower1 = read_phy_reg(pi, 0x118);
2161 estPower2 = read_phy_reg(pi, 0x119);
2163 if ((estPower1 & (0x1 << 8))
2165 pwr0 = (u8) (estPower1 & (0xff << 0))
2171 if ((estPower2 & (0x1 << 8))
2173 pwr1 = (u8) (estPower2 & (0xff << 0))
2179 tx0_status = read_phy_reg(pi, 0x1ed);
2180 tx1_status = read_phy_reg(pi, 0x1ee);
2182 if ((tx0_status & (0x1 << 15))
2184 adj_pwr0 = (u8) (tx0_status & (0xff << 0))
2189 if ((tx1_status & (0x1 << 15))
2191 adj_pwr1 = (u8) (tx1_status & (0xff << 0))
2198 (u32) ((pwr0 << 24) | (pwr1 << 16) | (adj_pwr0 << 8) | adj_pwr1);
2203 wlc_phy_txpower_get_current(wlc_phy_t *ppi, tx_power_t *power, uint channel)
2205 phy_info_t *pi = (phy_info_t *) ppi;
2206 uint rate, num_rates;
2207 u8 min_pwr, max_pwr;
2209 #if WL_TX_POWER_RATES != TXP_NUM_RATES
2210 #error "tx_power_t struct out of sync with this fn"
2214 power->rf_cores = 2;
2215 power->flags |= (WL_TX_POWER_F_MIMO);
2216 if (pi->nphy_txpwrctrl == PHY_TPC_HW_ON)
2218 (WL_TX_POWER_F_ENABLED | WL_TX_POWER_F_HW);
2219 } else if (ISLCNPHY(pi)) {
2220 power->rf_cores = 1;
2221 power->flags |= (WL_TX_POWER_F_SISO);
2222 if (pi->radiopwr_override == RADIOPWR_OVERRIDE_DEF)
2223 power->flags |= WL_TX_POWER_F_ENABLED;
2225 power->flags |= WL_TX_POWER_F_HW;
2228 num_rates = ((ISNPHY(pi)) ? (TXP_NUM_RATES) :
2230 (TXP_LAST_OFDM_20_CDD + 1) : (TXP_LAST_OFDM + 1)));
2232 for (rate = 0; rate < num_rates; rate++) {
2233 power->user_limit[rate] = pi->tx_user_target[rate];
2234 wlc_phy_txpower_sromlimit(ppi, channel, &min_pwr, &max_pwr,
2236 power->board_limit[rate] = (u8) max_pwr;
2237 power->target[rate] = pi->tx_power_target[rate];
2243 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2244 wlc_phyreg_enter((wlc_phy_t *) pi);
2245 est_pout = wlc_phy_txpower_est_power_nphy(pi);
2246 wlc_phyreg_exit((wlc_phy_t *) pi);
2247 wlapi_enable_mac(pi->sh->physhim);
2249 power->est_Pout[0] = (est_pout >> 8) & 0xff;
2250 power->est_Pout[1] = est_pout & 0xff;
2252 power->est_Pout_act[0] = est_pout >> 24;
2253 power->est_Pout_act[1] = (est_pout >> 16) & 0xff;
2255 if (power->est_Pout[0] == 0x80)
2256 power->est_Pout[0] = 0;
2257 if (power->est_Pout[1] == 0x80)
2258 power->est_Pout[1] = 0;
2260 if (power->est_Pout_act[0] == 0x80)
2261 power->est_Pout_act[0] = 0;
2262 if (power->est_Pout_act[1] == 0x80)
2263 power->est_Pout_act[1] = 0;
2265 power->est_Pout_cck = 0;
2267 power->tx_power_max[0] = pi->tx_power_max;
2268 power->tx_power_max[1] = pi->tx_power_max;
2270 power->tx_power_max_rate_ind[0] = pi->tx_power_max_rate_ind;
2271 power->tx_power_max_rate_ind[1] = pi->tx_power_max_rate_ind;
2272 } else if (!pi->hwpwrctrl) {
2273 } else if (pi->sh->up) {
2275 wlc_phyreg_enter(ppi);
2278 power->tx_power_max[0] = pi->tx_power_max;
2279 power->tx_power_max[1] = pi->tx_power_max;
2281 power->tx_power_max_rate_ind[0] =
2282 pi->tx_power_max_rate_ind;
2283 power->tx_power_max_rate_ind[1] =
2284 pi->tx_power_max_rate_ind;
2286 if (wlc_phy_tpc_isenabled_lcnphy(pi))
2288 (WL_TX_POWER_F_HW | WL_TX_POWER_F_ENABLED);
2291 ~(WL_TX_POWER_F_HW | WL_TX_POWER_F_ENABLED);
2293 wlc_lcnphy_get_tssi(pi, (s8 *) &power->est_Pout[0],
2294 (s8 *) &power->est_Pout_cck);
2296 wlc_phyreg_exit(ppi);
2300 void wlc_phy_antsel_type_set(wlc_phy_t *ppi, u8 antsel_type)
2302 phy_info_t *pi = (phy_info_t *) ppi;
2304 pi->antsel_type = antsel_type;
2307 bool wlc_phy_test_ison(wlc_phy_t *ppi)
2309 phy_info_t *pi = (phy_info_t *) ppi;
2311 return pi->phytest_on;
2314 void wlc_phy_ant_rxdiv_set(wlc_phy_t *ppi, u8 val)
2316 phy_info_t *pi = (phy_info_t *) ppi;
2319 pi->sh->rx_antdiv = val;
2321 if (!(ISNPHY(pi) && D11REV_IS(pi->sh->corerev, 16))) {
2322 if (val > ANT_RX_DIV_FORCE_1)
2323 wlapi_bmac_mhf(pi->sh->physhim, MHF1, MHF1_ANTDIV,
2324 MHF1_ANTDIV, WLC_BAND_ALL);
2326 wlapi_bmac_mhf(pi->sh->physhim, MHF1, MHF1_ANTDIV, 0,
2339 (0 == (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC));
2341 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2344 if (val > ANT_RX_DIV_FORCE_1) {
2345 mod_phy_reg(pi, 0x410, (0x1 << 1), 0x01 << 1);
2346 mod_phy_reg(pi, 0x410,
2348 ((ANT_RX_DIV_START_1 == val) ? 1 : 0) << 0);
2350 mod_phy_reg(pi, 0x410, (0x1 << 1), 0x00 << 1);
2351 mod_phy_reg(pi, 0x410, (0x1 << 0), (u16) val << 0);
2356 wlapi_enable_mac(pi->sh->physhim);
2362 wlc_phy_noise_calc_phy(phy_info_t *pi, u32 *cmplx_pwr, s8 *pwr_ant)
2364 s8 cmplx_pwr_dbm[PHY_CORE_MAX];
2367 memset((u8 *) cmplx_pwr_dbm, 0, sizeof(cmplx_pwr_dbm));
2368 wlc_phy_compute_dB(cmplx_pwr, cmplx_pwr_dbm, pi->pubpi.phy_corenum);
2370 for (i = 0; i < pi->pubpi.phy_corenum; i++) {
2371 if (NREV_GE(pi->pubpi.phy_rev, 3))
2372 cmplx_pwr_dbm[i] += (s8) PHY_NOISE_OFFSETFACT_4322;
2375 cmplx_pwr_dbm[i] += (s8) (16 - (15) * 3 - 70);
2378 for (i = 0; i < pi->pubpi.phy_corenum; i++) {
2379 pi->nphy_noise_win[i][pi->nphy_noise_index] = cmplx_pwr_dbm[i];
2380 pwr_ant[i] = cmplx_pwr_dbm[i];
2382 pi->nphy_noise_index =
2383 MODINC_POW2(pi->nphy_noise_index, PHY_NOISE_WINDOW_SZ);
2388 wlc_phy_noise_sample_request(wlc_phy_t *pih, u8 reason, u8 ch)
2390 phy_info_t *pi = (phy_info_t *) pih;
2391 s8 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;
2392 bool sampling_in_progress = (pi->phynoise_state != 0);
2393 bool wait_for_intr = true;
2395 if (NORADIO_ENAB(pi->pubpi)) {
2400 case PHY_NOISE_SAMPLE_MON:
2402 pi->phynoise_chan_watchdog = ch;
2403 pi->phynoise_state |= PHY_NOISE_STATE_MON;
2407 case PHY_NOISE_SAMPLE_EXTERNAL:
2409 pi->phynoise_state |= PHY_NOISE_STATE_EXTERNAL;
2416 if (sampling_in_progress)
2419 pi->phynoise_now = pi->sh->now;
2421 if (pi->phy_fixed_noise) {
2423 pi->nphy_noise_win[WL_ANT_IDX_1][pi->nphy_noise_index] =
2424 PHY_NOISE_FIXED_VAL_NPHY;
2425 pi->nphy_noise_win[WL_ANT_IDX_2][pi->nphy_noise_index] =
2426 PHY_NOISE_FIXED_VAL_NPHY;
2427 pi->nphy_noise_index = MODINC_POW2(pi->nphy_noise_index,
2428 PHY_NOISE_WINDOW_SZ);
2430 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;
2433 noise_dbm = PHY_NOISE_FIXED_VAL;
2436 wait_for_intr = false;
2441 if (!pi->phynoise_polling
2442 || (reason == PHY_NOISE_SAMPLE_EXTERNAL)) {
2443 wlapi_bmac_write_shm(pi->sh->physhim, M_JSSI_0, 0);
2444 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP0, 0);
2445 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP1, 0);
2446 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP2, 0);
2447 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP3, 0);
2449 OR_REG(&pi->regs->maccommand,
2452 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2453 wlc_lcnphy_deaf_mode(pi, (bool) 0);
2454 noise_dbm = (s8) wlc_lcnphy_rx_signal_power(pi, 20);
2455 wlc_lcnphy_deaf_mode(pi, (bool) 1);
2456 wlapi_enable_mac(pi->sh->physhim);
2457 wait_for_intr = false;
2459 } else if (ISNPHY(pi)) {
2460 if (!pi->phynoise_polling
2461 || (reason == PHY_NOISE_SAMPLE_EXTERNAL)) {
2463 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP0, 0);
2464 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP1, 0);
2465 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP2, 0);
2466 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP3, 0);
2468 OR_REG(&pi->regs->maccommand,
2471 phy_iq_est_t est[PHY_CORE_MAX];
2472 u32 cmplx_pwr[PHY_CORE_MAX];
2473 s8 noise_dbm_ant[PHY_CORE_MAX];
2474 u16 log_num_samps, num_samps, classif_state = 0;
2479 memset((u8 *) est, 0, sizeof(est));
2480 memset((u8 *) cmplx_pwr, 0, sizeof(cmplx_pwr));
2481 memset((u8 *) noise_dbm_ant, 0, sizeof(noise_dbm_ant));
2483 log_num_samps = PHY_NOISE_SAMPLE_LOG_NUM_NPHY;
2484 num_samps = 1 << log_num_samps;
2486 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2487 classif_state = wlc_phy_classifier_nphy(pi, 0, 0);
2488 wlc_phy_classifier_nphy(pi, 3, 0);
2489 wlc_phy_rx_iq_est_nphy(pi, est, num_samps, wait_time,
2491 wlc_phy_classifier_nphy(pi, (0x7 << 0), classif_state);
2492 wlapi_enable_mac(pi->sh->physhim);
2494 for (i = 0; i < pi->pubpi.phy_corenum; i++)
2497 est[i].q_pwr) >> log_num_samps;
2499 wlc_phy_noise_calc_phy(pi, cmplx_pwr, noise_dbm_ant);
2501 for (i = 0; i < pi->pubpi.phy_corenum; i++) {
2502 pi->nphy_noise_win[i][pi->nphy_noise_index] =
2505 if (noise_dbm_ant[i] > noise_dbm)
2506 noise_dbm = noise_dbm_ant[i];
2508 pi->nphy_noise_index = MODINC_POW2(pi->nphy_noise_index,
2509 PHY_NOISE_WINDOW_SZ);
2511 wait_for_intr = false;
2518 wlc_phy_noise_cb(pi, ch, noise_dbm);
2522 void wlc_phy_noise_sample_request_external(wlc_phy_t *pih)
2526 channel = CHSPEC_CHANNEL(wlc_phy_chanspec_get(pih));
2528 wlc_phy_noise_sample_request(pih, PHY_NOISE_SAMPLE_EXTERNAL, channel);
2531 static void wlc_phy_noise_cb(phy_info_t *pi, u8 channel, s8 noise_dbm)
2533 if (!pi->phynoise_state)
2536 if (pi->phynoise_state & PHY_NOISE_STATE_MON) {
2537 if (pi->phynoise_chan_watchdog == channel) {
2538 pi->sh->phy_noise_window[pi->sh->phy_noise_index] =
2540 pi->sh->phy_noise_index =
2541 MODINC(pi->sh->phy_noise_index, MA_WINDOW_SZ);
2543 pi->phynoise_state &= ~PHY_NOISE_STATE_MON;
2546 if (pi->phynoise_state & PHY_NOISE_STATE_EXTERNAL) {
2547 pi->phynoise_state &= ~PHY_NOISE_STATE_EXTERNAL;
2552 static s8 wlc_phy_noise_read_shmem(phy_info_t *pi)
2554 u32 cmplx_pwr[PHY_CORE_MAX];
2555 s8 noise_dbm_ant[PHY_CORE_MAX];
2557 u32 cmplx_pwr_tot = 0;
2558 s8 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;
2561 memset((u8 *) cmplx_pwr, 0, sizeof(cmplx_pwr));
2562 memset((u8 *) noise_dbm_ant, 0, sizeof(noise_dbm_ant));
2564 for (idx = 0, core = 0; core < pi->pubpi.phy_corenum; idx += 2, core++) {
2565 lo = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP(idx));
2566 hi = wlapi_bmac_read_shm(pi->sh->physhim,
2567 M_PWRIND_MAP(idx + 1));
2568 cmplx_pwr[core] = (hi << 16) + lo;
2569 cmplx_pwr_tot += cmplx_pwr[core];
2570 if (cmplx_pwr[core] == 0) {
2571 noise_dbm_ant[core] = PHY_NOISE_FIXED_VAL_NPHY;
2573 cmplx_pwr[core] >>= PHY_NOISE_SAMPLE_LOG_NUM_UCODE;
2576 if (cmplx_pwr_tot != 0)
2577 wlc_phy_noise_calc_phy(pi, cmplx_pwr, noise_dbm_ant);
2579 for (core = 0; core < pi->pubpi.phy_corenum; core++) {
2580 pi->nphy_noise_win[core][pi->nphy_noise_index] =
2581 noise_dbm_ant[core];
2583 if (noise_dbm_ant[core] > noise_dbm)
2584 noise_dbm = noise_dbm_ant[core];
2586 pi->nphy_noise_index =
2587 MODINC_POW2(pi->nphy_noise_index, PHY_NOISE_WINDOW_SZ);
2593 void wlc_phy_noise_sample_intr(wlc_phy_t *pih)
2595 phy_info_t *pi = (phy_info_t *) pih;
2598 s8 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;
2601 u32 cmplx_pwr, cmplx_pwr0, cmplx_pwr1;
2603 s32 pwr_offset_dB, gain_dB;
2604 u16 status_0, status_1;
2606 jssi_aux = wlapi_bmac_read_shm(pi->sh->physhim, M_JSSI_AUX);
2607 channel = jssi_aux & D11_CURCHANNEL_MAX;
2609 lo = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP0);
2610 hi = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP1);
2611 cmplx_pwr0 = (hi << 16) + lo;
2613 lo = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP2);
2614 hi = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP3);
2615 cmplx_pwr1 = (hi << 16) + lo;
2616 cmplx_pwr = (cmplx_pwr0 + cmplx_pwr1) >> 6;
2619 status_1 = wlapi_bmac_read_shm(pi->sh->physhim, M_JSSI_0);
2620 if ((cmplx_pwr > 0 && cmplx_pwr < 500)
2621 && ((status_1 & 0xc000) == 0x4000)) {
2623 wlc_phy_compute_dB(&cmplx_pwr, &noise_dbm,
2624 pi->pubpi.phy_corenum);
2625 pwr_offset_dB = (read_phy_reg(pi, 0x434) & 0xFF);
2626 if (pwr_offset_dB > 127)
2627 pwr_offset_dB -= 256;
2629 noise_dbm += (s8) (pwr_offset_dB - 30);
2631 gain_dB = (status_0 & 0x1ff);
2632 noise_dbm -= (s8) (gain_dB);
2634 noise_dbm = PHY_NOISE_FIXED_VAL_LCNPHY;
2636 } else if (ISNPHY(pi)) {
2638 jssi_aux = wlapi_bmac_read_shm(pi->sh->physhim, M_JSSI_AUX);
2639 channel = jssi_aux & D11_CURCHANNEL_MAX;
2641 noise_dbm = wlc_phy_noise_read_shmem(pi);
2644 wlc_phy_noise_cb(pi, channel, noise_dbm);
2648 s8 lcnphy_gain_index_offset_for_pkt_rssi[] = {
2689 void wlc_phy_compute_dB(u32 *cmplx_pwr, s8 *p_cmplx_pwr_dB, u8 core)
2691 u8 msb, secondmsb, i;
2694 for (i = 0; i < core; i++) {
2699 secondmsb = (u8) ((tmp >> (--msb - 1)) & 1);
2700 p_cmplx_pwr_dB[i] = (s8) (3 * msb + 2 * secondmsb);
2704 void wlc_phy_rssi_compute(wlc_phy_t *pih, void *ctx)
2706 wlc_d11rxhdr_t *wlc_rxhdr = (wlc_d11rxhdr_t *) ctx;
2707 d11rxhdr_t *rxh = &wlc_rxhdr->rxhdr;
2708 int rssi = le16_to_cpu(rxh->PhyRxStatus_1) & PRXS1_JSSI_MASK;
2709 uint radioid = pih->radioid;
2710 phy_info_t *pi = (phy_info_t *) pih;
2712 if (NORADIO_ENAB(pi->pubpi)) {
2713 rssi = WLC_RSSI_INVALID;
2717 if ((pi->sh->corerev >= 11)
2718 && !(le16_to_cpu(rxh->RxStatus2) & RXS_PHYRXST_VALID)) {
2719 rssi = WLC_RSSI_INVALID;
2724 u8 gidx = (le16_to_cpu(rxh->PhyRxStatus_2) & 0xFC00) >> 10;
2725 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
2730 rssi = rssi + lcnphy_gain_index_offset_for_pkt_rssi[gidx];
2731 if ((rssi > -46) && (gidx > 18))
2734 rssi = rssi + pi_lcn->lcnphy_pkteng_rssi_slope;
2744 } else if (radioid == BCM2055_ID || radioid == BCM2056_ID
2745 || radioid == BCM2057_ID) {
2746 rssi = wlc_phy_rssi_compute_nphy(pi, wlc_rxhdr);
2750 wlc_rxhdr->rssi = (s8) rssi;
2753 void wlc_phy_freqtrack_start(wlc_phy_t *pih)
2758 void wlc_phy_freqtrack_end(wlc_phy_t *pih)
2763 void wlc_phy_set_deaf(wlc_phy_t *ppi, bool user_flag)
2766 pi = (phy_info_t *) ppi;
2769 wlc_lcnphy_deaf_mode(pi, true);
2770 else if (ISNPHY(pi))
2771 wlc_nphy_deaf_mode(pi, true);
2774 void wlc_phy_watchdog(wlc_phy_t *pih)
2776 phy_info_t *pi = (phy_info_t *) pih;
2777 bool delay_phy_cal = false;
2780 if (!pi->watchdog_override)
2783 if (!(SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi))) {
2784 wlc_phy_noise_sample_request((wlc_phy_t *) pi,
2785 PHY_NOISE_SAMPLE_MON,
2790 if (pi->phynoise_state && (pi->sh->now - pi->phynoise_now) > 5) {
2791 pi->phynoise_state = 0;
2794 if ((!pi->phycal_txpower) ||
2795 ((pi->sh->now - pi->phycal_txpower) >= pi->sh->fast_timer)) {
2797 if (!SCAN_INPROG_PHY(pi) && wlc_phy_cal_txpower_recalc_sw(pi)) {
2798 pi->phycal_txpower = pi->sh->now;
2802 if (NORADIO_ENAB(pi->pubpi))
2805 if ((SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi)
2806 || ASSOC_INPROG_PHY(pi)))
2809 if (ISNPHY(pi) && !pi->disable_percal && !delay_phy_cal) {
2811 if ((pi->nphy_perical != PHY_PERICAL_DISABLE) &&
2812 (pi->nphy_perical != PHY_PERICAL_MANUAL) &&
2813 ((pi->sh->now - pi->nphy_perical_last) >=
2814 pi->sh->glacial_timer))
2815 wlc_phy_cal_perical((wlc_phy_t *) pi,
2816 PHY_PERICAL_WATCHDOG);
2818 wlc_phy_txpwr_papd_cal_nphy(pi);
2822 if (pi->phy_forcecal ||
2823 ((pi->sh->now - pi->phy_lastcal) >=
2824 pi->sh->glacial_timer)) {
2825 if (!(SCAN_RM_IN_PROGRESS(pi) || ASSOC_INPROG_PHY(pi)))
2826 wlc_lcnphy_calib_modes(pi,
2827 LCNPHY_PERICAL_TEMPBASED_TXPWRCTRL);
2829 (SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi)
2830 || ASSOC_INPROG_PHY(pi)
2831 || pi->carrier_suppr_disable
2832 || pi->disable_percal))
2833 wlc_lcnphy_calib_modes(pi,
2834 PHY_PERICAL_WATCHDOG);
2839 void wlc_phy_BSSinit(wlc_phy_t *pih, bool bonlyap, int rssi)
2841 phy_info_t *pi = (phy_info_t *) pih;
2845 for (i = 0; i < MA_WINDOW_SZ; i++) {
2846 pi->sh->phy_noise_window[i] = (s8) (rssi & 0xff);
2849 for (i = 0; i < MA_WINDOW_SZ; i++)
2850 pi->sh->phy_noise_window[i] =
2851 PHY_NOISE_FIXED_VAL_LCNPHY;
2853 pi->sh->phy_noise_index = 0;
2855 for (i = 0; i < PHY_NOISE_WINDOW_SZ; i++) {
2856 for (k = WL_ANT_IDX_1; k < WL_ANT_RX_MAX; k++)
2857 pi->nphy_noise_win[k][i] = PHY_NOISE_FIXED_VAL_NPHY;
2859 pi->nphy_noise_index = 0;
2863 wlc_phy_papd_decode_epsilon(u32 epsilon, s32 *eps_real, s32 *eps_imag)
2865 *eps_imag = (epsilon >> 13);
2866 if (*eps_imag > 0xfff)
2867 *eps_imag -= 0x2000;
2869 *eps_real = (epsilon & 0x1fff);
2870 if (*eps_real > 0xfff)
2871 *eps_real -= 0x2000;
2874 static const fixed AtanTbl[] = {
2895 void wlc_phy_cordic(fixed theta, cs32 *val)
2897 fixed angle, valtmp;
2902 val[0].i = CORDIC_AG;
2906 signtheta = (theta < 0) ? -1 : 1;
2908 ((theta + FIXED(180) * signtheta) % FIXED(360)) -
2909 FIXED(180) * signtheta;
2911 if (FLOAT(theta) > 90) {
2912 theta -= FIXED(180);
2914 } else if (FLOAT(theta) < -90) {
2915 theta += FIXED(180);
2919 for (iter = 0; iter < CORDIC_NI; iter++) {
2920 if (theta > angle) {
2921 valtmp = val[0].i - (val[0].q >> iter);
2922 val[0].q = (val[0].i >> iter) + val[0].q;
2924 angle += AtanTbl[iter];
2926 valtmp = val[0].i + (val[0].q >> iter);
2927 val[0].q = -(val[0].i >> iter) + val[0].q;
2929 angle -= AtanTbl[iter];
2933 val[0].i = val[0].i * signx;
2934 val[0].q = val[0].q * signx;
2937 void wlc_phy_cal_perical_mphase_reset(phy_info_t *pi)
2939 wlapi_del_timer(pi->sh->physhim, pi->phycal_timer);
2941 pi->cal_type_override = PHY_PERICAL_AUTO;
2942 pi->mphase_cal_phase_id = MPHASE_CAL_STATE_IDLE;
2943 pi->mphase_txcal_cmdidx = 0;
2946 static void wlc_phy_cal_perical_mphase_schedule(phy_info_t *pi, uint delay)
2949 if ((pi->nphy_perical != PHY_PERICAL_MPHASE) &&
2950 (pi->nphy_perical != PHY_PERICAL_MANUAL))
2953 wlapi_del_timer(pi->sh->physhim, pi->phycal_timer);
2955 pi->mphase_cal_phase_id = MPHASE_CAL_STATE_INIT;
2956 wlapi_add_timer(pi->sh->physhim, pi->phycal_timer, delay, 0);
2959 void wlc_phy_cal_perical(wlc_phy_t *pih, u8 reason)
2961 s16 nphy_currtemp = 0;
2963 bool do_periodic_cal = true;
2964 phy_info_t *pi = (phy_info_t *) pih;
2969 if ((pi->nphy_perical == PHY_PERICAL_DISABLE) ||
2970 (pi->nphy_perical == PHY_PERICAL_MANUAL))
2974 case PHY_PERICAL_DRIVERUP:
2977 case PHY_PERICAL_PHYINIT:
2978 if (pi->nphy_perical == PHY_PERICAL_MPHASE) {
2979 if (PHY_PERICAL_MPHASE_PENDING(pi)) {
2980 wlc_phy_cal_perical_mphase_reset(pi);
2982 wlc_phy_cal_perical_mphase_schedule(pi,
2983 PHY_PERICAL_INIT_DELAY);
2987 case PHY_PERICAL_JOIN_BSS:
2988 case PHY_PERICAL_START_IBSS:
2989 case PHY_PERICAL_UP_BSS:
2990 if ((pi->nphy_perical == PHY_PERICAL_MPHASE) &&
2991 PHY_PERICAL_MPHASE_PENDING(pi)) {
2992 wlc_phy_cal_perical_mphase_reset(pi);
2995 pi->first_cal_after_assoc = true;
2997 pi->cal_type_override = PHY_PERICAL_FULL;
2999 if (pi->phycal_tempdelta) {
3000 pi->nphy_lastcal_temp = wlc_phy_tempsense_nphy(pi);
3002 wlc_phy_cal_perical_nphy_run(pi, PHY_PERICAL_FULL);
3005 case PHY_PERICAL_WATCHDOG:
3006 if (pi->phycal_tempdelta) {
3007 nphy_currtemp = wlc_phy_tempsense_nphy(pi);
3009 (nphy_currtemp > pi->nphy_lastcal_temp) ?
3010 nphy_currtemp - pi->nphy_lastcal_temp :
3011 pi->nphy_lastcal_temp - nphy_currtemp;
3013 if ((delta_temp < (s16) pi->phycal_tempdelta) &&
3014 (pi->nphy_txiqlocal_chanspec ==
3015 pi->radio_chanspec)) {
3016 do_periodic_cal = false;
3018 pi->nphy_lastcal_temp = nphy_currtemp;
3022 if (do_periodic_cal) {
3024 if (pi->nphy_perical == PHY_PERICAL_MPHASE) {
3026 if (!PHY_PERICAL_MPHASE_PENDING(pi))
3027 wlc_phy_cal_perical_mphase_schedule(pi,
3028 PHY_PERICAL_WDOG_DELAY);
3029 } else if (pi->nphy_perical == PHY_PERICAL_SPHASE)
3030 wlc_phy_cal_perical_nphy_run(pi,
3039 void wlc_phy_cal_perical_mphase_restart(phy_info_t *pi)
3041 pi->mphase_cal_phase_id = MPHASE_CAL_STATE_INIT;
3042 pi->mphase_txcal_cmdidx = 0;
3045 u8 wlc_phy_nbits(s32 value)
3050 abs_val = ABS(value);
3051 while ((abs_val >> nbits) > 0)
3057 void wlc_phy_stf_chain_init(wlc_phy_t *pih, u8 txchain, u8 rxchain)
3059 phy_info_t *pi = (phy_info_t *) pih;
3061 pi->sh->hw_phytxchain = txchain;
3062 pi->sh->hw_phyrxchain = rxchain;
3063 pi->sh->phytxchain = txchain;
3064 pi->sh->phyrxchain = rxchain;
3065 pi->pubpi.phy_corenum = (u8) PHY_BITSCNT(pi->sh->phyrxchain);
3068 void wlc_phy_stf_chain_set(wlc_phy_t *pih, u8 txchain, u8 rxchain)
3070 phy_info_t *pi = (phy_info_t *) pih;
3072 pi->sh->phytxchain = txchain;
3075 wlc_phy_rxcore_setstate_nphy(pih, rxchain);
3077 pi->pubpi.phy_corenum = (u8) PHY_BITSCNT(pi->sh->phyrxchain);
3080 void wlc_phy_stf_chain_get(wlc_phy_t *pih, u8 *txchain, u8 *rxchain)
3082 phy_info_t *pi = (phy_info_t *) pih;
3084 *txchain = pi->sh->phytxchain;
3085 *rxchain = pi->sh->phyrxchain;
3088 u8 wlc_phy_stf_chain_active_get(wlc_phy_t *pih)
3092 phy_info_t *pi = (phy_info_t *) pih;
3094 active_bitmap = (pi->phy_txcore_heatedup) ? 0x31 : 0x33;
3096 if (!pi->watchdog_override)
3097 return active_bitmap;
3099 if (NREV_GE(pi->pubpi.phy_rev, 6)) {
3100 wlapi_suspend_mac_and_wait(pi->sh->physhim);
3101 nphy_currtemp = wlc_phy_tempsense_nphy(pi);
3102 wlapi_enable_mac(pi->sh->physhim);
3104 if (!pi->phy_txcore_heatedup) {
3105 if (nphy_currtemp >= pi->phy_txcore_disable_temp) {
3106 active_bitmap &= 0xFD;
3107 pi->phy_txcore_heatedup = true;
3110 if (nphy_currtemp <= pi->phy_txcore_enable_temp) {
3111 active_bitmap |= 0x2;
3112 pi->phy_txcore_heatedup = false;
3117 return active_bitmap;
3120 s8 wlc_phy_stf_ssmode_get(wlc_phy_t *pih, chanspec_t chanspec)
3122 phy_info_t *pi = (phy_info_t *) pih;
3123 u8 siso_mcs_id, cdd_mcs_id;
3126 (CHSPEC_IS40(chanspec)) ? TXP_FIRST_MCS_40_SISO :
3127 TXP_FIRST_MCS_20_SISO;
3129 (CHSPEC_IS40(chanspec)) ? TXP_FIRST_MCS_40_CDD :
3130 TXP_FIRST_MCS_20_CDD;
3132 if (pi->tx_power_target[siso_mcs_id] >
3133 (pi->tx_power_target[cdd_mcs_id] + 12))
3134 return PHY_TXC1_MODE_SISO;
3136 return PHY_TXC1_MODE_CDD;
3139 const u8 *wlc_phy_get_ofdm_rate_lookup(void)
3141 return ofdm_rate_lookup;
3144 void wlc_lcnphy_epa_switch(phy_info_t *pi, bool mode)
3146 if ((pi->sh->chip == BCM4313_CHIP_ID) &&
3147 (pi->sh->boardflags & BFL_FEM)) {
3150 txant = wlapi_bmac_get_txant(pi->sh->physhim);
3152 mod_phy_reg(pi, 0x44d, (0x1 << 2), (1) << 2);
3154 mod_phy_reg(pi, 0x44c, (0x1 << 2), (1) << 2);
3157 ai_corereg(pi->sh->sih, SI_CC_IDX,
3158 offsetof(chipcregs_t, gpiocontrol), ~0x0,
3160 ai_corereg(pi->sh->sih, SI_CC_IDX,
3161 offsetof(chipcregs_t, gpioout), 0x40, 0x40);
3162 ai_corereg(pi->sh->sih, SI_CC_IDX,
3163 offsetof(chipcregs_t, gpioouten), 0x40,
3166 mod_phy_reg(pi, 0x44c, (0x1 << 2), (0) << 2);
3168 mod_phy_reg(pi, 0x44d, (0x1 << 2), (0) << 2);
3170 ai_corereg(pi->sh->sih, SI_CC_IDX,
3171 offsetof(chipcregs_t, gpioout), 0x40, 0x00);
3172 ai_corereg(pi->sh->sih, SI_CC_IDX,
3173 offsetof(chipcregs_t, gpioouten), 0x40, 0x0);
3174 ai_corereg(pi->sh->sih, SI_CC_IDX,
3175 offsetof(chipcregs_t, gpiocontrol), ~0x0,
3182 wlc_user_txpwr_antport_to_rfport(phy_info_t *pi, uint chan, u32 band,
3187 if (!pi->user_txpwr_at_rfport)
3192 static s8 wlc_phy_env_measure_vbat(phy_info_t *pi)
3195 return wlc_lcnphy_vbatsense(pi, 0);
3200 static s8 wlc_phy_env_measure_temperature(phy_info_t *pi)
3203 return wlc_lcnphy_tempsense_degree(pi, 0);
3208 static void wlc_phy_upd_env_txpwr_rate_limits(phy_info_t *pi, u32 band)
3213 for (i = 0; i < TXP_NUM_RATES; i++)
3214 pi->txpwr_env_limit[i] = WLC_TXPWR_MAX;
3216 vbat = wlc_phy_env_measure_vbat(pi);
3217 temp = wlc_phy_env_measure_temperature(pi);
3221 void wlc_phy_ldpc_override_set(wlc_phy_t *ppi, bool ldpc)
3227 wlc_phy_get_pwrdet_offsets(phy_info_t *pi, s8 *cckoffset, s8 *ofdmoffset)
3233 s8 wlc_phy_upd_rssi_offset(phy_info_t *pi, s8 rssi, chanspec_t chanspec)
3239 bool wlc_phy_txpower_ipa_ison(wlc_phy_t *ppi)
3241 phy_info_t *pi = (phy_info_t *) ppi;
3244 return wlc_phy_n_txpower_ipa_ison(pi);