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.
19 #include <linux/kernel.h>
20 #include <linux/string.h>
22 #include <linux/delay.h>
23 #include <linux/module.h>
24 #include <linux/pci.h>
30 #include <wlc_phy_int.h>
31 #include <wlc_phyreg_n.h>
32 #include <wlc_phy_radio.h>
33 #include <wlc_phy_lcn.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] == '='))
173 return nvram_get(name);
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(&pi->regs->radioregaddr, addr);
250 (void)R_REG(&pi->regs->radioregaddr);
252 data = R_REG(&pi->regs->radioregdata);
254 W_REG(&pi->regs->phy4waddr, addr);
256 (void)R_REG(&pi->regs->phy4waddr);
259 #ifdef __ARM_ARCH_4T__
260 __asm__(" .align 4 ");
262 data = R_REG(&pi->regs->phy4wdatalo);
264 data = R_REG(&pi->regs->phy4wdatalo);
273 void write_radio_reg(phy_info_t *pi, u16 addr, u16 val)
275 if (NORADIO_ENAB(pi->pubpi))
278 if ((D11REV_GE(pi->sh->corerev, 24)) ||
279 (D11REV_IS(pi->sh->corerev, 22)
280 && (pi->pubpi.phy_type != PHY_TYPE_SSN))) {
282 W_REG(&pi->regs->radioregaddr, addr);
284 (void)R_REG(&pi->regs->radioregaddr);
286 W_REG(&pi->regs->radioregdata, val);
288 W_REG(&pi->regs->phy4waddr, addr);
290 (void)R_REG(&pi->regs->phy4waddr);
292 W_REG(&pi->regs->phy4wdatalo, val);
295 if (pi->sh->bustype == PCI_BUS) {
296 if (++pi->phy_wreg >= pi->phy_wreg_limit) {
297 (void)R_REG(&pi->regs->maccontrol);
303 static u32 read_radio_id(phy_info_t *pi)
307 if (NORADIO_ENAB(pi->pubpi))
308 return NORADIO_IDCODE;
310 if (D11REV_GE(pi->sh->corerev, 24)) {
313 W_REG(&pi->regs->radioregaddr, 0);
315 (void)R_REG(&pi->regs->radioregaddr);
317 b0 = (u32) R_REG(&pi->regs->radioregdata);
318 W_REG(&pi->regs->radioregaddr, 1);
320 (void)R_REG(&pi->regs->radioregaddr);
322 b1 = (u32) R_REG(&pi->regs->radioregdata);
323 W_REG(&pi->regs->radioregaddr, 2);
325 (void)R_REG(&pi->regs->radioregaddr);
327 b2 = (u32) R_REG(&pi->regs->radioregdata);
329 id = ((b0 & 0xf) << 28) | (((b2 << 8) | b1) << 12) | ((b0 >> 4)
332 W_REG(&pi->regs->phy4waddr, RADIO_IDCODE);
334 (void)R_REG(&pi->regs->phy4waddr);
336 id = (u32) R_REG(&pi->regs->phy4wdatalo);
337 id |= (u32) R_REG(&pi->regs->phy4wdatahi) << 16;
343 void and_radio_reg(phy_info_t *pi, u16 addr, u16 val)
347 if (NORADIO_ENAB(pi->pubpi))
350 rval = read_radio_reg(pi, addr);
351 write_radio_reg(pi, addr, (rval & val));
354 void or_radio_reg(phy_info_t *pi, u16 addr, u16 val)
358 if (NORADIO_ENAB(pi->pubpi))
361 rval = read_radio_reg(pi, addr);
362 write_radio_reg(pi, addr, (rval | val));
365 void xor_radio_reg(phy_info_t *pi, u16 addr, u16 mask)
369 if (NORADIO_ENAB(pi->pubpi))
372 rval = read_radio_reg(pi, addr);
373 write_radio_reg(pi, addr, (rval ^ mask));
376 void mod_radio_reg(phy_info_t *pi, u16 addr, u16 mask, u16 val)
380 if (NORADIO_ENAB(pi->pubpi))
383 rval = read_radio_reg(pi, addr);
384 write_radio_reg(pi, addr, (rval & ~mask) | (val & mask));
387 void write_phy_channel_reg(phy_info_t *pi, uint val)
389 W_REG(&pi->regs->phychannel, val);
392 u16 read_phy_reg(phy_info_t *pi, u16 addr)
398 W_REG(®s->phyregaddr, addr);
400 (void)R_REG(®s->phyregaddr);
404 return R_REG(®s->phyregdata);
407 void write_phy_reg(phy_info_t *pi, u16 addr, u16 val)
414 W_REG(®s->phyregaddr, addr);
415 (void)R_REG(®s->phyregaddr);
416 W_REG(®s->phyregdata, val);
418 (void)R_REG(®s->phyregdata);
420 W_REG((u32 *)(®s->phyregaddr),
422 if (pi->sh->bustype == PCI_BUS) {
423 if (++pi->phy_wreg >= pi->phy_wreg_limit) {
425 (void)R_REG(®s->phyversion);
431 void and_phy_reg(phy_info_t *pi, u16 addr, u16 val)
437 W_REG(®s->phyregaddr, addr);
439 (void)R_REG(®s->phyregaddr);
442 W_REG(®s->phyregdata, (R_REG(®s->phyregdata) & val));
446 void or_phy_reg(phy_info_t *pi, u16 addr, u16 val)
452 W_REG(®s->phyregaddr, addr);
454 (void)R_REG(®s->phyregaddr);
457 W_REG(®s->phyregdata, (R_REG(®s->phyregdata) | val));
461 void mod_phy_reg(phy_info_t *pi, u16 addr, u16 mask, u16 val)
467 W_REG(®s->phyregaddr, addr);
469 (void)R_REG(®s->phyregaddr);
472 W_REG(®s->phyregdata,
473 ((R_REG(®s->phyregdata) & ~mask) | (val & mask)));
477 static void WLBANDINITFN(wlc_set_phy_uninitted) (phy_info_t *pi)
481 pi->initialized = false;
484 pi->nrssi_table_delta = 0x7fffffff;
486 pi->mintxbias = 0xffff;
489 pi->phy_spuravoid = SPURAVOID_DISABLE;
491 if (NREV_GE(pi->pubpi.phy_rev, 3)
492 && NREV_LT(pi->pubpi.phy_rev, 7))
493 pi->phy_spuravoid = SPURAVOID_AUTO;
495 pi->nphy_papd_skip = 0;
496 pi->nphy_papd_epsilon_offset[0] = 0xf588;
497 pi->nphy_papd_epsilon_offset[1] = 0xf588;
498 pi->nphy_txpwr_idx[0] = 128;
499 pi->nphy_txpwr_idx[1] = 128;
500 pi->nphy_txpwrindex[0].index_internal = 40;
501 pi->nphy_txpwrindex[1].index_internal = 40;
504 pi->phy_spuravoid = SPURAVOID_AUTO;
506 pi->radiopwr = 0xffff;
507 for (i = 0; i < STATIC_NUM_RF; i++) {
508 for (j = 0; j < STATIC_NUM_BB; j++) {
509 pi->stats_11b_txpower[i][j] = -1;
514 shared_phy_t *wlc_phy_shared_attach(shared_phy_params_t *shp)
518 sh = kzalloc(sizeof(shared_phy_t), GFP_ATOMIC);
524 sh->physhim = shp->physhim;
525 sh->unit = shp->unit;
526 sh->corerev = shp->corerev;
530 sh->chip = shp->chip;
531 sh->chiprev = shp->chiprev;
532 sh->chippkg = shp->chippkg;
533 sh->sromrev = shp->sromrev;
534 sh->boardtype = shp->boardtype;
535 sh->boardrev = shp->boardrev;
536 sh->boardvendor = shp->boardvendor;
537 sh->boardflags = shp->boardflags;
538 sh->boardflags2 = shp->boardflags2;
539 sh->bustype = shp->bustype;
540 sh->buscorerev = shp->buscorerev;
542 sh->fast_timer = PHY_SW_TIMER_FAST;
543 sh->slow_timer = PHY_SW_TIMER_SLOW;
544 sh->glacial_timer = PHY_SW_TIMER_GLACIAL;
546 sh->rssi_mode = RSSI_ANT_MERGE_MAX;
551 void wlc_phy_shared_detach(shared_phy_t *phy_sh)
558 wlc_phy_t *wlc_phy_attach(shared_phy_t *sh, void *regs, int bandtype,
559 char *vars, struct wiphy *wiphy)
566 if (D11REV_IS(sh->corerev, 4))
567 sflags = SISF_2G_PHY | SISF_5G_PHY;
569 sflags = ai_core_sflags(sh->sih, 0, 0);
571 if (BAND_5G(bandtype)) {
572 if ((sflags & (SISF_5G_PHY | SISF_DB_PHY)) == 0) {
578 if ((sflags & SISF_DB_PHY) && pi) {
580 wlapi_bmac_corereset(pi->sh->physhim, pi->pubpi.coreflags);
582 return &pi->pubpi_ro;
585 pi = kzalloc(sizeof(phy_info_t), GFP_ATOMIC);
590 pi->regs = (d11regs_t *) regs;
592 pi->phy_init_por = true;
593 pi->phy_wreg_limit = PHY_WREG_LIMIT;
597 pi->txpwr_percent = 100;
599 pi->do_initcal = true;
601 pi->phycal_tempdelta = 0;
603 if (BAND_2G(bandtype) && (sflags & SISF_2G_PHY)) {
605 pi->pubpi.coreflags = SICF_GMODE;
608 wlapi_bmac_corereset(pi->sh->physhim, pi->pubpi.coreflags);
609 phyversion = R_REG(&pi->regs->phyversion);
611 pi->pubpi.phy_type = PHY_TYPE(phyversion);
612 pi->pubpi.phy_rev = phyversion & PV_PV_MASK;
614 if (pi->pubpi.phy_type == PHY_TYPE_LCNXN) {
615 pi->pubpi.phy_type = PHY_TYPE_N;
616 pi->pubpi.phy_rev += LCNXN_BASEREV;
618 pi->pubpi.phy_corenum = PHY_CORE_NUM_2;
619 pi->pubpi.ana_rev = (phyversion & PV_AV_MASK) >> PV_AV_SHIFT;
621 if (!VALID_PHYTYPE(pi->pubpi.phy_type)) {
624 if (BAND_5G(bandtype)) {
629 if (!ISNPHY(pi) && !ISLCNPHY(pi)) {
634 if (ISSIM_ENAB(pi->sh->sih)) {
635 pi->pubpi.radioid = NORADIO_ID;
636 pi->pubpi.radiorev = 5;
640 wlc_phy_anacore((wlc_phy_t *) pi, ON);
642 idcode = wlc_phy_get_radio_ver(pi);
644 (idcode & IDCODE_ID_MASK) >> IDCODE_ID_SHIFT;
646 (idcode & IDCODE_REV_MASK) >> IDCODE_REV_SHIFT;
648 (idcode & IDCODE_VER_MASK) >> IDCODE_VER_SHIFT;
649 if (!VALID_RADIO(pi, pi->pubpi.radioid)) {
653 wlc_phy_switch_radio((wlc_phy_t *) pi, OFF);
656 wlc_set_phy_uninitted(pi);
658 pi->bw = WL_CHANSPEC_BW_20;
660 BAND_2G(bandtype) ? CH20MHZ_CHSPEC(1) : CH20MHZ_CHSPEC(36);
662 pi->rxiq_samps = PHY_NOISE_SAMPLE_LOG_NUM_NPHY;
663 pi->rxiq_antsel = ANT_RX_DIV_DEF;
665 pi->watchdog_override = true;
667 pi->cal_type_override = PHY_PERICAL_AUTO;
669 pi->nphy_saved_noisevars.bufcount = 0;
672 pi->min_txpower = PHY_TXPWR_MIN_NPHY;
674 pi->min_txpower = PHY_TXPWR_MIN;
676 pi->sh->phyrxchain = 0x3;
678 pi->rx2tx_biasentry = -1;
680 pi->phy_txcore_disable_temp = PHY_CHAIN_TX_DISABLE_TEMP;
681 pi->phy_txcore_enable_temp =
682 PHY_CHAIN_TX_DISABLE_TEMP - PHY_HYSTERESIS_DELTATEMP;
683 pi->phy_tempsense_offset = 0;
684 pi->phy_txcore_heatedup = false;
686 pi->nphy_lastcal_temp = -50;
688 pi->phynoise_polling = true;
689 if (ISNPHY(pi) || ISLCNPHY(pi))
690 pi->phynoise_polling = false;
692 for (i = 0; i < TXP_NUM_RATES; i++) {
693 pi->txpwr_limit[i] = WLC_TXPWR_MAX;
694 pi->txpwr_env_limit[i] = WLC_TXPWR_MAX;
695 pi->tx_user_target[i] = WLC_TXPWR_MAX;
698 pi->radiopwr_override = RADIOPWR_OVERRIDE_DEF;
700 pi->user_txpwr_at_rfport = false;
704 pi->phycal_timer = wlapi_init_timer(pi->sh->physhim,
705 wlc_phy_timercb_phycal,
707 if (!pi->phycal_timer) {
711 if (!wlc_phy_attach_nphy(pi))
714 } else if (ISLCNPHY(pi)) {
715 if (!wlc_phy_attach_lcnphy(pi))
723 pi->next = pi->sh->phy_head;
726 pi->vars = (char *)&pi->vars;
728 memcpy(&pi->pubpi_ro, &pi->pubpi, sizeof(wlc_phy_t));
730 return &pi->pubpi_ro;
737 void wlc_phy_detach(wlc_phy_t *pih)
739 phy_info_t *pi = (phy_info_t *) pih;
746 if (pi->phycal_timer) {
747 wlapi_free_timer(pi->sh->physhim, pi->phycal_timer);
748 pi->phycal_timer = NULL;
751 if (pi->sh->phy_head == pi)
752 pi->sh->phy_head = pi->next;
753 else if (pi->sh->phy_head->next == pi)
754 pi->sh->phy_head->next = NULL;
756 if (pi->pi_fptr.detach)
757 (pi->pi_fptr.detach) (pi);
764 wlc_phy_get_phyversion(wlc_phy_t *pih, u16 *phytype, u16 *phyrev,
765 u16 *radioid, u16 *radiover)
767 phy_info_t *pi = (phy_info_t *) pih;
768 *phytype = (u16) pi->pubpi.phy_type;
769 *phyrev = (u16) pi->pubpi.phy_rev;
770 *radioid = pi->pubpi.radioid;
771 *radiover = pi->pubpi.radiorev;
776 bool wlc_phy_get_encore(wlc_phy_t *pih)
778 phy_info_t *pi = (phy_info_t *) pih;
779 return pi->pubpi.abgphy_encore;
782 u32 wlc_phy_get_coreflags(wlc_phy_t *pih)
784 phy_info_t *pi = (phy_info_t *) pih;
785 return pi->pubpi.coreflags;
788 static void wlc_phy_timercb_phycal(void *arg)
790 phy_info_t *pi = (phy_info_t *) arg;
793 if (PHY_PERICAL_MPHASE_PENDING(pi)) {
795 wlc_phy_cal_perical_mphase_reset(pi);
799 if (SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi)) {
802 wlc_phy_cal_perical_mphase_restart(pi);
804 wlc_phy_cal_perical_nphy_run(pi, PHY_PERICAL_AUTO);
805 wlapi_add_timer(pi->sh->physhim, pi->phycal_timer, delay, 0);
811 void wlc_phy_anacore(wlc_phy_t *pih, bool on)
813 phy_info_t *pi = (phy_info_t *) pih;
817 if (NREV_GE(pi->pubpi.phy_rev, 3)) {
818 write_phy_reg(pi, 0xa6, 0x0d);
819 write_phy_reg(pi, 0x8f, 0x0);
820 write_phy_reg(pi, 0xa7, 0x0d);
821 write_phy_reg(pi, 0xa5, 0x0);
823 write_phy_reg(pi, 0xa5, 0x0);
826 if (NREV_GE(pi->pubpi.phy_rev, 3)) {
827 write_phy_reg(pi, 0x8f, 0x07ff);
828 write_phy_reg(pi, 0xa6, 0x0fd);
829 write_phy_reg(pi, 0xa5, 0x07ff);
830 write_phy_reg(pi, 0xa7, 0x0fd);
832 write_phy_reg(pi, 0xa5, 0x7fff);
835 } else if (ISLCNPHY(pi)) {
837 and_phy_reg(pi, 0x43b,
838 ~((0x1 << 0) | (0x1 << 1) | (0x1 << 2)));
840 or_phy_reg(pi, 0x43c,
841 (0x1 << 0) | (0x1 << 1) | (0x1 << 2));
842 or_phy_reg(pi, 0x43b,
843 (0x1 << 0) | (0x1 << 1) | (0x1 << 2));
848 u32 wlc_phy_clk_bwbits(wlc_phy_t *pih)
850 phy_info_t *pi = (phy_info_t *) pih;
852 u32 phy_bw_clkbits = 0;
854 if (pi && (ISNPHY(pi) || ISLCNPHY(pi))) {
856 case WL_CHANSPEC_BW_10:
857 phy_bw_clkbits = SICF_BW10;
859 case WL_CHANSPEC_BW_20:
860 phy_bw_clkbits = SICF_BW20;
862 case WL_CHANSPEC_BW_40:
863 phy_bw_clkbits = SICF_BW40;
870 return phy_bw_clkbits;
873 void WLBANDINITFN(wlc_phy_por_inform) (wlc_phy_t *ppi)
875 phy_info_t *pi = (phy_info_t *) ppi;
877 pi->phy_init_por = true;
880 void wlc_phy_edcrs_lock(wlc_phy_t *pih, bool lock)
882 phy_info_t *pi = (phy_info_t *) pih;
884 pi->edcrs_threshold_lock = lock;
886 write_phy_reg(pi, 0x22c, 0x46b);
887 write_phy_reg(pi, 0x22d, 0x46b);
888 write_phy_reg(pi, 0x22e, 0x3c0);
889 write_phy_reg(pi, 0x22f, 0x3c0);
892 void wlc_phy_initcal_enable(wlc_phy_t *pih, bool initcal)
894 phy_info_t *pi = (phy_info_t *) pih;
896 pi->do_initcal = initcal;
899 void wlc_phy_hw_clk_state_upd(wlc_phy_t *pih, bool newstate)
901 phy_info_t *pi = (phy_info_t *) pih;
906 pi->sh->clk = newstate;
909 void wlc_phy_hw_state_upd(wlc_phy_t *pih, bool newstate)
911 phy_info_t *pi = (phy_info_t *) pih;
916 pi->sh->up = newstate;
919 void WLBANDINITFN(wlc_phy_init) (wlc_phy_t *pih, chanspec_t chanspec)
922 initfn_t phy_init = NULL;
923 phy_info_t *pi = (phy_info_t *) pih;
925 if (pi->init_in_progress)
928 pi->init_in_progress = true;
930 pi->radio_chanspec = chanspec;
932 mc = R_REG(&pi->regs->maccontrol);
933 if (WARN(mc & MCTL_EN_MAC, "HW error MAC running on init"))
936 if (!(pi->measure_hold & PHY_HOLD_FOR_SCAN)) {
937 pi->measure_hold |= PHY_HOLD_FOR_NOT_ASSOC;
940 if (WARN(!(ai_core_sflags(pi->sh->sih, 0, 0) & SISF_FCLKA),
941 "HW error SISF_FCLKA\n"))
944 phy_init = pi->pi_fptr.init;
946 if (phy_init == NULL) {
950 wlc_phy_anacore(pih, ON);
952 if (CHSPEC_BW(pi->radio_chanspec) != pi->bw)
953 wlapi_bmac_bw_set(pi->sh->physhim,
954 CHSPEC_BW(pi->radio_chanspec));
956 pi->nphy_gain_boost = true;
958 wlc_phy_switch_radio((wlc_phy_t *) pi, ON);
962 pi->phy_init_por = false;
964 if (D11REV_IS(pi->sh->corerev, 11) || D11REV_IS(pi->sh->corerev, 12))
965 wlc_phy_do_dummy_tx(pi, true, OFF);
968 wlc_phy_txpower_update_shm(pi);
970 wlc_phy_ant_rxdiv_set((wlc_phy_t *) pi, pi->sh->rx_antdiv);
972 pi->init_in_progress = false;
975 void wlc_phy_cal_init(wlc_phy_t *pih)
977 phy_info_t *pi = (phy_info_t *) pih;
978 initfn_t cal_init = NULL;
980 if (WARN((R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC) != 0,
981 "HW error: MAC enabled during phy cal\n"))
984 if (!pi->initialized) {
985 cal_init = pi->pi_fptr.calinit;
989 pi->initialized = true;
993 int wlc_phy_down(wlc_phy_t *pih)
995 phy_info_t *pi = (phy_info_t *) pih;
999 && !wlapi_del_timer(pi->sh->physhim, pi->phycal_timer))
1002 pi->nphy_iqcal_chanspec_2G = 0;
1003 pi->nphy_iqcal_chanspec_5G = 0;
1008 static u32 wlc_phy_get_radio_ver(phy_info_t *pi)
1012 ver = read_radio_id(pi);
1018 wlc_phy_table_addr(phy_info_t *pi, uint tbl_id, uint tbl_offset,
1019 u16 tblAddr, u16 tblDataHi, u16 tblDataLo)
1021 write_phy_reg(pi, tblAddr, (tbl_id << 10) | tbl_offset);
1023 pi->tbl_data_hi = tblDataHi;
1024 pi->tbl_data_lo = tblDataLo;
1026 if ((pi->sh->chip == BCM43224_CHIP_ID ||
1027 pi->sh->chip == BCM43421_CHIP_ID) &&
1028 (pi->sh->chiprev == 1)) {
1029 pi->tbl_addr = tblAddr;
1030 pi->tbl_save_id = tbl_id;
1031 pi->tbl_save_offset = tbl_offset;
1035 void wlc_phy_table_data_write(phy_info_t *pi, uint width, u32 val)
1037 if ((pi->sh->chip == BCM43224_CHIP_ID ||
1038 pi->sh->chip == BCM43421_CHIP_ID) &&
1039 (pi->sh->chiprev == 1) &&
1040 (pi->tbl_save_id == NPHY_TBL_ID_ANTSWCTRLLUT)) {
1041 read_phy_reg(pi, pi->tbl_data_lo);
1043 write_phy_reg(pi, pi->tbl_addr,
1044 (pi->tbl_save_id << 10) | pi->tbl_save_offset);
1045 pi->tbl_save_offset++;
1050 write_phy_reg(pi, pi->tbl_data_hi, (u16) (val >> 16));
1051 write_phy_reg(pi, pi->tbl_data_lo, (u16) val);
1054 write_phy_reg(pi, pi->tbl_data_lo, (u16) val);
1059 wlc_phy_write_table(phy_info_t *pi, const phytbl_info_t *ptbl_info,
1060 u16 tblAddr, u16 tblDataHi, u16 tblDataLo)
1063 uint tbl_id = ptbl_info->tbl_id;
1064 uint tbl_offset = ptbl_info->tbl_offset;
1065 uint tbl_width = ptbl_info->tbl_width;
1066 const u8 *ptbl_8b = (const u8 *)ptbl_info->tbl_ptr;
1067 const u16 *ptbl_16b = (const u16 *)ptbl_info->tbl_ptr;
1068 const u32 *ptbl_32b = (const u32 *)ptbl_info->tbl_ptr;
1070 write_phy_reg(pi, tblAddr, (tbl_id << 10) | tbl_offset);
1072 for (idx = 0; idx < ptbl_info->tbl_len; idx++) {
1074 if ((pi->sh->chip == BCM43224_CHIP_ID ||
1075 pi->sh->chip == BCM43421_CHIP_ID) &&
1076 (pi->sh->chiprev == 1) &&
1077 (tbl_id == NPHY_TBL_ID_ANTSWCTRLLUT)) {
1078 read_phy_reg(pi, tblDataLo);
1080 write_phy_reg(pi, tblAddr,
1081 (tbl_id << 10) | (tbl_offset + idx));
1084 if (tbl_width == 32) {
1086 write_phy_reg(pi, tblDataHi,
1087 (u16) (ptbl_32b[idx] >> 16));
1088 write_phy_reg(pi, tblDataLo, (u16) ptbl_32b[idx]);
1089 } else if (tbl_width == 16) {
1091 write_phy_reg(pi, tblDataLo, ptbl_16b[idx]);
1094 write_phy_reg(pi, tblDataLo, ptbl_8b[idx]);
1100 wlc_phy_read_table(phy_info_t *pi, const phytbl_info_t *ptbl_info,
1101 u16 tblAddr, u16 tblDataHi, u16 tblDataLo)
1104 uint tbl_id = ptbl_info->tbl_id;
1105 uint tbl_offset = ptbl_info->tbl_offset;
1106 uint tbl_width = ptbl_info->tbl_width;
1107 u8 *ptbl_8b = (u8 *)ptbl_info->tbl_ptr;
1108 u16 *ptbl_16b = (u16 *)ptbl_info->tbl_ptr;
1109 u32 *ptbl_32b = (u32 *)ptbl_info->tbl_ptr;
1111 write_phy_reg(pi, tblAddr, (tbl_id << 10) | tbl_offset);
1113 for (idx = 0; idx < ptbl_info->tbl_len; idx++) {
1115 if ((pi->sh->chip == BCM43224_CHIP_ID ||
1116 pi->sh->chip == BCM43421_CHIP_ID) &&
1117 (pi->sh->chiprev == 1)) {
1118 (void)read_phy_reg(pi, tblDataLo);
1120 write_phy_reg(pi, tblAddr,
1121 (tbl_id << 10) | (tbl_offset + idx));
1124 if (tbl_width == 32) {
1126 ptbl_32b[idx] = read_phy_reg(pi, tblDataLo);
1127 ptbl_32b[idx] |= (read_phy_reg(pi, tblDataHi) << 16);
1128 } else if (tbl_width == 16) {
1130 ptbl_16b[idx] = read_phy_reg(pi, tblDataLo);
1133 ptbl_8b[idx] = (u8) read_phy_reg(pi, tblDataLo);
1139 wlc_phy_init_radio_regs_allbands(phy_info_t *pi, radio_20xx_regs_t *radioregs)
1144 if (radioregs[i].do_init) {
1145 write_radio_reg(pi, radioregs[i].address,
1146 (u16) radioregs[i].init);
1150 } while (radioregs[i].address != 0xffff);
1156 wlc_phy_init_radio_regs(phy_info_t *pi, radio_regs_t *radioregs,
1163 if (CHSPEC_IS5G(pi->radio_chanspec)) {
1164 if (radioregs[i].do_init_a) {
1167 address | core_offset,
1168 (u16) radioregs[i].init_a);
1169 if (ISNPHY(pi) && (++count % 4 == 0))
1170 WLC_PHY_WAR_PR51571(pi);
1173 if (radioregs[i].do_init_g) {
1176 address | core_offset,
1177 (u16) radioregs[i].init_g);
1178 if (ISNPHY(pi) && (++count % 4 == 0))
1179 WLC_PHY_WAR_PR51571(pi);
1184 } while (radioregs[i].address != 0xffff);
1189 void wlc_phy_do_dummy_tx(phy_info_t *pi, bool ofdm, bool pa_on)
1191 #define DUMMY_PKT_LEN 20
1192 d11regs_t *regs = pi->regs;
1194 u8 ofdmpkt[DUMMY_PKT_LEN] = {
1195 0xcc, 0x01, 0x02, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00,
1196 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00
1198 u8 cckpkt[DUMMY_PKT_LEN] = {
1199 0x6e, 0x84, 0x0b, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00,
1200 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00
1204 dummypkt = (u32 *) (ofdm ? ofdmpkt : cckpkt);
1205 wlapi_bmac_write_template_ram(pi->sh->physhim, 0, DUMMY_PKT_LEN,
1208 W_REG(®s->xmtsel, 0);
1210 if (D11REV_GE(pi->sh->corerev, 11))
1211 W_REG(®s->wepctl, 0x100);
1213 W_REG(®s->wepctl, 0);
1215 W_REG(®s->txe_phyctl, (ofdm ? 1 : 0) | PHY_TXC_ANT_0);
1216 if (ISNPHY(pi) || ISLCNPHY(pi)) {
1217 W_REG(®s->txe_phyctl1, 0x1A02);
1220 W_REG(®s->txe_wm_0, 0);
1221 W_REG(®s->txe_wm_1, 0);
1223 W_REG(®s->xmttplatetxptr, 0);
1224 W_REG(®s->xmttxcnt, DUMMY_PKT_LEN);
1226 W_REG(®s->xmtsel, ((8 << 8) | (1 << 5) | (1 << 2) | 2));
1228 W_REG(®s->txe_ctl, 0);
1232 wlc_phy_pa_override_nphy(pi, OFF);
1235 if (ISNPHY(pi) || ISLCNPHY(pi))
1236 W_REG(®s->txe_aux, 0xD0);
1238 W_REG(®s->txe_aux, ((1 << 5) | (1 << 4)));
1240 (void)R_REG(®s->txe_aux);
1243 count = ofdm ? 30 : 250;
1245 if (ISSIM_ENAB(pi->sh->sih)) {
1249 while ((i++ < count)
1250 && (R_REG(®s->txe_status) & (1 << 7))) {
1257 && ((R_REG(®s->txe_status) & (1 << 10)) == 0)) {
1263 while ((i++ < 10) && ((R_REG(®s->ifsstat) & (1 << 8))))
1268 wlc_phy_pa_override_nphy(pi, ON);
1272 void wlc_phy_hold_upd(wlc_phy_t *pih, mbool id, bool set)
1274 phy_info_t *pi = (phy_info_t *) pih;
1277 mboolset(pi->measure_hold, id);
1279 mboolclr(pi->measure_hold, id);
1285 void wlc_phy_mute_upd(wlc_phy_t *pih, bool mute, mbool flags)
1287 phy_info_t *pi = (phy_info_t *) pih;
1290 mboolset(pi->measure_hold, PHY_HOLD_FOR_MUTE);
1292 mboolclr(pi->measure_hold, PHY_HOLD_FOR_MUTE);
1295 if (!mute && (flags & PHY_MUTE_FOR_PREISM))
1296 pi->nphy_perical_last = pi->sh->now - pi->sh->glacial_timer;
1300 void wlc_phy_clear_tssi(wlc_phy_t *pih)
1302 phy_info_t *pi = (phy_info_t *) pih;
1307 wlapi_bmac_write_shm(pi->sh->physhim, M_B_TSSI_0, NULL_TSSI_W);
1308 wlapi_bmac_write_shm(pi->sh->physhim, M_B_TSSI_1, NULL_TSSI_W);
1309 wlapi_bmac_write_shm(pi->sh->physhim, M_G_TSSI_0, NULL_TSSI_W);
1310 wlapi_bmac_write_shm(pi->sh->physhim, M_G_TSSI_1, NULL_TSSI_W);
1314 static bool wlc_phy_cal_txpower_recalc_sw(phy_info_t *pi)
1319 void wlc_phy_switch_radio(wlc_phy_t *pih, bool on)
1321 phy_info_t *pi = (phy_info_t *) pih;
1323 if (NORADIO_ENAB(pi->pubpi))
1329 mc = R_REG(&pi->regs->maccontrol);
1333 wlc_phy_switch_radio_nphy(pi, on);
1335 } else if (ISLCNPHY(pi)) {
1337 and_phy_reg(pi, 0x44c,
1340 (0x1 << 10) | (0x1 << 11) | (0x1 << 12)));
1341 and_phy_reg(pi, 0x4b0, ~((0x1 << 3) | (0x1 << 11)));
1342 and_phy_reg(pi, 0x4f9, ~(0x1 << 3));
1344 and_phy_reg(pi, 0x44d,
1347 (0x1 << 12) | (0x1 << 13) | (0x1 << 14)));
1348 or_phy_reg(pi, 0x44c,
1351 (0x1 << 10) | (0x1 << 11) | (0x1 << 12));
1353 and_phy_reg(pi, 0x4b7, ~((0x7f << 8)));
1354 and_phy_reg(pi, 0x4b1, ~((0x1 << 13)));
1355 or_phy_reg(pi, 0x4b0, (0x1 << 3) | (0x1 << 11));
1356 and_phy_reg(pi, 0x4fa, ~((0x1 << 3)));
1357 or_phy_reg(pi, 0x4f9, (0x1 << 3));
1362 u16 wlc_phy_bw_state_get(wlc_phy_t *ppi)
1364 phy_info_t *pi = (phy_info_t *) ppi;
1369 void wlc_phy_bw_state_set(wlc_phy_t *ppi, u16 bw)
1371 phy_info_t *pi = (phy_info_t *) ppi;
1376 void wlc_phy_chanspec_radio_set(wlc_phy_t *ppi, chanspec_t newch)
1378 phy_info_t *pi = (phy_info_t *) ppi;
1379 pi->radio_chanspec = newch;
1383 chanspec_t wlc_phy_chanspec_get(wlc_phy_t *ppi)
1385 phy_info_t *pi = (phy_info_t *) ppi;
1387 return pi->radio_chanspec;
1390 void wlc_phy_chanspec_set(wlc_phy_t *ppi, chanspec_t chanspec)
1392 phy_info_t *pi = (phy_info_t *) ppi;
1394 chansetfn_t chanspec_set = NULL;
1396 m_cur_channel = CHSPEC_CHANNEL(chanspec);
1397 if (CHSPEC_IS5G(chanspec))
1398 m_cur_channel |= D11_CURCHANNEL_5G;
1399 if (CHSPEC_IS40(chanspec))
1400 m_cur_channel |= D11_CURCHANNEL_40;
1401 wlapi_bmac_write_shm(pi->sh->physhim, M_CURCHANNEL, m_cur_channel);
1403 chanspec_set = pi->pi_fptr.chanset;
1405 (*chanspec_set) (pi, chanspec);
1409 int wlc_phy_chanspec_freq2bandrange_lpssn(uint freq)
1414 range = WL_CHAN_FREQ_RANGE_2G;
1415 else if (freq <= 5320)
1416 range = WL_CHAN_FREQ_RANGE_5GL;
1417 else if (freq <= 5700)
1418 range = WL_CHAN_FREQ_RANGE_5GM;
1420 range = WL_CHAN_FREQ_RANGE_5GH;
1425 int wlc_phy_chanspec_bandrange_get(phy_info_t *pi, chanspec_t chanspec)
1428 uint channel = CHSPEC_CHANNEL(chanspec);
1429 uint freq = wlc_phy_channel2freq(channel);
1432 range = wlc_phy_get_chan_freq_range_nphy(pi, channel);
1433 } else if (ISLCNPHY(pi)) {
1434 range = wlc_phy_chanspec_freq2bandrange_lpssn(freq);
1440 void wlc_phy_chanspec_ch14_widefilter_set(wlc_phy_t *ppi, bool wide_filter)
1442 phy_info_t *pi = (phy_info_t *) ppi;
1444 pi->channel_14_wide_filter = wide_filter;
1448 int wlc_phy_channel2freq(uint channel)
1452 for (i = 0; i < ARRAY_SIZE(chan_info_all); i++)
1453 if (chan_info_all[i].chan == channel)
1454 return chan_info_all[i].freq;
1459 wlc_phy_chanspec_band_validch(wlc_phy_t *ppi, uint band, chanvec_t *channels)
1461 phy_info_t *pi = (phy_info_t *) ppi;
1465 memset(channels, 0, sizeof(chanvec_t));
1467 for (i = 0; i < ARRAY_SIZE(chan_info_all); i++) {
1468 channel = chan_info_all[i].chan;
1470 if ((pi->a_band_high_disable) && (channel >= FIRST_REF5_CHANNUM)
1471 && (channel <= LAST_REF5_CHANNUM))
1474 if (((band == WLC_BAND_2G) && (channel <= CH_MAX_2G_CHANNEL)) ||
1475 ((band == WLC_BAND_5G) && (channel > CH_MAX_2G_CHANNEL)))
1476 setbit(channels->vec, channel);
1480 chanspec_t wlc_phy_chanspec_band_firstch(wlc_phy_t *ppi, uint band)
1482 phy_info_t *pi = (phy_info_t *) ppi;
1487 for (i = 0; i < ARRAY_SIZE(chan_info_all); i++) {
1488 channel = chan_info_all[i].chan;
1490 if (ISNPHY(pi) && IS40MHZ(pi)) {
1493 for (j = 0; j < ARRAY_SIZE(chan_info_all); j++) {
1494 if (chan_info_all[j].chan ==
1495 channel + CH_10MHZ_APART)
1499 if (j == ARRAY_SIZE(chan_info_all))
1502 channel = UPPER_20_SB(channel);
1504 channel | WL_CHANSPEC_BW_40 |
1505 WL_CHANSPEC_CTL_SB_LOWER;
1506 if (band == WLC_BAND_2G)
1507 chspec |= WL_CHANSPEC_BAND_2G;
1509 chspec |= WL_CHANSPEC_BAND_5G;
1511 chspec = CH20MHZ_CHSPEC(channel);
1513 if ((pi->a_band_high_disable) && (channel >= FIRST_REF5_CHANNUM)
1514 && (channel <= LAST_REF5_CHANNUM))
1517 if (((band == WLC_BAND_2G) && (channel <= CH_MAX_2G_CHANNEL)) ||
1518 ((band == WLC_BAND_5G) && (channel > CH_MAX_2G_CHANNEL)))
1522 return (chanspec_t) INVCHANSPEC;
1525 int wlc_phy_txpower_get(wlc_phy_t *ppi, uint *qdbm, bool *override)
1527 phy_info_t *pi = (phy_info_t *) ppi;
1529 *qdbm = pi->tx_user_target[0];
1530 if (override != NULL)
1531 *override = pi->txpwroverride;
1535 void wlc_phy_txpower_target_set(wlc_phy_t *ppi, struct txpwr_limits *txpwr)
1537 bool mac_enabled = false;
1538 phy_info_t *pi = (phy_info_t *) ppi;
1540 memcpy(&pi->tx_user_target[TXP_FIRST_CCK],
1541 &txpwr->cck[0], WLC_NUM_RATES_CCK);
1543 memcpy(&pi->tx_user_target[TXP_FIRST_OFDM],
1544 &txpwr->ofdm[0], WLC_NUM_RATES_OFDM);
1545 memcpy(&pi->tx_user_target[TXP_FIRST_OFDM_20_CDD],
1546 &txpwr->ofdm_cdd[0], WLC_NUM_RATES_OFDM);
1548 memcpy(&pi->tx_user_target[TXP_FIRST_OFDM_40_SISO],
1549 &txpwr->ofdm_40_siso[0], WLC_NUM_RATES_OFDM);
1550 memcpy(&pi->tx_user_target[TXP_FIRST_OFDM_40_CDD],
1551 &txpwr->ofdm_40_cdd[0], WLC_NUM_RATES_OFDM);
1553 memcpy(&pi->tx_user_target[TXP_FIRST_MCS_20_SISO],
1554 &txpwr->mcs_20_siso[0], WLC_NUM_RATES_MCS_1_STREAM);
1555 memcpy(&pi->tx_user_target[TXP_FIRST_MCS_20_CDD],
1556 &txpwr->mcs_20_cdd[0], WLC_NUM_RATES_MCS_1_STREAM);
1557 memcpy(&pi->tx_user_target[TXP_FIRST_MCS_20_STBC],
1558 &txpwr->mcs_20_stbc[0], WLC_NUM_RATES_MCS_1_STREAM);
1559 memcpy(&pi->tx_user_target[TXP_FIRST_MCS_20_SDM],
1560 &txpwr->mcs_20_mimo[0], WLC_NUM_RATES_MCS_2_STREAM);
1562 memcpy(&pi->tx_user_target[TXP_FIRST_MCS_40_SISO],
1563 &txpwr->mcs_40_siso[0], WLC_NUM_RATES_MCS_1_STREAM);
1564 memcpy(&pi->tx_user_target[TXP_FIRST_MCS_40_CDD],
1565 &txpwr->mcs_40_cdd[0], WLC_NUM_RATES_MCS_1_STREAM);
1566 memcpy(&pi->tx_user_target[TXP_FIRST_MCS_40_STBC],
1567 &txpwr->mcs_40_stbc[0], WLC_NUM_RATES_MCS_1_STREAM);
1568 memcpy(&pi->tx_user_target[TXP_FIRST_MCS_40_SDM],
1569 &txpwr->mcs_40_mimo[0], WLC_NUM_RATES_MCS_2_STREAM);
1571 if (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC)
1575 wlapi_suspend_mac_and_wait(pi->sh->physhim);
1577 wlc_phy_txpower_recalc_target(pi);
1578 wlc_phy_cal_txpower_recalc_sw(pi);
1581 wlapi_enable_mac(pi->sh->physhim);
1584 int wlc_phy_txpower_set(wlc_phy_t *ppi, uint qdbm, bool override)
1586 phy_info_t *pi = (phy_info_t *) ppi;
1592 for (i = 0; i < TXP_NUM_RATES; i++)
1593 pi->tx_user_target[i] = (u8) qdbm;
1595 pi->txpwroverride = false;
1598 if (!SCAN_INPROG_PHY(pi)) {
1603 (R_REG(&pi->regs->maccontrol) &
1607 wlapi_suspend_mac_and_wait(pi->sh->physhim);
1609 wlc_phy_txpower_recalc_target(pi);
1610 wlc_phy_cal_txpower_recalc_sw(pi);
1613 wlapi_enable_mac(pi->sh->physhim);
1620 wlc_phy_txpower_sromlimit(wlc_phy_t *ppi, uint channel, u8 *min_pwr,
1621 u8 *max_pwr, int txp_rate_idx)
1623 phy_info_t *pi = (phy_info_t *) ppi;
1626 *min_pwr = pi->min_txpower * WLC_TXPWR_DB_FACTOR;
1629 if (txp_rate_idx < 0)
1630 txp_rate_idx = TXP_FIRST_CCK;
1631 wlc_phy_txpower_sromlimit_get_nphy(pi, channel, max_pwr,
1634 } else if ((channel <= CH_MAX_2G_CHANNEL)) {
1635 if (txp_rate_idx < 0)
1636 txp_rate_idx = TXP_FIRST_CCK;
1637 *max_pwr = pi->tx_srom_max_rate_2g[txp_rate_idx];
1640 *max_pwr = WLC_TXPWR_MAX;
1642 if (txp_rate_idx < 0)
1643 txp_rate_idx = TXP_FIRST_OFDM;
1645 for (i = 0; i < ARRAY_SIZE(chan_info_all); i++) {
1646 if (channel == chan_info_all[i].chan) {
1652 *max_pwr = pi->hwtxpwr[i];
1655 if ((i >= FIRST_MID_5G_CHAN) && (i <= LAST_MID_5G_CHAN))
1657 pi->tx_srom_max_rate_5g_mid[txp_rate_idx];
1658 if ((i >= FIRST_HIGH_5G_CHAN)
1659 && (i <= LAST_HIGH_5G_CHAN))
1661 pi->tx_srom_max_rate_5g_hi[txp_rate_idx];
1662 if ((i >= FIRST_LOW_5G_CHAN) && (i <= LAST_LOW_5G_CHAN))
1664 pi->tx_srom_max_rate_5g_low[txp_rate_idx];
1670 wlc_phy_txpower_sromlimit_max_get(wlc_phy_t *ppi, uint chan, u8 *max_txpwr,
1673 phy_info_t *pi = (phy_info_t *) ppi;
1675 u8 tx_pwr_min = 255;
1677 u8 maxtxpwr, mintxpwr, rate, pactrl;
1681 max_num_rate = ISNPHY(pi) ? TXP_NUM_RATES :
1682 ISLCNPHY(pi) ? (TXP_LAST_SISO_MCS_20 + 1) : (TXP_LAST_OFDM + 1);
1684 for (rate = 0; rate < max_num_rate; rate++) {
1686 wlc_phy_txpower_sromlimit(ppi, chan, &mintxpwr, &maxtxpwr,
1689 maxtxpwr = (maxtxpwr > pactrl) ? (maxtxpwr - pactrl) : 0;
1691 maxtxpwr = (maxtxpwr > 6) ? (maxtxpwr - 6) : 0;
1693 tx_pwr_max = max(tx_pwr_max, maxtxpwr);
1694 tx_pwr_min = min(tx_pwr_min, maxtxpwr);
1696 *max_txpwr = tx_pwr_max;
1697 *min_txpwr = tx_pwr_min;
1701 wlc_phy_txpower_boardlimit_band(wlc_phy_t *ppi, uint bandunit, s32 *max_pwr,
1702 s32 *min_pwr, u32 *step_pwr)
1707 u8 wlc_phy_txpower_get_target_min(wlc_phy_t *ppi)
1709 phy_info_t *pi = (phy_info_t *) ppi;
1711 return pi->tx_power_min;
1714 u8 wlc_phy_txpower_get_target_max(wlc_phy_t *ppi)
1716 phy_info_t *pi = (phy_info_t *) ppi;
1718 return pi->tx_power_max;
1721 void wlc_phy_txpower_recalc_target(phy_info_t *pi)
1723 u8 maxtxpwr, mintxpwr, rate, pactrl;
1725 u8 tx_pwr_target[TXP_NUM_RATES];
1727 u8 tx_pwr_min = 255;
1728 u8 tx_pwr_max_rate_ind = 0;
1732 u32 band = CHSPEC2WLC_BAND(pi->radio_chanspec);
1733 initfn_t txpwr_recalc_fn = NULL;
1735 chspec = pi->radio_chanspec;
1736 if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_NONE)
1737 target_chan = CHSPEC_CHANNEL(chspec);
1738 else if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_UPPER)
1739 target_chan = UPPER_20_SB(CHSPEC_CHANNEL(chspec));
1741 target_chan = LOWER_20_SB(CHSPEC_CHANNEL(chspec));
1747 if (CHSPEC_IS40(pi->radio_chanspec)) {
1748 offset_mcs = pi->mcs40_po;
1749 for (i = TXP_FIRST_SISO_MCS_20;
1750 i <= TXP_LAST_SISO_MCS_20; i++) {
1751 pi->tx_srom_max_rate_2g[i - 8] =
1752 pi->tx_srom_max_2g -
1753 ((offset_mcs & 0xf) * 2);
1757 offset_mcs = pi->mcs20_po;
1758 for (i = TXP_FIRST_SISO_MCS_20;
1759 i <= TXP_LAST_SISO_MCS_20; i++) {
1760 pi->tx_srom_max_rate_2g[i - 8] =
1761 pi->tx_srom_max_2g -
1762 ((offset_mcs & 0xf) * 2);
1768 max_num_rate = ((ISNPHY(pi)) ? (TXP_NUM_RATES) :
1770 (TXP_LAST_SISO_MCS_20 + 1) : (TXP_LAST_OFDM + 1)));
1772 max_num_rate = ((ISNPHY(pi)) ? (TXP_NUM_RATES) : (TXP_LAST_OFDM + 1));
1775 wlc_phy_upd_env_txpwr_rate_limits(pi, band);
1777 for (rate = start_rate; rate < max_num_rate; rate++) {
1779 tx_pwr_target[rate] = pi->tx_user_target[rate];
1781 if (pi->user_txpwr_at_rfport) {
1782 tx_pwr_target[rate] +=
1783 wlc_user_txpwr_antport_to_rfport(pi, target_chan,
1789 wlc_phy_txpower_sromlimit((wlc_phy_t *) pi, target_chan,
1790 &mintxpwr, &maxtxpwr, rate);
1792 maxtxpwr = min(maxtxpwr, pi->txpwr_limit[rate]);
1795 (maxtxpwr > pactrl) ? (maxtxpwr - pactrl) : 0;
1797 maxtxpwr = (maxtxpwr > 6) ? (maxtxpwr - 6) : 0;
1799 maxtxpwr = min(maxtxpwr, tx_pwr_target[rate]);
1801 if (pi->txpwr_percent <= 100)
1802 maxtxpwr = (maxtxpwr * pi->txpwr_percent) / 100;
1804 tx_pwr_target[rate] = max(maxtxpwr, mintxpwr);
1807 tx_pwr_target[rate] =
1808 min(tx_pwr_target[rate], pi->txpwr_env_limit[rate]);
1810 if (tx_pwr_target[rate] > tx_pwr_max)
1811 tx_pwr_max_rate_ind = rate;
1813 tx_pwr_max = max(tx_pwr_max, tx_pwr_target[rate]);
1814 tx_pwr_min = min(tx_pwr_min, tx_pwr_target[rate]);
1817 memset(pi->tx_power_offset, 0, sizeof(pi->tx_power_offset));
1818 pi->tx_power_max = tx_pwr_max;
1819 pi->tx_power_min = tx_pwr_min;
1820 pi->tx_power_max_rate_ind = tx_pwr_max_rate_ind;
1821 for (rate = 0; rate < max_num_rate; rate++) {
1823 pi->tx_power_target[rate] = tx_pwr_target[rate];
1825 if (!pi->hwpwrctrl || ISNPHY(pi)) {
1826 pi->tx_power_offset[rate] =
1827 pi->tx_power_max - pi->tx_power_target[rate];
1829 pi->tx_power_offset[rate] =
1830 pi->tx_power_target[rate] - pi->tx_power_min;
1834 txpwr_recalc_fn = pi->pi_fptr.txpwrrecalc;
1835 if (txpwr_recalc_fn)
1836 (*txpwr_recalc_fn) (pi);
1840 wlc_phy_txpower_reg_limit_calc(phy_info_t *pi, struct txpwr_limits *txpwr,
1841 chanspec_t chanspec)
1843 u8 tmp_txpwr_limit[2 * WLC_NUM_RATES_OFDM];
1844 u8 *txpwr_ptr1 = NULL, *txpwr_ptr2 = NULL;
1845 int rate_start_index = 0, rate1, rate2, k;
1847 for (rate1 = WL_TX_POWER_CCK_FIRST, rate2 = 0;
1848 rate2 < WL_TX_POWER_CCK_NUM; rate1++, rate2++)
1849 pi->txpwr_limit[rate1] = txpwr->cck[rate2];
1851 for (rate1 = WL_TX_POWER_OFDM_FIRST, rate2 = 0;
1852 rate2 < WL_TX_POWER_OFDM_NUM; rate1++, rate2++)
1853 pi->txpwr_limit[rate1] = txpwr->ofdm[rate2];
1857 for (k = 0; k < 4; k++) {
1861 txpwr_ptr1 = txpwr->mcs_20_siso;
1862 txpwr_ptr2 = txpwr->ofdm;
1863 rate_start_index = WL_TX_POWER_OFDM_FIRST;
1867 txpwr_ptr1 = txpwr->mcs_20_cdd;
1868 txpwr_ptr2 = txpwr->ofdm_cdd;
1869 rate_start_index = WL_TX_POWER_OFDM20_CDD_FIRST;
1873 txpwr_ptr1 = txpwr->mcs_40_siso;
1874 txpwr_ptr2 = txpwr->ofdm_40_siso;
1876 WL_TX_POWER_OFDM40_SISO_FIRST;
1880 txpwr_ptr1 = txpwr->mcs_40_cdd;
1881 txpwr_ptr2 = txpwr->ofdm_40_cdd;
1882 rate_start_index = WL_TX_POWER_OFDM40_CDD_FIRST;
1886 for (rate2 = 0; rate2 < WLC_NUM_RATES_OFDM; rate2++) {
1887 tmp_txpwr_limit[rate2] = 0;
1888 tmp_txpwr_limit[WLC_NUM_RATES_OFDM + rate2] =
1891 wlc_phy_mcs_to_ofdm_powers_nphy(tmp_txpwr_limit, 0,
1892 WLC_NUM_RATES_OFDM - 1,
1893 WLC_NUM_RATES_OFDM);
1894 for (rate1 = rate_start_index, rate2 = 0;
1895 rate2 < WLC_NUM_RATES_OFDM; rate1++, rate2++)
1896 pi->txpwr_limit[rate1] =
1897 min(txpwr_ptr2[rate2],
1898 tmp_txpwr_limit[rate2]);
1901 for (k = 0; k < 4; k++) {
1905 txpwr_ptr1 = txpwr->ofdm;
1906 txpwr_ptr2 = txpwr->mcs_20_siso;
1907 rate_start_index = WL_TX_POWER_MCS20_SISO_FIRST;
1911 txpwr_ptr1 = txpwr->ofdm_cdd;
1912 txpwr_ptr2 = txpwr->mcs_20_cdd;
1913 rate_start_index = WL_TX_POWER_MCS20_CDD_FIRST;
1917 txpwr_ptr1 = txpwr->ofdm_40_siso;
1918 txpwr_ptr2 = txpwr->mcs_40_siso;
1919 rate_start_index = WL_TX_POWER_MCS40_SISO_FIRST;
1923 txpwr_ptr1 = txpwr->ofdm_40_cdd;
1924 txpwr_ptr2 = txpwr->mcs_40_cdd;
1925 rate_start_index = WL_TX_POWER_MCS40_CDD_FIRST;
1928 for (rate2 = 0; rate2 < WLC_NUM_RATES_OFDM; rate2++) {
1929 tmp_txpwr_limit[rate2] = 0;
1930 tmp_txpwr_limit[WLC_NUM_RATES_OFDM + rate2] =
1933 wlc_phy_ofdm_to_mcs_powers_nphy(tmp_txpwr_limit, 0,
1934 WLC_NUM_RATES_OFDM - 1,
1935 WLC_NUM_RATES_OFDM);
1936 for (rate1 = rate_start_index, rate2 = 0;
1937 rate2 < WLC_NUM_RATES_MCS_1_STREAM;
1939 pi->txpwr_limit[rate1] =
1940 min(txpwr_ptr2[rate2],
1941 tmp_txpwr_limit[rate2]);
1944 for (k = 0; k < 2; k++) {
1948 rate_start_index = WL_TX_POWER_MCS20_STBC_FIRST;
1949 txpwr_ptr1 = txpwr->mcs_20_stbc;
1953 rate_start_index = WL_TX_POWER_MCS40_STBC_FIRST;
1954 txpwr_ptr1 = txpwr->mcs_40_stbc;
1957 for (rate1 = rate_start_index, rate2 = 0;
1958 rate2 < WLC_NUM_RATES_MCS_1_STREAM;
1960 pi->txpwr_limit[rate1] = txpwr_ptr1[rate2];
1963 for (k = 0; k < 2; k++) {
1967 rate_start_index = WL_TX_POWER_MCS20_SDM_FIRST;
1968 txpwr_ptr1 = txpwr->mcs_20_mimo;
1972 rate_start_index = WL_TX_POWER_MCS40_SDM_FIRST;
1973 txpwr_ptr1 = txpwr->mcs_40_mimo;
1976 for (rate1 = rate_start_index, rate2 = 0;
1977 rate2 < WLC_NUM_RATES_MCS_2_STREAM;
1979 pi->txpwr_limit[rate1] = txpwr_ptr1[rate2];
1982 pi->txpwr_limit[WL_TX_POWER_MCS_32] = txpwr->mcs32;
1984 pi->txpwr_limit[WL_TX_POWER_MCS40_CDD_FIRST] =
1985 min(pi->txpwr_limit[WL_TX_POWER_MCS40_CDD_FIRST],
1986 pi->txpwr_limit[WL_TX_POWER_MCS_32]);
1987 pi->txpwr_limit[WL_TX_POWER_MCS_32] =
1988 pi->txpwr_limit[WL_TX_POWER_MCS40_CDD_FIRST];
1992 void wlc_phy_txpwr_percent_set(wlc_phy_t *ppi, u8 txpwr_percent)
1994 phy_info_t *pi = (phy_info_t *) ppi;
1996 pi->txpwr_percent = txpwr_percent;
1999 void wlc_phy_machwcap_set(wlc_phy_t *ppi, u32 machwcap)
2001 phy_info_t *pi = (phy_info_t *) ppi;
2003 pi->sh->machwcap = machwcap;
2006 void wlc_phy_runbist_config(wlc_phy_t *ppi, bool start_end)
2008 phy_info_t *pi = (phy_info_t *) ppi;
2012 if (start_end == ON) {
2016 if (NREV_IS(pi->pubpi.phy_rev, 3)
2017 || NREV_IS(pi->pubpi.phy_rev, 4)) {
2018 W_REG(&pi->regs->phyregaddr, 0xa0);
2019 (void)R_REG(&pi->regs->phyregaddr);
2020 rxc = R_REG(&pi->regs->phyregdata);
2021 W_REG(&pi->regs->phyregdata,
2025 if (NREV_IS(pi->pubpi.phy_rev, 3)
2026 || NREV_IS(pi->pubpi.phy_rev, 4)) {
2027 W_REG(&pi->regs->phyregaddr, 0xa0);
2028 (void)R_REG(&pi->regs->phyregaddr);
2029 W_REG(&pi->regs->phyregdata, rxc);
2032 wlc_phy_por_inform(ppi);
2037 wlc_phy_txpower_limit_set(wlc_phy_t *ppi, struct txpwr_limits *txpwr,
2038 chanspec_t chanspec)
2040 phy_info_t *pi = (phy_info_t *) ppi;
2042 wlc_phy_txpower_reg_limit_calc(pi, txpwr, chanspec);
2046 for (i = TXP_FIRST_OFDM_20_CDD, j = 0;
2047 j < WLC_NUM_RATES_MCS_1_STREAM; i++, j++) {
2048 if (txpwr->mcs_20_siso[j])
2049 pi->txpwr_limit[i] = txpwr->mcs_20_siso[j];
2051 pi->txpwr_limit[i] = txpwr->ofdm[j];
2055 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2057 wlc_phy_txpower_recalc_target(pi);
2058 wlc_phy_cal_txpower_recalc_sw(pi);
2059 wlapi_enable_mac(pi->sh->physhim);
2062 void wlc_phy_ofdm_rateset_war(wlc_phy_t *pih, bool war)
2064 phy_info_t *pi = (phy_info_t *) pih;
2066 pi->ofdm_rateset_war = war;
2069 void wlc_phy_bf_preempt_enable(wlc_phy_t *pih, bool bf_preempt)
2071 phy_info_t *pi = (phy_info_t *) pih;
2073 pi->bf_preempt_4306 = bf_preempt;
2076 void wlc_phy_txpower_update_shm(phy_info_t *pi)
2086 if (pi->hwpwrctrl) {
2089 wlapi_bmac_write_shm(pi->sh->physhim, M_TXPWR_MAX, 63);
2090 wlapi_bmac_write_shm(pi->sh->physhim, M_TXPWR_N,
2091 1 << NUM_TSSI_FRAMES);
2093 wlapi_bmac_write_shm(pi->sh->physhim, M_TXPWR_TARGET,
2094 pi->tx_power_min << NUM_TSSI_FRAMES);
2096 wlapi_bmac_write_shm(pi->sh->physhim, M_TXPWR_CUR,
2099 for (j = TXP_FIRST_OFDM; j <= TXP_LAST_OFDM; j++) {
2100 const u8 ucode_ofdm_rates[] = {
2101 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c
2103 offset = wlapi_bmac_rate_shm_offset(pi->sh->physhim,
2104 ucode_ofdm_rates[j -
2106 wlapi_bmac_write_shm(pi->sh->physhim, offset + 6,
2107 pi->tx_power_offset[j]);
2108 wlapi_bmac_write_shm(pi->sh->physhim, offset + 14,
2109 -(pi->tx_power_offset[j] / 2));
2112 wlapi_bmac_mhf(pi->sh->physhim, MHF2, MHF2_HWPWRCTL,
2113 MHF2_HWPWRCTL, WLC_BAND_ALL);
2117 for (i = TXP_FIRST_OFDM; i <= TXP_LAST_OFDM; i++)
2118 pi->tx_power_offset[i] =
2119 (u8) roundup(pi->tx_power_offset[i], 8);
2120 wlapi_bmac_write_shm(pi->sh->physhim, M_OFDM_OFFSET,
2122 tx_power_offset[TXP_FIRST_OFDM]
2127 bool wlc_phy_txpower_hw_ctrl_get(wlc_phy_t *ppi)
2129 phy_info_t *pi = (phy_info_t *) ppi;
2132 return pi->nphy_txpwrctrl;
2134 return pi->hwpwrctrl;
2138 void wlc_phy_txpower_hw_ctrl_set(wlc_phy_t *ppi, bool hwpwrctrl)
2140 phy_info_t *pi = (phy_info_t *) ppi;
2141 bool cur_hwpwrctrl = pi->hwpwrctrl;
2144 if (!pi->hwpwrctrl_capable) {
2148 pi->hwpwrctrl = hwpwrctrl;
2149 pi->nphy_txpwrctrl = hwpwrctrl;
2150 pi->txpwrctrl = hwpwrctrl;
2155 (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC));
2157 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2159 wlc_phy_txpwrctrl_enable_nphy(pi, pi->nphy_txpwrctrl);
2160 if (pi->nphy_txpwrctrl == PHY_TPC_HW_OFF) {
2161 wlc_phy_txpwr_fixpower_nphy(pi);
2164 mod_phy_reg(pi, 0x1e7, (0x7f << 0),
2165 pi->saved_txpwr_idx);
2169 wlapi_enable_mac(pi->sh->physhim);
2170 } else if (hwpwrctrl != cur_hwpwrctrl) {
2176 void wlc_phy_txpower_ipa_upd(phy_info_t *pi)
2179 if (NREV_GE(pi->pubpi.phy_rev, 3)) {
2180 pi->ipa2g_on = (pi->srom_fem2g.extpagain == 2);
2181 pi->ipa5g_on = (pi->srom_fem5g.extpagain == 2);
2183 pi->ipa2g_on = false;
2184 pi->ipa5g_on = false;
2188 static u32 wlc_phy_txpower_est_power_nphy(phy_info_t *pi);
2190 static u32 wlc_phy_txpower_est_power_nphy(phy_info_t *pi)
2192 s16 tx0_status, tx1_status;
2193 u16 estPower1, estPower2;
2194 u8 pwr0, pwr1, adj_pwr0, adj_pwr1;
2197 estPower1 = read_phy_reg(pi, 0x118);
2198 estPower2 = read_phy_reg(pi, 0x119);
2200 if ((estPower1 & (0x1 << 8))
2202 pwr0 = (u8) (estPower1 & (0xff << 0))
2208 if ((estPower2 & (0x1 << 8))
2210 pwr1 = (u8) (estPower2 & (0xff << 0))
2216 tx0_status = read_phy_reg(pi, 0x1ed);
2217 tx1_status = read_phy_reg(pi, 0x1ee);
2219 if ((tx0_status & (0x1 << 15))
2221 adj_pwr0 = (u8) (tx0_status & (0xff << 0))
2226 if ((tx1_status & (0x1 << 15))
2228 adj_pwr1 = (u8) (tx1_status & (0xff << 0))
2235 (u32) ((pwr0 << 24) | (pwr1 << 16) | (adj_pwr0 << 8) | adj_pwr1);
2240 wlc_phy_txpower_get_current(wlc_phy_t *ppi, tx_power_t *power, uint channel)
2242 phy_info_t *pi = (phy_info_t *) ppi;
2243 uint rate, num_rates;
2244 u8 min_pwr, max_pwr;
2246 #if WL_TX_POWER_RATES != TXP_NUM_RATES
2247 #error "tx_power_t struct out of sync with this fn"
2251 power->rf_cores = 2;
2252 power->flags |= (WL_TX_POWER_F_MIMO);
2253 if (pi->nphy_txpwrctrl == PHY_TPC_HW_ON)
2255 (WL_TX_POWER_F_ENABLED | WL_TX_POWER_F_HW);
2256 } else if (ISLCNPHY(pi)) {
2257 power->rf_cores = 1;
2258 power->flags |= (WL_TX_POWER_F_SISO);
2259 if (pi->radiopwr_override == RADIOPWR_OVERRIDE_DEF)
2260 power->flags |= WL_TX_POWER_F_ENABLED;
2262 power->flags |= WL_TX_POWER_F_HW;
2265 num_rates = ((ISNPHY(pi)) ? (TXP_NUM_RATES) :
2267 (TXP_LAST_OFDM_20_CDD + 1) : (TXP_LAST_OFDM + 1)));
2269 for (rate = 0; rate < num_rates; rate++) {
2270 power->user_limit[rate] = pi->tx_user_target[rate];
2271 wlc_phy_txpower_sromlimit(ppi, channel, &min_pwr, &max_pwr,
2273 power->board_limit[rate] = (u8) max_pwr;
2274 power->target[rate] = pi->tx_power_target[rate];
2280 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2281 wlc_phyreg_enter((wlc_phy_t *) pi);
2282 est_pout = wlc_phy_txpower_est_power_nphy(pi);
2283 wlc_phyreg_exit((wlc_phy_t *) pi);
2284 wlapi_enable_mac(pi->sh->physhim);
2286 power->est_Pout[0] = (est_pout >> 8) & 0xff;
2287 power->est_Pout[1] = est_pout & 0xff;
2289 power->est_Pout_act[0] = est_pout >> 24;
2290 power->est_Pout_act[1] = (est_pout >> 16) & 0xff;
2292 if (power->est_Pout[0] == 0x80)
2293 power->est_Pout[0] = 0;
2294 if (power->est_Pout[1] == 0x80)
2295 power->est_Pout[1] = 0;
2297 if (power->est_Pout_act[0] == 0x80)
2298 power->est_Pout_act[0] = 0;
2299 if (power->est_Pout_act[1] == 0x80)
2300 power->est_Pout_act[1] = 0;
2302 power->est_Pout_cck = 0;
2304 power->tx_power_max[0] = pi->tx_power_max;
2305 power->tx_power_max[1] = pi->tx_power_max;
2307 power->tx_power_max_rate_ind[0] = pi->tx_power_max_rate_ind;
2308 power->tx_power_max_rate_ind[1] = pi->tx_power_max_rate_ind;
2309 } else if (!pi->hwpwrctrl) {
2310 } else if (pi->sh->up) {
2312 wlc_phyreg_enter(ppi);
2315 power->tx_power_max[0] = pi->tx_power_max;
2316 power->tx_power_max[1] = pi->tx_power_max;
2318 power->tx_power_max_rate_ind[0] =
2319 pi->tx_power_max_rate_ind;
2320 power->tx_power_max_rate_ind[1] =
2321 pi->tx_power_max_rate_ind;
2323 if (wlc_phy_tpc_isenabled_lcnphy(pi))
2325 (WL_TX_POWER_F_HW | WL_TX_POWER_F_ENABLED);
2328 ~(WL_TX_POWER_F_HW | WL_TX_POWER_F_ENABLED);
2330 wlc_lcnphy_get_tssi(pi, (s8 *) &power->est_Pout[0],
2331 (s8 *) &power->est_Pout_cck);
2333 wlc_phyreg_exit(ppi);
2337 void wlc_phy_antsel_type_set(wlc_phy_t *ppi, u8 antsel_type)
2339 phy_info_t *pi = (phy_info_t *) ppi;
2341 pi->antsel_type = antsel_type;
2344 bool wlc_phy_test_ison(wlc_phy_t *ppi)
2346 phy_info_t *pi = (phy_info_t *) ppi;
2348 return pi->phytest_on;
2351 bool wlc_phy_ant_rxdiv_get(wlc_phy_t *ppi, u8 *pval)
2353 phy_info_t *pi = (phy_info_t *) ppi;
2356 wlc_phyreg_enter(ppi);
2361 } else if (ISLCNPHY(pi)) {
2362 u16 crsctrl = read_phy_reg(pi, 0x410);
2363 u16 div = crsctrl & (0x1 << 1);
2364 *pval = (div | ((crsctrl & (0x1 << 0)) ^ (div >> 1)));
2367 wlc_phyreg_exit(ppi);
2372 void wlc_phy_ant_rxdiv_set(wlc_phy_t *ppi, u8 val)
2374 phy_info_t *pi = (phy_info_t *) ppi;
2377 pi->sh->rx_antdiv = val;
2379 if (!(ISNPHY(pi) && D11REV_IS(pi->sh->corerev, 16))) {
2380 if (val > ANT_RX_DIV_FORCE_1)
2381 wlapi_bmac_mhf(pi->sh->physhim, MHF1, MHF1_ANTDIV,
2382 MHF1_ANTDIV, WLC_BAND_ALL);
2384 wlapi_bmac_mhf(pi->sh->physhim, MHF1, MHF1_ANTDIV, 0,
2397 (0 == (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC));
2399 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2402 if (val > ANT_RX_DIV_FORCE_1) {
2403 mod_phy_reg(pi, 0x410, (0x1 << 1), 0x01 << 1);
2404 mod_phy_reg(pi, 0x410,
2406 ((ANT_RX_DIV_START_1 == val) ? 1 : 0) << 0);
2408 mod_phy_reg(pi, 0x410, (0x1 << 1), 0x00 << 1);
2409 mod_phy_reg(pi, 0x410, (0x1 << 0), (u16) val << 0);
2414 wlapi_enable_mac(pi->sh->physhim);
2420 wlc_phy_noise_calc_phy(phy_info_t *pi, u32 *cmplx_pwr, s8 *pwr_ant)
2422 s8 cmplx_pwr_dbm[PHY_CORE_MAX];
2425 memset((u8 *) cmplx_pwr_dbm, 0, sizeof(cmplx_pwr_dbm));
2426 wlc_phy_compute_dB(cmplx_pwr, cmplx_pwr_dbm, pi->pubpi.phy_corenum);
2428 for (i = 0; i < pi->pubpi.phy_corenum; i++) {
2429 if (NREV_GE(pi->pubpi.phy_rev, 3))
2430 cmplx_pwr_dbm[i] += (s8) PHY_NOISE_OFFSETFACT_4322;
2433 cmplx_pwr_dbm[i] += (s8) (16 - (15) * 3 - 70);
2436 for (i = 0; i < pi->pubpi.phy_corenum; i++) {
2437 pi->nphy_noise_win[i][pi->nphy_noise_index] = cmplx_pwr_dbm[i];
2438 pwr_ant[i] = cmplx_pwr_dbm[i];
2440 pi->nphy_noise_index =
2441 MODINC_POW2(pi->nphy_noise_index, PHY_NOISE_WINDOW_SZ);
2446 wlc_phy_noise_sample_request(wlc_phy_t *pih, u8 reason, u8 ch)
2448 phy_info_t *pi = (phy_info_t *) pih;
2449 s8 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;
2450 bool sampling_in_progress = (pi->phynoise_state != 0);
2451 bool wait_for_intr = true;
2453 if (NORADIO_ENAB(pi->pubpi)) {
2458 case PHY_NOISE_SAMPLE_MON:
2460 pi->phynoise_chan_watchdog = ch;
2461 pi->phynoise_state |= PHY_NOISE_STATE_MON;
2465 case PHY_NOISE_SAMPLE_EXTERNAL:
2467 pi->phynoise_state |= PHY_NOISE_STATE_EXTERNAL;
2474 if (sampling_in_progress)
2477 pi->phynoise_now = pi->sh->now;
2479 if (pi->phy_fixed_noise) {
2481 pi->nphy_noise_win[WL_ANT_IDX_1][pi->nphy_noise_index] =
2482 PHY_NOISE_FIXED_VAL_NPHY;
2483 pi->nphy_noise_win[WL_ANT_IDX_2][pi->nphy_noise_index] =
2484 PHY_NOISE_FIXED_VAL_NPHY;
2485 pi->nphy_noise_index = MODINC_POW2(pi->nphy_noise_index,
2486 PHY_NOISE_WINDOW_SZ);
2488 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;
2491 noise_dbm = PHY_NOISE_FIXED_VAL;
2494 wait_for_intr = false;
2499 if (!pi->phynoise_polling
2500 || (reason == PHY_NOISE_SAMPLE_EXTERNAL)) {
2501 wlapi_bmac_write_shm(pi->sh->physhim, M_JSSI_0, 0);
2502 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP0, 0);
2503 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP1, 0);
2504 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP2, 0);
2505 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP3, 0);
2507 OR_REG(&pi->regs->maccommand,
2510 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2511 wlc_lcnphy_deaf_mode(pi, (bool) 0);
2512 noise_dbm = (s8) wlc_lcnphy_rx_signal_power(pi, 20);
2513 wlc_lcnphy_deaf_mode(pi, (bool) 1);
2514 wlapi_enable_mac(pi->sh->physhim);
2515 wait_for_intr = false;
2517 } else if (ISNPHY(pi)) {
2518 if (!pi->phynoise_polling
2519 || (reason == PHY_NOISE_SAMPLE_EXTERNAL)) {
2521 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP0, 0);
2522 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP1, 0);
2523 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP2, 0);
2524 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP3, 0);
2526 OR_REG(&pi->regs->maccommand,
2529 phy_iq_est_t est[PHY_CORE_MAX];
2530 u32 cmplx_pwr[PHY_CORE_MAX];
2531 s8 noise_dbm_ant[PHY_CORE_MAX];
2532 u16 log_num_samps, num_samps, classif_state = 0;
2537 memset((u8 *) est, 0, sizeof(est));
2538 memset((u8 *) cmplx_pwr, 0, sizeof(cmplx_pwr));
2539 memset((u8 *) noise_dbm_ant, 0, sizeof(noise_dbm_ant));
2541 log_num_samps = PHY_NOISE_SAMPLE_LOG_NUM_NPHY;
2542 num_samps = 1 << log_num_samps;
2544 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2545 classif_state = wlc_phy_classifier_nphy(pi, 0, 0);
2546 wlc_phy_classifier_nphy(pi, 3, 0);
2547 wlc_phy_rx_iq_est_nphy(pi, est, num_samps, wait_time,
2549 wlc_phy_classifier_nphy(pi, (0x7 << 0), classif_state);
2550 wlapi_enable_mac(pi->sh->physhim);
2552 for (i = 0; i < pi->pubpi.phy_corenum; i++)
2555 est[i].q_pwr) >> log_num_samps;
2557 wlc_phy_noise_calc_phy(pi, cmplx_pwr, noise_dbm_ant);
2559 for (i = 0; i < pi->pubpi.phy_corenum; i++) {
2560 pi->nphy_noise_win[i][pi->nphy_noise_index] =
2563 if (noise_dbm_ant[i] > noise_dbm)
2564 noise_dbm = noise_dbm_ant[i];
2566 pi->nphy_noise_index = MODINC_POW2(pi->nphy_noise_index,
2567 PHY_NOISE_WINDOW_SZ);
2569 wait_for_intr = false;
2576 wlc_phy_noise_cb(pi, ch, noise_dbm);
2580 void wlc_phy_noise_sample_request_external(wlc_phy_t *pih)
2584 channel = CHSPEC_CHANNEL(wlc_phy_chanspec_get(pih));
2586 wlc_phy_noise_sample_request(pih, PHY_NOISE_SAMPLE_EXTERNAL, channel);
2589 static void wlc_phy_noise_cb(phy_info_t *pi, u8 channel, s8 noise_dbm)
2591 if (!pi->phynoise_state)
2594 if (pi->phynoise_state & PHY_NOISE_STATE_MON) {
2595 if (pi->phynoise_chan_watchdog == channel) {
2596 pi->sh->phy_noise_window[pi->sh->phy_noise_index] =
2598 pi->sh->phy_noise_index =
2599 MODINC(pi->sh->phy_noise_index, MA_WINDOW_SZ);
2601 pi->phynoise_state &= ~PHY_NOISE_STATE_MON;
2604 if (pi->phynoise_state & PHY_NOISE_STATE_EXTERNAL) {
2605 pi->phynoise_state &= ~PHY_NOISE_STATE_EXTERNAL;
2610 static s8 wlc_phy_noise_read_shmem(phy_info_t *pi)
2612 u32 cmplx_pwr[PHY_CORE_MAX];
2613 s8 noise_dbm_ant[PHY_CORE_MAX];
2615 u32 cmplx_pwr_tot = 0;
2616 s8 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;
2619 memset((u8 *) cmplx_pwr, 0, sizeof(cmplx_pwr));
2620 memset((u8 *) noise_dbm_ant, 0, sizeof(noise_dbm_ant));
2622 for (idx = 0, core = 0; core < pi->pubpi.phy_corenum; idx += 2, core++) {
2623 lo = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP(idx));
2624 hi = wlapi_bmac_read_shm(pi->sh->physhim,
2625 M_PWRIND_MAP(idx + 1));
2626 cmplx_pwr[core] = (hi << 16) + lo;
2627 cmplx_pwr_tot += cmplx_pwr[core];
2628 if (cmplx_pwr[core] == 0) {
2629 noise_dbm_ant[core] = PHY_NOISE_FIXED_VAL_NPHY;
2631 cmplx_pwr[core] >>= PHY_NOISE_SAMPLE_LOG_NUM_UCODE;
2634 if (cmplx_pwr_tot != 0)
2635 wlc_phy_noise_calc_phy(pi, cmplx_pwr, noise_dbm_ant);
2637 for (core = 0; core < pi->pubpi.phy_corenum; core++) {
2638 pi->nphy_noise_win[core][pi->nphy_noise_index] =
2639 noise_dbm_ant[core];
2641 if (noise_dbm_ant[core] > noise_dbm)
2642 noise_dbm = noise_dbm_ant[core];
2644 pi->nphy_noise_index =
2645 MODINC_POW2(pi->nphy_noise_index, PHY_NOISE_WINDOW_SZ);
2651 void wlc_phy_noise_sample_intr(wlc_phy_t *pih)
2653 phy_info_t *pi = (phy_info_t *) pih;
2656 s8 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;
2659 u32 cmplx_pwr, cmplx_pwr0, cmplx_pwr1;
2661 s32 pwr_offset_dB, gain_dB;
2662 u16 status_0, status_1;
2664 jssi_aux = wlapi_bmac_read_shm(pi->sh->physhim, M_JSSI_AUX);
2665 channel = jssi_aux & D11_CURCHANNEL_MAX;
2667 lo = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP0);
2668 hi = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP1);
2669 cmplx_pwr0 = (hi << 16) + lo;
2671 lo = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP2);
2672 hi = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP3);
2673 cmplx_pwr1 = (hi << 16) + lo;
2674 cmplx_pwr = (cmplx_pwr0 + cmplx_pwr1) >> 6;
2677 status_1 = wlapi_bmac_read_shm(pi->sh->physhim, M_JSSI_0);
2678 if ((cmplx_pwr > 0 && cmplx_pwr < 500)
2679 && ((status_1 & 0xc000) == 0x4000)) {
2681 wlc_phy_compute_dB(&cmplx_pwr, &noise_dbm,
2682 pi->pubpi.phy_corenum);
2683 pwr_offset_dB = (read_phy_reg(pi, 0x434) & 0xFF);
2684 if (pwr_offset_dB > 127)
2685 pwr_offset_dB -= 256;
2687 noise_dbm += (s8) (pwr_offset_dB - 30);
2689 gain_dB = (status_0 & 0x1ff);
2690 noise_dbm -= (s8) (gain_dB);
2692 noise_dbm = PHY_NOISE_FIXED_VAL_LCNPHY;
2694 } else if (ISNPHY(pi)) {
2696 jssi_aux = wlapi_bmac_read_shm(pi->sh->physhim, M_JSSI_AUX);
2697 channel = jssi_aux & D11_CURCHANNEL_MAX;
2699 noise_dbm = wlc_phy_noise_read_shmem(pi);
2702 wlc_phy_noise_cb(pi, channel, noise_dbm);
2706 s8 lcnphy_gain_index_offset_for_pkt_rssi[] = {
2747 void wlc_phy_compute_dB(u32 *cmplx_pwr, s8 *p_cmplx_pwr_dB, u8 core)
2749 u8 shift_ct, lsb, msb, secondmsb, i;
2752 for (i = 0; i < core; i++) {
2754 shift_ct = msb = secondmsb = 0;
2758 lsb = (u8) (tmp & 1);
2762 secondmsb = (u8) ((cmplx_pwr[i] >> (msb - 1)) & 1);
2763 p_cmplx_pwr_dB[i] = (s8) (3 * msb + 2 * secondmsb);
2767 void BCMFASTPATH wlc_phy_rssi_compute(wlc_phy_t *pih, void *ctx)
2769 wlc_d11rxhdr_t *wlc_rxhdr = (wlc_d11rxhdr_t *) ctx;
2770 d11rxhdr_t *rxh = &wlc_rxhdr->rxhdr;
2771 int rssi = le16_to_cpu(rxh->PhyRxStatus_1) & PRXS1_JSSI_MASK;
2772 uint radioid = pih->radioid;
2773 phy_info_t *pi = (phy_info_t *) pih;
2775 if (NORADIO_ENAB(pi->pubpi)) {
2776 rssi = WLC_RSSI_INVALID;
2780 if ((pi->sh->corerev >= 11)
2781 && !(le16_to_cpu(rxh->RxStatus2) & RXS_PHYRXST_VALID)) {
2782 rssi = WLC_RSSI_INVALID;
2787 u8 gidx = (le16_to_cpu(rxh->PhyRxStatus_2) & 0xFC00) >> 10;
2788 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
2793 rssi = rssi + lcnphy_gain_index_offset_for_pkt_rssi[gidx];
2794 if ((rssi > -46) && (gidx > 18))
2797 rssi = rssi + pi_lcn->lcnphy_pkteng_rssi_slope;
2807 } else if (radioid == BCM2055_ID || radioid == BCM2056_ID
2808 || radioid == BCM2057_ID) {
2809 rssi = wlc_phy_rssi_compute_nphy(pi, wlc_rxhdr);
2813 wlc_rxhdr->rssi = (s8) rssi;
2816 void wlc_phy_freqtrack_start(wlc_phy_t *pih)
2821 void wlc_phy_freqtrack_end(wlc_phy_t *pih)
2826 void wlc_phy_set_deaf(wlc_phy_t *ppi, bool user_flag)
2829 pi = (phy_info_t *) ppi;
2832 wlc_lcnphy_deaf_mode(pi, true);
2833 else if (ISNPHY(pi))
2834 wlc_nphy_deaf_mode(pi, true);
2837 void wlc_phy_watchdog(wlc_phy_t *pih)
2839 phy_info_t *pi = (phy_info_t *) pih;
2840 bool delay_phy_cal = false;
2843 if (!pi->watchdog_override)
2846 if (!(SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi))) {
2847 wlc_phy_noise_sample_request((wlc_phy_t *) pi,
2848 PHY_NOISE_SAMPLE_MON,
2853 if (pi->phynoise_state && (pi->sh->now - pi->phynoise_now) > 5) {
2854 pi->phynoise_state = 0;
2857 if ((!pi->phycal_txpower) ||
2858 ((pi->sh->now - pi->phycal_txpower) >= pi->sh->fast_timer)) {
2860 if (!SCAN_INPROG_PHY(pi) && wlc_phy_cal_txpower_recalc_sw(pi)) {
2861 pi->phycal_txpower = pi->sh->now;
2865 if (NORADIO_ENAB(pi->pubpi))
2868 if ((SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi)
2869 || ASSOC_INPROG_PHY(pi)))
2872 if (ISNPHY(pi) && !pi->disable_percal && !delay_phy_cal) {
2874 if ((pi->nphy_perical != PHY_PERICAL_DISABLE) &&
2875 (pi->nphy_perical != PHY_PERICAL_MANUAL) &&
2876 ((pi->sh->now - pi->nphy_perical_last) >=
2877 pi->sh->glacial_timer))
2878 wlc_phy_cal_perical((wlc_phy_t *) pi,
2879 PHY_PERICAL_WATCHDOG);
2881 wlc_phy_txpwr_papd_cal_nphy(pi);
2885 if (pi->phy_forcecal ||
2886 ((pi->sh->now - pi->phy_lastcal) >=
2887 pi->sh->glacial_timer)) {
2888 if (!(SCAN_RM_IN_PROGRESS(pi) || ASSOC_INPROG_PHY(pi)))
2889 wlc_lcnphy_calib_modes(pi,
2890 LCNPHY_PERICAL_TEMPBASED_TXPWRCTRL);
2892 (SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi)
2893 || ASSOC_INPROG_PHY(pi)
2894 || pi->carrier_suppr_disable
2895 || pi->disable_percal))
2896 wlc_lcnphy_calib_modes(pi,
2897 PHY_PERICAL_WATCHDOG);
2902 void wlc_phy_BSSinit(wlc_phy_t *pih, bool bonlyap, int rssi)
2904 phy_info_t *pi = (phy_info_t *) pih;
2908 for (i = 0; i < MA_WINDOW_SZ; i++) {
2909 pi->sh->phy_noise_window[i] = (s8) (rssi & 0xff);
2912 for (i = 0; i < MA_WINDOW_SZ; i++)
2913 pi->sh->phy_noise_window[i] =
2914 PHY_NOISE_FIXED_VAL_LCNPHY;
2916 pi->sh->phy_noise_index = 0;
2918 for (i = 0; i < PHY_NOISE_WINDOW_SZ; i++) {
2919 for (k = WL_ANT_IDX_1; k < WL_ANT_RX_MAX; k++)
2920 pi->nphy_noise_win[k][i] = PHY_NOISE_FIXED_VAL_NPHY;
2922 pi->nphy_noise_index = 0;
2926 wlc_phy_papd_decode_epsilon(u32 epsilon, s32 *eps_real, s32 *eps_imag)
2928 *eps_imag = (epsilon >> 13);
2929 if (*eps_imag > 0xfff)
2930 *eps_imag -= 0x2000;
2932 *eps_real = (epsilon & 0x1fff);
2933 if (*eps_real > 0xfff)
2934 *eps_real -= 0x2000;
2937 static const fixed AtanTbl[] = {
2958 void wlc_phy_cordic(fixed theta, cs32 *val)
2960 fixed angle, valtmp;
2965 val[0].i = CORDIC_AG;
2969 signtheta = (theta < 0) ? -1 : 1;
2971 ((theta + FIXED(180) * signtheta) % FIXED(360)) -
2972 FIXED(180) * signtheta;
2974 if (FLOAT(theta) > 90) {
2975 theta -= FIXED(180);
2977 } else if (FLOAT(theta) < -90) {
2978 theta += FIXED(180);
2982 for (iter = 0; iter < CORDIC_NI; iter++) {
2983 if (theta > angle) {
2984 valtmp = val[0].i - (val[0].q >> iter);
2985 val[0].q = (val[0].i >> iter) + val[0].q;
2987 angle += AtanTbl[iter];
2989 valtmp = val[0].i + (val[0].q >> iter);
2990 val[0].q = -(val[0].i >> iter) + val[0].q;
2992 angle -= AtanTbl[iter];
2996 val[0].i = val[0].i * signx;
2997 val[0].q = val[0].q * signx;
3000 void wlc_phy_cal_perical_mphase_reset(phy_info_t *pi)
3002 wlapi_del_timer(pi->sh->physhim, pi->phycal_timer);
3004 pi->cal_type_override = PHY_PERICAL_AUTO;
3005 pi->mphase_cal_phase_id = MPHASE_CAL_STATE_IDLE;
3006 pi->mphase_txcal_cmdidx = 0;
3009 static void wlc_phy_cal_perical_mphase_schedule(phy_info_t *pi, uint delay)
3012 if ((pi->nphy_perical != PHY_PERICAL_MPHASE) &&
3013 (pi->nphy_perical != PHY_PERICAL_MANUAL))
3016 wlapi_del_timer(pi->sh->physhim, pi->phycal_timer);
3018 pi->mphase_cal_phase_id = MPHASE_CAL_STATE_INIT;
3019 wlapi_add_timer(pi->sh->physhim, pi->phycal_timer, delay, 0);
3022 void wlc_phy_cal_perical(wlc_phy_t *pih, u8 reason)
3024 s16 nphy_currtemp = 0;
3026 bool do_periodic_cal = true;
3027 phy_info_t *pi = (phy_info_t *) pih;
3032 if ((pi->nphy_perical == PHY_PERICAL_DISABLE) ||
3033 (pi->nphy_perical == PHY_PERICAL_MANUAL))
3037 case PHY_PERICAL_DRIVERUP:
3040 case PHY_PERICAL_PHYINIT:
3041 if (pi->nphy_perical == PHY_PERICAL_MPHASE) {
3042 if (PHY_PERICAL_MPHASE_PENDING(pi)) {
3043 wlc_phy_cal_perical_mphase_reset(pi);
3045 wlc_phy_cal_perical_mphase_schedule(pi,
3046 PHY_PERICAL_INIT_DELAY);
3050 case PHY_PERICAL_JOIN_BSS:
3051 case PHY_PERICAL_START_IBSS:
3052 case PHY_PERICAL_UP_BSS:
3053 if ((pi->nphy_perical == PHY_PERICAL_MPHASE) &&
3054 PHY_PERICAL_MPHASE_PENDING(pi)) {
3055 wlc_phy_cal_perical_mphase_reset(pi);
3058 pi->first_cal_after_assoc = true;
3060 pi->cal_type_override = PHY_PERICAL_FULL;
3062 if (pi->phycal_tempdelta) {
3063 pi->nphy_lastcal_temp = wlc_phy_tempsense_nphy(pi);
3065 wlc_phy_cal_perical_nphy_run(pi, PHY_PERICAL_FULL);
3068 case PHY_PERICAL_WATCHDOG:
3069 if (pi->phycal_tempdelta) {
3070 nphy_currtemp = wlc_phy_tempsense_nphy(pi);
3072 (nphy_currtemp > pi->nphy_lastcal_temp) ?
3073 nphy_currtemp - pi->nphy_lastcal_temp :
3074 pi->nphy_lastcal_temp - nphy_currtemp;
3076 if ((delta_temp < (s16) pi->phycal_tempdelta) &&
3077 (pi->nphy_txiqlocal_chanspec ==
3078 pi->radio_chanspec)) {
3079 do_periodic_cal = false;
3081 pi->nphy_lastcal_temp = nphy_currtemp;
3085 if (do_periodic_cal) {
3087 if (pi->nphy_perical == PHY_PERICAL_MPHASE) {
3089 if (!PHY_PERICAL_MPHASE_PENDING(pi))
3090 wlc_phy_cal_perical_mphase_schedule(pi,
3091 PHY_PERICAL_WDOG_DELAY);
3092 } else if (pi->nphy_perical == PHY_PERICAL_SPHASE)
3093 wlc_phy_cal_perical_nphy_run(pi,
3102 void wlc_phy_cal_perical_mphase_restart(phy_info_t *pi)
3104 pi->mphase_cal_phase_id = MPHASE_CAL_STATE_INIT;
3105 pi->mphase_txcal_cmdidx = 0;
3108 u8 wlc_phy_nbits(s32 value)
3113 abs_val = ABS(value);
3114 while ((abs_val >> nbits) > 0)
3120 void wlc_phy_stf_chain_init(wlc_phy_t *pih, u8 txchain, u8 rxchain)
3122 phy_info_t *pi = (phy_info_t *) pih;
3124 pi->sh->hw_phytxchain = txchain;
3125 pi->sh->hw_phyrxchain = rxchain;
3126 pi->sh->phytxchain = txchain;
3127 pi->sh->phyrxchain = rxchain;
3128 pi->pubpi.phy_corenum = (u8) PHY_BITSCNT(pi->sh->phyrxchain);
3131 void wlc_phy_stf_chain_set(wlc_phy_t *pih, u8 txchain, u8 rxchain)
3133 phy_info_t *pi = (phy_info_t *) pih;
3135 pi->sh->phytxchain = txchain;
3138 wlc_phy_rxcore_setstate_nphy(pih, rxchain);
3140 pi->pubpi.phy_corenum = (u8) PHY_BITSCNT(pi->sh->phyrxchain);
3143 void wlc_phy_stf_chain_get(wlc_phy_t *pih, u8 *txchain, u8 *rxchain)
3145 phy_info_t *pi = (phy_info_t *) pih;
3147 *txchain = pi->sh->phytxchain;
3148 *rxchain = pi->sh->phyrxchain;
3151 u8 wlc_phy_stf_chain_active_get(wlc_phy_t *pih)
3155 phy_info_t *pi = (phy_info_t *) pih;
3157 active_bitmap = (pi->phy_txcore_heatedup) ? 0x31 : 0x33;
3159 if (!pi->watchdog_override)
3160 return active_bitmap;
3162 if (NREV_GE(pi->pubpi.phy_rev, 6)) {
3163 wlapi_suspend_mac_and_wait(pi->sh->physhim);
3164 nphy_currtemp = wlc_phy_tempsense_nphy(pi);
3165 wlapi_enable_mac(pi->sh->physhim);
3167 if (!pi->phy_txcore_heatedup) {
3168 if (nphy_currtemp >= pi->phy_txcore_disable_temp) {
3169 active_bitmap &= 0xFD;
3170 pi->phy_txcore_heatedup = true;
3173 if (nphy_currtemp <= pi->phy_txcore_enable_temp) {
3174 active_bitmap |= 0x2;
3175 pi->phy_txcore_heatedup = false;
3180 return active_bitmap;
3183 s8 wlc_phy_stf_ssmode_get(wlc_phy_t *pih, chanspec_t chanspec)
3185 phy_info_t *pi = (phy_info_t *) pih;
3186 u8 siso_mcs_id, cdd_mcs_id;
3189 (CHSPEC_IS40(chanspec)) ? TXP_FIRST_MCS_40_SISO :
3190 TXP_FIRST_MCS_20_SISO;
3192 (CHSPEC_IS40(chanspec)) ? TXP_FIRST_MCS_40_CDD :
3193 TXP_FIRST_MCS_20_CDD;
3195 if (pi->tx_power_target[siso_mcs_id] >
3196 (pi->tx_power_target[cdd_mcs_id] + 12))
3197 return PHY_TXC1_MODE_SISO;
3199 return PHY_TXC1_MODE_CDD;
3202 const u8 *wlc_phy_get_ofdm_rate_lookup(void)
3204 return ofdm_rate_lookup;
3207 void wlc_lcnphy_epa_switch(phy_info_t *pi, bool mode)
3209 if ((pi->sh->chip == BCM4313_CHIP_ID) &&
3210 (pi->sh->boardflags & BFL_FEM)) {
3213 txant = wlapi_bmac_get_txant(pi->sh->physhim);
3215 mod_phy_reg(pi, 0x44d, (0x1 << 2), (1) << 2);
3217 mod_phy_reg(pi, 0x44c, (0x1 << 2), (1) << 2);
3220 ai_corereg(pi->sh->sih, SI_CC_IDX,
3221 offsetof(chipcregs_t, gpiocontrol), ~0x0,
3223 ai_corereg(pi->sh->sih, SI_CC_IDX,
3224 offsetof(chipcregs_t, gpioout), 0x40, 0x40);
3225 ai_corereg(pi->sh->sih, SI_CC_IDX,
3226 offsetof(chipcregs_t, gpioouten), 0x40,
3229 mod_phy_reg(pi, 0x44c, (0x1 << 2), (0) << 2);
3231 mod_phy_reg(pi, 0x44d, (0x1 << 2), (0) << 2);
3233 ai_corereg(pi->sh->sih, SI_CC_IDX,
3234 offsetof(chipcregs_t, gpioout), 0x40, 0x00);
3235 ai_corereg(pi->sh->sih, SI_CC_IDX,
3236 offsetof(chipcregs_t, gpioouten), 0x40, 0x0);
3237 ai_corereg(pi->sh->sih, SI_CC_IDX,
3238 offsetof(chipcregs_t, gpiocontrol), ~0x0,
3245 wlc_user_txpwr_antport_to_rfport(phy_info_t *pi, uint chan, u32 band,
3250 if (!pi->user_txpwr_at_rfport)
3255 static s8 wlc_phy_env_measure_vbat(phy_info_t *pi)
3258 return wlc_lcnphy_vbatsense(pi, 0);
3263 static s8 wlc_phy_env_measure_temperature(phy_info_t *pi)
3266 return wlc_lcnphy_tempsense_degree(pi, 0);
3271 static void wlc_phy_upd_env_txpwr_rate_limits(phy_info_t *pi, u32 band)
3276 for (i = 0; i < TXP_NUM_RATES; i++)
3277 pi->txpwr_env_limit[i] = WLC_TXPWR_MAX;
3279 vbat = wlc_phy_env_measure_vbat(pi);
3280 temp = wlc_phy_env_measure_temperature(pi);
3284 void wlc_phy_ldpc_override_set(wlc_phy_t *ppi, bool ldpc)
3290 wlc_phy_get_pwrdet_offsets(phy_info_t *pi, s8 *cckoffset, s8 *ofdmoffset)
3296 s8 wlc_phy_upd_rssi_offset(phy_info_t *pi, s8 rssi, chanspec_t chanspec)
3302 bool wlc_phy_txpower_ipa_ison(wlc_phy_t *ppi)
3304 phy_info_t *pi = (phy_info_t *) ppi;
3307 return wlc_phy_n_txpower_ipa_ison(pi);