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>
21 #include <linux/bitops.h>
22 #include <linux/delay.h>
23 #include <linux/module.h>
24 #include <linux/pci.h>
32 #include <wlc_types.h>
33 #include <wlc_phy_int.h>
34 #include <wlc_phyreg_n.h>
35 #include <wlc_phy_radio.h>
36 #include <wlc_phy_lcn.h>
38 u32 phyhal_msg_level = PHYHAL_ERROR;
40 typedef struct _chan_info_basic {
45 static chan_info_basic_t chan_info_all[] = {
105 u16 ltrn_list[PHY_LTRN_LIST_LEN] = {
106 0x18f9, 0x0d01, 0x00e4, 0xdef4, 0x06f1, 0x0ffc,
107 0xfa27, 0x1dff, 0x10f0, 0x0918, 0xf20a, 0xe010,
108 0x1417, 0x1104, 0xf114, 0xf2fa, 0xf7db, 0xe2fc,
109 0xe1fb, 0x13ee, 0xff0d, 0xe91c, 0x171a, 0x0318,
110 0xda00, 0x03e8, 0x17e6, 0xe9e4, 0xfff3, 0x1312,
111 0xe105, 0xe204, 0xf725, 0xf206, 0xf1ec, 0x11fc,
112 0x14e9, 0xe0f0, 0xf2f6, 0x09e8, 0x1010, 0x1d01,
113 0xfad9, 0x0f04, 0x060f, 0xde0c, 0x001c, 0x0dff,
114 0x1807, 0xf61a, 0xe40e, 0x0f16, 0x05f9, 0x18ec,
115 0x0a1b, 0xff1e, 0x2600, 0xffe2, 0x0ae5, 0x1814,
116 0x0507, 0x0fea, 0xe4f2, 0xf6e6
119 const u8 ofdm_rate_lookup[] = {
131 #define PHY_WREG_LIMIT 24
133 static void wlc_set_phy_uninitted(phy_info_t *pi);
134 static u32 wlc_phy_get_radio_ver(phy_info_t *pi);
135 static void wlc_phy_timercb_phycal(void *arg);
137 static bool wlc_phy_noise_calc_phy(phy_info_t *pi, u32 *cmplx_pwr,
140 static void wlc_phy_cal_perical_mphase_schedule(phy_info_t *pi, uint delay);
141 static void wlc_phy_noise_cb(phy_info_t *pi, u8 channel, s8 noise_dbm);
142 static void wlc_phy_noise_sample_request(wlc_phy_t *pih, u8 reason,
145 static void wlc_phy_txpower_reg_limit_calc(phy_info_t *pi,
146 struct txpwr_limits *tp, chanspec_t);
147 static bool wlc_phy_cal_txpower_recalc_sw(phy_info_t *pi);
149 static s8 wlc_user_txpwr_antport_to_rfport(phy_info_t *pi, uint chan,
151 static void wlc_phy_upd_env_txpwr_rate_limits(phy_info_t *pi, u32 band);
152 static s8 wlc_phy_env_measure_vbat(phy_info_t *pi);
153 static s8 wlc_phy_env_measure_temperature(phy_info_t *pi);
155 char *phy_getvar(phy_info_t *pi, const char *name)
157 char *vars = pi->vars;
168 for (s = vars; s && *s;) {
169 if ((memcmp(s, name, len) == 0) && (s[len] == '='))
176 return nvram_get(name);
179 int phy_getintvar(phy_info_t *pi, const char *name)
183 val = PHY_GETVAR(pi, name);
187 return simple_strtoul(val, NULL, 0);
190 void wlc_phyreg_enter(wlc_phy_t *pih)
192 phy_info_t *pi = (phy_info_t *) pih;
193 wlapi_bmac_ucode_wake_override_phyreg_set(pi->sh->physhim);
196 void wlc_phyreg_exit(wlc_phy_t *pih)
198 phy_info_t *pi = (phy_info_t *) pih;
199 wlapi_bmac_ucode_wake_override_phyreg_clear(pi->sh->physhim);
202 void wlc_radioreg_enter(wlc_phy_t *pih)
204 phy_info_t *pi = (phy_info_t *) pih;
205 wlapi_bmac_mctrl(pi->sh->physhim, MCTL_LOCK_RADIO, MCTL_LOCK_RADIO);
210 void wlc_radioreg_exit(wlc_phy_t *pih)
212 phy_info_t *pi = (phy_info_t *) pih;
215 dummy = R_REG(&pi->regs->phyversion);
217 wlapi_bmac_mctrl(pi->sh->physhim, MCTL_LOCK_RADIO, 0);
220 u16 read_radio_reg(phy_info_t *pi, u16 addr)
224 if ((addr == RADIO_IDCODE))
227 if (NORADIO_ENAB(pi->pubpi))
228 return NORADIO_IDCODE & 0xffff;
230 switch (pi->pubpi.phy_type) {
232 CASECHECK(PHYTYPE, PHY_TYPE_N);
233 if (NREV_GE(pi->pubpi.phy_rev, 7))
234 addr |= RADIO_2057_READ_OFF;
236 addr |= RADIO_2055_READ_OFF;
240 CASECHECK(PHYTYPE, PHY_TYPE_LCN);
241 addr |= RADIO_2064_READ_OFF;
248 if ((D11REV_GE(pi->sh->corerev, 24)) ||
249 (D11REV_IS(pi->sh->corerev, 22)
250 && (pi->pubpi.phy_type != PHY_TYPE_SSN))) {
251 W_REG_FLUSH(&pi->regs->radioregaddr, addr);
252 data = R_REG(&pi->regs->radioregdata);
254 W_REG_FLUSH(&pi->regs->phy4waddr, addr);
256 #ifdef __ARM_ARCH_4T__
257 __asm__(" .align 4 ");
259 data = R_REG(&pi->regs->phy4wdatalo);
261 data = R_REG(&pi->regs->phy4wdatalo);
270 void write_radio_reg(phy_info_t *pi, u16 addr, u16 val)
272 if (NORADIO_ENAB(pi->pubpi))
275 if ((D11REV_GE(pi->sh->corerev, 24)) ||
276 (D11REV_IS(pi->sh->corerev, 22)
277 && (pi->pubpi.phy_type != PHY_TYPE_SSN))) {
279 W_REG_FLUSH(&pi->regs->radioregaddr, addr);
280 W_REG(&pi->regs->radioregdata, val);
282 W_REG_FLUSH(&pi->regs->phy4waddr, addr);
283 W_REG(&pi->regs->phy4wdatalo, val);
286 if (pi->sh->bustype == PCI_BUS) {
287 if (++pi->phy_wreg >= pi->phy_wreg_limit) {
288 (void)R_REG(&pi->regs->maccontrol);
294 static u32 read_radio_id(phy_info_t *pi)
298 if (NORADIO_ENAB(pi->pubpi))
299 return NORADIO_IDCODE;
301 if (D11REV_GE(pi->sh->corerev, 24)) {
304 W_REG_FLUSH(&pi->regs->radioregaddr, 0);
305 b0 = (u32) R_REG(&pi->regs->radioregdata);
306 W_REG_FLUSH(&pi->regs->radioregaddr, 1);
307 b1 = (u32) R_REG(&pi->regs->radioregdata);
308 W_REG_FLUSH(&pi->regs->radioregaddr, 2);
309 b2 = (u32) R_REG(&pi->regs->radioregdata);
311 id = ((b0 & 0xf) << 28) | (((b2 << 8) | b1) << 12) | ((b0 >> 4)
314 W_REG_FLUSH(&pi->regs->phy4waddr, RADIO_IDCODE);
315 id = (u32) R_REG(&pi->regs->phy4wdatalo);
316 id |= (u32) R_REG(&pi->regs->phy4wdatahi) << 16;
322 void and_radio_reg(phy_info_t *pi, u16 addr, u16 val)
326 if (NORADIO_ENAB(pi->pubpi))
329 rval = read_radio_reg(pi, addr);
330 write_radio_reg(pi, addr, (rval & val));
333 void or_radio_reg(phy_info_t *pi, u16 addr, u16 val)
337 if (NORADIO_ENAB(pi->pubpi))
340 rval = read_radio_reg(pi, addr);
341 write_radio_reg(pi, addr, (rval | val));
344 void xor_radio_reg(phy_info_t *pi, u16 addr, u16 mask)
348 if (NORADIO_ENAB(pi->pubpi))
351 rval = read_radio_reg(pi, addr);
352 write_radio_reg(pi, addr, (rval ^ mask));
355 void mod_radio_reg(phy_info_t *pi, u16 addr, u16 mask, u16 val)
359 if (NORADIO_ENAB(pi->pubpi))
362 rval = read_radio_reg(pi, addr);
363 write_radio_reg(pi, addr, (rval & ~mask) | (val & mask));
366 void write_phy_channel_reg(phy_info_t *pi, uint val)
368 W_REG(&pi->regs->phychannel, val);
371 u16 read_phy_reg(phy_info_t *pi, u16 addr)
377 W_REG_FLUSH(®s->phyregaddr, addr);
380 return R_REG(®s->phyregdata);
383 void write_phy_reg(phy_info_t *pi, u16 addr, u16 val)
390 W_REG_FLUSH(®s->phyregaddr, addr);
391 W_REG(®s->phyregdata, val);
393 (void)R_REG(®s->phyregdata);
395 W_REG((u32 *)(®s->phyregaddr),
397 if (pi->sh->bustype == PCI_BUS) {
398 if (++pi->phy_wreg >= pi->phy_wreg_limit) {
400 (void)R_REG(®s->phyversion);
406 void and_phy_reg(phy_info_t *pi, u16 addr, u16 val)
412 W_REG_FLUSH(®s->phyregaddr, addr);
414 W_REG(®s->phyregdata, (R_REG(®s->phyregdata) & val));
418 void or_phy_reg(phy_info_t *pi, u16 addr, u16 val)
424 W_REG_FLUSH(®s->phyregaddr, addr);
426 W_REG(®s->phyregdata, (R_REG(®s->phyregdata) | val));
430 void mod_phy_reg(phy_info_t *pi, u16 addr, u16 mask, u16 val)
436 W_REG_FLUSH(®s->phyregaddr, addr);
438 W_REG(®s->phyregdata,
439 ((R_REG(®s->phyregdata) & ~mask) | (val & mask)));
443 static void WLBANDINITFN(wlc_set_phy_uninitted) (phy_info_t *pi)
447 pi->initialized = false;
450 pi->nrssi_table_delta = 0x7fffffff;
452 pi->mintxbias = 0xffff;
455 pi->phy_spuravoid = SPURAVOID_DISABLE;
457 if (NREV_GE(pi->pubpi.phy_rev, 3)
458 && NREV_LT(pi->pubpi.phy_rev, 7))
459 pi->phy_spuravoid = SPURAVOID_AUTO;
461 pi->nphy_papd_skip = 0;
462 pi->nphy_papd_epsilon_offset[0] = 0xf588;
463 pi->nphy_papd_epsilon_offset[1] = 0xf588;
464 pi->nphy_txpwr_idx[0] = 128;
465 pi->nphy_txpwr_idx[1] = 128;
466 pi->nphy_txpwrindex[0].index_internal = 40;
467 pi->nphy_txpwrindex[1].index_internal = 40;
470 pi->phy_spuravoid = SPURAVOID_AUTO;
472 pi->radiopwr = 0xffff;
473 for (i = 0; i < STATIC_NUM_RF; i++) {
474 for (j = 0; j < STATIC_NUM_BB; j++) {
475 pi->stats_11b_txpower[i][j] = -1;
480 shared_phy_t *wlc_phy_shared_attach(shared_phy_params_t *shp)
484 sh = kzalloc(sizeof(shared_phy_t), GFP_ATOMIC);
490 sh->physhim = shp->physhim;
491 sh->unit = shp->unit;
492 sh->corerev = shp->corerev;
496 sh->chip = shp->chip;
497 sh->chiprev = shp->chiprev;
498 sh->chippkg = shp->chippkg;
499 sh->sromrev = shp->sromrev;
500 sh->boardtype = shp->boardtype;
501 sh->boardrev = shp->boardrev;
502 sh->boardvendor = shp->boardvendor;
503 sh->boardflags = shp->boardflags;
504 sh->boardflags2 = shp->boardflags2;
505 sh->bustype = shp->bustype;
506 sh->buscorerev = shp->buscorerev;
508 sh->fast_timer = PHY_SW_TIMER_FAST;
509 sh->slow_timer = PHY_SW_TIMER_SLOW;
510 sh->glacial_timer = PHY_SW_TIMER_GLACIAL;
512 sh->rssi_mode = RSSI_ANT_MERGE_MAX;
517 void wlc_phy_shared_detach(shared_phy_t *phy_sh)
524 wlc_phy_t *wlc_phy_attach(shared_phy_t *sh, void *regs, int bandtype,
525 char *vars, struct wiphy *wiphy)
532 if (D11REV_IS(sh->corerev, 4))
533 sflags = SISF_2G_PHY | SISF_5G_PHY;
535 sflags = ai_core_sflags(sh->sih, 0, 0);
537 if (BAND_5G(bandtype)) {
538 if ((sflags & (SISF_5G_PHY | SISF_DB_PHY)) == 0) {
544 if ((sflags & SISF_DB_PHY) && pi) {
546 wlapi_bmac_corereset(pi->sh->physhim, pi->pubpi.coreflags);
548 return &pi->pubpi_ro;
551 pi = kzalloc(sizeof(phy_info_t), GFP_ATOMIC);
556 pi->regs = (d11regs_t *) regs;
558 pi->phy_init_por = true;
559 pi->phy_wreg_limit = PHY_WREG_LIMIT;
563 pi->txpwr_percent = 100;
565 pi->do_initcal = true;
567 pi->phycal_tempdelta = 0;
569 if (BAND_2G(bandtype) && (sflags & SISF_2G_PHY)) {
571 pi->pubpi.coreflags = SICF_GMODE;
574 wlapi_bmac_corereset(pi->sh->physhim, pi->pubpi.coreflags);
575 phyversion = R_REG(&pi->regs->phyversion);
577 pi->pubpi.phy_type = PHY_TYPE(phyversion);
578 pi->pubpi.phy_rev = phyversion & PV_PV_MASK;
580 if (pi->pubpi.phy_type == PHY_TYPE_LCNXN) {
581 pi->pubpi.phy_type = PHY_TYPE_N;
582 pi->pubpi.phy_rev += LCNXN_BASEREV;
584 pi->pubpi.phy_corenum = PHY_CORE_NUM_2;
585 pi->pubpi.ana_rev = (phyversion & PV_AV_MASK) >> PV_AV_SHIFT;
587 if (!VALID_PHYTYPE(pi->pubpi.phy_type)) {
590 if (BAND_5G(bandtype)) {
595 if (!ISNPHY(pi) && !ISLCNPHY(pi)) {
600 if (ISSIM_ENAB(pi->sh->sih)) {
601 pi->pubpi.radioid = NORADIO_ID;
602 pi->pubpi.radiorev = 5;
606 wlc_phy_anacore((wlc_phy_t *) pi, ON);
608 idcode = wlc_phy_get_radio_ver(pi);
610 (idcode & IDCODE_ID_MASK) >> IDCODE_ID_SHIFT;
612 (idcode & IDCODE_REV_MASK) >> IDCODE_REV_SHIFT;
614 (idcode & IDCODE_VER_MASK) >> IDCODE_VER_SHIFT;
615 if (!VALID_RADIO(pi, pi->pubpi.radioid)) {
619 wlc_phy_switch_radio((wlc_phy_t *) pi, OFF);
622 wlc_set_phy_uninitted(pi);
624 pi->bw = WL_CHANSPEC_BW_20;
626 BAND_2G(bandtype) ? CH20MHZ_CHSPEC(1) : CH20MHZ_CHSPEC(36);
628 pi->rxiq_samps = PHY_NOISE_SAMPLE_LOG_NUM_NPHY;
629 pi->rxiq_antsel = ANT_RX_DIV_DEF;
631 pi->watchdog_override = true;
633 pi->cal_type_override = PHY_PERICAL_AUTO;
635 pi->nphy_saved_noisevars.bufcount = 0;
638 pi->min_txpower = PHY_TXPWR_MIN_NPHY;
640 pi->min_txpower = PHY_TXPWR_MIN;
642 pi->sh->phyrxchain = 0x3;
644 pi->rx2tx_biasentry = -1;
646 pi->phy_txcore_disable_temp = PHY_CHAIN_TX_DISABLE_TEMP;
647 pi->phy_txcore_enable_temp =
648 PHY_CHAIN_TX_DISABLE_TEMP - PHY_HYSTERESIS_DELTATEMP;
649 pi->phy_tempsense_offset = 0;
650 pi->phy_txcore_heatedup = false;
652 pi->nphy_lastcal_temp = -50;
654 pi->phynoise_polling = true;
655 if (ISNPHY(pi) || ISLCNPHY(pi))
656 pi->phynoise_polling = false;
658 for (i = 0; i < TXP_NUM_RATES; i++) {
659 pi->txpwr_limit[i] = WLC_TXPWR_MAX;
660 pi->txpwr_env_limit[i] = WLC_TXPWR_MAX;
661 pi->tx_user_target[i] = WLC_TXPWR_MAX;
664 pi->radiopwr_override = RADIOPWR_OVERRIDE_DEF;
666 pi->user_txpwr_at_rfport = false;
670 pi->phycal_timer = wlapi_init_timer(pi->sh->physhim,
671 wlc_phy_timercb_phycal,
673 if (!pi->phycal_timer) {
677 if (!wlc_phy_attach_nphy(pi))
680 } else if (ISLCNPHY(pi)) {
681 if (!wlc_phy_attach_lcnphy(pi))
689 pi->next = pi->sh->phy_head;
692 pi->vars = (char *)&pi->vars;
694 memcpy(&pi->pubpi_ro, &pi->pubpi, sizeof(wlc_phy_t));
696 return &pi->pubpi_ro;
703 void wlc_phy_detach(wlc_phy_t *pih)
705 phy_info_t *pi = (phy_info_t *) pih;
712 if (pi->phycal_timer) {
713 wlapi_free_timer(pi->sh->physhim, pi->phycal_timer);
714 pi->phycal_timer = NULL;
717 if (pi->sh->phy_head == pi)
718 pi->sh->phy_head = pi->next;
719 else if (pi->sh->phy_head->next == pi)
720 pi->sh->phy_head->next = NULL;
722 if (pi->pi_fptr.detach)
723 (pi->pi_fptr.detach) (pi);
730 wlc_phy_get_phyversion(wlc_phy_t *pih, u16 *phytype, u16 *phyrev,
731 u16 *radioid, u16 *radiover)
733 phy_info_t *pi = (phy_info_t *) pih;
734 *phytype = (u16) pi->pubpi.phy_type;
735 *phyrev = (u16) pi->pubpi.phy_rev;
736 *radioid = pi->pubpi.radioid;
737 *radiover = pi->pubpi.radiorev;
742 bool wlc_phy_get_encore(wlc_phy_t *pih)
744 phy_info_t *pi = (phy_info_t *) pih;
745 return pi->pubpi.abgphy_encore;
748 u32 wlc_phy_get_coreflags(wlc_phy_t *pih)
750 phy_info_t *pi = (phy_info_t *) pih;
751 return pi->pubpi.coreflags;
754 static void wlc_phy_timercb_phycal(void *arg)
756 phy_info_t *pi = (phy_info_t *) arg;
759 if (PHY_PERICAL_MPHASE_PENDING(pi)) {
761 wlc_phy_cal_perical_mphase_reset(pi);
765 if (SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi)) {
768 wlc_phy_cal_perical_mphase_restart(pi);
770 wlc_phy_cal_perical_nphy_run(pi, PHY_PERICAL_AUTO);
771 wlapi_add_timer(pi->sh->physhim, pi->phycal_timer, delay, 0);
777 void wlc_phy_anacore(wlc_phy_t *pih, bool on)
779 phy_info_t *pi = (phy_info_t *) pih;
783 if (NREV_GE(pi->pubpi.phy_rev, 3)) {
784 write_phy_reg(pi, 0xa6, 0x0d);
785 write_phy_reg(pi, 0x8f, 0x0);
786 write_phy_reg(pi, 0xa7, 0x0d);
787 write_phy_reg(pi, 0xa5, 0x0);
789 write_phy_reg(pi, 0xa5, 0x0);
792 if (NREV_GE(pi->pubpi.phy_rev, 3)) {
793 write_phy_reg(pi, 0x8f, 0x07ff);
794 write_phy_reg(pi, 0xa6, 0x0fd);
795 write_phy_reg(pi, 0xa5, 0x07ff);
796 write_phy_reg(pi, 0xa7, 0x0fd);
798 write_phy_reg(pi, 0xa5, 0x7fff);
801 } else if (ISLCNPHY(pi)) {
803 and_phy_reg(pi, 0x43b,
804 ~((0x1 << 0) | (0x1 << 1) | (0x1 << 2)));
806 or_phy_reg(pi, 0x43c,
807 (0x1 << 0) | (0x1 << 1) | (0x1 << 2));
808 or_phy_reg(pi, 0x43b,
809 (0x1 << 0) | (0x1 << 1) | (0x1 << 2));
814 u32 wlc_phy_clk_bwbits(wlc_phy_t *pih)
816 phy_info_t *pi = (phy_info_t *) pih;
818 u32 phy_bw_clkbits = 0;
820 if (pi && (ISNPHY(pi) || ISLCNPHY(pi))) {
822 case WL_CHANSPEC_BW_10:
823 phy_bw_clkbits = SICF_BW10;
825 case WL_CHANSPEC_BW_20:
826 phy_bw_clkbits = SICF_BW20;
828 case WL_CHANSPEC_BW_40:
829 phy_bw_clkbits = SICF_BW40;
836 return phy_bw_clkbits;
839 void WLBANDINITFN(wlc_phy_por_inform) (wlc_phy_t *ppi)
841 phy_info_t *pi = (phy_info_t *) ppi;
843 pi->phy_init_por = true;
846 void wlc_phy_edcrs_lock(wlc_phy_t *pih, bool lock)
848 phy_info_t *pi = (phy_info_t *) pih;
850 pi->edcrs_threshold_lock = lock;
852 write_phy_reg(pi, 0x22c, 0x46b);
853 write_phy_reg(pi, 0x22d, 0x46b);
854 write_phy_reg(pi, 0x22e, 0x3c0);
855 write_phy_reg(pi, 0x22f, 0x3c0);
858 void wlc_phy_initcal_enable(wlc_phy_t *pih, bool initcal)
860 phy_info_t *pi = (phy_info_t *) pih;
862 pi->do_initcal = initcal;
865 void wlc_phy_hw_clk_state_upd(wlc_phy_t *pih, bool newstate)
867 phy_info_t *pi = (phy_info_t *) pih;
872 pi->sh->clk = newstate;
875 void wlc_phy_hw_state_upd(wlc_phy_t *pih, bool newstate)
877 phy_info_t *pi = (phy_info_t *) pih;
882 pi->sh->up = newstate;
885 void WLBANDINITFN(wlc_phy_init) (wlc_phy_t *pih, chanspec_t chanspec)
888 initfn_t phy_init = NULL;
889 phy_info_t *pi = (phy_info_t *) pih;
891 if (pi->init_in_progress)
894 pi->init_in_progress = true;
896 pi->radio_chanspec = chanspec;
898 mc = R_REG(&pi->regs->maccontrol);
899 if (WARN(mc & MCTL_EN_MAC, "HW error MAC running on init"))
902 if (!(pi->measure_hold & PHY_HOLD_FOR_SCAN)) {
903 pi->measure_hold |= PHY_HOLD_FOR_NOT_ASSOC;
906 if (WARN(!(ai_core_sflags(pi->sh->sih, 0, 0) & SISF_FCLKA),
907 "HW error SISF_FCLKA\n"))
910 phy_init = pi->pi_fptr.init;
912 if (phy_init == NULL) {
916 wlc_phy_anacore(pih, ON);
918 if (CHSPEC_BW(pi->radio_chanspec) != pi->bw)
919 wlapi_bmac_bw_set(pi->sh->physhim,
920 CHSPEC_BW(pi->radio_chanspec));
922 pi->nphy_gain_boost = true;
924 wlc_phy_switch_radio((wlc_phy_t *) pi, ON);
928 pi->phy_init_por = false;
930 if (D11REV_IS(pi->sh->corerev, 11) || D11REV_IS(pi->sh->corerev, 12))
931 wlc_phy_do_dummy_tx(pi, true, OFF);
934 wlc_phy_txpower_update_shm(pi);
936 wlc_phy_ant_rxdiv_set((wlc_phy_t *) pi, pi->sh->rx_antdiv);
938 pi->init_in_progress = false;
941 void wlc_phy_cal_init(wlc_phy_t *pih)
943 phy_info_t *pi = (phy_info_t *) pih;
944 initfn_t cal_init = NULL;
946 if (WARN((R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC) != 0,
947 "HW error: MAC enabled during phy cal\n"))
950 if (!pi->initialized) {
951 cal_init = pi->pi_fptr.calinit;
955 pi->initialized = true;
959 int wlc_phy_down(wlc_phy_t *pih)
961 phy_info_t *pi = (phy_info_t *) pih;
965 && !wlapi_del_timer(pi->sh->physhim, pi->phycal_timer))
968 pi->nphy_iqcal_chanspec_2G = 0;
969 pi->nphy_iqcal_chanspec_5G = 0;
974 static u32 wlc_phy_get_radio_ver(phy_info_t *pi)
978 ver = read_radio_id(pi);
984 wlc_phy_table_addr(phy_info_t *pi, uint tbl_id, uint tbl_offset,
985 u16 tblAddr, u16 tblDataHi, u16 tblDataLo)
987 write_phy_reg(pi, tblAddr, (tbl_id << 10) | tbl_offset);
989 pi->tbl_data_hi = tblDataHi;
990 pi->tbl_data_lo = tblDataLo;
992 if ((pi->sh->chip == BCM43224_CHIP_ID ||
993 pi->sh->chip == BCM43421_CHIP_ID) &&
994 (pi->sh->chiprev == 1)) {
995 pi->tbl_addr = tblAddr;
996 pi->tbl_save_id = tbl_id;
997 pi->tbl_save_offset = tbl_offset;
1001 void wlc_phy_table_data_write(phy_info_t *pi, uint width, u32 val)
1003 if ((pi->sh->chip == BCM43224_CHIP_ID ||
1004 pi->sh->chip == BCM43421_CHIP_ID) &&
1005 (pi->sh->chiprev == 1) &&
1006 (pi->tbl_save_id == NPHY_TBL_ID_ANTSWCTRLLUT)) {
1007 read_phy_reg(pi, pi->tbl_data_lo);
1009 write_phy_reg(pi, pi->tbl_addr,
1010 (pi->tbl_save_id << 10) | pi->tbl_save_offset);
1011 pi->tbl_save_offset++;
1016 write_phy_reg(pi, pi->tbl_data_hi, (u16) (val >> 16));
1017 write_phy_reg(pi, pi->tbl_data_lo, (u16) val);
1020 write_phy_reg(pi, pi->tbl_data_lo, (u16) val);
1025 wlc_phy_write_table(phy_info_t *pi, const phytbl_info_t *ptbl_info,
1026 u16 tblAddr, u16 tblDataHi, u16 tblDataLo)
1029 uint tbl_id = ptbl_info->tbl_id;
1030 uint tbl_offset = ptbl_info->tbl_offset;
1031 uint tbl_width = ptbl_info->tbl_width;
1032 const u8 *ptbl_8b = (const u8 *)ptbl_info->tbl_ptr;
1033 const u16 *ptbl_16b = (const u16 *)ptbl_info->tbl_ptr;
1034 const u32 *ptbl_32b = (const u32 *)ptbl_info->tbl_ptr;
1036 write_phy_reg(pi, tblAddr, (tbl_id << 10) | tbl_offset);
1038 for (idx = 0; idx < ptbl_info->tbl_len; idx++) {
1040 if ((pi->sh->chip == BCM43224_CHIP_ID ||
1041 pi->sh->chip == BCM43421_CHIP_ID) &&
1042 (pi->sh->chiprev == 1) &&
1043 (tbl_id == NPHY_TBL_ID_ANTSWCTRLLUT)) {
1044 read_phy_reg(pi, tblDataLo);
1046 write_phy_reg(pi, tblAddr,
1047 (tbl_id << 10) | (tbl_offset + idx));
1050 if (tbl_width == 32) {
1052 write_phy_reg(pi, tblDataHi,
1053 (u16) (ptbl_32b[idx] >> 16));
1054 write_phy_reg(pi, tblDataLo, (u16) ptbl_32b[idx]);
1055 } else if (tbl_width == 16) {
1057 write_phy_reg(pi, tblDataLo, ptbl_16b[idx]);
1060 write_phy_reg(pi, tblDataLo, ptbl_8b[idx]);
1066 wlc_phy_read_table(phy_info_t *pi, const phytbl_info_t *ptbl_info,
1067 u16 tblAddr, u16 tblDataHi, u16 tblDataLo)
1070 uint tbl_id = ptbl_info->tbl_id;
1071 uint tbl_offset = ptbl_info->tbl_offset;
1072 uint tbl_width = ptbl_info->tbl_width;
1073 u8 *ptbl_8b = (u8 *)ptbl_info->tbl_ptr;
1074 u16 *ptbl_16b = (u16 *)ptbl_info->tbl_ptr;
1075 u32 *ptbl_32b = (u32 *)ptbl_info->tbl_ptr;
1077 write_phy_reg(pi, tblAddr, (tbl_id << 10) | tbl_offset);
1079 for (idx = 0; idx < ptbl_info->tbl_len; idx++) {
1081 if ((pi->sh->chip == BCM43224_CHIP_ID ||
1082 pi->sh->chip == BCM43421_CHIP_ID) &&
1083 (pi->sh->chiprev == 1)) {
1084 (void)read_phy_reg(pi, tblDataLo);
1086 write_phy_reg(pi, tblAddr,
1087 (tbl_id << 10) | (tbl_offset + idx));
1090 if (tbl_width == 32) {
1092 ptbl_32b[idx] = read_phy_reg(pi, tblDataLo);
1093 ptbl_32b[idx] |= (read_phy_reg(pi, tblDataHi) << 16);
1094 } else if (tbl_width == 16) {
1096 ptbl_16b[idx] = read_phy_reg(pi, tblDataLo);
1099 ptbl_8b[idx] = (u8) read_phy_reg(pi, tblDataLo);
1105 wlc_phy_init_radio_regs_allbands(phy_info_t *pi, radio_20xx_regs_t *radioregs)
1110 if (radioregs[i].do_init) {
1111 write_radio_reg(pi, radioregs[i].address,
1112 (u16) radioregs[i].init);
1116 } while (radioregs[i].address != 0xffff);
1122 wlc_phy_init_radio_regs(phy_info_t *pi, radio_regs_t *radioregs,
1129 if (CHSPEC_IS5G(pi->radio_chanspec)) {
1130 if (radioregs[i].do_init_a) {
1133 address | core_offset,
1134 (u16) radioregs[i].init_a);
1135 if (ISNPHY(pi) && (++count % 4 == 0))
1136 WLC_PHY_WAR_PR51571(pi);
1139 if (radioregs[i].do_init_g) {
1142 address | core_offset,
1143 (u16) radioregs[i].init_g);
1144 if (ISNPHY(pi) && (++count % 4 == 0))
1145 WLC_PHY_WAR_PR51571(pi);
1150 } while (radioregs[i].address != 0xffff);
1155 void wlc_phy_do_dummy_tx(phy_info_t *pi, bool ofdm, bool pa_on)
1157 #define DUMMY_PKT_LEN 20
1158 d11regs_t *regs = pi->regs;
1160 u8 ofdmpkt[DUMMY_PKT_LEN] = {
1161 0xcc, 0x01, 0x02, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00,
1162 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00
1164 u8 cckpkt[DUMMY_PKT_LEN] = {
1165 0x6e, 0x84, 0x0b, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00,
1166 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00
1170 dummypkt = (u32 *) (ofdm ? ofdmpkt : cckpkt);
1171 wlapi_bmac_write_template_ram(pi->sh->physhim, 0, DUMMY_PKT_LEN,
1174 W_REG(®s->xmtsel, 0);
1176 if (D11REV_GE(pi->sh->corerev, 11))
1177 W_REG(®s->wepctl, 0x100);
1179 W_REG(®s->wepctl, 0);
1181 W_REG(®s->txe_phyctl, (ofdm ? 1 : 0) | PHY_TXC_ANT_0);
1182 if (ISNPHY(pi) || ISLCNPHY(pi)) {
1183 W_REG(®s->txe_phyctl1, 0x1A02);
1186 W_REG(®s->txe_wm_0, 0);
1187 W_REG(®s->txe_wm_1, 0);
1189 W_REG(®s->xmttplatetxptr, 0);
1190 W_REG(®s->xmttxcnt, DUMMY_PKT_LEN);
1192 W_REG(®s->xmtsel, ((8 << 8) | (1 << 5) | (1 << 2) | 2));
1194 W_REG(®s->txe_ctl, 0);
1198 wlc_phy_pa_override_nphy(pi, OFF);
1201 if (ISNPHY(pi) || ISLCNPHY(pi))
1202 W_REG(®s->txe_aux, 0xD0);
1204 W_REG(®s->txe_aux, ((1 << 5) | (1 << 4)));
1206 (void)R_REG(®s->txe_aux);
1209 count = ofdm ? 30 : 250;
1211 if (ISSIM_ENAB(pi->sh->sih)) {
1215 while ((i++ < count)
1216 && (R_REG(®s->txe_status) & (1 << 7))) {
1223 && ((R_REG(®s->txe_status) & (1 << 10)) == 0)) {
1229 while ((i++ < 10) && ((R_REG(®s->ifsstat) & (1 << 8))))
1234 wlc_phy_pa_override_nphy(pi, ON);
1238 void wlc_phy_hold_upd(wlc_phy_t *pih, mbool id, bool set)
1240 phy_info_t *pi = (phy_info_t *) pih;
1243 mboolset(pi->measure_hold, id);
1245 mboolclr(pi->measure_hold, id);
1251 void wlc_phy_mute_upd(wlc_phy_t *pih, bool mute, mbool flags)
1253 phy_info_t *pi = (phy_info_t *) pih;
1256 mboolset(pi->measure_hold, PHY_HOLD_FOR_MUTE);
1258 mboolclr(pi->measure_hold, PHY_HOLD_FOR_MUTE);
1261 if (!mute && (flags & PHY_MUTE_FOR_PREISM))
1262 pi->nphy_perical_last = pi->sh->now - pi->sh->glacial_timer;
1266 void wlc_phy_clear_tssi(wlc_phy_t *pih)
1268 phy_info_t *pi = (phy_info_t *) pih;
1273 wlapi_bmac_write_shm(pi->sh->physhim, M_B_TSSI_0, NULL_TSSI_W);
1274 wlapi_bmac_write_shm(pi->sh->physhim, M_B_TSSI_1, NULL_TSSI_W);
1275 wlapi_bmac_write_shm(pi->sh->physhim, M_G_TSSI_0, NULL_TSSI_W);
1276 wlapi_bmac_write_shm(pi->sh->physhim, M_G_TSSI_1, NULL_TSSI_W);
1280 static bool wlc_phy_cal_txpower_recalc_sw(phy_info_t *pi)
1285 void wlc_phy_switch_radio(wlc_phy_t *pih, bool on)
1287 phy_info_t *pi = (phy_info_t *) pih;
1289 if (NORADIO_ENAB(pi->pubpi))
1295 mc = R_REG(&pi->regs->maccontrol);
1299 wlc_phy_switch_radio_nphy(pi, on);
1301 } else if (ISLCNPHY(pi)) {
1303 and_phy_reg(pi, 0x44c,
1306 (0x1 << 10) | (0x1 << 11) | (0x1 << 12)));
1307 and_phy_reg(pi, 0x4b0, ~((0x1 << 3) | (0x1 << 11)));
1308 and_phy_reg(pi, 0x4f9, ~(0x1 << 3));
1310 and_phy_reg(pi, 0x44d,
1313 (0x1 << 12) | (0x1 << 13) | (0x1 << 14)));
1314 or_phy_reg(pi, 0x44c,
1317 (0x1 << 10) | (0x1 << 11) | (0x1 << 12));
1319 and_phy_reg(pi, 0x4b7, ~((0x7f << 8)));
1320 and_phy_reg(pi, 0x4b1, ~((0x1 << 13)));
1321 or_phy_reg(pi, 0x4b0, (0x1 << 3) | (0x1 << 11));
1322 and_phy_reg(pi, 0x4fa, ~((0x1 << 3)));
1323 or_phy_reg(pi, 0x4f9, (0x1 << 3));
1328 u16 wlc_phy_bw_state_get(wlc_phy_t *ppi)
1330 phy_info_t *pi = (phy_info_t *) ppi;
1335 void wlc_phy_bw_state_set(wlc_phy_t *ppi, u16 bw)
1337 phy_info_t *pi = (phy_info_t *) ppi;
1342 void wlc_phy_chanspec_radio_set(wlc_phy_t *ppi, chanspec_t newch)
1344 phy_info_t *pi = (phy_info_t *) ppi;
1345 pi->radio_chanspec = newch;
1349 chanspec_t wlc_phy_chanspec_get(wlc_phy_t *ppi)
1351 phy_info_t *pi = (phy_info_t *) ppi;
1353 return pi->radio_chanspec;
1356 void wlc_phy_chanspec_set(wlc_phy_t *ppi, chanspec_t chanspec)
1358 phy_info_t *pi = (phy_info_t *) ppi;
1360 chansetfn_t chanspec_set = NULL;
1362 m_cur_channel = CHSPEC_CHANNEL(chanspec);
1363 if (CHSPEC_IS5G(chanspec))
1364 m_cur_channel |= D11_CURCHANNEL_5G;
1365 if (CHSPEC_IS40(chanspec))
1366 m_cur_channel |= D11_CURCHANNEL_40;
1367 wlapi_bmac_write_shm(pi->sh->physhim, M_CURCHANNEL, m_cur_channel);
1369 chanspec_set = pi->pi_fptr.chanset;
1371 (*chanspec_set) (pi, chanspec);
1375 int wlc_phy_chanspec_freq2bandrange_lpssn(uint freq)
1380 range = WL_CHAN_FREQ_RANGE_2G;
1381 else if (freq <= 5320)
1382 range = WL_CHAN_FREQ_RANGE_5GL;
1383 else if (freq <= 5700)
1384 range = WL_CHAN_FREQ_RANGE_5GM;
1386 range = WL_CHAN_FREQ_RANGE_5GH;
1391 int wlc_phy_chanspec_bandrange_get(phy_info_t *pi, chanspec_t chanspec)
1394 uint channel = CHSPEC_CHANNEL(chanspec);
1395 uint freq = wlc_phy_channel2freq(channel);
1398 range = wlc_phy_get_chan_freq_range_nphy(pi, channel);
1399 } else if (ISLCNPHY(pi)) {
1400 range = wlc_phy_chanspec_freq2bandrange_lpssn(freq);
1406 void wlc_phy_chanspec_ch14_widefilter_set(wlc_phy_t *ppi, bool wide_filter)
1408 phy_info_t *pi = (phy_info_t *) ppi;
1410 pi->channel_14_wide_filter = wide_filter;
1414 int wlc_phy_channel2freq(uint channel)
1418 for (i = 0; i < ARRAY_SIZE(chan_info_all); i++)
1419 if (chan_info_all[i].chan == channel)
1420 return chan_info_all[i].freq;
1425 wlc_phy_chanspec_band_validch(wlc_phy_t *ppi, uint band, chanvec_t *channels)
1427 phy_info_t *pi = (phy_info_t *) ppi;
1431 memset(channels, 0, sizeof(chanvec_t));
1433 for (i = 0; i < ARRAY_SIZE(chan_info_all); i++) {
1434 channel = chan_info_all[i].chan;
1436 if ((pi->a_band_high_disable) && (channel >= FIRST_REF5_CHANNUM)
1437 && (channel <= LAST_REF5_CHANNUM))
1440 if (((band == WLC_BAND_2G) && (channel <= CH_MAX_2G_CHANNEL)) ||
1441 ((band == WLC_BAND_5G) && (channel > CH_MAX_2G_CHANNEL)))
1442 setbit(channels->vec, channel);
1446 chanspec_t wlc_phy_chanspec_band_firstch(wlc_phy_t *ppi, uint band)
1448 phy_info_t *pi = (phy_info_t *) ppi;
1453 for (i = 0; i < ARRAY_SIZE(chan_info_all); i++) {
1454 channel = chan_info_all[i].chan;
1456 if (ISNPHY(pi) && IS40MHZ(pi)) {
1459 for (j = 0; j < ARRAY_SIZE(chan_info_all); j++) {
1460 if (chan_info_all[j].chan ==
1461 channel + CH_10MHZ_APART)
1465 if (j == ARRAY_SIZE(chan_info_all))
1468 channel = UPPER_20_SB(channel);
1470 channel | WL_CHANSPEC_BW_40 |
1471 WL_CHANSPEC_CTL_SB_LOWER;
1472 if (band == WLC_BAND_2G)
1473 chspec |= WL_CHANSPEC_BAND_2G;
1475 chspec |= WL_CHANSPEC_BAND_5G;
1477 chspec = CH20MHZ_CHSPEC(channel);
1479 if ((pi->a_band_high_disable) && (channel >= FIRST_REF5_CHANNUM)
1480 && (channel <= LAST_REF5_CHANNUM))
1483 if (((band == WLC_BAND_2G) && (channel <= CH_MAX_2G_CHANNEL)) ||
1484 ((band == WLC_BAND_5G) && (channel > CH_MAX_2G_CHANNEL)))
1488 return (chanspec_t) INVCHANSPEC;
1491 int wlc_phy_txpower_get(wlc_phy_t *ppi, uint *qdbm, bool *override)
1493 phy_info_t *pi = (phy_info_t *) ppi;
1495 *qdbm = pi->tx_user_target[0];
1496 if (override != NULL)
1497 *override = pi->txpwroverride;
1501 void wlc_phy_txpower_target_set(wlc_phy_t *ppi, struct txpwr_limits *txpwr)
1503 bool mac_enabled = false;
1504 phy_info_t *pi = (phy_info_t *) ppi;
1506 memcpy(&pi->tx_user_target[TXP_FIRST_CCK],
1507 &txpwr->cck[0], WLC_NUM_RATES_CCK);
1509 memcpy(&pi->tx_user_target[TXP_FIRST_OFDM],
1510 &txpwr->ofdm[0], WLC_NUM_RATES_OFDM);
1511 memcpy(&pi->tx_user_target[TXP_FIRST_OFDM_20_CDD],
1512 &txpwr->ofdm_cdd[0], WLC_NUM_RATES_OFDM);
1514 memcpy(&pi->tx_user_target[TXP_FIRST_OFDM_40_SISO],
1515 &txpwr->ofdm_40_siso[0], WLC_NUM_RATES_OFDM);
1516 memcpy(&pi->tx_user_target[TXP_FIRST_OFDM_40_CDD],
1517 &txpwr->ofdm_40_cdd[0], WLC_NUM_RATES_OFDM);
1519 memcpy(&pi->tx_user_target[TXP_FIRST_MCS_20_SISO],
1520 &txpwr->mcs_20_siso[0], WLC_NUM_RATES_MCS_1_STREAM);
1521 memcpy(&pi->tx_user_target[TXP_FIRST_MCS_20_CDD],
1522 &txpwr->mcs_20_cdd[0], WLC_NUM_RATES_MCS_1_STREAM);
1523 memcpy(&pi->tx_user_target[TXP_FIRST_MCS_20_STBC],
1524 &txpwr->mcs_20_stbc[0], WLC_NUM_RATES_MCS_1_STREAM);
1525 memcpy(&pi->tx_user_target[TXP_FIRST_MCS_20_SDM],
1526 &txpwr->mcs_20_mimo[0], WLC_NUM_RATES_MCS_2_STREAM);
1528 memcpy(&pi->tx_user_target[TXP_FIRST_MCS_40_SISO],
1529 &txpwr->mcs_40_siso[0], WLC_NUM_RATES_MCS_1_STREAM);
1530 memcpy(&pi->tx_user_target[TXP_FIRST_MCS_40_CDD],
1531 &txpwr->mcs_40_cdd[0], WLC_NUM_RATES_MCS_1_STREAM);
1532 memcpy(&pi->tx_user_target[TXP_FIRST_MCS_40_STBC],
1533 &txpwr->mcs_40_stbc[0], WLC_NUM_RATES_MCS_1_STREAM);
1534 memcpy(&pi->tx_user_target[TXP_FIRST_MCS_40_SDM],
1535 &txpwr->mcs_40_mimo[0], WLC_NUM_RATES_MCS_2_STREAM);
1537 if (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC)
1541 wlapi_suspend_mac_and_wait(pi->sh->physhim);
1543 wlc_phy_txpower_recalc_target(pi);
1544 wlc_phy_cal_txpower_recalc_sw(pi);
1547 wlapi_enable_mac(pi->sh->physhim);
1550 int wlc_phy_txpower_set(wlc_phy_t *ppi, uint qdbm, bool override)
1552 phy_info_t *pi = (phy_info_t *) ppi;
1558 for (i = 0; i < TXP_NUM_RATES; i++)
1559 pi->tx_user_target[i] = (u8) qdbm;
1561 pi->txpwroverride = false;
1564 if (!SCAN_INPROG_PHY(pi)) {
1569 (R_REG(&pi->regs->maccontrol) &
1573 wlapi_suspend_mac_and_wait(pi->sh->physhim);
1575 wlc_phy_txpower_recalc_target(pi);
1576 wlc_phy_cal_txpower_recalc_sw(pi);
1579 wlapi_enable_mac(pi->sh->physhim);
1586 wlc_phy_txpower_sromlimit(wlc_phy_t *ppi, uint channel, u8 *min_pwr,
1587 u8 *max_pwr, int txp_rate_idx)
1589 phy_info_t *pi = (phy_info_t *) ppi;
1592 *min_pwr = pi->min_txpower * WLC_TXPWR_DB_FACTOR;
1595 if (txp_rate_idx < 0)
1596 txp_rate_idx = TXP_FIRST_CCK;
1597 wlc_phy_txpower_sromlimit_get_nphy(pi, channel, max_pwr,
1600 } else if ((channel <= CH_MAX_2G_CHANNEL)) {
1601 if (txp_rate_idx < 0)
1602 txp_rate_idx = TXP_FIRST_CCK;
1603 *max_pwr = pi->tx_srom_max_rate_2g[txp_rate_idx];
1606 *max_pwr = WLC_TXPWR_MAX;
1608 if (txp_rate_idx < 0)
1609 txp_rate_idx = TXP_FIRST_OFDM;
1611 for (i = 0; i < ARRAY_SIZE(chan_info_all); i++) {
1612 if (channel == chan_info_all[i].chan) {
1618 *max_pwr = pi->hwtxpwr[i];
1621 if ((i >= FIRST_MID_5G_CHAN) && (i <= LAST_MID_5G_CHAN))
1623 pi->tx_srom_max_rate_5g_mid[txp_rate_idx];
1624 if ((i >= FIRST_HIGH_5G_CHAN)
1625 && (i <= LAST_HIGH_5G_CHAN))
1627 pi->tx_srom_max_rate_5g_hi[txp_rate_idx];
1628 if ((i >= FIRST_LOW_5G_CHAN) && (i <= LAST_LOW_5G_CHAN))
1630 pi->tx_srom_max_rate_5g_low[txp_rate_idx];
1636 wlc_phy_txpower_sromlimit_max_get(wlc_phy_t *ppi, uint chan, u8 *max_txpwr,
1639 phy_info_t *pi = (phy_info_t *) ppi;
1641 u8 tx_pwr_min = 255;
1643 u8 maxtxpwr, mintxpwr, rate, pactrl;
1647 max_num_rate = ISNPHY(pi) ? TXP_NUM_RATES :
1648 ISLCNPHY(pi) ? (TXP_LAST_SISO_MCS_20 + 1) : (TXP_LAST_OFDM + 1);
1650 for (rate = 0; rate < max_num_rate; rate++) {
1652 wlc_phy_txpower_sromlimit(ppi, chan, &mintxpwr, &maxtxpwr,
1655 maxtxpwr = (maxtxpwr > pactrl) ? (maxtxpwr - pactrl) : 0;
1657 maxtxpwr = (maxtxpwr > 6) ? (maxtxpwr - 6) : 0;
1659 tx_pwr_max = max(tx_pwr_max, maxtxpwr);
1660 tx_pwr_min = min(tx_pwr_min, maxtxpwr);
1662 *max_txpwr = tx_pwr_max;
1663 *min_txpwr = tx_pwr_min;
1667 wlc_phy_txpower_boardlimit_band(wlc_phy_t *ppi, uint bandunit, s32 *max_pwr,
1668 s32 *min_pwr, u32 *step_pwr)
1673 u8 wlc_phy_txpower_get_target_min(wlc_phy_t *ppi)
1675 phy_info_t *pi = (phy_info_t *) ppi;
1677 return pi->tx_power_min;
1680 u8 wlc_phy_txpower_get_target_max(wlc_phy_t *ppi)
1682 phy_info_t *pi = (phy_info_t *) ppi;
1684 return pi->tx_power_max;
1687 void wlc_phy_txpower_recalc_target(phy_info_t *pi)
1689 u8 maxtxpwr, mintxpwr, rate, pactrl;
1691 u8 tx_pwr_target[TXP_NUM_RATES];
1693 u8 tx_pwr_min = 255;
1694 u8 tx_pwr_max_rate_ind = 0;
1698 u32 band = CHSPEC2WLC_BAND(pi->radio_chanspec);
1699 initfn_t txpwr_recalc_fn = NULL;
1701 chspec = pi->radio_chanspec;
1702 if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_NONE)
1703 target_chan = CHSPEC_CHANNEL(chspec);
1704 else if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_UPPER)
1705 target_chan = UPPER_20_SB(CHSPEC_CHANNEL(chspec));
1707 target_chan = LOWER_20_SB(CHSPEC_CHANNEL(chspec));
1713 if (CHSPEC_IS40(pi->radio_chanspec)) {
1714 offset_mcs = pi->mcs40_po;
1715 for (i = TXP_FIRST_SISO_MCS_20;
1716 i <= TXP_LAST_SISO_MCS_20; i++) {
1717 pi->tx_srom_max_rate_2g[i - 8] =
1718 pi->tx_srom_max_2g -
1719 ((offset_mcs & 0xf) * 2);
1723 offset_mcs = pi->mcs20_po;
1724 for (i = TXP_FIRST_SISO_MCS_20;
1725 i <= TXP_LAST_SISO_MCS_20; i++) {
1726 pi->tx_srom_max_rate_2g[i - 8] =
1727 pi->tx_srom_max_2g -
1728 ((offset_mcs & 0xf) * 2);
1734 max_num_rate = ((ISNPHY(pi)) ? (TXP_NUM_RATES) :
1736 (TXP_LAST_SISO_MCS_20 + 1) : (TXP_LAST_OFDM + 1)));
1738 max_num_rate = ((ISNPHY(pi)) ? (TXP_NUM_RATES) : (TXP_LAST_OFDM + 1));
1741 wlc_phy_upd_env_txpwr_rate_limits(pi, band);
1743 for (rate = start_rate; rate < max_num_rate; rate++) {
1745 tx_pwr_target[rate] = pi->tx_user_target[rate];
1747 if (pi->user_txpwr_at_rfport) {
1748 tx_pwr_target[rate] +=
1749 wlc_user_txpwr_antport_to_rfport(pi, target_chan,
1755 wlc_phy_txpower_sromlimit((wlc_phy_t *) pi, target_chan,
1756 &mintxpwr, &maxtxpwr, rate);
1758 maxtxpwr = min(maxtxpwr, pi->txpwr_limit[rate]);
1761 (maxtxpwr > pactrl) ? (maxtxpwr - pactrl) : 0;
1763 maxtxpwr = (maxtxpwr > 6) ? (maxtxpwr - 6) : 0;
1765 maxtxpwr = min(maxtxpwr, tx_pwr_target[rate]);
1767 if (pi->txpwr_percent <= 100)
1768 maxtxpwr = (maxtxpwr * pi->txpwr_percent) / 100;
1770 tx_pwr_target[rate] = max(maxtxpwr, mintxpwr);
1773 tx_pwr_target[rate] =
1774 min(tx_pwr_target[rate], pi->txpwr_env_limit[rate]);
1776 if (tx_pwr_target[rate] > tx_pwr_max)
1777 tx_pwr_max_rate_ind = rate;
1779 tx_pwr_max = max(tx_pwr_max, tx_pwr_target[rate]);
1780 tx_pwr_min = min(tx_pwr_min, tx_pwr_target[rate]);
1783 memset(pi->tx_power_offset, 0, sizeof(pi->tx_power_offset));
1784 pi->tx_power_max = tx_pwr_max;
1785 pi->tx_power_min = tx_pwr_min;
1786 pi->tx_power_max_rate_ind = tx_pwr_max_rate_ind;
1787 for (rate = 0; rate < max_num_rate; rate++) {
1789 pi->tx_power_target[rate] = tx_pwr_target[rate];
1791 if (!pi->hwpwrctrl || ISNPHY(pi)) {
1792 pi->tx_power_offset[rate] =
1793 pi->tx_power_max - pi->tx_power_target[rate];
1795 pi->tx_power_offset[rate] =
1796 pi->tx_power_target[rate] - pi->tx_power_min;
1800 txpwr_recalc_fn = pi->pi_fptr.txpwrrecalc;
1801 if (txpwr_recalc_fn)
1802 (*txpwr_recalc_fn) (pi);
1806 wlc_phy_txpower_reg_limit_calc(phy_info_t *pi, struct txpwr_limits *txpwr,
1807 chanspec_t chanspec)
1809 u8 tmp_txpwr_limit[2 * WLC_NUM_RATES_OFDM];
1810 u8 *txpwr_ptr1 = NULL, *txpwr_ptr2 = NULL;
1811 int rate_start_index = 0, rate1, rate2, k;
1813 for (rate1 = WL_TX_POWER_CCK_FIRST, rate2 = 0;
1814 rate2 < WL_TX_POWER_CCK_NUM; rate1++, rate2++)
1815 pi->txpwr_limit[rate1] = txpwr->cck[rate2];
1817 for (rate1 = WL_TX_POWER_OFDM_FIRST, rate2 = 0;
1818 rate2 < WL_TX_POWER_OFDM_NUM; rate1++, rate2++)
1819 pi->txpwr_limit[rate1] = txpwr->ofdm[rate2];
1823 for (k = 0; k < 4; k++) {
1827 txpwr_ptr1 = txpwr->mcs_20_siso;
1828 txpwr_ptr2 = txpwr->ofdm;
1829 rate_start_index = WL_TX_POWER_OFDM_FIRST;
1833 txpwr_ptr1 = txpwr->mcs_20_cdd;
1834 txpwr_ptr2 = txpwr->ofdm_cdd;
1835 rate_start_index = WL_TX_POWER_OFDM20_CDD_FIRST;
1839 txpwr_ptr1 = txpwr->mcs_40_siso;
1840 txpwr_ptr2 = txpwr->ofdm_40_siso;
1842 WL_TX_POWER_OFDM40_SISO_FIRST;
1846 txpwr_ptr1 = txpwr->mcs_40_cdd;
1847 txpwr_ptr2 = txpwr->ofdm_40_cdd;
1848 rate_start_index = WL_TX_POWER_OFDM40_CDD_FIRST;
1852 for (rate2 = 0; rate2 < WLC_NUM_RATES_OFDM; rate2++) {
1853 tmp_txpwr_limit[rate2] = 0;
1854 tmp_txpwr_limit[WLC_NUM_RATES_OFDM + rate2] =
1857 wlc_phy_mcs_to_ofdm_powers_nphy(tmp_txpwr_limit, 0,
1858 WLC_NUM_RATES_OFDM - 1,
1859 WLC_NUM_RATES_OFDM);
1860 for (rate1 = rate_start_index, rate2 = 0;
1861 rate2 < WLC_NUM_RATES_OFDM; rate1++, rate2++)
1862 pi->txpwr_limit[rate1] =
1863 min(txpwr_ptr2[rate2],
1864 tmp_txpwr_limit[rate2]);
1867 for (k = 0; k < 4; k++) {
1871 txpwr_ptr1 = txpwr->ofdm;
1872 txpwr_ptr2 = txpwr->mcs_20_siso;
1873 rate_start_index = WL_TX_POWER_MCS20_SISO_FIRST;
1877 txpwr_ptr1 = txpwr->ofdm_cdd;
1878 txpwr_ptr2 = txpwr->mcs_20_cdd;
1879 rate_start_index = WL_TX_POWER_MCS20_CDD_FIRST;
1883 txpwr_ptr1 = txpwr->ofdm_40_siso;
1884 txpwr_ptr2 = txpwr->mcs_40_siso;
1885 rate_start_index = WL_TX_POWER_MCS40_SISO_FIRST;
1889 txpwr_ptr1 = txpwr->ofdm_40_cdd;
1890 txpwr_ptr2 = txpwr->mcs_40_cdd;
1891 rate_start_index = WL_TX_POWER_MCS40_CDD_FIRST;
1894 for (rate2 = 0; rate2 < WLC_NUM_RATES_OFDM; rate2++) {
1895 tmp_txpwr_limit[rate2] = 0;
1896 tmp_txpwr_limit[WLC_NUM_RATES_OFDM + rate2] =
1899 wlc_phy_ofdm_to_mcs_powers_nphy(tmp_txpwr_limit, 0,
1900 WLC_NUM_RATES_OFDM - 1,
1901 WLC_NUM_RATES_OFDM);
1902 for (rate1 = rate_start_index, rate2 = 0;
1903 rate2 < WLC_NUM_RATES_MCS_1_STREAM;
1905 pi->txpwr_limit[rate1] =
1906 min(txpwr_ptr2[rate2],
1907 tmp_txpwr_limit[rate2]);
1910 for (k = 0; k < 2; k++) {
1914 rate_start_index = WL_TX_POWER_MCS20_STBC_FIRST;
1915 txpwr_ptr1 = txpwr->mcs_20_stbc;
1919 rate_start_index = WL_TX_POWER_MCS40_STBC_FIRST;
1920 txpwr_ptr1 = txpwr->mcs_40_stbc;
1923 for (rate1 = rate_start_index, rate2 = 0;
1924 rate2 < WLC_NUM_RATES_MCS_1_STREAM;
1926 pi->txpwr_limit[rate1] = txpwr_ptr1[rate2];
1929 for (k = 0; k < 2; k++) {
1933 rate_start_index = WL_TX_POWER_MCS20_SDM_FIRST;
1934 txpwr_ptr1 = txpwr->mcs_20_mimo;
1938 rate_start_index = WL_TX_POWER_MCS40_SDM_FIRST;
1939 txpwr_ptr1 = txpwr->mcs_40_mimo;
1942 for (rate1 = rate_start_index, rate2 = 0;
1943 rate2 < WLC_NUM_RATES_MCS_2_STREAM;
1945 pi->txpwr_limit[rate1] = txpwr_ptr1[rate2];
1948 pi->txpwr_limit[WL_TX_POWER_MCS_32] = txpwr->mcs32;
1950 pi->txpwr_limit[WL_TX_POWER_MCS40_CDD_FIRST] =
1951 min(pi->txpwr_limit[WL_TX_POWER_MCS40_CDD_FIRST],
1952 pi->txpwr_limit[WL_TX_POWER_MCS_32]);
1953 pi->txpwr_limit[WL_TX_POWER_MCS_32] =
1954 pi->txpwr_limit[WL_TX_POWER_MCS40_CDD_FIRST];
1958 void wlc_phy_txpwr_percent_set(wlc_phy_t *ppi, u8 txpwr_percent)
1960 phy_info_t *pi = (phy_info_t *) ppi;
1962 pi->txpwr_percent = txpwr_percent;
1965 void wlc_phy_machwcap_set(wlc_phy_t *ppi, u32 machwcap)
1967 phy_info_t *pi = (phy_info_t *) ppi;
1969 pi->sh->machwcap = machwcap;
1972 void wlc_phy_runbist_config(wlc_phy_t *ppi, bool start_end)
1974 phy_info_t *pi = (phy_info_t *) ppi;
1978 if (start_end == ON) {
1982 if (NREV_IS(pi->pubpi.phy_rev, 3)
1983 || NREV_IS(pi->pubpi.phy_rev, 4)) {
1984 W_REG(&pi->regs->phyregaddr, 0xa0);
1985 (void)R_REG(&pi->regs->phyregaddr);
1986 rxc = R_REG(&pi->regs->phyregdata);
1987 W_REG(&pi->regs->phyregdata,
1991 if (NREV_IS(pi->pubpi.phy_rev, 3)
1992 || NREV_IS(pi->pubpi.phy_rev, 4)) {
1993 W_REG(&pi->regs->phyregaddr, 0xa0);
1994 (void)R_REG(&pi->regs->phyregaddr);
1995 W_REG(&pi->regs->phyregdata, rxc);
1998 wlc_phy_por_inform(ppi);
2003 wlc_phy_txpower_limit_set(wlc_phy_t *ppi, struct txpwr_limits *txpwr,
2004 chanspec_t chanspec)
2006 phy_info_t *pi = (phy_info_t *) ppi;
2008 wlc_phy_txpower_reg_limit_calc(pi, txpwr, chanspec);
2012 for (i = TXP_FIRST_OFDM_20_CDD, j = 0;
2013 j < WLC_NUM_RATES_MCS_1_STREAM; i++, j++) {
2014 if (txpwr->mcs_20_siso[j])
2015 pi->txpwr_limit[i] = txpwr->mcs_20_siso[j];
2017 pi->txpwr_limit[i] = txpwr->ofdm[j];
2021 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2023 wlc_phy_txpower_recalc_target(pi);
2024 wlc_phy_cal_txpower_recalc_sw(pi);
2025 wlapi_enable_mac(pi->sh->physhim);
2028 void wlc_phy_ofdm_rateset_war(wlc_phy_t *pih, bool war)
2030 phy_info_t *pi = (phy_info_t *) pih;
2032 pi->ofdm_rateset_war = war;
2035 void wlc_phy_bf_preempt_enable(wlc_phy_t *pih, bool bf_preempt)
2037 phy_info_t *pi = (phy_info_t *) pih;
2039 pi->bf_preempt_4306 = bf_preempt;
2042 void wlc_phy_txpower_update_shm(phy_info_t *pi)
2052 if (pi->hwpwrctrl) {
2055 wlapi_bmac_write_shm(pi->sh->physhim, M_TXPWR_MAX, 63);
2056 wlapi_bmac_write_shm(pi->sh->physhim, M_TXPWR_N,
2057 1 << NUM_TSSI_FRAMES);
2059 wlapi_bmac_write_shm(pi->sh->physhim, M_TXPWR_TARGET,
2060 pi->tx_power_min << NUM_TSSI_FRAMES);
2062 wlapi_bmac_write_shm(pi->sh->physhim, M_TXPWR_CUR,
2065 for (j = TXP_FIRST_OFDM; j <= TXP_LAST_OFDM; j++) {
2066 const u8 ucode_ofdm_rates[] = {
2067 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c
2069 offset = wlapi_bmac_rate_shm_offset(pi->sh->physhim,
2070 ucode_ofdm_rates[j -
2072 wlapi_bmac_write_shm(pi->sh->physhim, offset + 6,
2073 pi->tx_power_offset[j]);
2074 wlapi_bmac_write_shm(pi->sh->physhim, offset + 14,
2075 -(pi->tx_power_offset[j] / 2));
2078 wlapi_bmac_mhf(pi->sh->physhim, MHF2, MHF2_HWPWRCTL,
2079 MHF2_HWPWRCTL, WLC_BAND_ALL);
2083 for (i = TXP_FIRST_OFDM; i <= TXP_LAST_OFDM; i++)
2084 pi->tx_power_offset[i] =
2085 (u8) roundup(pi->tx_power_offset[i], 8);
2086 wlapi_bmac_write_shm(pi->sh->physhim, M_OFDM_OFFSET,
2088 tx_power_offset[TXP_FIRST_OFDM]
2093 bool wlc_phy_txpower_hw_ctrl_get(wlc_phy_t *ppi)
2095 phy_info_t *pi = (phy_info_t *) ppi;
2098 return pi->nphy_txpwrctrl;
2100 return pi->hwpwrctrl;
2104 void wlc_phy_txpower_hw_ctrl_set(wlc_phy_t *ppi, bool hwpwrctrl)
2106 phy_info_t *pi = (phy_info_t *) ppi;
2107 bool cur_hwpwrctrl = pi->hwpwrctrl;
2110 if (!pi->hwpwrctrl_capable) {
2114 pi->hwpwrctrl = hwpwrctrl;
2115 pi->nphy_txpwrctrl = hwpwrctrl;
2116 pi->txpwrctrl = hwpwrctrl;
2121 (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC));
2123 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2125 wlc_phy_txpwrctrl_enable_nphy(pi, pi->nphy_txpwrctrl);
2126 if (pi->nphy_txpwrctrl == PHY_TPC_HW_OFF) {
2127 wlc_phy_txpwr_fixpower_nphy(pi);
2130 mod_phy_reg(pi, 0x1e7, (0x7f << 0),
2131 pi->saved_txpwr_idx);
2135 wlapi_enable_mac(pi->sh->physhim);
2136 } else if (hwpwrctrl != cur_hwpwrctrl) {
2142 void wlc_phy_txpower_ipa_upd(phy_info_t *pi)
2145 if (NREV_GE(pi->pubpi.phy_rev, 3)) {
2146 pi->ipa2g_on = (pi->srom_fem2g.extpagain == 2);
2147 pi->ipa5g_on = (pi->srom_fem5g.extpagain == 2);
2149 pi->ipa2g_on = false;
2150 pi->ipa5g_on = false;
2154 static u32 wlc_phy_txpower_est_power_nphy(phy_info_t *pi);
2156 static u32 wlc_phy_txpower_est_power_nphy(phy_info_t *pi)
2158 s16 tx0_status, tx1_status;
2159 u16 estPower1, estPower2;
2160 u8 pwr0, pwr1, adj_pwr0, adj_pwr1;
2163 estPower1 = read_phy_reg(pi, 0x118);
2164 estPower2 = read_phy_reg(pi, 0x119);
2166 if ((estPower1 & (0x1 << 8))
2168 pwr0 = (u8) (estPower1 & (0xff << 0))
2174 if ((estPower2 & (0x1 << 8))
2176 pwr1 = (u8) (estPower2 & (0xff << 0))
2182 tx0_status = read_phy_reg(pi, 0x1ed);
2183 tx1_status = read_phy_reg(pi, 0x1ee);
2185 if ((tx0_status & (0x1 << 15))
2187 adj_pwr0 = (u8) (tx0_status & (0xff << 0))
2192 if ((tx1_status & (0x1 << 15))
2194 adj_pwr1 = (u8) (tx1_status & (0xff << 0))
2201 (u32) ((pwr0 << 24) | (pwr1 << 16) | (adj_pwr0 << 8) | adj_pwr1);
2206 wlc_phy_txpower_get_current(wlc_phy_t *ppi, tx_power_t *power, uint channel)
2208 phy_info_t *pi = (phy_info_t *) ppi;
2209 uint rate, num_rates;
2210 u8 min_pwr, max_pwr;
2212 #if WL_TX_POWER_RATES != TXP_NUM_RATES
2213 #error "tx_power_t struct out of sync with this fn"
2217 power->rf_cores = 2;
2218 power->flags |= (WL_TX_POWER_F_MIMO);
2219 if (pi->nphy_txpwrctrl == PHY_TPC_HW_ON)
2221 (WL_TX_POWER_F_ENABLED | WL_TX_POWER_F_HW);
2222 } else if (ISLCNPHY(pi)) {
2223 power->rf_cores = 1;
2224 power->flags |= (WL_TX_POWER_F_SISO);
2225 if (pi->radiopwr_override == RADIOPWR_OVERRIDE_DEF)
2226 power->flags |= WL_TX_POWER_F_ENABLED;
2228 power->flags |= WL_TX_POWER_F_HW;
2231 num_rates = ((ISNPHY(pi)) ? (TXP_NUM_RATES) :
2233 (TXP_LAST_OFDM_20_CDD + 1) : (TXP_LAST_OFDM + 1)));
2235 for (rate = 0; rate < num_rates; rate++) {
2236 power->user_limit[rate] = pi->tx_user_target[rate];
2237 wlc_phy_txpower_sromlimit(ppi, channel, &min_pwr, &max_pwr,
2239 power->board_limit[rate] = (u8) max_pwr;
2240 power->target[rate] = pi->tx_power_target[rate];
2246 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2247 wlc_phyreg_enter((wlc_phy_t *) pi);
2248 est_pout = wlc_phy_txpower_est_power_nphy(pi);
2249 wlc_phyreg_exit((wlc_phy_t *) pi);
2250 wlapi_enable_mac(pi->sh->physhim);
2252 power->est_Pout[0] = (est_pout >> 8) & 0xff;
2253 power->est_Pout[1] = est_pout & 0xff;
2255 power->est_Pout_act[0] = est_pout >> 24;
2256 power->est_Pout_act[1] = (est_pout >> 16) & 0xff;
2258 if (power->est_Pout[0] == 0x80)
2259 power->est_Pout[0] = 0;
2260 if (power->est_Pout[1] == 0x80)
2261 power->est_Pout[1] = 0;
2263 if (power->est_Pout_act[0] == 0x80)
2264 power->est_Pout_act[0] = 0;
2265 if (power->est_Pout_act[1] == 0x80)
2266 power->est_Pout_act[1] = 0;
2268 power->est_Pout_cck = 0;
2270 power->tx_power_max[0] = pi->tx_power_max;
2271 power->tx_power_max[1] = pi->tx_power_max;
2273 power->tx_power_max_rate_ind[0] = pi->tx_power_max_rate_ind;
2274 power->tx_power_max_rate_ind[1] = pi->tx_power_max_rate_ind;
2275 } else if (!pi->hwpwrctrl) {
2276 } else if (pi->sh->up) {
2278 wlc_phyreg_enter(ppi);
2281 power->tx_power_max[0] = pi->tx_power_max;
2282 power->tx_power_max[1] = pi->tx_power_max;
2284 power->tx_power_max_rate_ind[0] =
2285 pi->tx_power_max_rate_ind;
2286 power->tx_power_max_rate_ind[1] =
2287 pi->tx_power_max_rate_ind;
2289 if (wlc_phy_tpc_isenabled_lcnphy(pi))
2291 (WL_TX_POWER_F_HW | WL_TX_POWER_F_ENABLED);
2294 ~(WL_TX_POWER_F_HW | WL_TX_POWER_F_ENABLED);
2296 wlc_lcnphy_get_tssi(pi, (s8 *) &power->est_Pout[0],
2297 (s8 *) &power->est_Pout_cck);
2299 wlc_phyreg_exit(ppi);
2303 void wlc_phy_antsel_type_set(wlc_phy_t *ppi, u8 antsel_type)
2305 phy_info_t *pi = (phy_info_t *) ppi;
2307 pi->antsel_type = antsel_type;
2310 bool wlc_phy_test_ison(wlc_phy_t *ppi)
2312 phy_info_t *pi = (phy_info_t *) ppi;
2314 return pi->phytest_on;
2317 void wlc_phy_ant_rxdiv_set(wlc_phy_t *ppi, u8 val)
2319 phy_info_t *pi = (phy_info_t *) ppi;
2322 pi->sh->rx_antdiv = val;
2324 if (!(ISNPHY(pi) && D11REV_IS(pi->sh->corerev, 16))) {
2325 if (val > ANT_RX_DIV_FORCE_1)
2326 wlapi_bmac_mhf(pi->sh->physhim, MHF1, MHF1_ANTDIV,
2327 MHF1_ANTDIV, WLC_BAND_ALL);
2329 wlapi_bmac_mhf(pi->sh->physhim, MHF1, MHF1_ANTDIV, 0,
2342 (0 == (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC));
2344 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2347 if (val > ANT_RX_DIV_FORCE_1) {
2348 mod_phy_reg(pi, 0x410, (0x1 << 1), 0x01 << 1);
2349 mod_phy_reg(pi, 0x410,
2351 ((ANT_RX_DIV_START_1 == val) ? 1 : 0) << 0);
2353 mod_phy_reg(pi, 0x410, (0x1 << 1), 0x00 << 1);
2354 mod_phy_reg(pi, 0x410, (0x1 << 0), (u16) val << 0);
2359 wlapi_enable_mac(pi->sh->physhim);
2365 wlc_phy_noise_calc_phy(phy_info_t *pi, u32 *cmplx_pwr, s8 *pwr_ant)
2367 s8 cmplx_pwr_dbm[PHY_CORE_MAX];
2370 memset((u8 *) cmplx_pwr_dbm, 0, sizeof(cmplx_pwr_dbm));
2371 wlc_phy_compute_dB(cmplx_pwr, cmplx_pwr_dbm, pi->pubpi.phy_corenum);
2373 for (i = 0; i < pi->pubpi.phy_corenum; i++) {
2374 if (NREV_GE(pi->pubpi.phy_rev, 3))
2375 cmplx_pwr_dbm[i] += (s8) PHY_NOISE_OFFSETFACT_4322;
2378 cmplx_pwr_dbm[i] += (s8) (16 - (15) * 3 - 70);
2381 for (i = 0; i < pi->pubpi.phy_corenum; i++) {
2382 pi->nphy_noise_win[i][pi->nphy_noise_index] = cmplx_pwr_dbm[i];
2383 pwr_ant[i] = cmplx_pwr_dbm[i];
2385 pi->nphy_noise_index =
2386 MODINC_POW2(pi->nphy_noise_index, PHY_NOISE_WINDOW_SZ);
2391 wlc_phy_noise_sample_request(wlc_phy_t *pih, u8 reason, u8 ch)
2393 phy_info_t *pi = (phy_info_t *) pih;
2394 s8 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;
2395 bool sampling_in_progress = (pi->phynoise_state != 0);
2396 bool wait_for_intr = true;
2398 if (NORADIO_ENAB(pi->pubpi)) {
2403 case PHY_NOISE_SAMPLE_MON:
2405 pi->phynoise_chan_watchdog = ch;
2406 pi->phynoise_state |= PHY_NOISE_STATE_MON;
2410 case PHY_NOISE_SAMPLE_EXTERNAL:
2412 pi->phynoise_state |= PHY_NOISE_STATE_EXTERNAL;
2419 if (sampling_in_progress)
2422 pi->phynoise_now = pi->sh->now;
2424 if (pi->phy_fixed_noise) {
2426 pi->nphy_noise_win[WL_ANT_IDX_1][pi->nphy_noise_index] =
2427 PHY_NOISE_FIXED_VAL_NPHY;
2428 pi->nphy_noise_win[WL_ANT_IDX_2][pi->nphy_noise_index] =
2429 PHY_NOISE_FIXED_VAL_NPHY;
2430 pi->nphy_noise_index = MODINC_POW2(pi->nphy_noise_index,
2431 PHY_NOISE_WINDOW_SZ);
2433 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;
2436 noise_dbm = PHY_NOISE_FIXED_VAL;
2439 wait_for_intr = false;
2444 if (!pi->phynoise_polling
2445 || (reason == PHY_NOISE_SAMPLE_EXTERNAL)) {
2446 wlapi_bmac_write_shm(pi->sh->physhim, M_JSSI_0, 0);
2447 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP0, 0);
2448 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP1, 0);
2449 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP2, 0);
2450 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP3, 0);
2452 OR_REG(&pi->regs->maccommand,
2455 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2456 wlc_lcnphy_deaf_mode(pi, (bool) 0);
2457 noise_dbm = (s8) wlc_lcnphy_rx_signal_power(pi, 20);
2458 wlc_lcnphy_deaf_mode(pi, (bool) 1);
2459 wlapi_enable_mac(pi->sh->physhim);
2460 wait_for_intr = false;
2462 } else if (ISNPHY(pi)) {
2463 if (!pi->phynoise_polling
2464 || (reason == PHY_NOISE_SAMPLE_EXTERNAL)) {
2466 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP0, 0);
2467 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP1, 0);
2468 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP2, 0);
2469 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP3, 0);
2471 OR_REG(&pi->regs->maccommand,
2474 phy_iq_est_t est[PHY_CORE_MAX];
2475 u32 cmplx_pwr[PHY_CORE_MAX];
2476 s8 noise_dbm_ant[PHY_CORE_MAX];
2477 u16 log_num_samps, num_samps, classif_state = 0;
2482 memset((u8 *) est, 0, sizeof(est));
2483 memset((u8 *) cmplx_pwr, 0, sizeof(cmplx_pwr));
2484 memset((u8 *) noise_dbm_ant, 0, sizeof(noise_dbm_ant));
2486 log_num_samps = PHY_NOISE_SAMPLE_LOG_NUM_NPHY;
2487 num_samps = 1 << log_num_samps;
2489 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2490 classif_state = wlc_phy_classifier_nphy(pi, 0, 0);
2491 wlc_phy_classifier_nphy(pi, 3, 0);
2492 wlc_phy_rx_iq_est_nphy(pi, est, num_samps, wait_time,
2494 wlc_phy_classifier_nphy(pi, (0x7 << 0), classif_state);
2495 wlapi_enable_mac(pi->sh->physhim);
2497 for (i = 0; i < pi->pubpi.phy_corenum; i++)
2500 est[i].q_pwr) >> log_num_samps;
2502 wlc_phy_noise_calc_phy(pi, cmplx_pwr, noise_dbm_ant);
2504 for (i = 0; i < pi->pubpi.phy_corenum; i++) {
2505 pi->nphy_noise_win[i][pi->nphy_noise_index] =
2508 if (noise_dbm_ant[i] > noise_dbm)
2509 noise_dbm = noise_dbm_ant[i];
2511 pi->nphy_noise_index = MODINC_POW2(pi->nphy_noise_index,
2512 PHY_NOISE_WINDOW_SZ);
2514 wait_for_intr = false;
2521 wlc_phy_noise_cb(pi, ch, noise_dbm);
2525 void wlc_phy_noise_sample_request_external(wlc_phy_t *pih)
2529 channel = CHSPEC_CHANNEL(wlc_phy_chanspec_get(pih));
2531 wlc_phy_noise_sample_request(pih, PHY_NOISE_SAMPLE_EXTERNAL, channel);
2534 static void wlc_phy_noise_cb(phy_info_t *pi, u8 channel, s8 noise_dbm)
2536 if (!pi->phynoise_state)
2539 if (pi->phynoise_state & PHY_NOISE_STATE_MON) {
2540 if (pi->phynoise_chan_watchdog == channel) {
2541 pi->sh->phy_noise_window[pi->sh->phy_noise_index] =
2543 pi->sh->phy_noise_index =
2544 MODINC(pi->sh->phy_noise_index, MA_WINDOW_SZ);
2546 pi->phynoise_state &= ~PHY_NOISE_STATE_MON;
2549 if (pi->phynoise_state & PHY_NOISE_STATE_EXTERNAL) {
2550 pi->phynoise_state &= ~PHY_NOISE_STATE_EXTERNAL;
2555 static s8 wlc_phy_noise_read_shmem(phy_info_t *pi)
2557 u32 cmplx_pwr[PHY_CORE_MAX];
2558 s8 noise_dbm_ant[PHY_CORE_MAX];
2560 u32 cmplx_pwr_tot = 0;
2561 s8 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;
2564 memset((u8 *) cmplx_pwr, 0, sizeof(cmplx_pwr));
2565 memset((u8 *) noise_dbm_ant, 0, sizeof(noise_dbm_ant));
2567 for (idx = 0, core = 0; core < pi->pubpi.phy_corenum; idx += 2, core++) {
2568 lo = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP(idx));
2569 hi = wlapi_bmac_read_shm(pi->sh->physhim,
2570 M_PWRIND_MAP(idx + 1));
2571 cmplx_pwr[core] = (hi << 16) + lo;
2572 cmplx_pwr_tot += cmplx_pwr[core];
2573 if (cmplx_pwr[core] == 0) {
2574 noise_dbm_ant[core] = PHY_NOISE_FIXED_VAL_NPHY;
2576 cmplx_pwr[core] >>= PHY_NOISE_SAMPLE_LOG_NUM_UCODE;
2579 if (cmplx_pwr_tot != 0)
2580 wlc_phy_noise_calc_phy(pi, cmplx_pwr, noise_dbm_ant);
2582 for (core = 0; core < pi->pubpi.phy_corenum; core++) {
2583 pi->nphy_noise_win[core][pi->nphy_noise_index] =
2584 noise_dbm_ant[core];
2586 if (noise_dbm_ant[core] > noise_dbm)
2587 noise_dbm = noise_dbm_ant[core];
2589 pi->nphy_noise_index =
2590 MODINC_POW2(pi->nphy_noise_index, PHY_NOISE_WINDOW_SZ);
2596 void wlc_phy_noise_sample_intr(wlc_phy_t *pih)
2598 phy_info_t *pi = (phy_info_t *) pih;
2601 s8 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;
2604 u32 cmplx_pwr, cmplx_pwr0, cmplx_pwr1;
2606 s32 pwr_offset_dB, gain_dB;
2607 u16 status_0, status_1;
2609 jssi_aux = wlapi_bmac_read_shm(pi->sh->physhim, M_JSSI_AUX);
2610 channel = jssi_aux & D11_CURCHANNEL_MAX;
2612 lo = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP0);
2613 hi = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP1);
2614 cmplx_pwr0 = (hi << 16) + lo;
2616 lo = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP2);
2617 hi = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP3);
2618 cmplx_pwr1 = (hi << 16) + lo;
2619 cmplx_pwr = (cmplx_pwr0 + cmplx_pwr1) >> 6;
2622 status_1 = wlapi_bmac_read_shm(pi->sh->physhim, M_JSSI_0);
2623 if ((cmplx_pwr > 0 && cmplx_pwr < 500)
2624 && ((status_1 & 0xc000) == 0x4000)) {
2626 wlc_phy_compute_dB(&cmplx_pwr, &noise_dbm,
2627 pi->pubpi.phy_corenum);
2628 pwr_offset_dB = (read_phy_reg(pi, 0x434) & 0xFF);
2629 if (pwr_offset_dB > 127)
2630 pwr_offset_dB -= 256;
2632 noise_dbm += (s8) (pwr_offset_dB - 30);
2634 gain_dB = (status_0 & 0x1ff);
2635 noise_dbm -= (s8) (gain_dB);
2637 noise_dbm = PHY_NOISE_FIXED_VAL_LCNPHY;
2639 } else if (ISNPHY(pi)) {
2641 jssi_aux = wlapi_bmac_read_shm(pi->sh->physhim, M_JSSI_AUX);
2642 channel = jssi_aux & D11_CURCHANNEL_MAX;
2644 noise_dbm = wlc_phy_noise_read_shmem(pi);
2647 wlc_phy_noise_cb(pi, channel, noise_dbm);
2651 s8 lcnphy_gain_index_offset_for_pkt_rssi[] = {
2692 void wlc_phy_compute_dB(u32 *cmplx_pwr, s8 *p_cmplx_pwr_dB, u8 core)
2694 u8 msb, secondmsb, i;
2697 for (i = 0; i < core; i++) {
2702 secondmsb = (u8) ((tmp >> (--msb - 1)) & 1);
2703 p_cmplx_pwr_dB[i] = (s8) (3 * msb + 2 * secondmsb);
2707 void wlc_phy_rssi_compute(wlc_phy_t *pih, void *ctx)
2709 wlc_d11rxhdr_t *wlc_rxhdr = (wlc_d11rxhdr_t *) ctx;
2710 d11rxhdr_t *rxh = &wlc_rxhdr->rxhdr;
2711 int rssi = le16_to_cpu(rxh->PhyRxStatus_1) & PRXS1_JSSI_MASK;
2712 uint radioid = pih->radioid;
2713 phy_info_t *pi = (phy_info_t *) pih;
2715 if (NORADIO_ENAB(pi->pubpi)) {
2716 rssi = WLC_RSSI_INVALID;
2720 if ((pi->sh->corerev >= 11)
2721 && !(le16_to_cpu(rxh->RxStatus2) & RXS_PHYRXST_VALID)) {
2722 rssi = WLC_RSSI_INVALID;
2727 u8 gidx = (le16_to_cpu(rxh->PhyRxStatus_2) & 0xFC00) >> 10;
2728 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
2733 rssi = rssi + lcnphy_gain_index_offset_for_pkt_rssi[gidx];
2734 if ((rssi > -46) && (gidx > 18))
2737 rssi = rssi + pi_lcn->lcnphy_pkteng_rssi_slope;
2747 } else if (radioid == BCM2055_ID || radioid == BCM2056_ID
2748 || radioid == BCM2057_ID) {
2749 rssi = wlc_phy_rssi_compute_nphy(pi, wlc_rxhdr);
2753 wlc_rxhdr->rssi = (s8) rssi;
2756 void wlc_phy_freqtrack_start(wlc_phy_t *pih)
2761 void wlc_phy_freqtrack_end(wlc_phy_t *pih)
2766 void wlc_phy_set_deaf(wlc_phy_t *ppi, bool user_flag)
2769 pi = (phy_info_t *) ppi;
2772 wlc_lcnphy_deaf_mode(pi, true);
2773 else if (ISNPHY(pi))
2774 wlc_nphy_deaf_mode(pi, true);
2777 void wlc_phy_watchdog(wlc_phy_t *pih)
2779 phy_info_t *pi = (phy_info_t *) pih;
2780 bool delay_phy_cal = false;
2783 if (!pi->watchdog_override)
2786 if (!(SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi))) {
2787 wlc_phy_noise_sample_request((wlc_phy_t *) pi,
2788 PHY_NOISE_SAMPLE_MON,
2793 if (pi->phynoise_state && (pi->sh->now - pi->phynoise_now) > 5) {
2794 pi->phynoise_state = 0;
2797 if ((!pi->phycal_txpower) ||
2798 ((pi->sh->now - pi->phycal_txpower) >= pi->sh->fast_timer)) {
2800 if (!SCAN_INPROG_PHY(pi) && wlc_phy_cal_txpower_recalc_sw(pi)) {
2801 pi->phycal_txpower = pi->sh->now;
2805 if (NORADIO_ENAB(pi->pubpi))
2808 if ((SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi)
2809 || ASSOC_INPROG_PHY(pi)))
2812 if (ISNPHY(pi) && !pi->disable_percal && !delay_phy_cal) {
2814 if ((pi->nphy_perical != PHY_PERICAL_DISABLE) &&
2815 (pi->nphy_perical != PHY_PERICAL_MANUAL) &&
2816 ((pi->sh->now - pi->nphy_perical_last) >=
2817 pi->sh->glacial_timer))
2818 wlc_phy_cal_perical((wlc_phy_t *) pi,
2819 PHY_PERICAL_WATCHDOG);
2821 wlc_phy_txpwr_papd_cal_nphy(pi);
2825 if (pi->phy_forcecal ||
2826 ((pi->sh->now - pi->phy_lastcal) >=
2827 pi->sh->glacial_timer)) {
2828 if (!(SCAN_RM_IN_PROGRESS(pi) || ASSOC_INPROG_PHY(pi)))
2829 wlc_lcnphy_calib_modes(pi,
2830 LCNPHY_PERICAL_TEMPBASED_TXPWRCTRL);
2832 (SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi)
2833 || ASSOC_INPROG_PHY(pi)
2834 || pi->carrier_suppr_disable
2835 || pi->disable_percal))
2836 wlc_lcnphy_calib_modes(pi,
2837 PHY_PERICAL_WATCHDOG);
2842 void wlc_phy_BSSinit(wlc_phy_t *pih, bool bonlyap, int rssi)
2844 phy_info_t *pi = (phy_info_t *) pih;
2848 for (i = 0; i < MA_WINDOW_SZ; i++) {
2849 pi->sh->phy_noise_window[i] = (s8) (rssi & 0xff);
2852 for (i = 0; i < MA_WINDOW_SZ; i++)
2853 pi->sh->phy_noise_window[i] =
2854 PHY_NOISE_FIXED_VAL_LCNPHY;
2856 pi->sh->phy_noise_index = 0;
2858 for (i = 0; i < PHY_NOISE_WINDOW_SZ; i++) {
2859 for (k = WL_ANT_IDX_1; k < WL_ANT_RX_MAX; k++)
2860 pi->nphy_noise_win[k][i] = PHY_NOISE_FIXED_VAL_NPHY;
2862 pi->nphy_noise_index = 0;
2866 wlc_phy_papd_decode_epsilon(u32 epsilon, s32 *eps_real, s32 *eps_imag)
2868 *eps_imag = (epsilon >> 13);
2869 if (*eps_imag > 0xfff)
2870 *eps_imag -= 0x2000;
2872 *eps_real = (epsilon & 0x1fff);
2873 if (*eps_real > 0xfff)
2874 *eps_real -= 0x2000;
2877 static const fixed AtanTbl[] = {
2898 void wlc_phy_cordic(fixed theta, cs32 *val)
2900 fixed angle, valtmp;
2905 val[0].i = CORDIC_AG;
2909 signtheta = (theta < 0) ? -1 : 1;
2911 ((theta + FIXED(180) * signtheta) % FIXED(360)) -
2912 FIXED(180) * signtheta;
2914 if (FLOAT(theta) > 90) {
2915 theta -= FIXED(180);
2917 } else if (FLOAT(theta) < -90) {
2918 theta += FIXED(180);
2922 for (iter = 0; iter < CORDIC_NI; iter++) {
2923 if (theta > angle) {
2924 valtmp = val[0].i - (val[0].q >> iter);
2925 val[0].q = (val[0].i >> iter) + val[0].q;
2927 angle += AtanTbl[iter];
2929 valtmp = val[0].i + (val[0].q >> iter);
2930 val[0].q = -(val[0].i >> iter) + val[0].q;
2932 angle -= AtanTbl[iter];
2936 val[0].i = val[0].i * signx;
2937 val[0].q = val[0].q * signx;
2940 void wlc_phy_cal_perical_mphase_reset(phy_info_t *pi)
2942 wlapi_del_timer(pi->sh->physhim, pi->phycal_timer);
2944 pi->cal_type_override = PHY_PERICAL_AUTO;
2945 pi->mphase_cal_phase_id = MPHASE_CAL_STATE_IDLE;
2946 pi->mphase_txcal_cmdidx = 0;
2949 static void wlc_phy_cal_perical_mphase_schedule(phy_info_t *pi, uint delay)
2952 if ((pi->nphy_perical != PHY_PERICAL_MPHASE) &&
2953 (pi->nphy_perical != PHY_PERICAL_MANUAL))
2956 wlapi_del_timer(pi->sh->physhim, pi->phycal_timer);
2958 pi->mphase_cal_phase_id = MPHASE_CAL_STATE_INIT;
2959 wlapi_add_timer(pi->sh->physhim, pi->phycal_timer, delay, 0);
2962 void wlc_phy_cal_perical(wlc_phy_t *pih, u8 reason)
2964 s16 nphy_currtemp = 0;
2966 bool do_periodic_cal = true;
2967 phy_info_t *pi = (phy_info_t *) pih;
2972 if ((pi->nphy_perical == PHY_PERICAL_DISABLE) ||
2973 (pi->nphy_perical == PHY_PERICAL_MANUAL))
2977 case PHY_PERICAL_DRIVERUP:
2980 case PHY_PERICAL_PHYINIT:
2981 if (pi->nphy_perical == PHY_PERICAL_MPHASE) {
2982 if (PHY_PERICAL_MPHASE_PENDING(pi)) {
2983 wlc_phy_cal_perical_mphase_reset(pi);
2985 wlc_phy_cal_perical_mphase_schedule(pi,
2986 PHY_PERICAL_INIT_DELAY);
2990 case PHY_PERICAL_JOIN_BSS:
2991 case PHY_PERICAL_START_IBSS:
2992 case PHY_PERICAL_UP_BSS:
2993 if ((pi->nphy_perical == PHY_PERICAL_MPHASE) &&
2994 PHY_PERICAL_MPHASE_PENDING(pi)) {
2995 wlc_phy_cal_perical_mphase_reset(pi);
2998 pi->first_cal_after_assoc = true;
3000 pi->cal_type_override = PHY_PERICAL_FULL;
3002 if (pi->phycal_tempdelta) {
3003 pi->nphy_lastcal_temp = wlc_phy_tempsense_nphy(pi);
3005 wlc_phy_cal_perical_nphy_run(pi, PHY_PERICAL_FULL);
3008 case PHY_PERICAL_WATCHDOG:
3009 if (pi->phycal_tempdelta) {
3010 nphy_currtemp = wlc_phy_tempsense_nphy(pi);
3012 (nphy_currtemp > pi->nphy_lastcal_temp) ?
3013 nphy_currtemp - pi->nphy_lastcal_temp :
3014 pi->nphy_lastcal_temp - nphy_currtemp;
3016 if ((delta_temp < (s16) pi->phycal_tempdelta) &&
3017 (pi->nphy_txiqlocal_chanspec ==
3018 pi->radio_chanspec)) {
3019 do_periodic_cal = false;
3021 pi->nphy_lastcal_temp = nphy_currtemp;
3025 if (do_periodic_cal) {
3027 if (pi->nphy_perical == PHY_PERICAL_MPHASE) {
3029 if (!PHY_PERICAL_MPHASE_PENDING(pi))
3030 wlc_phy_cal_perical_mphase_schedule(pi,
3031 PHY_PERICAL_WDOG_DELAY);
3032 } else if (pi->nphy_perical == PHY_PERICAL_SPHASE)
3033 wlc_phy_cal_perical_nphy_run(pi,
3042 void wlc_phy_cal_perical_mphase_restart(phy_info_t *pi)
3044 pi->mphase_cal_phase_id = MPHASE_CAL_STATE_INIT;
3045 pi->mphase_txcal_cmdidx = 0;
3048 u8 wlc_phy_nbits(s32 value)
3053 abs_val = ABS(value);
3054 while ((abs_val >> nbits) > 0)
3060 void wlc_phy_stf_chain_init(wlc_phy_t *pih, u8 txchain, u8 rxchain)
3062 phy_info_t *pi = (phy_info_t *) pih;
3064 pi->sh->hw_phytxchain = txchain;
3065 pi->sh->hw_phyrxchain = rxchain;
3066 pi->sh->phytxchain = txchain;
3067 pi->sh->phyrxchain = rxchain;
3068 pi->pubpi.phy_corenum = (u8) PHY_BITSCNT(pi->sh->phyrxchain);
3071 void wlc_phy_stf_chain_set(wlc_phy_t *pih, u8 txchain, u8 rxchain)
3073 phy_info_t *pi = (phy_info_t *) pih;
3075 pi->sh->phytxchain = txchain;
3078 wlc_phy_rxcore_setstate_nphy(pih, rxchain);
3080 pi->pubpi.phy_corenum = (u8) PHY_BITSCNT(pi->sh->phyrxchain);
3083 void wlc_phy_stf_chain_get(wlc_phy_t *pih, u8 *txchain, u8 *rxchain)
3085 phy_info_t *pi = (phy_info_t *) pih;
3087 *txchain = pi->sh->phytxchain;
3088 *rxchain = pi->sh->phyrxchain;
3091 u8 wlc_phy_stf_chain_active_get(wlc_phy_t *pih)
3095 phy_info_t *pi = (phy_info_t *) pih;
3097 active_bitmap = (pi->phy_txcore_heatedup) ? 0x31 : 0x33;
3099 if (!pi->watchdog_override)
3100 return active_bitmap;
3102 if (NREV_GE(pi->pubpi.phy_rev, 6)) {
3103 wlapi_suspend_mac_and_wait(pi->sh->physhim);
3104 nphy_currtemp = wlc_phy_tempsense_nphy(pi);
3105 wlapi_enable_mac(pi->sh->physhim);
3107 if (!pi->phy_txcore_heatedup) {
3108 if (nphy_currtemp >= pi->phy_txcore_disable_temp) {
3109 active_bitmap &= 0xFD;
3110 pi->phy_txcore_heatedup = true;
3113 if (nphy_currtemp <= pi->phy_txcore_enable_temp) {
3114 active_bitmap |= 0x2;
3115 pi->phy_txcore_heatedup = false;
3120 return active_bitmap;
3123 s8 wlc_phy_stf_ssmode_get(wlc_phy_t *pih, chanspec_t chanspec)
3125 phy_info_t *pi = (phy_info_t *) pih;
3126 u8 siso_mcs_id, cdd_mcs_id;
3129 (CHSPEC_IS40(chanspec)) ? TXP_FIRST_MCS_40_SISO :
3130 TXP_FIRST_MCS_20_SISO;
3132 (CHSPEC_IS40(chanspec)) ? TXP_FIRST_MCS_40_CDD :
3133 TXP_FIRST_MCS_20_CDD;
3135 if (pi->tx_power_target[siso_mcs_id] >
3136 (pi->tx_power_target[cdd_mcs_id] + 12))
3137 return PHY_TXC1_MODE_SISO;
3139 return PHY_TXC1_MODE_CDD;
3142 const u8 *wlc_phy_get_ofdm_rate_lookup(void)
3144 return ofdm_rate_lookup;
3147 void wlc_lcnphy_epa_switch(phy_info_t *pi, bool mode)
3149 if ((pi->sh->chip == BCM4313_CHIP_ID) &&
3150 (pi->sh->boardflags & BFL_FEM)) {
3153 txant = wlapi_bmac_get_txant(pi->sh->physhim);
3155 mod_phy_reg(pi, 0x44d, (0x1 << 2), (1) << 2);
3157 mod_phy_reg(pi, 0x44c, (0x1 << 2), (1) << 2);
3160 ai_corereg(pi->sh->sih, SI_CC_IDX,
3161 offsetof(chipcregs_t, gpiocontrol), ~0x0,
3163 ai_corereg(pi->sh->sih, SI_CC_IDX,
3164 offsetof(chipcregs_t, gpioout), 0x40, 0x40);
3165 ai_corereg(pi->sh->sih, SI_CC_IDX,
3166 offsetof(chipcregs_t, gpioouten), 0x40,
3169 mod_phy_reg(pi, 0x44c, (0x1 << 2), (0) << 2);
3171 mod_phy_reg(pi, 0x44d, (0x1 << 2), (0) << 2);
3173 ai_corereg(pi->sh->sih, SI_CC_IDX,
3174 offsetof(chipcregs_t, gpioout), 0x40, 0x00);
3175 ai_corereg(pi->sh->sih, SI_CC_IDX,
3176 offsetof(chipcregs_t, gpioouten), 0x40, 0x0);
3177 ai_corereg(pi->sh->sih, SI_CC_IDX,
3178 offsetof(chipcregs_t, gpiocontrol), ~0x0,
3185 wlc_user_txpwr_antport_to_rfport(phy_info_t *pi, uint chan, u32 band,
3190 if (!pi->user_txpwr_at_rfport)
3195 static s8 wlc_phy_env_measure_vbat(phy_info_t *pi)
3198 return wlc_lcnphy_vbatsense(pi, 0);
3203 static s8 wlc_phy_env_measure_temperature(phy_info_t *pi)
3206 return wlc_lcnphy_tempsense_degree(pi, 0);
3211 static void wlc_phy_upd_env_txpwr_rate_limits(phy_info_t *pi, u32 band)
3216 for (i = 0; i < TXP_NUM_RATES; i++)
3217 pi->txpwr_env_limit[i] = WLC_TXPWR_MAX;
3219 vbat = wlc_phy_env_measure_vbat(pi);
3220 temp = wlc_phy_env_measure_temperature(pi);
3224 void wlc_phy_ldpc_override_set(wlc_phy_t *ppi, bool ldpc)
3230 wlc_phy_get_pwrdet_offsets(phy_info_t *pi, s8 *cckoffset, s8 *ofdmoffset)
3236 s8 wlc_phy_upd_rssi_offset(phy_info_t *pi, s8 rssi, chanspec_t chanspec)
3242 bool wlc_phy_txpower_ipa_ison(wlc_phy_t *ppi)
3244 phy_info_t *pi = (phy_info_t *) ppi;
3247 return wlc_phy_n_txpower_ipa_ison(pi);