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.
21 #include <linux/kernel.h>
22 #include <linux/string.h>
24 #include <bcmendian.h>
28 #include <wlc_phy_int.h>
29 #include <wlc_phyreg_n.h>
30 #include <wlc_phy_radio.h>
31 #include <wlc_phy_lcn.h>
33 u32 phyhal_msg_level = PHYHAL_ERROR;
35 typedef struct _chan_info_basic {
40 static chan_info_basic_t chan_info_all[] = {
100 u16 ltrn_list[PHY_LTRN_LIST_LEN] = {
101 0x18f9, 0x0d01, 0x00e4, 0xdef4, 0x06f1, 0x0ffc,
102 0xfa27, 0x1dff, 0x10f0, 0x0918, 0xf20a, 0xe010,
103 0x1417, 0x1104, 0xf114, 0xf2fa, 0xf7db, 0xe2fc,
104 0xe1fb, 0x13ee, 0xff0d, 0xe91c, 0x171a, 0x0318,
105 0xda00, 0x03e8, 0x17e6, 0xe9e4, 0xfff3, 0x1312,
106 0xe105, 0xe204, 0xf725, 0xf206, 0xf1ec, 0x11fc,
107 0x14e9, 0xe0f0, 0xf2f6, 0x09e8, 0x1010, 0x1d01,
108 0xfad9, 0x0f04, 0x060f, 0xde0c, 0x001c, 0x0dff,
109 0x1807, 0xf61a, 0xe40e, 0x0f16, 0x05f9, 0x18ec,
110 0x0a1b, 0xff1e, 0x2600, 0xffe2, 0x0ae5, 0x1814,
111 0x0507, 0x0fea, 0xe4f2, 0xf6e6
114 const u8 ofdm_rate_lookup[] = {
126 #define PHY_WREG_LIMIT 24
128 static void wlc_set_phy_uninitted(phy_info_t *pi);
129 static u32 wlc_phy_get_radio_ver(phy_info_t *pi);
130 static void wlc_phy_timercb_phycal(void *arg);
132 static bool wlc_phy_noise_calc_phy(phy_info_t *pi, u32 *cmplx_pwr,
135 static void wlc_phy_cal_perical_mphase_schedule(phy_info_t *pi, uint delay);
136 static void wlc_phy_noise_cb(phy_info_t *pi, u8 channel, s8 noise_dbm);
137 static void wlc_phy_noise_sample_request(wlc_phy_t *pih, u8 reason,
140 static void wlc_phy_txpower_reg_limit_calc(phy_info_t *pi,
141 struct txpwr_limits *tp, chanspec_t);
142 static bool wlc_phy_cal_txpower_recalc_sw(phy_info_t *pi);
144 static s8 wlc_user_txpwr_antport_to_rfport(phy_info_t *pi, uint chan,
146 static void wlc_phy_upd_env_txpwr_rate_limits(phy_info_t *pi, u32 band);
147 static s8 wlc_phy_env_measure_vbat(phy_info_t *pi);
148 static s8 wlc_phy_env_measure_temperature(phy_info_t *pi);
150 char *phy_getvar(phy_info_t *pi, const char *name)
152 char *vars = pi->vars;
156 ASSERT(pi->vars != (char *)&pi->vars);
165 for (s = vars; s && *s;) {
166 if ((bcmp(s, name, len) == 0) && (s[len] == '='))
173 return nvram_get(name);
176 int phy_getintvar(phy_info_t *pi, const char *name)
180 val = PHY_GETVAR(pi, name);
184 return simple_strtoul(val, NULL, 0);
187 void wlc_phyreg_enter(wlc_phy_t *pih)
189 phy_info_t *pi = (phy_info_t *) pih;
190 wlapi_bmac_ucode_wake_override_phyreg_set(pi->sh->physhim);
193 void wlc_phyreg_exit(wlc_phy_t *pih)
195 phy_info_t *pi = (phy_info_t *) pih;
196 wlapi_bmac_ucode_wake_override_phyreg_clear(pi->sh->physhim);
199 void wlc_radioreg_enter(wlc_phy_t *pih)
201 phy_info_t *pi = (phy_info_t *) pih;
202 wlapi_bmac_mctrl(pi->sh->physhim, MCTL_LOCK_RADIO, MCTL_LOCK_RADIO);
207 void wlc_radioreg_exit(wlc_phy_t *pih)
209 phy_info_t *pi = (phy_info_t *) pih;
212 dummy = R_REG(pi->sh->osh, &pi->regs->phyversion);
214 wlapi_bmac_mctrl(pi->sh->physhim, MCTL_LOCK_RADIO, 0);
217 u16 read_radio_reg(phy_info_t *pi, u16 addr)
221 if ((addr == RADIO_IDCODE))
224 if (NORADIO_ENAB(pi->pubpi))
225 return NORADIO_IDCODE & 0xffff;
227 switch (pi->pubpi.phy_type) {
229 CASECHECK(PHYTYPE, PHY_TYPE_N);
230 if (NREV_GE(pi->pubpi.phy_rev, 7))
231 addr |= RADIO_2057_READ_OFF;
233 addr |= RADIO_2055_READ_OFF;
237 CASECHECK(PHYTYPE, PHY_TYPE_LCN);
238 addr |= RADIO_2064_READ_OFF;
242 ASSERT(VALID_PHYTYPE(pi->pubpi.phy_type));
245 if ((D11REV_GE(pi->sh->corerev, 24)) ||
246 (D11REV_IS(pi->sh->corerev, 22)
247 && (pi->pubpi.phy_type != PHY_TYPE_SSN))) {
248 W_REG(pi->sh->osh, &pi->regs->radioregaddr, addr);
250 (void)R_REG(pi->sh->osh, &pi->regs->radioregaddr);
252 data = R_REG(pi->sh->osh, &pi->regs->radioregdata);
254 W_REG(pi->sh->osh, &pi->regs->phy4waddr, addr);
256 (void)R_REG(pi->sh->osh, &pi->regs->phy4waddr);
259 #ifdef __ARM_ARCH_4T__
260 __asm__(" .align 4 ");
262 data = R_REG(pi->sh->osh, &pi->regs->phy4wdatalo);
264 data = R_REG(pi->sh->osh, &pi->regs->phy4wdatalo);
273 void write_radio_reg(phy_info_t *pi, u16 addr, u16 val)
277 if (NORADIO_ENAB(pi->pubpi))
282 if ((D11REV_GE(pi->sh->corerev, 24)) ||
283 (D11REV_IS(pi->sh->corerev, 22)
284 && (pi->pubpi.phy_type != PHY_TYPE_SSN))) {
286 W_REG(osh, &pi->regs->radioregaddr, addr);
288 (void)R_REG(osh, &pi->regs->radioregaddr);
290 W_REG(osh, &pi->regs->radioregdata, val);
292 W_REG(osh, &pi->regs->phy4waddr, addr);
294 (void)R_REG(osh, &pi->regs->phy4waddr);
296 W_REG(osh, &pi->regs->phy4wdatalo, val);
299 if (BUSTYPE(pi->sh->bustype) == PCI_BUS) {
300 if (++pi->phy_wreg >= pi->phy_wreg_limit) {
301 (void)R_REG(osh, &pi->regs->maccontrol);
307 static u32 read_radio_id(phy_info_t *pi)
311 if (NORADIO_ENAB(pi->pubpi))
312 return NORADIO_IDCODE;
314 if (D11REV_GE(pi->sh->corerev, 24)) {
317 W_REG(pi->sh->osh, &pi->regs->radioregaddr, 0);
319 (void)R_REG(pi->sh->osh, &pi->regs->radioregaddr);
321 b0 = (u32) R_REG(pi->sh->osh, &pi->regs->radioregdata);
322 W_REG(pi->sh->osh, &pi->regs->radioregaddr, 1);
324 (void)R_REG(pi->sh->osh, &pi->regs->radioregaddr);
326 b1 = (u32) R_REG(pi->sh->osh, &pi->regs->radioregdata);
327 W_REG(pi->sh->osh, &pi->regs->radioregaddr, 2);
329 (void)R_REG(pi->sh->osh, &pi->regs->radioregaddr);
331 b2 = (u32) R_REG(pi->sh->osh, &pi->regs->radioregdata);
333 id = ((b0 & 0xf) << 28) | (((b2 << 8) | b1) << 12) | ((b0 >> 4)
336 W_REG(pi->sh->osh, &pi->regs->phy4waddr, RADIO_IDCODE);
338 (void)R_REG(pi->sh->osh, &pi->regs->phy4waddr);
340 id = (u32) R_REG(pi->sh->osh, &pi->regs->phy4wdatalo);
341 id |= (u32) R_REG(pi->sh->osh, &pi->regs->phy4wdatahi) << 16;
347 void and_radio_reg(phy_info_t *pi, u16 addr, u16 val)
351 if (NORADIO_ENAB(pi->pubpi))
354 rval = read_radio_reg(pi, addr);
355 write_radio_reg(pi, addr, (rval & val));
358 void or_radio_reg(phy_info_t *pi, u16 addr, u16 val)
362 if (NORADIO_ENAB(pi->pubpi))
365 rval = read_radio_reg(pi, addr);
366 write_radio_reg(pi, addr, (rval | val));
369 void xor_radio_reg(phy_info_t *pi, u16 addr, u16 mask)
373 if (NORADIO_ENAB(pi->pubpi))
376 rval = read_radio_reg(pi, addr);
377 write_radio_reg(pi, addr, (rval ^ mask));
380 void mod_radio_reg(phy_info_t *pi, u16 addr, u16 mask, u16 val)
384 if (NORADIO_ENAB(pi->pubpi))
387 rval = read_radio_reg(pi, addr);
388 write_radio_reg(pi, addr, (rval & ~mask) | (val & mask));
391 void write_phy_channel_reg(phy_info_t *pi, uint val)
393 W_REG(pi->sh->osh, &pi->regs->phychannel, val);
397 static bool wlc_phy_war41476(phy_info_t *pi)
399 u32 mc = R_REG(pi->sh->osh, &pi->regs->maccontrol);
401 return ((mc & MCTL_EN_MAC) == 0)
402 || ((mc & MCTL_PHYLOCK) == MCTL_PHYLOCK);
406 u16 read_phy_reg(phy_info_t *pi, u16 addr)
414 W_REG(osh, ®s->phyregaddr, addr);
416 (void)R_REG(osh, ®s->phyregaddr);
420 (D11REV_IS(pi->sh->corerev, 11)
421 || D11REV_IS(pi->sh->corerev, 12)) || wlc_phy_war41476(pi));
424 return R_REG(osh, ®s->phyregdata);
427 void write_phy_reg(phy_info_t *pi, u16 addr, u16 val)
436 W_REG(osh, ®s->phyregaddr, addr);
437 (void)R_REG(osh, ®s->phyregaddr);
438 W_REG(osh, ®s->phyregdata, val);
440 (void)R_REG(osh, ®s->phyregdata);
442 W_REG(osh, (volatile u32 *)(uintptr) (®s->phyregaddr),
444 if (BUSTYPE(pi->sh->bustype) == PCI_BUS) {
445 if (++pi->phy_wreg >= pi->phy_wreg_limit) {
447 (void)R_REG(osh, ®s->phyversion);
453 void and_phy_reg(phy_info_t *pi, u16 addr, u16 val)
461 W_REG(osh, ®s->phyregaddr, addr);
463 (void)R_REG(osh, ®s->phyregaddr);
467 (D11REV_IS(pi->sh->corerev, 11)
468 || D11REV_IS(pi->sh->corerev, 12)) || wlc_phy_war41476(pi));
470 W_REG(osh, ®s->phyregdata, (R_REG(osh, ®s->phyregdata) & val));
474 void or_phy_reg(phy_info_t *pi, u16 addr, u16 val)
482 W_REG(osh, ®s->phyregaddr, addr);
484 (void)R_REG(osh, ®s->phyregaddr);
488 (D11REV_IS(pi->sh->corerev, 11)
489 || D11REV_IS(pi->sh->corerev, 12)) || wlc_phy_war41476(pi));
491 W_REG(osh, ®s->phyregdata, (R_REG(osh, ®s->phyregdata) | val));
495 void mod_phy_reg(phy_info_t *pi, u16 addr, u16 mask, u16 val)
503 W_REG(osh, ®s->phyregaddr, addr);
505 (void)R_REG(osh, ®s->phyregaddr);
509 (D11REV_IS(pi->sh->corerev, 11)
510 || D11REV_IS(pi->sh->corerev, 12)) || wlc_phy_war41476(pi));
512 W_REG(osh, ®s->phyregdata,
513 ((R_REG(osh, ®s->phyregdata) & ~mask) | (val & mask)));
517 static void WLBANDINITFN(wlc_set_phy_uninitted) (phy_info_t *pi)
521 pi->initialized = FALSE;
524 pi->nrssi_table_delta = 0x7fffffff;
526 pi->mintxbias = 0xffff;
529 pi->phy_spuravoid = SPURAVOID_DISABLE;
531 if (NREV_GE(pi->pubpi.phy_rev, 3)
532 && NREV_LT(pi->pubpi.phy_rev, 7))
533 pi->phy_spuravoid = SPURAVOID_AUTO;
535 pi->nphy_papd_skip = 0;
536 pi->nphy_papd_epsilon_offset[0] = 0xf588;
537 pi->nphy_papd_epsilon_offset[1] = 0xf588;
538 pi->nphy_txpwr_idx[0] = 128;
539 pi->nphy_txpwr_idx[1] = 128;
540 pi->nphy_txpwrindex[0].index_internal = 40;
541 pi->nphy_txpwrindex[1].index_internal = 40;
544 pi->phy_spuravoid = SPURAVOID_AUTO;
546 pi->radiopwr = 0xffff;
547 for (i = 0; i < STATIC_NUM_RF; i++) {
548 for (j = 0; j < STATIC_NUM_BB; j++) {
549 pi->stats_11b_txpower[i][j] = -1;
554 shared_phy_t *BCMATTACHFN(wlc_phy_shared_attach) (shared_phy_params_t *shp)
558 sh = (shared_phy_t *) MALLOC(shp->osh, sizeof(shared_phy_t));
562 bzero((char *)sh, sizeof(shared_phy_t));
566 sh->physhim = shp->physhim;
567 sh->unit = shp->unit;
568 sh->corerev = shp->corerev;
572 sh->chip = shp->chip;
573 sh->chiprev = shp->chiprev;
574 sh->chippkg = shp->chippkg;
575 sh->sromrev = shp->sromrev;
576 sh->boardtype = shp->boardtype;
577 sh->boardrev = shp->boardrev;
578 sh->boardvendor = shp->boardvendor;
579 sh->boardflags = shp->boardflags;
580 sh->boardflags2 = shp->boardflags2;
581 sh->bustype = shp->bustype;
582 sh->buscorerev = shp->buscorerev;
584 sh->fast_timer = PHY_SW_TIMER_FAST;
585 sh->slow_timer = PHY_SW_TIMER_SLOW;
586 sh->glacial_timer = PHY_SW_TIMER_GLACIAL;
588 sh->rssi_mode = RSSI_ANT_MERGE_MAX;
593 void BCMATTACHFN(wlc_phy_shared_detach) (shared_phy_t *phy_sh)
600 if (phy_sh->phy_head) {
601 ASSERT(!phy_sh->phy_head);
603 MFREE(osh, phy_sh, sizeof(shared_phy_t));
607 wlc_phy_t *BCMATTACHFN(wlc_phy_attach) (shared_phy_t *sh, void *regs,
608 int bandtype, char *vars) {
617 if (D11REV_IS(sh->corerev, 4))
618 sflags = SISF_2G_PHY | SISF_5G_PHY;
620 sflags = si_core_sflags(sh->sih, 0, 0);
622 if (BAND_5G(bandtype)) {
623 if ((sflags & (SISF_5G_PHY | SISF_DB_PHY)) == 0) {
629 if ((sflags & SISF_DB_PHY) && pi) {
631 wlapi_bmac_corereset(pi->sh->physhim, pi->pubpi.coreflags);
633 return &pi->pubpi_ro;
636 pi = (phy_info_t *) MALLOC(osh, sizeof(phy_info_t));
640 bzero((char *)pi, sizeof(phy_info_t));
641 pi->regs = (d11regs_t *) regs;
643 pi->phy_init_por = TRUE;
644 pi->phy_wreg_limit = PHY_WREG_LIMIT;
648 pi->txpwr_percent = 100;
650 pi->do_initcal = TRUE;
652 pi->phycal_tempdelta = 0;
654 if (BAND_2G(bandtype) && (sflags & SISF_2G_PHY)) {
656 pi->pubpi.coreflags = SICF_GMODE;
659 wlapi_bmac_corereset(pi->sh->physhim, pi->pubpi.coreflags);
660 phyversion = R_REG(osh, &pi->regs->phyversion);
662 pi->pubpi.phy_type = PHY_TYPE(phyversion);
663 pi->pubpi.phy_rev = phyversion & PV_PV_MASK;
665 if (pi->pubpi.phy_type == PHY_TYPE_LCNXN) {
666 pi->pubpi.phy_type = PHY_TYPE_N;
667 pi->pubpi.phy_rev += LCNXN_BASEREV;
669 pi->pubpi.phy_corenum = PHY_CORE_NUM_2;
670 pi->pubpi.ana_rev = (phyversion & PV_AV_MASK) >> PV_AV_SHIFT;
672 if (!VALID_PHYTYPE(pi->pubpi.phy_type)) {
675 if (BAND_5G(bandtype)) {
680 if (!ISNPHY(pi) && !ISLCNPHY(pi)) {
685 if (ISSIM_ENAB(pi->sh->sih)) {
686 pi->pubpi.radioid = NORADIO_ID;
687 pi->pubpi.radiorev = 5;
691 wlc_phy_anacore((wlc_phy_t *) pi, ON);
693 idcode = wlc_phy_get_radio_ver(pi);
695 (idcode & IDCODE_ID_MASK) >> IDCODE_ID_SHIFT;
697 (idcode & IDCODE_REV_MASK) >> IDCODE_REV_SHIFT;
699 (idcode & IDCODE_VER_MASK) >> IDCODE_VER_SHIFT;
700 if (!VALID_RADIO(pi, pi->pubpi.radioid)) {
704 wlc_phy_switch_radio((wlc_phy_t *) pi, OFF);
707 wlc_set_phy_uninitted(pi);
709 pi->bw = WL_CHANSPEC_BW_20;
711 BAND_2G(bandtype) ? CH20MHZ_CHSPEC(1) : CH20MHZ_CHSPEC(36);
713 pi->rxiq_samps = PHY_NOISE_SAMPLE_LOG_NUM_NPHY;
714 pi->rxiq_antsel = ANT_RX_DIV_DEF;
716 pi->watchdog_override = TRUE;
718 pi->cal_type_override = PHY_PERICAL_AUTO;
720 pi->nphy_saved_noisevars.bufcount = 0;
723 pi->min_txpower = PHY_TXPWR_MIN_NPHY;
725 pi->min_txpower = PHY_TXPWR_MIN;
727 pi->sh->phyrxchain = 0x3;
729 pi->rx2tx_biasentry = -1;
731 pi->phy_txcore_disable_temp = PHY_CHAIN_TX_DISABLE_TEMP;
732 pi->phy_txcore_enable_temp =
733 PHY_CHAIN_TX_DISABLE_TEMP - PHY_HYSTERESIS_DELTATEMP;
734 pi->phy_tempsense_offset = 0;
735 pi->phy_txcore_heatedup = FALSE;
737 pi->nphy_lastcal_temp = -50;
739 pi->phynoise_polling = TRUE;
740 if (ISNPHY(pi) || ISLCNPHY(pi))
741 pi->phynoise_polling = FALSE;
743 for (i = 0; i < TXP_NUM_RATES; i++) {
744 pi->txpwr_limit[i] = WLC_TXPWR_MAX;
745 pi->txpwr_env_limit[i] = WLC_TXPWR_MAX;
746 pi->tx_user_target[i] = WLC_TXPWR_MAX;
749 pi->radiopwr_override = RADIOPWR_OVERRIDE_DEF;
751 pi->user_txpwr_at_rfport = FALSE;
755 pi->phycal_timer = wlapi_init_timer(pi->sh->physhim,
756 wlc_phy_timercb_phycal,
758 if (!pi->phycal_timer) {
762 if (!wlc_phy_attach_nphy(pi))
765 } else if (ISLCNPHY(pi)) {
766 if (!wlc_phy_attach_lcnphy(pi))
774 pi->next = pi->sh->phy_head;
777 pi->vars = (char *)&pi->vars;
779 bcopy(&pi->pubpi, &pi->pubpi_ro, sizeof(wlc_phy_t));
781 return &pi->pubpi_ro;
785 MFREE(sh->osh, pi, sizeof(phy_info_t));
789 void BCMATTACHFN(wlc_phy_detach) (wlc_phy_t *pih)
791 phy_info_t *pi = (phy_info_t *) pih;
798 if (pi->phycal_timer) {
799 wlapi_free_timer(pi->sh->physhim, pi->phycal_timer);
800 pi->phycal_timer = NULL;
803 if (pi->sh->phy_head == pi)
804 pi->sh->phy_head = pi->next;
805 else if (pi->sh->phy_head->next == pi)
806 pi->sh->phy_head->next = NULL;
810 if (pi->pi_fptr.detach)
811 (pi->pi_fptr.detach) (pi);
813 MFREE(pi->sh->osh, pi, sizeof(phy_info_t));
818 wlc_phy_get_phyversion(wlc_phy_t *pih, u16 *phytype, u16 *phyrev,
819 u16 *radioid, u16 *radiover)
821 phy_info_t *pi = (phy_info_t *) pih;
822 *phytype = (u16) pi->pubpi.phy_type;
823 *phyrev = (u16) pi->pubpi.phy_rev;
824 *radioid = pi->pubpi.radioid;
825 *radiover = pi->pubpi.radiorev;
830 bool wlc_phy_get_encore(wlc_phy_t *pih)
832 phy_info_t *pi = (phy_info_t *) pih;
833 return pi->pubpi.abgphy_encore;
836 u32 wlc_phy_get_coreflags(wlc_phy_t *pih)
838 phy_info_t *pi = (phy_info_t *) pih;
839 return pi->pubpi.coreflags;
842 static void wlc_phy_timercb_phycal(void *arg)
844 phy_info_t *pi = (phy_info_t *) arg;
847 if (PHY_PERICAL_MPHASE_PENDING(pi)) {
849 wlc_phy_cal_perical_mphase_reset(pi);
853 if (SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi)) {
856 wlc_phy_cal_perical_mphase_restart(pi);
858 wlc_phy_cal_perical_nphy_run(pi, PHY_PERICAL_AUTO);
859 wlapi_add_timer(pi->sh->physhim, pi->phycal_timer, delay, 0);
865 void wlc_phy_anacore(wlc_phy_t *pih, bool on)
867 phy_info_t *pi = (phy_info_t *) pih;
871 if (NREV_GE(pi->pubpi.phy_rev, 3)) {
872 write_phy_reg(pi, 0xa6, 0x0d);
873 write_phy_reg(pi, 0x8f, 0x0);
874 write_phy_reg(pi, 0xa7, 0x0d);
875 write_phy_reg(pi, 0xa5, 0x0);
877 write_phy_reg(pi, 0xa5, 0x0);
880 if (NREV_GE(pi->pubpi.phy_rev, 3)) {
881 write_phy_reg(pi, 0x8f, 0x07ff);
882 write_phy_reg(pi, 0xa6, 0x0fd);
883 write_phy_reg(pi, 0xa5, 0x07ff);
884 write_phy_reg(pi, 0xa7, 0x0fd);
886 write_phy_reg(pi, 0xa5, 0x7fff);
889 } else if (ISLCNPHY(pi)) {
891 and_phy_reg(pi, 0x43b,
892 ~((0x1 << 0) | (0x1 << 1) | (0x1 << 2)));
894 or_phy_reg(pi, 0x43c,
895 (0x1 << 0) | (0x1 << 1) | (0x1 << 2));
896 or_phy_reg(pi, 0x43b,
897 (0x1 << 0) | (0x1 << 1) | (0x1 << 2));
902 u32 wlc_phy_clk_bwbits(wlc_phy_t *pih)
904 phy_info_t *pi = (phy_info_t *) pih;
906 u32 phy_bw_clkbits = 0;
908 if (pi && (ISNPHY(pi) || ISLCNPHY(pi))) {
910 case WL_CHANSPEC_BW_10:
911 phy_bw_clkbits = SICF_BW10;
913 case WL_CHANSPEC_BW_20:
914 phy_bw_clkbits = SICF_BW20;
916 case WL_CHANSPEC_BW_40:
917 phy_bw_clkbits = SICF_BW40;
925 return phy_bw_clkbits;
928 void WLBANDINITFN(wlc_phy_por_inform) (wlc_phy_t *ppi)
930 phy_info_t *pi = (phy_info_t *) ppi;
932 pi->phy_init_por = TRUE;
935 void wlc_phy_edcrs_lock(wlc_phy_t *pih, bool lock)
937 phy_info_t *pi = (phy_info_t *) pih;
939 pi->edcrs_threshold_lock = lock;
941 write_phy_reg(pi, 0x22c, 0x46b);
942 write_phy_reg(pi, 0x22d, 0x46b);
943 write_phy_reg(pi, 0x22e, 0x3c0);
944 write_phy_reg(pi, 0x22f, 0x3c0);
947 void wlc_phy_initcal_enable(wlc_phy_t *pih, bool initcal)
949 phy_info_t *pi = (phy_info_t *) pih;
951 pi->do_initcal = initcal;
954 void wlc_phy_hw_clk_state_upd(wlc_phy_t *pih, bool newstate)
956 phy_info_t *pi = (phy_info_t *) pih;
961 pi->sh->clk = newstate;
964 void wlc_phy_hw_state_upd(wlc_phy_t *pih, bool newstate)
966 phy_info_t *pi = (phy_info_t *) pih;
971 pi->sh->up = newstate;
974 void WLBANDINITFN(wlc_phy_init) (wlc_phy_t *pih, chanspec_t chanspec)
977 initfn_t phy_init = NULL;
978 phy_info_t *pi = (phy_info_t *) pih;
980 if (pi->init_in_progress)
983 pi->init_in_progress = TRUE;
985 pi->radio_chanspec = chanspec;
987 mc = R_REG(pi->sh->osh, &pi->regs->maccontrol);
988 if ((mc & MCTL_EN_MAC) != 0) {
989 ASSERT((const char *)
990 "wlc_phy_init: Called with the MAC running!" == NULL);
995 if (!(pi->measure_hold & PHY_HOLD_FOR_SCAN)) {
996 pi->measure_hold |= PHY_HOLD_FOR_NOT_ASSOC;
999 if (D11REV_GE(pi->sh->corerev, 5))
1000 ASSERT(si_core_sflags(pi->sh->sih, 0, 0) & SISF_FCLKA);
1002 phy_init = pi->pi_fptr.init;
1004 if (phy_init == NULL) {
1005 ASSERT(phy_init != NULL);
1009 wlc_phy_anacore(pih, ON);
1011 if (CHSPEC_BW(pi->radio_chanspec) != pi->bw)
1012 wlapi_bmac_bw_set(pi->sh->physhim,
1013 CHSPEC_BW(pi->radio_chanspec));
1015 pi->nphy_gain_boost = TRUE;
1017 wlc_phy_switch_radio((wlc_phy_t *) pi, ON);
1021 pi->phy_init_por = FALSE;
1023 if (D11REV_IS(pi->sh->corerev, 11) || D11REV_IS(pi->sh->corerev, 12))
1024 wlc_phy_do_dummy_tx(pi, TRUE, OFF);
1027 wlc_phy_txpower_update_shm(pi);
1029 wlc_phy_ant_rxdiv_set((wlc_phy_t *) pi, pi->sh->rx_antdiv);
1031 pi->init_in_progress = FALSE;
1034 void BCMINITFN(wlc_phy_cal_init) (wlc_phy_t *pih)
1036 phy_info_t *pi = (phy_info_t *) pih;
1037 initfn_t cal_init = NULL;
1039 ASSERT((R_REG(pi->sh->osh, &pi->regs->maccontrol) & MCTL_EN_MAC) == 0);
1041 if (!pi->initialized) {
1042 cal_init = pi->pi_fptr.calinit;
1046 pi->initialized = TRUE;
1050 int BCMUNINITFN(wlc_phy_down) (wlc_phy_t *pih)
1052 phy_info_t *pi = (phy_info_t *) pih;
1055 ASSERT(pi->phytest_on == FALSE);
1057 if (pi->phycal_timer
1058 && !wlapi_del_timer(pi->sh->physhim, pi->phycal_timer))
1061 pi->nphy_iqcal_chanspec_2G = 0;
1062 pi->nphy_iqcal_chanspec_5G = 0;
1067 static u32 wlc_phy_get_radio_ver(phy_info_t *pi)
1071 ver = read_radio_id(pi);
1077 wlc_phy_table_addr(phy_info_t *pi, uint tbl_id, uint tbl_offset,
1078 u16 tblAddr, u16 tblDataHi, u16 tblDataLo)
1080 write_phy_reg(pi, tblAddr, (tbl_id << 10) | tbl_offset);
1082 pi->tbl_data_hi = tblDataHi;
1083 pi->tbl_data_lo = tblDataLo;
1085 if ((CHIPID(pi->sh->chip) == BCM43224_CHIP_ID ||
1086 CHIPID(pi->sh->chip) == BCM43421_CHIP_ID) &&
1087 (pi->sh->chiprev == 1)) {
1088 pi->tbl_addr = tblAddr;
1089 pi->tbl_save_id = tbl_id;
1090 pi->tbl_save_offset = tbl_offset;
1094 void wlc_phy_table_data_write(phy_info_t *pi, uint width, u32 val)
1096 ASSERT((width == 8) || (width == 16) || (width == 32));
1098 if ((CHIPID(pi->sh->chip) == BCM43224_CHIP_ID ||
1099 CHIPID(pi->sh->chip) == BCM43421_CHIP_ID) &&
1100 (pi->sh->chiprev == 1) &&
1101 (pi->tbl_save_id == NPHY_TBL_ID_ANTSWCTRLLUT)) {
1102 read_phy_reg(pi, pi->tbl_data_lo);
1104 write_phy_reg(pi, pi->tbl_addr,
1105 (pi->tbl_save_id << 10) | pi->tbl_save_offset);
1106 pi->tbl_save_offset++;
1111 write_phy_reg(pi, pi->tbl_data_hi, (u16) (val >> 16));
1112 write_phy_reg(pi, pi->tbl_data_lo, (u16) val);
1115 write_phy_reg(pi, pi->tbl_data_lo, (u16) val);
1120 wlc_phy_write_table(phy_info_t *pi, const phytbl_info_t *ptbl_info,
1121 u16 tblAddr, u16 tblDataHi, u16 tblDataLo)
1124 uint tbl_id = ptbl_info->tbl_id;
1125 uint tbl_offset = ptbl_info->tbl_offset;
1126 uint tbl_width = ptbl_info->tbl_width;
1127 const u8 *ptbl_8b = (const u8 *)ptbl_info->tbl_ptr;
1128 const u16 *ptbl_16b = (const u16 *)ptbl_info->tbl_ptr;
1129 const u32 *ptbl_32b = (const u32 *)ptbl_info->tbl_ptr;
1131 ASSERT((tbl_width == 8) || (tbl_width == 16) || (tbl_width == 32));
1133 write_phy_reg(pi, tblAddr, (tbl_id << 10) | tbl_offset);
1135 for (idx = 0; idx < ptbl_info->tbl_len; idx++) {
1137 if ((CHIPID(pi->sh->chip) == BCM43224_CHIP_ID ||
1138 CHIPID(pi->sh->chip) == BCM43421_CHIP_ID) &&
1139 (pi->sh->chiprev == 1) &&
1140 (tbl_id == NPHY_TBL_ID_ANTSWCTRLLUT)) {
1141 read_phy_reg(pi, tblDataLo);
1143 write_phy_reg(pi, tblAddr,
1144 (tbl_id << 10) | (tbl_offset + idx));
1147 if (tbl_width == 32) {
1149 write_phy_reg(pi, tblDataHi,
1150 (u16) (ptbl_32b[idx] >> 16));
1151 write_phy_reg(pi, tblDataLo, (u16) ptbl_32b[idx]);
1152 } else if (tbl_width == 16) {
1154 write_phy_reg(pi, tblDataLo, ptbl_16b[idx]);
1157 write_phy_reg(pi, tblDataLo, ptbl_8b[idx]);
1163 wlc_phy_read_table(phy_info_t *pi, const phytbl_info_t *ptbl_info,
1164 u16 tblAddr, u16 tblDataHi, u16 tblDataLo)
1167 uint tbl_id = ptbl_info->tbl_id;
1168 uint tbl_offset = ptbl_info->tbl_offset;
1169 uint tbl_width = ptbl_info->tbl_width;
1170 u8 *ptbl_8b = (u8 *) (uintptr) ptbl_info->tbl_ptr;
1171 u16 *ptbl_16b = (u16 *) (uintptr) ptbl_info->tbl_ptr;
1172 u32 *ptbl_32b = (u32 *) (uintptr) ptbl_info->tbl_ptr;
1174 ASSERT((tbl_width == 8) || (tbl_width == 16) || (tbl_width == 32));
1176 write_phy_reg(pi, tblAddr, (tbl_id << 10) | tbl_offset);
1178 for (idx = 0; idx < ptbl_info->tbl_len; idx++) {
1180 if ((CHIPID(pi->sh->chip) == BCM43224_CHIP_ID ||
1181 CHIPID(pi->sh->chip) == BCM43421_CHIP_ID) &&
1182 (pi->sh->chiprev == 1)) {
1183 (void)read_phy_reg(pi, tblDataLo);
1185 write_phy_reg(pi, tblAddr,
1186 (tbl_id << 10) | (tbl_offset + idx));
1189 if (tbl_width == 32) {
1191 ptbl_32b[idx] = read_phy_reg(pi, tblDataLo);
1192 ptbl_32b[idx] |= (read_phy_reg(pi, tblDataHi) << 16);
1193 } else if (tbl_width == 16) {
1195 ptbl_16b[idx] = read_phy_reg(pi, tblDataLo);
1198 ptbl_8b[idx] = (u8) read_phy_reg(pi, tblDataLo);
1204 wlc_phy_init_radio_regs_allbands(phy_info_t *pi, radio_20xx_regs_t *radioregs)
1209 if (radioregs[i].do_init) {
1210 write_radio_reg(pi, radioregs[i].address,
1211 (u16) radioregs[i].init);
1215 } while (radioregs[i].address != 0xffff);
1221 wlc_phy_init_radio_regs(phy_info_t *pi, radio_regs_t *radioregs,
1228 if (CHSPEC_IS5G(pi->radio_chanspec)) {
1229 if (radioregs[i].do_init_a) {
1232 address | core_offset,
1233 (u16) radioregs[i].init_a);
1234 if (ISNPHY(pi) && (++count % 4 == 0))
1235 WLC_PHY_WAR_PR51571(pi);
1238 if (radioregs[i].do_init_g) {
1241 address | core_offset,
1242 (u16) radioregs[i].init_g);
1243 if (ISNPHY(pi) && (++count % 4 == 0))
1244 WLC_PHY_WAR_PR51571(pi);
1249 } while (radioregs[i].address != 0xffff);
1254 void wlc_phy_do_dummy_tx(phy_info_t *pi, bool ofdm, bool pa_on)
1256 #define DUMMY_PKT_LEN 20
1257 d11regs_t *regs = pi->regs;
1259 u8 ofdmpkt[DUMMY_PKT_LEN] = {
1260 0xcc, 0x01, 0x02, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00,
1261 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00
1263 u8 cckpkt[DUMMY_PKT_LEN] = {
1264 0x6e, 0x84, 0x0b, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00,
1265 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00
1269 ASSERT((R_REG(pi->sh->osh, &pi->regs->maccontrol) & MCTL_EN_MAC) == 0);
1271 dummypkt = (u32 *) (ofdm ? ofdmpkt : cckpkt);
1272 wlapi_bmac_write_template_ram(pi->sh->physhim, 0, DUMMY_PKT_LEN,
1275 W_REG(pi->sh->osh, ®s->xmtsel, 0);
1277 if (D11REV_GE(pi->sh->corerev, 11))
1278 W_REG(pi->sh->osh, ®s->wepctl, 0x100);
1280 W_REG(pi->sh->osh, ®s->wepctl, 0);
1282 W_REG(pi->sh->osh, ®s->txe_phyctl, (ofdm ? 1 : 0) | PHY_TXC_ANT_0);
1283 if (ISNPHY(pi) || ISLCNPHY(pi)) {
1285 W_REG(pi->sh->osh, ®s->txe_phyctl1, 0x1A02);
1288 W_REG(pi->sh->osh, ®s->txe_wm_0, 0);
1289 W_REG(pi->sh->osh, ®s->txe_wm_1, 0);
1291 W_REG(pi->sh->osh, ®s->xmttplatetxptr, 0);
1292 W_REG(pi->sh->osh, ®s->xmttxcnt, DUMMY_PKT_LEN);
1294 W_REG(pi->sh->osh, ®s->xmtsel, ((8 << 8) | (1 << 5) | (1 << 2) | 2));
1296 W_REG(pi->sh->osh, ®s->txe_ctl, 0);
1300 wlc_phy_pa_override_nphy(pi, OFF);
1303 if (ISNPHY(pi) || ISLCNPHY(pi))
1304 W_REG(pi->sh->osh, ®s->txe_aux, 0xD0);
1306 W_REG(pi->sh->osh, ®s->txe_aux, ((1 << 5) | (1 << 4)));
1308 (void)R_REG(pi->sh->osh, ®s->txe_aux);
1311 count = ofdm ? 30 : 250;
1313 if (ISSIM_ENAB(pi->sh->sih)) {
1317 while ((i++ < count)
1318 && (R_REG(pi->sh->osh, ®s->txe_status) & (1 << 7))) {
1325 && ((R_REG(pi->sh->osh, ®s->txe_status) & (1 << 10)) == 0)) {
1331 while ((i++ < 10) && ((R_REG(pi->sh->osh, ®s->ifsstat) & (1 << 8)))) {
1336 wlc_phy_pa_override_nphy(pi, ON);
1340 void wlc_phy_hold_upd(wlc_phy_t *pih, mbool id, bool set)
1342 phy_info_t *pi = (phy_info_t *) pih;
1346 mboolset(pi->measure_hold, id);
1348 mboolclr(pi->measure_hold, id);
1354 void wlc_phy_mute_upd(wlc_phy_t *pih, bool mute, mbool flags)
1356 phy_info_t *pi = (phy_info_t *) pih;
1359 mboolset(pi->measure_hold, PHY_HOLD_FOR_MUTE);
1361 mboolclr(pi->measure_hold, PHY_HOLD_FOR_MUTE);
1364 if (!mute && (flags & PHY_MUTE_FOR_PREISM))
1365 pi->nphy_perical_last = pi->sh->now - pi->sh->glacial_timer;
1369 void wlc_phy_clear_tssi(wlc_phy_t *pih)
1371 phy_info_t *pi = (phy_info_t *) pih;
1376 wlapi_bmac_write_shm(pi->sh->physhim, M_B_TSSI_0, NULL_TSSI_W);
1377 wlapi_bmac_write_shm(pi->sh->physhim, M_B_TSSI_1, NULL_TSSI_W);
1378 wlapi_bmac_write_shm(pi->sh->physhim, M_G_TSSI_0, NULL_TSSI_W);
1379 wlapi_bmac_write_shm(pi->sh->physhim, M_G_TSSI_1, NULL_TSSI_W);
1383 static bool wlc_phy_cal_txpower_recalc_sw(phy_info_t *pi)
1388 void wlc_phy_switch_radio(wlc_phy_t *pih, bool on)
1390 phy_info_t *pi = (phy_info_t *) pih;
1392 if (NORADIO_ENAB(pi->pubpi))
1398 mc = R_REG(pi->sh->osh, &pi->regs->maccontrol);
1402 wlc_phy_switch_radio_nphy(pi, on);
1404 } else if (ISLCNPHY(pi)) {
1406 and_phy_reg(pi, 0x44c,
1409 (0x1 << 10) | (0x1 << 11) | (0x1 << 12)));
1410 and_phy_reg(pi, 0x4b0, ~((0x1 << 3) | (0x1 << 11)));
1411 and_phy_reg(pi, 0x4f9, ~(0x1 << 3));
1413 and_phy_reg(pi, 0x44d,
1416 (0x1 << 12) | (0x1 << 13) | (0x1 << 14)));
1417 or_phy_reg(pi, 0x44c,
1420 (0x1 << 10) | (0x1 << 11) | (0x1 << 12));
1422 and_phy_reg(pi, 0x4b7, ~((0x7f << 8)));
1423 and_phy_reg(pi, 0x4b1, ~((0x1 << 13)));
1424 or_phy_reg(pi, 0x4b0, (0x1 << 3) | (0x1 << 11));
1425 and_phy_reg(pi, 0x4fa, ~((0x1 << 3)));
1426 or_phy_reg(pi, 0x4f9, (0x1 << 3));
1431 u16 wlc_phy_bw_state_get(wlc_phy_t *ppi)
1433 phy_info_t *pi = (phy_info_t *) ppi;
1438 void wlc_phy_bw_state_set(wlc_phy_t *ppi, u16 bw)
1440 phy_info_t *pi = (phy_info_t *) ppi;
1445 void wlc_phy_chanspec_radio_set(wlc_phy_t *ppi, chanspec_t newch)
1447 phy_info_t *pi = (phy_info_t *) ppi;
1448 pi->radio_chanspec = newch;
1452 chanspec_t wlc_phy_chanspec_get(wlc_phy_t *ppi)
1454 phy_info_t *pi = (phy_info_t *) ppi;
1456 return pi->radio_chanspec;
1459 void wlc_phy_chanspec_set(wlc_phy_t *ppi, chanspec_t chanspec)
1461 phy_info_t *pi = (phy_info_t *) ppi;
1463 chansetfn_t chanspec_set = NULL;
1465 ASSERT(!wf_chspec_malformed(chanspec));
1467 m_cur_channel = CHSPEC_CHANNEL(chanspec);
1468 if (CHSPEC_IS5G(chanspec))
1469 m_cur_channel |= D11_CURCHANNEL_5G;
1470 if (CHSPEC_IS40(chanspec))
1471 m_cur_channel |= D11_CURCHANNEL_40;
1472 wlapi_bmac_write_shm(pi->sh->physhim, M_CURCHANNEL, m_cur_channel);
1474 chanspec_set = pi->pi_fptr.chanset;
1476 (*chanspec_set) (pi, chanspec);
1480 int wlc_phy_chanspec_freq2bandrange_lpssn(uint freq)
1485 range = WL_CHAN_FREQ_RANGE_2G;
1486 else if (freq <= 5320)
1487 range = WL_CHAN_FREQ_RANGE_5GL;
1488 else if (freq <= 5700)
1489 range = WL_CHAN_FREQ_RANGE_5GM;
1491 range = WL_CHAN_FREQ_RANGE_5GH;
1496 int wlc_phy_chanspec_bandrange_get(phy_info_t *pi, chanspec_t chanspec)
1499 uint channel = CHSPEC_CHANNEL(chanspec);
1500 uint freq = wlc_phy_channel2freq(channel);
1503 range = wlc_phy_get_chan_freq_range_nphy(pi, channel);
1504 } else if (ISLCNPHY(pi)) {
1505 range = wlc_phy_chanspec_freq2bandrange_lpssn(freq);
1512 void wlc_phy_chanspec_ch14_widefilter_set(wlc_phy_t *ppi, bool wide_filter)
1514 phy_info_t *pi = (phy_info_t *) ppi;
1516 pi->channel_14_wide_filter = wide_filter;
1520 int wlc_phy_channel2freq(uint channel)
1524 for (i = 0; i < ARRAYSIZE(chan_info_all); i++)
1525 if (chan_info_all[i].chan == channel)
1526 return chan_info_all[i].freq;
1531 wlc_phy_chanspec_band_validch(wlc_phy_t *ppi, uint band, chanvec_t *channels)
1533 phy_info_t *pi = (phy_info_t *) ppi;
1537 ASSERT((band == WLC_BAND_2G) || (band == WLC_BAND_5G));
1539 bzero(channels, sizeof(chanvec_t));
1541 for (i = 0; i < ARRAYSIZE(chan_info_all); i++) {
1542 channel = chan_info_all[i].chan;
1544 if ((pi->a_band_high_disable) && (channel >= FIRST_REF5_CHANNUM)
1545 && (channel <= LAST_REF5_CHANNUM))
1548 if (((band == WLC_BAND_2G) && (channel <= CH_MAX_2G_CHANNEL)) ||
1549 ((band == WLC_BAND_5G) && (channel > CH_MAX_2G_CHANNEL)))
1550 setbit(channels->vec, channel);
1554 chanspec_t wlc_phy_chanspec_band_firstch(wlc_phy_t *ppi, uint band)
1556 phy_info_t *pi = (phy_info_t *) ppi;
1561 ASSERT((band == WLC_BAND_2G) || (band == WLC_BAND_5G));
1563 for (i = 0; i < ARRAYSIZE(chan_info_all); i++) {
1564 channel = chan_info_all[i].chan;
1566 if (ISNPHY(pi) && IS40MHZ(pi)) {
1569 for (j = 0; j < ARRAYSIZE(chan_info_all); j++) {
1570 if (chan_info_all[j].chan ==
1571 channel + CH_10MHZ_APART)
1575 if (j == ARRAYSIZE(chan_info_all))
1578 channel = UPPER_20_SB(channel);
1580 channel | WL_CHANSPEC_BW_40 |
1581 WL_CHANSPEC_CTL_SB_LOWER;
1582 if (band == WLC_BAND_2G)
1583 chspec |= WL_CHANSPEC_BAND_2G;
1585 chspec |= WL_CHANSPEC_BAND_5G;
1587 chspec = CH20MHZ_CHSPEC(channel);
1589 if ((pi->a_band_high_disable) && (channel >= FIRST_REF5_CHANNUM)
1590 && (channel <= LAST_REF5_CHANNUM))
1593 if (((band == WLC_BAND_2G) && (channel <= CH_MAX_2G_CHANNEL)) ||
1594 ((band == WLC_BAND_5G) && (channel > CH_MAX_2G_CHANNEL)))
1600 return (chanspec_t) INVCHANSPEC;
1603 int wlc_phy_txpower_get(wlc_phy_t *ppi, uint *qdbm, bool *override)
1605 phy_info_t *pi = (phy_info_t *) ppi;
1607 ASSERT(qdbm != NULL);
1608 *qdbm = pi->tx_user_target[0];
1609 if (override != NULL)
1610 *override = pi->txpwroverride;
1614 void wlc_phy_txpower_target_set(wlc_phy_t *ppi, struct txpwr_limits *txpwr)
1616 bool mac_enabled = FALSE;
1617 phy_info_t *pi = (phy_info_t *) ppi;
1619 bcopy(&txpwr->cck[0], &pi->tx_user_target[TXP_FIRST_CCK],
1622 bcopy(&txpwr->ofdm[0], &pi->tx_user_target[TXP_FIRST_OFDM],
1623 WLC_NUM_RATES_OFDM);
1624 bcopy(&txpwr->ofdm_cdd[0], &pi->tx_user_target[TXP_FIRST_OFDM_20_CDD],
1625 WLC_NUM_RATES_OFDM);
1627 bcopy(&txpwr->ofdm_40_siso[0],
1628 &pi->tx_user_target[TXP_FIRST_OFDM_40_SISO], WLC_NUM_RATES_OFDM);
1629 bcopy(&txpwr->ofdm_40_cdd[0],
1630 &pi->tx_user_target[TXP_FIRST_OFDM_40_CDD], WLC_NUM_RATES_OFDM);
1632 bcopy(&txpwr->mcs_20_siso[0],
1633 &pi->tx_user_target[TXP_FIRST_MCS_20_SISO],
1634 WLC_NUM_RATES_MCS_1_STREAM);
1635 bcopy(&txpwr->mcs_20_cdd[0], &pi->tx_user_target[TXP_FIRST_MCS_20_CDD],
1636 WLC_NUM_RATES_MCS_1_STREAM);
1637 bcopy(&txpwr->mcs_20_stbc[0],
1638 &pi->tx_user_target[TXP_FIRST_MCS_20_STBC],
1639 WLC_NUM_RATES_MCS_1_STREAM);
1640 bcopy(&txpwr->mcs_20_mimo[0], &pi->tx_user_target[TXP_FIRST_MCS_20_SDM],
1641 WLC_NUM_RATES_MCS_2_STREAM);
1643 bcopy(&txpwr->mcs_40_siso[0],
1644 &pi->tx_user_target[TXP_FIRST_MCS_40_SISO],
1645 WLC_NUM_RATES_MCS_1_STREAM);
1646 bcopy(&txpwr->mcs_40_cdd[0], &pi->tx_user_target[TXP_FIRST_MCS_40_CDD],
1647 WLC_NUM_RATES_MCS_1_STREAM);
1648 bcopy(&txpwr->mcs_40_stbc[0],
1649 &pi->tx_user_target[TXP_FIRST_MCS_40_STBC],
1650 WLC_NUM_RATES_MCS_1_STREAM);
1651 bcopy(&txpwr->mcs_40_mimo[0], &pi->tx_user_target[TXP_FIRST_MCS_40_SDM],
1652 WLC_NUM_RATES_MCS_2_STREAM);
1654 if (R_REG(pi->sh->osh, &pi->regs->maccontrol) & MCTL_EN_MAC)
1658 wlapi_suspend_mac_and_wait(pi->sh->physhim);
1660 wlc_phy_txpower_recalc_target(pi);
1661 wlc_phy_cal_txpower_recalc_sw(pi);
1664 wlapi_enable_mac(pi->sh->physhim);
1667 int wlc_phy_txpower_set(wlc_phy_t *ppi, uint qdbm, bool override)
1669 phy_info_t *pi = (phy_info_t *) ppi;
1675 for (i = 0; i < TXP_NUM_RATES; i++)
1676 pi->tx_user_target[i] = (u8) qdbm;
1678 pi->txpwroverride = FALSE;
1681 if (!SCAN_INPROG_PHY(pi)) {
1686 (R_REG(pi->sh->osh, &pi->regs->maccontrol) &
1690 wlapi_suspend_mac_and_wait(pi->sh->physhim);
1692 wlc_phy_txpower_recalc_target(pi);
1693 wlc_phy_cal_txpower_recalc_sw(pi);
1696 wlapi_enable_mac(pi->sh->physhim);
1703 wlc_phy_txpower_sromlimit(wlc_phy_t *ppi, uint channel, u8 *min_pwr,
1704 u8 *max_pwr, int txp_rate_idx)
1706 phy_info_t *pi = (phy_info_t *) ppi;
1709 *min_pwr = pi->min_txpower * WLC_TXPWR_DB_FACTOR;
1712 if (txp_rate_idx < 0)
1713 txp_rate_idx = TXP_FIRST_CCK;
1714 wlc_phy_txpower_sromlimit_get_nphy(pi, channel, max_pwr,
1717 } else if ((channel <= CH_MAX_2G_CHANNEL)) {
1718 if (txp_rate_idx < 0)
1719 txp_rate_idx = TXP_FIRST_CCK;
1720 *max_pwr = pi->tx_srom_max_rate_2g[txp_rate_idx];
1723 *max_pwr = WLC_TXPWR_MAX;
1725 if (txp_rate_idx < 0)
1726 txp_rate_idx = TXP_FIRST_OFDM;
1728 for (i = 0; i < ARRAYSIZE(chan_info_all); i++) {
1729 if (channel == chan_info_all[i].chan) {
1733 ASSERT(i < ARRAYSIZE(chan_info_all));
1736 *max_pwr = pi->hwtxpwr[i];
1739 if ((i >= FIRST_MID_5G_CHAN) && (i <= LAST_MID_5G_CHAN))
1741 pi->tx_srom_max_rate_5g_mid[txp_rate_idx];
1742 if ((i >= FIRST_HIGH_5G_CHAN)
1743 && (i <= LAST_HIGH_5G_CHAN))
1745 pi->tx_srom_max_rate_5g_hi[txp_rate_idx];
1746 if ((i >= FIRST_LOW_5G_CHAN) && (i <= LAST_LOW_5G_CHAN))
1748 pi->tx_srom_max_rate_5g_low[txp_rate_idx];
1754 wlc_phy_txpower_sromlimit_max_get(wlc_phy_t *ppi, uint chan, u8 *max_txpwr,
1757 phy_info_t *pi = (phy_info_t *) ppi;
1759 u8 tx_pwr_min = 255;
1761 u8 maxtxpwr, mintxpwr, rate, pactrl;
1765 max_num_rate = ISNPHY(pi) ? TXP_NUM_RATES :
1766 ISLCNPHY(pi) ? (TXP_LAST_SISO_MCS_20 + 1) : (TXP_LAST_OFDM + 1);
1768 for (rate = 0; rate < max_num_rate; rate++) {
1770 wlc_phy_txpower_sromlimit(ppi, chan, &mintxpwr, &maxtxpwr,
1773 maxtxpwr = (maxtxpwr > pactrl) ? (maxtxpwr - pactrl) : 0;
1775 maxtxpwr = (maxtxpwr > 6) ? (maxtxpwr - 6) : 0;
1777 tx_pwr_max = MAX(tx_pwr_max, maxtxpwr);
1778 tx_pwr_min = MIN(tx_pwr_min, maxtxpwr);
1780 *max_txpwr = tx_pwr_max;
1781 *min_txpwr = tx_pwr_min;
1785 wlc_phy_txpower_boardlimit_band(wlc_phy_t *ppi, uint bandunit, int32 *max_pwr,
1786 int32 *min_pwr, u32 *step_pwr)
1791 u8 wlc_phy_txpower_get_target_min(wlc_phy_t *ppi)
1793 phy_info_t *pi = (phy_info_t *) ppi;
1795 return pi->tx_power_min;
1798 u8 wlc_phy_txpower_get_target_max(wlc_phy_t *ppi)
1800 phy_info_t *pi = (phy_info_t *) ppi;
1802 return pi->tx_power_max;
1805 void wlc_phy_txpower_recalc_target(phy_info_t *pi)
1807 u8 maxtxpwr, mintxpwr, rate, pactrl;
1809 u8 tx_pwr_target[TXP_NUM_RATES];
1811 u8 tx_pwr_min = 255;
1812 u8 tx_pwr_max_rate_ind = 0;
1816 u32 band = CHSPEC2WLC_BAND(pi->radio_chanspec);
1817 initfn_t txpwr_recalc_fn = NULL;
1819 chspec = pi->radio_chanspec;
1820 if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_NONE)
1821 target_chan = CHSPEC_CHANNEL(chspec);
1822 else if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_UPPER)
1823 target_chan = UPPER_20_SB(CHSPEC_CHANNEL(chspec));
1825 target_chan = LOWER_20_SB(CHSPEC_CHANNEL(chspec));
1831 if (CHSPEC_IS40(pi->radio_chanspec)) {
1832 offset_mcs = pi->mcs40_po;
1833 for (i = TXP_FIRST_SISO_MCS_20;
1834 i <= TXP_LAST_SISO_MCS_20; i++) {
1835 pi->tx_srom_max_rate_2g[i - 8] =
1836 pi->tx_srom_max_2g -
1837 ((offset_mcs & 0xf) * 2);
1841 offset_mcs = pi->mcs20_po;
1842 for (i = TXP_FIRST_SISO_MCS_20;
1843 i <= TXP_LAST_SISO_MCS_20; i++) {
1844 pi->tx_srom_max_rate_2g[i - 8] =
1845 pi->tx_srom_max_2g -
1846 ((offset_mcs & 0xf) * 2);
1852 max_num_rate = ((ISNPHY(pi)) ? (TXP_NUM_RATES) :
1854 (TXP_LAST_SISO_MCS_20 + 1) : (TXP_LAST_OFDM + 1)));
1856 max_num_rate = ((ISNPHY(pi)) ? (TXP_NUM_RATES) : (TXP_LAST_OFDM + 1));
1859 wlc_phy_upd_env_txpwr_rate_limits(pi, band);
1861 for (rate = start_rate; rate < max_num_rate; rate++) {
1863 tx_pwr_target[rate] = pi->tx_user_target[rate];
1865 if (pi->user_txpwr_at_rfport) {
1866 tx_pwr_target[rate] +=
1867 wlc_user_txpwr_antport_to_rfport(pi, target_chan,
1873 wlc_phy_txpower_sromlimit((wlc_phy_t *) pi, target_chan,
1874 &mintxpwr, &maxtxpwr, rate);
1876 maxtxpwr = MIN(maxtxpwr, pi->txpwr_limit[rate]);
1879 (maxtxpwr > pactrl) ? (maxtxpwr - pactrl) : 0;
1881 maxtxpwr = (maxtxpwr > 6) ? (maxtxpwr - 6) : 0;
1883 maxtxpwr = MIN(maxtxpwr, tx_pwr_target[rate]);
1885 if (pi->txpwr_percent <= 100)
1886 maxtxpwr = (maxtxpwr * pi->txpwr_percent) / 100;
1888 tx_pwr_target[rate] = MAX(maxtxpwr, mintxpwr);
1891 tx_pwr_target[rate] =
1892 MIN(tx_pwr_target[rate], pi->txpwr_env_limit[rate]);
1894 if (tx_pwr_target[rate] > tx_pwr_max)
1895 tx_pwr_max_rate_ind = rate;
1897 tx_pwr_max = MAX(tx_pwr_max, tx_pwr_target[rate]);
1898 tx_pwr_min = MIN(tx_pwr_min, tx_pwr_target[rate]);
1901 bzero(pi->tx_power_offset, sizeof(pi->tx_power_offset));
1902 pi->tx_power_max = tx_pwr_max;
1903 pi->tx_power_min = tx_pwr_min;
1904 pi->tx_power_max_rate_ind = tx_pwr_max_rate_ind;
1905 for (rate = 0; rate < max_num_rate; rate++) {
1907 pi->tx_power_target[rate] = tx_pwr_target[rate];
1909 if (!pi->hwpwrctrl || ISNPHY(pi)) {
1910 pi->tx_power_offset[rate] =
1911 pi->tx_power_max - pi->tx_power_target[rate];
1913 pi->tx_power_offset[rate] =
1914 pi->tx_power_target[rate] - pi->tx_power_min;
1918 txpwr_recalc_fn = pi->pi_fptr.txpwrrecalc;
1919 if (txpwr_recalc_fn)
1920 (*txpwr_recalc_fn) (pi);
1924 wlc_phy_txpower_reg_limit_calc(phy_info_t *pi, struct txpwr_limits *txpwr,
1925 chanspec_t chanspec)
1927 u8 tmp_txpwr_limit[2 * WLC_NUM_RATES_OFDM];
1928 u8 *txpwr_ptr1 = NULL, *txpwr_ptr2 = NULL;
1929 int rate_start_index = 0, rate1, rate2, k;
1931 for (rate1 = WL_TX_POWER_CCK_FIRST, rate2 = 0;
1932 rate2 < WL_TX_POWER_CCK_NUM; rate1++, rate2++)
1933 pi->txpwr_limit[rate1] = txpwr->cck[rate2];
1935 for (rate1 = WL_TX_POWER_OFDM_FIRST, rate2 = 0;
1936 rate2 < WL_TX_POWER_OFDM_NUM; rate1++, rate2++)
1937 pi->txpwr_limit[rate1] = txpwr->ofdm[rate2];
1941 for (k = 0; k < 4; k++) {
1945 txpwr_ptr1 = txpwr->mcs_20_siso;
1946 txpwr_ptr2 = txpwr->ofdm;
1947 rate_start_index = WL_TX_POWER_OFDM_FIRST;
1951 txpwr_ptr1 = txpwr->mcs_20_cdd;
1952 txpwr_ptr2 = txpwr->ofdm_cdd;
1953 rate_start_index = WL_TX_POWER_OFDM20_CDD_FIRST;
1957 txpwr_ptr1 = txpwr->mcs_40_siso;
1958 txpwr_ptr2 = txpwr->ofdm_40_siso;
1960 WL_TX_POWER_OFDM40_SISO_FIRST;
1964 txpwr_ptr1 = txpwr->mcs_40_cdd;
1965 txpwr_ptr2 = txpwr->ofdm_40_cdd;
1966 rate_start_index = WL_TX_POWER_OFDM40_CDD_FIRST;
1970 for (rate2 = 0; rate2 < WLC_NUM_RATES_OFDM; rate2++) {
1971 tmp_txpwr_limit[rate2] = 0;
1972 tmp_txpwr_limit[WLC_NUM_RATES_OFDM + rate2] =
1975 wlc_phy_mcs_to_ofdm_powers_nphy(tmp_txpwr_limit, 0,
1976 WLC_NUM_RATES_OFDM - 1,
1977 WLC_NUM_RATES_OFDM);
1978 for (rate1 = rate_start_index, rate2 = 0;
1979 rate2 < WLC_NUM_RATES_OFDM; rate1++, rate2++)
1980 pi->txpwr_limit[rate1] =
1981 MIN(txpwr_ptr2[rate2],
1982 tmp_txpwr_limit[rate2]);
1985 for (k = 0; k < 4; k++) {
1989 txpwr_ptr1 = txpwr->ofdm;
1990 txpwr_ptr2 = txpwr->mcs_20_siso;
1991 rate_start_index = WL_TX_POWER_MCS20_SISO_FIRST;
1995 txpwr_ptr1 = txpwr->ofdm_cdd;
1996 txpwr_ptr2 = txpwr->mcs_20_cdd;
1997 rate_start_index = WL_TX_POWER_MCS20_CDD_FIRST;
2001 txpwr_ptr1 = txpwr->ofdm_40_siso;
2002 txpwr_ptr2 = txpwr->mcs_40_siso;
2003 rate_start_index = WL_TX_POWER_MCS40_SISO_FIRST;
2007 txpwr_ptr1 = txpwr->ofdm_40_cdd;
2008 txpwr_ptr2 = txpwr->mcs_40_cdd;
2009 rate_start_index = WL_TX_POWER_MCS40_CDD_FIRST;
2012 for (rate2 = 0; rate2 < WLC_NUM_RATES_OFDM; rate2++) {
2013 tmp_txpwr_limit[rate2] = 0;
2014 tmp_txpwr_limit[WLC_NUM_RATES_OFDM + rate2] =
2017 wlc_phy_ofdm_to_mcs_powers_nphy(tmp_txpwr_limit, 0,
2018 WLC_NUM_RATES_OFDM - 1,
2019 WLC_NUM_RATES_OFDM);
2020 for (rate1 = rate_start_index, rate2 = 0;
2021 rate2 < WLC_NUM_RATES_MCS_1_STREAM;
2023 pi->txpwr_limit[rate1] =
2024 MIN(txpwr_ptr2[rate2],
2025 tmp_txpwr_limit[rate2]);
2028 for (k = 0; k < 2; k++) {
2032 rate_start_index = WL_TX_POWER_MCS20_STBC_FIRST;
2033 txpwr_ptr1 = txpwr->mcs_20_stbc;
2037 rate_start_index = WL_TX_POWER_MCS40_STBC_FIRST;
2038 txpwr_ptr1 = txpwr->mcs_40_stbc;
2041 for (rate1 = rate_start_index, rate2 = 0;
2042 rate2 < WLC_NUM_RATES_MCS_1_STREAM;
2044 pi->txpwr_limit[rate1] = txpwr_ptr1[rate2];
2047 for (k = 0; k < 2; k++) {
2051 rate_start_index = WL_TX_POWER_MCS20_SDM_FIRST;
2052 txpwr_ptr1 = txpwr->mcs_20_mimo;
2056 rate_start_index = WL_TX_POWER_MCS40_SDM_FIRST;
2057 txpwr_ptr1 = txpwr->mcs_40_mimo;
2060 for (rate1 = rate_start_index, rate2 = 0;
2061 rate2 < WLC_NUM_RATES_MCS_2_STREAM;
2063 pi->txpwr_limit[rate1] = txpwr_ptr1[rate2];
2066 pi->txpwr_limit[WL_TX_POWER_MCS_32] = txpwr->mcs32;
2068 pi->txpwr_limit[WL_TX_POWER_MCS40_CDD_FIRST] =
2069 MIN(pi->txpwr_limit[WL_TX_POWER_MCS40_CDD_FIRST],
2070 pi->txpwr_limit[WL_TX_POWER_MCS_32]);
2071 pi->txpwr_limit[WL_TX_POWER_MCS_32] =
2072 pi->txpwr_limit[WL_TX_POWER_MCS40_CDD_FIRST];
2076 void wlc_phy_txpwr_percent_set(wlc_phy_t *ppi, u8 txpwr_percent)
2078 phy_info_t *pi = (phy_info_t *) ppi;
2080 pi->txpwr_percent = txpwr_percent;
2083 void wlc_phy_machwcap_set(wlc_phy_t *ppi, u32 machwcap)
2085 phy_info_t *pi = (phy_info_t *) ppi;
2087 pi->sh->machwcap = machwcap;
2090 void wlc_phy_runbist_config(wlc_phy_t *ppi, bool start_end)
2092 phy_info_t *pi = (phy_info_t *) ppi;
2096 if (start_end == ON) {
2100 if (NREV_IS(pi->pubpi.phy_rev, 3)
2101 || NREV_IS(pi->pubpi.phy_rev, 4)) {
2102 W_REG(pi->sh->osh, &pi->regs->phyregaddr, 0xa0);
2103 (void)R_REG(pi->sh->osh, &pi->regs->phyregaddr);
2104 rxc = R_REG(pi->sh->osh, &pi->regs->phyregdata);
2105 W_REG(pi->sh->osh, &pi->regs->phyregdata,
2109 if (NREV_IS(pi->pubpi.phy_rev, 3)
2110 || NREV_IS(pi->pubpi.phy_rev, 4)) {
2111 W_REG(pi->sh->osh, &pi->regs->phyregaddr, 0xa0);
2112 (void)R_REG(pi->sh->osh, &pi->regs->phyregaddr);
2113 W_REG(pi->sh->osh, &pi->regs->phyregdata, rxc);
2116 wlc_phy_por_inform(ppi);
2121 wlc_phy_txpower_limit_set(wlc_phy_t *ppi, struct txpwr_limits *txpwr,
2122 chanspec_t chanspec)
2124 phy_info_t *pi = (phy_info_t *) ppi;
2126 wlc_phy_txpower_reg_limit_calc(pi, txpwr, chanspec);
2130 for (i = TXP_FIRST_OFDM_20_CDD, j = 0;
2131 j < WLC_NUM_RATES_MCS_1_STREAM; i++, j++) {
2132 if (txpwr->mcs_20_siso[j])
2133 pi->txpwr_limit[i] = txpwr->mcs_20_siso[j];
2135 pi->txpwr_limit[i] = txpwr->ofdm[j];
2139 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2141 wlc_phy_txpower_recalc_target(pi);
2142 wlc_phy_cal_txpower_recalc_sw(pi);
2143 wlapi_enable_mac(pi->sh->physhim);
2146 void wlc_phy_ofdm_rateset_war(wlc_phy_t *pih, bool war)
2148 phy_info_t *pi = (phy_info_t *) pih;
2150 pi->ofdm_rateset_war = war;
2153 void wlc_phy_bf_preempt_enable(wlc_phy_t *pih, bool bf_preempt)
2155 phy_info_t *pi = (phy_info_t *) pih;
2157 pi->bf_preempt_4306 = bf_preempt;
2160 void wlc_phy_txpower_update_shm(phy_info_t *pi)
2171 if (pi->hwpwrctrl) {
2174 wlapi_bmac_write_shm(pi->sh->physhim, M_TXPWR_MAX, 63);
2175 wlapi_bmac_write_shm(pi->sh->physhim, M_TXPWR_N,
2176 1 << NUM_TSSI_FRAMES);
2178 wlapi_bmac_write_shm(pi->sh->physhim, M_TXPWR_TARGET,
2179 pi->tx_power_min << NUM_TSSI_FRAMES);
2181 wlapi_bmac_write_shm(pi->sh->physhim, M_TXPWR_CUR,
2184 for (j = TXP_FIRST_OFDM; j <= TXP_LAST_OFDM; j++) {
2185 const u8 ucode_ofdm_rates[] = {
2186 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c
2188 offset = wlapi_bmac_rate_shm_offset(pi->sh->physhim,
2189 ucode_ofdm_rates[j -
2191 wlapi_bmac_write_shm(pi->sh->physhim, offset + 6,
2192 pi->tx_power_offset[j]);
2193 wlapi_bmac_write_shm(pi->sh->physhim, offset + 14,
2194 -(pi->tx_power_offset[j] / 2));
2197 wlapi_bmac_mhf(pi->sh->physhim, MHF2, MHF2_HWPWRCTL,
2198 MHF2_HWPWRCTL, WLC_BAND_ALL);
2202 for (i = TXP_FIRST_OFDM; i <= TXP_LAST_OFDM; i++)
2203 pi->tx_power_offset[i] =
2204 (u8) ROUNDUP(pi->tx_power_offset[i], 8);
2205 wlapi_bmac_write_shm(pi->sh->physhim, M_OFDM_OFFSET,
2207 tx_power_offset[TXP_FIRST_OFDM]
2212 bool wlc_phy_txpower_hw_ctrl_get(wlc_phy_t *ppi)
2214 phy_info_t *pi = (phy_info_t *) ppi;
2217 return pi->nphy_txpwrctrl;
2219 return pi->hwpwrctrl;
2223 void wlc_phy_txpower_hw_ctrl_set(wlc_phy_t *ppi, bool hwpwrctrl)
2225 phy_info_t *pi = (phy_info_t *) ppi;
2226 bool cur_hwpwrctrl = pi->hwpwrctrl;
2229 if (!pi->hwpwrctrl_capable) {
2233 pi->hwpwrctrl = hwpwrctrl;
2234 pi->nphy_txpwrctrl = hwpwrctrl;
2235 pi->txpwrctrl = hwpwrctrl;
2240 (R_REG(pi->sh->osh, &pi->regs->maccontrol) & MCTL_EN_MAC));
2242 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2244 wlc_phy_txpwrctrl_enable_nphy(pi, pi->nphy_txpwrctrl);
2245 if (pi->nphy_txpwrctrl == PHY_TPC_HW_OFF) {
2246 wlc_phy_txpwr_fixpower_nphy(pi);
2249 mod_phy_reg(pi, 0x1e7, (0x7f << 0),
2250 pi->saved_txpwr_idx);
2254 wlapi_enable_mac(pi->sh->physhim);
2255 } else if (hwpwrctrl != cur_hwpwrctrl) {
2261 void wlc_phy_txpower_ipa_upd(phy_info_t *pi)
2264 if (NREV_GE(pi->pubpi.phy_rev, 3)) {
2265 pi->ipa2g_on = (pi->srom_fem2g.extpagain == 2);
2266 pi->ipa5g_on = (pi->srom_fem5g.extpagain == 2);
2268 pi->ipa2g_on = FALSE;
2269 pi->ipa5g_on = FALSE;
2273 static u32 wlc_phy_txpower_est_power_nphy(phy_info_t *pi);
2275 static u32 wlc_phy_txpower_est_power_nphy(phy_info_t *pi)
2277 s16 tx0_status, tx1_status;
2278 u16 estPower1, estPower2;
2279 u8 pwr0, pwr1, adj_pwr0, adj_pwr1;
2282 estPower1 = read_phy_reg(pi, 0x118);
2283 estPower2 = read_phy_reg(pi, 0x119);
2285 if ((estPower1 & (0x1 << 8))
2287 pwr0 = (u8) (estPower1 & (0xff << 0))
2293 if ((estPower2 & (0x1 << 8))
2295 pwr1 = (u8) (estPower2 & (0xff << 0))
2301 tx0_status = read_phy_reg(pi, 0x1ed);
2302 tx1_status = read_phy_reg(pi, 0x1ee);
2304 if ((tx0_status & (0x1 << 15))
2306 adj_pwr0 = (u8) (tx0_status & (0xff << 0))
2311 if ((tx1_status & (0x1 << 15))
2313 adj_pwr1 = (u8) (tx1_status & (0xff << 0))
2320 (u32) ((pwr0 << 24) | (pwr1 << 16) | (adj_pwr0 << 8) | adj_pwr1);
2325 wlc_phy_txpower_get_current(wlc_phy_t *ppi, tx_power_t *power, uint channel)
2327 phy_info_t *pi = (phy_info_t *) ppi;
2328 uint rate, num_rates;
2329 u8 min_pwr, max_pwr;
2331 #if WL_TX_POWER_RATES != TXP_NUM_RATES
2332 #error "tx_power_t struct out of sync with this fn"
2336 power->rf_cores = 2;
2337 power->flags |= (WL_TX_POWER_F_MIMO);
2338 if (pi->nphy_txpwrctrl == PHY_TPC_HW_ON)
2340 (WL_TX_POWER_F_ENABLED | WL_TX_POWER_F_HW);
2341 } else if (ISLCNPHY(pi)) {
2342 power->rf_cores = 1;
2343 power->flags |= (WL_TX_POWER_F_SISO);
2344 if (pi->radiopwr_override == RADIOPWR_OVERRIDE_DEF)
2345 power->flags |= WL_TX_POWER_F_ENABLED;
2347 power->flags |= WL_TX_POWER_F_HW;
2350 num_rates = ((ISNPHY(pi)) ? (TXP_NUM_RATES) :
2352 (TXP_LAST_OFDM_20_CDD + 1) : (TXP_LAST_OFDM + 1)));
2354 for (rate = 0; rate < num_rates; rate++) {
2355 power->user_limit[rate] = pi->tx_user_target[rate];
2356 wlc_phy_txpower_sromlimit(ppi, channel, &min_pwr, &max_pwr,
2358 power->board_limit[rate] = (u8) max_pwr;
2359 power->target[rate] = pi->tx_power_target[rate];
2365 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2366 wlc_phyreg_enter((wlc_phy_t *) pi);
2367 est_pout = wlc_phy_txpower_est_power_nphy(pi);
2368 wlc_phyreg_exit((wlc_phy_t *) pi);
2369 wlapi_enable_mac(pi->sh->physhim);
2371 power->est_Pout[0] = (est_pout >> 8) & 0xff;
2372 power->est_Pout[1] = est_pout & 0xff;
2374 power->est_Pout_act[0] = est_pout >> 24;
2375 power->est_Pout_act[1] = (est_pout >> 16) & 0xff;
2377 if (power->est_Pout[0] == 0x80)
2378 power->est_Pout[0] = 0;
2379 if (power->est_Pout[1] == 0x80)
2380 power->est_Pout[1] = 0;
2382 if (power->est_Pout_act[0] == 0x80)
2383 power->est_Pout_act[0] = 0;
2384 if (power->est_Pout_act[1] == 0x80)
2385 power->est_Pout_act[1] = 0;
2387 power->est_Pout_cck = 0;
2389 power->tx_power_max[0] = pi->tx_power_max;
2390 power->tx_power_max[1] = pi->tx_power_max;
2392 power->tx_power_max_rate_ind[0] = pi->tx_power_max_rate_ind;
2393 power->tx_power_max_rate_ind[1] = pi->tx_power_max_rate_ind;
2394 } else if (!pi->hwpwrctrl) {
2395 } else if (pi->sh->up) {
2397 wlc_phyreg_enter(ppi);
2400 power->tx_power_max[0] = pi->tx_power_max;
2401 power->tx_power_max[1] = pi->tx_power_max;
2403 power->tx_power_max_rate_ind[0] =
2404 pi->tx_power_max_rate_ind;
2405 power->tx_power_max_rate_ind[1] =
2406 pi->tx_power_max_rate_ind;
2408 if (wlc_phy_tpc_isenabled_lcnphy(pi))
2410 (WL_TX_POWER_F_HW | WL_TX_POWER_F_ENABLED);
2413 ~(WL_TX_POWER_F_HW | WL_TX_POWER_F_ENABLED);
2415 wlc_lcnphy_get_tssi(pi, (s8 *) &power->est_Pout[0],
2416 (s8 *) &power->est_Pout_cck);
2418 wlc_phyreg_exit(ppi);
2422 void wlc_phy_antsel_type_set(wlc_phy_t *ppi, u8 antsel_type)
2424 phy_info_t *pi = (phy_info_t *) ppi;
2426 pi->antsel_type = antsel_type;
2429 bool wlc_phy_test_ison(wlc_phy_t *ppi)
2431 phy_info_t *pi = (phy_info_t *) ppi;
2433 return pi->phytest_on;
2436 bool wlc_phy_ant_rxdiv_get(wlc_phy_t *ppi, u8 *pval)
2438 phy_info_t *pi = (phy_info_t *) ppi;
2441 wlc_phyreg_enter(ppi);
2446 } else if (ISLCNPHY(pi)) {
2447 u16 crsctrl = read_phy_reg(pi, 0x410);
2448 u16 div = crsctrl & (0x1 << 1);
2449 *pval = (div | ((crsctrl & (0x1 << 0)) ^ (div >> 1)));
2452 wlc_phyreg_exit(ppi);
2457 void wlc_phy_ant_rxdiv_set(wlc_phy_t *ppi, u8 val)
2459 phy_info_t *pi = (phy_info_t *) ppi;
2462 pi->sh->rx_antdiv = val;
2464 if (!(ISNPHY(pi) && D11REV_IS(pi->sh->corerev, 16))) {
2465 if (val > ANT_RX_DIV_FORCE_1)
2466 wlapi_bmac_mhf(pi->sh->physhim, MHF1, MHF1_ANTDIV,
2467 MHF1_ANTDIV, WLC_BAND_ALL);
2469 wlapi_bmac_mhf(pi->sh->physhim, MHF1, MHF1_ANTDIV, 0,
2482 (0 == (R_REG(pi->sh->osh, &pi->regs->maccontrol) & MCTL_EN_MAC));
2484 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2487 if (val > ANT_RX_DIV_FORCE_1) {
2488 mod_phy_reg(pi, 0x410, (0x1 << 1), 0x01 << 1);
2489 mod_phy_reg(pi, 0x410,
2491 ((ANT_RX_DIV_START_1 == val) ? 1 : 0) << 0);
2493 mod_phy_reg(pi, 0x410, (0x1 << 1), 0x00 << 1);
2494 mod_phy_reg(pi, 0x410, (0x1 << 0), (u16) val << 0);
2501 wlapi_enable_mac(pi->sh->physhim);
2507 wlc_phy_noise_calc_phy(phy_info_t *pi, u32 *cmplx_pwr, s8 *pwr_ant)
2509 s8 cmplx_pwr_dbm[PHY_CORE_MAX];
2512 bzero((u8 *) cmplx_pwr_dbm, sizeof(cmplx_pwr_dbm));
2513 ASSERT(pi->pubpi.phy_corenum <= PHY_CORE_MAX);
2514 wlc_phy_compute_dB(cmplx_pwr, cmplx_pwr_dbm, pi->pubpi.phy_corenum);
2516 for (i = 0; i < pi->pubpi.phy_corenum; i++) {
2517 if (NREV_GE(pi->pubpi.phy_rev, 3))
2518 cmplx_pwr_dbm[i] += (s8) PHY_NOISE_OFFSETFACT_4322;
2521 cmplx_pwr_dbm[i] += (s8) (16 - (15) * 3 - 70);
2524 for (i = 0; i < pi->pubpi.phy_corenum; i++) {
2525 pi->nphy_noise_win[i][pi->nphy_noise_index] = cmplx_pwr_dbm[i];
2526 pwr_ant[i] = cmplx_pwr_dbm[i];
2528 pi->nphy_noise_index =
2529 MODINC_POW2(pi->nphy_noise_index, PHY_NOISE_WINDOW_SZ);
2534 wlc_phy_noise_sample_request(wlc_phy_t *pih, u8 reason, u8 ch)
2536 phy_info_t *pi = (phy_info_t *) pih;
2537 s8 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;
2538 bool sampling_in_progress = (pi->phynoise_state != 0);
2539 bool wait_for_intr = TRUE;
2541 if (NORADIO_ENAB(pi->pubpi)) {
2546 case PHY_NOISE_SAMPLE_MON:
2548 pi->phynoise_chan_watchdog = ch;
2549 pi->phynoise_state |= PHY_NOISE_STATE_MON;
2553 case PHY_NOISE_SAMPLE_EXTERNAL:
2555 pi->phynoise_state |= PHY_NOISE_STATE_EXTERNAL;
2563 if (sampling_in_progress)
2566 pi->phynoise_now = pi->sh->now;
2568 if (pi->phy_fixed_noise) {
2570 pi->nphy_noise_win[WL_ANT_IDX_1][pi->nphy_noise_index] =
2571 PHY_NOISE_FIXED_VAL_NPHY;
2572 pi->nphy_noise_win[WL_ANT_IDX_2][pi->nphy_noise_index] =
2573 PHY_NOISE_FIXED_VAL_NPHY;
2574 pi->nphy_noise_index = MODINC_POW2(pi->nphy_noise_index,
2575 PHY_NOISE_WINDOW_SZ);
2577 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;
2580 noise_dbm = PHY_NOISE_FIXED_VAL;
2583 wait_for_intr = FALSE;
2588 if (!pi->phynoise_polling
2589 || (reason == PHY_NOISE_SAMPLE_EXTERNAL)) {
2590 wlapi_bmac_write_shm(pi->sh->physhim, M_JSSI_0, 0);
2591 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP0, 0);
2592 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP1, 0);
2593 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP2, 0);
2594 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP3, 0);
2596 OR_REG(pi->sh->osh, &pi->regs->maccommand,
2599 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2600 wlc_lcnphy_deaf_mode(pi, (bool) 0);
2601 noise_dbm = (s8) wlc_lcnphy_rx_signal_power(pi, 20);
2602 wlc_lcnphy_deaf_mode(pi, (bool) 1);
2603 wlapi_enable_mac(pi->sh->physhim);
2604 wait_for_intr = FALSE;
2606 } else if (ISNPHY(pi)) {
2607 if (!pi->phynoise_polling
2608 || (reason == PHY_NOISE_SAMPLE_EXTERNAL)) {
2610 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP0, 0);
2611 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP1, 0);
2612 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP2, 0);
2613 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP3, 0);
2615 OR_REG(pi->sh->osh, &pi->regs->maccommand,
2618 phy_iq_est_t est[PHY_CORE_MAX];
2619 u32 cmplx_pwr[PHY_CORE_MAX];
2620 s8 noise_dbm_ant[PHY_CORE_MAX];
2621 u16 log_num_samps, num_samps, classif_state = 0;
2626 bzero((u8 *) est, sizeof(est));
2627 bzero((u8 *) cmplx_pwr, sizeof(cmplx_pwr));
2628 bzero((u8 *) noise_dbm_ant, sizeof(noise_dbm_ant));
2630 log_num_samps = PHY_NOISE_SAMPLE_LOG_NUM_NPHY;
2631 num_samps = 1 << log_num_samps;
2633 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2634 classif_state = wlc_phy_classifier_nphy(pi, 0, 0);
2635 wlc_phy_classifier_nphy(pi, 3, 0);
2636 wlc_phy_rx_iq_est_nphy(pi, est, num_samps, wait_time,
2638 wlc_phy_classifier_nphy(pi, (0x7 << 0), classif_state);
2639 wlapi_enable_mac(pi->sh->physhim);
2641 for (i = 0; i < pi->pubpi.phy_corenum; i++)
2644 est[i].q_pwr) >> log_num_samps;
2646 wlc_phy_noise_calc_phy(pi, cmplx_pwr, noise_dbm_ant);
2648 for (i = 0; i < pi->pubpi.phy_corenum; i++) {
2649 pi->nphy_noise_win[i][pi->nphy_noise_index] =
2652 if (noise_dbm_ant[i] > noise_dbm)
2653 noise_dbm = noise_dbm_ant[i];
2655 pi->nphy_noise_index = MODINC_POW2(pi->nphy_noise_index,
2656 PHY_NOISE_WINDOW_SZ);
2658 wait_for_intr = FALSE;
2665 wlc_phy_noise_cb(pi, ch, noise_dbm);
2669 void wlc_phy_noise_sample_request_external(wlc_phy_t *pih)
2673 channel = CHSPEC_CHANNEL(wlc_phy_chanspec_get(pih));
2675 wlc_phy_noise_sample_request(pih, PHY_NOISE_SAMPLE_EXTERNAL, channel);
2678 static void wlc_phy_noise_cb(phy_info_t *pi, u8 channel, s8 noise_dbm)
2680 if (!pi->phynoise_state)
2683 if (pi->phynoise_state & PHY_NOISE_STATE_MON) {
2684 if (pi->phynoise_chan_watchdog == channel) {
2685 pi->sh->phy_noise_window[pi->sh->phy_noise_index] =
2687 pi->sh->phy_noise_index =
2688 MODINC(pi->sh->phy_noise_index, MA_WINDOW_SZ);
2690 pi->phynoise_state &= ~PHY_NOISE_STATE_MON;
2693 if (pi->phynoise_state & PHY_NOISE_STATE_EXTERNAL) {
2694 pi->phynoise_state &= ~PHY_NOISE_STATE_EXTERNAL;
2699 static s8 wlc_phy_noise_read_shmem(phy_info_t *pi)
2701 u32 cmplx_pwr[PHY_CORE_MAX];
2702 s8 noise_dbm_ant[PHY_CORE_MAX];
2704 u32 cmplx_pwr_tot = 0;
2705 s8 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;
2708 ASSERT(pi->pubpi.phy_corenum <= PHY_CORE_MAX);
2709 bzero((u8 *) cmplx_pwr, sizeof(cmplx_pwr));
2710 bzero((u8 *) noise_dbm_ant, sizeof(noise_dbm_ant));
2712 for (idx = 0, core = 0; core < pi->pubpi.phy_corenum; idx += 2, core++) {
2713 lo = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP(idx));
2714 hi = wlapi_bmac_read_shm(pi->sh->physhim,
2715 M_PWRIND_MAP(idx + 1));
2716 cmplx_pwr[core] = (hi << 16) + lo;
2717 cmplx_pwr_tot += cmplx_pwr[core];
2718 if (cmplx_pwr[core] == 0) {
2719 noise_dbm_ant[core] = PHY_NOISE_FIXED_VAL_NPHY;
2721 cmplx_pwr[core] >>= PHY_NOISE_SAMPLE_LOG_NUM_UCODE;
2724 if (cmplx_pwr_tot != 0)
2725 wlc_phy_noise_calc_phy(pi, cmplx_pwr, noise_dbm_ant);
2727 for (core = 0; core < pi->pubpi.phy_corenum; core++) {
2728 pi->nphy_noise_win[core][pi->nphy_noise_index] =
2729 noise_dbm_ant[core];
2731 if (noise_dbm_ant[core] > noise_dbm)
2732 noise_dbm = noise_dbm_ant[core];
2734 pi->nphy_noise_index =
2735 MODINC_POW2(pi->nphy_noise_index, PHY_NOISE_WINDOW_SZ);
2741 void wlc_phy_noise_sample_intr(wlc_phy_t *pih)
2743 phy_info_t *pi = (phy_info_t *) pih;
2746 s8 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;
2749 u32 cmplx_pwr, cmplx_pwr0, cmplx_pwr1;
2751 int32 pwr_offset_dB, gain_dB;
2752 u16 status_0, status_1;
2754 jssi_aux = wlapi_bmac_read_shm(pi->sh->physhim, M_JSSI_AUX);
2755 channel = jssi_aux & D11_CURCHANNEL_MAX;
2757 lo = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP0);
2758 hi = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP1);
2759 cmplx_pwr0 = (hi << 16) + lo;
2761 lo = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP2);
2762 hi = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP3);
2763 cmplx_pwr1 = (hi << 16) + lo;
2764 cmplx_pwr = (cmplx_pwr0 + cmplx_pwr1) >> 6;
2767 status_1 = wlapi_bmac_read_shm(pi->sh->physhim, M_JSSI_0);
2768 if ((cmplx_pwr > 0 && cmplx_pwr < 500)
2769 && ((status_1 & 0xc000) == 0x4000)) {
2771 wlc_phy_compute_dB(&cmplx_pwr, &noise_dbm,
2772 pi->pubpi.phy_corenum);
2773 pwr_offset_dB = (read_phy_reg(pi, 0x434) & 0xFF);
2774 if (pwr_offset_dB > 127)
2775 pwr_offset_dB -= 256;
2777 noise_dbm += (s8) (pwr_offset_dB - 30);
2779 gain_dB = (status_0 & 0x1ff);
2780 noise_dbm -= (s8) (gain_dB);
2782 noise_dbm = PHY_NOISE_FIXED_VAL_LCNPHY;
2784 } else if (ISNPHY(pi)) {
2786 jssi_aux = wlapi_bmac_read_shm(pi->sh->physhim, M_JSSI_AUX);
2787 channel = jssi_aux & D11_CURCHANNEL_MAX;
2789 noise_dbm = wlc_phy_noise_read_shmem(pi);
2794 wlc_phy_noise_cb(pi, channel, noise_dbm);
2798 s8 lcnphy_gain_index_offset_for_pkt_rssi[] = {
2839 void wlc_phy_compute_dB(u32 *cmplx_pwr, s8 *p_cmplx_pwr_dB, u8 core)
2841 u8 shift_ct, lsb, msb, secondmsb, i;
2844 for (i = 0; i < core; i++) {
2846 shift_ct = msb = secondmsb = 0;
2850 lsb = (u8) (tmp & 1);
2854 secondmsb = (u8) ((cmplx_pwr[i] >> (msb - 1)) & 1);
2855 p_cmplx_pwr_dB[i] = (s8) (3 * msb + 2 * secondmsb);
2859 void BCMFASTPATH wlc_phy_rssi_compute(wlc_phy_t *pih, void *ctx)
2861 wlc_d11rxhdr_t *wlc_rxhdr = (wlc_d11rxhdr_t *) ctx;
2862 d11rxhdr_t *rxh = &wlc_rxhdr->rxhdr;
2863 int rssi = ltoh16(rxh->PhyRxStatus_1) & PRXS1_JSSI_MASK;
2864 uint radioid = pih->radioid;
2865 phy_info_t *pi = (phy_info_t *) pih;
2867 if (NORADIO_ENAB(pi->pubpi)) {
2868 rssi = WLC_RSSI_INVALID;
2872 if ((pi->sh->corerev >= 11)
2873 && !(ltoh16(rxh->RxStatus2) & RXS_PHYRXST_VALID)) {
2874 rssi = WLC_RSSI_INVALID;
2879 u8 gidx = (ltoh16(rxh->PhyRxStatus_2) & 0xFC00) >> 10;
2880 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
2885 rssi = rssi + lcnphy_gain_index_offset_for_pkt_rssi[gidx];
2886 if ((rssi > -46) && (gidx > 18))
2889 rssi = rssi + pi_lcn->lcnphy_pkteng_rssi_slope;
2899 } else if (radioid == BCM2055_ID || radioid == BCM2056_ID
2900 || radioid == BCM2057_ID) {
2902 rssi = wlc_phy_rssi_compute_nphy(pi, wlc_rxhdr);
2904 ASSERT((const char *)"Unknown radio" == NULL);
2908 wlc_rxhdr->rssi = (s8) rssi;
2911 void wlc_phy_freqtrack_start(wlc_phy_t *pih)
2916 void wlc_phy_freqtrack_end(wlc_phy_t *pih)
2921 void wlc_phy_set_deaf(wlc_phy_t *ppi, bool user_flag)
2924 pi = (phy_info_t *) ppi;
2927 wlc_lcnphy_deaf_mode(pi, TRUE);
2928 else if (ISNPHY(pi))
2929 wlc_nphy_deaf_mode(pi, TRUE);
2935 void wlc_phy_watchdog(wlc_phy_t *pih)
2937 phy_info_t *pi = (phy_info_t *) pih;
2938 bool delay_phy_cal = FALSE;
2941 if (!pi->watchdog_override)
2944 if (!(SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi))) {
2945 wlc_phy_noise_sample_request((wlc_phy_t *) pi,
2946 PHY_NOISE_SAMPLE_MON,
2951 if (pi->phynoise_state && (pi->sh->now - pi->phynoise_now) > 5) {
2952 pi->phynoise_state = 0;
2955 if ((!pi->phycal_txpower) ||
2956 ((pi->sh->now - pi->phycal_txpower) >= pi->sh->fast_timer)) {
2958 if (!SCAN_INPROG_PHY(pi) && wlc_phy_cal_txpower_recalc_sw(pi)) {
2959 pi->phycal_txpower = pi->sh->now;
2963 if (NORADIO_ENAB(pi->pubpi))
2966 if ((SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi)
2967 || ASSOC_INPROG_PHY(pi)))
2970 if (ISNPHY(pi) && !pi->disable_percal && !delay_phy_cal) {
2972 if ((pi->nphy_perical != PHY_PERICAL_DISABLE) &&
2973 (pi->nphy_perical != PHY_PERICAL_MANUAL) &&
2974 ((pi->sh->now - pi->nphy_perical_last) >=
2975 pi->sh->glacial_timer))
2976 wlc_phy_cal_perical((wlc_phy_t *) pi,
2977 PHY_PERICAL_WATCHDOG);
2979 wlc_phy_txpwr_papd_cal_nphy(pi);
2983 if (pi->phy_forcecal ||
2984 ((pi->sh->now - pi->phy_lastcal) >=
2985 pi->sh->glacial_timer)) {
2986 if (!(SCAN_RM_IN_PROGRESS(pi) || ASSOC_INPROG_PHY(pi)))
2987 wlc_lcnphy_calib_modes(pi,
2988 LCNPHY_PERICAL_TEMPBASED_TXPWRCTRL);
2990 (SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi)
2991 || ASSOC_INPROG_PHY(pi)
2992 || pi->carrier_suppr_disable
2993 || pi->pkteng_in_progress || pi->disable_percal))
2994 wlc_lcnphy_calib_modes(pi,
2995 PHY_PERICAL_WATCHDOG);
3000 void wlc_phy_BSSinit(wlc_phy_t *pih, bool bonlyap, int rssi)
3002 phy_info_t *pi = (phy_info_t *) pih;
3006 for (i = 0; i < MA_WINDOW_SZ; i++) {
3007 pi->sh->phy_noise_window[i] = (s8) (rssi & 0xff);
3010 for (i = 0; i < MA_WINDOW_SZ; i++)
3011 pi->sh->phy_noise_window[i] =
3012 PHY_NOISE_FIXED_VAL_LCNPHY;
3014 pi->sh->phy_noise_index = 0;
3016 for (i = 0; i < PHY_NOISE_WINDOW_SZ; i++) {
3017 for (k = WL_ANT_IDX_1; k < WL_ANT_RX_MAX; k++)
3018 pi->nphy_noise_win[k][i] = PHY_NOISE_FIXED_VAL_NPHY;
3020 pi->nphy_noise_index = 0;
3024 wlc_phy_papd_decode_epsilon(u32 epsilon, int32 *eps_real, int32 *eps_imag)
3026 *eps_imag = (epsilon >> 13);
3027 if (*eps_imag > 0xfff)
3028 *eps_imag -= 0x2000;
3030 *eps_real = (epsilon & 0x1fff);
3031 if (*eps_real > 0xfff)
3032 *eps_real -= 0x2000;
3035 static const fixed AtanTbl[] = {
3056 void wlc_phy_cordic(fixed theta, cint32 *val)
3058 fixed angle, valtmp;
3063 val[0].i = CORDIC_AG;
3067 signtheta = (theta < 0) ? -1 : 1;
3069 ((theta + FIXED(180) * signtheta) % FIXED(360)) -
3070 FIXED(180) * signtheta;
3072 if (FLOAT(theta) > 90) {
3073 theta -= FIXED(180);
3075 } else if (FLOAT(theta) < -90) {
3076 theta += FIXED(180);
3080 for (iter = 0; iter < CORDIC_NI; iter++) {
3081 if (theta > angle) {
3082 valtmp = val[0].i - (val[0].q >> iter);
3083 val[0].q = (val[0].i >> iter) + val[0].q;
3085 angle += AtanTbl[iter];
3087 valtmp = val[0].i + (val[0].q >> iter);
3088 val[0].q = -(val[0].i >> iter) + val[0].q;
3090 angle -= AtanTbl[iter];
3094 val[0].i = val[0].i * signx;
3095 val[0].q = val[0].q * signx;
3098 void wlc_phy_cal_perical_mphase_reset(phy_info_t *pi)
3100 wlapi_del_timer(pi->sh->physhim, pi->phycal_timer);
3102 pi->cal_type_override = PHY_PERICAL_AUTO;
3103 pi->mphase_cal_phase_id = MPHASE_CAL_STATE_IDLE;
3104 pi->mphase_txcal_cmdidx = 0;
3107 static void wlc_phy_cal_perical_mphase_schedule(phy_info_t *pi, uint delay)
3110 if ((pi->nphy_perical != PHY_PERICAL_MPHASE) &&
3111 (pi->nphy_perical != PHY_PERICAL_MANUAL))
3114 wlapi_del_timer(pi->sh->physhim, pi->phycal_timer);
3116 pi->mphase_cal_phase_id = MPHASE_CAL_STATE_INIT;
3117 wlapi_add_timer(pi->sh->physhim, pi->phycal_timer, delay, 0);
3120 void wlc_phy_cal_perical(wlc_phy_t *pih, u8 reason)
3122 s16 nphy_currtemp = 0;
3124 bool do_periodic_cal = TRUE;
3125 phy_info_t *pi = (phy_info_t *) pih;
3130 if ((pi->nphy_perical == PHY_PERICAL_DISABLE) ||
3131 (pi->nphy_perical == PHY_PERICAL_MANUAL))
3135 case PHY_PERICAL_DRIVERUP:
3138 case PHY_PERICAL_PHYINIT:
3139 if (pi->nphy_perical == PHY_PERICAL_MPHASE) {
3140 if (PHY_PERICAL_MPHASE_PENDING(pi)) {
3141 wlc_phy_cal_perical_mphase_reset(pi);
3143 wlc_phy_cal_perical_mphase_schedule(pi,
3144 PHY_PERICAL_INIT_DELAY);
3148 case PHY_PERICAL_JOIN_BSS:
3149 case PHY_PERICAL_START_IBSS:
3150 case PHY_PERICAL_UP_BSS:
3151 if ((pi->nphy_perical == PHY_PERICAL_MPHASE) &&
3152 PHY_PERICAL_MPHASE_PENDING(pi)) {
3153 wlc_phy_cal_perical_mphase_reset(pi);
3156 pi->first_cal_after_assoc = TRUE;
3158 pi->cal_type_override = PHY_PERICAL_FULL;
3160 if (pi->phycal_tempdelta) {
3161 pi->nphy_lastcal_temp = wlc_phy_tempsense_nphy(pi);
3163 wlc_phy_cal_perical_nphy_run(pi, PHY_PERICAL_FULL);
3166 case PHY_PERICAL_WATCHDOG:
3167 if (pi->phycal_tempdelta) {
3168 nphy_currtemp = wlc_phy_tempsense_nphy(pi);
3170 (nphy_currtemp > pi->nphy_lastcal_temp) ?
3171 nphy_currtemp - pi->nphy_lastcal_temp :
3172 pi->nphy_lastcal_temp - nphy_currtemp;
3174 if ((delta_temp < (s16) pi->phycal_tempdelta) &&
3175 (pi->nphy_txiqlocal_chanspec ==
3176 pi->radio_chanspec)) {
3177 do_periodic_cal = FALSE;
3179 pi->nphy_lastcal_temp = nphy_currtemp;
3183 if (do_periodic_cal) {
3185 if (pi->nphy_perical == PHY_PERICAL_MPHASE) {
3187 if (!PHY_PERICAL_MPHASE_PENDING(pi))
3188 wlc_phy_cal_perical_mphase_schedule(pi,
3189 PHY_PERICAL_WDOG_DELAY);
3190 } else if (pi->nphy_perical == PHY_PERICAL_SPHASE)
3191 wlc_phy_cal_perical_nphy_run(pi,
3204 void wlc_phy_cal_perical_mphase_restart(phy_info_t *pi)
3206 pi->mphase_cal_phase_id = MPHASE_CAL_STATE_INIT;
3207 pi->mphase_txcal_cmdidx = 0;
3210 u8 wlc_phy_nbits(int32 value)
3215 abs_val = ABS(value);
3216 while ((abs_val >> nbits) > 0)
3222 u32 wlc_phy_sqrt_int(u32 value)
3224 u32 root = 0, shift = 0;
3226 for (shift = 0; shift < 32; shift += 2) {
3227 if (((0x40000000 >> shift) + root) <= value) {
3228 value -= ((0x40000000 >> shift) + root);
3229 root = (root >> 1) | (0x40000000 >> shift);
3241 void wlc_phy_stf_chain_init(wlc_phy_t *pih, u8 txchain, u8 rxchain)
3243 phy_info_t *pi = (phy_info_t *) pih;
3245 pi->sh->hw_phytxchain = txchain;
3246 pi->sh->hw_phyrxchain = rxchain;
3247 pi->sh->phytxchain = txchain;
3248 pi->sh->phyrxchain = rxchain;
3249 pi->pubpi.phy_corenum = (u8) PHY_BITSCNT(pi->sh->phyrxchain);
3252 void wlc_phy_stf_chain_set(wlc_phy_t *pih, u8 txchain, u8 rxchain)
3254 phy_info_t *pi = (phy_info_t *) pih;
3256 pi->sh->phytxchain = txchain;
3259 wlc_phy_rxcore_setstate_nphy(pih, rxchain);
3261 pi->pubpi.phy_corenum = (u8) PHY_BITSCNT(pi->sh->phyrxchain);
3264 void wlc_phy_stf_chain_get(wlc_phy_t *pih, u8 *txchain, u8 *rxchain)
3266 phy_info_t *pi = (phy_info_t *) pih;
3268 *txchain = pi->sh->phytxchain;
3269 *rxchain = pi->sh->phyrxchain;
3272 u8 wlc_phy_stf_chain_active_get(wlc_phy_t *pih)
3276 phy_info_t *pi = (phy_info_t *) pih;
3278 active_bitmap = (pi->phy_txcore_heatedup) ? 0x31 : 0x33;
3280 if (!pi->watchdog_override)
3281 return active_bitmap;
3283 if (NREV_GE(pi->pubpi.phy_rev, 6)) {
3284 wlapi_suspend_mac_and_wait(pi->sh->physhim);
3285 nphy_currtemp = wlc_phy_tempsense_nphy(pi);
3286 wlapi_enable_mac(pi->sh->physhim);
3288 if (!pi->phy_txcore_heatedup) {
3289 if (nphy_currtemp >= pi->phy_txcore_disable_temp) {
3290 active_bitmap &= 0xFD;
3291 pi->phy_txcore_heatedup = TRUE;
3294 if (nphy_currtemp <= pi->phy_txcore_enable_temp) {
3295 active_bitmap |= 0x2;
3296 pi->phy_txcore_heatedup = FALSE;
3301 return active_bitmap;
3304 s8 wlc_phy_stf_ssmode_get(wlc_phy_t *pih, chanspec_t chanspec)
3306 phy_info_t *pi = (phy_info_t *) pih;
3307 u8 siso_mcs_id, cdd_mcs_id;
3310 (CHSPEC_IS40(chanspec)) ? TXP_FIRST_MCS_40_SISO :
3311 TXP_FIRST_MCS_20_SISO;
3313 (CHSPEC_IS40(chanspec)) ? TXP_FIRST_MCS_40_CDD :
3314 TXP_FIRST_MCS_20_CDD;
3316 if (pi->tx_power_target[siso_mcs_id] >
3317 (pi->tx_power_target[cdd_mcs_id] + 12))
3318 return PHY_TXC1_MODE_SISO;
3320 return PHY_TXC1_MODE_CDD;
3323 const u8 *wlc_phy_get_ofdm_rate_lookup(void)
3325 return ofdm_rate_lookup;
3328 void wlc_lcnphy_epa_switch(phy_info_t *pi, bool mode)
3330 if ((CHIPID(pi->sh->chip) == BCM4313_CHIP_ID) &&
3331 (pi->sh->boardflags & BFL_FEM)) {
3334 txant = wlapi_bmac_get_txant(pi->sh->physhim);
3336 mod_phy_reg(pi, 0x44d, (0x1 << 2), (1) << 2);
3338 mod_phy_reg(pi, 0x44c, (0x1 << 2), (1) << 2);
3341 si_corereg(pi->sh->sih, SI_CC_IDX,
3342 OFFSETOF(chipcregs_t, gpiocontrol), ~0x0,
3344 si_corereg(pi->sh->sih, SI_CC_IDX,
3345 OFFSETOF(chipcregs_t, gpioout), 0x40, 0x40);
3346 si_corereg(pi->sh->sih, SI_CC_IDX,
3347 OFFSETOF(chipcregs_t, gpioouten), 0x40,
3350 mod_phy_reg(pi, 0x44c, (0x1 << 2), (0) << 2);
3352 mod_phy_reg(pi, 0x44d, (0x1 << 2), (0) << 2);
3354 si_corereg(pi->sh->sih, SI_CC_IDX,
3355 OFFSETOF(chipcregs_t, gpioout), 0x40, 0x00);
3356 si_corereg(pi->sh->sih, SI_CC_IDX,
3357 OFFSETOF(chipcregs_t, gpioouten), 0x40, 0x0);
3358 si_corereg(pi->sh->sih, SI_CC_IDX,
3359 OFFSETOF(chipcregs_t, gpiocontrol), ~0x0,
3366 wlc_user_txpwr_antport_to_rfport(phy_info_t *pi, uint chan, u32 band,
3371 if (!pi->user_txpwr_at_rfport)
3376 static s8 wlc_phy_env_measure_vbat(phy_info_t *pi)
3379 return wlc_lcnphy_vbatsense(pi, 0);
3384 static s8 wlc_phy_env_measure_temperature(phy_info_t *pi)
3387 return wlc_lcnphy_tempsense_degree(pi, 0);
3392 static void wlc_phy_upd_env_txpwr_rate_limits(phy_info_t *pi, u32 band)
3397 for (i = 0; i < TXP_NUM_RATES; i++)
3398 pi->txpwr_env_limit[i] = WLC_TXPWR_MAX;
3400 vbat = wlc_phy_env_measure_vbat(pi);
3401 temp = wlc_phy_env_measure_temperature(pi);
3405 void wlc_phy_ldpc_override_set(wlc_phy_t *ppi, bool ldpc)
3411 wlc_phy_get_pwrdet_offsets(phy_info_t *pi, s8 *cckoffset, s8 *ofdmoffset)
3417 u32 wlc_phy_qdiv_roundup(u32 dividend, u32 divisor, u8 precision)
3419 u32 quotient, remainder, roundup, rbit;
3423 quotient = dividend / divisor;
3424 remainder = dividend % divisor;
3426 roundup = (divisor >> 1) + rbit;
3428 while (precision--) {
3430 if (remainder >= roundup) {
3432 remainder = ((remainder - roundup) << 1) + rbit;
3438 if (remainder >= roundup)
3444 s8 wlc_phy_upd_rssi_offset(phy_info_t *pi, s8 rssi, chanspec_t chanspec)
3450 bool wlc_phy_txpower_ipa_ison(wlc_phy_t *ppi)
3452 phy_info_t *pi = (phy_info_t *) ppi;
3455 return wlc_phy_n_txpower_ipa_ison(pi);