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.
20 #include <bcmendian.h>
24 #include <wlc_phy_int.h>
25 #include <wlc_phyreg_n.h>
26 #include <wlc_phy_radio.h>
27 #include <wlc_phy_lcn.h>
29 uint32 phyhal_msg_level = PHYHAL_ERROR;
31 typedef struct _chan_info_basic {
36 static chan_info_basic_t chan_info_all[] = {
96 uint16 ltrn_list[PHY_LTRN_LIST_LEN] = {
97 0x18f9, 0x0d01, 0x00e4, 0xdef4, 0x06f1, 0x0ffc,
98 0xfa27, 0x1dff, 0x10f0, 0x0918, 0xf20a, 0xe010,
99 0x1417, 0x1104, 0xf114, 0xf2fa, 0xf7db, 0xe2fc,
100 0xe1fb, 0x13ee, 0xff0d, 0xe91c, 0x171a, 0x0318,
101 0xda00, 0x03e8, 0x17e6, 0xe9e4, 0xfff3, 0x1312,
102 0xe105, 0xe204, 0xf725, 0xf206, 0xf1ec, 0x11fc,
103 0x14e9, 0xe0f0, 0xf2f6, 0x09e8, 0x1010, 0x1d01,
104 0xfad9, 0x0f04, 0x060f, 0xde0c, 0x001c, 0x0dff,
105 0x1807, 0xf61a, 0xe40e, 0x0f16, 0x05f9, 0x18ec,
106 0x0a1b, 0xff1e, 0x2600, 0xffe2, 0x0ae5, 0x1814,
107 0x0507, 0x0fea, 0xe4f2, 0xf6e6
110 const uint8 ofdm_rate_lookup[] = {
122 #define PHY_WREG_LIMIT 24
124 static void wlc_set_phy_uninitted(phy_info_t * pi);
125 static uint32 wlc_phy_get_radio_ver(phy_info_t * pi);
126 static void wlc_phy_timercb_phycal(void *arg);
128 static bool wlc_phy_noise_calc_phy(phy_info_t * pi, uint32 * cmplx_pwr,
131 static void wlc_phy_cal_perical_mphase_schedule(phy_info_t * pi, uint delay);
132 static void wlc_phy_noise_cb(phy_info_t * pi, uint8 channel, int8 noise_dbm);
133 static void wlc_phy_noise_sample_request(wlc_phy_t * pih, uint8 reason,
136 static void wlc_phy_txpower_reg_limit_calc(phy_info_t * pi,
137 struct txpwr_limits *tp, chanspec_t);
138 static bool wlc_phy_cal_txpower_recalc_sw(phy_info_t * pi);
140 static int8 wlc_user_txpwr_antport_to_rfport(phy_info_t * pi, uint chan,
141 uint32 band, uint8 rate);
142 static void wlc_phy_upd_env_txpwr_rate_limits(phy_info_t * pi, uint32 band);
143 static int8 wlc_phy_env_measure_vbat(phy_info_t * pi);
144 static int8 wlc_phy_env_measure_temperature(phy_info_t * pi);
146 char *phy_getvar(phy_info_t * pi, const char *name)
148 char *vars = pi->vars;
152 ASSERT(pi->vars != (char *)&pi->vars);
161 for (s = vars; s && *s;) {
162 if ((bcmp(s, name, len) == 0) && (s[len] == '='))
163 return (&s[len + 1]);
168 return (nvram_get(name));
171 int phy_getintvar(phy_info_t * pi, const char *name)
175 if ((val = PHY_GETVAR(pi, name)) == NULL)
178 return (bcm_strtoul(val, NULL, 0));
181 void wlc_phyreg_enter(wlc_phy_t * pih)
183 phy_info_t *pi = (phy_info_t *) pih;
184 wlapi_bmac_ucode_wake_override_phyreg_set(pi->sh->physhim);
187 void wlc_phyreg_exit(wlc_phy_t * pih)
189 phy_info_t *pi = (phy_info_t *) pih;
190 wlapi_bmac_ucode_wake_override_phyreg_clear(pi->sh->physhim);
193 void wlc_radioreg_enter(wlc_phy_t * pih)
195 phy_info_t *pi = (phy_info_t *) pih;
196 wlapi_bmac_mctrl(pi->sh->physhim, MCTL_LOCK_RADIO, MCTL_LOCK_RADIO);
201 void wlc_radioreg_exit(wlc_phy_t * pih)
203 phy_info_t *pi = (phy_info_t *) pih;
204 volatile uint16 dummy;
206 dummy = R_REG(pi->sh->osh, &pi->regs->phyversion);
208 wlapi_bmac_mctrl(pi->sh->physhim, MCTL_LOCK_RADIO, 0);
211 uint16 read_radio_reg(phy_info_t * pi, uint16 addr)
215 if ((addr == RADIO_IDCODE))
218 if (NORADIO_ENAB(pi->pubpi))
219 return (NORADIO_IDCODE & 0xffff);
221 switch (pi->pubpi.phy_type) {
223 CASECHECK(PHYTYPE, PHY_TYPE_N);
224 if (NREV_GE(pi->pubpi.phy_rev, 7))
225 addr |= RADIO_2057_READ_OFF;
227 addr |= RADIO_2055_READ_OFF;
231 CASECHECK(PHYTYPE, PHY_TYPE_LCN);
232 addr |= RADIO_2064_READ_OFF;
236 ASSERT(VALID_PHYTYPE(pi->pubpi.phy_type));
239 if ((D11REV_GE(pi->sh->corerev, 24)) ||
240 (D11REV_IS(pi->sh->corerev, 22)
241 && (pi->pubpi.phy_type != PHY_TYPE_SSN))) {
242 W_REG(pi->sh->osh, &pi->regs->radioregaddr, addr);
244 (void)R_REG(pi->sh->osh, &pi->regs->radioregaddr);
246 data = R_REG(pi->sh->osh, &pi->regs->radioregdata);
248 W_REG(pi->sh->osh, &pi->regs->phy4waddr, addr);
250 (void)R_REG(pi->sh->osh, &pi->regs->phy4waddr);
253 #ifdef __ARM_ARCH_4T__
254 __asm__(" .align 4 ");
256 data = R_REG(pi->sh->osh, &pi->regs->phy4wdatalo);
258 data = R_REG(pi->sh->osh, &pi->regs->phy4wdatalo);
267 void write_radio_reg(phy_info_t * pi, uint16 addr, uint16 val)
271 if (NORADIO_ENAB(pi->pubpi))
276 if ((D11REV_GE(pi->sh->corerev, 24)) ||
277 (D11REV_IS(pi->sh->corerev, 22)
278 && (pi->pubpi.phy_type != PHY_TYPE_SSN))) {
280 W_REG(osh, &pi->regs->radioregaddr, addr);
282 (void)R_REG(osh, &pi->regs->radioregaddr);
284 W_REG(osh, &pi->regs->radioregdata, val);
286 W_REG(osh, &pi->regs->phy4waddr, addr);
288 (void)R_REG(osh, &pi->regs->phy4waddr);
290 W_REG(osh, &pi->regs->phy4wdatalo, val);
293 if (BUSTYPE(pi->sh->bustype) == PCI_BUS) {
294 if (++pi->phy_wreg >= pi->phy_wreg_limit) {
295 (void)R_REG(osh, &pi->regs->maccontrol);
301 static uint32 read_radio_id(phy_info_t * pi)
305 if (NORADIO_ENAB(pi->pubpi))
306 return (NORADIO_IDCODE);
308 if (D11REV_GE(pi->sh->corerev, 24)) {
311 W_REG(pi->sh->osh, &pi->regs->radioregaddr, 0);
313 (void)R_REG(pi->sh->osh, &pi->regs->radioregaddr);
315 b0 = (uint32) R_REG(pi->sh->osh, &pi->regs->radioregdata);
316 W_REG(pi->sh->osh, &pi->regs->radioregaddr, 1);
318 (void)R_REG(pi->sh->osh, &pi->regs->radioregaddr);
320 b1 = (uint32) R_REG(pi->sh->osh, &pi->regs->radioregdata);
321 W_REG(pi->sh->osh, &pi->regs->radioregaddr, 2);
323 (void)R_REG(pi->sh->osh, &pi->regs->radioregaddr);
325 b2 = (uint32) R_REG(pi->sh->osh, &pi->regs->radioregdata);
327 id = ((b0 & 0xf) << 28) | (((b2 << 8) | b1) << 12) | ((b0 >> 4)
330 W_REG(pi->sh->osh, &pi->regs->phy4waddr, RADIO_IDCODE);
332 (void)R_REG(pi->sh->osh, &pi->regs->phy4waddr);
334 id = (uint32) R_REG(pi->sh->osh, &pi->regs->phy4wdatalo);
335 id |= (uint32) R_REG(pi->sh->osh, &pi->regs->phy4wdatahi) << 16;
341 void and_radio_reg(phy_info_t * pi, uint16 addr, uint16 val)
345 if (NORADIO_ENAB(pi->pubpi))
348 rval = read_radio_reg(pi, addr);
349 write_radio_reg(pi, addr, (rval & val));
352 void or_radio_reg(phy_info_t * pi, uint16 addr, uint16 val)
356 if (NORADIO_ENAB(pi->pubpi))
359 rval = read_radio_reg(pi, addr);
360 write_radio_reg(pi, addr, (rval | val));
363 void xor_radio_reg(phy_info_t * pi, uint16 addr, uint16 mask)
367 if (NORADIO_ENAB(pi->pubpi))
370 rval = read_radio_reg(pi, addr);
371 write_radio_reg(pi, addr, (rval ^ mask));
374 void mod_radio_reg(phy_info_t * pi, uint16 addr, uint16 mask, uint16 val)
378 if (NORADIO_ENAB(pi->pubpi))
381 rval = read_radio_reg(pi, addr);
382 write_radio_reg(pi, addr, (rval & ~mask) | (val & mask));
385 void write_phy_channel_reg(phy_info_t * pi, uint val)
387 W_REG(pi->sh->osh, &pi->regs->phychannel, val);
391 static bool wlc_phy_war41476(phy_info_t * pi)
393 uint32 mc = R_REG(pi->sh->osh, &pi->regs->maccontrol);
395 return ((mc & MCTL_EN_MAC) == 0)
396 || ((mc & MCTL_PHYLOCK) == MCTL_PHYLOCK);
400 uint16 read_phy_reg(phy_info_t * pi, uint16 addr)
408 W_REG(osh, ®s->phyregaddr, addr);
410 (void)R_REG(osh, ®s->phyregaddr);
414 (D11REV_IS(pi->sh->corerev, 11)
415 || D11REV_IS(pi->sh->corerev, 12)) || wlc_phy_war41476(pi));
418 return (R_REG(osh, ®s->phyregdata));
421 void write_phy_reg(phy_info_t * pi, uint16 addr, uint16 val)
430 W_REG(osh, ®s->phyregaddr, addr);
431 (void)R_REG(osh, ®s->phyregaddr);
432 W_REG(osh, ®s->phyregdata, val);
434 (void)R_REG(osh, ®s->phyregdata);
436 W_REG(osh, (volatile uint32 *)(uintptr) (®s->phyregaddr),
438 if (BUSTYPE(pi->sh->bustype) == PCI_BUS) {
439 if (++pi->phy_wreg >= pi->phy_wreg_limit) {
441 (void)R_REG(osh, ®s->phyversion);
447 void and_phy_reg(phy_info_t * pi, uint16 addr, uint16 val)
455 W_REG(osh, ®s->phyregaddr, addr);
457 (void)R_REG(osh, ®s->phyregaddr);
461 (D11REV_IS(pi->sh->corerev, 11)
462 || D11REV_IS(pi->sh->corerev, 12)) || wlc_phy_war41476(pi));
464 W_REG(osh, ®s->phyregdata, (R_REG(osh, ®s->phyregdata) & val));
468 void or_phy_reg(phy_info_t * pi, uint16 addr, uint16 val)
476 W_REG(osh, ®s->phyregaddr, addr);
478 (void)R_REG(osh, ®s->phyregaddr);
482 (D11REV_IS(pi->sh->corerev, 11)
483 || D11REV_IS(pi->sh->corerev, 12)) || wlc_phy_war41476(pi));
485 W_REG(osh, ®s->phyregdata, (R_REG(osh, ®s->phyregdata) | val));
489 void mod_phy_reg(phy_info_t * pi, uint16 addr, uint16 mask, uint16 val)
497 W_REG(osh, ®s->phyregaddr, addr);
499 (void)R_REG(osh, ®s->phyregaddr);
503 (D11REV_IS(pi->sh->corerev, 11)
504 || D11REV_IS(pi->sh->corerev, 12)) || wlc_phy_war41476(pi));
506 W_REG(osh, ®s->phyregdata,
507 ((R_REG(osh, ®s->phyregdata) & ~mask) | (val & mask)));
511 static void WLBANDINITFN(wlc_set_phy_uninitted) (phy_info_t * pi) {
514 pi->initialized = FALSE;
517 pi->nrssi_table_delta = 0x7fffffff;
519 pi->mintxbias = 0xffff;
522 pi->phy_spuravoid = SPURAVOID_DISABLE;
524 if (NREV_GE(pi->pubpi.phy_rev, 3)
525 && NREV_LT(pi->pubpi.phy_rev, 7))
526 pi->phy_spuravoid = SPURAVOID_AUTO;
528 pi->nphy_papd_skip = 0;
529 pi->nphy_papd_epsilon_offset[0] = 0xf588;
530 pi->nphy_papd_epsilon_offset[1] = 0xf588;
531 pi->nphy_txpwr_idx[0] = 128;
532 pi->nphy_txpwr_idx[1] = 128;
533 pi->nphy_txpwrindex[0].index_internal = 40;
534 pi->nphy_txpwrindex[1].index_internal = 40;
537 pi->phy_spuravoid = SPURAVOID_AUTO;
539 pi->radiopwr = 0xffff;
540 for (i = 0; i < STATIC_NUM_RF; i++) {
541 for (j = 0; j < STATIC_NUM_BB; j++) {
542 pi->stats_11b_txpower[i][j] = -1;
547 shared_phy_t *BCMATTACHFN(wlc_phy_shared_attach) (shared_phy_params_t * shp) {
551 (shared_phy_t *) MALLOC(shp->osh, sizeof(shared_phy_t))) == NULL) {
554 bzero((char *)sh, sizeof(shared_phy_t));
558 sh->physhim = shp->physhim;
559 sh->unit = shp->unit;
560 sh->corerev = shp->corerev;
564 sh->chip = shp->chip;
565 sh->chiprev = shp->chiprev;
566 sh->chippkg = shp->chippkg;
567 sh->sromrev = shp->sromrev;
568 sh->boardtype = shp->boardtype;
569 sh->boardrev = shp->boardrev;
570 sh->boardvendor = shp->boardvendor;
571 sh->boardflags = shp->boardflags;
572 sh->boardflags2 = shp->boardflags2;
573 sh->bustype = shp->bustype;
574 sh->buscorerev = shp->buscorerev;
576 sh->fast_timer = PHY_SW_TIMER_FAST;
577 sh->slow_timer = PHY_SW_TIMER_SLOW;
578 sh->glacial_timer = PHY_SW_TIMER_GLACIAL;
580 sh->rssi_mode = RSSI_ANT_MERGE_MAX;
585 void BCMATTACHFN(wlc_phy_shared_detach) (shared_phy_t * phy_sh) {
591 if (phy_sh->phy_head) {
592 ASSERT(!phy_sh->phy_head);
594 MFREE(osh, phy_sh, sizeof(shared_phy_t));
598 wlc_phy_t *BCMATTACHFN(wlc_phy_attach) (shared_phy_t * sh, void *regs,
599 int bandtype, char *vars) {
608 if (D11REV_IS(sh->corerev, 4))
609 sflags = SISF_2G_PHY | SISF_5G_PHY;
611 sflags = si_core_sflags(sh->sih, 0, 0);
613 if (BAND_5G(bandtype)) {
614 if ((sflags & (SISF_5G_PHY | SISF_DB_PHY)) == 0) {
619 if ((sflags & SISF_DB_PHY) && (pi = sh->phy_head)) {
621 wlapi_bmac_corereset(pi->sh->physhim, pi->pubpi.coreflags);
623 return &pi->pubpi_ro;
626 if ((pi = (phy_info_t *) MALLOC(osh, sizeof(phy_info_t))) == NULL) {
629 bzero((char *)pi, sizeof(phy_info_t));
630 pi->regs = (d11regs_t *) regs;
632 pi->phy_init_por = TRUE;
633 pi->phy_wreg_limit = PHY_WREG_LIMIT;
637 pi->txpwr_percent = 100;
639 pi->do_initcal = TRUE;
641 pi->phycal_tempdelta = 0;
643 if (BAND_2G(bandtype) && (sflags & SISF_2G_PHY)) {
645 pi->pubpi.coreflags = SICF_GMODE;
648 wlapi_bmac_corereset(pi->sh->physhim, pi->pubpi.coreflags);
649 phyversion = R_REG(osh, &pi->regs->phyversion);
651 pi->pubpi.phy_type = PHY_TYPE(phyversion);
652 pi->pubpi.phy_rev = phyversion & PV_PV_MASK;
654 if (pi->pubpi.phy_type == PHY_TYPE_LCNXN) {
655 pi->pubpi.phy_type = PHY_TYPE_N;
656 pi->pubpi.phy_rev += LCNXN_BASEREV;
658 pi->pubpi.phy_corenum = PHY_CORE_NUM_2;
659 pi->pubpi.ana_rev = (phyversion & PV_AV_MASK) >> PV_AV_SHIFT;
661 if (!VALID_PHYTYPE(pi->pubpi.phy_type)) {
664 if (BAND_5G(bandtype)) {
669 if (!ISNPHY(pi) && !ISLCNPHY(pi)) {
674 if (ISSIM_ENAB(pi->sh->sih)) {
675 pi->pubpi.radioid = NORADIO_ID;
676 pi->pubpi.radiorev = 5;
680 wlc_phy_anacore((wlc_phy_t *) pi, ON);
682 idcode = wlc_phy_get_radio_ver(pi);
684 (idcode & IDCODE_ID_MASK) >> IDCODE_ID_SHIFT;
686 (idcode & IDCODE_REV_MASK) >> IDCODE_REV_SHIFT;
688 (idcode & IDCODE_VER_MASK) >> IDCODE_VER_SHIFT;
689 if (!VALID_RADIO(pi, pi->pubpi.radioid)) {
693 wlc_phy_switch_radio((wlc_phy_t *) pi, OFF);
696 wlc_set_phy_uninitted(pi);
698 pi->bw = WL_CHANSPEC_BW_20;
700 BAND_2G(bandtype) ? CH20MHZ_CHSPEC(1) : CH20MHZ_CHSPEC(36);
702 pi->rxiq_samps = PHY_NOISE_SAMPLE_LOG_NUM_NPHY;
703 pi->rxiq_antsel = ANT_RX_DIV_DEF;
705 pi->watchdog_override = TRUE;
707 pi->cal_type_override = PHY_PERICAL_AUTO;
709 pi->nphy_saved_noisevars.bufcount = 0;
712 pi->min_txpower = PHY_TXPWR_MIN_NPHY;
714 pi->min_txpower = PHY_TXPWR_MIN;
716 pi->sh->phyrxchain = 0x3;
718 pi->rx2tx_biasentry = -1;
720 pi->phy_txcore_disable_temp = PHY_CHAIN_TX_DISABLE_TEMP;
721 pi->phy_txcore_enable_temp =
722 PHY_CHAIN_TX_DISABLE_TEMP - PHY_HYSTERESIS_DELTATEMP;
723 pi->phy_tempsense_offset = 0;
724 pi->phy_txcore_heatedup = FALSE;
726 pi->nphy_lastcal_temp = -50;
728 pi->phynoise_polling = TRUE;
729 if (ISNPHY(pi) || ISLCNPHY(pi))
730 pi->phynoise_polling = FALSE;
732 for (i = 0; i < TXP_NUM_RATES; i++) {
733 pi->txpwr_limit[i] = WLC_TXPWR_MAX;
734 pi->txpwr_env_limit[i] = WLC_TXPWR_MAX;
735 pi->tx_user_target[i] = WLC_TXPWR_MAX;
738 pi->radiopwr_override = RADIOPWR_OVERRIDE_DEF;
740 pi->user_txpwr_at_rfport = FALSE;
744 if (!(pi->phycal_timer = wlapi_init_timer(pi->sh->physhim,
745 wlc_phy_timercb_phycal,
750 if (!wlc_phy_attach_nphy(pi))
753 } else if (ISLCNPHY(pi)) {
754 if (!wlc_phy_attach_lcnphy(pi))
762 pi->next = pi->sh->phy_head;
765 pi->vars = (char *)&pi->vars;
767 bcopy(&pi->pubpi, &pi->pubpi_ro, sizeof(wlc_phy_t));
769 return &pi->pubpi_ro;
773 MFREE(sh->osh, pi, sizeof(phy_info_t));
777 void BCMATTACHFN(wlc_phy_detach) (wlc_phy_t * pih) {
778 phy_info_t *pi = (phy_info_t *) pih;
785 if (pi->phycal_timer) {
786 wlapi_free_timer(pi->sh->physhim, pi->phycal_timer);
787 pi->phycal_timer = NULL;
790 if (pi->sh->phy_head == pi)
791 pi->sh->phy_head = pi->next;
792 else if (pi->sh->phy_head->next == pi)
793 pi->sh->phy_head->next = NULL;
797 if (pi->pi_fptr.detach)
798 (pi->pi_fptr.detach) (pi);
800 MFREE(pi->sh->osh, pi, sizeof(phy_info_t));
805 wlc_phy_get_phyversion(wlc_phy_t * pih, uint16 * phytype, uint16 * phyrev,
806 uint16 * radioid, uint16 * radiover)
808 phy_info_t *pi = (phy_info_t *) pih;
809 *phytype = (uint16) pi->pubpi.phy_type;
810 *phyrev = (uint16) pi->pubpi.phy_rev;
811 *radioid = pi->pubpi.radioid;
812 *radiover = pi->pubpi.radiorev;
817 bool wlc_phy_get_encore(wlc_phy_t * pih)
819 phy_info_t *pi = (phy_info_t *) pih;
820 return pi->pubpi.abgphy_encore;
823 uint32 wlc_phy_get_coreflags(wlc_phy_t * pih)
825 phy_info_t *pi = (phy_info_t *) pih;
826 return pi->pubpi.coreflags;
829 static void wlc_phy_timercb_phycal(void *arg)
831 phy_info_t *pi = (phy_info_t *) arg;
834 if (PHY_PERICAL_MPHASE_PENDING(pi)) {
836 wlc_phy_cal_perical_mphase_reset(pi);
840 if (SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi)) {
843 wlc_phy_cal_perical_mphase_restart(pi);
845 wlc_phy_cal_perical_nphy_run(pi, PHY_PERICAL_AUTO);
846 wlapi_add_timer(pi->sh->physhim, pi->phycal_timer, delay, 0);
852 void wlc_phy_anacore(wlc_phy_t * pih, bool on)
854 phy_info_t *pi = (phy_info_t *) pih;
858 if (NREV_GE(pi->pubpi.phy_rev, 3)) {
859 write_phy_reg(pi, 0xa6, 0x0d);
860 write_phy_reg(pi, 0x8f, 0x0);
861 write_phy_reg(pi, 0xa7, 0x0d);
862 write_phy_reg(pi, 0xa5, 0x0);
864 write_phy_reg(pi, 0xa5, 0x0);
867 if (NREV_GE(pi->pubpi.phy_rev, 3)) {
868 write_phy_reg(pi, 0x8f, 0x07ff);
869 write_phy_reg(pi, 0xa6, 0x0fd);
870 write_phy_reg(pi, 0xa5, 0x07ff);
871 write_phy_reg(pi, 0xa7, 0x0fd);
873 write_phy_reg(pi, 0xa5, 0x7fff);
876 } else if (ISLCNPHY(pi)) {
878 and_phy_reg(pi, 0x43b,
879 ~((0x1 << 0) | (0x1 << 1) | (0x1 << 2)));
881 or_phy_reg(pi, 0x43c,
882 (0x1 << 0) | (0x1 << 1) | (0x1 << 2));
883 or_phy_reg(pi, 0x43b,
884 (0x1 << 0) | (0x1 << 1) | (0x1 << 2));
889 uint32 wlc_phy_clk_bwbits(wlc_phy_t * pih)
891 phy_info_t *pi = (phy_info_t *) pih;
893 uint32 phy_bw_clkbits = 0;
895 if (pi && (ISNPHY(pi) || ISLCNPHY(pi))) {
897 case WL_CHANSPEC_BW_10:
898 phy_bw_clkbits = SICF_BW10;
900 case WL_CHANSPEC_BW_20:
901 phy_bw_clkbits = SICF_BW20;
903 case WL_CHANSPEC_BW_40:
904 phy_bw_clkbits = SICF_BW40;
912 return phy_bw_clkbits;
915 void WLBANDINITFN(wlc_phy_por_inform) (wlc_phy_t * ppi) {
916 phy_info_t *pi = (phy_info_t *) ppi;
918 pi->phy_init_por = TRUE;
921 void wlc_phy_edcrs_lock(wlc_phy_t * pih, bool lock)
923 phy_info_t *pi = (phy_info_t *) pih;
925 pi->edcrs_threshold_lock = lock;
927 write_phy_reg(pi, 0x22c, 0x46b);
928 write_phy_reg(pi, 0x22d, 0x46b);
929 write_phy_reg(pi, 0x22e, 0x3c0);
930 write_phy_reg(pi, 0x22f, 0x3c0);
933 void wlc_phy_initcal_enable(wlc_phy_t * pih, bool initcal)
935 phy_info_t *pi = (phy_info_t *) pih;
937 pi->do_initcal = initcal;
940 void wlc_phy_hw_clk_state_upd(wlc_phy_t * pih, bool newstate)
942 phy_info_t *pi = (phy_info_t *) pih;
947 pi->sh->clk = newstate;
950 void wlc_phy_hw_state_upd(wlc_phy_t * pih, bool newstate)
952 phy_info_t *pi = (phy_info_t *) pih;
957 pi->sh->up = newstate;
960 void WLBANDINITFN(wlc_phy_init) (wlc_phy_t * pih, chanspec_t chanspec) {
962 initfn_t phy_init = NULL;
963 phy_info_t *pi = (phy_info_t *) pih;
965 if (pi->init_in_progress)
968 pi->init_in_progress = TRUE;
970 pi->radio_chanspec = chanspec;
972 mc = R_REG(pi->sh->osh, &pi->regs->maccontrol);
973 if ((mc & MCTL_EN_MAC) != 0) {
974 ASSERT((const char *)
975 "wlc_phy_init: Called with the MAC running!" == NULL);
980 if (!(pi->measure_hold & PHY_HOLD_FOR_SCAN)) {
981 pi->measure_hold |= PHY_HOLD_FOR_NOT_ASSOC;
984 if (D11REV_GE(pi->sh->corerev, 5))
985 ASSERT(si_core_sflags(pi->sh->sih, 0, 0) & SISF_FCLKA);
987 phy_init = pi->pi_fptr.init;
989 if (phy_init == NULL) {
990 ASSERT(phy_init != NULL);
994 wlc_phy_anacore(pih, ON);
996 if (CHSPEC_BW(pi->radio_chanspec) != pi->bw)
997 wlapi_bmac_bw_set(pi->sh->physhim,
998 CHSPEC_BW(pi->radio_chanspec));
1000 pi->nphy_gain_boost = TRUE;
1002 wlc_phy_switch_radio((wlc_phy_t *) pi, ON);
1006 pi->phy_init_por = FALSE;
1008 if (D11REV_IS(pi->sh->corerev, 11) || D11REV_IS(pi->sh->corerev, 12))
1009 wlc_phy_do_dummy_tx(pi, TRUE, OFF);
1012 wlc_phy_txpower_update_shm(pi);
1014 wlc_phy_ant_rxdiv_set((wlc_phy_t *) pi, pi->sh->rx_antdiv);
1016 pi->init_in_progress = FALSE;
1019 void BCMINITFN(wlc_phy_cal_init) (wlc_phy_t * pih) {
1020 phy_info_t *pi = (phy_info_t *) pih;
1021 initfn_t cal_init = NULL;
1023 ASSERT((R_REG(pi->sh->osh, &pi->regs->maccontrol) & MCTL_EN_MAC) == 0);
1025 if (!pi->initialized) {
1026 cal_init = pi->pi_fptr.calinit;
1030 pi->initialized = TRUE;
1034 int BCMUNINITFN(wlc_phy_down) (wlc_phy_t * pih) {
1035 phy_info_t *pi = (phy_info_t *) pih;
1038 ASSERT(pi->phytest_on == FALSE);
1040 if (pi->phycal_timer
1041 && !wlapi_del_timer(pi->sh->physhim, pi->phycal_timer))
1044 pi->nphy_iqcal_chanspec_2G = 0;
1045 pi->nphy_iqcal_chanspec_5G = 0;
1050 static uint32 wlc_phy_get_radio_ver(phy_info_t * pi)
1054 ver = read_radio_id(pi);
1060 wlc_phy_table_addr(phy_info_t * pi, uint tbl_id, uint tbl_offset,
1061 uint16 tblAddr, uint16 tblDataHi, uint16 tblDataLo)
1063 write_phy_reg(pi, tblAddr, (tbl_id << 10) | tbl_offset);
1065 pi->tbl_data_hi = tblDataHi;
1066 pi->tbl_data_lo = tblDataLo;
1068 if ((CHIPID(pi->sh->chip) == BCM43224_CHIP_ID ||
1069 CHIPID(pi->sh->chip) == BCM43421_CHIP_ID) &&
1070 (pi->sh->chiprev == 1)) {
1071 pi->tbl_addr = tblAddr;
1072 pi->tbl_save_id = tbl_id;
1073 pi->tbl_save_offset = tbl_offset;
1077 void wlc_phy_table_data_write(phy_info_t * pi, uint width, uint32 val)
1079 ASSERT((width == 8) || (width == 16) || (width == 32));
1081 if ((CHIPID(pi->sh->chip) == BCM43224_CHIP_ID ||
1082 CHIPID(pi->sh->chip) == BCM43421_CHIP_ID) &&
1083 (pi->sh->chiprev == 1) &&
1084 (pi->tbl_save_id == NPHY_TBL_ID_ANTSWCTRLLUT)) {
1085 read_phy_reg(pi, pi->tbl_data_lo);
1087 write_phy_reg(pi, pi->tbl_addr,
1088 (pi->tbl_save_id << 10) | pi->tbl_save_offset);
1089 pi->tbl_save_offset++;
1094 write_phy_reg(pi, pi->tbl_data_hi, (uint16) (val >> 16));
1095 write_phy_reg(pi, pi->tbl_data_lo, (uint16) val);
1098 write_phy_reg(pi, pi->tbl_data_lo, (uint16) val);
1103 wlc_phy_write_table(phy_info_t * pi, const phytbl_info_t * ptbl_info,
1104 uint16 tblAddr, uint16 tblDataHi, uint16 tblDataLo)
1107 uint tbl_id = ptbl_info->tbl_id;
1108 uint tbl_offset = ptbl_info->tbl_offset;
1109 uint tbl_width = ptbl_info->tbl_width;
1110 const uint8 *ptbl_8b = (const uint8 *)ptbl_info->tbl_ptr;
1111 const uint16 *ptbl_16b = (const uint16 *)ptbl_info->tbl_ptr;
1112 const uint32 *ptbl_32b = (const uint32 *)ptbl_info->tbl_ptr;
1114 ASSERT((tbl_width == 8) || (tbl_width == 16) || (tbl_width == 32));
1116 write_phy_reg(pi, tblAddr, (tbl_id << 10) | tbl_offset);
1118 for (idx = 0; idx < ptbl_info->tbl_len; idx++) {
1120 if ((CHIPID(pi->sh->chip) == BCM43224_CHIP_ID ||
1121 CHIPID(pi->sh->chip) == BCM43421_CHIP_ID) &&
1122 (pi->sh->chiprev == 1) &&
1123 (tbl_id == NPHY_TBL_ID_ANTSWCTRLLUT)) {
1124 read_phy_reg(pi, tblDataLo);
1126 write_phy_reg(pi, tblAddr,
1127 (tbl_id << 10) | (tbl_offset + idx));
1130 if (tbl_width == 32) {
1132 write_phy_reg(pi, tblDataHi,
1133 (uint16) (ptbl_32b[idx] >> 16));
1134 write_phy_reg(pi, tblDataLo, (uint16) ptbl_32b[idx]);
1135 } else if (tbl_width == 16) {
1137 write_phy_reg(pi, tblDataLo, ptbl_16b[idx]);
1140 write_phy_reg(pi, tblDataLo, ptbl_8b[idx]);
1146 wlc_phy_read_table(phy_info_t * pi, const phytbl_info_t * ptbl_info,
1147 uint16 tblAddr, uint16 tblDataHi, uint16 tblDataLo)
1150 uint tbl_id = ptbl_info->tbl_id;
1151 uint tbl_offset = ptbl_info->tbl_offset;
1152 uint tbl_width = ptbl_info->tbl_width;
1153 uint8 *ptbl_8b = (uint8 *) (uintptr) ptbl_info->tbl_ptr;
1154 uint16 *ptbl_16b = (uint16 *) (uintptr) ptbl_info->tbl_ptr;
1155 uint32 *ptbl_32b = (uint32 *) (uintptr) ptbl_info->tbl_ptr;
1157 ASSERT((tbl_width == 8) || (tbl_width == 16) || (tbl_width == 32));
1159 write_phy_reg(pi, tblAddr, (tbl_id << 10) | tbl_offset);
1161 for (idx = 0; idx < ptbl_info->tbl_len; idx++) {
1163 if ((CHIPID(pi->sh->chip) == BCM43224_CHIP_ID ||
1164 CHIPID(pi->sh->chip) == BCM43421_CHIP_ID) &&
1165 (pi->sh->chiprev == 1)) {
1166 (void)read_phy_reg(pi, tblDataLo);
1168 write_phy_reg(pi, tblAddr,
1169 (tbl_id << 10) | (tbl_offset + idx));
1172 if (tbl_width == 32) {
1174 ptbl_32b[idx] = read_phy_reg(pi, tblDataLo);
1175 ptbl_32b[idx] |= (read_phy_reg(pi, tblDataHi) << 16);
1176 } else if (tbl_width == 16) {
1178 ptbl_16b[idx] = read_phy_reg(pi, tblDataLo);
1181 ptbl_8b[idx] = (uint8) read_phy_reg(pi, tblDataLo);
1187 wlc_phy_init_radio_regs_allbands(phy_info_t * pi, radio_20xx_regs_t * radioregs)
1192 if (radioregs[i].do_init) {
1193 write_radio_reg(pi, radioregs[i].address,
1194 (uint16) radioregs[i].init);
1198 } while (radioregs[i].address != 0xffff);
1204 wlc_phy_init_radio_regs(phy_info_t * pi, radio_regs_t * radioregs,
1211 if (CHSPEC_IS5G(pi->radio_chanspec)) {
1212 if (radioregs[i].do_init_a) {
1215 address | core_offset,
1216 (uint16) radioregs[i].init_a);
1217 if (ISNPHY(pi) && (++count % 4 == 0))
1218 WLC_PHY_WAR_PR51571(pi);
1221 if (radioregs[i].do_init_g) {
1224 address | core_offset,
1225 (uint16) radioregs[i].init_g);
1226 if (ISNPHY(pi) && (++count % 4 == 0))
1227 WLC_PHY_WAR_PR51571(pi);
1232 } while (radioregs[i].address != 0xffff);
1237 void wlc_phy_do_dummy_tx(phy_info_t * pi, bool ofdm, bool pa_on)
1239 #define DUMMY_PKT_LEN 20
1240 d11regs_t *regs = pi->regs;
1242 uint8 ofdmpkt[DUMMY_PKT_LEN] = {
1243 0xcc, 0x01, 0x02, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00,
1244 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00
1246 uint8 cckpkt[DUMMY_PKT_LEN] = {
1247 0x6e, 0x84, 0x0b, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00,
1248 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00
1252 ASSERT((R_REG(pi->sh->osh, &pi->regs->maccontrol) & MCTL_EN_MAC) == 0);
1254 dummypkt = (uint32 *) (ofdm ? ofdmpkt : cckpkt);
1255 wlapi_bmac_write_template_ram(pi->sh->physhim, 0, DUMMY_PKT_LEN,
1258 W_REG(pi->sh->osh, ®s->xmtsel, 0);
1260 if (D11REV_GE(pi->sh->corerev, 11))
1261 W_REG(pi->sh->osh, ®s->wepctl, 0x100);
1263 W_REG(pi->sh->osh, ®s->wepctl, 0);
1265 W_REG(pi->sh->osh, ®s->txe_phyctl, (ofdm ? 1 : 0) | PHY_TXC_ANT_0);
1266 if (ISNPHY(pi) || ISLCNPHY(pi)) {
1268 W_REG(pi->sh->osh, ®s->txe_phyctl1, 0x1A02);
1271 W_REG(pi->sh->osh, ®s->txe_wm_0, 0);
1272 W_REG(pi->sh->osh, ®s->txe_wm_1, 0);
1274 W_REG(pi->sh->osh, ®s->xmttplatetxptr, 0);
1275 W_REG(pi->sh->osh, ®s->xmttxcnt, DUMMY_PKT_LEN);
1277 W_REG(pi->sh->osh, ®s->xmtsel, ((8 << 8) | (1 << 5) | (1 << 2) | 2));
1279 W_REG(pi->sh->osh, ®s->txe_ctl, 0);
1283 wlc_phy_pa_override_nphy(pi, OFF);
1286 if (ISNPHY(pi) || ISLCNPHY(pi))
1287 W_REG(pi->sh->osh, ®s->txe_aux, 0xD0);
1289 W_REG(pi->sh->osh, ®s->txe_aux, ((1 << 5) | (1 << 4)));
1291 (void)R_REG(pi->sh->osh, ®s->txe_aux);
1294 count = ofdm ? 30 : 250;
1296 if (ISSIM_ENAB(pi->sh->sih)) {
1300 while ((i++ < count)
1301 && (R_REG(pi->sh->osh, ®s->txe_status) & (1 << 7))) {
1308 && ((R_REG(pi->sh->osh, ®s->txe_status) & (1 << 10)) == 0)) {
1314 while ((i++ < 10) && ((R_REG(pi->sh->osh, ®s->ifsstat) & (1 << 8)))) {
1319 wlc_phy_pa_override_nphy(pi, ON);
1323 void wlc_phy_hold_upd(wlc_phy_t * pih, mbool id, bool set)
1325 phy_info_t *pi = (phy_info_t *) pih;
1329 mboolset(pi->measure_hold, id);
1331 mboolclr(pi->measure_hold, id);
1337 void wlc_phy_mute_upd(wlc_phy_t * pih, bool mute, mbool flags)
1339 phy_info_t *pi = (phy_info_t *) pih;
1342 mboolset(pi->measure_hold, PHY_HOLD_FOR_MUTE);
1344 mboolclr(pi->measure_hold, PHY_HOLD_FOR_MUTE);
1347 if (!mute && (flags & PHY_MUTE_FOR_PREISM))
1348 pi->nphy_perical_last = pi->sh->now - pi->sh->glacial_timer;
1352 void wlc_phy_clear_tssi(wlc_phy_t * pih)
1354 phy_info_t *pi = (phy_info_t *) pih;
1359 wlapi_bmac_write_shm(pi->sh->physhim, M_B_TSSI_0, NULL_TSSI_W);
1360 wlapi_bmac_write_shm(pi->sh->physhim, M_B_TSSI_1, NULL_TSSI_W);
1361 wlapi_bmac_write_shm(pi->sh->physhim, M_G_TSSI_0, NULL_TSSI_W);
1362 wlapi_bmac_write_shm(pi->sh->physhim, M_G_TSSI_1, NULL_TSSI_W);
1366 static bool wlc_phy_cal_txpower_recalc_sw(phy_info_t * pi)
1371 void wlc_phy_switch_radio(wlc_phy_t * pih, bool on)
1373 phy_info_t *pi = (phy_info_t *) pih;
1375 if (NORADIO_ENAB(pi->pubpi))
1381 mc = R_REG(pi->sh->osh, &pi->regs->maccontrol);
1385 wlc_phy_switch_radio_nphy(pi, on);
1387 } else if (ISLCNPHY(pi)) {
1389 and_phy_reg(pi, 0x44c,
1392 (0x1 << 10) | (0x1 << 11) | (0x1 << 12)));
1393 and_phy_reg(pi, 0x4b0, ~((0x1 << 3) | (0x1 << 11)));
1394 and_phy_reg(pi, 0x4f9, ~(0x1 << 3));
1396 and_phy_reg(pi, 0x44d,
1399 (0x1 << 12) | (0x1 << 13) | (0x1 << 14)));
1400 or_phy_reg(pi, 0x44c,
1403 (0x1 << 10) | (0x1 << 11) | (0x1 << 12));
1405 and_phy_reg(pi, 0x4b7, ~((0x7f << 8)));
1406 and_phy_reg(pi, 0x4b1, ~((0x1 << 13)));
1407 or_phy_reg(pi, 0x4b0, (0x1 << 3) | (0x1 << 11));
1408 and_phy_reg(pi, 0x4fa, ~((0x1 << 3)));
1409 or_phy_reg(pi, 0x4f9, (0x1 << 3));
1414 uint16 wlc_phy_bw_state_get(wlc_phy_t * ppi)
1416 phy_info_t *pi = (phy_info_t *) ppi;
1421 void wlc_phy_bw_state_set(wlc_phy_t * ppi, uint16 bw)
1423 phy_info_t *pi = (phy_info_t *) ppi;
1428 void wlc_phy_chanspec_radio_set(wlc_phy_t * ppi, chanspec_t newch)
1430 phy_info_t *pi = (phy_info_t *) ppi;
1431 pi->radio_chanspec = newch;
1435 chanspec_t wlc_phy_chanspec_get(wlc_phy_t * ppi)
1437 phy_info_t *pi = (phy_info_t *) ppi;
1439 return pi->radio_chanspec;
1442 void wlc_phy_chanspec_set(wlc_phy_t * ppi, chanspec_t chanspec)
1444 phy_info_t *pi = (phy_info_t *) ppi;
1445 uint16 m_cur_channel;
1446 chansetfn_t chanspec_set = NULL;
1448 ASSERT(!wf_chspec_malformed(chanspec));
1450 m_cur_channel = CHSPEC_CHANNEL(chanspec);
1451 if (CHSPEC_IS5G(chanspec))
1452 m_cur_channel |= D11_CURCHANNEL_5G;
1453 if (CHSPEC_IS40(chanspec))
1454 m_cur_channel |= D11_CURCHANNEL_40;
1455 wlapi_bmac_write_shm(pi->sh->physhim, M_CURCHANNEL, m_cur_channel);
1457 chanspec_set = pi->pi_fptr.chanset;
1459 (*chanspec_set) (pi, chanspec);
1463 int wlc_phy_chanspec_freq2bandrange_lpssn(uint freq)
1468 range = WL_CHAN_FREQ_RANGE_2G;
1469 else if (freq <= 5320)
1470 range = WL_CHAN_FREQ_RANGE_5GL;
1471 else if (freq <= 5700)
1472 range = WL_CHAN_FREQ_RANGE_5GM;
1474 range = WL_CHAN_FREQ_RANGE_5GH;
1479 int wlc_phy_chanspec_bandrange_get(phy_info_t * pi, chanspec_t chanspec)
1482 uint channel = CHSPEC_CHANNEL(chanspec);
1483 uint freq = wlc_phy_channel2freq(channel);
1486 range = wlc_phy_get_chan_freq_range_nphy(pi, channel);
1487 } else if (ISLCNPHY(pi)) {
1488 range = wlc_phy_chanspec_freq2bandrange_lpssn(freq);
1495 void wlc_phy_chanspec_ch14_widefilter_set(wlc_phy_t * ppi, bool wide_filter)
1497 phy_info_t *pi = (phy_info_t *) ppi;
1499 pi->channel_14_wide_filter = wide_filter;
1503 int wlc_phy_channel2freq(uint channel)
1507 for (i = 0; i < ARRAYSIZE(chan_info_all); i++)
1508 if (chan_info_all[i].chan == channel)
1509 return (chan_info_all[i].freq);
1514 wlc_phy_chanspec_band_validch(wlc_phy_t * ppi, uint band, chanvec_t * channels)
1516 phy_info_t *pi = (phy_info_t *) ppi;
1520 ASSERT((band == WLC_BAND_2G) || (band == WLC_BAND_5G));
1522 bzero(channels, sizeof(chanvec_t));
1524 for (i = 0; i < ARRAYSIZE(chan_info_all); i++) {
1525 channel = chan_info_all[i].chan;
1527 if ((pi->a_band_high_disable) && (channel >= FIRST_REF5_CHANNUM)
1528 && (channel <= LAST_REF5_CHANNUM))
1531 if (((band == WLC_BAND_2G) && (channel <= CH_MAX_2G_CHANNEL)) ||
1532 ((band == WLC_BAND_5G) && (channel > CH_MAX_2G_CHANNEL)))
1533 setbit(channels->vec, channel);
1537 chanspec_t wlc_phy_chanspec_band_firstch(wlc_phy_t * ppi, uint band)
1539 phy_info_t *pi = (phy_info_t *) ppi;
1544 ASSERT((band == WLC_BAND_2G) || (band == WLC_BAND_5G));
1546 for (i = 0; i < ARRAYSIZE(chan_info_all); i++) {
1547 channel = chan_info_all[i].chan;
1549 if (ISNPHY(pi) && IS40MHZ(pi)) {
1552 for (j = 0; j < ARRAYSIZE(chan_info_all); j++) {
1553 if (chan_info_all[j].chan ==
1554 channel + CH_10MHZ_APART)
1558 if (j == ARRAYSIZE(chan_info_all))
1561 channel = UPPER_20_SB(channel);
1563 channel | WL_CHANSPEC_BW_40 |
1564 WL_CHANSPEC_CTL_SB_LOWER;
1565 if (band == WLC_BAND_2G)
1566 chspec |= WL_CHANSPEC_BAND_2G;
1568 chspec |= WL_CHANSPEC_BAND_5G;
1570 chspec = CH20MHZ_CHSPEC(channel);
1572 if ((pi->a_band_high_disable) && (channel >= FIRST_REF5_CHANNUM)
1573 && (channel <= LAST_REF5_CHANNUM))
1576 if (((band == WLC_BAND_2G) && (channel <= CH_MAX_2G_CHANNEL)) ||
1577 ((band == WLC_BAND_5G) && (channel > CH_MAX_2G_CHANNEL)))
1583 return (chanspec_t) INVCHANSPEC;
1586 int wlc_phy_txpower_get(wlc_phy_t * ppi, uint * qdbm, bool * override)
1588 phy_info_t *pi = (phy_info_t *) ppi;
1590 ASSERT(qdbm != NULL);
1591 *qdbm = pi->tx_user_target[0];
1592 if (override != NULL)
1593 *override = pi->txpwroverride;
1597 void wlc_phy_txpower_target_set(wlc_phy_t * ppi, struct txpwr_limits *txpwr)
1599 bool mac_enabled = FALSE;
1600 phy_info_t *pi = (phy_info_t *) ppi;
1602 bcopy(&txpwr->cck[0], &pi->tx_user_target[TXP_FIRST_CCK],
1605 bcopy(&txpwr->ofdm[0], &pi->tx_user_target[TXP_FIRST_OFDM],
1606 WLC_NUM_RATES_OFDM);
1607 bcopy(&txpwr->ofdm_cdd[0], &pi->tx_user_target[TXP_FIRST_OFDM_20_CDD],
1608 WLC_NUM_RATES_OFDM);
1610 bcopy(&txpwr->ofdm_40_siso[0],
1611 &pi->tx_user_target[TXP_FIRST_OFDM_40_SISO], WLC_NUM_RATES_OFDM);
1612 bcopy(&txpwr->ofdm_40_cdd[0],
1613 &pi->tx_user_target[TXP_FIRST_OFDM_40_CDD], WLC_NUM_RATES_OFDM);
1615 bcopy(&txpwr->mcs_20_siso[0],
1616 &pi->tx_user_target[TXP_FIRST_MCS_20_SISO],
1617 WLC_NUM_RATES_MCS_1_STREAM);
1618 bcopy(&txpwr->mcs_20_cdd[0], &pi->tx_user_target[TXP_FIRST_MCS_20_CDD],
1619 WLC_NUM_RATES_MCS_1_STREAM);
1620 bcopy(&txpwr->mcs_20_stbc[0],
1621 &pi->tx_user_target[TXP_FIRST_MCS_20_STBC],
1622 WLC_NUM_RATES_MCS_1_STREAM);
1623 bcopy(&txpwr->mcs_20_mimo[0], &pi->tx_user_target[TXP_FIRST_MCS_20_SDM],
1624 WLC_NUM_RATES_MCS_2_STREAM);
1626 bcopy(&txpwr->mcs_40_siso[0],
1627 &pi->tx_user_target[TXP_FIRST_MCS_40_SISO],
1628 WLC_NUM_RATES_MCS_1_STREAM);
1629 bcopy(&txpwr->mcs_40_cdd[0], &pi->tx_user_target[TXP_FIRST_MCS_40_CDD],
1630 WLC_NUM_RATES_MCS_1_STREAM);
1631 bcopy(&txpwr->mcs_40_stbc[0],
1632 &pi->tx_user_target[TXP_FIRST_MCS_40_STBC],
1633 WLC_NUM_RATES_MCS_1_STREAM);
1634 bcopy(&txpwr->mcs_40_mimo[0], &pi->tx_user_target[TXP_FIRST_MCS_40_SDM],
1635 WLC_NUM_RATES_MCS_2_STREAM);
1637 if (R_REG(pi->sh->osh, &pi->regs->maccontrol) & MCTL_EN_MAC)
1641 wlapi_suspend_mac_and_wait(pi->sh->physhim);
1643 wlc_phy_txpower_recalc_target(pi);
1644 wlc_phy_cal_txpower_recalc_sw(pi);
1647 wlapi_enable_mac(pi->sh->physhim);
1650 int wlc_phy_txpower_set(wlc_phy_t * ppi, uint qdbm, bool override)
1652 phy_info_t *pi = (phy_info_t *) ppi;
1658 for (i = 0; i < TXP_NUM_RATES; i++)
1659 pi->tx_user_target[i] = (uint8) qdbm;
1661 pi->txpwroverride = FALSE;
1664 if (!SCAN_INPROG_PHY(pi)) {
1669 (R_REG(pi->sh->osh, &pi->regs->maccontrol) &
1673 wlapi_suspend_mac_and_wait(pi->sh->physhim);
1675 wlc_phy_txpower_recalc_target(pi);
1676 wlc_phy_cal_txpower_recalc_sw(pi);
1679 wlapi_enable_mac(pi->sh->physhim);
1686 wlc_phy_txpower_sromlimit(wlc_phy_t * ppi, uint channel, uint8 * min_pwr,
1687 uint8 * max_pwr, int txp_rate_idx)
1689 phy_info_t *pi = (phy_info_t *) ppi;
1692 *min_pwr = pi->min_txpower * WLC_TXPWR_DB_FACTOR;
1695 if (txp_rate_idx < 0)
1696 txp_rate_idx = TXP_FIRST_CCK;
1697 wlc_phy_txpower_sromlimit_get_nphy(pi, channel, max_pwr,
1698 (uint8) txp_rate_idx);
1700 } else if ((channel <= CH_MAX_2G_CHANNEL)) {
1701 if (txp_rate_idx < 0)
1702 txp_rate_idx = TXP_FIRST_CCK;
1703 *max_pwr = pi->tx_srom_max_rate_2g[txp_rate_idx];
1706 *max_pwr = WLC_TXPWR_MAX;
1708 if (txp_rate_idx < 0)
1709 txp_rate_idx = TXP_FIRST_OFDM;
1711 for (i = 0; i < ARRAYSIZE(chan_info_all); i++) {
1712 if (channel == chan_info_all[i].chan) {
1716 ASSERT(i < ARRAYSIZE(chan_info_all));
1719 *max_pwr = pi->hwtxpwr[i];
1722 if ((i >= FIRST_MID_5G_CHAN) && (i <= LAST_MID_5G_CHAN))
1724 pi->tx_srom_max_rate_5g_mid[txp_rate_idx];
1725 if ((i >= FIRST_HIGH_5G_CHAN)
1726 && (i <= LAST_HIGH_5G_CHAN))
1728 pi->tx_srom_max_rate_5g_hi[txp_rate_idx];
1729 if ((i >= FIRST_LOW_5G_CHAN) && (i <= LAST_LOW_5G_CHAN))
1731 pi->tx_srom_max_rate_5g_low[txp_rate_idx];
1737 wlc_phy_txpower_sromlimit_max_get(wlc_phy_t * ppi, uint chan, uint8 * max_txpwr,
1740 phy_info_t *pi = (phy_info_t *) ppi;
1741 uint8 tx_pwr_max = 0;
1742 uint8 tx_pwr_min = 255;
1744 uint8 maxtxpwr, mintxpwr, rate, pactrl;
1748 max_num_rate = ISNPHY(pi) ? TXP_NUM_RATES :
1749 ISLCNPHY(pi) ? (TXP_LAST_SISO_MCS_20 + 1) : (TXP_LAST_OFDM + 1);
1751 for (rate = 0; rate < max_num_rate; rate++) {
1753 wlc_phy_txpower_sromlimit(ppi, chan, &mintxpwr, &maxtxpwr,
1756 maxtxpwr = (maxtxpwr > pactrl) ? (maxtxpwr - pactrl) : 0;
1758 maxtxpwr = (maxtxpwr > 6) ? (maxtxpwr - 6) : 0;
1760 tx_pwr_max = MAX(tx_pwr_max, maxtxpwr);
1761 tx_pwr_min = MIN(tx_pwr_min, maxtxpwr);
1763 *max_txpwr = tx_pwr_max;
1764 *min_txpwr = tx_pwr_min;
1768 wlc_phy_txpower_boardlimit_band(wlc_phy_t * ppi, uint bandunit, int32 * max_pwr,
1769 int32 * min_pwr, uint32 * step_pwr)
1774 uint8 wlc_phy_txpower_get_target_min(wlc_phy_t * ppi)
1776 phy_info_t *pi = (phy_info_t *) ppi;
1778 return pi->tx_power_min;
1781 uint8 wlc_phy_txpower_get_target_max(wlc_phy_t * ppi)
1783 phy_info_t *pi = (phy_info_t *) ppi;
1785 return pi->tx_power_max;
1788 void wlc_phy_txpower_recalc_target(phy_info_t * pi)
1790 uint8 maxtxpwr, mintxpwr, rate, pactrl;
1792 uint8 tx_pwr_target[TXP_NUM_RATES];
1793 uint8 tx_pwr_max = 0;
1794 uint8 tx_pwr_min = 255;
1795 uint8 tx_pwr_max_rate_ind = 0;
1797 uint8 start_rate = 0;
1799 uint32 band = CHSPEC2WLC_BAND(pi->radio_chanspec);
1800 initfn_t txpwr_recalc_fn = NULL;
1802 chspec = pi->radio_chanspec;
1803 if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_NONE)
1804 target_chan = CHSPEC_CHANNEL(chspec);
1805 else if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_UPPER)
1806 target_chan = UPPER_20_SB(CHSPEC_CHANNEL(chspec));
1808 target_chan = LOWER_20_SB(CHSPEC_CHANNEL(chspec));
1812 uint32 offset_mcs, i;
1814 if (CHSPEC_IS40(pi->radio_chanspec)) {
1815 offset_mcs = pi->mcs40_po;
1816 for (i = TXP_FIRST_SISO_MCS_20;
1817 i <= TXP_LAST_SISO_MCS_20; i++) {
1818 pi->tx_srom_max_rate_2g[i - 8] =
1819 pi->tx_srom_max_2g -
1820 ((offset_mcs & 0xf) * 2);
1824 offset_mcs = pi->mcs20_po;
1825 for (i = TXP_FIRST_SISO_MCS_20;
1826 i <= TXP_LAST_SISO_MCS_20; i++) {
1827 pi->tx_srom_max_rate_2g[i - 8] =
1828 pi->tx_srom_max_2g -
1829 ((offset_mcs & 0xf) * 2);
1835 max_num_rate = ((ISNPHY(pi)) ? (TXP_NUM_RATES) :
1837 (TXP_LAST_SISO_MCS_20 + 1) : (TXP_LAST_OFDM + 1)));
1839 max_num_rate = ((ISNPHY(pi)) ? (TXP_NUM_RATES) : (TXP_LAST_OFDM + 1));
1842 wlc_phy_upd_env_txpwr_rate_limits(pi, band);
1844 for (rate = start_rate; rate < max_num_rate; rate++) {
1846 tx_pwr_target[rate] = pi->tx_user_target[rate];
1848 if (pi->user_txpwr_at_rfport) {
1849 tx_pwr_target[rate] +=
1850 wlc_user_txpwr_antport_to_rfport(pi, target_chan,
1856 wlc_phy_txpower_sromlimit((wlc_phy_t *) pi, target_chan,
1857 &mintxpwr, &maxtxpwr, rate);
1859 maxtxpwr = MIN(maxtxpwr, pi->txpwr_limit[rate]);
1862 (maxtxpwr > pactrl) ? (maxtxpwr - pactrl) : 0;
1864 maxtxpwr = (maxtxpwr > 6) ? (maxtxpwr - 6) : 0;
1866 maxtxpwr = MIN(maxtxpwr, tx_pwr_target[rate]);
1868 if (pi->txpwr_percent <= 100)
1869 maxtxpwr = (maxtxpwr * pi->txpwr_percent) / 100;
1871 tx_pwr_target[rate] = MAX(maxtxpwr, mintxpwr);
1874 tx_pwr_target[rate] =
1875 MIN(tx_pwr_target[rate], pi->txpwr_env_limit[rate]);
1877 if (tx_pwr_target[rate] > tx_pwr_max)
1878 tx_pwr_max_rate_ind = rate;
1880 tx_pwr_max = MAX(tx_pwr_max, tx_pwr_target[rate]);
1881 tx_pwr_min = MIN(tx_pwr_min, tx_pwr_target[rate]);
1884 bzero(pi->tx_power_offset, sizeof(pi->tx_power_offset));
1885 pi->tx_power_max = tx_pwr_max;
1886 pi->tx_power_min = tx_pwr_min;
1887 pi->tx_power_max_rate_ind = tx_pwr_max_rate_ind;
1888 for (rate = 0; rate < max_num_rate; rate++) {
1890 pi->tx_power_target[rate] = tx_pwr_target[rate];
1892 if (!pi->hwpwrctrl || ISNPHY(pi)) {
1893 pi->tx_power_offset[rate] =
1894 pi->tx_power_max - pi->tx_power_target[rate];
1896 pi->tx_power_offset[rate] =
1897 pi->tx_power_target[rate] - pi->tx_power_min;
1901 txpwr_recalc_fn = pi->pi_fptr.txpwrrecalc;
1902 if (txpwr_recalc_fn)
1903 (*txpwr_recalc_fn) (pi);
1907 wlc_phy_txpower_reg_limit_calc(phy_info_t * pi, struct txpwr_limits *txpwr,
1908 chanspec_t chanspec)
1910 uint8 tmp_txpwr_limit[2 * WLC_NUM_RATES_OFDM];
1911 uint8 *txpwr_ptr1 = NULL, *txpwr_ptr2 = NULL;
1912 int rate_start_index = 0, rate1, rate2, k;
1914 for (rate1 = WL_TX_POWER_CCK_FIRST, rate2 = 0;
1915 rate2 < WL_TX_POWER_CCK_NUM; rate1++, rate2++)
1916 pi->txpwr_limit[rate1] = txpwr->cck[rate2];
1918 for (rate1 = WL_TX_POWER_OFDM_FIRST, rate2 = 0;
1919 rate2 < WL_TX_POWER_OFDM_NUM; rate1++, rate2++)
1920 pi->txpwr_limit[rate1] = txpwr->ofdm[rate2];
1924 for (k = 0; k < 4; k++) {
1928 txpwr_ptr1 = txpwr->mcs_20_siso;
1929 txpwr_ptr2 = txpwr->ofdm;
1930 rate_start_index = WL_TX_POWER_OFDM_FIRST;
1934 txpwr_ptr1 = txpwr->mcs_20_cdd;
1935 txpwr_ptr2 = txpwr->ofdm_cdd;
1936 rate_start_index = WL_TX_POWER_OFDM20_CDD_FIRST;
1940 txpwr_ptr1 = txpwr->mcs_40_siso;
1941 txpwr_ptr2 = txpwr->ofdm_40_siso;
1943 WL_TX_POWER_OFDM40_SISO_FIRST;
1947 txpwr_ptr1 = txpwr->mcs_40_cdd;
1948 txpwr_ptr2 = txpwr->ofdm_40_cdd;
1949 rate_start_index = WL_TX_POWER_OFDM40_CDD_FIRST;
1953 for (rate2 = 0; rate2 < WLC_NUM_RATES_OFDM; rate2++) {
1954 tmp_txpwr_limit[rate2] = 0;
1955 tmp_txpwr_limit[WLC_NUM_RATES_OFDM + rate2] =
1958 wlc_phy_mcs_to_ofdm_powers_nphy(tmp_txpwr_limit, 0,
1959 WLC_NUM_RATES_OFDM - 1,
1960 WLC_NUM_RATES_OFDM);
1961 for (rate1 = rate_start_index, rate2 = 0;
1962 rate2 < WLC_NUM_RATES_OFDM; rate1++, rate2++)
1963 pi->txpwr_limit[rate1] =
1964 MIN(txpwr_ptr2[rate2],
1965 tmp_txpwr_limit[rate2]);
1968 for (k = 0; k < 4; k++) {
1972 txpwr_ptr1 = txpwr->ofdm;
1973 txpwr_ptr2 = txpwr->mcs_20_siso;
1974 rate_start_index = WL_TX_POWER_MCS20_SISO_FIRST;
1978 txpwr_ptr1 = txpwr->ofdm_cdd;
1979 txpwr_ptr2 = txpwr->mcs_20_cdd;
1980 rate_start_index = WL_TX_POWER_MCS20_CDD_FIRST;
1984 txpwr_ptr1 = txpwr->ofdm_40_siso;
1985 txpwr_ptr2 = txpwr->mcs_40_siso;
1986 rate_start_index = WL_TX_POWER_MCS40_SISO_FIRST;
1990 txpwr_ptr1 = txpwr->ofdm_40_cdd;
1991 txpwr_ptr2 = txpwr->mcs_40_cdd;
1992 rate_start_index = WL_TX_POWER_MCS40_CDD_FIRST;
1995 for (rate2 = 0; rate2 < WLC_NUM_RATES_OFDM; rate2++) {
1996 tmp_txpwr_limit[rate2] = 0;
1997 tmp_txpwr_limit[WLC_NUM_RATES_OFDM + rate2] =
2000 wlc_phy_ofdm_to_mcs_powers_nphy(tmp_txpwr_limit, 0,
2001 WLC_NUM_RATES_OFDM - 1,
2002 WLC_NUM_RATES_OFDM);
2003 for (rate1 = rate_start_index, rate2 = 0;
2004 rate2 < WLC_NUM_RATES_MCS_1_STREAM;
2006 pi->txpwr_limit[rate1] =
2007 MIN(txpwr_ptr2[rate2],
2008 tmp_txpwr_limit[rate2]);
2011 for (k = 0; k < 2; k++) {
2015 rate_start_index = WL_TX_POWER_MCS20_STBC_FIRST;
2016 txpwr_ptr1 = txpwr->mcs_20_stbc;
2020 rate_start_index = WL_TX_POWER_MCS40_STBC_FIRST;
2021 txpwr_ptr1 = txpwr->mcs_40_stbc;
2024 for (rate1 = rate_start_index, rate2 = 0;
2025 rate2 < WLC_NUM_RATES_MCS_1_STREAM;
2027 pi->txpwr_limit[rate1] = txpwr_ptr1[rate2];
2030 for (k = 0; k < 2; k++) {
2034 rate_start_index = WL_TX_POWER_MCS20_SDM_FIRST;
2035 txpwr_ptr1 = txpwr->mcs_20_mimo;
2039 rate_start_index = WL_TX_POWER_MCS40_SDM_FIRST;
2040 txpwr_ptr1 = txpwr->mcs_40_mimo;
2043 for (rate1 = rate_start_index, rate2 = 0;
2044 rate2 < WLC_NUM_RATES_MCS_2_STREAM;
2046 pi->txpwr_limit[rate1] = txpwr_ptr1[rate2];
2049 pi->txpwr_limit[WL_TX_POWER_MCS_32] = txpwr->mcs32;
2051 pi->txpwr_limit[WL_TX_POWER_MCS40_CDD_FIRST] =
2052 MIN(pi->txpwr_limit[WL_TX_POWER_MCS40_CDD_FIRST],
2053 pi->txpwr_limit[WL_TX_POWER_MCS_32]);
2054 pi->txpwr_limit[WL_TX_POWER_MCS_32] =
2055 pi->txpwr_limit[WL_TX_POWER_MCS40_CDD_FIRST];
2059 void wlc_phy_txpwr_percent_set(wlc_phy_t * ppi, uint8 txpwr_percent)
2061 phy_info_t *pi = (phy_info_t *) ppi;
2063 pi->txpwr_percent = txpwr_percent;
2066 void wlc_phy_machwcap_set(wlc_phy_t * ppi, uint32 machwcap)
2068 phy_info_t *pi = (phy_info_t *) ppi;
2070 pi->sh->machwcap = machwcap;
2073 void wlc_phy_runbist_config(wlc_phy_t * ppi, bool start_end)
2075 phy_info_t *pi = (phy_info_t *) ppi;
2079 if (start_end == ON) {
2083 if (NREV_IS(pi->pubpi.phy_rev, 3)
2084 || NREV_IS(pi->pubpi.phy_rev, 4)) {
2085 W_REG(pi->sh->osh, &pi->regs->phyregaddr, 0xa0);
2086 (void)R_REG(pi->sh->osh, &pi->regs->phyregaddr);
2087 rxc = R_REG(pi->sh->osh, &pi->regs->phyregdata);
2088 W_REG(pi->sh->osh, &pi->regs->phyregdata,
2092 if (NREV_IS(pi->pubpi.phy_rev, 3)
2093 || NREV_IS(pi->pubpi.phy_rev, 4)) {
2094 W_REG(pi->sh->osh, &pi->regs->phyregaddr, 0xa0);
2095 (void)R_REG(pi->sh->osh, &pi->regs->phyregaddr);
2096 W_REG(pi->sh->osh, &pi->regs->phyregdata, rxc);
2099 wlc_phy_por_inform(ppi);
2104 wlc_phy_txpower_limit_set(wlc_phy_t * ppi, struct txpwr_limits *txpwr,
2105 chanspec_t chanspec)
2107 phy_info_t *pi = (phy_info_t *) ppi;
2109 wlc_phy_txpower_reg_limit_calc(pi, txpwr, chanspec);
2113 for (i = TXP_FIRST_OFDM_20_CDD, j = 0;
2114 j < WLC_NUM_RATES_MCS_1_STREAM; i++, j++) {
2115 if (txpwr->mcs_20_siso[j])
2116 pi->txpwr_limit[i] = txpwr->mcs_20_siso[j];
2118 pi->txpwr_limit[i] = txpwr->ofdm[j];
2122 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2124 wlc_phy_txpower_recalc_target(pi);
2125 wlc_phy_cal_txpower_recalc_sw(pi);
2126 wlapi_enable_mac(pi->sh->physhim);
2129 void wlc_phy_ofdm_rateset_war(wlc_phy_t * pih, bool war)
2131 phy_info_t *pi = (phy_info_t *) pih;
2133 pi->ofdm_rateset_war = war;
2136 void wlc_phy_bf_preempt_enable(wlc_phy_t * pih, bool bf_preempt)
2138 phy_info_t *pi = (phy_info_t *) pih;
2140 pi->bf_preempt_4306 = bf_preempt;
2143 void wlc_phy_txpower_update_shm(phy_info_t * pi)
2154 if (pi->hwpwrctrl) {
2157 wlapi_bmac_write_shm(pi->sh->physhim, M_TXPWR_MAX, 63);
2158 wlapi_bmac_write_shm(pi->sh->physhim, M_TXPWR_N,
2159 1 << NUM_TSSI_FRAMES);
2161 wlapi_bmac_write_shm(pi->sh->physhim, M_TXPWR_TARGET,
2162 pi->tx_power_min << NUM_TSSI_FRAMES);
2164 wlapi_bmac_write_shm(pi->sh->physhim, M_TXPWR_CUR,
2167 for (j = TXP_FIRST_OFDM; j <= TXP_LAST_OFDM; j++) {
2168 const uint8 ucode_ofdm_rates[] = {
2169 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c
2171 offset = wlapi_bmac_rate_shm_offset(pi->sh->physhim,
2172 ucode_ofdm_rates[j -
2174 wlapi_bmac_write_shm(pi->sh->physhim, offset + 6,
2175 pi->tx_power_offset[j]);
2176 wlapi_bmac_write_shm(pi->sh->physhim, offset + 14,
2177 -(pi->tx_power_offset[j] / 2));
2180 wlapi_bmac_mhf(pi->sh->physhim, MHF2, MHF2_HWPWRCTL,
2181 MHF2_HWPWRCTL, WLC_BAND_ALL);
2185 for (i = TXP_FIRST_OFDM; i <= TXP_LAST_OFDM; i++)
2186 pi->tx_power_offset[i] =
2187 (uint8) ROUNDUP(pi->tx_power_offset[i], 8);
2188 wlapi_bmac_write_shm(pi->sh->physhim, M_OFDM_OFFSET,
2190 tx_power_offset[TXP_FIRST_OFDM]
2195 bool wlc_phy_txpower_hw_ctrl_get(wlc_phy_t * ppi)
2197 phy_info_t *pi = (phy_info_t *) ppi;
2200 return pi->nphy_txpwrctrl;
2202 return pi->hwpwrctrl;
2206 void wlc_phy_txpower_hw_ctrl_set(wlc_phy_t * ppi, bool hwpwrctrl)
2208 phy_info_t *pi = (phy_info_t *) ppi;
2209 bool cur_hwpwrctrl = pi->hwpwrctrl;
2212 if (!pi->hwpwrctrl_capable) {
2216 pi->hwpwrctrl = hwpwrctrl;
2217 pi->nphy_txpwrctrl = hwpwrctrl;
2218 pi->txpwrctrl = hwpwrctrl;
2223 (R_REG(pi->sh->osh, &pi->regs->maccontrol) & MCTL_EN_MAC));
2225 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2227 wlc_phy_txpwrctrl_enable_nphy(pi, pi->nphy_txpwrctrl);
2228 if (pi->nphy_txpwrctrl == PHY_TPC_HW_OFF) {
2229 wlc_phy_txpwr_fixpower_nphy(pi);
2232 mod_phy_reg(pi, 0x1e7, (0x7f << 0),
2233 pi->saved_txpwr_idx);
2237 wlapi_enable_mac(pi->sh->physhim);
2238 } else if (hwpwrctrl != cur_hwpwrctrl) {
2244 void wlc_phy_txpower_ipa_upd(phy_info_t * pi)
2247 if (NREV_GE(pi->pubpi.phy_rev, 3)) {
2248 pi->ipa2g_on = (pi->srom_fem2g.extpagain == 2);
2249 pi->ipa5g_on = (pi->srom_fem5g.extpagain == 2);
2251 pi->ipa2g_on = FALSE;
2252 pi->ipa5g_on = FALSE;
2256 static uint32 wlc_phy_txpower_est_power_nphy(phy_info_t * pi);
2258 static uint32 wlc_phy_txpower_est_power_nphy(phy_info_t * pi)
2260 int16 tx0_status, tx1_status;
2261 uint16 estPower1, estPower2;
2262 uint8 pwr0, pwr1, adj_pwr0, adj_pwr1;
2265 estPower1 = read_phy_reg(pi, 0x118);
2266 estPower2 = read_phy_reg(pi, 0x119);
2268 if ((estPower1 & (0x1 << 8))
2270 pwr0 = (uint8) (estPower1 & (0xff << 0))
2276 if ((estPower2 & (0x1 << 8))
2278 pwr1 = (uint8) (estPower2 & (0xff << 0))
2284 tx0_status = read_phy_reg(pi, 0x1ed);
2285 tx1_status = read_phy_reg(pi, 0x1ee);
2287 if ((tx0_status & (0x1 << 15))
2289 adj_pwr0 = (uint8) (tx0_status & (0xff << 0))
2294 if ((tx1_status & (0x1 << 15))
2296 adj_pwr1 = (uint8) (tx1_status & (0xff << 0))
2303 (uint32) ((pwr0 << 24) | (pwr1 << 16) | (adj_pwr0 << 8) | adj_pwr1);
2308 wlc_phy_txpower_get_current(wlc_phy_t * ppi, tx_power_t * power, uint channel)
2310 phy_info_t *pi = (phy_info_t *) ppi;
2311 uint rate, num_rates;
2312 uint8 min_pwr, max_pwr;
2314 #if WL_TX_POWER_RATES != TXP_NUM_RATES
2315 #error "tx_power_t struct out of sync with this fn"
2319 power->rf_cores = 2;
2320 power->flags |= (WL_TX_POWER_F_MIMO);
2321 if (pi->nphy_txpwrctrl == PHY_TPC_HW_ON)
2323 (WL_TX_POWER_F_ENABLED | WL_TX_POWER_F_HW);
2324 } else if (ISLCNPHY(pi)) {
2325 power->rf_cores = 1;
2326 power->flags |= (WL_TX_POWER_F_SISO);
2327 if (pi->radiopwr_override == RADIOPWR_OVERRIDE_DEF)
2328 power->flags |= WL_TX_POWER_F_ENABLED;
2330 power->flags |= WL_TX_POWER_F_HW;
2333 num_rates = ((ISNPHY(pi)) ? (TXP_NUM_RATES) :
2335 (TXP_LAST_OFDM_20_CDD + 1) : (TXP_LAST_OFDM + 1)));
2337 for (rate = 0; rate < num_rates; rate++) {
2338 power->user_limit[rate] = pi->tx_user_target[rate];
2339 wlc_phy_txpower_sromlimit(ppi, channel, &min_pwr, &max_pwr,
2341 power->board_limit[rate] = (uint8) max_pwr;
2342 power->target[rate] = pi->tx_power_target[rate];
2348 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2349 wlc_phyreg_enter((wlc_phy_t *) pi);
2350 est_pout = wlc_phy_txpower_est_power_nphy(pi);
2351 wlc_phyreg_exit((wlc_phy_t *) pi);
2352 wlapi_enable_mac(pi->sh->physhim);
2354 power->est_Pout[0] = (est_pout >> 8) & 0xff;
2355 power->est_Pout[1] = est_pout & 0xff;
2357 power->est_Pout_act[0] = est_pout >> 24;
2358 power->est_Pout_act[1] = (est_pout >> 16) & 0xff;
2360 if (power->est_Pout[0] == 0x80)
2361 power->est_Pout[0] = 0;
2362 if (power->est_Pout[1] == 0x80)
2363 power->est_Pout[1] = 0;
2365 if (power->est_Pout_act[0] == 0x80)
2366 power->est_Pout_act[0] = 0;
2367 if (power->est_Pout_act[1] == 0x80)
2368 power->est_Pout_act[1] = 0;
2370 power->est_Pout_cck = 0;
2372 power->tx_power_max[0] = pi->tx_power_max;
2373 power->tx_power_max[1] = pi->tx_power_max;
2375 power->tx_power_max_rate_ind[0] = pi->tx_power_max_rate_ind;
2376 power->tx_power_max_rate_ind[1] = pi->tx_power_max_rate_ind;
2377 } else if (!pi->hwpwrctrl) {
2378 } else if (pi->sh->up) {
2380 wlc_phyreg_enter(ppi);
2383 power->tx_power_max[0] = pi->tx_power_max;
2384 power->tx_power_max[1] = pi->tx_power_max;
2386 power->tx_power_max_rate_ind[0] =
2387 pi->tx_power_max_rate_ind;
2388 power->tx_power_max_rate_ind[1] =
2389 pi->tx_power_max_rate_ind;
2391 if (wlc_phy_tpc_isenabled_lcnphy(pi))
2393 (WL_TX_POWER_F_HW | WL_TX_POWER_F_ENABLED);
2396 ~(WL_TX_POWER_F_HW | WL_TX_POWER_F_ENABLED);
2398 wlc_lcnphy_get_tssi(pi, (int8 *) & power->est_Pout[0],
2399 (int8 *) & power->est_Pout_cck);
2401 wlc_phyreg_exit(ppi);
2405 void wlc_phy_antsel_type_set(wlc_phy_t * ppi, uint8 antsel_type)
2407 phy_info_t *pi = (phy_info_t *) ppi;
2409 pi->antsel_type = antsel_type;
2412 bool wlc_phy_test_ison(wlc_phy_t * ppi)
2414 phy_info_t *pi = (phy_info_t *) ppi;
2416 return (pi->phytest_on);
2419 bool wlc_phy_ant_rxdiv_get(wlc_phy_t * ppi, uint8 * pval)
2421 phy_info_t *pi = (phy_info_t *) ppi;
2424 wlc_phyreg_enter(ppi);
2429 } else if (ISLCNPHY(pi)) {
2430 uint16 crsctrl = read_phy_reg(pi, 0x410);
2431 uint16 div = crsctrl & (0x1 << 1);
2432 *pval = (div | ((crsctrl & (0x1 << 0)) ^ (div >> 1)));
2435 wlc_phyreg_exit(ppi);
2440 void wlc_phy_ant_rxdiv_set(wlc_phy_t * ppi, uint8 val)
2442 phy_info_t *pi = (phy_info_t *) ppi;
2445 pi->sh->rx_antdiv = val;
2447 if (!(ISNPHY(pi) && D11REV_IS(pi->sh->corerev, 16))) {
2448 if (val > ANT_RX_DIV_FORCE_1)
2449 wlapi_bmac_mhf(pi->sh->physhim, MHF1, MHF1_ANTDIV,
2450 MHF1_ANTDIV, WLC_BAND_ALL);
2452 wlapi_bmac_mhf(pi->sh->physhim, MHF1, MHF1_ANTDIV, 0,
2465 (0 == (R_REG(pi->sh->osh, &pi->regs->maccontrol) & MCTL_EN_MAC));
2467 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2470 if (val > ANT_RX_DIV_FORCE_1) {
2471 mod_phy_reg(pi, 0x410, (0x1 << 1), 0x01 << 1);
2472 mod_phy_reg(pi, 0x410,
2474 ((ANT_RX_DIV_START_1 == val) ? 1 : 0) << 0);
2476 mod_phy_reg(pi, 0x410, (0x1 << 1), 0x00 << 1);
2477 mod_phy_reg(pi, 0x410, (0x1 << 0), (uint16) val << 0);
2484 wlapi_enable_mac(pi->sh->physhim);
2490 wlc_phy_noise_calc_phy(phy_info_t * pi, uint32 * cmplx_pwr, int8 * pwr_ant)
2492 int8 cmplx_pwr_dbm[PHY_CORE_MAX];
2495 bzero((uint8 *) cmplx_pwr_dbm, sizeof(cmplx_pwr_dbm));
2496 ASSERT(pi->pubpi.phy_corenum <= PHY_CORE_MAX);
2497 wlc_phy_compute_dB(cmplx_pwr, cmplx_pwr_dbm, pi->pubpi.phy_corenum);
2499 for (i = 0; i < pi->pubpi.phy_corenum; i++) {
2500 if (NREV_GE(pi->pubpi.phy_rev, 3))
2501 cmplx_pwr_dbm[i] += (int8) PHY_NOISE_OFFSETFACT_4322;
2504 cmplx_pwr_dbm[i] += (int8) (16 - (15) * 3 - 70);
2507 for (i = 0; i < pi->pubpi.phy_corenum; i++) {
2508 pi->nphy_noise_win[i][pi->nphy_noise_index] = cmplx_pwr_dbm[i];
2509 pwr_ant[i] = cmplx_pwr_dbm[i];
2511 pi->nphy_noise_index =
2512 MODINC_POW2(pi->nphy_noise_index, PHY_NOISE_WINDOW_SZ);
2517 wlc_phy_noise_sample_request(wlc_phy_t * pih, uint8 reason, uint8 ch)
2519 phy_info_t *pi = (phy_info_t *) pih;
2520 int8 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;
2521 bool sampling_in_progress = (pi->phynoise_state != 0);
2522 bool wait_for_intr = TRUE;
2524 if (NORADIO_ENAB(pi->pubpi)) {
2529 case PHY_NOISE_SAMPLE_MON:
2531 pi->phynoise_chan_watchdog = ch;
2532 pi->phynoise_state |= PHY_NOISE_STATE_MON;
2536 case PHY_NOISE_SAMPLE_EXTERNAL:
2538 pi->phynoise_state |= PHY_NOISE_STATE_EXTERNAL;
2546 if (sampling_in_progress)
2549 pi->phynoise_now = pi->sh->now;
2551 if (pi->phy_fixed_noise) {
2553 pi->nphy_noise_win[WL_ANT_IDX_1][pi->nphy_noise_index] =
2554 PHY_NOISE_FIXED_VAL_NPHY;
2555 pi->nphy_noise_win[WL_ANT_IDX_2][pi->nphy_noise_index] =
2556 PHY_NOISE_FIXED_VAL_NPHY;
2557 pi->nphy_noise_index = MODINC_POW2(pi->nphy_noise_index,
2558 PHY_NOISE_WINDOW_SZ);
2560 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;
2563 noise_dbm = PHY_NOISE_FIXED_VAL;
2566 wait_for_intr = FALSE;
2571 if (!pi->phynoise_polling
2572 || (reason == PHY_NOISE_SAMPLE_EXTERNAL)) {
2573 wlapi_bmac_write_shm(pi->sh->physhim, M_JSSI_0, 0);
2574 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP0, 0);
2575 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP1, 0);
2576 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP2, 0);
2577 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP3, 0);
2579 OR_REG(pi->sh->osh, &pi->regs->maccommand,
2582 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2583 wlc_lcnphy_deaf_mode(pi, (bool) 0);
2584 noise_dbm = (int8) wlc_lcnphy_rx_signal_power(pi, 20);
2585 wlc_lcnphy_deaf_mode(pi, (bool) 1);
2586 wlapi_enable_mac(pi->sh->physhim);
2587 wait_for_intr = FALSE;
2589 } else if (ISNPHY(pi)) {
2590 if (!pi->phynoise_polling
2591 || (reason == PHY_NOISE_SAMPLE_EXTERNAL)) {
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 phy_iq_est_t est[PHY_CORE_MAX];
2602 uint32 cmplx_pwr[PHY_CORE_MAX];
2603 int8 noise_dbm_ant[PHY_CORE_MAX];
2604 uint16 log_num_samps, num_samps, classif_state = 0;
2605 uint8 wait_time = 32;
2609 bzero((uint8 *) est, sizeof(est));
2610 bzero((uint8 *) cmplx_pwr, sizeof(cmplx_pwr));
2611 bzero((uint8 *) noise_dbm_ant, sizeof(noise_dbm_ant));
2613 log_num_samps = PHY_NOISE_SAMPLE_LOG_NUM_NPHY;
2614 num_samps = 1 << log_num_samps;
2616 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2617 classif_state = wlc_phy_classifier_nphy(pi, 0, 0);
2618 wlc_phy_classifier_nphy(pi, 3, 0);
2619 wlc_phy_rx_iq_est_nphy(pi, est, num_samps, wait_time,
2621 wlc_phy_classifier_nphy(pi, (0x7 << 0), classif_state);
2622 wlapi_enable_mac(pi->sh->physhim);
2624 for (i = 0; i < pi->pubpi.phy_corenum; i++)
2627 est[i].q_pwr) >> log_num_samps;
2629 wlc_phy_noise_calc_phy(pi, cmplx_pwr, noise_dbm_ant);
2631 for (i = 0; i < pi->pubpi.phy_corenum; i++) {
2632 pi->nphy_noise_win[i][pi->nphy_noise_index] =
2635 if (noise_dbm_ant[i] > noise_dbm)
2636 noise_dbm = noise_dbm_ant[i];
2638 pi->nphy_noise_index = MODINC_POW2(pi->nphy_noise_index,
2639 PHY_NOISE_WINDOW_SZ);
2641 wait_for_intr = FALSE;
2648 wlc_phy_noise_cb(pi, ch, noise_dbm);
2652 void wlc_phy_noise_sample_request_external(wlc_phy_t * pih)
2656 channel = CHSPEC_CHANNEL(wlc_phy_chanspec_get(pih));
2658 wlc_phy_noise_sample_request(pih, PHY_NOISE_SAMPLE_EXTERNAL, channel);
2661 static void wlc_phy_noise_cb(phy_info_t * pi, uint8 channel, int8 noise_dbm)
2663 if (!pi->phynoise_state)
2666 if (pi->phynoise_state & PHY_NOISE_STATE_MON) {
2667 if (pi->phynoise_chan_watchdog == channel) {
2668 pi->sh->phy_noise_window[pi->sh->phy_noise_index] =
2670 pi->sh->phy_noise_index =
2671 MODINC(pi->sh->phy_noise_index, MA_WINDOW_SZ);
2673 pi->phynoise_state &= ~PHY_NOISE_STATE_MON;
2676 if (pi->phynoise_state & PHY_NOISE_STATE_EXTERNAL) {
2677 pi->phynoise_state &= ~PHY_NOISE_STATE_EXTERNAL;
2682 static int8 wlc_phy_noise_read_shmem(phy_info_t * pi)
2684 uint32 cmplx_pwr[PHY_CORE_MAX];
2685 int8 noise_dbm_ant[PHY_CORE_MAX];
2687 uint32 cmplx_pwr_tot = 0;
2688 int8 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;
2691 ASSERT(pi->pubpi.phy_corenum <= PHY_CORE_MAX);
2692 bzero((uint8 *) cmplx_pwr, sizeof(cmplx_pwr));
2693 bzero((uint8 *) noise_dbm_ant, sizeof(noise_dbm_ant));
2695 for (idx = 0, core = 0; core < pi->pubpi.phy_corenum; idx += 2, core++) {
2696 lo = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP(idx));
2697 hi = wlapi_bmac_read_shm(pi->sh->physhim,
2698 M_PWRIND_MAP(idx + 1));
2699 cmplx_pwr[core] = (hi << 16) + lo;
2700 cmplx_pwr_tot += cmplx_pwr[core];
2701 if (cmplx_pwr[core] == 0) {
2702 noise_dbm_ant[core] = PHY_NOISE_FIXED_VAL_NPHY;
2704 cmplx_pwr[core] >>= PHY_NOISE_SAMPLE_LOG_NUM_UCODE;
2707 if (cmplx_pwr_tot != 0)
2708 wlc_phy_noise_calc_phy(pi, cmplx_pwr, noise_dbm_ant);
2710 for (core = 0; core < pi->pubpi.phy_corenum; core++) {
2711 pi->nphy_noise_win[core][pi->nphy_noise_index] =
2712 noise_dbm_ant[core];
2714 if (noise_dbm_ant[core] > noise_dbm)
2715 noise_dbm = noise_dbm_ant[core];
2717 pi->nphy_noise_index =
2718 MODINC_POW2(pi->nphy_noise_index, PHY_NOISE_WINDOW_SZ);
2724 void wlc_phy_noise_sample_intr(wlc_phy_t * pih)
2726 phy_info_t *pi = (phy_info_t *) pih;
2729 int8 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;
2732 uint32 cmplx_pwr, cmplx_pwr0, cmplx_pwr1;
2734 int32 pwr_offset_dB, gain_dB;
2735 uint16 status_0, status_1;
2737 jssi_aux = wlapi_bmac_read_shm(pi->sh->physhim, M_JSSI_AUX);
2738 channel = jssi_aux & D11_CURCHANNEL_MAX;
2740 lo = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP0);
2741 hi = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP1);
2742 cmplx_pwr0 = (hi << 16) + lo;
2744 lo = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP2);
2745 hi = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP3);
2746 cmplx_pwr1 = (hi << 16) + lo;
2747 cmplx_pwr = (cmplx_pwr0 + cmplx_pwr1) >> 6;
2750 status_1 = wlapi_bmac_read_shm(pi->sh->physhim, M_JSSI_0);
2751 if ((cmplx_pwr > 0 && cmplx_pwr < 500)
2752 && ((status_1 & 0xc000) == 0x4000)) {
2754 wlc_phy_compute_dB(&cmplx_pwr, &noise_dbm,
2755 pi->pubpi.phy_corenum);
2756 pwr_offset_dB = (read_phy_reg(pi, 0x434) & 0xFF);
2757 if (pwr_offset_dB > 127)
2758 pwr_offset_dB -= 256;
2760 noise_dbm += (int8) (pwr_offset_dB - 30);
2762 gain_dB = (status_0 & 0x1ff);
2763 noise_dbm -= (int8) (gain_dB);
2765 noise_dbm = PHY_NOISE_FIXED_VAL_LCNPHY;
2767 } else if (ISNPHY(pi)) {
2769 jssi_aux = wlapi_bmac_read_shm(pi->sh->physhim, M_JSSI_AUX);
2770 channel = jssi_aux & D11_CURCHANNEL_MAX;
2772 noise_dbm = wlc_phy_noise_read_shmem(pi);
2777 wlc_phy_noise_cb(pi, channel, noise_dbm);
2781 int8 lcnphy_gain_index_offset_for_pkt_rssi[] = {
2822 void wlc_phy_compute_dB(uint32 * cmplx_pwr, int8 * p_cmplx_pwr_dB, uint8 core)
2824 uint8 shift_ct, lsb, msb, secondmsb, i;
2827 for (i = 0; i < core; i++) {
2829 shift_ct = msb = secondmsb = 0;
2833 lsb = (uint8) (tmp & 1);
2837 secondmsb = (uint8) ((cmplx_pwr[i] >> (msb - 1)) & 1);
2838 p_cmplx_pwr_dB[i] = (int8) (3 * msb + 2 * secondmsb);
2842 void BCMFASTPATH wlc_phy_rssi_compute(wlc_phy_t * pih, void *ctx)
2844 wlc_d11rxhdr_t *wlc_rxhdr = (wlc_d11rxhdr_t *) ctx;
2845 d11rxhdr_t *rxh = &wlc_rxhdr->rxhdr;
2846 int rssi = ltoh16(rxh->PhyRxStatus_1) & PRXS1_JSSI_MASK;
2847 uint radioid = pih->radioid;
2848 phy_info_t *pi = (phy_info_t *) pih;
2850 if (NORADIO_ENAB(pi->pubpi)) {
2851 rssi = WLC_RSSI_INVALID;
2855 if ((pi->sh->corerev >= 11)
2856 && !(ltoh16(rxh->RxStatus2) & RXS_PHYRXST_VALID)) {
2857 rssi = WLC_RSSI_INVALID;
2862 uint8 gidx = (ltoh16(rxh->PhyRxStatus_2) & 0xFC00) >> 10;
2863 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
2868 rssi = rssi + lcnphy_gain_index_offset_for_pkt_rssi[gidx];
2869 if ((rssi > -46) && (gidx > 18))
2872 rssi = rssi + pi_lcn->lcnphy_pkteng_rssi_slope;
2882 } else if (radioid == BCM2055_ID || radioid == BCM2056_ID
2883 || radioid == BCM2057_ID) {
2885 rssi = wlc_phy_rssi_compute_nphy(pi, wlc_rxhdr);
2887 ASSERT((const char *)"Unknown radio" == NULL);
2891 wlc_rxhdr->rssi = (int8) rssi;
2894 void wlc_phy_freqtrack_start(wlc_phy_t * pih)
2899 void wlc_phy_freqtrack_end(wlc_phy_t * pih)
2904 void wlc_phy_set_deaf(wlc_phy_t * ppi, bool user_flag)
2907 pi = (phy_info_t *) ppi;
2910 wlc_lcnphy_deaf_mode(pi, TRUE);
2911 else if (ISNPHY(pi))
2912 wlc_nphy_deaf_mode(pi, TRUE);
2918 void wlc_phy_watchdog(wlc_phy_t * pih)
2920 phy_info_t *pi = (phy_info_t *) pih;
2921 bool delay_phy_cal = FALSE;
2924 if (!pi->watchdog_override)
2927 if (!(SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi))) {
2928 wlc_phy_noise_sample_request((wlc_phy_t *) pi,
2929 PHY_NOISE_SAMPLE_MON,
2934 if (pi->phynoise_state && (pi->sh->now - pi->phynoise_now) > 5) {
2935 pi->phynoise_state = 0;
2938 if ((!pi->phycal_txpower) ||
2939 ((pi->sh->now - pi->phycal_txpower) >= pi->sh->fast_timer)) {
2941 if (!SCAN_INPROG_PHY(pi) && wlc_phy_cal_txpower_recalc_sw(pi)) {
2942 pi->phycal_txpower = pi->sh->now;
2946 if (NORADIO_ENAB(pi->pubpi))
2949 if ((SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi)
2950 || ASSOC_INPROG_PHY(pi)))
2953 if (ISNPHY(pi) && !pi->disable_percal && !delay_phy_cal) {
2955 if ((pi->nphy_perical != PHY_PERICAL_DISABLE) &&
2956 (pi->nphy_perical != PHY_PERICAL_MANUAL) &&
2957 ((pi->sh->now - pi->nphy_perical_last) >=
2958 pi->sh->glacial_timer))
2959 wlc_phy_cal_perical((wlc_phy_t *) pi,
2960 PHY_PERICAL_WATCHDOG);
2962 wlc_phy_txpwr_papd_cal_nphy(pi);
2966 if (pi->phy_forcecal ||
2967 ((pi->sh->now - pi->phy_lastcal) >=
2968 pi->sh->glacial_timer)) {
2969 if (!(SCAN_RM_IN_PROGRESS(pi) || ASSOC_INPROG_PHY(pi)))
2970 wlc_lcnphy_calib_modes(pi,
2971 LCNPHY_PERICAL_TEMPBASED_TXPWRCTRL);
2973 (SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi)
2974 || ASSOC_INPROG_PHY(pi)
2975 || pi->carrier_suppr_disable
2976 || pi->pkteng_in_progress || pi->disable_percal))
2977 wlc_lcnphy_calib_modes(pi,
2978 PHY_PERICAL_WATCHDOG);
2983 void wlc_phy_BSSinit(wlc_phy_t * pih, bool bonlyap, int rssi)
2985 phy_info_t *pi = (phy_info_t *) pih;
2989 for (i = 0; i < MA_WINDOW_SZ; i++) {
2990 pi->sh->phy_noise_window[i] = (int8) (rssi & 0xff);
2993 for (i = 0; i < MA_WINDOW_SZ; i++)
2994 pi->sh->phy_noise_window[i] =
2995 PHY_NOISE_FIXED_VAL_LCNPHY;
2997 pi->sh->phy_noise_index = 0;
2999 for (i = 0; i < PHY_NOISE_WINDOW_SZ; i++) {
3000 for (k = WL_ANT_IDX_1; k < WL_ANT_RX_MAX; k++)
3001 pi->nphy_noise_win[k][i] = PHY_NOISE_FIXED_VAL_NPHY;
3003 pi->nphy_noise_index = 0;
3007 wlc_phy_papd_decode_epsilon(uint32 epsilon, int32 * eps_real, int32 * eps_imag)
3009 if ((*eps_imag = (epsilon >> 13)) > 0xfff)
3010 *eps_imag -= 0x2000;
3011 if ((*eps_real = (epsilon & 0x1fff)) > 0xfff)
3012 *eps_real -= 0x2000;
3015 static const fixed AtanTbl[] = {
3036 void wlc_phy_cordic(fixed theta, cint32 * val)
3038 fixed angle, valtmp;
3043 val[0].i = CORDIC_AG;
3047 signtheta = (theta < 0) ? -1 : 1;
3049 ((theta + FIXED(180) * signtheta) % FIXED(360)) -
3050 FIXED(180) * signtheta;
3052 if (FLOAT(theta) > 90) {
3053 theta -= FIXED(180);
3055 } else if (FLOAT(theta) < -90) {
3056 theta += FIXED(180);
3060 for (iter = 0; iter < CORDIC_NI; iter++) {
3061 if (theta > angle) {
3062 valtmp = val[0].i - (val[0].q >> iter);
3063 val[0].q = (val[0].i >> iter) + val[0].q;
3065 angle += AtanTbl[iter];
3067 valtmp = val[0].i + (val[0].q >> iter);
3068 val[0].q = -(val[0].i >> iter) + val[0].q;
3070 angle -= AtanTbl[iter];
3074 val[0].i = val[0].i * signx;
3075 val[0].q = val[0].q * signx;
3078 void wlc_phy_cal_perical_mphase_reset(phy_info_t * pi)
3080 wlapi_del_timer(pi->sh->physhim, pi->phycal_timer);
3082 pi->cal_type_override = PHY_PERICAL_AUTO;
3083 pi->mphase_cal_phase_id = MPHASE_CAL_STATE_IDLE;
3084 pi->mphase_txcal_cmdidx = 0;
3087 static void wlc_phy_cal_perical_mphase_schedule(phy_info_t * pi, uint delay)
3090 if ((pi->nphy_perical != PHY_PERICAL_MPHASE) &&
3091 (pi->nphy_perical != PHY_PERICAL_MANUAL))
3094 wlapi_del_timer(pi->sh->physhim, pi->phycal_timer);
3096 pi->mphase_cal_phase_id = MPHASE_CAL_STATE_INIT;
3097 wlapi_add_timer(pi->sh->physhim, pi->phycal_timer, delay, 0);
3100 void wlc_phy_cal_perical(wlc_phy_t * pih, uint8 reason)
3102 int16 nphy_currtemp = 0;
3103 int16 delta_temp = 0;
3104 bool do_periodic_cal = TRUE;
3105 phy_info_t *pi = (phy_info_t *) pih;
3110 if ((pi->nphy_perical == PHY_PERICAL_DISABLE) ||
3111 (pi->nphy_perical == PHY_PERICAL_MANUAL))
3115 case PHY_PERICAL_DRIVERUP:
3118 case PHY_PERICAL_PHYINIT:
3119 if (pi->nphy_perical == PHY_PERICAL_MPHASE) {
3120 if (PHY_PERICAL_MPHASE_PENDING(pi)) {
3121 wlc_phy_cal_perical_mphase_reset(pi);
3123 wlc_phy_cal_perical_mphase_schedule(pi,
3124 PHY_PERICAL_INIT_DELAY);
3128 case PHY_PERICAL_JOIN_BSS:
3129 case PHY_PERICAL_START_IBSS:
3130 case PHY_PERICAL_UP_BSS:
3131 if ((pi->nphy_perical == PHY_PERICAL_MPHASE) &&
3132 PHY_PERICAL_MPHASE_PENDING(pi)) {
3133 wlc_phy_cal_perical_mphase_reset(pi);
3136 pi->first_cal_after_assoc = TRUE;
3138 pi->cal_type_override = PHY_PERICAL_FULL;
3140 if (pi->phycal_tempdelta) {
3141 pi->nphy_lastcal_temp = wlc_phy_tempsense_nphy(pi);
3143 wlc_phy_cal_perical_nphy_run(pi, PHY_PERICAL_FULL);
3146 case PHY_PERICAL_WATCHDOG:
3147 if (pi->phycal_tempdelta) {
3148 nphy_currtemp = wlc_phy_tempsense_nphy(pi);
3150 (nphy_currtemp > pi->nphy_lastcal_temp) ?
3151 nphy_currtemp - pi->nphy_lastcal_temp :
3152 pi->nphy_lastcal_temp - nphy_currtemp;
3154 if ((delta_temp < (int16) pi->phycal_tempdelta) &&
3155 (pi->nphy_txiqlocal_chanspec ==
3156 pi->radio_chanspec)) {
3157 do_periodic_cal = FALSE;
3159 pi->nphy_lastcal_temp = nphy_currtemp;
3163 if (do_periodic_cal) {
3165 if (pi->nphy_perical == PHY_PERICAL_MPHASE) {
3167 if (!PHY_PERICAL_MPHASE_PENDING(pi))
3168 wlc_phy_cal_perical_mphase_schedule(pi,
3169 PHY_PERICAL_WDOG_DELAY);
3170 } else if (pi->nphy_perical == PHY_PERICAL_SPHASE)
3171 wlc_phy_cal_perical_nphy_run(pi,
3184 void wlc_phy_cal_perical_mphase_restart(phy_info_t * pi)
3186 pi->mphase_cal_phase_id = MPHASE_CAL_STATE_INIT;
3187 pi->mphase_txcal_cmdidx = 0;
3190 uint8 wlc_phy_nbits(int32 value)
3195 abs_val = ABS(value);
3196 while ((abs_val >> nbits) > 0)
3202 uint32 wlc_phy_sqrt_int(uint32 value)
3204 uint32 root = 0, shift = 0;
3206 for (shift = 0; shift < 32; shift += 2) {
3207 if (((0x40000000 >> shift) + root) <= value) {
3208 value -= ((0x40000000 >> shift) + root);
3209 root = (root >> 1) | (0x40000000 >> shift);
3221 void wlc_phy_stf_chain_init(wlc_phy_t * pih, uint8 txchain, uint8 rxchain)
3223 phy_info_t *pi = (phy_info_t *) pih;
3225 pi->sh->hw_phytxchain = txchain;
3226 pi->sh->hw_phyrxchain = rxchain;
3227 pi->sh->phytxchain = txchain;
3228 pi->sh->phyrxchain = rxchain;
3229 pi->pubpi.phy_corenum = (uint8) PHY_BITSCNT(pi->sh->phyrxchain);
3232 void wlc_phy_stf_chain_set(wlc_phy_t * pih, uint8 txchain, uint8 rxchain)
3234 phy_info_t *pi = (phy_info_t *) pih;
3236 pi->sh->phytxchain = txchain;
3239 wlc_phy_rxcore_setstate_nphy(pih, rxchain);
3241 pi->pubpi.phy_corenum = (uint8) PHY_BITSCNT(pi->sh->phyrxchain);
3244 void wlc_phy_stf_chain_get(wlc_phy_t * pih, uint8 * txchain, uint8 * rxchain)
3246 phy_info_t *pi = (phy_info_t *) pih;
3248 *txchain = pi->sh->phytxchain;
3249 *rxchain = pi->sh->phyrxchain;
3252 uint8 wlc_phy_stf_chain_active_get(wlc_phy_t * pih)
3254 int16 nphy_currtemp;
3255 uint8 active_bitmap;
3256 phy_info_t *pi = (phy_info_t *) pih;
3258 active_bitmap = (pi->phy_txcore_heatedup) ? 0x31 : 0x33;
3260 if (!pi->watchdog_override)
3261 return active_bitmap;
3263 if (NREV_GE(pi->pubpi.phy_rev, 6)) {
3264 wlapi_suspend_mac_and_wait(pi->sh->physhim);
3265 nphy_currtemp = wlc_phy_tempsense_nphy(pi);
3266 wlapi_enable_mac(pi->sh->physhim);
3268 if (!pi->phy_txcore_heatedup) {
3269 if (nphy_currtemp >= pi->phy_txcore_disable_temp) {
3270 active_bitmap &= 0xFD;
3271 pi->phy_txcore_heatedup = TRUE;
3274 if (nphy_currtemp <= pi->phy_txcore_enable_temp) {
3275 active_bitmap |= 0x2;
3276 pi->phy_txcore_heatedup = FALSE;
3281 return active_bitmap;
3284 int8 wlc_phy_stf_ssmode_get(wlc_phy_t * pih, chanspec_t chanspec)
3286 phy_info_t *pi = (phy_info_t *) pih;
3287 uint8 siso_mcs_id, cdd_mcs_id;
3290 (CHSPEC_IS40(chanspec)) ? TXP_FIRST_MCS_40_SISO :
3291 TXP_FIRST_MCS_20_SISO;
3293 (CHSPEC_IS40(chanspec)) ? TXP_FIRST_MCS_40_CDD :
3294 TXP_FIRST_MCS_20_CDD;
3296 if (pi->tx_power_target[siso_mcs_id] >
3297 (pi->tx_power_target[cdd_mcs_id] + 12))
3298 return PHY_TXC1_MODE_SISO;
3300 return PHY_TXC1_MODE_CDD;
3303 const uint8 *wlc_phy_get_ofdm_rate_lookup(void)
3305 return ofdm_rate_lookup;
3308 void wlc_lcnphy_epa_switch(phy_info_t * pi, bool mode)
3310 if ((CHIPID(pi->sh->chip) == BCM4313_CHIP_ID) &&
3311 (pi->sh->boardflags & BFL_FEM)) {
3314 txant = wlapi_bmac_get_txant(pi->sh->physhim);
3316 mod_phy_reg(pi, 0x44d, (0x1 << 2), (1) << 2);
3318 mod_phy_reg(pi, 0x44c, (0x1 << 2), (1) << 2);
3321 si_corereg(pi->sh->sih, SI_CC_IDX,
3322 OFFSETOF(chipcregs_t, gpiocontrol), ~0x0,
3324 si_corereg(pi->sh->sih, SI_CC_IDX,
3325 OFFSETOF(chipcregs_t, gpioout), 0x40, 0x40);
3326 si_corereg(pi->sh->sih, SI_CC_IDX,
3327 OFFSETOF(chipcregs_t, gpioouten), 0x40,
3330 mod_phy_reg(pi, 0x44c, (0x1 << 2), (0) << 2);
3332 mod_phy_reg(pi, 0x44d, (0x1 << 2), (0) << 2);
3334 si_corereg(pi->sh->sih, SI_CC_IDX,
3335 OFFSETOF(chipcregs_t, gpioout), 0x40, 0x00);
3336 si_corereg(pi->sh->sih, SI_CC_IDX,
3337 OFFSETOF(chipcregs_t, gpioouten), 0x40, 0x0);
3338 si_corereg(pi->sh->sih, SI_CC_IDX,
3339 OFFSETOF(chipcregs_t, gpiocontrol), ~0x0,
3346 wlc_user_txpwr_antport_to_rfport(phy_info_t * pi, uint chan, uint32 band,
3351 if (!pi->user_txpwr_at_rfport)
3356 static int8 wlc_phy_env_measure_vbat(phy_info_t * pi)
3359 return wlc_lcnphy_vbatsense(pi, 0);
3364 static int8 wlc_phy_env_measure_temperature(phy_info_t * pi)
3367 return wlc_lcnphy_tempsense_degree(pi, 0);
3372 static void wlc_phy_upd_env_txpwr_rate_limits(phy_info_t * pi, uint32 band)
3377 for (i = 0; i < TXP_NUM_RATES; i++)
3378 pi->txpwr_env_limit[i] = WLC_TXPWR_MAX;
3380 vbat = wlc_phy_env_measure_vbat(pi);
3381 temp = wlc_phy_env_measure_temperature(pi);
3385 void wlc_phy_ldpc_override_set(wlc_phy_t * ppi, bool ldpc)
3391 wlc_phy_get_pwrdet_offsets(phy_info_t * pi, int8 * cckoffset, int8 * ofdmoffset)
3397 uint32 wlc_phy_qdiv_roundup(uint32 dividend, uint32 divisor, uint8 precision)
3399 uint32 quotient, remainder, roundup, rbit;
3403 quotient = dividend / divisor;
3404 remainder = dividend % divisor;
3406 roundup = (divisor >> 1) + rbit;
3408 while (precision--) {
3410 if (remainder >= roundup) {
3412 remainder = ((remainder - roundup) << 1) + rbit;
3418 if (remainder >= roundup)
3424 int8 wlc_phy_upd_rssi_offset(phy_info_t * pi, int8 rssi, chanspec_t chanspec)
3430 bool wlc_phy_txpower_ipa_ison(wlc_phy_t * ppi)
3432 phy_info_t *pi = (phy_info_t *) ppi;
3435 return (wlc_phy_n_txpower_ipa_ison(pi));