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>
23 #include <linux/module.h>
24 #include <linux/pci.h>
25 #include <bcmendian.h>
32 #include <wlc_phy_int.h>
33 #include <wlc_phyreg_n.h>
34 #include <wlc_phy_radio.h>
35 #include <wlc_phy_lcn.h>
37 u32 phyhal_msg_level = PHYHAL_ERROR;
39 typedef struct _chan_info_basic {
44 static chan_info_basic_t chan_info_all[] = {
104 u16 ltrn_list[PHY_LTRN_LIST_LEN] = {
105 0x18f9, 0x0d01, 0x00e4, 0xdef4, 0x06f1, 0x0ffc,
106 0xfa27, 0x1dff, 0x10f0, 0x0918, 0xf20a, 0xe010,
107 0x1417, 0x1104, 0xf114, 0xf2fa, 0xf7db, 0xe2fc,
108 0xe1fb, 0x13ee, 0xff0d, 0xe91c, 0x171a, 0x0318,
109 0xda00, 0x03e8, 0x17e6, 0xe9e4, 0xfff3, 0x1312,
110 0xe105, 0xe204, 0xf725, 0xf206, 0xf1ec, 0x11fc,
111 0x14e9, 0xe0f0, 0xf2f6, 0x09e8, 0x1010, 0x1d01,
112 0xfad9, 0x0f04, 0x060f, 0xde0c, 0x001c, 0x0dff,
113 0x1807, 0xf61a, 0xe40e, 0x0f16, 0x05f9, 0x18ec,
114 0x0a1b, 0xff1e, 0x2600, 0xffe2, 0x0ae5, 0x1814,
115 0x0507, 0x0fea, 0xe4f2, 0xf6e6
118 const u8 ofdm_rate_lookup[] = {
130 #define PHY_WREG_LIMIT 24
132 static void wlc_set_phy_uninitted(phy_info_t *pi);
133 static u32 wlc_phy_get_radio_ver(phy_info_t *pi);
134 static void wlc_phy_timercb_phycal(void *arg);
136 static bool wlc_phy_noise_calc_phy(phy_info_t *pi, u32 *cmplx_pwr,
139 static void wlc_phy_cal_perical_mphase_schedule(phy_info_t *pi, uint delay);
140 static void wlc_phy_noise_cb(phy_info_t *pi, u8 channel, s8 noise_dbm);
141 static void wlc_phy_noise_sample_request(wlc_phy_t *pih, u8 reason,
144 static void wlc_phy_txpower_reg_limit_calc(phy_info_t *pi,
145 struct txpwr_limits *tp, chanspec_t);
146 static bool wlc_phy_cal_txpower_recalc_sw(phy_info_t *pi);
148 static s8 wlc_user_txpwr_antport_to_rfport(phy_info_t *pi, uint chan,
150 static void wlc_phy_upd_env_txpwr_rate_limits(phy_info_t *pi, u32 band);
151 static s8 wlc_phy_env_measure_vbat(phy_info_t *pi);
152 static s8 wlc_phy_env_measure_temperature(phy_info_t *pi);
154 char *phy_getvar(phy_info_t *pi, const char *name)
156 char *vars = pi->vars;
160 ASSERT(pi->vars != (char *)&pi->vars);
169 for (s = vars; s && *s;) {
170 if ((bcmp(s, name, len) == 0) && (s[len] == '='))
177 return nvram_get(name);
180 int phy_getintvar(phy_info_t *pi, const char *name)
184 val = PHY_GETVAR(pi, name);
188 return simple_strtoul(val, NULL, 0);
191 void wlc_phyreg_enter(wlc_phy_t *pih)
193 phy_info_t *pi = (phy_info_t *) pih;
194 wlapi_bmac_ucode_wake_override_phyreg_set(pi->sh->physhim);
197 void wlc_phyreg_exit(wlc_phy_t *pih)
199 phy_info_t *pi = (phy_info_t *) pih;
200 wlapi_bmac_ucode_wake_override_phyreg_clear(pi->sh->physhim);
203 void wlc_radioreg_enter(wlc_phy_t *pih)
205 phy_info_t *pi = (phy_info_t *) pih;
206 wlapi_bmac_mctrl(pi->sh->physhim, MCTL_LOCK_RADIO, MCTL_LOCK_RADIO);
211 void wlc_radioreg_exit(wlc_phy_t *pih)
213 phy_info_t *pi = (phy_info_t *) pih;
216 dummy = R_REG(pi->sh->osh, &pi->regs->phyversion);
218 wlapi_bmac_mctrl(pi->sh->physhim, MCTL_LOCK_RADIO, 0);
221 u16 read_radio_reg(phy_info_t *pi, u16 addr)
225 if ((addr == RADIO_IDCODE))
228 if (NORADIO_ENAB(pi->pubpi))
229 return NORADIO_IDCODE & 0xffff;
231 switch (pi->pubpi.phy_type) {
233 CASECHECK(PHYTYPE, PHY_TYPE_N);
234 if (NREV_GE(pi->pubpi.phy_rev, 7))
235 addr |= RADIO_2057_READ_OFF;
237 addr |= RADIO_2055_READ_OFF;
241 CASECHECK(PHYTYPE, PHY_TYPE_LCN);
242 addr |= RADIO_2064_READ_OFF;
246 ASSERT(VALID_PHYTYPE(pi->pubpi.phy_type));
249 if ((D11REV_GE(pi->sh->corerev, 24)) ||
250 (D11REV_IS(pi->sh->corerev, 22)
251 && (pi->pubpi.phy_type != PHY_TYPE_SSN))) {
252 W_REG(pi->sh->osh, &pi->regs->radioregaddr, addr);
254 (void)R_REG(pi->sh->osh, &pi->regs->radioregaddr);
256 data = R_REG(pi->sh->osh, &pi->regs->radioregdata);
258 W_REG(pi->sh->osh, &pi->regs->phy4waddr, addr);
260 (void)R_REG(pi->sh->osh, &pi->regs->phy4waddr);
263 #ifdef __ARM_ARCH_4T__
264 __asm__(" .align 4 ");
266 data = R_REG(pi->sh->osh, &pi->regs->phy4wdatalo);
268 data = R_REG(pi->sh->osh, &pi->regs->phy4wdatalo);
277 void write_radio_reg(phy_info_t *pi, u16 addr, u16 val)
279 struct osl_info *osh;
281 if (NORADIO_ENAB(pi->pubpi))
286 if ((D11REV_GE(pi->sh->corerev, 24)) ||
287 (D11REV_IS(pi->sh->corerev, 22)
288 && (pi->pubpi.phy_type != PHY_TYPE_SSN))) {
290 W_REG(osh, &pi->regs->radioregaddr, addr);
292 (void)R_REG(osh, &pi->regs->radioregaddr);
294 W_REG(osh, &pi->regs->radioregdata, val);
296 W_REG(osh, &pi->regs->phy4waddr, addr);
298 (void)R_REG(osh, &pi->regs->phy4waddr);
300 W_REG(osh, &pi->regs->phy4wdatalo, val);
303 if (pi->sh->bustype == PCI_BUS) {
304 if (++pi->phy_wreg >= pi->phy_wreg_limit) {
305 (void)R_REG(osh, &pi->regs->maccontrol);
311 static u32 read_radio_id(phy_info_t *pi)
315 if (NORADIO_ENAB(pi->pubpi))
316 return NORADIO_IDCODE;
318 if (D11REV_GE(pi->sh->corerev, 24)) {
321 W_REG(pi->sh->osh, &pi->regs->radioregaddr, 0);
323 (void)R_REG(pi->sh->osh, &pi->regs->radioregaddr);
325 b0 = (u32) R_REG(pi->sh->osh, &pi->regs->radioregdata);
326 W_REG(pi->sh->osh, &pi->regs->radioregaddr, 1);
328 (void)R_REG(pi->sh->osh, &pi->regs->radioregaddr);
330 b1 = (u32) R_REG(pi->sh->osh, &pi->regs->radioregdata);
331 W_REG(pi->sh->osh, &pi->regs->radioregaddr, 2);
333 (void)R_REG(pi->sh->osh, &pi->regs->radioregaddr);
335 b2 = (u32) R_REG(pi->sh->osh, &pi->regs->radioregdata);
337 id = ((b0 & 0xf) << 28) | (((b2 << 8) | b1) << 12) | ((b0 >> 4)
340 W_REG(pi->sh->osh, &pi->regs->phy4waddr, RADIO_IDCODE);
342 (void)R_REG(pi->sh->osh, &pi->regs->phy4waddr);
344 id = (u32) R_REG(pi->sh->osh, &pi->regs->phy4wdatalo);
345 id |= (u32) R_REG(pi->sh->osh, &pi->regs->phy4wdatahi) << 16;
351 void and_radio_reg(phy_info_t *pi, u16 addr, u16 val)
355 if (NORADIO_ENAB(pi->pubpi))
358 rval = read_radio_reg(pi, addr);
359 write_radio_reg(pi, addr, (rval & val));
362 void or_radio_reg(phy_info_t *pi, u16 addr, u16 val)
366 if (NORADIO_ENAB(pi->pubpi))
369 rval = read_radio_reg(pi, addr);
370 write_radio_reg(pi, addr, (rval | val));
373 void xor_radio_reg(phy_info_t *pi, u16 addr, u16 mask)
377 if (NORADIO_ENAB(pi->pubpi))
380 rval = read_radio_reg(pi, addr);
381 write_radio_reg(pi, addr, (rval ^ mask));
384 void mod_radio_reg(phy_info_t *pi, u16 addr, u16 mask, u16 val)
388 if (NORADIO_ENAB(pi->pubpi))
391 rval = read_radio_reg(pi, addr);
392 write_radio_reg(pi, addr, (rval & ~mask) | (val & mask));
395 void write_phy_channel_reg(phy_info_t *pi, uint val)
397 W_REG(pi->sh->osh, &pi->regs->phychannel, val);
401 static bool wlc_phy_war41476(phy_info_t *pi)
403 u32 mc = R_REG(pi->sh->osh, &pi->regs->maccontrol);
405 return ((mc & MCTL_EN_MAC) == 0)
406 || ((mc & MCTL_PHYLOCK) == MCTL_PHYLOCK);
410 u16 read_phy_reg(phy_info_t *pi, u16 addr)
412 struct osl_info *osh;
418 W_REG(osh, ®s->phyregaddr, addr);
420 (void)R_REG(osh, ®s->phyregaddr);
424 (D11REV_IS(pi->sh->corerev, 11)
425 || D11REV_IS(pi->sh->corerev, 12)) || wlc_phy_war41476(pi));
428 return R_REG(osh, ®s->phyregdata);
431 void write_phy_reg(phy_info_t *pi, u16 addr, u16 val)
433 struct osl_info *osh;
440 W_REG(osh, ®s->phyregaddr, addr);
441 (void)R_REG(osh, ®s->phyregaddr);
442 W_REG(osh, ®s->phyregdata, val);
444 (void)R_REG(osh, ®s->phyregdata);
446 W_REG(osh, (volatile u32 *)(®s->phyregaddr),
448 if (pi->sh->bustype == PCI_BUS) {
449 if (++pi->phy_wreg >= pi->phy_wreg_limit) {
451 (void)R_REG(osh, ®s->phyversion);
457 void and_phy_reg(phy_info_t *pi, u16 addr, u16 val)
459 struct osl_info *osh;
465 W_REG(osh, ®s->phyregaddr, addr);
467 (void)R_REG(osh, ®s->phyregaddr);
471 (D11REV_IS(pi->sh->corerev, 11)
472 || D11REV_IS(pi->sh->corerev, 12)) || wlc_phy_war41476(pi));
474 W_REG(osh, ®s->phyregdata, (R_REG(osh, ®s->phyregdata) & val));
478 void or_phy_reg(phy_info_t *pi, u16 addr, u16 val)
480 struct osl_info *osh;
486 W_REG(osh, ®s->phyregaddr, addr);
488 (void)R_REG(osh, ®s->phyregaddr);
492 (D11REV_IS(pi->sh->corerev, 11)
493 || D11REV_IS(pi->sh->corerev, 12)) || wlc_phy_war41476(pi));
495 W_REG(osh, ®s->phyregdata, (R_REG(osh, ®s->phyregdata) | val));
499 void mod_phy_reg(phy_info_t *pi, u16 addr, u16 mask, u16 val)
501 struct osl_info *osh;
507 W_REG(osh, ®s->phyregaddr, addr);
509 (void)R_REG(osh, ®s->phyregaddr);
513 (D11REV_IS(pi->sh->corerev, 11)
514 || D11REV_IS(pi->sh->corerev, 12)) || wlc_phy_war41476(pi));
516 W_REG(osh, ®s->phyregdata,
517 ((R_REG(osh, ®s->phyregdata) & ~mask) | (val & mask)));
521 static void WLBANDINITFN(wlc_set_phy_uninitted) (phy_info_t *pi)
525 pi->initialized = false;
528 pi->nrssi_table_delta = 0x7fffffff;
530 pi->mintxbias = 0xffff;
533 pi->phy_spuravoid = SPURAVOID_DISABLE;
535 if (NREV_GE(pi->pubpi.phy_rev, 3)
536 && NREV_LT(pi->pubpi.phy_rev, 7))
537 pi->phy_spuravoid = SPURAVOID_AUTO;
539 pi->nphy_papd_skip = 0;
540 pi->nphy_papd_epsilon_offset[0] = 0xf588;
541 pi->nphy_papd_epsilon_offset[1] = 0xf588;
542 pi->nphy_txpwr_idx[0] = 128;
543 pi->nphy_txpwr_idx[1] = 128;
544 pi->nphy_txpwrindex[0].index_internal = 40;
545 pi->nphy_txpwrindex[1].index_internal = 40;
548 pi->phy_spuravoid = SPURAVOID_AUTO;
550 pi->radiopwr = 0xffff;
551 for (i = 0; i < STATIC_NUM_RF; i++) {
552 for (j = 0; j < STATIC_NUM_BB; j++) {
553 pi->stats_11b_txpower[i][j] = -1;
558 shared_phy_t *wlc_phy_shared_attach(shared_phy_params_t *shp)
562 sh = kzalloc(sizeof(shared_phy_t), GFP_ATOMIC);
569 sh->physhim = shp->physhim;
570 sh->unit = shp->unit;
571 sh->corerev = shp->corerev;
575 sh->chip = shp->chip;
576 sh->chiprev = shp->chiprev;
577 sh->chippkg = shp->chippkg;
578 sh->sromrev = shp->sromrev;
579 sh->boardtype = shp->boardtype;
580 sh->boardrev = shp->boardrev;
581 sh->boardvendor = shp->boardvendor;
582 sh->boardflags = shp->boardflags;
583 sh->boardflags2 = shp->boardflags2;
584 sh->bustype = shp->bustype;
585 sh->buscorerev = shp->buscorerev;
587 sh->fast_timer = PHY_SW_TIMER_FAST;
588 sh->slow_timer = PHY_SW_TIMER_SLOW;
589 sh->glacial_timer = PHY_SW_TIMER_GLACIAL;
591 sh->rssi_mode = RSSI_ANT_MERGE_MAX;
596 void wlc_phy_shared_detach(shared_phy_t *phy_sh)
598 struct osl_info *osh;
603 if (phy_sh->phy_head) {
604 ASSERT(!phy_sh->phy_head);
610 wlc_phy_t *wlc_phy_attach(shared_phy_t *sh, void *regs, int bandtype, char *vars)
616 struct osl_info *osh;
620 if (D11REV_IS(sh->corerev, 4))
621 sflags = SISF_2G_PHY | SISF_5G_PHY;
623 sflags = si_core_sflags(sh->sih, 0, 0);
625 if (BAND_5G(bandtype)) {
626 if ((sflags & (SISF_5G_PHY | SISF_DB_PHY)) == 0) {
632 if ((sflags & SISF_DB_PHY) && pi) {
634 wlapi_bmac_corereset(pi->sh->physhim, pi->pubpi.coreflags);
636 return &pi->pubpi_ro;
639 pi = kzalloc(sizeof(phy_info_t), GFP_ATOMIC);
643 pi->regs = (d11regs_t *) regs;
645 pi->phy_init_por = true;
646 pi->phy_wreg_limit = PHY_WREG_LIMIT;
650 pi->txpwr_percent = 100;
652 pi->do_initcal = true;
654 pi->phycal_tempdelta = 0;
656 if (BAND_2G(bandtype) && (sflags & SISF_2G_PHY)) {
658 pi->pubpi.coreflags = SICF_GMODE;
661 wlapi_bmac_corereset(pi->sh->physhim, pi->pubpi.coreflags);
662 phyversion = R_REG(osh, &pi->regs->phyversion);
664 pi->pubpi.phy_type = PHY_TYPE(phyversion);
665 pi->pubpi.phy_rev = phyversion & PV_PV_MASK;
667 if (pi->pubpi.phy_type == PHY_TYPE_LCNXN) {
668 pi->pubpi.phy_type = PHY_TYPE_N;
669 pi->pubpi.phy_rev += LCNXN_BASEREV;
671 pi->pubpi.phy_corenum = PHY_CORE_NUM_2;
672 pi->pubpi.ana_rev = (phyversion & PV_AV_MASK) >> PV_AV_SHIFT;
674 if (!VALID_PHYTYPE(pi->pubpi.phy_type)) {
677 if (BAND_5G(bandtype)) {
682 if (!ISNPHY(pi) && !ISLCNPHY(pi)) {
687 if (ISSIM_ENAB(pi->sh->sih)) {
688 pi->pubpi.radioid = NORADIO_ID;
689 pi->pubpi.radiorev = 5;
693 wlc_phy_anacore((wlc_phy_t *) pi, ON);
695 idcode = wlc_phy_get_radio_ver(pi);
697 (idcode & IDCODE_ID_MASK) >> IDCODE_ID_SHIFT;
699 (idcode & IDCODE_REV_MASK) >> IDCODE_REV_SHIFT;
701 (idcode & IDCODE_VER_MASK) >> IDCODE_VER_SHIFT;
702 if (!VALID_RADIO(pi, pi->pubpi.radioid)) {
706 wlc_phy_switch_radio((wlc_phy_t *) pi, OFF);
709 wlc_set_phy_uninitted(pi);
711 pi->bw = WL_CHANSPEC_BW_20;
713 BAND_2G(bandtype) ? CH20MHZ_CHSPEC(1) : CH20MHZ_CHSPEC(36);
715 pi->rxiq_samps = PHY_NOISE_SAMPLE_LOG_NUM_NPHY;
716 pi->rxiq_antsel = ANT_RX_DIV_DEF;
718 pi->watchdog_override = true;
720 pi->cal_type_override = PHY_PERICAL_AUTO;
722 pi->nphy_saved_noisevars.bufcount = 0;
725 pi->min_txpower = PHY_TXPWR_MIN_NPHY;
727 pi->min_txpower = PHY_TXPWR_MIN;
729 pi->sh->phyrxchain = 0x3;
731 pi->rx2tx_biasentry = -1;
733 pi->phy_txcore_disable_temp = PHY_CHAIN_TX_DISABLE_TEMP;
734 pi->phy_txcore_enable_temp =
735 PHY_CHAIN_TX_DISABLE_TEMP - PHY_HYSTERESIS_DELTATEMP;
736 pi->phy_tempsense_offset = 0;
737 pi->phy_txcore_heatedup = false;
739 pi->nphy_lastcal_temp = -50;
741 pi->phynoise_polling = true;
742 if (ISNPHY(pi) || ISLCNPHY(pi))
743 pi->phynoise_polling = false;
745 for (i = 0; i < TXP_NUM_RATES; i++) {
746 pi->txpwr_limit[i] = WLC_TXPWR_MAX;
747 pi->txpwr_env_limit[i] = WLC_TXPWR_MAX;
748 pi->tx_user_target[i] = WLC_TXPWR_MAX;
751 pi->radiopwr_override = RADIOPWR_OVERRIDE_DEF;
753 pi->user_txpwr_at_rfport = false;
757 pi->phycal_timer = wlapi_init_timer(pi->sh->physhim,
758 wlc_phy_timercb_phycal,
760 if (!pi->phycal_timer) {
764 if (!wlc_phy_attach_nphy(pi))
767 } else if (ISLCNPHY(pi)) {
768 if (!wlc_phy_attach_lcnphy(pi))
776 pi->next = pi->sh->phy_head;
779 pi->vars = (char *)&pi->vars;
781 bcopy(&pi->pubpi, &pi->pubpi_ro, sizeof(wlc_phy_t));
783 return &pi->pubpi_ro;
791 void wlc_phy_detach(wlc_phy_t *pih)
793 phy_info_t *pi = (phy_info_t *) pih;
800 if (pi->phycal_timer) {
801 wlapi_free_timer(pi->sh->physhim, pi->phycal_timer);
802 pi->phycal_timer = NULL;
805 if (pi->sh->phy_head == pi)
806 pi->sh->phy_head = pi->next;
807 else if (pi->sh->phy_head->next == pi)
808 pi->sh->phy_head->next = NULL;
812 if (pi->pi_fptr.detach)
813 (pi->pi_fptr.detach) (pi);
820 wlc_phy_get_phyversion(wlc_phy_t *pih, u16 *phytype, u16 *phyrev,
821 u16 *radioid, u16 *radiover)
823 phy_info_t *pi = (phy_info_t *) pih;
824 *phytype = (u16) pi->pubpi.phy_type;
825 *phyrev = (u16) pi->pubpi.phy_rev;
826 *radioid = pi->pubpi.radioid;
827 *radiover = pi->pubpi.radiorev;
832 bool wlc_phy_get_encore(wlc_phy_t *pih)
834 phy_info_t *pi = (phy_info_t *) pih;
835 return pi->pubpi.abgphy_encore;
838 u32 wlc_phy_get_coreflags(wlc_phy_t *pih)
840 phy_info_t *pi = (phy_info_t *) pih;
841 return pi->pubpi.coreflags;
844 static void wlc_phy_timercb_phycal(void *arg)
846 phy_info_t *pi = (phy_info_t *) arg;
849 if (PHY_PERICAL_MPHASE_PENDING(pi)) {
851 wlc_phy_cal_perical_mphase_reset(pi);
855 if (SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi)) {
858 wlc_phy_cal_perical_mphase_restart(pi);
860 wlc_phy_cal_perical_nphy_run(pi, PHY_PERICAL_AUTO);
861 wlapi_add_timer(pi->sh->physhim, pi->phycal_timer, delay, 0);
867 void wlc_phy_anacore(wlc_phy_t *pih, bool on)
869 phy_info_t *pi = (phy_info_t *) pih;
873 if (NREV_GE(pi->pubpi.phy_rev, 3)) {
874 write_phy_reg(pi, 0xa6, 0x0d);
875 write_phy_reg(pi, 0x8f, 0x0);
876 write_phy_reg(pi, 0xa7, 0x0d);
877 write_phy_reg(pi, 0xa5, 0x0);
879 write_phy_reg(pi, 0xa5, 0x0);
882 if (NREV_GE(pi->pubpi.phy_rev, 3)) {
883 write_phy_reg(pi, 0x8f, 0x07ff);
884 write_phy_reg(pi, 0xa6, 0x0fd);
885 write_phy_reg(pi, 0xa5, 0x07ff);
886 write_phy_reg(pi, 0xa7, 0x0fd);
888 write_phy_reg(pi, 0xa5, 0x7fff);
891 } else if (ISLCNPHY(pi)) {
893 and_phy_reg(pi, 0x43b,
894 ~((0x1 << 0) | (0x1 << 1) | (0x1 << 2)));
896 or_phy_reg(pi, 0x43c,
897 (0x1 << 0) | (0x1 << 1) | (0x1 << 2));
898 or_phy_reg(pi, 0x43b,
899 (0x1 << 0) | (0x1 << 1) | (0x1 << 2));
904 u32 wlc_phy_clk_bwbits(wlc_phy_t *pih)
906 phy_info_t *pi = (phy_info_t *) pih;
908 u32 phy_bw_clkbits = 0;
910 if (pi && (ISNPHY(pi) || ISLCNPHY(pi))) {
912 case WL_CHANSPEC_BW_10:
913 phy_bw_clkbits = SICF_BW10;
915 case WL_CHANSPEC_BW_20:
916 phy_bw_clkbits = SICF_BW20;
918 case WL_CHANSPEC_BW_40:
919 phy_bw_clkbits = SICF_BW40;
927 return phy_bw_clkbits;
930 void WLBANDINITFN(wlc_phy_por_inform) (wlc_phy_t *ppi)
932 phy_info_t *pi = (phy_info_t *) ppi;
934 pi->phy_init_por = true;
937 void wlc_phy_edcrs_lock(wlc_phy_t *pih, bool lock)
939 phy_info_t *pi = (phy_info_t *) pih;
941 pi->edcrs_threshold_lock = lock;
943 write_phy_reg(pi, 0x22c, 0x46b);
944 write_phy_reg(pi, 0x22d, 0x46b);
945 write_phy_reg(pi, 0x22e, 0x3c0);
946 write_phy_reg(pi, 0x22f, 0x3c0);
949 void wlc_phy_initcal_enable(wlc_phy_t *pih, bool initcal)
951 phy_info_t *pi = (phy_info_t *) pih;
953 pi->do_initcal = initcal;
956 void wlc_phy_hw_clk_state_upd(wlc_phy_t *pih, bool newstate)
958 phy_info_t *pi = (phy_info_t *) pih;
963 pi->sh->clk = newstate;
966 void wlc_phy_hw_state_upd(wlc_phy_t *pih, bool newstate)
968 phy_info_t *pi = (phy_info_t *) pih;
973 pi->sh->up = newstate;
976 void WLBANDINITFN(wlc_phy_init) (wlc_phy_t *pih, chanspec_t chanspec)
979 initfn_t phy_init = NULL;
980 phy_info_t *pi = (phy_info_t *) pih;
982 if (pi->init_in_progress)
985 pi->init_in_progress = true;
987 pi->radio_chanspec = chanspec;
989 mc = R_REG(pi->sh->osh, &pi->regs->maccontrol);
990 if ((mc & MCTL_EN_MAC) != 0) {
991 ASSERT((const char *)
992 "wlc_phy_init: Called with the MAC running!" == NULL);
997 if (!(pi->measure_hold & PHY_HOLD_FOR_SCAN)) {
998 pi->measure_hold |= PHY_HOLD_FOR_NOT_ASSOC;
1001 if (D11REV_GE(pi->sh->corerev, 5))
1002 ASSERT(si_core_sflags(pi->sh->sih, 0, 0) & SISF_FCLKA);
1004 phy_init = pi->pi_fptr.init;
1006 if (phy_init == NULL) {
1007 ASSERT(phy_init != NULL);
1011 wlc_phy_anacore(pih, ON);
1013 if (CHSPEC_BW(pi->radio_chanspec) != pi->bw)
1014 wlapi_bmac_bw_set(pi->sh->physhim,
1015 CHSPEC_BW(pi->radio_chanspec));
1017 pi->nphy_gain_boost = true;
1019 wlc_phy_switch_radio((wlc_phy_t *) pi, ON);
1023 pi->phy_init_por = false;
1025 if (D11REV_IS(pi->sh->corerev, 11) || D11REV_IS(pi->sh->corerev, 12))
1026 wlc_phy_do_dummy_tx(pi, true, OFF);
1029 wlc_phy_txpower_update_shm(pi);
1031 wlc_phy_ant_rxdiv_set((wlc_phy_t *) pi, pi->sh->rx_antdiv);
1033 pi->init_in_progress = false;
1036 void wlc_phy_cal_init(wlc_phy_t *pih)
1038 phy_info_t *pi = (phy_info_t *) pih;
1039 initfn_t cal_init = NULL;
1041 ASSERT((R_REG(pi->sh->osh, &pi->regs->maccontrol) & MCTL_EN_MAC) == 0);
1043 if (!pi->initialized) {
1044 cal_init = pi->pi_fptr.calinit;
1048 pi->initialized = true;
1052 int wlc_phy_down(wlc_phy_t *pih)
1054 phy_info_t *pi = (phy_info_t *) pih;
1057 ASSERT(pi->phytest_on == false);
1059 if (pi->phycal_timer
1060 && !wlapi_del_timer(pi->sh->physhim, pi->phycal_timer))
1063 pi->nphy_iqcal_chanspec_2G = 0;
1064 pi->nphy_iqcal_chanspec_5G = 0;
1069 static u32 wlc_phy_get_radio_ver(phy_info_t *pi)
1073 ver = read_radio_id(pi);
1079 wlc_phy_table_addr(phy_info_t *pi, uint tbl_id, uint tbl_offset,
1080 u16 tblAddr, u16 tblDataHi, u16 tblDataLo)
1082 write_phy_reg(pi, tblAddr, (tbl_id << 10) | tbl_offset);
1084 pi->tbl_data_hi = tblDataHi;
1085 pi->tbl_data_lo = tblDataLo;
1087 if ((CHIPID(pi->sh->chip) == BCM43224_CHIP_ID ||
1088 CHIPID(pi->sh->chip) == BCM43421_CHIP_ID) &&
1089 (pi->sh->chiprev == 1)) {
1090 pi->tbl_addr = tblAddr;
1091 pi->tbl_save_id = tbl_id;
1092 pi->tbl_save_offset = tbl_offset;
1096 void wlc_phy_table_data_write(phy_info_t *pi, uint width, u32 val)
1098 ASSERT((width == 8) || (width == 16) || (width == 32));
1100 if ((CHIPID(pi->sh->chip) == BCM43224_CHIP_ID ||
1101 CHIPID(pi->sh->chip) == BCM43421_CHIP_ID) &&
1102 (pi->sh->chiprev == 1) &&
1103 (pi->tbl_save_id == NPHY_TBL_ID_ANTSWCTRLLUT)) {
1104 read_phy_reg(pi, pi->tbl_data_lo);
1106 write_phy_reg(pi, pi->tbl_addr,
1107 (pi->tbl_save_id << 10) | pi->tbl_save_offset);
1108 pi->tbl_save_offset++;
1113 write_phy_reg(pi, pi->tbl_data_hi, (u16) (val >> 16));
1114 write_phy_reg(pi, pi->tbl_data_lo, (u16) val);
1117 write_phy_reg(pi, pi->tbl_data_lo, (u16) val);
1122 wlc_phy_write_table(phy_info_t *pi, const phytbl_info_t *ptbl_info,
1123 u16 tblAddr, u16 tblDataHi, u16 tblDataLo)
1126 uint tbl_id = ptbl_info->tbl_id;
1127 uint tbl_offset = ptbl_info->tbl_offset;
1128 uint tbl_width = ptbl_info->tbl_width;
1129 const u8 *ptbl_8b = (const u8 *)ptbl_info->tbl_ptr;
1130 const u16 *ptbl_16b = (const u16 *)ptbl_info->tbl_ptr;
1131 const u32 *ptbl_32b = (const u32 *)ptbl_info->tbl_ptr;
1133 ASSERT((tbl_width == 8) || (tbl_width == 16) || (tbl_width == 32));
1135 write_phy_reg(pi, tblAddr, (tbl_id << 10) | tbl_offset);
1137 for (idx = 0; idx < ptbl_info->tbl_len; idx++) {
1139 if ((CHIPID(pi->sh->chip) == BCM43224_CHIP_ID ||
1140 CHIPID(pi->sh->chip) == BCM43421_CHIP_ID) &&
1141 (pi->sh->chiprev == 1) &&
1142 (tbl_id == NPHY_TBL_ID_ANTSWCTRLLUT)) {
1143 read_phy_reg(pi, tblDataLo);
1145 write_phy_reg(pi, tblAddr,
1146 (tbl_id << 10) | (tbl_offset + idx));
1149 if (tbl_width == 32) {
1151 write_phy_reg(pi, tblDataHi,
1152 (u16) (ptbl_32b[idx] >> 16));
1153 write_phy_reg(pi, tblDataLo, (u16) ptbl_32b[idx]);
1154 } else if (tbl_width == 16) {
1156 write_phy_reg(pi, tblDataLo, ptbl_16b[idx]);
1159 write_phy_reg(pi, tblDataLo, ptbl_8b[idx]);
1165 wlc_phy_read_table(phy_info_t *pi, const phytbl_info_t *ptbl_info,
1166 u16 tblAddr, u16 tblDataHi, u16 tblDataLo)
1169 uint tbl_id = ptbl_info->tbl_id;
1170 uint tbl_offset = ptbl_info->tbl_offset;
1171 uint tbl_width = ptbl_info->tbl_width;
1172 u8 *ptbl_8b = (u8 *)ptbl_info->tbl_ptr;
1173 u16 *ptbl_16b = (u16 *)ptbl_info->tbl_ptr;
1174 u32 *ptbl_32b = (u32 *)ptbl_info->tbl_ptr;
1176 ASSERT((tbl_width == 8) || (tbl_width == 16) || (tbl_width == 32));
1178 write_phy_reg(pi, tblAddr, (tbl_id << 10) | tbl_offset);
1180 for (idx = 0; idx < ptbl_info->tbl_len; idx++) {
1182 if ((CHIPID(pi->sh->chip) == BCM43224_CHIP_ID ||
1183 CHIPID(pi->sh->chip) == BCM43421_CHIP_ID) &&
1184 (pi->sh->chiprev == 1)) {
1185 (void)read_phy_reg(pi, tblDataLo);
1187 write_phy_reg(pi, tblAddr,
1188 (tbl_id << 10) | (tbl_offset + idx));
1191 if (tbl_width == 32) {
1193 ptbl_32b[idx] = read_phy_reg(pi, tblDataLo);
1194 ptbl_32b[idx] |= (read_phy_reg(pi, tblDataHi) << 16);
1195 } else if (tbl_width == 16) {
1197 ptbl_16b[idx] = read_phy_reg(pi, tblDataLo);
1200 ptbl_8b[idx] = (u8) read_phy_reg(pi, tblDataLo);
1206 wlc_phy_init_radio_regs_allbands(phy_info_t *pi, radio_20xx_regs_t *radioregs)
1211 if (radioregs[i].do_init) {
1212 write_radio_reg(pi, radioregs[i].address,
1213 (u16) radioregs[i].init);
1217 } while (radioregs[i].address != 0xffff);
1223 wlc_phy_init_radio_regs(phy_info_t *pi, radio_regs_t *radioregs,
1230 if (CHSPEC_IS5G(pi->radio_chanspec)) {
1231 if (radioregs[i].do_init_a) {
1234 address | core_offset,
1235 (u16) radioregs[i].init_a);
1236 if (ISNPHY(pi) && (++count % 4 == 0))
1237 WLC_PHY_WAR_PR51571(pi);
1240 if (radioregs[i].do_init_g) {
1243 address | core_offset,
1244 (u16) radioregs[i].init_g);
1245 if (ISNPHY(pi) && (++count % 4 == 0))
1246 WLC_PHY_WAR_PR51571(pi);
1251 } while (radioregs[i].address != 0xffff);
1256 void wlc_phy_do_dummy_tx(phy_info_t *pi, bool ofdm, bool pa_on)
1258 #define DUMMY_PKT_LEN 20
1259 d11regs_t *regs = pi->regs;
1261 u8 ofdmpkt[DUMMY_PKT_LEN] = {
1262 0xcc, 0x01, 0x02, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00,
1263 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00
1265 u8 cckpkt[DUMMY_PKT_LEN] = {
1266 0x6e, 0x84, 0x0b, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00,
1267 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00
1271 ASSERT((R_REG(pi->sh->osh, &pi->regs->maccontrol) & MCTL_EN_MAC) == 0);
1273 dummypkt = (u32 *) (ofdm ? ofdmpkt : cckpkt);
1274 wlapi_bmac_write_template_ram(pi->sh->physhim, 0, DUMMY_PKT_LEN,
1277 W_REG(pi->sh->osh, ®s->xmtsel, 0);
1279 if (D11REV_GE(pi->sh->corerev, 11))
1280 W_REG(pi->sh->osh, ®s->wepctl, 0x100);
1282 W_REG(pi->sh->osh, ®s->wepctl, 0);
1284 W_REG(pi->sh->osh, ®s->txe_phyctl, (ofdm ? 1 : 0) | PHY_TXC_ANT_0);
1285 if (ISNPHY(pi) || ISLCNPHY(pi)) {
1287 W_REG(pi->sh->osh, ®s->txe_phyctl1, 0x1A02);
1290 W_REG(pi->sh->osh, ®s->txe_wm_0, 0);
1291 W_REG(pi->sh->osh, ®s->txe_wm_1, 0);
1293 W_REG(pi->sh->osh, ®s->xmttplatetxptr, 0);
1294 W_REG(pi->sh->osh, ®s->xmttxcnt, DUMMY_PKT_LEN);
1296 W_REG(pi->sh->osh, ®s->xmtsel, ((8 << 8) | (1 << 5) | (1 << 2) | 2));
1298 W_REG(pi->sh->osh, ®s->txe_ctl, 0);
1302 wlc_phy_pa_override_nphy(pi, OFF);
1305 if (ISNPHY(pi) || ISLCNPHY(pi))
1306 W_REG(pi->sh->osh, ®s->txe_aux, 0xD0);
1308 W_REG(pi->sh->osh, ®s->txe_aux, ((1 << 5) | (1 << 4)));
1310 (void)R_REG(pi->sh->osh, ®s->txe_aux);
1313 count = ofdm ? 30 : 250;
1315 if (ISSIM_ENAB(pi->sh->sih)) {
1319 while ((i++ < count)
1320 && (R_REG(pi->sh->osh, ®s->txe_status) & (1 << 7))) {
1327 && ((R_REG(pi->sh->osh, ®s->txe_status) & (1 << 10)) == 0)) {
1333 while ((i++ < 10) && ((R_REG(pi->sh->osh, ®s->ifsstat) & (1 << 8)))) {
1338 wlc_phy_pa_override_nphy(pi, ON);
1342 void wlc_phy_hold_upd(wlc_phy_t *pih, mbool id, bool set)
1344 phy_info_t *pi = (phy_info_t *) pih;
1348 mboolset(pi->measure_hold, id);
1350 mboolclr(pi->measure_hold, id);
1356 void wlc_phy_mute_upd(wlc_phy_t *pih, bool mute, mbool flags)
1358 phy_info_t *pi = (phy_info_t *) pih;
1361 mboolset(pi->measure_hold, PHY_HOLD_FOR_MUTE);
1363 mboolclr(pi->measure_hold, PHY_HOLD_FOR_MUTE);
1366 if (!mute && (flags & PHY_MUTE_FOR_PREISM))
1367 pi->nphy_perical_last = pi->sh->now - pi->sh->glacial_timer;
1371 void wlc_phy_clear_tssi(wlc_phy_t *pih)
1373 phy_info_t *pi = (phy_info_t *) pih;
1378 wlapi_bmac_write_shm(pi->sh->physhim, M_B_TSSI_0, NULL_TSSI_W);
1379 wlapi_bmac_write_shm(pi->sh->physhim, M_B_TSSI_1, NULL_TSSI_W);
1380 wlapi_bmac_write_shm(pi->sh->physhim, M_G_TSSI_0, NULL_TSSI_W);
1381 wlapi_bmac_write_shm(pi->sh->physhim, M_G_TSSI_1, NULL_TSSI_W);
1385 static bool wlc_phy_cal_txpower_recalc_sw(phy_info_t *pi)
1390 void wlc_phy_switch_radio(wlc_phy_t *pih, bool on)
1392 phy_info_t *pi = (phy_info_t *) pih;
1394 if (NORADIO_ENAB(pi->pubpi))
1400 mc = R_REG(pi->sh->osh, &pi->regs->maccontrol);
1404 wlc_phy_switch_radio_nphy(pi, on);
1406 } else if (ISLCNPHY(pi)) {
1408 and_phy_reg(pi, 0x44c,
1411 (0x1 << 10) | (0x1 << 11) | (0x1 << 12)));
1412 and_phy_reg(pi, 0x4b0, ~((0x1 << 3) | (0x1 << 11)));
1413 and_phy_reg(pi, 0x4f9, ~(0x1 << 3));
1415 and_phy_reg(pi, 0x44d,
1418 (0x1 << 12) | (0x1 << 13) | (0x1 << 14)));
1419 or_phy_reg(pi, 0x44c,
1422 (0x1 << 10) | (0x1 << 11) | (0x1 << 12));
1424 and_phy_reg(pi, 0x4b7, ~((0x7f << 8)));
1425 and_phy_reg(pi, 0x4b1, ~((0x1 << 13)));
1426 or_phy_reg(pi, 0x4b0, (0x1 << 3) | (0x1 << 11));
1427 and_phy_reg(pi, 0x4fa, ~((0x1 << 3)));
1428 or_phy_reg(pi, 0x4f9, (0x1 << 3));
1433 u16 wlc_phy_bw_state_get(wlc_phy_t *ppi)
1435 phy_info_t *pi = (phy_info_t *) ppi;
1440 void wlc_phy_bw_state_set(wlc_phy_t *ppi, u16 bw)
1442 phy_info_t *pi = (phy_info_t *) ppi;
1447 void wlc_phy_chanspec_radio_set(wlc_phy_t *ppi, chanspec_t newch)
1449 phy_info_t *pi = (phy_info_t *) ppi;
1450 pi->radio_chanspec = newch;
1454 chanspec_t wlc_phy_chanspec_get(wlc_phy_t *ppi)
1456 phy_info_t *pi = (phy_info_t *) ppi;
1458 return pi->radio_chanspec;
1461 void wlc_phy_chanspec_set(wlc_phy_t *ppi, chanspec_t chanspec)
1463 phy_info_t *pi = (phy_info_t *) ppi;
1465 chansetfn_t chanspec_set = NULL;
1467 ASSERT(!wf_chspec_malformed(chanspec));
1469 m_cur_channel = CHSPEC_CHANNEL(chanspec);
1470 if (CHSPEC_IS5G(chanspec))
1471 m_cur_channel |= D11_CURCHANNEL_5G;
1472 if (CHSPEC_IS40(chanspec))
1473 m_cur_channel |= D11_CURCHANNEL_40;
1474 wlapi_bmac_write_shm(pi->sh->physhim, M_CURCHANNEL, m_cur_channel);
1476 chanspec_set = pi->pi_fptr.chanset;
1478 (*chanspec_set) (pi, chanspec);
1482 int wlc_phy_chanspec_freq2bandrange_lpssn(uint freq)
1487 range = WL_CHAN_FREQ_RANGE_2G;
1488 else if (freq <= 5320)
1489 range = WL_CHAN_FREQ_RANGE_5GL;
1490 else if (freq <= 5700)
1491 range = WL_CHAN_FREQ_RANGE_5GM;
1493 range = WL_CHAN_FREQ_RANGE_5GH;
1498 int wlc_phy_chanspec_bandrange_get(phy_info_t *pi, chanspec_t chanspec)
1501 uint channel = CHSPEC_CHANNEL(chanspec);
1502 uint freq = wlc_phy_channel2freq(channel);
1505 range = wlc_phy_get_chan_freq_range_nphy(pi, channel);
1506 } else if (ISLCNPHY(pi)) {
1507 range = wlc_phy_chanspec_freq2bandrange_lpssn(freq);
1514 void wlc_phy_chanspec_ch14_widefilter_set(wlc_phy_t *ppi, bool wide_filter)
1516 phy_info_t *pi = (phy_info_t *) ppi;
1518 pi->channel_14_wide_filter = wide_filter;
1522 int wlc_phy_channel2freq(uint channel)
1526 for (i = 0; i < ARRAY_SIZE(chan_info_all); i++)
1527 if (chan_info_all[i].chan == channel)
1528 return chan_info_all[i].freq;
1533 wlc_phy_chanspec_band_validch(wlc_phy_t *ppi, uint band, chanvec_t *channels)
1535 phy_info_t *pi = (phy_info_t *) ppi;
1539 ASSERT((band == WLC_BAND_2G) || (band == WLC_BAND_5G));
1541 memset(channels, 0, sizeof(chanvec_t));
1543 for (i = 0; i < ARRAY_SIZE(chan_info_all); i++) {
1544 channel = chan_info_all[i].chan;
1546 if ((pi->a_band_high_disable) && (channel >= FIRST_REF5_CHANNUM)
1547 && (channel <= LAST_REF5_CHANNUM))
1550 if (((band == WLC_BAND_2G) && (channel <= CH_MAX_2G_CHANNEL)) ||
1551 ((band == WLC_BAND_5G) && (channel > CH_MAX_2G_CHANNEL)))
1552 setbit(channels->vec, channel);
1556 chanspec_t wlc_phy_chanspec_band_firstch(wlc_phy_t *ppi, uint band)
1558 phy_info_t *pi = (phy_info_t *) ppi;
1563 ASSERT((band == WLC_BAND_2G) || (band == WLC_BAND_5G));
1565 for (i = 0; i < ARRAY_SIZE(chan_info_all); i++) {
1566 channel = chan_info_all[i].chan;
1568 if (ISNPHY(pi) && IS40MHZ(pi)) {
1571 for (j = 0; j < ARRAY_SIZE(chan_info_all); j++) {
1572 if (chan_info_all[j].chan ==
1573 channel + CH_10MHZ_APART)
1577 if (j == ARRAY_SIZE(chan_info_all))
1580 channel = UPPER_20_SB(channel);
1582 channel | WL_CHANSPEC_BW_40 |
1583 WL_CHANSPEC_CTL_SB_LOWER;
1584 if (band == WLC_BAND_2G)
1585 chspec |= WL_CHANSPEC_BAND_2G;
1587 chspec |= WL_CHANSPEC_BAND_5G;
1589 chspec = CH20MHZ_CHSPEC(channel);
1591 if ((pi->a_band_high_disable) && (channel >= FIRST_REF5_CHANNUM)
1592 && (channel <= LAST_REF5_CHANNUM))
1595 if (((band == WLC_BAND_2G) && (channel <= CH_MAX_2G_CHANNEL)) ||
1596 ((band == WLC_BAND_5G) && (channel > CH_MAX_2G_CHANNEL)))
1602 return (chanspec_t) INVCHANSPEC;
1605 int wlc_phy_txpower_get(wlc_phy_t *ppi, uint *qdbm, bool *override)
1607 phy_info_t *pi = (phy_info_t *) ppi;
1609 ASSERT(qdbm != NULL);
1610 *qdbm = pi->tx_user_target[0];
1611 if (override != NULL)
1612 *override = pi->txpwroverride;
1616 void wlc_phy_txpower_target_set(wlc_phy_t *ppi, struct txpwr_limits *txpwr)
1618 bool mac_enabled = false;
1619 phy_info_t *pi = (phy_info_t *) ppi;
1621 bcopy(&txpwr->cck[0], &pi->tx_user_target[TXP_FIRST_CCK],
1624 bcopy(&txpwr->ofdm[0], &pi->tx_user_target[TXP_FIRST_OFDM],
1625 WLC_NUM_RATES_OFDM);
1626 bcopy(&txpwr->ofdm_cdd[0], &pi->tx_user_target[TXP_FIRST_OFDM_20_CDD],
1627 WLC_NUM_RATES_OFDM);
1629 bcopy(&txpwr->ofdm_40_siso[0],
1630 &pi->tx_user_target[TXP_FIRST_OFDM_40_SISO], WLC_NUM_RATES_OFDM);
1631 bcopy(&txpwr->ofdm_40_cdd[0],
1632 &pi->tx_user_target[TXP_FIRST_OFDM_40_CDD], WLC_NUM_RATES_OFDM);
1634 bcopy(&txpwr->mcs_20_siso[0],
1635 &pi->tx_user_target[TXP_FIRST_MCS_20_SISO],
1636 WLC_NUM_RATES_MCS_1_STREAM);
1637 bcopy(&txpwr->mcs_20_cdd[0], &pi->tx_user_target[TXP_FIRST_MCS_20_CDD],
1638 WLC_NUM_RATES_MCS_1_STREAM);
1639 bcopy(&txpwr->mcs_20_stbc[0],
1640 &pi->tx_user_target[TXP_FIRST_MCS_20_STBC],
1641 WLC_NUM_RATES_MCS_1_STREAM);
1642 bcopy(&txpwr->mcs_20_mimo[0], &pi->tx_user_target[TXP_FIRST_MCS_20_SDM],
1643 WLC_NUM_RATES_MCS_2_STREAM);
1645 bcopy(&txpwr->mcs_40_siso[0],
1646 &pi->tx_user_target[TXP_FIRST_MCS_40_SISO],
1647 WLC_NUM_RATES_MCS_1_STREAM);
1648 bcopy(&txpwr->mcs_40_cdd[0], &pi->tx_user_target[TXP_FIRST_MCS_40_CDD],
1649 WLC_NUM_RATES_MCS_1_STREAM);
1650 bcopy(&txpwr->mcs_40_stbc[0],
1651 &pi->tx_user_target[TXP_FIRST_MCS_40_STBC],
1652 WLC_NUM_RATES_MCS_1_STREAM);
1653 bcopy(&txpwr->mcs_40_mimo[0], &pi->tx_user_target[TXP_FIRST_MCS_40_SDM],
1654 WLC_NUM_RATES_MCS_2_STREAM);
1656 if (R_REG(pi->sh->osh, &pi->regs->maccontrol) & MCTL_EN_MAC)
1660 wlapi_suspend_mac_and_wait(pi->sh->physhim);
1662 wlc_phy_txpower_recalc_target(pi);
1663 wlc_phy_cal_txpower_recalc_sw(pi);
1666 wlapi_enable_mac(pi->sh->physhim);
1669 int wlc_phy_txpower_set(wlc_phy_t *ppi, uint qdbm, bool override)
1671 phy_info_t *pi = (phy_info_t *) ppi;
1677 for (i = 0; i < TXP_NUM_RATES; i++)
1678 pi->tx_user_target[i] = (u8) qdbm;
1680 pi->txpwroverride = false;
1683 if (!SCAN_INPROG_PHY(pi)) {
1688 (R_REG(pi->sh->osh, &pi->regs->maccontrol) &
1692 wlapi_suspend_mac_and_wait(pi->sh->physhim);
1694 wlc_phy_txpower_recalc_target(pi);
1695 wlc_phy_cal_txpower_recalc_sw(pi);
1698 wlapi_enable_mac(pi->sh->physhim);
1705 wlc_phy_txpower_sromlimit(wlc_phy_t *ppi, uint channel, u8 *min_pwr,
1706 u8 *max_pwr, int txp_rate_idx)
1708 phy_info_t *pi = (phy_info_t *) ppi;
1711 *min_pwr = pi->min_txpower * WLC_TXPWR_DB_FACTOR;
1714 if (txp_rate_idx < 0)
1715 txp_rate_idx = TXP_FIRST_CCK;
1716 wlc_phy_txpower_sromlimit_get_nphy(pi, channel, max_pwr,
1719 } else if ((channel <= CH_MAX_2G_CHANNEL)) {
1720 if (txp_rate_idx < 0)
1721 txp_rate_idx = TXP_FIRST_CCK;
1722 *max_pwr = pi->tx_srom_max_rate_2g[txp_rate_idx];
1725 *max_pwr = WLC_TXPWR_MAX;
1727 if (txp_rate_idx < 0)
1728 txp_rate_idx = TXP_FIRST_OFDM;
1730 for (i = 0; i < ARRAY_SIZE(chan_info_all); i++) {
1731 if (channel == chan_info_all[i].chan) {
1735 ASSERT(i < ARRAY_SIZE(chan_info_all));
1738 *max_pwr = pi->hwtxpwr[i];
1741 if ((i >= FIRST_MID_5G_CHAN) && (i <= LAST_MID_5G_CHAN))
1743 pi->tx_srom_max_rate_5g_mid[txp_rate_idx];
1744 if ((i >= FIRST_HIGH_5G_CHAN)
1745 && (i <= LAST_HIGH_5G_CHAN))
1747 pi->tx_srom_max_rate_5g_hi[txp_rate_idx];
1748 if ((i >= FIRST_LOW_5G_CHAN) && (i <= LAST_LOW_5G_CHAN))
1750 pi->tx_srom_max_rate_5g_low[txp_rate_idx];
1756 wlc_phy_txpower_sromlimit_max_get(wlc_phy_t *ppi, uint chan, u8 *max_txpwr,
1759 phy_info_t *pi = (phy_info_t *) ppi;
1761 u8 tx_pwr_min = 255;
1763 u8 maxtxpwr, mintxpwr, rate, pactrl;
1767 max_num_rate = ISNPHY(pi) ? TXP_NUM_RATES :
1768 ISLCNPHY(pi) ? (TXP_LAST_SISO_MCS_20 + 1) : (TXP_LAST_OFDM + 1);
1770 for (rate = 0; rate < max_num_rate; rate++) {
1772 wlc_phy_txpower_sromlimit(ppi, chan, &mintxpwr, &maxtxpwr,
1775 maxtxpwr = (maxtxpwr > pactrl) ? (maxtxpwr - pactrl) : 0;
1777 maxtxpwr = (maxtxpwr > 6) ? (maxtxpwr - 6) : 0;
1779 tx_pwr_max = max(tx_pwr_max, maxtxpwr);
1780 tx_pwr_min = min(tx_pwr_min, maxtxpwr);
1782 *max_txpwr = tx_pwr_max;
1783 *min_txpwr = tx_pwr_min;
1787 wlc_phy_txpower_boardlimit_band(wlc_phy_t *ppi, uint bandunit, s32 *max_pwr,
1788 s32 *min_pwr, u32 *step_pwr)
1793 u8 wlc_phy_txpower_get_target_min(wlc_phy_t *ppi)
1795 phy_info_t *pi = (phy_info_t *) ppi;
1797 return pi->tx_power_min;
1800 u8 wlc_phy_txpower_get_target_max(wlc_phy_t *ppi)
1802 phy_info_t *pi = (phy_info_t *) ppi;
1804 return pi->tx_power_max;
1807 void wlc_phy_txpower_recalc_target(phy_info_t *pi)
1809 u8 maxtxpwr, mintxpwr, rate, pactrl;
1811 u8 tx_pwr_target[TXP_NUM_RATES];
1813 u8 tx_pwr_min = 255;
1814 u8 tx_pwr_max_rate_ind = 0;
1818 u32 band = CHSPEC2WLC_BAND(pi->radio_chanspec);
1819 initfn_t txpwr_recalc_fn = NULL;
1821 chspec = pi->radio_chanspec;
1822 if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_NONE)
1823 target_chan = CHSPEC_CHANNEL(chspec);
1824 else if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_UPPER)
1825 target_chan = UPPER_20_SB(CHSPEC_CHANNEL(chspec));
1827 target_chan = LOWER_20_SB(CHSPEC_CHANNEL(chspec));
1833 if (CHSPEC_IS40(pi->radio_chanspec)) {
1834 offset_mcs = pi->mcs40_po;
1835 for (i = TXP_FIRST_SISO_MCS_20;
1836 i <= TXP_LAST_SISO_MCS_20; i++) {
1837 pi->tx_srom_max_rate_2g[i - 8] =
1838 pi->tx_srom_max_2g -
1839 ((offset_mcs & 0xf) * 2);
1843 offset_mcs = pi->mcs20_po;
1844 for (i = TXP_FIRST_SISO_MCS_20;
1845 i <= TXP_LAST_SISO_MCS_20; i++) {
1846 pi->tx_srom_max_rate_2g[i - 8] =
1847 pi->tx_srom_max_2g -
1848 ((offset_mcs & 0xf) * 2);
1854 max_num_rate = ((ISNPHY(pi)) ? (TXP_NUM_RATES) :
1856 (TXP_LAST_SISO_MCS_20 + 1) : (TXP_LAST_OFDM + 1)));
1858 max_num_rate = ((ISNPHY(pi)) ? (TXP_NUM_RATES) : (TXP_LAST_OFDM + 1));
1861 wlc_phy_upd_env_txpwr_rate_limits(pi, band);
1863 for (rate = start_rate; rate < max_num_rate; rate++) {
1865 tx_pwr_target[rate] = pi->tx_user_target[rate];
1867 if (pi->user_txpwr_at_rfport) {
1868 tx_pwr_target[rate] +=
1869 wlc_user_txpwr_antport_to_rfport(pi, target_chan,
1875 wlc_phy_txpower_sromlimit((wlc_phy_t *) pi, target_chan,
1876 &mintxpwr, &maxtxpwr, rate);
1878 maxtxpwr = min(maxtxpwr, pi->txpwr_limit[rate]);
1881 (maxtxpwr > pactrl) ? (maxtxpwr - pactrl) : 0;
1883 maxtxpwr = (maxtxpwr > 6) ? (maxtxpwr - 6) : 0;
1885 maxtxpwr = min(maxtxpwr, tx_pwr_target[rate]);
1887 if (pi->txpwr_percent <= 100)
1888 maxtxpwr = (maxtxpwr * pi->txpwr_percent) / 100;
1890 tx_pwr_target[rate] = max(maxtxpwr, mintxpwr);
1893 tx_pwr_target[rate] =
1894 min(tx_pwr_target[rate], pi->txpwr_env_limit[rate]);
1896 if (tx_pwr_target[rate] > tx_pwr_max)
1897 tx_pwr_max_rate_ind = rate;
1899 tx_pwr_max = max(tx_pwr_max, tx_pwr_target[rate]);
1900 tx_pwr_min = min(tx_pwr_min, tx_pwr_target[rate]);
1903 memset(pi->tx_power_offset, 0, sizeof(pi->tx_power_offset));
1904 pi->tx_power_max = tx_pwr_max;
1905 pi->tx_power_min = tx_pwr_min;
1906 pi->tx_power_max_rate_ind = tx_pwr_max_rate_ind;
1907 for (rate = 0; rate < max_num_rate; rate++) {
1909 pi->tx_power_target[rate] = tx_pwr_target[rate];
1911 if (!pi->hwpwrctrl || ISNPHY(pi)) {
1912 pi->tx_power_offset[rate] =
1913 pi->tx_power_max - pi->tx_power_target[rate];
1915 pi->tx_power_offset[rate] =
1916 pi->tx_power_target[rate] - pi->tx_power_min;
1920 txpwr_recalc_fn = pi->pi_fptr.txpwrrecalc;
1921 if (txpwr_recalc_fn)
1922 (*txpwr_recalc_fn) (pi);
1926 wlc_phy_txpower_reg_limit_calc(phy_info_t *pi, struct txpwr_limits *txpwr,
1927 chanspec_t chanspec)
1929 u8 tmp_txpwr_limit[2 * WLC_NUM_RATES_OFDM];
1930 u8 *txpwr_ptr1 = NULL, *txpwr_ptr2 = NULL;
1931 int rate_start_index = 0, rate1, rate2, k;
1933 for (rate1 = WL_TX_POWER_CCK_FIRST, rate2 = 0;
1934 rate2 < WL_TX_POWER_CCK_NUM; rate1++, rate2++)
1935 pi->txpwr_limit[rate1] = txpwr->cck[rate2];
1937 for (rate1 = WL_TX_POWER_OFDM_FIRST, rate2 = 0;
1938 rate2 < WL_TX_POWER_OFDM_NUM; rate1++, rate2++)
1939 pi->txpwr_limit[rate1] = txpwr->ofdm[rate2];
1943 for (k = 0; k < 4; k++) {
1947 txpwr_ptr1 = txpwr->mcs_20_siso;
1948 txpwr_ptr2 = txpwr->ofdm;
1949 rate_start_index = WL_TX_POWER_OFDM_FIRST;
1953 txpwr_ptr1 = txpwr->mcs_20_cdd;
1954 txpwr_ptr2 = txpwr->ofdm_cdd;
1955 rate_start_index = WL_TX_POWER_OFDM20_CDD_FIRST;
1959 txpwr_ptr1 = txpwr->mcs_40_siso;
1960 txpwr_ptr2 = txpwr->ofdm_40_siso;
1962 WL_TX_POWER_OFDM40_SISO_FIRST;
1966 txpwr_ptr1 = txpwr->mcs_40_cdd;
1967 txpwr_ptr2 = txpwr->ofdm_40_cdd;
1968 rate_start_index = WL_TX_POWER_OFDM40_CDD_FIRST;
1972 for (rate2 = 0; rate2 < WLC_NUM_RATES_OFDM; rate2++) {
1973 tmp_txpwr_limit[rate2] = 0;
1974 tmp_txpwr_limit[WLC_NUM_RATES_OFDM + rate2] =
1977 wlc_phy_mcs_to_ofdm_powers_nphy(tmp_txpwr_limit, 0,
1978 WLC_NUM_RATES_OFDM - 1,
1979 WLC_NUM_RATES_OFDM);
1980 for (rate1 = rate_start_index, rate2 = 0;
1981 rate2 < WLC_NUM_RATES_OFDM; rate1++, rate2++)
1982 pi->txpwr_limit[rate1] =
1983 min(txpwr_ptr2[rate2],
1984 tmp_txpwr_limit[rate2]);
1987 for (k = 0; k < 4; k++) {
1991 txpwr_ptr1 = txpwr->ofdm;
1992 txpwr_ptr2 = txpwr->mcs_20_siso;
1993 rate_start_index = WL_TX_POWER_MCS20_SISO_FIRST;
1997 txpwr_ptr1 = txpwr->ofdm_cdd;
1998 txpwr_ptr2 = txpwr->mcs_20_cdd;
1999 rate_start_index = WL_TX_POWER_MCS20_CDD_FIRST;
2003 txpwr_ptr1 = txpwr->ofdm_40_siso;
2004 txpwr_ptr2 = txpwr->mcs_40_siso;
2005 rate_start_index = WL_TX_POWER_MCS40_SISO_FIRST;
2009 txpwr_ptr1 = txpwr->ofdm_40_cdd;
2010 txpwr_ptr2 = txpwr->mcs_40_cdd;
2011 rate_start_index = WL_TX_POWER_MCS40_CDD_FIRST;
2014 for (rate2 = 0; rate2 < WLC_NUM_RATES_OFDM; rate2++) {
2015 tmp_txpwr_limit[rate2] = 0;
2016 tmp_txpwr_limit[WLC_NUM_RATES_OFDM + rate2] =
2019 wlc_phy_ofdm_to_mcs_powers_nphy(tmp_txpwr_limit, 0,
2020 WLC_NUM_RATES_OFDM - 1,
2021 WLC_NUM_RATES_OFDM);
2022 for (rate1 = rate_start_index, rate2 = 0;
2023 rate2 < WLC_NUM_RATES_MCS_1_STREAM;
2025 pi->txpwr_limit[rate1] =
2026 min(txpwr_ptr2[rate2],
2027 tmp_txpwr_limit[rate2]);
2030 for (k = 0; k < 2; k++) {
2034 rate_start_index = WL_TX_POWER_MCS20_STBC_FIRST;
2035 txpwr_ptr1 = txpwr->mcs_20_stbc;
2039 rate_start_index = WL_TX_POWER_MCS40_STBC_FIRST;
2040 txpwr_ptr1 = txpwr->mcs_40_stbc;
2043 for (rate1 = rate_start_index, rate2 = 0;
2044 rate2 < WLC_NUM_RATES_MCS_1_STREAM;
2046 pi->txpwr_limit[rate1] = txpwr_ptr1[rate2];
2049 for (k = 0; k < 2; k++) {
2053 rate_start_index = WL_TX_POWER_MCS20_SDM_FIRST;
2054 txpwr_ptr1 = txpwr->mcs_20_mimo;
2058 rate_start_index = WL_TX_POWER_MCS40_SDM_FIRST;
2059 txpwr_ptr1 = txpwr->mcs_40_mimo;
2062 for (rate1 = rate_start_index, rate2 = 0;
2063 rate2 < WLC_NUM_RATES_MCS_2_STREAM;
2065 pi->txpwr_limit[rate1] = txpwr_ptr1[rate2];
2068 pi->txpwr_limit[WL_TX_POWER_MCS_32] = txpwr->mcs32;
2070 pi->txpwr_limit[WL_TX_POWER_MCS40_CDD_FIRST] =
2071 min(pi->txpwr_limit[WL_TX_POWER_MCS40_CDD_FIRST],
2072 pi->txpwr_limit[WL_TX_POWER_MCS_32]);
2073 pi->txpwr_limit[WL_TX_POWER_MCS_32] =
2074 pi->txpwr_limit[WL_TX_POWER_MCS40_CDD_FIRST];
2078 void wlc_phy_txpwr_percent_set(wlc_phy_t *ppi, u8 txpwr_percent)
2080 phy_info_t *pi = (phy_info_t *) ppi;
2082 pi->txpwr_percent = txpwr_percent;
2085 void wlc_phy_machwcap_set(wlc_phy_t *ppi, u32 machwcap)
2087 phy_info_t *pi = (phy_info_t *) ppi;
2089 pi->sh->machwcap = machwcap;
2092 void wlc_phy_runbist_config(wlc_phy_t *ppi, bool start_end)
2094 phy_info_t *pi = (phy_info_t *) ppi;
2098 if (start_end == ON) {
2102 if (NREV_IS(pi->pubpi.phy_rev, 3)
2103 || NREV_IS(pi->pubpi.phy_rev, 4)) {
2104 W_REG(pi->sh->osh, &pi->regs->phyregaddr, 0xa0);
2105 (void)R_REG(pi->sh->osh, &pi->regs->phyregaddr);
2106 rxc = R_REG(pi->sh->osh, &pi->regs->phyregdata);
2107 W_REG(pi->sh->osh, &pi->regs->phyregdata,
2111 if (NREV_IS(pi->pubpi.phy_rev, 3)
2112 || NREV_IS(pi->pubpi.phy_rev, 4)) {
2113 W_REG(pi->sh->osh, &pi->regs->phyregaddr, 0xa0);
2114 (void)R_REG(pi->sh->osh, &pi->regs->phyregaddr);
2115 W_REG(pi->sh->osh, &pi->regs->phyregdata, rxc);
2118 wlc_phy_por_inform(ppi);
2123 wlc_phy_txpower_limit_set(wlc_phy_t *ppi, struct txpwr_limits *txpwr,
2124 chanspec_t chanspec)
2126 phy_info_t *pi = (phy_info_t *) ppi;
2128 wlc_phy_txpower_reg_limit_calc(pi, txpwr, chanspec);
2132 for (i = TXP_FIRST_OFDM_20_CDD, j = 0;
2133 j < WLC_NUM_RATES_MCS_1_STREAM; i++, j++) {
2134 if (txpwr->mcs_20_siso[j])
2135 pi->txpwr_limit[i] = txpwr->mcs_20_siso[j];
2137 pi->txpwr_limit[i] = txpwr->ofdm[j];
2141 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2143 wlc_phy_txpower_recalc_target(pi);
2144 wlc_phy_cal_txpower_recalc_sw(pi);
2145 wlapi_enable_mac(pi->sh->physhim);
2148 void wlc_phy_ofdm_rateset_war(wlc_phy_t *pih, bool war)
2150 phy_info_t *pi = (phy_info_t *) pih;
2152 pi->ofdm_rateset_war = war;
2155 void wlc_phy_bf_preempt_enable(wlc_phy_t *pih, bool bf_preempt)
2157 phy_info_t *pi = (phy_info_t *) pih;
2159 pi->bf_preempt_4306 = bf_preempt;
2162 void wlc_phy_txpower_update_shm(phy_info_t *pi)
2173 if (pi->hwpwrctrl) {
2176 wlapi_bmac_write_shm(pi->sh->physhim, M_TXPWR_MAX, 63);
2177 wlapi_bmac_write_shm(pi->sh->physhim, M_TXPWR_N,
2178 1 << NUM_TSSI_FRAMES);
2180 wlapi_bmac_write_shm(pi->sh->physhim, M_TXPWR_TARGET,
2181 pi->tx_power_min << NUM_TSSI_FRAMES);
2183 wlapi_bmac_write_shm(pi->sh->physhim, M_TXPWR_CUR,
2186 for (j = TXP_FIRST_OFDM; j <= TXP_LAST_OFDM; j++) {
2187 const u8 ucode_ofdm_rates[] = {
2188 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c
2190 offset = wlapi_bmac_rate_shm_offset(pi->sh->physhim,
2191 ucode_ofdm_rates[j -
2193 wlapi_bmac_write_shm(pi->sh->physhim, offset + 6,
2194 pi->tx_power_offset[j]);
2195 wlapi_bmac_write_shm(pi->sh->physhim, offset + 14,
2196 -(pi->tx_power_offset[j] / 2));
2199 wlapi_bmac_mhf(pi->sh->physhim, MHF2, MHF2_HWPWRCTL,
2200 MHF2_HWPWRCTL, WLC_BAND_ALL);
2204 for (i = TXP_FIRST_OFDM; i <= TXP_LAST_OFDM; i++)
2205 pi->tx_power_offset[i] =
2206 (u8) roundup(pi->tx_power_offset[i], 8);
2207 wlapi_bmac_write_shm(pi->sh->physhim, M_OFDM_OFFSET,
2209 tx_power_offset[TXP_FIRST_OFDM]
2214 bool wlc_phy_txpower_hw_ctrl_get(wlc_phy_t *ppi)
2216 phy_info_t *pi = (phy_info_t *) ppi;
2219 return pi->nphy_txpwrctrl;
2221 return pi->hwpwrctrl;
2225 void wlc_phy_txpower_hw_ctrl_set(wlc_phy_t *ppi, bool hwpwrctrl)
2227 phy_info_t *pi = (phy_info_t *) ppi;
2228 bool cur_hwpwrctrl = pi->hwpwrctrl;
2231 if (!pi->hwpwrctrl_capable) {
2235 pi->hwpwrctrl = hwpwrctrl;
2236 pi->nphy_txpwrctrl = hwpwrctrl;
2237 pi->txpwrctrl = hwpwrctrl;
2242 (R_REG(pi->sh->osh, &pi->regs->maccontrol) & MCTL_EN_MAC));
2244 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2246 wlc_phy_txpwrctrl_enable_nphy(pi, pi->nphy_txpwrctrl);
2247 if (pi->nphy_txpwrctrl == PHY_TPC_HW_OFF) {
2248 wlc_phy_txpwr_fixpower_nphy(pi);
2251 mod_phy_reg(pi, 0x1e7, (0x7f << 0),
2252 pi->saved_txpwr_idx);
2256 wlapi_enable_mac(pi->sh->physhim);
2257 } else if (hwpwrctrl != cur_hwpwrctrl) {
2263 void wlc_phy_txpower_ipa_upd(phy_info_t *pi)
2266 if (NREV_GE(pi->pubpi.phy_rev, 3)) {
2267 pi->ipa2g_on = (pi->srom_fem2g.extpagain == 2);
2268 pi->ipa5g_on = (pi->srom_fem5g.extpagain == 2);
2270 pi->ipa2g_on = false;
2271 pi->ipa5g_on = false;
2275 static u32 wlc_phy_txpower_est_power_nphy(phy_info_t *pi);
2277 static u32 wlc_phy_txpower_est_power_nphy(phy_info_t *pi)
2279 s16 tx0_status, tx1_status;
2280 u16 estPower1, estPower2;
2281 u8 pwr0, pwr1, adj_pwr0, adj_pwr1;
2284 estPower1 = read_phy_reg(pi, 0x118);
2285 estPower2 = read_phy_reg(pi, 0x119);
2287 if ((estPower1 & (0x1 << 8))
2289 pwr0 = (u8) (estPower1 & (0xff << 0))
2295 if ((estPower2 & (0x1 << 8))
2297 pwr1 = (u8) (estPower2 & (0xff << 0))
2303 tx0_status = read_phy_reg(pi, 0x1ed);
2304 tx1_status = read_phy_reg(pi, 0x1ee);
2306 if ((tx0_status & (0x1 << 15))
2308 adj_pwr0 = (u8) (tx0_status & (0xff << 0))
2313 if ((tx1_status & (0x1 << 15))
2315 adj_pwr1 = (u8) (tx1_status & (0xff << 0))
2322 (u32) ((pwr0 << 24) | (pwr1 << 16) | (adj_pwr0 << 8) | adj_pwr1);
2327 wlc_phy_txpower_get_current(wlc_phy_t *ppi, tx_power_t *power, uint channel)
2329 phy_info_t *pi = (phy_info_t *) ppi;
2330 uint rate, num_rates;
2331 u8 min_pwr, max_pwr;
2333 #if WL_TX_POWER_RATES != TXP_NUM_RATES
2334 #error "tx_power_t struct out of sync with this fn"
2338 power->rf_cores = 2;
2339 power->flags |= (WL_TX_POWER_F_MIMO);
2340 if (pi->nphy_txpwrctrl == PHY_TPC_HW_ON)
2342 (WL_TX_POWER_F_ENABLED | WL_TX_POWER_F_HW);
2343 } else if (ISLCNPHY(pi)) {
2344 power->rf_cores = 1;
2345 power->flags |= (WL_TX_POWER_F_SISO);
2346 if (pi->radiopwr_override == RADIOPWR_OVERRIDE_DEF)
2347 power->flags |= WL_TX_POWER_F_ENABLED;
2349 power->flags |= WL_TX_POWER_F_HW;
2352 num_rates = ((ISNPHY(pi)) ? (TXP_NUM_RATES) :
2354 (TXP_LAST_OFDM_20_CDD + 1) : (TXP_LAST_OFDM + 1)));
2356 for (rate = 0; rate < num_rates; rate++) {
2357 power->user_limit[rate] = pi->tx_user_target[rate];
2358 wlc_phy_txpower_sromlimit(ppi, channel, &min_pwr, &max_pwr,
2360 power->board_limit[rate] = (u8) max_pwr;
2361 power->target[rate] = pi->tx_power_target[rate];
2367 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2368 wlc_phyreg_enter((wlc_phy_t *) pi);
2369 est_pout = wlc_phy_txpower_est_power_nphy(pi);
2370 wlc_phyreg_exit((wlc_phy_t *) pi);
2371 wlapi_enable_mac(pi->sh->physhim);
2373 power->est_Pout[0] = (est_pout >> 8) & 0xff;
2374 power->est_Pout[1] = est_pout & 0xff;
2376 power->est_Pout_act[0] = est_pout >> 24;
2377 power->est_Pout_act[1] = (est_pout >> 16) & 0xff;
2379 if (power->est_Pout[0] == 0x80)
2380 power->est_Pout[0] = 0;
2381 if (power->est_Pout[1] == 0x80)
2382 power->est_Pout[1] = 0;
2384 if (power->est_Pout_act[0] == 0x80)
2385 power->est_Pout_act[0] = 0;
2386 if (power->est_Pout_act[1] == 0x80)
2387 power->est_Pout_act[1] = 0;
2389 power->est_Pout_cck = 0;
2391 power->tx_power_max[0] = pi->tx_power_max;
2392 power->tx_power_max[1] = pi->tx_power_max;
2394 power->tx_power_max_rate_ind[0] = pi->tx_power_max_rate_ind;
2395 power->tx_power_max_rate_ind[1] = pi->tx_power_max_rate_ind;
2396 } else if (!pi->hwpwrctrl) {
2397 } else if (pi->sh->up) {
2399 wlc_phyreg_enter(ppi);
2402 power->tx_power_max[0] = pi->tx_power_max;
2403 power->tx_power_max[1] = pi->tx_power_max;
2405 power->tx_power_max_rate_ind[0] =
2406 pi->tx_power_max_rate_ind;
2407 power->tx_power_max_rate_ind[1] =
2408 pi->tx_power_max_rate_ind;
2410 if (wlc_phy_tpc_isenabled_lcnphy(pi))
2412 (WL_TX_POWER_F_HW | WL_TX_POWER_F_ENABLED);
2415 ~(WL_TX_POWER_F_HW | WL_TX_POWER_F_ENABLED);
2417 wlc_lcnphy_get_tssi(pi, (s8 *) &power->est_Pout[0],
2418 (s8 *) &power->est_Pout_cck);
2420 wlc_phyreg_exit(ppi);
2424 void wlc_phy_antsel_type_set(wlc_phy_t *ppi, u8 antsel_type)
2426 phy_info_t *pi = (phy_info_t *) ppi;
2428 pi->antsel_type = antsel_type;
2431 bool wlc_phy_test_ison(wlc_phy_t *ppi)
2433 phy_info_t *pi = (phy_info_t *) ppi;
2435 return pi->phytest_on;
2438 bool wlc_phy_ant_rxdiv_get(wlc_phy_t *ppi, u8 *pval)
2440 phy_info_t *pi = (phy_info_t *) ppi;
2443 wlc_phyreg_enter(ppi);
2448 } else if (ISLCNPHY(pi)) {
2449 u16 crsctrl = read_phy_reg(pi, 0x410);
2450 u16 div = crsctrl & (0x1 << 1);
2451 *pval = (div | ((crsctrl & (0x1 << 0)) ^ (div >> 1)));
2454 wlc_phyreg_exit(ppi);
2459 void wlc_phy_ant_rxdiv_set(wlc_phy_t *ppi, u8 val)
2461 phy_info_t *pi = (phy_info_t *) ppi;
2464 pi->sh->rx_antdiv = val;
2466 if (!(ISNPHY(pi) && D11REV_IS(pi->sh->corerev, 16))) {
2467 if (val > ANT_RX_DIV_FORCE_1)
2468 wlapi_bmac_mhf(pi->sh->physhim, MHF1, MHF1_ANTDIV,
2469 MHF1_ANTDIV, WLC_BAND_ALL);
2471 wlapi_bmac_mhf(pi->sh->physhim, MHF1, MHF1_ANTDIV, 0,
2484 (0 == (R_REG(pi->sh->osh, &pi->regs->maccontrol) & MCTL_EN_MAC));
2486 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2489 if (val > ANT_RX_DIV_FORCE_1) {
2490 mod_phy_reg(pi, 0x410, (0x1 << 1), 0x01 << 1);
2491 mod_phy_reg(pi, 0x410,
2493 ((ANT_RX_DIV_START_1 == val) ? 1 : 0) << 0);
2495 mod_phy_reg(pi, 0x410, (0x1 << 1), 0x00 << 1);
2496 mod_phy_reg(pi, 0x410, (0x1 << 0), (u16) val << 0);
2503 wlapi_enable_mac(pi->sh->physhim);
2509 wlc_phy_noise_calc_phy(phy_info_t *pi, u32 *cmplx_pwr, s8 *pwr_ant)
2511 s8 cmplx_pwr_dbm[PHY_CORE_MAX];
2514 memset((u8 *) cmplx_pwr_dbm, 0, sizeof(cmplx_pwr_dbm));
2515 ASSERT(pi->pubpi.phy_corenum <= PHY_CORE_MAX);
2516 wlc_phy_compute_dB(cmplx_pwr, cmplx_pwr_dbm, pi->pubpi.phy_corenum);
2518 for (i = 0; i < pi->pubpi.phy_corenum; i++) {
2519 if (NREV_GE(pi->pubpi.phy_rev, 3))
2520 cmplx_pwr_dbm[i] += (s8) PHY_NOISE_OFFSETFACT_4322;
2523 cmplx_pwr_dbm[i] += (s8) (16 - (15) * 3 - 70);
2526 for (i = 0; i < pi->pubpi.phy_corenum; i++) {
2527 pi->nphy_noise_win[i][pi->nphy_noise_index] = cmplx_pwr_dbm[i];
2528 pwr_ant[i] = cmplx_pwr_dbm[i];
2530 pi->nphy_noise_index =
2531 MODINC_POW2(pi->nphy_noise_index, PHY_NOISE_WINDOW_SZ);
2536 wlc_phy_noise_sample_request(wlc_phy_t *pih, u8 reason, u8 ch)
2538 phy_info_t *pi = (phy_info_t *) pih;
2539 s8 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;
2540 bool sampling_in_progress = (pi->phynoise_state != 0);
2541 bool wait_for_intr = true;
2543 if (NORADIO_ENAB(pi->pubpi)) {
2548 case PHY_NOISE_SAMPLE_MON:
2550 pi->phynoise_chan_watchdog = ch;
2551 pi->phynoise_state |= PHY_NOISE_STATE_MON;
2555 case PHY_NOISE_SAMPLE_EXTERNAL:
2557 pi->phynoise_state |= PHY_NOISE_STATE_EXTERNAL;
2565 if (sampling_in_progress)
2568 pi->phynoise_now = pi->sh->now;
2570 if (pi->phy_fixed_noise) {
2572 pi->nphy_noise_win[WL_ANT_IDX_1][pi->nphy_noise_index] =
2573 PHY_NOISE_FIXED_VAL_NPHY;
2574 pi->nphy_noise_win[WL_ANT_IDX_2][pi->nphy_noise_index] =
2575 PHY_NOISE_FIXED_VAL_NPHY;
2576 pi->nphy_noise_index = MODINC_POW2(pi->nphy_noise_index,
2577 PHY_NOISE_WINDOW_SZ);
2579 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;
2582 noise_dbm = PHY_NOISE_FIXED_VAL;
2585 wait_for_intr = false;
2590 if (!pi->phynoise_polling
2591 || (reason == PHY_NOISE_SAMPLE_EXTERNAL)) {
2592 wlapi_bmac_write_shm(pi->sh->physhim, M_JSSI_0, 0);
2593 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP0, 0);
2594 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP1, 0);
2595 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP2, 0);
2596 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP3, 0);
2598 OR_REG(pi->sh->osh, &pi->regs->maccommand,
2601 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2602 wlc_lcnphy_deaf_mode(pi, (bool) 0);
2603 noise_dbm = (s8) wlc_lcnphy_rx_signal_power(pi, 20);
2604 wlc_lcnphy_deaf_mode(pi, (bool) 1);
2605 wlapi_enable_mac(pi->sh->physhim);
2606 wait_for_intr = false;
2608 } else if (ISNPHY(pi)) {
2609 if (!pi->phynoise_polling
2610 || (reason == PHY_NOISE_SAMPLE_EXTERNAL)) {
2612 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP0, 0);
2613 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP1, 0);
2614 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP2, 0);
2615 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP3, 0);
2617 OR_REG(pi->sh->osh, &pi->regs->maccommand,
2620 phy_iq_est_t est[PHY_CORE_MAX];
2621 u32 cmplx_pwr[PHY_CORE_MAX];
2622 s8 noise_dbm_ant[PHY_CORE_MAX];
2623 u16 log_num_samps, num_samps, classif_state = 0;
2628 memset((u8 *) est, 0, sizeof(est));
2629 memset((u8 *) cmplx_pwr, 0, sizeof(cmplx_pwr));
2630 memset((u8 *) noise_dbm_ant, 0, sizeof(noise_dbm_ant));
2632 log_num_samps = PHY_NOISE_SAMPLE_LOG_NUM_NPHY;
2633 num_samps = 1 << log_num_samps;
2635 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2636 classif_state = wlc_phy_classifier_nphy(pi, 0, 0);
2637 wlc_phy_classifier_nphy(pi, 3, 0);
2638 wlc_phy_rx_iq_est_nphy(pi, est, num_samps, wait_time,
2640 wlc_phy_classifier_nphy(pi, (0x7 << 0), classif_state);
2641 wlapi_enable_mac(pi->sh->physhim);
2643 for (i = 0; i < pi->pubpi.phy_corenum; i++)
2646 est[i].q_pwr) >> log_num_samps;
2648 wlc_phy_noise_calc_phy(pi, cmplx_pwr, noise_dbm_ant);
2650 for (i = 0; i < pi->pubpi.phy_corenum; i++) {
2651 pi->nphy_noise_win[i][pi->nphy_noise_index] =
2654 if (noise_dbm_ant[i] > noise_dbm)
2655 noise_dbm = noise_dbm_ant[i];
2657 pi->nphy_noise_index = MODINC_POW2(pi->nphy_noise_index,
2658 PHY_NOISE_WINDOW_SZ);
2660 wait_for_intr = false;
2667 wlc_phy_noise_cb(pi, ch, noise_dbm);
2671 void wlc_phy_noise_sample_request_external(wlc_phy_t *pih)
2675 channel = CHSPEC_CHANNEL(wlc_phy_chanspec_get(pih));
2677 wlc_phy_noise_sample_request(pih, PHY_NOISE_SAMPLE_EXTERNAL, channel);
2680 static void wlc_phy_noise_cb(phy_info_t *pi, u8 channel, s8 noise_dbm)
2682 if (!pi->phynoise_state)
2685 if (pi->phynoise_state & PHY_NOISE_STATE_MON) {
2686 if (pi->phynoise_chan_watchdog == channel) {
2687 pi->sh->phy_noise_window[pi->sh->phy_noise_index] =
2689 pi->sh->phy_noise_index =
2690 MODINC(pi->sh->phy_noise_index, MA_WINDOW_SZ);
2692 pi->phynoise_state &= ~PHY_NOISE_STATE_MON;
2695 if (pi->phynoise_state & PHY_NOISE_STATE_EXTERNAL) {
2696 pi->phynoise_state &= ~PHY_NOISE_STATE_EXTERNAL;
2701 static s8 wlc_phy_noise_read_shmem(phy_info_t *pi)
2703 u32 cmplx_pwr[PHY_CORE_MAX];
2704 s8 noise_dbm_ant[PHY_CORE_MAX];
2706 u32 cmplx_pwr_tot = 0;
2707 s8 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;
2710 ASSERT(pi->pubpi.phy_corenum <= PHY_CORE_MAX);
2711 memset((u8 *) cmplx_pwr, 0, sizeof(cmplx_pwr));
2712 memset((u8 *) noise_dbm_ant, 0, sizeof(noise_dbm_ant));
2714 for (idx = 0, core = 0; core < pi->pubpi.phy_corenum; idx += 2, core++) {
2715 lo = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP(idx));
2716 hi = wlapi_bmac_read_shm(pi->sh->physhim,
2717 M_PWRIND_MAP(idx + 1));
2718 cmplx_pwr[core] = (hi << 16) + lo;
2719 cmplx_pwr_tot += cmplx_pwr[core];
2720 if (cmplx_pwr[core] == 0) {
2721 noise_dbm_ant[core] = PHY_NOISE_FIXED_VAL_NPHY;
2723 cmplx_pwr[core] >>= PHY_NOISE_SAMPLE_LOG_NUM_UCODE;
2726 if (cmplx_pwr_tot != 0)
2727 wlc_phy_noise_calc_phy(pi, cmplx_pwr, noise_dbm_ant);
2729 for (core = 0; core < pi->pubpi.phy_corenum; core++) {
2730 pi->nphy_noise_win[core][pi->nphy_noise_index] =
2731 noise_dbm_ant[core];
2733 if (noise_dbm_ant[core] > noise_dbm)
2734 noise_dbm = noise_dbm_ant[core];
2736 pi->nphy_noise_index =
2737 MODINC_POW2(pi->nphy_noise_index, PHY_NOISE_WINDOW_SZ);
2743 void wlc_phy_noise_sample_intr(wlc_phy_t *pih)
2745 phy_info_t *pi = (phy_info_t *) pih;
2748 s8 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;
2751 u32 cmplx_pwr, cmplx_pwr0, cmplx_pwr1;
2753 s32 pwr_offset_dB, gain_dB;
2754 u16 status_0, status_1;
2756 jssi_aux = wlapi_bmac_read_shm(pi->sh->physhim, M_JSSI_AUX);
2757 channel = jssi_aux & D11_CURCHANNEL_MAX;
2759 lo = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP0);
2760 hi = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP1);
2761 cmplx_pwr0 = (hi << 16) + lo;
2763 lo = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP2);
2764 hi = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP3);
2765 cmplx_pwr1 = (hi << 16) + lo;
2766 cmplx_pwr = (cmplx_pwr0 + cmplx_pwr1) >> 6;
2769 status_1 = wlapi_bmac_read_shm(pi->sh->physhim, M_JSSI_0);
2770 if ((cmplx_pwr > 0 && cmplx_pwr < 500)
2771 && ((status_1 & 0xc000) == 0x4000)) {
2773 wlc_phy_compute_dB(&cmplx_pwr, &noise_dbm,
2774 pi->pubpi.phy_corenum);
2775 pwr_offset_dB = (read_phy_reg(pi, 0x434) & 0xFF);
2776 if (pwr_offset_dB > 127)
2777 pwr_offset_dB -= 256;
2779 noise_dbm += (s8) (pwr_offset_dB - 30);
2781 gain_dB = (status_0 & 0x1ff);
2782 noise_dbm -= (s8) (gain_dB);
2784 noise_dbm = PHY_NOISE_FIXED_VAL_LCNPHY;
2786 } else if (ISNPHY(pi)) {
2788 jssi_aux = wlapi_bmac_read_shm(pi->sh->physhim, M_JSSI_AUX);
2789 channel = jssi_aux & D11_CURCHANNEL_MAX;
2791 noise_dbm = wlc_phy_noise_read_shmem(pi);
2796 wlc_phy_noise_cb(pi, channel, noise_dbm);
2800 s8 lcnphy_gain_index_offset_for_pkt_rssi[] = {
2841 void wlc_phy_compute_dB(u32 *cmplx_pwr, s8 *p_cmplx_pwr_dB, u8 core)
2843 u8 shift_ct, lsb, msb, secondmsb, i;
2846 for (i = 0; i < core; i++) {
2848 shift_ct = msb = secondmsb = 0;
2852 lsb = (u8) (tmp & 1);
2856 secondmsb = (u8) ((cmplx_pwr[i] >> (msb - 1)) & 1);
2857 p_cmplx_pwr_dB[i] = (s8) (3 * msb + 2 * secondmsb);
2861 void BCMFASTPATH wlc_phy_rssi_compute(wlc_phy_t *pih, void *ctx)
2863 wlc_d11rxhdr_t *wlc_rxhdr = (wlc_d11rxhdr_t *) ctx;
2864 d11rxhdr_t *rxh = &wlc_rxhdr->rxhdr;
2865 int rssi = ltoh16(rxh->PhyRxStatus_1) & PRXS1_JSSI_MASK;
2866 uint radioid = pih->radioid;
2867 phy_info_t *pi = (phy_info_t *) pih;
2869 if (NORADIO_ENAB(pi->pubpi)) {
2870 rssi = WLC_RSSI_INVALID;
2874 if ((pi->sh->corerev >= 11)
2875 && !(ltoh16(rxh->RxStatus2) & RXS_PHYRXST_VALID)) {
2876 rssi = WLC_RSSI_INVALID;
2881 u8 gidx = (ltoh16(rxh->PhyRxStatus_2) & 0xFC00) >> 10;
2882 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
2887 rssi = rssi + lcnphy_gain_index_offset_for_pkt_rssi[gidx];
2888 if ((rssi > -46) && (gidx > 18))
2891 rssi = rssi + pi_lcn->lcnphy_pkteng_rssi_slope;
2901 } else if (radioid == BCM2055_ID || radioid == BCM2056_ID
2902 || radioid == BCM2057_ID) {
2904 rssi = wlc_phy_rssi_compute_nphy(pi, wlc_rxhdr);
2906 ASSERT((const char *)"Unknown radio" == NULL);
2910 wlc_rxhdr->rssi = (s8) rssi;
2913 void wlc_phy_freqtrack_start(wlc_phy_t *pih)
2918 void wlc_phy_freqtrack_end(wlc_phy_t *pih)
2923 void wlc_phy_set_deaf(wlc_phy_t *ppi, bool user_flag)
2926 pi = (phy_info_t *) ppi;
2929 wlc_lcnphy_deaf_mode(pi, true);
2930 else if (ISNPHY(pi))
2931 wlc_nphy_deaf_mode(pi, true);
2937 void wlc_phy_watchdog(wlc_phy_t *pih)
2939 phy_info_t *pi = (phy_info_t *) pih;
2940 bool delay_phy_cal = false;
2943 if (!pi->watchdog_override)
2946 if (!(SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi))) {
2947 wlc_phy_noise_sample_request((wlc_phy_t *) pi,
2948 PHY_NOISE_SAMPLE_MON,
2953 if (pi->phynoise_state && (pi->sh->now - pi->phynoise_now) > 5) {
2954 pi->phynoise_state = 0;
2957 if ((!pi->phycal_txpower) ||
2958 ((pi->sh->now - pi->phycal_txpower) >= pi->sh->fast_timer)) {
2960 if (!SCAN_INPROG_PHY(pi) && wlc_phy_cal_txpower_recalc_sw(pi)) {
2961 pi->phycal_txpower = pi->sh->now;
2965 if (NORADIO_ENAB(pi->pubpi))
2968 if ((SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi)
2969 || ASSOC_INPROG_PHY(pi)))
2972 if (ISNPHY(pi) && !pi->disable_percal && !delay_phy_cal) {
2974 if ((pi->nphy_perical != PHY_PERICAL_DISABLE) &&
2975 (pi->nphy_perical != PHY_PERICAL_MANUAL) &&
2976 ((pi->sh->now - pi->nphy_perical_last) >=
2977 pi->sh->glacial_timer))
2978 wlc_phy_cal_perical((wlc_phy_t *) pi,
2979 PHY_PERICAL_WATCHDOG);
2981 wlc_phy_txpwr_papd_cal_nphy(pi);
2985 if (pi->phy_forcecal ||
2986 ((pi->sh->now - pi->phy_lastcal) >=
2987 pi->sh->glacial_timer)) {
2988 if (!(SCAN_RM_IN_PROGRESS(pi) || ASSOC_INPROG_PHY(pi)))
2989 wlc_lcnphy_calib_modes(pi,
2990 LCNPHY_PERICAL_TEMPBASED_TXPWRCTRL);
2992 (SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi)
2993 || ASSOC_INPROG_PHY(pi)
2994 || pi->carrier_suppr_disable
2995 || pi->disable_percal))
2996 wlc_lcnphy_calib_modes(pi,
2997 PHY_PERICAL_WATCHDOG);
3002 void wlc_phy_BSSinit(wlc_phy_t *pih, bool bonlyap, int rssi)
3004 phy_info_t *pi = (phy_info_t *) pih;
3008 for (i = 0; i < MA_WINDOW_SZ; i++) {
3009 pi->sh->phy_noise_window[i] = (s8) (rssi & 0xff);
3012 for (i = 0; i < MA_WINDOW_SZ; i++)
3013 pi->sh->phy_noise_window[i] =
3014 PHY_NOISE_FIXED_VAL_LCNPHY;
3016 pi->sh->phy_noise_index = 0;
3018 for (i = 0; i < PHY_NOISE_WINDOW_SZ; i++) {
3019 for (k = WL_ANT_IDX_1; k < WL_ANT_RX_MAX; k++)
3020 pi->nphy_noise_win[k][i] = PHY_NOISE_FIXED_VAL_NPHY;
3022 pi->nphy_noise_index = 0;
3026 wlc_phy_papd_decode_epsilon(u32 epsilon, s32 *eps_real, s32 *eps_imag)
3028 *eps_imag = (epsilon >> 13);
3029 if (*eps_imag > 0xfff)
3030 *eps_imag -= 0x2000;
3032 *eps_real = (epsilon & 0x1fff);
3033 if (*eps_real > 0xfff)
3034 *eps_real -= 0x2000;
3037 static const fixed AtanTbl[] = {
3058 void wlc_phy_cordic(fixed theta, cs32 *val)
3060 fixed angle, valtmp;
3065 val[0].i = CORDIC_AG;
3069 signtheta = (theta < 0) ? -1 : 1;
3071 ((theta + FIXED(180) * signtheta) % FIXED(360)) -
3072 FIXED(180) * signtheta;
3074 if (FLOAT(theta) > 90) {
3075 theta -= FIXED(180);
3077 } else if (FLOAT(theta) < -90) {
3078 theta += FIXED(180);
3082 for (iter = 0; iter < CORDIC_NI; iter++) {
3083 if (theta > angle) {
3084 valtmp = val[0].i - (val[0].q >> iter);
3085 val[0].q = (val[0].i >> iter) + val[0].q;
3087 angle += AtanTbl[iter];
3089 valtmp = val[0].i + (val[0].q >> iter);
3090 val[0].q = -(val[0].i >> iter) + val[0].q;
3092 angle -= AtanTbl[iter];
3096 val[0].i = val[0].i * signx;
3097 val[0].q = val[0].q * signx;
3100 void wlc_phy_cal_perical_mphase_reset(phy_info_t *pi)
3102 wlapi_del_timer(pi->sh->physhim, pi->phycal_timer);
3104 pi->cal_type_override = PHY_PERICAL_AUTO;
3105 pi->mphase_cal_phase_id = MPHASE_CAL_STATE_IDLE;
3106 pi->mphase_txcal_cmdidx = 0;
3109 static void wlc_phy_cal_perical_mphase_schedule(phy_info_t *pi, uint delay)
3112 if ((pi->nphy_perical != PHY_PERICAL_MPHASE) &&
3113 (pi->nphy_perical != PHY_PERICAL_MANUAL))
3116 wlapi_del_timer(pi->sh->physhim, pi->phycal_timer);
3118 pi->mphase_cal_phase_id = MPHASE_CAL_STATE_INIT;
3119 wlapi_add_timer(pi->sh->physhim, pi->phycal_timer, delay, 0);
3122 void wlc_phy_cal_perical(wlc_phy_t *pih, u8 reason)
3124 s16 nphy_currtemp = 0;
3126 bool do_periodic_cal = true;
3127 phy_info_t *pi = (phy_info_t *) pih;
3132 if ((pi->nphy_perical == PHY_PERICAL_DISABLE) ||
3133 (pi->nphy_perical == PHY_PERICAL_MANUAL))
3137 case PHY_PERICAL_DRIVERUP:
3140 case PHY_PERICAL_PHYINIT:
3141 if (pi->nphy_perical == PHY_PERICAL_MPHASE) {
3142 if (PHY_PERICAL_MPHASE_PENDING(pi)) {
3143 wlc_phy_cal_perical_mphase_reset(pi);
3145 wlc_phy_cal_perical_mphase_schedule(pi,
3146 PHY_PERICAL_INIT_DELAY);
3150 case PHY_PERICAL_JOIN_BSS:
3151 case PHY_PERICAL_START_IBSS:
3152 case PHY_PERICAL_UP_BSS:
3153 if ((pi->nphy_perical == PHY_PERICAL_MPHASE) &&
3154 PHY_PERICAL_MPHASE_PENDING(pi)) {
3155 wlc_phy_cal_perical_mphase_reset(pi);
3158 pi->first_cal_after_assoc = true;
3160 pi->cal_type_override = PHY_PERICAL_FULL;
3162 if (pi->phycal_tempdelta) {
3163 pi->nphy_lastcal_temp = wlc_phy_tempsense_nphy(pi);
3165 wlc_phy_cal_perical_nphy_run(pi, PHY_PERICAL_FULL);
3168 case PHY_PERICAL_WATCHDOG:
3169 if (pi->phycal_tempdelta) {
3170 nphy_currtemp = wlc_phy_tempsense_nphy(pi);
3172 (nphy_currtemp > pi->nphy_lastcal_temp) ?
3173 nphy_currtemp - pi->nphy_lastcal_temp :
3174 pi->nphy_lastcal_temp - nphy_currtemp;
3176 if ((delta_temp < (s16) pi->phycal_tempdelta) &&
3177 (pi->nphy_txiqlocal_chanspec ==
3178 pi->radio_chanspec)) {
3179 do_periodic_cal = false;
3181 pi->nphy_lastcal_temp = nphy_currtemp;
3185 if (do_periodic_cal) {
3187 if (pi->nphy_perical == PHY_PERICAL_MPHASE) {
3189 if (!PHY_PERICAL_MPHASE_PENDING(pi))
3190 wlc_phy_cal_perical_mphase_schedule(pi,
3191 PHY_PERICAL_WDOG_DELAY);
3192 } else if (pi->nphy_perical == PHY_PERICAL_SPHASE)
3193 wlc_phy_cal_perical_nphy_run(pi,
3206 void wlc_phy_cal_perical_mphase_restart(phy_info_t *pi)
3208 pi->mphase_cal_phase_id = MPHASE_CAL_STATE_INIT;
3209 pi->mphase_txcal_cmdidx = 0;
3212 u8 wlc_phy_nbits(s32 value)
3217 abs_val = ABS(value);
3218 while ((abs_val >> nbits) > 0)
3224 u32 wlc_phy_sqrt_int(u32 value)
3226 u32 root = 0, shift = 0;
3228 for (shift = 0; shift < 32; shift += 2) {
3229 if (((0x40000000 >> shift) + root) <= value) {
3230 value -= ((0x40000000 >> shift) + root);
3231 root = (root >> 1) | (0x40000000 >> shift);
3243 void wlc_phy_stf_chain_init(wlc_phy_t *pih, u8 txchain, u8 rxchain)
3245 phy_info_t *pi = (phy_info_t *) pih;
3247 pi->sh->hw_phytxchain = txchain;
3248 pi->sh->hw_phyrxchain = rxchain;
3249 pi->sh->phytxchain = txchain;
3250 pi->sh->phyrxchain = rxchain;
3251 pi->pubpi.phy_corenum = (u8) PHY_BITSCNT(pi->sh->phyrxchain);
3254 void wlc_phy_stf_chain_set(wlc_phy_t *pih, u8 txchain, u8 rxchain)
3256 phy_info_t *pi = (phy_info_t *) pih;
3258 pi->sh->phytxchain = txchain;
3261 wlc_phy_rxcore_setstate_nphy(pih, rxchain);
3263 pi->pubpi.phy_corenum = (u8) PHY_BITSCNT(pi->sh->phyrxchain);
3266 void wlc_phy_stf_chain_get(wlc_phy_t *pih, u8 *txchain, u8 *rxchain)
3268 phy_info_t *pi = (phy_info_t *) pih;
3270 *txchain = pi->sh->phytxchain;
3271 *rxchain = pi->sh->phyrxchain;
3274 u8 wlc_phy_stf_chain_active_get(wlc_phy_t *pih)
3278 phy_info_t *pi = (phy_info_t *) pih;
3280 active_bitmap = (pi->phy_txcore_heatedup) ? 0x31 : 0x33;
3282 if (!pi->watchdog_override)
3283 return active_bitmap;
3285 if (NREV_GE(pi->pubpi.phy_rev, 6)) {
3286 wlapi_suspend_mac_and_wait(pi->sh->physhim);
3287 nphy_currtemp = wlc_phy_tempsense_nphy(pi);
3288 wlapi_enable_mac(pi->sh->physhim);
3290 if (!pi->phy_txcore_heatedup) {
3291 if (nphy_currtemp >= pi->phy_txcore_disable_temp) {
3292 active_bitmap &= 0xFD;
3293 pi->phy_txcore_heatedup = true;
3296 if (nphy_currtemp <= pi->phy_txcore_enable_temp) {
3297 active_bitmap |= 0x2;
3298 pi->phy_txcore_heatedup = false;
3303 return active_bitmap;
3306 s8 wlc_phy_stf_ssmode_get(wlc_phy_t *pih, chanspec_t chanspec)
3308 phy_info_t *pi = (phy_info_t *) pih;
3309 u8 siso_mcs_id, cdd_mcs_id;
3312 (CHSPEC_IS40(chanspec)) ? TXP_FIRST_MCS_40_SISO :
3313 TXP_FIRST_MCS_20_SISO;
3315 (CHSPEC_IS40(chanspec)) ? TXP_FIRST_MCS_40_CDD :
3316 TXP_FIRST_MCS_20_CDD;
3318 if (pi->tx_power_target[siso_mcs_id] >
3319 (pi->tx_power_target[cdd_mcs_id] + 12))
3320 return PHY_TXC1_MODE_SISO;
3322 return PHY_TXC1_MODE_CDD;
3325 const u8 *wlc_phy_get_ofdm_rate_lookup(void)
3327 return ofdm_rate_lookup;
3330 void wlc_lcnphy_epa_switch(phy_info_t *pi, bool mode)
3332 if ((CHIPID(pi->sh->chip) == BCM4313_CHIP_ID) &&
3333 (pi->sh->boardflags & BFL_FEM)) {
3336 txant = wlapi_bmac_get_txant(pi->sh->physhim);
3338 mod_phy_reg(pi, 0x44d, (0x1 << 2), (1) << 2);
3340 mod_phy_reg(pi, 0x44c, (0x1 << 2), (1) << 2);
3343 si_corereg(pi->sh->sih, SI_CC_IDX,
3344 offsetof(chipcregs_t, gpiocontrol), ~0x0,
3346 si_corereg(pi->sh->sih, SI_CC_IDX,
3347 offsetof(chipcregs_t, gpioout), 0x40, 0x40);
3348 si_corereg(pi->sh->sih, SI_CC_IDX,
3349 offsetof(chipcregs_t, gpioouten), 0x40,
3352 mod_phy_reg(pi, 0x44c, (0x1 << 2), (0) << 2);
3354 mod_phy_reg(pi, 0x44d, (0x1 << 2), (0) << 2);
3356 si_corereg(pi->sh->sih, SI_CC_IDX,
3357 offsetof(chipcregs_t, gpioout), 0x40, 0x00);
3358 si_corereg(pi->sh->sih, SI_CC_IDX,
3359 offsetof(chipcregs_t, gpioouten), 0x40, 0x0);
3360 si_corereg(pi->sh->sih, SI_CC_IDX,
3361 offsetof(chipcregs_t, gpiocontrol), ~0x0,
3368 wlc_user_txpwr_antport_to_rfport(phy_info_t *pi, uint chan, u32 band,
3373 if (!pi->user_txpwr_at_rfport)
3378 static s8 wlc_phy_env_measure_vbat(phy_info_t *pi)
3381 return wlc_lcnphy_vbatsense(pi, 0);
3386 static s8 wlc_phy_env_measure_temperature(phy_info_t *pi)
3389 return wlc_lcnphy_tempsense_degree(pi, 0);
3394 static void wlc_phy_upd_env_txpwr_rate_limits(phy_info_t *pi, u32 band)
3399 for (i = 0; i < TXP_NUM_RATES; i++)
3400 pi->txpwr_env_limit[i] = WLC_TXPWR_MAX;
3402 vbat = wlc_phy_env_measure_vbat(pi);
3403 temp = wlc_phy_env_measure_temperature(pi);
3407 void wlc_phy_ldpc_override_set(wlc_phy_t *ppi, bool ldpc)
3413 wlc_phy_get_pwrdet_offsets(phy_info_t *pi, s8 *cckoffset, s8 *ofdmoffset)
3419 u32 wlc_phy_qdiv_roundup(u32 dividend, u32 divisor, u8 precision)
3421 u32 quotient, remainder, roundup, rbit;
3425 quotient = dividend / divisor;
3426 remainder = dividend % divisor;
3428 roundup = (divisor >> 1) + rbit;
3430 while (precision--) {
3432 if (remainder >= roundup) {
3434 remainder = ((remainder - roundup) << 1) + rbit;
3440 if (remainder >= roundup)
3446 s8 wlc_phy_upd_rssi_offset(phy_info_t *pi, s8 rssi, chanspec_t chanspec)
3452 bool wlc_phy_txpower_ipa_ison(wlc_phy_t *ppi)
3454 phy_info_t *pi = (phy_info_t *) ppi;
3457 return wlc_phy_n_txpower_ipa_ison(pi);