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>
24 #include <bcmendian.h>
28 #include <wlc_phy_int.h>
29 #include <wlc_phyreg_n.h>
30 #include <wlc_phy_radio.h>
31 #include <wlc_phy_lcn.h>
33 u32 phyhal_msg_level = PHYHAL_ERROR;
35 typedef struct _chan_info_basic {
40 static chan_info_basic_t chan_info_all[] = {
100 u16 ltrn_list[PHY_LTRN_LIST_LEN] = {
101 0x18f9, 0x0d01, 0x00e4, 0xdef4, 0x06f1, 0x0ffc,
102 0xfa27, 0x1dff, 0x10f0, 0x0918, 0xf20a, 0xe010,
103 0x1417, 0x1104, 0xf114, 0xf2fa, 0xf7db, 0xe2fc,
104 0xe1fb, 0x13ee, 0xff0d, 0xe91c, 0x171a, 0x0318,
105 0xda00, 0x03e8, 0x17e6, 0xe9e4, 0xfff3, 0x1312,
106 0xe105, 0xe204, 0xf725, 0xf206, 0xf1ec, 0x11fc,
107 0x14e9, 0xe0f0, 0xf2f6, 0x09e8, 0x1010, 0x1d01,
108 0xfad9, 0x0f04, 0x060f, 0xde0c, 0x001c, 0x0dff,
109 0x1807, 0xf61a, 0xe40e, 0x0f16, 0x05f9, 0x18ec,
110 0x0a1b, 0xff1e, 0x2600, 0xffe2, 0x0ae5, 0x1814,
111 0x0507, 0x0fea, 0xe4f2, 0xf6e6
114 const u8 ofdm_rate_lookup[] = {
126 #define PHY_WREG_LIMIT 24
128 static void wlc_set_phy_uninitted(phy_info_t *pi);
129 static u32 wlc_phy_get_radio_ver(phy_info_t *pi);
130 static void wlc_phy_timercb_phycal(void *arg);
132 static bool wlc_phy_noise_calc_phy(phy_info_t *pi, u32 *cmplx_pwr,
135 static void wlc_phy_cal_perical_mphase_schedule(phy_info_t *pi, uint delay);
136 static void wlc_phy_noise_cb(phy_info_t *pi, u8 channel, s8 noise_dbm);
137 static void wlc_phy_noise_sample_request(wlc_phy_t *pih, u8 reason,
140 static void wlc_phy_txpower_reg_limit_calc(phy_info_t *pi,
141 struct txpwr_limits *tp, chanspec_t);
142 static bool wlc_phy_cal_txpower_recalc_sw(phy_info_t *pi);
144 static s8 wlc_user_txpwr_antport_to_rfport(phy_info_t *pi, uint chan,
146 static void wlc_phy_upd_env_txpwr_rate_limits(phy_info_t *pi, u32 band);
147 static s8 wlc_phy_env_measure_vbat(phy_info_t *pi);
148 static s8 wlc_phy_env_measure_temperature(phy_info_t *pi);
150 char *phy_getvar(phy_info_t *pi, const char *name)
152 char *vars = pi->vars;
156 ASSERT(pi->vars != (char *)&pi->vars);
165 for (s = vars; s && *s;) {
166 if ((bcmp(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->sh->osh, &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;
242 ASSERT(VALID_PHYTYPE(pi->pubpi.phy_type));
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->sh->osh, &pi->regs->radioregaddr, addr);
250 (void)R_REG(pi->sh->osh, &pi->regs->radioregaddr);
252 data = R_REG(pi->sh->osh, &pi->regs->radioregdata);
254 W_REG(pi->sh->osh, &pi->regs->phy4waddr, addr);
256 (void)R_REG(pi->sh->osh, &pi->regs->phy4waddr);
259 #ifdef __ARM_ARCH_4T__
260 __asm__(" .align 4 ");
262 data = R_REG(pi->sh->osh, &pi->regs->phy4wdatalo);
264 data = R_REG(pi->sh->osh, &pi->regs->phy4wdatalo);
273 void write_radio_reg(phy_info_t *pi, u16 addr, u16 val)
277 if (NORADIO_ENAB(pi->pubpi))
282 if ((D11REV_GE(pi->sh->corerev, 24)) ||
283 (D11REV_IS(pi->sh->corerev, 22)
284 && (pi->pubpi.phy_type != PHY_TYPE_SSN))) {
286 W_REG(osh, &pi->regs->radioregaddr, addr);
288 (void)R_REG(osh, &pi->regs->radioregaddr);
290 W_REG(osh, &pi->regs->radioregdata, val);
292 W_REG(osh, &pi->regs->phy4waddr, addr);
294 (void)R_REG(osh, &pi->regs->phy4waddr);
296 W_REG(osh, &pi->regs->phy4wdatalo, val);
299 if (BUSTYPE(pi->sh->bustype) == PCI_BUS) {
300 if (++pi->phy_wreg >= pi->phy_wreg_limit) {
301 (void)R_REG(osh, &pi->regs->maccontrol);
307 static u32 read_radio_id(phy_info_t *pi)
311 if (NORADIO_ENAB(pi->pubpi))
312 return NORADIO_IDCODE;
314 if (D11REV_GE(pi->sh->corerev, 24)) {
317 W_REG(pi->sh->osh, &pi->regs->radioregaddr, 0);
319 (void)R_REG(pi->sh->osh, &pi->regs->radioregaddr);
321 b0 = (u32) R_REG(pi->sh->osh, &pi->regs->radioregdata);
322 W_REG(pi->sh->osh, &pi->regs->radioregaddr, 1);
324 (void)R_REG(pi->sh->osh, &pi->regs->radioregaddr);
326 b1 = (u32) R_REG(pi->sh->osh, &pi->regs->radioregdata);
327 W_REG(pi->sh->osh, &pi->regs->radioregaddr, 2);
329 (void)R_REG(pi->sh->osh, &pi->regs->radioregaddr);
331 b2 = (u32) R_REG(pi->sh->osh, &pi->regs->radioregdata);
333 id = ((b0 & 0xf) << 28) | (((b2 << 8) | b1) << 12) | ((b0 >> 4)
336 W_REG(pi->sh->osh, &pi->regs->phy4waddr, RADIO_IDCODE);
338 (void)R_REG(pi->sh->osh, &pi->regs->phy4waddr);
340 id = (u32) R_REG(pi->sh->osh, &pi->regs->phy4wdatalo);
341 id |= (u32) R_REG(pi->sh->osh, &pi->regs->phy4wdatahi) << 16;
347 void and_radio_reg(phy_info_t *pi, u16 addr, u16 val)
351 if (NORADIO_ENAB(pi->pubpi))
354 rval = read_radio_reg(pi, addr);
355 write_radio_reg(pi, addr, (rval & val));
358 void or_radio_reg(phy_info_t *pi, u16 addr, u16 val)
362 if (NORADIO_ENAB(pi->pubpi))
365 rval = read_radio_reg(pi, addr);
366 write_radio_reg(pi, addr, (rval | val));
369 void xor_radio_reg(phy_info_t *pi, u16 addr, u16 mask)
373 if (NORADIO_ENAB(pi->pubpi))
376 rval = read_radio_reg(pi, addr);
377 write_radio_reg(pi, addr, (rval ^ mask));
380 void mod_radio_reg(phy_info_t *pi, u16 addr, u16 mask, u16 val)
384 if (NORADIO_ENAB(pi->pubpi))
387 rval = read_radio_reg(pi, addr);
388 write_radio_reg(pi, addr, (rval & ~mask) | (val & mask));
391 void write_phy_channel_reg(phy_info_t *pi, uint val)
393 W_REG(pi->sh->osh, &pi->regs->phychannel, val);
397 static bool wlc_phy_war41476(phy_info_t *pi)
399 u32 mc = R_REG(pi->sh->osh, &pi->regs->maccontrol);
401 return ((mc & MCTL_EN_MAC) == 0)
402 || ((mc & MCTL_PHYLOCK) == MCTL_PHYLOCK);
406 u16 read_phy_reg(phy_info_t *pi, u16 addr)
414 W_REG(osh, ®s->phyregaddr, addr);
416 (void)R_REG(osh, ®s->phyregaddr);
420 (D11REV_IS(pi->sh->corerev, 11)
421 || D11REV_IS(pi->sh->corerev, 12)) || wlc_phy_war41476(pi));
424 return R_REG(osh, ®s->phyregdata);
427 void write_phy_reg(phy_info_t *pi, u16 addr, u16 val)
436 W_REG(osh, ®s->phyregaddr, addr);
437 (void)R_REG(osh, ®s->phyregaddr);
438 W_REG(osh, ®s->phyregdata, val);
440 (void)R_REG(osh, ®s->phyregdata);
442 W_REG(osh, (volatile u32 *)(®s->phyregaddr),
444 if (BUSTYPE(pi->sh->bustype) == PCI_BUS) {
445 if (++pi->phy_wreg >= pi->phy_wreg_limit) {
447 (void)R_REG(osh, ®s->phyversion);
453 void and_phy_reg(phy_info_t *pi, u16 addr, u16 val)
461 W_REG(osh, ®s->phyregaddr, addr);
463 (void)R_REG(osh, ®s->phyregaddr);
467 (D11REV_IS(pi->sh->corerev, 11)
468 || D11REV_IS(pi->sh->corerev, 12)) || wlc_phy_war41476(pi));
470 W_REG(osh, ®s->phyregdata, (R_REG(osh, ®s->phyregdata) & val));
474 void or_phy_reg(phy_info_t *pi, u16 addr, u16 val)
482 W_REG(osh, ®s->phyregaddr, addr);
484 (void)R_REG(osh, ®s->phyregaddr);
488 (D11REV_IS(pi->sh->corerev, 11)
489 || D11REV_IS(pi->sh->corerev, 12)) || wlc_phy_war41476(pi));
491 W_REG(osh, ®s->phyregdata, (R_REG(osh, ®s->phyregdata) | val));
495 void mod_phy_reg(phy_info_t *pi, u16 addr, u16 mask, u16 val)
503 W_REG(osh, ®s->phyregaddr, addr);
505 (void)R_REG(osh, ®s->phyregaddr);
509 (D11REV_IS(pi->sh->corerev, 11)
510 || D11REV_IS(pi->sh->corerev, 12)) || wlc_phy_war41476(pi));
512 W_REG(osh, ®s->phyregdata,
513 ((R_REG(osh, ®s->phyregdata) & ~mask) | (val & mask)));
517 static void WLBANDINITFN(wlc_set_phy_uninitted) (phy_info_t *pi)
521 pi->initialized = false;
524 pi->nrssi_table_delta = 0x7fffffff;
526 pi->mintxbias = 0xffff;
529 pi->phy_spuravoid = SPURAVOID_DISABLE;
531 if (NREV_GE(pi->pubpi.phy_rev, 3)
532 && NREV_LT(pi->pubpi.phy_rev, 7))
533 pi->phy_spuravoid = SPURAVOID_AUTO;
535 pi->nphy_papd_skip = 0;
536 pi->nphy_papd_epsilon_offset[0] = 0xf588;
537 pi->nphy_papd_epsilon_offset[1] = 0xf588;
538 pi->nphy_txpwr_idx[0] = 128;
539 pi->nphy_txpwr_idx[1] = 128;
540 pi->nphy_txpwrindex[0].index_internal = 40;
541 pi->nphy_txpwrindex[1].index_internal = 40;
544 pi->phy_spuravoid = SPURAVOID_AUTO;
546 pi->radiopwr = 0xffff;
547 for (i = 0; i < STATIC_NUM_RF; i++) {
548 for (j = 0; j < STATIC_NUM_BB; j++) {
549 pi->stats_11b_txpower[i][j] = -1;
554 shared_phy_t *wlc_phy_shared_attach(shared_phy_params_t *shp)
558 sh = kzalloc(sizeof(shared_phy_t), GFP_ATOMIC);
565 sh->physhim = shp->physhim;
566 sh->unit = shp->unit;
567 sh->corerev = shp->corerev;
571 sh->chip = shp->chip;
572 sh->chiprev = shp->chiprev;
573 sh->chippkg = shp->chippkg;
574 sh->sromrev = shp->sromrev;
575 sh->boardtype = shp->boardtype;
576 sh->boardrev = shp->boardrev;
577 sh->boardvendor = shp->boardvendor;
578 sh->boardflags = shp->boardflags;
579 sh->boardflags2 = shp->boardflags2;
580 sh->bustype = shp->bustype;
581 sh->buscorerev = shp->buscorerev;
583 sh->fast_timer = PHY_SW_TIMER_FAST;
584 sh->slow_timer = PHY_SW_TIMER_SLOW;
585 sh->glacial_timer = PHY_SW_TIMER_GLACIAL;
587 sh->rssi_mode = RSSI_ANT_MERGE_MAX;
592 void wlc_phy_shared_detach(shared_phy_t *phy_sh)
599 if (phy_sh->phy_head) {
600 ASSERT(!phy_sh->phy_head);
606 wlc_phy_t *wlc_phy_attach(shared_phy_t *sh, void *regs, int bandtype, char *vars)
616 if (D11REV_IS(sh->corerev, 4))
617 sflags = SISF_2G_PHY | SISF_5G_PHY;
619 sflags = si_core_sflags(sh->sih, 0, 0);
621 if (BAND_5G(bandtype)) {
622 if ((sflags & (SISF_5G_PHY | SISF_DB_PHY)) == 0) {
628 if ((sflags & SISF_DB_PHY) && pi) {
630 wlapi_bmac_corereset(pi->sh->physhim, pi->pubpi.coreflags);
632 return &pi->pubpi_ro;
635 pi = kzalloc(sizeof(phy_info_t), GFP_ATOMIC);
639 pi->regs = (d11regs_t *) regs;
641 pi->phy_init_por = true;
642 pi->phy_wreg_limit = PHY_WREG_LIMIT;
646 pi->txpwr_percent = 100;
648 pi->do_initcal = true;
650 pi->phycal_tempdelta = 0;
652 if (BAND_2G(bandtype) && (sflags & SISF_2G_PHY)) {
654 pi->pubpi.coreflags = SICF_GMODE;
657 wlapi_bmac_corereset(pi->sh->physhim, pi->pubpi.coreflags);
658 phyversion = R_REG(osh, &pi->regs->phyversion);
660 pi->pubpi.phy_type = PHY_TYPE(phyversion);
661 pi->pubpi.phy_rev = phyversion & PV_PV_MASK;
663 if (pi->pubpi.phy_type == PHY_TYPE_LCNXN) {
664 pi->pubpi.phy_type = PHY_TYPE_N;
665 pi->pubpi.phy_rev += LCNXN_BASEREV;
667 pi->pubpi.phy_corenum = PHY_CORE_NUM_2;
668 pi->pubpi.ana_rev = (phyversion & PV_AV_MASK) >> PV_AV_SHIFT;
670 if (!VALID_PHYTYPE(pi->pubpi.phy_type)) {
673 if (BAND_5G(bandtype)) {
678 if (!ISNPHY(pi) && !ISLCNPHY(pi)) {
683 if (ISSIM_ENAB(pi->sh->sih)) {
684 pi->pubpi.radioid = NORADIO_ID;
685 pi->pubpi.radiorev = 5;
689 wlc_phy_anacore((wlc_phy_t *) pi, ON);
691 idcode = wlc_phy_get_radio_ver(pi);
693 (idcode & IDCODE_ID_MASK) >> IDCODE_ID_SHIFT;
695 (idcode & IDCODE_REV_MASK) >> IDCODE_REV_SHIFT;
697 (idcode & IDCODE_VER_MASK) >> IDCODE_VER_SHIFT;
698 if (!VALID_RADIO(pi, pi->pubpi.radioid)) {
702 wlc_phy_switch_radio((wlc_phy_t *) pi, OFF);
705 wlc_set_phy_uninitted(pi);
707 pi->bw = WL_CHANSPEC_BW_20;
709 BAND_2G(bandtype) ? CH20MHZ_CHSPEC(1) : CH20MHZ_CHSPEC(36);
711 pi->rxiq_samps = PHY_NOISE_SAMPLE_LOG_NUM_NPHY;
712 pi->rxiq_antsel = ANT_RX_DIV_DEF;
714 pi->watchdog_override = true;
716 pi->cal_type_override = PHY_PERICAL_AUTO;
718 pi->nphy_saved_noisevars.bufcount = 0;
721 pi->min_txpower = PHY_TXPWR_MIN_NPHY;
723 pi->min_txpower = PHY_TXPWR_MIN;
725 pi->sh->phyrxchain = 0x3;
727 pi->rx2tx_biasentry = -1;
729 pi->phy_txcore_disable_temp = PHY_CHAIN_TX_DISABLE_TEMP;
730 pi->phy_txcore_enable_temp =
731 PHY_CHAIN_TX_DISABLE_TEMP - PHY_HYSTERESIS_DELTATEMP;
732 pi->phy_tempsense_offset = 0;
733 pi->phy_txcore_heatedup = false;
735 pi->nphy_lastcal_temp = -50;
737 pi->phynoise_polling = true;
738 if (ISNPHY(pi) || ISLCNPHY(pi))
739 pi->phynoise_polling = false;
741 for (i = 0; i < TXP_NUM_RATES; i++) {
742 pi->txpwr_limit[i] = WLC_TXPWR_MAX;
743 pi->txpwr_env_limit[i] = WLC_TXPWR_MAX;
744 pi->tx_user_target[i] = WLC_TXPWR_MAX;
747 pi->radiopwr_override = RADIOPWR_OVERRIDE_DEF;
749 pi->user_txpwr_at_rfport = false;
753 pi->phycal_timer = wlapi_init_timer(pi->sh->physhim,
754 wlc_phy_timercb_phycal,
756 if (!pi->phycal_timer) {
760 if (!wlc_phy_attach_nphy(pi))
763 } else if (ISLCNPHY(pi)) {
764 if (!wlc_phy_attach_lcnphy(pi))
772 pi->next = pi->sh->phy_head;
775 pi->vars = (char *)&pi->vars;
777 bcopy(&pi->pubpi, &pi->pubpi_ro, sizeof(wlc_phy_t));
779 return &pi->pubpi_ro;
787 void wlc_phy_detach(wlc_phy_t *pih)
789 phy_info_t *pi = (phy_info_t *) pih;
796 if (pi->phycal_timer) {
797 wlapi_free_timer(pi->sh->physhim, pi->phycal_timer);
798 pi->phycal_timer = NULL;
801 if (pi->sh->phy_head == pi)
802 pi->sh->phy_head = pi->next;
803 else if (pi->sh->phy_head->next == pi)
804 pi->sh->phy_head->next = NULL;
808 if (pi->pi_fptr.detach)
809 (pi->pi_fptr.detach) (pi);
816 wlc_phy_get_phyversion(wlc_phy_t *pih, u16 *phytype, u16 *phyrev,
817 u16 *radioid, u16 *radiover)
819 phy_info_t *pi = (phy_info_t *) pih;
820 *phytype = (u16) pi->pubpi.phy_type;
821 *phyrev = (u16) pi->pubpi.phy_rev;
822 *radioid = pi->pubpi.radioid;
823 *radiover = pi->pubpi.radiorev;
828 bool wlc_phy_get_encore(wlc_phy_t *pih)
830 phy_info_t *pi = (phy_info_t *) pih;
831 return pi->pubpi.abgphy_encore;
834 u32 wlc_phy_get_coreflags(wlc_phy_t *pih)
836 phy_info_t *pi = (phy_info_t *) pih;
837 return pi->pubpi.coreflags;
840 static void wlc_phy_timercb_phycal(void *arg)
842 phy_info_t *pi = (phy_info_t *) arg;
845 if (PHY_PERICAL_MPHASE_PENDING(pi)) {
847 wlc_phy_cal_perical_mphase_reset(pi);
851 if (SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi)) {
854 wlc_phy_cal_perical_mphase_restart(pi);
856 wlc_phy_cal_perical_nphy_run(pi, PHY_PERICAL_AUTO);
857 wlapi_add_timer(pi->sh->physhim, pi->phycal_timer, delay, 0);
863 void wlc_phy_anacore(wlc_phy_t *pih, bool on)
865 phy_info_t *pi = (phy_info_t *) pih;
869 if (NREV_GE(pi->pubpi.phy_rev, 3)) {
870 write_phy_reg(pi, 0xa6, 0x0d);
871 write_phy_reg(pi, 0x8f, 0x0);
872 write_phy_reg(pi, 0xa7, 0x0d);
873 write_phy_reg(pi, 0xa5, 0x0);
875 write_phy_reg(pi, 0xa5, 0x0);
878 if (NREV_GE(pi->pubpi.phy_rev, 3)) {
879 write_phy_reg(pi, 0x8f, 0x07ff);
880 write_phy_reg(pi, 0xa6, 0x0fd);
881 write_phy_reg(pi, 0xa5, 0x07ff);
882 write_phy_reg(pi, 0xa7, 0x0fd);
884 write_phy_reg(pi, 0xa5, 0x7fff);
887 } else if (ISLCNPHY(pi)) {
889 and_phy_reg(pi, 0x43b,
890 ~((0x1 << 0) | (0x1 << 1) | (0x1 << 2)));
892 or_phy_reg(pi, 0x43c,
893 (0x1 << 0) | (0x1 << 1) | (0x1 << 2));
894 or_phy_reg(pi, 0x43b,
895 (0x1 << 0) | (0x1 << 1) | (0x1 << 2));
900 u32 wlc_phy_clk_bwbits(wlc_phy_t *pih)
902 phy_info_t *pi = (phy_info_t *) pih;
904 u32 phy_bw_clkbits = 0;
906 if (pi && (ISNPHY(pi) || ISLCNPHY(pi))) {
908 case WL_CHANSPEC_BW_10:
909 phy_bw_clkbits = SICF_BW10;
911 case WL_CHANSPEC_BW_20:
912 phy_bw_clkbits = SICF_BW20;
914 case WL_CHANSPEC_BW_40:
915 phy_bw_clkbits = SICF_BW40;
923 return phy_bw_clkbits;
926 void WLBANDINITFN(wlc_phy_por_inform) (wlc_phy_t *ppi)
928 phy_info_t *pi = (phy_info_t *) ppi;
930 pi->phy_init_por = true;
933 void wlc_phy_edcrs_lock(wlc_phy_t *pih, bool lock)
935 phy_info_t *pi = (phy_info_t *) pih;
937 pi->edcrs_threshold_lock = lock;
939 write_phy_reg(pi, 0x22c, 0x46b);
940 write_phy_reg(pi, 0x22d, 0x46b);
941 write_phy_reg(pi, 0x22e, 0x3c0);
942 write_phy_reg(pi, 0x22f, 0x3c0);
945 void wlc_phy_initcal_enable(wlc_phy_t *pih, bool initcal)
947 phy_info_t *pi = (phy_info_t *) pih;
949 pi->do_initcal = initcal;
952 void wlc_phy_hw_clk_state_upd(wlc_phy_t *pih, bool newstate)
954 phy_info_t *pi = (phy_info_t *) pih;
959 pi->sh->clk = newstate;
962 void wlc_phy_hw_state_upd(wlc_phy_t *pih, bool newstate)
964 phy_info_t *pi = (phy_info_t *) pih;
969 pi->sh->up = newstate;
972 void WLBANDINITFN(wlc_phy_init) (wlc_phy_t *pih, chanspec_t chanspec)
975 initfn_t phy_init = NULL;
976 phy_info_t *pi = (phy_info_t *) pih;
978 if (pi->init_in_progress)
981 pi->init_in_progress = true;
983 pi->radio_chanspec = chanspec;
985 mc = R_REG(pi->sh->osh, &pi->regs->maccontrol);
986 if ((mc & MCTL_EN_MAC) != 0) {
987 ASSERT((const char *)
988 "wlc_phy_init: Called with the MAC running!" == NULL);
993 if (!(pi->measure_hold & PHY_HOLD_FOR_SCAN)) {
994 pi->measure_hold |= PHY_HOLD_FOR_NOT_ASSOC;
997 if (D11REV_GE(pi->sh->corerev, 5))
998 ASSERT(si_core_sflags(pi->sh->sih, 0, 0) & SISF_FCLKA);
1000 phy_init = pi->pi_fptr.init;
1002 if (phy_init == NULL) {
1003 ASSERT(phy_init != NULL);
1007 wlc_phy_anacore(pih, ON);
1009 if (CHSPEC_BW(pi->radio_chanspec) != pi->bw)
1010 wlapi_bmac_bw_set(pi->sh->physhim,
1011 CHSPEC_BW(pi->radio_chanspec));
1013 pi->nphy_gain_boost = true;
1015 wlc_phy_switch_radio((wlc_phy_t *) pi, ON);
1019 pi->phy_init_por = false;
1021 if (D11REV_IS(pi->sh->corerev, 11) || D11REV_IS(pi->sh->corerev, 12))
1022 wlc_phy_do_dummy_tx(pi, true, OFF);
1025 wlc_phy_txpower_update_shm(pi);
1027 wlc_phy_ant_rxdiv_set((wlc_phy_t *) pi, pi->sh->rx_antdiv);
1029 pi->init_in_progress = false;
1032 void wlc_phy_cal_init(wlc_phy_t *pih)
1034 phy_info_t *pi = (phy_info_t *) pih;
1035 initfn_t cal_init = NULL;
1037 ASSERT((R_REG(pi->sh->osh, &pi->regs->maccontrol) & MCTL_EN_MAC) == 0);
1039 if (!pi->initialized) {
1040 cal_init = pi->pi_fptr.calinit;
1044 pi->initialized = true;
1048 int wlc_phy_down(wlc_phy_t *pih)
1050 phy_info_t *pi = (phy_info_t *) pih;
1053 ASSERT(pi->phytest_on == false);
1055 if (pi->phycal_timer
1056 && !wlapi_del_timer(pi->sh->physhim, pi->phycal_timer))
1059 pi->nphy_iqcal_chanspec_2G = 0;
1060 pi->nphy_iqcal_chanspec_5G = 0;
1065 static u32 wlc_phy_get_radio_ver(phy_info_t *pi)
1069 ver = read_radio_id(pi);
1075 wlc_phy_table_addr(phy_info_t *pi, uint tbl_id, uint tbl_offset,
1076 u16 tblAddr, u16 tblDataHi, u16 tblDataLo)
1078 write_phy_reg(pi, tblAddr, (tbl_id << 10) | tbl_offset);
1080 pi->tbl_data_hi = tblDataHi;
1081 pi->tbl_data_lo = tblDataLo;
1083 if ((CHIPID(pi->sh->chip) == BCM43224_CHIP_ID ||
1084 CHIPID(pi->sh->chip) == BCM43421_CHIP_ID) &&
1085 (pi->sh->chiprev == 1)) {
1086 pi->tbl_addr = tblAddr;
1087 pi->tbl_save_id = tbl_id;
1088 pi->tbl_save_offset = tbl_offset;
1092 void wlc_phy_table_data_write(phy_info_t *pi, uint width, u32 val)
1094 ASSERT((width == 8) || (width == 16) || (width == 32));
1096 if ((CHIPID(pi->sh->chip) == BCM43224_CHIP_ID ||
1097 CHIPID(pi->sh->chip) == BCM43421_CHIP_ID) &&
1098 (pi->sh->chiprev == 1) &&
1099 (pi->tbl_save_id == NPHY_TBL_ID_ANTSWCTRLLUT)) {
1100 read_phy_reg(pi, pi->tbl_data_lo);
1102 write_phy_reg(pi, pi->tbl_addr,
1103 (pi->tbl_save_id << 10) | pi->tbl_save_offset);
1104 pi->tbl_save_offset++;
1109 write_phy_reg(pi, pi->tbl_data_hi, (u16) (val >> 16));
1110 write_phy_reg(pi, pi->tbl_data_lo, (u16) val);
1113 write_phy_reg(pi, pi->tbl_data_lo, (u16) val);
1118 wlc_phy_write_table(phy_info_t *pi, const phytbl_info_t *ptbl_info,
1119 u16 tblAddr, u16 tblDataHi, u16 tblDataLo)
1122 uint tbl_id = ptbl_info->tbl_id;
1123 uint tbl_offset = ptbl_info->tbl_offset;
1124 uint tbl_width = ptbl_info->tbl_width;
1125 const u8 *ptbl_8b = (const u8 *)ptbl_info->tbl_ptr;
1126 const u16 *ptbl_16b = (const u16 *)ptbl_info->tbl_ptr;
1127 const u32 *ptbl_32b = (const u32 *)ptbl_info->tbl_ptr;
1129 ASSERT((tbl_width == 8) || (tbl_width == 16) || (tbl_width == 32));
1131 write_phy_reg(pi, tblAddr, (tbl_id << 10) | tbl_offset);
1133 for (idx = 0; idx < ptbl_info->tbl_len; idx++) {
1135 if ((CHIPID(pi->sh->chip) == BCM43224_CHIP_ID ||
1136 CHIPID(pi->sh->chip) == BCM43421_CHIP_ID) &&
1137 (pi->sh->chiprev == 1) &&
1138 (tbl_id == NPHY_TBL_ID_ANTSWCTRLLUT)) {
1139 read_phy_reg(pi, tblDataLo);
1141 write_phy_reg(pi, tblAddr,
1142 (tbl_id << 10) | (tbl_offset + idx));
1145 if (tbl_width == 32) {
1147 write_phy_reg(pi, tblDataHi,
1148 (u16) (ptbl_32b[idx] >> 16));
1149 write_phy_reg(pi, tblDataLo, (u16) ptbl_32b[idx]);
1150 } else if (tbl_width == 16) {
1152 write_phy_reg(pi, tblDataLo, ptbl_16b[idx]);
1155 write_phy_reg(pi, tblDataLo, ptbl_8b[idx]);
1161 wlc_phy_read_table(phy_info_t *pi, const phytbl_info_t *ptbl_info,
1162 u16 tblAddr, u16 tblDataHi, u16 tblDataLo)
1165 uint tbl_id = ptbl_info->tbl_id;
1166 uint tbl_offset = ptbl_info->tbl_offset;
1167 uint tbl_width = ptbl_info->tbl_width;
1168 u8 *ptbl_8b = (u8 *)ptbl_info->tbl_ptr;
1169 u16 *ptbl_16b = (u16 *)ptbl_info->tbl_ptr;
1170 u32 *ptbl_32b = (u32 *)ptbl_info->tbl_ptr;
1172 ASSERT((tbl_width == 8) || (tbl_width == 16) || (tbl_width == 32));
1174 write_phy_reg(pi, tblAddr, (tbl_id << 10) | tbl_offset);
1176 for (idx = 0; idx < ptbl_info->tbl_len; idx++) {
1178 if ((CHIPID(pi->sh->chip) == BCM43224_CHIP_ID ||
1179 CHIPID(pi->sh->chip) == BCM43421_CHIP_ID) &&
1180 (pi->sh->chiprev == 1)) {
1181 (void)read_phy_reg(pi, tblDataLo);
1183 write_phy_reg(pi, tblAddr,
1184 (tbl_id << 10) | (tbl_offset + idx));
1187 if (tbl_width == 32) {
1189 ptbl_32b[idx] = read_phy_reg(pi, tblDataLo);
1190 ptbl_32b[idx] |= (read_phy_reg(pi, tblDataHi) << 16);
1191 } else if (tbl_width == 16) {
1193 ptbl_16b[idx] = read_phy_reg(pi, tblDataLo);
1196 ptbl_8b[idx] = (u8) read_phy_reg(pi, tblDataLo);
1202 wlc_phy_init_radio_regs_allbands(phy_info_t *pi, radio_20xx_regs_t *radioregs)
1207 if (radioregs[i].do_init) {
1208 write_radio_reg(pi, radioregs[i].address,
1209 (u16) radioregs[i].init);
1213 } while (radioregs[i].address != 0xffff);
1219 wlc_phy_init_radio_regs(phy_info_t *pi, radio_regs_t *radioregs,
1226 if (CHSPEC_IS5G(pi->radio_chanspec)) {
1227 if (radioregs[i].do_init_a) {
1230 address | core_offset,
1231 (u16) radioregs[i].init_a);
1232 if (ISNPHY(pi) && (++count % 4 == 0))
1233 WLC_PHY_WAR_PR51571(pi);
1236 if (radioregs[i].do_init_g) {
1239 address | core_offset,
1240 (u16) radioregs[i].init_g);
1241 if (ISNPHY(pi) && (++count % 4 == 0))
1242 WLC_PHY_WAR_PR51571(pi);
1247 } while (radioregs[i].address != 0xffff);
1252 void wlc_phy_do_dummy_tx(phy_info_t *pi, bool ofdm, bool pa_on)
1254 #define DUMMY_PKT_LEN 20
1255 d11regs_t *regs = pi->regs;
1257 u8 ofdmpkt[DUMMY_PKT_LEN] = {
1258 0xcc, 0x01, 0x02, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00,
1259 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00
1261 u8 cckpkt[DUMMY_PKT_LEN] = {
1262 0x6e, 0x84, 0x0b, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00,
1263 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00
1267 ASSERT((R_REG(pi->sh->osh, &pi->regs->maccontrol) & MCTL_EN_MAC) == 0);
1269 dummypkt = (u32 *) (ofdm ? ofdmpkt : cckpkt);
1270 wlapi_bmac_write_template_ram(pi->sh->physhim, 0, DUMMY_PKT_LEN,
1273 W_REG(pi->sh->osh, ®s->xmtsel, 0);
1275 if (D11REV_GE(pi->sh->corerev, 11))
1276 W_REG(pi->sh->osh, ®s->wepctl, 0x100);
1278 W_REG(pi->sh->osh, ®s->wepctl, 0);
1280 W_REG(pi->sh->osh, ®s->txe_phyctl, (ofdm ? 1 : 0) | PHY_TXC_ANT_0);
1281 if (ISNPHY(pi) || ISLCNPHY(pi)) {
1283 W_REG(pi->sh->osh, ®s->txe_phyctl1, 0x1A02);
1286 W_REG(pi->sh->osh, ®s->txe_wm_0, 0);
1287 W_REG(pi->sh->osh, ®s->txe_wm_1, 0);
1289 W_REG(pi->sh->osh, ®s->xmttplatetxptr, 0);
1290 W_REG(pi->sh->osh, ®s->xmttxcnt, DUMMY_PKT_LEN);
1292 W_REG(pi->sh->osh, ®s->xmtsel, ((8 << 8) | (1 << 5) | (1 << 2) | 2));
1294 W_REG(pi->sh->osh, ®s->txe_ctl, 0);
1298 wlc_phy_pa_override_nphy(pi, OFF);
1301 if (ISNPHY(pi) || ISLCNPHY(pi))
1302 W_REG(pi->sh->osh, ®s->txe_aux, 0xD0);
1304 W_REG(pi->sh->osh, ®s->txe_aux, ((1 << 5) | (1 << 4)));
1306 (void)R_REG(pi->sh->osh, ®s->txe_aux);
1309 count = ofdm ? 30 : 250;
1311 if (ISSIM_ENAB(pi->sh->sih)) {
1315 while ((i++ < count)
1316 && (R_REG(pi->sh->osh, ®s->txe_status) & (1 << 7))) {
1323 && ((R_REG(pi->sh->osh, ®s->txe_status) & (1 << 10)) == 0)) {
1329 while ((i++ < 10) && ((R_REG(pi->sh->osh, ®s->ifsstat) & (1 << 8)))) {
1334 wlc_phy_pa_override_nphy(pi, ON);
1338 void wlc_phy_hold_upd(wlc_phy_t *pih, mbool id, bool set)
1340 phy_info_t *pi = (phy_info_t *) pih;
1344 mboolset(pi->measure_hold, id);
1346 mboolclr(pi->measure_hold, id);
1352 void wlc_phy_mute_upd(wlc_phy_t *pih, bool mute, mbool flags)
1354 phy_info_t *pi = (phy_info_t *) pih;
1357 mboolset(pi->measure_hold, PHY_HOLD_FOR_MUTE);
1359 mboolclr(pi->measure_hold, PHY_HOLD_FOR_MUTE);
1362 if (!mute && (flags & PHY_MUTE_FOR_PREISM))
1363 pi->nphy_perical_last = pi->sh->now - pi->sh->glacial_timer;
1367 void wlc_phy_clear_tssi(wlc_phy_t *pih)
1369 phy_info_t *pi = (phy_info_t *) pih;
1374 wlapi_bmac_write_shm(pi->sh->physhim, M_B_TSSI_0, NULL_TSSI_W);
1375 wlapi_bmac_write_shm(pi->sh->physhim, M_B_TSSI_1, NULL_TSSI_W);
1376 wlapi_bmac_write_shm(pi->sh->physhim, M_G_TSSI_0, NULL_TSSI_W);
1377 wlapi_bmac_write_shm(pi->sh->physhim, M_G_TSSI_1, NULL_TSSI_W);
1381 static bool wlc_phy_cal_txpower_recalc_sw(phy_info_t *pi)
1386 void wlc_phy_switch_radio(wlc_phy_t *pih, bool on)
1388 phy_info_t *pi = (phy_info_t *) pih;
1390 if (NORADIO_ENAB(pi->pubpi))
1396 mc = R_REG(pi->sh->osh, &pi->regs->maccontrol);
1400 wlc_phy_switch_radio_nphy(pi, on);
1402 } else if (ISLCNPHY(pi)) {
1404 and_phy_reg(pi, 0x44c,
1407 (0x1 << 10) | (0x1 << 11) | (0x1 << 12)));
1408 and_phy_reg(pi, 0x4b0, ~((0x1 << 3) | (0x1 << 11)));
1409 and_phy_reg(pi, 0x4f9, ~(0x1 << 3));
1411 and_phy_reg(pi, 0x44d,
1414 (0x1 << 12) | (0x1 << 13) | (0x1 << 14)));
1415 or_phy_reg(pi, 0x44c,
1418 (0x1 << 10) | (0x1 << 11) | (0x1 << 12));
1420 and_phy_reg(pi, 0x4b7, ~((0x7f << 8)));
1421 and_phy_reg(pi, 0x4b1, ~((0x1 << 13)));
1422 or_phy_reg(pi, 0x4b0, (0x1 << 3) | (0x1 << 11));
1423 and_phy_reg(pi, 0x4fa, ~((0x1 << 3)));
1424 or_phy_reg(pi, 0x4f9, (0x1 << 3));
1429 u16 wlc_phy_bw_state_get(wlc_phy_t *ppi)
1431 phy_info_t *pi = (phy_info_t *) ppi;
1436 void wlc_phy_bw_state_set(wlc_phy_t *ppi, u16 bw)
1438 phy_info_t *pi = (phy_info_t *) ppi;
1443 void wlc_phy_chanspec_radio_set(wlc_phy_t *ppi, chanspec_t newch)
1445 phy_info_t *pi = (phy_info_t *) ppi;
1446 pi->radio_chanspec = newch;
1450 chanspec_t wlc_phy_chanspec_get(wlc_phy_t *ppi)
1452 phy_info_t *pi = (phy_info_t *) ppi;
1454 return pi->radio_chanspec;
1457 void wlc_phy_chanspec_set(wlc_phy_t *ppi, chanspec_t chanspec)
1459 phy_info_t *pi = (phy_info_t *) ppi;
1461 chansetfn_t chanspec_set = NULL;
1463 ASSERT(!wf_chspec_malformed(chanspec));
1465 m_cur_channel = CHSPEC_CHANNEL(chanspec);
1466 if (CHSPEC_IS5G(chanspec))
1467 m_cur_channel |= D11_CURCHANNEL_5G;
1468 if (CHSPEC_IS40(chanspec))
1469 m_cur_channel |= D11_CURCHANNEL_40;
1470 wlapi_bmac_write_shm(pi->sh->physhim, M_CURCHANNEL, m_cur_channel);
1472 chanspec_set = pi->pi_fptr.chanset;
1474 (*chanspec_set) (pi, chanspec);
1478 int wlc_phy_chanspec_freq2bandrange_lpssn(uint freq)
1483 range = WL_CHAN_FREQ_RANGE_2G;
1484 else if (freq <= 5320)
1485 range = WL_CHAN_FREQ_RANGE_5GL;
1486 else if (freq <= 5700)
1487 range = WL_CHAN_FREQ_RANGE_5GM;
1489 range = WL_CHAN_FREQ_RANGE_5GH;
1494 int wlc_phy_chanspec_bandrange_get(phy_info_t *pi, chanspec_t chanspec)
1497 uint channel = CHSPEC_CHANNEL(chanspec);
1498 uint freq = wlc_phy_channel2freq(channel);
1501 range = wlc_phy_get_chan_freq_range_nphy(pi, channel);
1502 } else if (ISLCNPHY(pi)) {
1503 range = wlc_phy_chanspec_freq2bandrange_lpssn(freq);
1510 void wlc_phy_chanspec_ch14_widefilter_set(wlc_phy_t *ppi, bool wide_filter)
1512 phy_info_t *pi = (phy_info_t *) ppi;
1514 pi->channel_14_wide_filter = wide_filter;
1518 int wlc_phy_channel2freq(uint channel)
1522 for (i = 0; i < ARRAY_SIZE(chan_info_all); i++)
1523 if (chan_info_all[i].chan == channel)
1524 return chan_info_all[i].freq;
1529 wlc_phy_chanspec_band_validch(wlc_phy_t *ppi, uint band, chanvec_t *channels)
1531 phy_info_t *pi = (phy_info_t *) ppi;
1535 ASSERT((band == WLC_BAND_2G) || (band == WLC_BAND_5G));
1537 bzero(channels, sizeof(chanvec_t));
1539 for (i = 0; i < ARRAY_SIZE(chan_info_all); i++) {
1540 channel = chan_info_all[i].chan;
1542 if ((pi->a_band_high_disable) && (channel >= FIRST_REF5_CHANNUM)
1543 && (channel <= LAST_REF5_CHANNUM))
1546 if (((band == WLC_BAND_2G) && (channel <= CH_MAX_2G_CHANNEL)) ||
1547 ((band == WLC_BAND_5G) && (channel > CH_MAX_2G_CHANNEL)))
1548 setbit(channels->vec, channel);
1552 chanspec_t wlc_phy_chanspec_band_firstch(wlc_phy_t *ppi, uint band)
1554 phy_info_t *pi = (phy_info_t *) ppi;
1559 ASSERT((band == WLC_BAND_2G) || (band == WLC_BAND_5G));
1561 for (i = 0; i < ARRAY_SIZE(chan_info_all); i++) {
1562 channel = chan_info_all[i].chan;
1564 if (ISNPHY(pi) && IS40MHZ(pi)) {
1567 for (j = 0; j < ARRAY_SIZE(chan_info_all); j++) {
1568 if (chan_info_all[j].chan ==
1569 channel + CH_10MHZ_APART)
1573 if (j == ARRAY_SIZE(chan_info_all))
1576 channel = UPPER_20_SB(channel);
1578 channel | WL_CHANSPEC_BW_40 |
1579 WL_CHANSPEC_CTL_SB_LOWER;
1580 if (band == WLC_BAND_2G)
1581 chspec |= WL_CHANSPEC_BAND_2G;
1583 chspec |= WL_CHANSPEC_BAND_5G;
1585 chspec = CH20MHZ_CHSPEC(channel);
1587 if ((pi->a_band_high_disable) && (channel >= FIRST_REF5_CHANNUM)
1588 && (channel <= LAST_REF5_CHANNUM))
1591 if (((band == WLC_BAND_2G) && (channel <= CH_MAX_2G_CHANNEL)) ||
1592 ((band == WLC_BAND_5G) && (channel > CH_MAX_2G_CHANNEL)))
1598 return (chanspec_t) INVCHANSPEC;
1601 int wlc_phy_txpower_get(wlc_phy_t *ppi, uint *qdbm, bool *override)
1603 phy_info_t *pi = (phy_info_t *) ppi;
1605 ASSERT(qdbm != NULL);
1606 *qdbm = pi->tx_user_target[0];
1607 if (override != NULL)
1608 *override = pi->txpwroverride;
1612 void wlc_phy_txpower_target_set(wlc_phy_t *ppi, struct txpwr_limits *txpwr)
1614 bool mac_enabled = false;
1615 phy_info_t *pi = (phy_info_t *) ppi;
1617 bcopy(&txpwr->cck[0], &pi->tx_user_target[TXP_FIRST_CCK],
1620 bcopy(&txpwr->ofdm[0], &pi->tx_user_target[TXP_FIRST_OFDM],
1621 WLC_NUM_RATES_OFDM);
1622 bcopy(&txpwr->ofdm_cdd[0], &pi->tx_user_target[TXP_FIRST_OFDM_20_CDD],
1623 WLC_NUM_RATES_OFDM);
1625 bcopy(&txpwr->ofdm_40_siso[0],
1626 &pi->tx_user_target[TXP_FIRST_OFDM_40_SISO], WLC_NUM_RATES_OFDM);
1627 bcopy(&txpwr->ofdm_40_cdd[0],
1628 &pi->tx_user_target[TXP_FIRST_OFDM_40_CDD], WLC_NUM_RATES_OFDM);
1630 bcopy(&txpwr->mcs_20_siso[0],
1631 &pi->tx_user_target[TXP_FIRST_MCS_20_SISO],
1632 WLC_NUM_RATES_MCS_1_STREAM);
1633 bcopy(&txpwr->mcs_20_cdd[0], &pi->tx_user_target[TXP_FIRST_MCS_20_CDD],
1634 WLC_NUM_RATES_MCS_1_STREAM);
1635 bcopy(&txpwr->mcs_20_stbc[0],
1636 &pi->tx_user_target[TXP_FIRST_MCS_20_STBC],
1637 WLC_NUM_RATES_MCS_1_STREAM);
1638 bcopy(&txpwr->mcs_20_mimo[0], &pi->tx_user_target[TXP_FIRST_MCS_20_SDM],
1639 WLC_NUM_RATES_MCS_2_STREAM);
1641 bcopy(&txpwr->mcs_40_siso[0],
1642 &pi->tx_user_target[TXP_FIRST_MCS_40_SISO],
1643 WLC_NUM_RATES_MCS_1_STREAM);
1644 bcopy(&txpwr->mcs_40_cdd[0], &pi->tx_user_target[TXP_FIRST_MCS_40_CDD],
1645 WLC_NUM_RATES_MCS_1_STREAM);
1646 bcopy(&txpwr->mcs_40_stbc[0],
1647 &pi->tx_user_target[TXP_FIRST_MCS_40_STBC],
1648 WLC_NUM_RATES_MCS_1_STREAM);
1649 bcopy(&txpwr->mcs_40_mimo[0], &pi->tx_user_target[TXP_FIRST_MCS_40_SDM],
1650 WLC_NUM_RATES_MCS_2_STREAM);
1652 if (R_REG(pi->sh->osh, &pi->regs->maccontrol) & MCTL_EN_MAC)
1656 wlapi_suspend_mac_and_wait(pi->sh->physhim);
1658 wlc_phy_txpower_recalc_target(pi);
1659 wlc_phy_cal_txpower_recalc_sw(pi);
1662 wlapi_enable_mac(pi->sh->physhim);
1665 int wlc_phy_txpower_set(wlc_phy_t *ppi, uint qdbm, bool override)
1667 phy_info_t *pi = (phy_info_t *) ppi;
1673 for (i = 0; i < TXP_NUM_RATES; i++)
1674 pi->tx_user_target[i] = (u8) qdbm;
1676 pi->txpwroverride = false;
1679 if (!SCAN_INPROG_PHY(pi)) {
1684 (R_REG(pi->sh->osh, &pi->regs->maccontrol) &
1688 wlapi_suspend_mac_and_wait(pi->sh->physhim);
1690 wlc_phy_txpower_recalc_target(pi);
1691 wlc_phy_cal_txpower_recalc_sw(pi);
1694 wlapi_enable_mac(pi->sh->physhim);
1701 wlc_phy_txpower_sromlimit(wlc_phy_t *ppi, uint channel, u8 *min_pwr,
1702 u8 *max_pwr, int txp_rate_idx)
1704 phy_info_t *pi = (phy_info_t *) ppi;
1707 *min_pwr = pi->min_txpower * WLC_TXPWR_DB_FACTOR;
1710 if (txp_rate_idx < 0)
1711 txp_rate_idx = TXP_FIRST_CCK;
1712 wlc_phy_txpower_sromlimit_get_nphy(pi, channel, max_pwr,
1715 } else if ((channel <= CH_MAX_2G_CHANNEL)) {
1716 if (txp_rate_idx < 0)
1717 txp_rate_idx = TXP_FIRST_CCK;
1718 *max_pwr = pi->tx_srom_max_rate_2g[txp_rate_idx];
1721 *max_pwr = WLC_TXPWR_MAX;
1723 if (txp_rate_idx < 0)
1724 txp_rate_idx = TXP_FIRST_OFDM;
1726 for (i = 0; i < ARRAY_SIZE(chan_info_all); i++) {
1727 if (channel == chan_info_all[i].chan) {
1731 ASSERT(i < ARRAY_SIZE(chan_info_all));
1734 *max_pwr = pi->hwtxpwr[i];
1737 if ((i >= FIRST_MID_5G_CHAN) && (i <= LAST_MID_5G_CHAN))
1739 pi->tx_srom_max_rate_5g_mid[txp_rate_idx];
1740 if ((i >= FIRST_HIGH_5G_CHAN)
1741 && (i <= LAST_HIGH_5G_CHAN))
1743 pi->tx_srom_max_rate_5g_hi[txp_rate_idx];
1744 if ((i >= FIRST_LOW_5G_CHAN) && (i <= LAST_LOW_5G_CHAN))
1746 pi->tx_srom_max_rate_5g_low[txp_rate_idx];
1752 wlc_phy_txpower_sromlimit_max_get(wlc_phy_t *ppi, uint chan, u8 *max_txpwr,
1755 phy_info_t *pi = (phy_info_t *) ppi;
1757 u8 tx_pwr_min = 255;
1759 u8 maxtxpwr, mintxpwr, rate, pactrl;
1763 max_num_rate = ISNPHY(pi) ? TXP_NUM_RATES :
1764 ISLCNPHY(pi) ? (TXP_LAST_SISO_MCS_20 + 1) : (TXP_LAST_OFDM + 1);
1766 for (rate = 0; rate < max_num_rate; rate++) {
1768 wlc_phy_txpower_sromlimit(ppi, chan, &mintxpwr, &maxtxpwr,
1771 maxtxpwr = (maxtxpwr > pactrl) ? (maxtxpwr - pactrl) : 0;
1773 maxtxpwr = (maxtxpwr > 6) ? (maxtxpwr - 6) : 0;
1775 tx_pwr_max = max(tx_pwr_max, maxtxpwr);
1776 tx_pwr_min = min(tx_pwr_min, maxtxpwr);
1778 *max_txpwr = tx_pwr_max;
1779 *min_txpwr = tx_pwr_min;
1783 wlc_phy_txpower_boardlimit_band(wlc_phy_t *ppi, uint bandunit, s32 *max_pwr,
1784 s32 *min_pwr, u32 *step_pwr)
1789 u8 wlc_phy_txpower_get_target_min(wlc_phy_t *ppi)
1791 phy_info_t *pi = (phy_info_t *) ppi;
1793 return pi->tx_power_min;
1796 u8 wlc_phy_txpower_get_target_max(wlc_phy_t *ppi)
1798 phy_info_t *pi = (phy_info_t *) ppi;
1800 return pi->tx_power_max;
1803 void wlc_phy_txpower_recalc_target(phy_info_t *pi)
1805 u8 maxtxpwr, mintxpwr, rate, pactrl;
1807 u8 tx_pwr_target[TXP_NUM_RATES];
1809 u8 tx_pwr_min = 255;
1810 u8 tx_pwr_max_rate_ind = 0;
1814 u32 band = CHSPEC2WLC_BAND(pi->radio_chanspec);
1815 initfn_t txpwr_recalc_fn = NULL;
1817 chspec = pi->radio_chanspec;
1818 if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_NONE)
1819 target_chan = CHSPEC_CHANNEL(chspec);
1820 else if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_UPPER)
1821 target_chan = UPPER_20_SB(CHSPEC_CHANNEL(chspec));
1823 target_chan = LOWER_20_SB(CHSPEC_CHANNEL(chspec));
1829 if (CHSPEC_IS40(pi->radio_chanspec)) {
1830 offset_mcs = pi->mcs40_po;
1831 for (i = TXP_FIRST_SISO_MCS_20;
1832 i <= TXP_LAST_SISO_MCS_20; i++) {
1833 pi->tx_srom_max_rate_2g[i - 8] =
1834 pi->tx_srom_max_2g -
1835 ((offset_mcs & 0xf) * 2);
1839 offset_mcs = pi->mcs20_po;
1840 for (i = TXP_FIRST_SISO_MCS_20;
1841 i <= TXP_LAST_SISO_MCS_20; i++) {
1842 pi->tx_srom_max_rate_2g[i - 8] =
1843 pi->tx_srom_max_2g -
1844 ((offset_mcs & 0xf) * 2);
1850 max_num_rate = ((ISNPHY(pi)) ? (TXP_NUM_RATES) :
1852 (TXP_LAST_SISO_MCS_20 + 1) : (TXP_LAST_OFDM + 1)));
1854 max_num_rate = ((ISNPHY(pi)) ? (TXP_NUM_RATES) : (TXP_LAST_OFDM + 1));
1857 wlc_phy_upd_env_txpwr_rate_limits(pi, band);
1859 for (rate = start_rate; rate < max_num_rate; rate++) {
1861 tx_pwr_target[rate] = pi->tx_user_target[rate];
1863 if (pi->user_txpwr_at_rfport) {
1864 tx_pwr_target[rate] +=
1865 wlc_user_txpwr_antport_to_rfport(pi, target_chan,
1871 wlc_phy_txpower_sromlimit((wlc_phy_t *) pi, target_chan,
1872 &mintxpwr, &maxtxpwr, rate);
1874 maxtxpwr = min(maxtxpwr, pi->txpwr_limit[rate]);
1877 (maxtxpwr > pactrl) ? (maxtxpwr - pactrl) : 0;
1879 maxtxpwr = (maxtxpwr > 6) ? (maxtxpwr - 6) : 0;
1881 maxtxpwr = min(maxtxpwr, tx_pwr_target[rate]);
1883 if (pi->txpwr_percent <= 100)
1884 maxtxpwr = (maxtxpwr * pi->txpwr_percent) / 100;
1886 tx_pwr_target[rate] = max(maxtxpwr, mintxpwr);
1889 tx_pwr_target[rate] =
1890 min(tx_pwr_target[rate], pi->txpwr_env_limit[rate]);
1892 if (tx_pwr_target[rate] > tx_pwr_max)
1893 tx_pwr_max_rate_ind = rate;
1895 tx_pwr_max = max(tx_pwr_max, tx_pwr_target[rate]);
1896 tx_pwr_min = min(tx_pwr_min, tx_pwr_target[rate]);
1899 bzero(pi->tx_power_offset, sizeof(pi->tx_power_offset));
1900 pi->tx_power_max = tx_pwr_max;
1901 pi->tx_power_min = tx_pwr_min;
1902 pi->tx_power_max_rate_ind = tx_pwr_max_rate_ind;
1903 for (rate = 0; rate < max_num_rate; rate++) {
1905 pi->tx_power_target[rate] = tx_pwr_target[rate];
1907 if (!pi->hwpwrctrl || ISNPHY(pi)) {
1908 pi->tx_power_offset[rate] =
1909 pi->tx_power_max - pi->tx_power_target[rate];
1911 pi->tx_power_offset[rate] =
1912 pi->tx_power_target[rate] - pi->tx_power_min;
1916 txpwr_recalc_fn = pi->pi_fptr.txpwrrecalc;
1917 if (txpwr_recalc_fn)
1918 (*txpwr_recalc_fn) (pi);
1922 wlc_phy_txpower_reg_limit_calc(phy_info_t *pi, struct txpwr_limits *txpwr,
1923 chanspec_t chanspec)
1925 u8 tmp_txpwr_limit[2 * WLC_NUM_RATES_OFDM];
1926 u8 *txpwr_ptr1 = NULL, *txpwr_ptr2 = NULL;
1927 int rate_start_index = 0, rate1, rate2, k;
1929 for (rate1 = WL_TX_POWER_CCK_FIRST, rate2 = 0;
1930 rate2 < WL_TX_POWER_CCK_NUM; rate1++, rate2++)
1931 pi->txpwr_limit[rate1] = txpwr->cck[rate2];
1933 for (rate1 = WL_TX_POWER_OFDM_FIRST, rate2 = 0;
1934 rate2 < WL_TX_POWER_OFDM_NUM; rate1++, rate2++)
1935 pi->txpwr_limit[rate1] = txpwr->ofdm[rate2];
1939 for (k = 0; k < 4; k++) {
1943 txpwr_ptr1 = txpwr->mcs_20_siso;
1944 txpwr_ptr2 = txpwr->ofdm;
1945 rate_start_index = WL_TX_POWER_OFDM_FIRST;
1949 txpwr_ptr1 = txpwr->mcs_20_cdd;
1950 txpwr_ptr2 = txpwr->ofdm_cdd;
1951 rate_start_index = WL_TX_POWER_OFDM20_CDD_FIRST;
1955 txpwr_ptr1 = txpwr->mcs_40_siso;
1956 txpwr_ptr2 = txpwr->ofdm_40_siso;
1958 WL_TX_POWER_OFDM40_SISO_FIRST;
1962 txpwr_ptr1 = txpwr->mcs_40_cdd;
1963 txpwr_ptr2 = txpwr->ofdm_40_cdd;
1964 rate_start_index = WL_TX_POWER_OFDM40_CDD_FIRST;
1968 for (rate2 = 0; rate2 < WLC_NUM_RATES_OFDM; rate2++) {
1969 tmp_txpwr_limit[rate2] = 0;
1970 tmp_txpwr_limit[WLC_NUM_RATES_OFDM + rate2] =
1973 wlc_phy_mcs_to_ofdm_powers_nphy(tmp_txpwr_limit, 0,
1974 WLC_NUM_RATES_OFDM - 1,
1975 WLC_NUM_RATES_OFDM);
1976 for (rate1 = rate_start_index, rate2 = 0;
1977 rate2 < WLC_NUM_RATES_OFDM; rate1++, rate2++)
1978 pi->txpwr_limit[rate1] =
1979 min(txpwr_ptr2[rate2],
1980 tmp_txpwr_limit[rate2]);
1983 for (k = 0; k < 4; k++) {
1987 txpwr_ptr1 = txpwr->ofdm;
1988 txpwr_ptr2 = txpwr->mcs_20_siso;
1989 rate_start_index = WL_TX_POWER_MCS20_SISO_FIRST;
1993 txpwr_ptr1 = txpwr->ofdm_cdd;
1994 txpwr_ptr2 = txpwr->mcs_20_cdd;
1995 rate_start_index = WL_TX_POWER_MCS20_CDD_FIRST;
1999 txpwr_ptr1 = txpwr->ofdm_40_siso;
2000 txpwr_ptr2 = txpwr->mcs_40_siso;
2001 rate_start_index = WL_TX_POWER_MCS40_SISO_FIRST;
2005 txpwr_ptr1 = txpwr->ofdm_40_cdd;
2006 txpwr_ptr2 = txpwr->mcs_40_cdd;
2007 rate_start_index = WL_TX_POWER_MCS40_CDD_FIRST;
2010 for (rate2 = 0; rate2 < WLC_NUM_RATES_OFDM; rate2++) {
2011 tmp_txpwr_limit[rate2] = 0;
2012 tmp_txpwr_limit[WLC_NUM_RATES_OFDM + rate2] =
2015 wlc_phy_ofdm_to_mcs_powers_nphy(tmp_txpwr_limit, 0,
2016 WLC_NUM_RATES_OFDM - 1,
2017 WLC_NUM_RATES_OFDM);
2018 for (rate1 = rate_start_index, rate2 = 0;
2019 rate2 < WLC_NUM_RATES_MCS_1_STREAM;
2021 pi->txpwr_limit[rate1] =
2022 min(txpwr_ptr2[rate2],
2023 tmp_txpwr_limit[rate2]);
2026 for (k = 0; k < 2; k++) {
2030 rate_start_index = WL_TX_POWER_MCS20_STBC_FIRST;
2031 txpwr_ptr1 = txpwr->mcs_20_stbc;
2035 rate_start_index = WL_TX_POWER_MCS40_STBC_FIRST;
2036 txpwr_ptr1 = txpwr->mcs_40_stbc;
2039 for (rate1 = rate_start_index, rate2 = 0;
2040 rate2 < WLC_NUM_RATES_MCS_1_STREAM;
2042 pi->txpwr_limit[rate1] = txpwr_ptr1[rate2];
2045 for (k = 0; k < 2; k++) {
2049 rate_start_index = WL_TX_POWER_MCS20_SDM_FIRST;
2050 txpwr_ptr1 = txpwr->mcs_20_mimo;
2054 rate_start_index = WL_TX_POWER_MCS40_SDM_FIRST;
2055 txpwr_ptr1 = txpwr->mcs_40_mimo;
2058 for (rate1 = rate_start_index, rate2 = 0;
2059 rate2 < WLC_NUM_RATES_MCS_2_STREAM;
2061 pi->txpwr_limit[rate1] = txpwr_ptr1[rate2];
2064 pi->txpwr_limit[WL_TX_POWER_MCS_32] = txpwr->mcs32;
2066 pi->txpwr_limit[WL_TX_POWER_MCS40_CDD_FIRST] =
2067 min(pi->txpwr_limit[WL_TX_POWER_MCS40_CDD_FIRST],
2068 pi->txpwr_limit[WL_TX_POWER_MCS_32]);
2069 pi->txpwr_limit[WL_TX_POWER_MCS_32] =
2070 pi->txpwr_limit[WL_TX_POWER_MCS40_CDD_FIRST];
2074 void wlc_phy_txpwr_percent_set(wlc_phy_t *ppi, u8 txpwr_percent)
2076 phy_info_t *pi = (phy_info_t *) ppi;
2078 pi->txpwr_percent = txpwr_percent;
2081 void wlc_phy_machwcap_set(wlc_phy_t *ppi, u32 machwcap)
2083 phy_info_t *pi = (phy_info_t *) ppi;
2085 pi->sh->machwcap = machwcap;
2088 void wlc_phy_runbist_config(wlc_phy_t *ppi, bool start_end)
2090 phy_info_t *pi = (phy_info_t *) ppi;
2094 if (start_end == ON) {
2098 if (NREV_IS(pi->pubpi.phy_rev, 3)
2099 || NREV_IS(pi->pubpi.phy_rev, 4)) {
2100 W_REG(pi->sh->osh, &pi->regs->phyregaddr, 0xa0);
2101 (void)R_REG(pi->sh->osh, &pi->regs->phyregaddr);
2102 rxc = R_REG(pi->sh->osh, &pi->regs->phyregdata);
2103 W_REG(pi->sh->osh, &pi->regs->phyregdata,
2107 if (NREV_IS(pi->pubpi.phy_rev, 3)
2108 || NREV_IS(pi->pubpi.phy_rev, 4)) {
2109 W_REG(pi->sh->osh, &pi->regs->phyregaddr, 0xa0);
2110 (void)R_REG(pi->sh->osh, &pi->regs->phyregaddr);
2111 W_REG(pi->sh->osh, &pi->regs->phyregdata, rxc);
2114 wlc_phy_por_inform(ppi);
2119 wlc_phy_txpower_limit_set(wlc_phy_t *ppi, struct txpwr_limits *txpwr,
2120 chanspec_t chanspec)
2122 phy_info_t *pi = (phy_info_t *) ppi;
2124 wlc_phy_txpower_reg_limit_calc(pi, txpwr, chanspec);
2128 for (i = TXP_FIRST_OFDM_20_CDD, j = 0;
2129 j < WLC_NUM_RATES_MCS_1_STREAM; i++, j++) {
2130 if (txpwr->mcs_20_siso[j])
2131 pi->txpwr_limit[i] = txpwr->mcs_20_siso[j];
2133 pi->txpwr_limit[i] = txpwr->ofdm[j];
2137 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2139 wlc_phy_txpower_recalc_target(pi);
2140 wlc_phy_cal_txpower_recalc_sw(pi);
2141 wlapi_enable_mac(pi->sh->physhim);
2144 void wlc_phy_ofdm_rateset_war(wlc_phy_t *pih, bool war)
2146 phy_info_t *pi = (phy_info_t *) pih;
2148 pi->ofdm_rateset_war = war;
2151 void wlc_phy_bf_preempt_enable(wlc_phy_t *pih, bool bf_preempt)
2153 phy_info_t *pi = (phy_info_t *) pih;
2155 pi->bf_preempt_4306 = bf_preempt;
2158 void wlc_phy_txpower_update_shm(phy_info_t *pi)
2169 if (pi->hwpwrctrl) {
2172 wlapi_bmac_write_shm(pi->sh->physhim, M_TXPWR_MAX, 63);
2173 wlapi_bmac_write_shm(pi->sh->physhim, M_TXPWR_N,
2174 1 << NUM_TSSI_FRAMES);
2176 wlapi_bmac_write_shm(pi->sh->physhim, M_TXPWR_TARGET,
2177 pi->tx_power_min << NUM_TSSI_FRAMES);
2179 wlapi_bmac_write_shm(pi->sh->physhim, M_TXPWR_CUR,
2182 for (j = TXP_FIRST_OFDM; j <= TXP_LAST_OFDM; j++) {
2183 const u8 ucode_ofdm_rates[] = {
2184 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c
2186 offset = wlapi_bmac_rate_shm_offset(pi->sh->physhim,
2187 ucode_ofdm_rates[j -
2189 wlapi_bmac_write_shm(pi->sh->physhim, offset + 6,
2190 pi->tx_power_offset[j]);
2191 wlapi_bmac_write_shm(pi->sh->physhim, offset + 14,
2192 -(pi->tx_power_offset[j] / 2));
2195 wlapi_bmac_mhf(pi->sh->physhim, MHF2, MHF2_HWPWRCTL,
2196 MHF2_HWPWRCTL, WLC_BAND_ALL);
2200 for (i = TXP_FIRST_OFDM; i <= TXP_LAST_OFDM; i++)
2201 pi->tx_power_offset[i] =
2202 (u8) roundup(pi->tx_power_offset[i], 8);
2203 wlapi_bmac_write_shm(pi->sh->physhim, M_OFDM_OFFSET,
2205 tx_power_offset[TXP_FIRST_OFDM]
2210 bool wlc_phy_txpower_hw_ctrl_get(wlc_phy_t *ppi)
2212 phy_info_t *pi = (phy_info_t *) ppi;
2215 return pi->nphy_txpwrctrl;
2217 return pi->hwpwrctrl;
2221 void wlc_phy_txpower_hw_ctrl_set(wlc_phy_t *ppi, bool hwpwrctrl)
2223 phy_info_t *pi = (phy_info_t *) ppi;
2224 bool cur_hwpwrctrl = pi->hwpwrctrl;
2227 if (!pi->hwpwrctrl_capable) {
2231 pi->hwpwrctrl = hwpwrctrl;
2232 pi->nphy_txpwrctrl = hwpwrctrl;
2233 pi->txpwrctrl = hwpwrctrl;
2238 (R_REG(pi->sh->osh, &pi->regs->maccontrol) & MCTL_EN_MAC));
2240 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2242 wlc_phy_txpwrctrl_enable_nphy(pi, pi->nphy_txpwrctrl);
2243 if (pi->nphy_txpwrctrl == PHY_TPC_HW_OFF) {
2244 wlc_phy_txpwr_fixpower_nphy(pi);
2247 mod_phy_reg(pi, 0x1e7, (0x7f << 0),
2248 pi->saved_txpwr_idx);
2252 wlapi_enable_mac(pi->sh->physhim);
2253 } else if (hwpwrctrl != cur_hwpwrctrl) {
2259 void wlc_phy_txpower_ipa_upd(phy_info_t *pi)
2262 if (NREV_GE(pi->pubpi.phy_rev, 3)) {
2263 pi->ipa2g_on = (pi->srom_fem2g.extpagain == 2);
2264 pi->ipa5g_on = (pi->srom_fem5g.extpagain == 2);
2266 pi->ipa2g_on = false;
2267 pi->ipa5g_on = false;
2271 static u32 wlc_phy_txpower_est_power_nphy(phy_info_t *pi);
2273 static u32 wlc_phy_txpower_est_power_nphy(phy_info_t *pi)
2275 s16 tx0_status, tx1_status;
2276 u16 estPower1, estPower2;
2277 u8 pwr0, pwr1, adj_pwr0, adj_pwr1;
2280 estPower1 = read_phy_reg(pi, 0x118);
2281 estPower2 = read_phy_reg(pi, 0x119);
2283 if ((estPower1 & (0x1 << 8))
2285 pwr0 = (u8) (estPower1 & (0xff << 0))
2291 if ((estPower2 & (0x1 << 8))
2293 pwr1 = (u8) (estPower2 & (0xff << 0))
2299 tx0_status = read_phy_reg(pi, 0x1ed);
2300 tx1_status = read_phy_reg(pi, 0x1ee);
2302 if ((tx0_status & (0x1 << 15))
2304 adj_pwr0 = (u8) (tx0_status & (0xff << 0))
2309 if ((tx1_status & (0x1 << 15))
2311 adj_pwr1 = (u8) (tx1_status & (0xff << 0))
2318 (u32) ((pwr0 << 24) | (pwr1 << 16) | (adj_pwr0 << 8) | adj_pwr1);
2323 wlc_phy_txpower_get_current(wlc_phy_t *ppi, tx_power_t *power, uint channel)
2325 phy_info_t *pi = (phy_info_t *) ppi;
2326 uint rate, num_rates;
2327 u8 min_pwr, max_pwr;
2329 #if WL_TX_POWER_RATES != TXP_NUM_RATES
2330 #error "tx_power_t struct out of sync with this fn"
2334 power->rf_cores = 2;
2335 power->flags |= (WL_TX_POWER_F_MIMO);
2336 if (pi->nphy_txpwrctrl == PHY_TPC_HW_ON)
2338 (WL_TX_POWER_F_ENABLED | WL_TX_POWER_F_HW);
2339 } else if (ISLCNPHY(pi)) {
2340 power->rf_cores = 1;
2341 power->flags |= (WL_TX_POWER_F_SISO);
2342 if (pi->radiopwr_override == RADIOPWR_OVERRIDE_DEF)
2343 power->flags |= WL_TX_POWER_F_ENABLED;
2345 power->flags |= WL_TX_POWER_F_HW;
2348 num_rates = ((ISNPHY(pi)) ? (TXP_NUM_RATES) :
2350 (TXP_LAST_OFDM_20_CDD + 1) : (TXP_LAST_OFDM + 1)));
2352 for (rate = 0; rate < num_rates; rate++) {
2353 power->user_limit[rate] = pi->tx_user_target[rate];
2354 wlc_phy_txpower_sromlimit(ppi, channel, &min_pwr, &max_pwr,
2356 power->board_limit[rate] = (u8) max_pwr;
2357 power->target[rate] = pi->tx_power_target[rate];
2363 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2364 wlc_phyreg_enter((wlc_phy_t *) pi);
2365 est_pout = wlc_phy_txpower_est_power_nphy(pi);
2366 wlc_phyreg_exit((wlc_phy_t *) pi);
2367 wlapi_enable_mac(pi->sh->physhim);
2369 power->est_Pout[0] = (est_pout >> 8) & 0xff;
2370 power->est_Pout[1] = est_pout & 0xff;
2372 power->est_Pout_act[0] = est_pout >> 24;
2373 power->est_Pout_act[1] = (est_pout >> 16) & 0xff;
2375 if (power->est_Pout[0] == 0x80)
2376 power->est_Pout[0] = 0;
2377 if (power->est_Pout[1] == 0x80)
2378 power->est_Pout[1] = 0;
2380 if (power->est_Pout_act[0] == 0x80)
2381 power->est_Pout_act[0] = 0;
2382 if (power->est_Pout_act[1] == 0x80)
2383 power->est_Pout_act[1] = 0;
2385 power->est_Pout_cck = 0;
2387 power->tx_power_max[0] = pi->tx_power_max;
2388 power->tx_power_max[1] = pi->tx_power_max;
2390 power->tx_power_max_rate_ind[0] = pi->tx_power_max_rate_ind;
2391 power->tx_power_max_rate_ind[1] = pi->tx_power_max_rate_ind;
2392 } else if (!pi->hwpwrctrl) {
2393 } else if (pi->sh->up) {
2395 wlc_phyreg_enter(ppi);
2398 power->tx_power_max[0] = pi->tx_power_max;
2399 power->tx_power_max[1] = pi->tx_power_max;
2401 power->tx_power_max_rate_ind[0] =
2402 pi->tx_power_max_rate_ind;
2403 power->tx_power_max_rate_ind[1] =
2404 pi->tx_power_max_rate_ind;
2406 if (wlc_phy_tpc_isenabled_lcnphy(pi))
2408 (WL_TX_POWER_F_HW | WL_TX_POWER_F_ENABLED);
2411 ~(WL_TX_POWER_F_HW | WL_TX_POWER_F_ENABLED);
2413 wlc_lcnphy_get_tssi(pi, (s8 *) &power->est_Pout[0],
2414 (s8 *) &power->est_Pout_cck);
2416 wlc_phyreg_exit(ppi);
2420 void wlc_phy_antsel_type_set(wlc_phy_t *ppi, u8 antsel_type)
2422 phy_info_t *pi = (phy_info_t *) ppi;
2424 pi->antsel_type = antsel_type;
2427 bool wlc_phy_test_ison(wlc_phy_t *ppi)
2429 phy_info_t *pi = (phy_info_t *) ppi;
2431 return pi->phytest_on;
2434 bool wlc_phy_ant_rxdiv_get(wlc_phy_t *ppi, u8 *pval)
2436 phy_info_t *pi = (phy_info_t *) ppi;
2439 wlc_phyreg_enter(ppi);
2444 } else if (ISLCNPHY(pi)) {
2445 u16 crsctrl = read_phy_reg(pi, 0x410);
2446 u16 div = crsctrl & (0x1 << 1);
2447 *pval = (div | ((crsctrl & (0x1 << 0)) ^ (div >> 1)));
2450 wlc_phyreg_exit(ppi);
2455 void wlc_phy_ant_rxdiv_set(wlc_phy_t *ppi, u8 val)
2457 phy_info_t *pi = (phy_info_t *) ppi;
2460 pi->sh->rx_antdiv = val;
2462 if (!(ISNPHY(pi) && D11REV_IS(pi->sh->corerev, 16))) {
2463 if (val > ANT_RX_DIV_FORCE_1)
2464 wlapi_bmac_mhf(pi->sh->physhim, MHF1, MHF1_ANTDIV,
2465 MHF1_ANTDIV, WLC_BAND_ALL);
2467 wlapi_bmac_mhf(pi->sh->physhim, MHF1, MHF1_ANTDIV, 0,
2480 (0 == (R_REG(pi->sh->osh, &pi->regs->maccontrol) & MCTL_EN_MAC));
2482 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2485 if (val > ANT_RX_DIV_FORCE_1) {
2486 mod_phy_reg(pi, 0x410, (0x1 << 1), 0x01 << 1);
2487 mod_phy_reg(pi, 0x410,
2489 ((ANT_RX_DIV_START_1 == val) ? 1 : 0) << 0);
2491 mod_phy_reg(pi, 0x410, (0x1 << 1), 0x00 << 1);
2492 mod_phy_reg(pi, 0x410, (0x1 << 0), (u16) val << 0);
2499 wlapi_enable_mac(pi->sh->physhim);
2505 wlc_phy_noise_calc_phy(phy_info_t *pi, u32 *cmplx_pwr, s8 *pwr_ant)
2507 s8 cmplx_pwr_dbm[PHY_CORE_MAX];
2510 bzero((u8 *) cmplx_pwr_dbm, sizeof(cmplx_pwr_dbm));
2511 ASSERT(pi->pubpi.phy_corenum <= PHY_CORE_MAX);
2512 wlc_phy_compute_dB(cmplx_pwr, cmplx_pwr_dbm, pi->pubpi.phy_corenum);
2514 for (i = 0; i < pi->pubpi.phy_corenum; i++) {
2515 if (NREV_GE(pi->pubpi.phy_rev, 3))
2516 cmplx_pwr_dbm[i] += (s8) PHY_NOISE_OFFSETFACT_4322;
2519 cmplx_pwr_dbm[i] += (s8) (16 - (15) * 3 - 70);
2522 for (i = 0; i < pi->pubpi.phy_corenum; i++) {
2523 pi->nphy_noise_win[i][pi->nphy_noise_index] = cmplx_pwr_dbm[i];
2524 pwr_ant[i] = cmplx_pwr_dbm[i];
2526 pi->nphy_noise_index =
2527 MODINC_POW2(pi->nphy_noise_index, PHY_NOISE_WINDOW_SZ);
2532 wlc_phy_noise_sample_request(wlc_phy_t *pih, u8 reason, u8 ch)
2534 phy_info_t *pi = (phy_info_t *) pih;
2535 s8 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;
2536 bool sampling_in_progress = (pi->phynoise_state != 0);
2537 bool wait_for_intr = true;
2539 if (NORADIO_ENAB(pi->pubpi)) {
2544 case PHY_NOISE_SAMPLE_MON:
2546 pi->phynoise_chan_watchdog = ch;
2547 pi->phynoise_state |= PHY_NOISE_STATE_MON;
2551 case PHY_NOISE_SAMPLE_EXTERNAL:
2553 pi->phynoise_state |= PHY_NOISE_STATE_EXTERNAL;
2561 if (sampling_in_progress)
2564 pi->phynoise_now = pi->sh->now;
2566 if (pi->phy_fixed_noise) {
2568 pi->nphy_noise_win[WL_ANT_IDX_1][pi->nphy_noise_index] =
2569 PHY_NOISE_FIXED_VAL_NPHY;
2570 pi->nphy_noise_win[WL_ANT_IDX_2][pi->nphy_noise_index] =
2571 PHY_NOISE_FIXED_VAL_NPHY;
2572 pi->nphy_noise_index = MODINC_POW2(pi->nphy_noise_index,
2573 PHY_NOISE_WINDOW_SZ);
2575 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;
2578 noise_dbm = PHY_NOISE_FIXED_VAL;
2581 wait_for_intr = false;
2586 if (!pi->phynoise_polling
2587 || (reason == PHY_NOISE_SAMPLE_EXTERNAL)) {
2588 wlapi_bmac_write_shm(pi->sh->physhim, M_JSSI_0, 0);
2589 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP0, 0);
2590 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP1, 0);
2591 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP2, 0);
2592 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP3, 0);
2594 OR_REG(pi->sh->osh, &pi->regs->maccommand,
2597 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2598 wlc_lcnphy_deaf_mode(pi, (bool) 0);
2599 noise_dbm = (s8) wlc_lcnphy_rx_signal_power(pi, 20);
2600 wlc_lcnphy_deaf_mode(pi, (bool) 1);
2601 wlapi_enable_mac(pi->sh->physhim);
2602 wait_for_intr = false;
2604 } else if (ISNPHY(pi)) {
2605 if (!pi->phynoise_polling
2606 || (reason == PHY_NOISE_SAMPLE_EXTERNAL)) {
2608 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP0, 0);
2609 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP1, 0);
2610 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP2, 0);
2611 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP3, 0);
2613 OR_REG(pi->sh->osh, &pi->regs->maccommand,
2616 phy_iq_est_t est[PHY_CORE_MAX];
2617 u32 cmplx_pwr[PHY_CORE_MAX];
2618 s8 noise_dbm_ant[PHY_CORE_MAX];
2619 u16 log_num_samps, num_samps, classif_state = 0;
2624 bzero((u8 *) est, sizeof(est));
2625 bzero((u8 *) cmplx_pwr, sizeof(cmplx_pwr));
2626 bzero((u8 *) noise_dbm_ant, sizeof(noise_dbm_ant));
2628 log_num_samps = PHY_NOISE_SAMPLE_LOG_NUM_NPHY;
2629 num_samps = 1 << log_num_samps;
2631 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2632 classif_state = wlc_phy_classifier_nphy(pi, 0, 0);
2633 wlc_phy_classifier_nphy(pi, 3, 0);
2634 wlc_phy_rx_iq_est_nphy(pi, est, num_samps, wait_time,
2636 wlc_phy_classifier_nphy(pi, (0x7 << 0), classif_state);
2637 wlapi_enable_mac(pi->sh->physhim);
2639 for (i = 0; i < pi->pubpi.phy_corenum; i++)
2642 est[i].q_pwr) >> log_num_samps;
2644 wlc_phy_noise_calc_phy(pi, cmplx_pwr, noise_dbm_ant);
2646 for (i = 0; i < pi->pubpi.phy_corenum; i++) {
2647 pi->nphy_noise_win[i][pi->nphy_noise_index] =
2650 if (noise_dbm_ant[i] > noise_dbm)
2651 noise_dbm = noise_dbm_ant[i];
2653 pi->nphy_noise_index = MODINC_POW2(pi->nphy_noise_index,
2654 PHY_NOISE_WINDOW_SZ);
2656 wait_for_intr = false;
2663 wlc_phy_noise_cb(pi, ch, noise_dbm);
2667 void wlc_phy_noise_sample_request_external(wlc_phy_t *pih)
2671 channel = CHSPEC_CHANNEL(wlc_phy_chanspec_get(pih));
2673 wlc_phy_noise_sample_request(pih, PHY_NOISE_SAMPLE_EXTERNAL, channel);
2676 static void wlc_phy_noise_cb(phy_info_t *pi, u8 channel, s8 noise_dbm)
2678 if (!pi->phynoise_state)
2681 if (pi->phynoise_state & PHY_NOISE_STATE_MON) {
2682 if (pi->phynoise_chan_watchdog == channel) {
2683 pi->sh->phy_noise_window[pi->sh->phy_noise_index] =
2685 pi->sh->phy_noise_index =
2686 MODINC(pi->sh->phy_noise_index, MA_WINDOW_SZ);
2688 pi->phynoise_state &= ~PHY_NOISE_STATE_MON;
2691 if (pi->phynoise_state & PHY_NOISE_STATE_EXTERNAL) {
2692 pi->phynoise_state &= ~PHY_NOISE_STATE_EXTERNAL;
2697 static s8 wlc_phy_noise_read_shmem(phy_info_t *pi)
2699 u32 cmplx_pwr[PHY_CORE_MAX];
2700 s8 noise_dbm_ant[PHY_CORE_MAX];
2702 u32 cmplx_pwr_tot = 0;
2703 s8 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;
2706 ASSERT(pi->pubpi.phy_corenum <= PHY_CORE_MAX);
2707 bzero((u8 *) cmplx_pwr, sizeof(cmplx_pwr));
2708 bzero((u8 *) noise_dbm_ant, sizeof(noise_dbm_ant));
2710 for (idx = 0, core = 0; core < pi->pubpi.phy_corenum; idx += 2, core++) {
2711 lo = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP(idx));
2712 hi = wlapi_bmac_read_shm(pi->sh->physhim,
2713 M_PWRIND_MAP(idx + 1));
2714 cmplx_pwr[core] = (hi << 16) + lo;
2715 cmplx_pwr_tot += cmplx_pwr[core];
2716 if (cmplx_pwr[core] == 0) {
2717 noise_dbm_ant[core] = PHY_NOISE_FIXED_VAL_NPHY;
2719 cmplx_pwr[core] >>= PHY_NOISE_SAMPLE_LOG_NUM_UCODE;
2722 if (cmplx_pwr_tot != 0)
2723 wlc_phy_noise_calc_phy(pi, cmplx_pwr, noise_dbm_ant);
2725 for (core = 0; core < pi->pubpi.phy_corenum; core++) {
2726 pi->nphy_noise_win[core][pi->nphy_noise_index] =
2727 noise_dbm_ant[core];
2729 if (noise_dbm_ant[core] > noise_dbm)
2730 noise_dbm = noise_dbm_ant[core];
2732 pi->nphy_noise_index =
2733 MODINC_POW2(pi->nphy_noise_index, PHY_NOISE_WINDOW_SZ);
2739 void wlc_phy_noise_sample_intr(wlc_phy_t *pih)
2741 phy_info_t *pi = (phy_info_t *) pih;
2744 s8 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;
2747 u32 cmplx_pwr, cmplx_pwr0, cmplx_pwr1;
2749 s32 pwr_offset_dB, gain_dB;
2750 u16 status_0, status_1;
2752 jssi_aux = wlapi_bmac_read_shm(pi->sh->physhim, M_JSSI_AUX);
2753 channel = jssi_aux & D11_CURCHANNEL_MAX;
2755 lo = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP0);
2756 hi = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP1);
2757 cmplx_pwr0 = (hi << 16) + lo;
2759 lo = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP2);
2760 hi = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP3);
2761 cmplx_pwr1 = (hi << 16) + lo;
2762 cmplx_pwr = (cmplx_pwr0 + cmplx_pwr1) >> 6;
2765 status_1 = wlapi_bmac_read_shm(pi->sh->physhim, M_JSSI_0);
2766 if ((cmplx_pwr > 0 && cmplx_pwr < 500)
2767 && ((status_1 & 0xc000) == 0x4000)) {
2769 wlc_phy_compute_dB(&cmplx_pwr, &noise_dbm,
2770 pi->pubpi.phy_corenum);
2771 pwr_offset_dB = (read_phy_reg(pi, 0x434) & 0xFF);
2772 if (pwr_offset_dB > 127)
2773 pwr_offset_dB -= 256;
2775 noise_dbm += (s8) (pwr_offset_dB - 30);
2777 gain_dB = (status_0 & 0x1ff);
2778 noise_dbm -= (s8) (gain_dB);
2780 noise_dbm = PHY_NOISE_FIXED_VAL_LCNPHY;
2782 } else if (ISNPHY(pi)) {
2784 jssi_aux = wlapi_bmac_read_shm(pi->sh->physhim, M_JSSI_AUX);
2785 channel = jssi_aux & D11_CURCHANNEL_MAX;
2787 noise_dbm = wlc_phy_noise_read_shmem(pi);
2792 wlc_phy_noise_cb(pi, channel, noise_dbm);
2796 s8 lcnphy_gain_index_offset_for_pkt_rssi[] = {
2837 void wlc_phy_compute_dB(u32 *cmplx_pwr, s8 *p_cmplx_pwr_dB, u8 core)
2839 u8 shift_ct, lsb, msb, secondmsb, i;
2842 for (i = 0; i < core; i++) {
2844 shift_ct = msb = secondmsb = 0;
2848 lsb = (u8) (tmp & 1);
2852 secondmsb = (u8) ((cmplx_pwr[i] >> (msb - 1)) & 1);
2853 p_cmplx_pwr_dB[i] = (s8) (3 * msb + 2 * secondmsb);
2857 void BCMFASTPATH wlc_phy_rssi_compute(wlc_phy_t *pih, void *ctx)
2859 wlc_d11rxhdr_t *wlc_rxhdr = (wlc_d11rxhdr_t *) ctx;
2860 d11rxhdr_t *rxh = &wlc_rxhdr->rxhdr;
2861 int rssi = ltoh16(rxh->PhyRxStatus_1) & PRXS1_JSSI_MASK;
2862 uint radioid = pih->radioid;
2863 phy_info_t *pi = (phy_info_t *) pih;
2865 if (NORADIO_ENAB(pi->pubpi)) {
2866 rssi = WLC_RSSI_INVALID;
2870 if ((pi->sh->corerev >= 11)
2871 && !(ltoh16(rxh->RxStatus2) & RXS_PHYRXST_VALID)) {
2872 rssi = WLC_RSSI_INVALID;
2877 u8 gidx = (ltoh16(rxh->PhyRxStatus_2) & 0xFC00) >> 10;
2878 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
2883 rssi = rssi + lcnphy_gain_index_offset_for_pkt_rssi[gidx];
2884 if ((rssi > -46) && (gidx > 18))
2887 rssi = rssi + pi_lcn->lcnphy_pkteng_rssi_slope;
2897 } else if (radioid == BCM2055_ID || radioid == BCM2056_ID
2898 || radioid == BCM2057_ID) {
2900 rssi = wlc_phy_rssi_compute_nphy(pi, wlc_rxhdr);
2902 ASSERT((const char *)"Unknown radio" == NULL);
2906 wlc_rxhdr->rssi = (s8) rssi;
2909 void wlc_phy_freqtrack_start(wlc_phy_t *pih)
2914 void wlc_phy_freqtrack_end(wlc_phy_t *pih)
2919 void wlc_phy_set_deaf(wlc_phy_t *ppi, bool user_flag)
2922 pi = (phy_info_t *) ppi;
2925 wlc_lcnphy_deaf_mode(pi, true);
2926 else if (ISNPHY(pi))
2927 wlc_nphy_deaf_mode(pi, true);
2933 void wlc_phy_watchdog(wlc_phy_t *pih)
2935 phy_info_t *pi = (phy_info_t *) pih;
2936 bool delay_phy_cal = false;
2939 if (!pi->watchdog_override)
2942 if (!(SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi))) {
2943 wlc_phy_noise_sample_request((wlc_phy_t *) pi,
2944 PHY_NOISE_SAMPLE_MON,
2949 if (pi->phynoise_state && (pi->sh->now - pi->phynoise_now) > 5) {
2950 pi->phynoise_state = 0;
2953 if ((!pi->phycal_txpower) ||
2954 ((pi->sh->now - pi->phycal_txpower) >= pi->sh->fast_timer)) {
2956 if (!SCAN_INPROG_PHY(pi) && wlc_phy_cal_txpower_recalc_sw(pi)) {
2957 pi->phycal_txpower = pi->sh->now;
2961 if (NORADIO_ENAB(pi->pubpi))
2964 if ((SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi)
2965 || ASSOC_INPROG_PHY(pi)))
2968 if (ISNPHY(pi) && !pi->disable_percal && !delay_phy_cal) {
2970 if ((pi->nphy_perical != PHY_PERICAL_DISABLE) &&
2971 (pi->nphy_perical != PHY_PERICAL_MANUAL) &&
2972 ((pi->sh->now - pi->nphy_perical_last) >=
2973 pi->sh->glacial_timer))
2974 wlc_phy_cal_perical((wlc_phy_t *) pi,
2975 PHY_PERICAL_WATCHDOG);
2977 wlc_phy_txpwr_papd_cal_nphy(pi);
2981 if (pi->phy_forcecal ||
2982 ((pi->sh->now - pi->phy_lastcal) >=
2983 pi->sh->glacial_timer)) {
2984 if (!(SCAN_RM_IN_PROGRESS(pi) || ASSOC_INPROG_PHY(pi)))
2985 wlc_lcnphy_calib_modes(pi,
2986 LCNPHY_PERICAL_TEMPBASED_TXPWRCTRL);
2988 (SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi)
2989 || ASSOC_INPROG_PHY(pi)
2990 || pi->carrier_suppr_disable
2991 || pi->disable_percal))
2992 wlc_lcnphy_calib_modes(pi,
2993 PHY_PERICAL_WATCHDOG);
2998 void wlc_phy_BSSinit(wlc_phy_t *pih, bool bonlyap, int rssi)
3000 phy_info_t *pi = (phy_info_t *) pih;
3004 for (i = 0; i < MA_WINDOW_SZ; i++) {
3005 pi->sh->phy_noise_window[i] = (s8) (rssi & 0xff);
3008 for (i = 0; i < MA_WINDOW_SZ; i++)
3009 pi->sh->phy_noise_window[i] =
3010 PHY_NOISE_FIXED_VAL_LCNPHY;
3012 pi->sh->phy_noise_index = 0;
3014 for (i = 0; i < PHY_NOISE_WINDOW_SZ; i++) {
3015 for (k = WL_ANT_IDX_1; k < WL_ANT_RX_MAX; k++)
3016 pi->nphy_noise_win[k][i] = PHY_NOISE_FIXED_VAL_NPHY;
3018 pi->nphy_noise_index = 0;
3022 wlc_phy_papd_decode_epsilon(u32 epsilon, s32 *eps_real, s32 *eps_imag)
3024 *eps_imag = (epsilon >> 13);
3025 if (*eps_imag > 0xfff)
3026 *eps_imag -= 0x2000;
3028 *eps_real = (epsilon & 0x1fff);
3029 if (*eps_real > 0xfff)
3030 *eps_real -= 0x2000;
3033 static const fixed AtanTbl[] = {
3054 void wlc_phy_cordic(fixed theta, cs32 *val)
3056 fixed angle, valtmp;
3061 val[0].i = CORDIC_AG;
3065 signtheta = (theta < 0) ? -1 : 1;
3067 ((theta + FIXED(180) * signtheta) % FIXED(360)) -
3068 FIXED(180) * signtheta;
3070 if (FLOAT(theta) > 90) {
3071 theta -= FIXED(180);
3073 } else if (FLOAT(theta) < -90) {
3074 theta += FIXED(180);
3078 for (iter = 0; iter < CORDIC_NI; iter++) {
3079 if (theta > angle) {
3080 valtmp = val[0].i - (val[0].q >> iter);
3081 val[0].q = (val[0].i >> iter) + val[0].q;
3083 angle += AtanTbl[iter];
3085 valtmp = val[0].i + (val[0].q >> iter);
3086 val[0].q = -(val[0].i >> iter) + val[0].q;
3088 angle -= AtanTbl[iter];
3092 val[0].i = val[0].i * signx;
3093 val[0].q = val[0].q * signx;
3096 void wlc_phy_cal_perical_mphase_reset(phy_info_t *pi)
3098 wlapi_del_timer(pi->sh->physhim, pi->phycal_timer);
3100 pi->cal_type_override = PHY_PERICAL_AUTO;
3101 pi->mphase_cal_phase_id = MPHASE_CAL_STATE_IDLE;
3102 pi->mphase_txcal_cmdidx = 0;
3105 static void wlc_phy_cal_perical_mphase_schedule(phy_info_t *pi, uint delay)
3108 if ((pi->nphy_perical != PHY_PERICAL_MPHASE) &&
3109 (pi->nphy_perical != PHY_PERICAL_MANUAL))
3112 wlapi_del_timer(pi->sh->physhim, pi->phycal_timer);
3114 pi->mphase_cal_phase_id = MPHASE_CAL_STATE_INIT;
3115 wlapi_add_timer(pi->sh->physhim, pi->phycal_timer, delay, 0);
3118 void wlc_phy_cal_perical(wlc_phy_t *pih, u8 reason)
3120 s16 nphy_currtemp = 0;
3122 bool do_periodic_cal = true;
3123 phy_info_t *pi = (phy_info_t *) pih;
3128 if ((pi->nphy_perical == PHY_PERICAL_DISABLE) ||
3129 (pi->nphy_perical == PHY_PERICAL_MANUAL))
3133 case PHY_PERICAL_DRIVERUP:
3136 case PHY_PERICAL_PHYINIT:
3137 if (pi->nphy_perical == PHY_PERICAL_MPHASE) {
3138 if (PHY_PERICAL_MPHASE_PENDING(pi)) {
3139 wlc_phy_cal_perical_mphase_reset(pi);
3141 wlc_phy_cal_perical_mphase_schedule(pi,
3142 PHY_PERICAL_INIT_DELAY);
3146 case PHY_PERICAL_JOIN_BSS:
3147 case PHY_PERICAL_START_IBSS:
3148 case PHY_PERICAL_UP_BSS:
3149 if ((pi->nphy_perical == PHY_PERICAL_MPHASE) &&
3150 PHY_PERICAL_MPHASE_PENDING(pi)) {
3151 wlc_phy_cal_perical_mphase_reset(pi);
3154 pi->first_cal_after_assoc = true;
3156 pi->cal_type_override = PHY_PERICAL_FULL;
3158 if (pi->phycal_tempdelta) {
3159 pi->nphy_lastcal_temp = wlc_phy_tempsense_nphy(pi);
3161 wlc_phy_cal_perical_nphy_run(pi, PHY_PERICAL_FULL);
3164 case PHY_PERICAL_WATCHDOG:
3165 if (pi->phycal_tempdelta) {
3166 nphy_currtemp = wlc_phy_tempsense_nphy(pi);
3168 (nphy_currtemp > pi->nphy_lastcal_temp) ?
3169 nphy_currtemp - pi->nphy_lastcal_temp :
3170 pi->nphy_lastcal_temp - nphy_currtemp;
3172 if ((delta_temp < (s16) pi->phycal_tempdelta) &&
3173 (pi->nphy_txiqlocal_chanspec ==
3174 pi->radio_chanspec)) {
3175 do_periodic_cal = false;
3177 pi->nphy_lastcal_temp = nphy_currtemp;
3181 if (do_periodic_cal) {
3183 if (pi->nphy_perical == PHY_PERICAL_MPHASE) {
3185 if (!PHY_PERICAL_MPHASE_PENDING(pi))
3186 wlc_phy_cal_perical_mphase_schedule(pi,
3187 PHY_PERICAL_WDOG_DELAY);
3188 } else if (pi->nphy_perical == PHY_PERICAL_SPHASE)
3189 wlc_phy_cal_perical_nphy_run(pi,
3202 void wlc_phy_cal_perical_mphase_restart(phy_info_t *pi)
3204 pi->mphase_cal_phase_id = MPHASE_CAL_STATE_INIT;
3205 pi->mphase_txcal_cmdidx = 0;
3208 u8 wlc_phy_nbits(s32 value)
3213 abs_val = ABS(value);
3214 while ((abs_val >> nbits) > 0)
3220 u32 wlc_phy_sqrt_int(u32 value)
3222 u32 root = 0, shift = 0;
3224 for (shift = 0; shift < 32; shift += 2) {
3225 if (((0x40000000 >> shift) + root) <= value) {
3226 value -= ((0x40000000 >> shift) + root);
3227 root = (root >> 1) | (0x40000000 >> shift);
3239 void wlc_phy_stf_chain_init(wlc_phy_t *pih, u8 txchain, u8 rxchain)
3241 phy_info_t *pi = (phy_info_t *) pih;
3243 pi->sh->hw_phytxchain = txchain;
3244 pi->sh->hw_phyrxchain = rxchain;
3245 pi->sh->phytxchain = txchain;
3246 pi->sh->phyrxchain = rxchain;
3247 pi->pubpi.phy_corenum = (u8) PHY_BITSCNT(pi->sh->phyrxchain);
3250 void wlc_phy_stf_chain_set(wlc_phy_t *pih, u8 txchain, u8 rxchain)
3252 phy_info_t *pi = (phy_info_t *) pih;
3254 pi->sh->phytxchain = txchain;
3257 wlc_phy_rxcore_setstate_nphy(pih, rxchain);
3259 pi->pubpi.phy_corenum = (u8) PHY_BITSCNT(pi->sh->phyrxchain);
3262 void wlc_phy_stf_chain_get(wlc_phy_t *pih, u8 *txchain, u8 *rxchain)
3264 phy_info_t *pi = (phy_info_t *) pih;
3266 *txchain = pi->sh->phytxchain;
3267 *rxchain = pi->sh->phyrxchain;
3270 u8 wlc_phy_stf_chain_active_get(wlc_phy_t *pih)
3274 phy_info_t *pi = (phy_info_t *) pih;
3276 active_bitmap = (pi->phy_txcore_heatedup) ? 0x31 : 0x33;
3278 if (!pi->watchdog_override)
3279 return active_bitmap;
3281 if (NREV_GE(pi->pubpi.phy_rev, 6)) {
3282 wlapi_suspend_mac_and_wait(pi->sh->physhim);
3283 nphy_currtemp = wlc_phy_tempsense_nphy(pi);
3284 wlapi_enable_mac(pi->sh->physhim);
3286 if (!pi->phy_txcore_heatedup) {
3287 if (nphy_currtemp >= pi->phy_txcore_disable_temp) {
3288 active_bitmap &= 0xFD;
3289 pi->phy_txcore_heatedup = true;
3292 if (nphy_currtemp <= pi->phy_txcore_enable_temp) {
3293 active_bitmap |= 0x2;
3294 pi->phy_txcore_heatedup = false;
3299 return active_bitmap;
3302 s8 wlc_phy_stf_ssmode_get(wlc_phy_t *pih, chanspec_t chanspec)
3304 phy_info_t *pi = (phy_info_t *) pih;
3305 u8 siso_mcs_id, cdd_mcs_id;
3308 (CHSPEC_IS40(chanspec)) ? TXP_FIRST_MCS_40_SISO :
3309 TXP_FIRST_MCS_20_SISO;
3311 (CHSPEC_IS40(chanspec)) ? TXP_FIRST_MCS_40_CDD :
3312 TXP_FIRST_MCS_20_CDD;
3314 if (pi->tx_power_target[siso_mcs_id] >
3315 (pi->tx_power_target[cdd_mcs_id] + 12))
3316 return PHY_TXC1_MODE_SISO;
3318 return PHY_TXC1_MODE_CDD;
3321 const u8 *wlc_phy_get_ofdm_rate_lookup(void)
3323 return ofdm_rate_lookup;
3326 void wlc_lcnphy_epa_switch(phy_info_t *pi, bool mode)
3328 if ((CHIPID(pi->sh->chip) == BCM4313_CHIP_ID) &&
3329 (pi->sh->boardflags & BFL_FEM)) {
3332 txant = wlapi_bmac_get_txant(pi->sh->physhim);
3334 mod_phy_reg(pi, 0x44d, (0x1 << 2), (1) << 2);
3336 mod_phy_reg(pi, 0x44c, (0x1 << 2), (1) << 2);
3339 si_corereg(pi->sh->sih, SI_CC_IDX,
3340 offsetof(chipcregs_t, gpiocontrol), ~0x0,
3342 si_corereg(pi->sh->sih, SI_CC_IDX,
3343 offsetof(chipcregs_t, gpioout), 0x40, 0x40);
3344 si_corereg(pi->sh->sih, SI_CC_IDX,
3345 offsetof(chipcregs_t, gpioouten), 0x40,
3348 mod_phy_reg(pi, 0x44c, (0x1 << 2), (0) << 2);
3350 mod_phy_reg(pi, 0x44d, (0x1 << 2), (0) << 2);
3352 si_corereg(pi->sh->sih, SI_CC_IDX,
3353 offsetof(chipcregs_t, gpioout), 0x40, 0x00);
3354 si_corereg(pi->sh->sih, SI_CC_IDX,
3355 offsetof(chipcregs_t, gpioouten), 0x40, 0x0);
3356 si_corereg(pi->sh->sih, SI_CC_IDX,
3357 offsetof(chipcregs_t, gpiocontrol), ~0x0,
3364 wlc_user_txpwr_antport_to_rfport(phy_info_t *pi, uint chan, u32 band,
3369 if (!pi->user_txpwr_at_rfport)
3374 static s8 wlc_phy_env_measure_vbat(phy_info_t *pi)
3377 return wlc_lcnphy_vbatsense(pi, 0);
3382 static s8 wlc_phy_env_measure_temperature(phy_info_t *pi)
3385 return wlc_lcnphy_tempsense_degree(pi, 0);
3390 static void wlc_phy_upd_env_txpwr_rate_limits(phy_info_t *pi, u32 band)
3395 for (i = 0; i < TXP_NUM_RATES; i++)
3396 pi->txpwr_env_limit[i] = WLC_TXPWR_MAX;
3398 vbat = wlc_phy_env_measure_vbat(pi);
3399 temp = wlc_phy_env_measure_temperature(pi);
3403 void wlc_phy_ldpc_override_set(wlc_phy_t *ppi, bool ldpc)
3409 wlc_phy_get_pwrdet_offsets(phy_info_t *pi, s8 *cckoffset, s8 *ofdmoffset)
3415 u32 wlc_phy_qdiv_roundup(u32 dividend, u32 divisor, u8 precision)
3417 u32 quotient, remainder, roundup, rbit;
3421 quotient = dividend / divisor;
3422 remainder = dividend % divisor;
3424 roundup = (divisor >> 1) + rbit;
3426 while (precision--) {
3428 if (remainder >= roundup) {
3430 remainder = ((remainder - roundup) << 1) + rbit;
3436 if (remainder >= roundup)
3442 s8 wlc_phy_upd_rssi_offset(phy_info_t *pi, s8 rssi, chanspec_t chanspec)
3448 bool wlc_phy_txpower_ipa_ison(wlc_phy_t *ppi)
3450 phy_info_t *pi = (phy_info_t *) ppi;
3453 return wlc_phy_n_txpower_ipa_ison(pi);