2 * Copyright (c) 2010 Broadcom Corporation
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
11 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
13 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 #include <linux/kernel.h>
20 #include <linux/string.h>
23 #include <linux/delay.h>
24 #include <linux/module.h>
25 #include <linux/pci.h>
26 #include <bcmendian.h>
33 #include <wlc_phy_int.h>
34 #include <wlc_phyreg_n.h>
35 #include <wlc_phy_radio.h>
36 #include <wlc_phy_lcn.h>
38 u32 phyhal_msg_level = PHYHAL_ERROR;
40 typedef struct _chan_info_basic {
45 static chan_info_basic_t chan_info_all[] = {
105 u16 ltrn_list[PHY_LTRN_LIST_LEN] = {
106 0x18f9, 0x0d01, 0x00e4, 0xdef4, 0x06f1, 0x0ffc,
107 0xfa27, 0x1dff, 0x10f0, 0x0918, 0xf20a, 0xe010,
108 0x1417, 0x1104, 0xf114, 0xf2fa, 0xf7db, 0xe2fc,
109 0xe1fb, 0x13ee, 0xff0d, 0xe91c, 0x171a, 0x0318,
110 0xda00, 0x03e8, 0x17e6, 0xe9e4, 0xfff3, 0x1312,
111 0xe105, 0xe204, 0xf725, 0xf206, 0xf1ec, 0x11fc,
112 0x14e9, 0xe0f0, 0xf2f6, 0x09e8, 0x1010, 0x1d01,
113 0xfad9, 0x0f04, 0x060f, 0xde0c, 0x001c, 0x0dff,
114 0x1807, 0xf61a, 0xe40e, 0x0f16, 0x05f9, 0x18ec,
115 0x0a1b, 0xff1e, 0x2600, 0xffe2, 0x0ae5, 0x1814,
116 0x0507, 0x0fea, 0xe4f2, 0xf6e6
119 const u8 ofdm_rate_lookup[] = {
131 #define PHY_WREG_LIMIT 24
133 static void wlc_set_phy_uninitted(phy_info_t *pi);
134 static u32 wlc_phy_get_radio_ver(phy_info_t *pi);
135 static void wlc_phy_timercb_phycal(void *arg);
137 static bool wlc_phy_noise_calc_phy(phy_info_t *pi, u32 *cmplx_pwr,
140 static void wlc_phy_cal_perical_mphase_schedule(phy_info_t *pi, uint delay);
141 static void wlc_phy_noise_cb(phy_info_t *pi, u8 channel, s8 noise_dbm);
142 static void wlc_phy_noise_sample_request(wlc_phy_t *pih, u8 reason,
145 static void wlc_phy_txpower_reg_limit_calc(phy_info_t *pi,
146 struct txpwr_limits *tp, chanspec_t);
147 static bool wlc_phy_cal_txpower_recalc_sw(phy_info_t *pi);
149 static s8 wlc_user_txpwr_antport_to_rfport(phy_info_t *pi, uint chan,
151 static void wlc_phy_upd_env_txpwr_rate_limits(phy_info_t *pi, u32 band);
152 static s8 wlc_phy_env_measure_vbat(phy_info_t *pi);
153 static s8 wlc_phy_env_measure_temperature(phy_info_t *pi);
155 char *phy_getvar(phy_info_t *pi, const char *name)
157 char *vars = pi->vars;
161 ASSERT(pi->vars != (char *)&pi->vars);
170 for (s = vars; s && *s;) {
171 if ((memcmp(s, name, len) == 0) && (s[len] == '='))
178 return nvram_get(name);
181 int phy_getintvar(phy_info_t *pi, const char *name)
185 val = PHY_GETVAR(pi, name);
189 return simple_strtoul(val, NULL, 0);
192 void wlc_phyreg_enter(wlc_phy_t *pih)
194 phy_info_t *pi = (phy_info_t *) pih;
195 wlapi_bmac_ucode_wake_override_phyreg_set(pi->sh->physhim);
198 void wlc_phyreg_exit(wlc_phy_t *pih)
200 phy_info_t *pi = (phy_info_t *) pih;
201 wlapi_bmac_ucode_wake_override_phyreg_clear(pi->sh->physhim);
204 void wlc_radioreg_enter(wlc_phy_t *pih)
206 phy_info_t *pi = (phy_info_t *) pih;
207 wlapi_bmac_mctrl(pi->sh->physhim, MCTL_LOCK_RADIO, MCTL_LOCK_RADIO);
212 void wlc_radioreg_exit(wlc_phy_t *pih)
214 phy_info_t *pi = (phy_info_t *) pih;
217 dummy = R_REG(pi->sh->osh, &pi->regs->phyversion);
219 wlapi_bmac_mctrl(pi->sh->physhim, MCTL_LOCK_RADIO, 0);
222 u16 read_radio_reg(phy_info_t *pi, u16 addr)
226 if ((addr == RADIO_IDCODE))
229 if (NORADIO_ENAB(pi->pubpi))
230 return NORADIO_IDCODE & 0xffff;
232 switch (pi->pubpi.phy_type) {
234 CASECHECK(PHYTYPE, PHY_TYPE_N);
235 if (NREV_GE(pi->pubpi.phy_rev, 7))
236 addr |= RADIO_2057_READ_OFF;
238 addr |= RADIO_2055_READ_OFF;
242 CASECHECK(PHYTYPE, PHY_TYPE_LCN);
243 addr |= RADIO_2064_READ_OFF;
247 ASSERT(VALID_PHYTYPE(pi->pubpi.phy_type));
250 if ((D11REV_GE(pi->sh->corerev, 24)) ||
251 (D11REV_IS(pi->sh->corerev, 22)
252 && (pi->pubpi.phy_type != PHY_TYPE_SSN))) {
253 W_REG(pi->sh->osh, &pi->regs->radioregaddr, addr);
255 (void)R_REG(pi->sh->osh, &pi->regs->radioregaddr);
257 data = R_REG(pi->sh->osh, &pi->regs->radioregdata);
259 W_REG(pi->sh->osh, &pi->regs->phy4waddr, addr);
261 (void)R_REG(pi->sh->osh, &pi->regs->phy4waddr);
264 #ifdef __ARM_ARCH_4T__
265 __asm__(" .align 4 ");
267 data = R_REG(pi->sh->osh, &pi->regs->phy4wdatalo);
269 data = R_REG(pi->sh->osh, &pi->regs->phy4wdatalo);
278 void write_radio_reg(phy_info_t *pi, u16 addr, u16 val)
280 struct osl_info *osh;
282 if (NORADIO_ENAB(pi->pubpi))
287 if ((D11REV_GE(pi->sh->corerev, 24)) ||
288 (D11REV_IS(pi->sh->corerev, 22)
289 && (pi->pubpi.phy_type != PHY_TYPE_SSN))) {
291 W_REG(osh, &pi->regs->radioregaddr, addr);
293 (void)R_REG(osh, &pi->regs->radioregaddr);
295 W_REG(osh, &pi->regs->radioregdata, val);
297 W_REG(osh, &pi->regs->phy4waddr, addr);
299 (void)R_REG(osh, &pi->regs->phy4waddr);
301 W_REG(osh, &pi->regs->phy4wdatalo, val);
304 if (pi->sh->bustype == PCI_BUS) {
305 if (++pi->phy_wreg >= pi->phy_wreg_limit) {
306 (void)R_REG(osh, &pi->regs->maccontrol);
312 static u32 read_radio_id(phy_info_t *pi)
316 if (NORADIO_ENAB(pi->pubpi))
317 return NORADIO_IDCODE;
319 if (D11REV_GE(pi->sh->corerev, 24)) {
322 W_REG(pi->sh->osh, &pi->regs->radioregaddr, 0);
324 (void)R_REG(pi->sh->osh, &pi->regs->radioregaddr);
326 b0 = (u32) R_REG(pi->sh->osh, &pi->regs->radioregdata);
327 W_REG(pi->sh->osh, &pi->regs->radioregaddr, 1);
329 (void)R_REG(pi->sh->osh, &pi->regs->radioregaddr);
331 b1 = (u32) R_REG(pi->sh->osh, &pi->regs->radioregdata);
332 W_REG(pi->sh->osh, &pi->regs->radioregaddr, 2);
334 (void)R_REG(pi->sh->osh, &pi->regs->radioregaddr);
336 b2 = (u32) R_REG(pi->sh->osh, &pi->regs->radioregdata);
338 id = ((b0 & 0xf) << 28) | (((b2 << 8) | b1) << 12) | ((b0 >> 4)
341 W_REG(pi->sh->osh, &pi->regs->phy4waddr, RADIO_IDCODE);
343 (void)R_REG(pi->sh->osh, &pi->regs->phy4waddr);
345 id = (u32) R_REG(pi->sh->osh, &pi->regs->phy4wdatalo);
346 id |= (u32) R_REG(pi->sh->osh, &pi->regs->phy4wdatahi) << 16;
352 void and_radio_reg(phy_info_t *pi, u16 addr, u16 val)
356 if (NORADIO_ENAB(pi->pubpi))
359 rval = read_radio_reg(pi, addr);
360 write_radio_reg(pi, addr, (rval & val));
363 void or_radio_reg(phy_info_t *pi, u16 addr, u16 val)
367 if (NORADIO_ENAB(pi->pubpi))
370 rval = read_radio_reg(pi, addr);
371 write_radio_reg(pi, addr, (rval | val));
374 void xor_radio_reg(phy_info_t *pi, u16 addr, u16 mask)
378 if (NORADIO_ENAB(pi->pubpi))
381 rval = read_radio_reg(pi, addr);
382 write_radio_reg(pi, addr, (rval ^ mask));
385 void mod_radio_reg(phy_info_t *pi, u16 addr, u16 mask, u16 val)
389 if (NORADIO_ENAB(pi->pubpi))
392 rval = read_radio_reg(pi, addr);
393 write_radio_reg(pi, addr, (rval & ~mask) | (val & mask));
396 void write_phy_channel_reg(phy_info_t *pi, uint val)
398 W_REG(pi->sh->osh, &pi->regs->phychannel, val);
402 static bool wlc_phy_war41476(phy_info_t *pi)
404 u32 mc = R_REG(pi->sh->osh, &pi->regs->maccontrol);
406 return ((mc & MCTL_EN_MAC) == 0)
407 || ((mc & MCTL_PHYLOCK) == MCTL_PHYLOCK);
411 u16 read_phy_reg(phy_info_t *pi, u16 addr)
413 struct osl_info *osh;
419 W_REG(osh, ®s->phyregaddr, addr);
421 (void)R_REG(osh, ®s->phyregaddr);
425 (D11REV_IS(pi->sh->corerev, 11)
426 || D11REV_IS(pi->sh->corerev, 12)) || wlc_phy_war41476(pi));
429 return R_REG(osh, ®s->phyregdata);
432 void write_phy_reg(phy_info_t *pi, u16 addr, u16 val)
434 struct osl_info *osh;
441 W_REG(osh, ®s->phyregaddr, addr);
442 (void)R_REG(osh, ®s->phyregaddr);
443 W_REG(osh, ®s->phyregdata, val);
445 (void)R_REG(osh, ®s->phyregdata);
447 W_REG(osh, (volatile u32 *)(®s->phyregaddr),
449 if (pi->sh->bustype == PCI_BUS) {
450 if (++pi->phy_wreg >= pi->phy_wreg_limit) {
452 (void)R_REG(osh, ®s->phyversion);
458 void and_phy_reg(phy_info_t *pi, u16 addr, u16 val)
460 struct osl_info *osh;
466 W_REG(osh, ®s->phyregaddr, addr);
468 (void)R_REG(osh, ®s->phyregaddr);
472 (D11REV_IS(pi->sh->corerev, 11)
473 || D11REV_IS(pi->sh->corerev, 12)) || wlc_phy_war41476(pi));
475 W_REG(osh, ®s->phyregdata, (R_REG(osh, ®s->phyregdata) & val));
479 void or_phy_reg(phy_info_t *pi, u16 addr, u16 val)
481 struct osl_info *osh;
487 W_REG(osh, ®s->phyregaddr, addr);
489 (void)R_REG(osh, ®s->phyregaddr);
493 (D11REV_IS(pi->sh->corerev, 11)
494 || D11REV_IS(pi->sh->corerev, 12)) || wlc_phy_war41476(pi));
496 W_REG(osh, ®s->phyregdata, (R_REG(osh, ®s->phyregdata) | val));
500 void mod_phy_reg(phy_info_t *pi, u16 addr, u16 mask, u16 val)
502 struct osl_info *osh;
508 W_REG(osh, ®s->phyregaddr, addr);
510 (void)R_REG(osh, ®s->phyregaddr);
514 (D11REV_IS(pi->sh->corerev, 11)
515 || D11REV_IS(pi->sh->corerev, 12)) || wlc_phy_war41476(pi));
517 W_REG(osh, ®s->phyregdata,
518 ((R_REG(osh, ®s->phyregdata) & ~mask) | (val & mask)));
522 static void WLBANDINITFN(wlc_set_phy_uninitted) (phy_info_t *pi)
526 pi->initialized = false;
529 pi->nrssi_table_delta = 0x7fffffff;
531 pi->mintxbias = 0xffff;
534 pi->phy_spuravoid = SPURAVOID_DISABLE;
536 if (NREV_GE(pi->pubpi.phy_rev, 3)
537 && NREV_LT(pi->pubpi.phy_rev, 7))
538 pi->phy_spuravoid = SPURAVOID_AUTO;
540 pi->nphy_papd_skip = 0;
541 pi->nphy_papd_epsilon_offset[0] = 0xf588;
542 pi->nphy_papd_epsilon_offset[1] = 0xf588;
543 pi->nphy_txpwr_idx[0] = 128;
544 pi->nphy_txpwr_idx[1] = 128;
545 pi->nphy_txpwrindex[0].index_internal = 40;
546 pi->nphy_txpwrindex[1].index_internal = 40;
549 pi->phy_spuravoid = SPURAVOID_AUTO;
551 pi->radiopwr = 0xffff;
552 for (i = 0; i < STATIC_NUM_RF; i++) {
553 for (j = 0; j < STATIC_NUM_BB; j++) {
554 pi->stats_11b_txpower[i][j] = -1;
559 shared_phy_t *wlc_phy_shared_attach(shared_phy_params_t *shp)
563 sh = kzalloc(sizeof(shared_phy_t), GFP_ATOMIC);
570 sh->physhim = shp->physhim;
571 sh->unit = shp->unit;
572 sh->corerev = shp->corerev;
576 sh->chip = shp->chip;
577 sh->chiprev = shp->chiprev;
578 sh->chippkg = shp->chippkg;
579 sh->sromrev = shp->sromrev;
580 sh->boardtype = shp->boardtype;
581 sh->boardrev = shp->boardrev;
582 sh->boardvendor = shp->boardvendor;
583 sh->boardflags = shp->boardflags;
584 sh->boardflags2 = shp->boardflags2;
585 sh->bustype = shp->bustype;
586 sh->buscorerev = shp->buscorerev;
588 sh->fast_timer = PHY_SW_TIMER_FAST;
589 sh->slow_timer = PHY_SW_TIMER_SLOW;
590 sh->glacial_timer = PHY_SW_TIMER_GLACIAL;
592 sh->rssi_mode = RSSI_ANT_MERGE_MAX;
597 void wlc_phy_shared_detach(shared_phy_t *phy_sh)
599 struct osl_info *osh;
604 if (phy_sh->phy_head) {
605 ASSERT(!phy_sh->phy_head);
611 wlc_phy_t *wlc_phy_attach(shared_phy_t *sh, void *regs, int bandtype, char *vars)
617 struct osl_info *osh;
621 if (D11REV_IS(sh->corerev, 4))
622 sflags = SISF_2G_PHY | SISF_5G_PHY;
624 sflags = si_core_sflags(sh->sih, 0, 0);
626 if (BAND_5G(bandtype)) {
627 if ((sflags & (SISF_5G_PHY | SISF_DB_PHY)) == 0) {
633 if ((sflags & SISF_DB_PHY) && pi) {
635 wlapi_bmac_corereset(pi->sh->physhim, pi->pubpi.coreflags);
637 return &pi->pubpi_ro;
640 pi = kzalloc(sizeof(phy_info_t), GFP_ATOMIC);
644 pi->regs = (d11regs_t *) regs;
646 pi->phy_init_por = true;
647 pi->phy_wreg_limit = PHY_WREG_LIMIT;
651 pi->txpwr_percent = 100;
653 pi->do_initcal = true;
655 pi->phycal_tempdelta = 0;
657 if (BAND_2G(bandtype) && (sflags & SISF_2G_PHY)) {
659 pi->pubpi.coreflags = SICF_GMODE;
662 wlapi_bmac_corereset(pi->sh->physhim, pi->pubpi.coreflags);
663 phyversion = R_REG(osh, &pi->regs->phyversion);
665 pi->pubpi.phy_type = PHY_TYPE(phyversion);
666 pi->pubpi.phy_rev = phyversion & PV_PV_MASK;
668 if (pi->pubpi.phy_type == PHY_TYPE_LCNXN) {
669 pi->pubpi.phy_type = PHY_TYPE_N;
670 pi->pubpi.phy_rev += LCNXN_BASEREV;
672 pi->pubpi.phy_corenum = PHY_CORE_NUM_2;
673 pi->pubpi.ana_rev = (phyversion & PV_AV_MASK) >> PV_AV_SHIFT;
675 if (!VALID_PHYTYPE(pi->pubpi.phy_type)) {
678 if (BAND_5G(bandtype)) {
683 if (!ISNPHY(pi) && !ISLCNPHY(pi)) {
688 if (ISSIM_ENAB(pi->sh->sih)) {
689 pi->pubpi.radioid = NORADIO_ID;
690 pi->pubpi.radiorev = 5;
694 wlc_phy_anacore((wlc_phy_t *) pi, ON);
696 idcode = wlc_phy_get_radio_ver(pi);
698 (idcode & IDCODE_ID_MASK) >> IDCODE_ID_SHIFT;
700 (idcode & IDCODE_REV_MASK) >> IDCODE_REV_SHIFT;
702 (idcode & IDCODE_VER_MASK) >> IDCODE_VER_SHIFT;
703 if (!VALID_RADIO(pi, pi->pubpi.radioid)) {
707 wlc_phy_switch_radio((wlc_phy_t *) pi, OFF);
710 wlc_set_phy_uninitted(pi);
712 pi->bw = WL_CHANSPEC_BW_20;
714 BAND_2G(bandtype) ? CH20MHZ_CHSPEC(1) : CH20MHZ_CHSPEC(36);
716 pi->rxiq_samps = PHY_NOISE_SAMPLE_LOG_NUM_NPHY;
717 pi->rxiq_antsel = ANT_RX_DIV_DEF;
719 pi->watchdog_override = true;
721 pi->cal_type_override = PHY_PERICAL_AUTO;
723 pi->nphy_saved_noisevars.bufcount = 0;
726 pi->min_txpower = PHY_TXPWR_MIN_NPHY;
728 pi->min_txpower = PHY_TXPWR_MIN;
730 pi->sh->phyrxchain = 0x3;
732 pi->rx2tx_biasentry = -1;
734 pi->phy_txcore_disable_temp = PHY_CHAIN_TX_DISABLE_TEMP;
735 pi->phy_txcore_enable_temp =
736 PHY_CHAIN_TX_DISABLE_TEMP - PHY_HYSTERESIS_DELTATEMP;
737 pi->phy_tempsense_offset = 0;
738 pi->phy_txcore_heatedup = false;
740 pi->nphy_lastcal_temp = -50;
742 pi->phynoise_polling = true;
743 if (ISNPHY(pi) || ISLCNPHY(pi))
744 pi->phynoise_polling = false;
746 for (i = 0; i < TXP_NUM_RATES; i++) {
747 pi->txpwr_limit[i] = WLC_TXPWR_MAX;
748 pi->txpwr_env_limit[i] = WLC_TXPWR_MAX;
749 pi->tx_user_target[i] = WLC_TXPWR_MAX;
752 pi->radiopwr_override = RADIOPWR_OVERRIDE_DEF;
754 pi->user_txpwr_at_rfport = false;
758 pi->phycal_timer = wlapi_init_timer(pi->sh->physhim,
759 wlc_phy_timercb_phycal,
761 if (!pi->phycal_timer) {
765 if (!wlc_phy_attach_nphy(pi))
768 } else if (ISLCNPHY(pi)) {
769 if (!wlc_phy_attach_lcnphy(pi))
777 pi->next = pi->sh->phy_head;
780 pi->vars = (char *)&pi->vars;
782 bcopy(&pi->pubpi, &pi->pubpi_ro, sizeof(wlc_phy_t));
784 return &pi->pubpi_ro;
792 void wlc_phy_detach(wlc_phy_t *pih)
794 phy_info_t *pi = (phy_info_t *) pih;
801 if (pi->phycal_timer) {
802 wlapi_free_timer(pi->sh->physhim, pi->phycal_timer);
803 pi->phycal_timer = NULL;
806 if (pi->sh->phy_head == pi)
807 pi->sh->phy_head = pi->next;
808 else if (pi->sh->phy_head->next == pi)
809 pi->sh->phy_head->next = NULL;
813 if (pi->pi_fptr.detach)
814 (pi->pi_fptr.detach) (pi);
821 wlc_phy_get_phyversion(wlc_phy_t *pih, u16 *phytype, u16 *phyrev,
822 u16 *radioid, u16 *radiover)
824 phy_info_t *pi = (phy_info_t *) pih;
825 *phytype = (u16) pi->pubpi.phy_type;
826 *phyrev = (u16) pi->pubpi.phy_rev;
827 *radioid = pi->pubpi.radioid;
828 *radiover = pi->pubpi.radiorev;
833 bool wlc_phy_get_encore(wlc_phy_t *pih)
835 phy_info_t *pi = (phy_info_t *) pih;
836 return pi->pubpi.abgphy_encore;
839 u32 wlc_phy_get_coreflags(wlc_phy_t *pih)
841 phy_info_t *pi = (phy_info_t *) pih;
842 return pi->pubpi.coreflags;
845 static void wlc_phy_timercb_phycal(void *arg)
847 phy_info_t *pi = (phy_info_t *) arg;
850 if (PHY_PERICAL_MPHASE_PENDING(pi)) {
852 wlc_phy_cal_perical_mphase_reset(pi);
856 if (SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi)) {
859 wlc_phy_cal_perical_mphase_restart(pi);
861 wlc_phy_cal_perical_nphy_run(pi, PHY_PERICAL_AUTO);
862 wlapi_add_timer(pi->sh->physhim, pi->phycal_timer, delay, 0);
868 void wlc_phy_anacore(wlc_phy_t *pih, bool on)
870 phy_info_t *pi = (phy_info_t *) pih;
874 if (NREV_GE(pi->pubpi.phy_rev, 3)) {
875 write_phy_reg(pi, 0xa6, 0x0d);
876 write_phy_reg(pi, 0x8f, 0x0);
877 write_phy_reg(pi, 0xa7, 0x0d);
878 write_phy_reg(pi, 0xa5, 0x0);
880 write_phy_reg(pi, 0xa5, 0x0);
883 if (NREV_GE(pi->pubpi.phy_rev, 3)) {
884 write_phy_reg(pi, 0x8f, 0x07ff);
885 write_phy_reg(pi, 0xa6, 0x0fd);
886 write_phy_reg(pi, 0xa5, 0x07ff);
887 write_phy_reg(pi, 0xa7, 0x0fd);
889 write_phy_reg(pi, 0xa5, 0x7fff);
892 } else if (ISLCNPHY(pi)) {
894 and_phy_reg(pi, 0x43b,
895 ~((0x1 << 0) | (0x1 << 1) | (0x1 << 2)));
897 or_phy_reg(pi, 0x43c,
898 (0x1 << 0) | (0x1 << 1) | (0x1 << 2));
899 or_phy_reg(pi, 0x43b,
900 (0x1 << 0) | (0x1 << 1) | (0x1 << 2));
905 u32 wlc_phy_clk_bwbits(wlc_phy_t *pih)
907 phy_info_t *pi = (phy_info_t *) pih;
909 u32 phy_bw_clkbits = 0;
911 if (pi && (ISNPHY(pi) || ISLCNPHY(pi))) {
913 case WL_CHANSPEC_BW_10:
914 phy_bw_clkbits = SICF_BW10;
916 case WL_CHANSPEC_BW_20:
917 phy_bw_clkbits = SICF_BW20;
919 case WL_CHANSPEC_BW_40:
920 phy_bw_clkbits = SICF_BW40;
928 return phy_bw_clkbits;
931 void WLBANDINITFN(wlc_phy_por_inform) (wlc_phy_t *ppi)
933 phy_info_t *pi = (phy_info_t *) ppi;
935 pi->phy_init_por = true;
938 void wlc_phy_edcrs_lock(wlc_phy_t *pih, bool lock)
940 phy_info_t *pi = (phy_info_t *) pih;
942 pi->edcrs_threshold_lock = lock;
944 write_phy_reg(pi, 0x22c, 0x46b);
945 write_phy_reg(pi, 0x22d, 0x46b);
946 write_phy_reg(pi, 0x22e, 0x3c0);
947 write_phy_reg(pi, 0x22f, 0x3c0);
950 void wlc_phy_initcal_enable(wlc_phy_t *pih, bool initcal)
952 phy_info_t *pi = (phy_info_t *) pih;
954 pi->do_initcal = initcal;
957 void wlc_phy_hw_clk_state_upd(wlc_phy_t *pih, bool newstate)
959 phy_info_t *pi = (phy_info_t *) pih;
964 pi->sh->clk = newstate;
967 void wlc_phy_hw_state_upd(wlc_phy_t *pih, bool newstate)
969 phy_info_t *pi = (phy_info_t *) pih;
974 pi->sh->up = newstate;
977 void WLBANDINITFN(wlc_phy_init) (wlc_phy_t *pih, chanspec_t chanspec)
980 initfn_t phy_init = NULL;
981 phy_info_t *pi = (phy_info_t *) pih;
983 if (pi->init_in_progress)
986 pi->init_in_progress = true;
988 pi->radio_chanspec = chanspec;
990 mc = R_REG(pi->sh->osh, &pi->regs->maccontrol);
991 if ((mc & MCTL_EN_MAC) != 0) {
992 ASSERT((const char *)
993 "wlc_phy_init: Called with the MAC running!" == NULL);
998 if (!(pi->measure_hold & PHY_HOLD_FOR_SCAN)) {
999 pi->measure_hold |= PHY_HOLD_FOR_NOT_ASSOC;
1002 if (D11REV_GE(pi->sh->corerev, 5))
1003 ASSERT(si_core_sflags(pi->sh->sih, 0, 0) & SISF_FCLKA);
1005 phy_init = pi->pi_fptr.init;
1007 if (phy_init == NULL) {
1008 ASSERT(phy_init != NULL);
1012 wlc_phy_anacore(pih, ON);
1014 if (CHSPEC_BW(pi->radio_chanspec) != pi->bw)
1015 wlapi_bmac_bw_set(pi->sh->physhim,
1016 CHSPEC_BW(pi->radio_chanspec));
1018 pi->nphy_gain_boost = true;
1020 wlc_phy_switch_radio((wlc_phy_t *) pi, ON);
1024 pi->phy_init_por = false;
1026 if (D11REV_IS(pi->sh->corerev, 11) || D11REV_IS(pi->sh->corerev, 12))
1027 wlc_phy_do_dummy_tx(pi, true, OFF);
1030 wlc_phy_txpower_update_shm(pi);
1032 wlc_phy_ant_rxdiv_set((wlc_phy_t *) pi, pi->sh->rx_antdiv);
1034 pi->init_in_progress = false;
1037 void wlc_phy_cal_init(wlc_phy_t *pih)
1039 phy_info_t *pi = (phy_info_t *) pih;
1040 initfn_t cal_init = NULL;
1042 ASSERT((R_REG(pi->sh->osh, &pi->regs->maccontrol) & MCTL_EN_MAC) == 0);
1044 if (!pi->initialized) {
1045 cal_init = pi->pi_fptr.calinit;
1049 pi->initialized = true;
1053 int wlc_phy_down(wlc_phy_t *pih)
1055 phy_info_t *pi = (phy_info_t *) pih;
1058 ASSERT(pi->phytest_on == false);
1060 if (pi->phycal_timer
1061 && !wlapi_del_timer(pi->sh->physhim, pi->phycal_timer))
1064 pi->nphy_iqcal_chanspec_2G = 0;
1065 pi->nphy_iqcal_chanspec_5G = 0;
1070 static u32 wlc_phy_get_radio_ver(phy_info_t *pi)
1074 ver = read_radio_id(pi);
1080 wlc_phy_table_addr(phy_info_t *pi, uint tbl_id, uint tbl_offset,
1081 u16 tblAddr, u16 tblDataHi, u16 tblDataLo)
1083 write_phy_reg(pi, tblAddr, (tbl_id << 10) | tbl_offset);
1085 pi->tbl_data_hi = tblDataHi;
1086 pi->tbl_data_lo = tblDataLo;
1088 if ((pi->sh->chip == BCM43224_CHIP_ID ||
1089 pi->sh->chip == BCM43421_CHIP_ID) &&
1090 (pi->sh->chiprev == 1)) {
1091 pi->tbl_addr = tblAddr;
1092 pi->tbl_save_id = tbl_id;
1093 pi->tbl_save_offset = tbl_offset;
1097 void wlc_phy_table_data_write(phy_info_t *pi, uint width, u32 val)
1099 ASSERT((width == 8) || (width == 16) || (width == 32));
1101 if ((pi->sh->chip == BCM43224_CHIP_ID ||
1102 pi->sh->chip == BCM43421_CHIP_ID) &&
1103 (pi->sh->chiprev == 1) &&
1104 (pi->tbl_save_id == NPHY_TBL_ID_ANTSWCTRLLUT)) {
1105 read_phy_reg(pi, pi->tbl_data_lo);
1107 write_phy_reg(pi, pi->tbl_addr,
1108 (pi->tbl_save_id << 10) | pi->tbl_save_offset);
1109 pi->tbl_save_offset++;
1114 write_phy_reg(pi, pi->tbl_data_hi, (u16) (val >> 16));
1115 write_phy_reg(pi, pi->tbl_data_lo, (u16) val);
1118 write_phy_reg(pi, pi->tbl_data_lo, (u16) val);
1123 wlc_phy_write_table(phy_info_t *pi, const phytbl_info_t *ptbl_info,
1124 u16 tblAddr, u16 tblDataHi, u16 tblDataLo)
1127 uint tbl_id = ptbl_info->tbl_id;
1128 uint tbl_offset = ptbl_info->tbl_offset;
1129 uint tbl_width = ptbl_info->tbl_width;
1130 const u8 *ptbl_8b = (const u8 *)ptbl_info->tbl_ptr;
1131 const u16 *ptbl_16b = (const u16 *)ptbl_info->tbl_ptr;
1132 const u32 *ptbl_32b = (const u32 *)ptbl_info->tbl_ptr;
1134 ASSERT((tbl_width == 8) || (tbl_width == 16) || (tbl_width == 32));
1136 write_phy_reg(pi, tblAddr, (tbl_id << 10) | tbl_offset);
1138 for (idx = 0; idx < ptbl_info->tbl_len; idx++) {
1140 if ((pi->sh->chip == BCM43224_CHIP_ID ||
1141 pi->sh->chip == BCM43421_CHIP_ID) &&
1142 (pi->sh->chiprev == 1) &&
1143 (tbl_id == NPHY_TBL_ID_ANTSWCTRLLUT)) {
1144 read_phy_reg(pi, tblDataLo);
1146 write_phy_reg(pi, tblAddr,
1147 (tbl_id << 10) | (tbl_offset + idx));
1150 if (tbl_width == 32) {
1152 write_phy_reg(pi, tblDataHi,
1153 (u16) (ptbl_32b[idx] >> 16));
1154 write_phy_reg(pi, tblDataLo, (u16) ptbl_32b[idx]);
1155 } else if (tbl_width == 16) {
1157 write_phy_reg(pi, tblDataLo, ptbl_16b[idx]);
1160 write_phy_reg(pi, tblDataLo, ptbl_8b[idx]);
1166 wlc_phy_read_table(phy_info_t *pi, const phytbl_info_t *ptbl_info,
1167 u16 tblAddr, u16 tblDataHi, u16 tblDataLo)
1170 uint tbl_id = ptbl_info->tbl_id;
1171 uint tbl_offset = ptbl_info->tbl_offset;
1172 uint tbl_width = ptbl_info->tbl_width;
1173 u8 *ptbl_8b = (u8 *)ptbl_info->tbl_ptr;
1174 u16 *ptbl_16b = (u16 *)ptbl_info->tbl_ptr;
1175 u32 *ptbl_32b = (u32 *)ptbl_info->tbl_ptr;
1177 ASSERT((tbl_width == 8) || (tbl_width == 16) || (tbl_width == 32));
1179 write_phy_reg(pi, tblAddr, (tbl_id << 10) | tbl_offset);
1181 for (idx = 0; idx < ptbl_info->tbl_len; idx++) {
1183 if ((pi->sh->chip == BCM43224_CHIP_ID ||
1184 pi->sh->chip == BCM43421_CHIP_ID) &&
1185 (pi->sh->chiprev == 1)) {
1186 (void)read_phy_reg(pi, tblDataLo);
1188 write_phy_reg(pi, tblAddr,
1189 (tbl_id << 10) | (tbl_offset + idx));
1192 if (tbl_width == 32) {
1194 ptbl_32b[idx] = read_phy_reg(pi, tblDataLo);
1195 ptbl_32b[idx] |= (read_phy_reg(pi, tblDataHi) << 16);
1196 } else if (tbl_width == 16) {
1198 ptbl_16b[idx] = read_phy_reg(pi, tblDataLo);
1201 ptbl_8b[idx] = (u8) read_phy_reg(pi, tblDataLo);
1207 wlc_phy_init_radio_regs_allbands(phy_info_t *pi, radio_20xx_regs_t *radioregs)
1212 if (radioregs[i].do_init) {
1213 write_radio_reg(pi, radioregs[i].address,
1214 (u16) radioregs[i].init);
1218 } while (radioregs[i].address != 0xffff);
1224 wlc_phy_init_radio_regs(phy_info_t *pi, radio_regs_t *radioregs,
1231 if (CHSPEC_IS5G(pi->radio_chanspec)) {
1232 if (radioregs[i].do_init_a) {
1235 address | core_offset,
1236 (u16) radioregs[i].init_a);
1237 if (ISNPHY(pi) && (++count % 4 == 0))
1238 WLC_PHY_WAR_PR51571(pi);
1241 if (radioregs[i].do_init_g) {
1244 address | core_offset,
1245 (u16) radioregs[i].init_g);
1246 if (ISNPHY(pi) && (++count % 4 == 0))
1247 WLC_PHY_WAR_PR51571(pi);
1252 } while (radioregs[i].address != 0xffff);
1257 void wlc_phy_do_dummy_tx(phy_info_t *pi, bool ofdm, bool pa_on)
1259 #define DUMMY_PKT_LEN 20
1260 d11regs_t *regs = pi->regs;
1262 u8 ofdmpkt[DUMMY_PKT_LEN] = {
1263 0xcc, 0x01, 0x02, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00,
1264 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00
1266 u8 cckpkt[DUMMY_PKT_LEN] = {
1267 0x6e, 0x84, 0x0b, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00,
1268 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00
1272 ASSERT((R_REG(pi->sh->osh, &pi->regs->maccontrol) & MCTL_EN_MAC) == 0);
1274 dummypkt = (u32 *) (ofdm ? ofdmpkt : cckpkt);
1275 wlapi_bmac_write_template_ram(pi->sh->physhim, 0, DUMMY_PKT_LEN,
1278 W_REG(pi->sh->osh, ®s->xmtsel, 0);
1280 if (D11REV_GE(pi->sh->corerev, 11))
1281 W_REG(pi->sh->osh, ®s->wepctl, 0x100);
1283 W_REG(pi->sh->osh, ®s->wepctl, 0);
1285 W_REG(pi->sh->osh, ®s->txe_phyctl, (ofdm ? 1 : 0) | PHY_TXC_ANT_0);
1286 if (ISNPHY(pi) || ISLCNPHY(pi)) {
1288 W_REG(pi->sh->osh, ®s->txe_phyctl1, 0x1A02);
1291 W_REG(pi->sh->osh, ®s->txe_wm_0, 0);
1292 W_REG(pi->sh->osh, ®s->txe_wm_1, 0);
1294 W_REG(pi->sh->osh, ®s->xmttplatetxptr, 0);
1295 W_REG(pi->sh->osh, ®s->xmttxcnt, DUMMY_PKT_LEN);
1297 W_REG(pi->sh->osh, ®s->xmtsel, ((8 << 8) | (1 << 5) | (1 << 2) | 2));
1299 W_REG(pi->sh->osh, ®s->txe_ctl, 0);
1303 wlc_phy_pa_override_nphy(pi, OFF);
1306 if (ISNPHY(pi) || ISLCNPHY(pi))
1307 W_REG(pi->sh->osh, ®s->txe_aux, 0xD0);
1309 W_REG(pi->sh->osh, ®s->txe_aux, ((1 << 5) | (1 << 4)));
1311 (void)R_REG(pi->sh->osh, ®s->txe_aux);
1314 count = ofdm ? 30 : 250;
1316 if (ISSIM_ENAB(pi->sh->sih)) {
1320 while ((i++ < count)
1321 && (R_REG(pi->sh->osh, ®s->txe_status) & (1 << 7))) {
1328 && ((R_REG(pi->sh->osh, ®s->txe_status) & (1 << 10)) == 0)) {
1334 while ((i++ < 10) && ((R_REG(pi->sh->osh, ®s->ifsstat) & (1 << 8)))) {
1339 wlc_phy_pa_override_nphy(pi, ON);
1343 void wlc_phy_hold_upd(wlc_phy_t *pih, mbool id, bool set)
1345 phy_info_t *pi = (phy_info_t *) pih;
1349 mboolset(pi->measure_hold, id);
1351 mboolclr(pi->measure_hold, id);
1357 void wlc_phy_mute_upd(wlc_phy_t *pih, bool mute, mbool flags)
1359 phy_info_t *pi = (phy_info_t *) pih;
1362 mboolset(pi->measure_hold, PHY_HOLD_FOR_MUTE);
1364 mboolclr(pi->measure_hold, PHY_HOLD_FOR_MUTE);
1367 if (!mute && (flags & PHY_MUTE_FOR_PREISM))
1368 pi->nphy_perical_last = pi->sh->now - pi->sh->glacial_timer;
1372 void wlc_phy_clear_tssi(wlc_phy_t *pih)
1374 phy_info_t *pi = (phy_info_t *) pih;
1379 wlapi_bmac_write_shm(pi->sh->physhim, M_B_TSSI_0, NULL_TSSI_W);
1380 wlapi_bmac_write_shm(pi->sh->physhim, M_B_TSSI_1, NULL_TSSI_W);
1381 wlapi_bmac_write_shm(pi->sh->physhim, M_G_TSSI_0, NULL_TSSI_W);
1382 wlapi_bmac_write_shm(pi->sh->physhim, M_G_TSSI_1, NULL_TSSI_W);
1386 static bool wlc_phy_cal_txpower_recalc_sw(phy_info_t *pi)
1391 void wlc_phy_switch_radio(wlc_phy_t *pih, bool on)
1393 phy_info_t *pi = (phy_info_t *) pih;
1395 if (NORADIO_ENAB(pi->pubpi))
1401 mc = R_REG(pi->sh->osh, &pi->regs->maccontrol);
1405 wlc_phy_switch_radio_nphy(pi, on);
1407 } else if (ISLCNPHY(pi)) {
1409 and_phy_reg(pi, 0x44c,
1412 (0x1 << 10) | (0x1 << 11) | (0x1 << 12)));
1413 and_phy_reg(pi, 0x4b0, ~((0x1 << 3) | (0x1 << 11)));
1414 and_phy_reg(pi, 0x4f9, ~(0x1 << 3));
1416 and_phy_reg(pi, 0x44d,
1419 (0x1 << 12) | (0x1 << 13) | (0x1 << 14)));
1420 or_phy_reg(pi, 0x44c,
1423 (0x1 << 10) | (0x1 << 11) | (0x1 << 12));
1425 and_phy_reg(pi, 0x4b7, ~((0x7f << 8)));
1426 and_phy_reg(pi, 0x4b1, ~((0x1 << 13)));
1427 or_phy_reg(pi, 0x4b0, (0x1 << 3) | (0x1 << 11));
1428 and_phy_reg(pi, 0x4fa, ~((0x1 << 3)));
1429 or_phy_reg(pi, 0x4f9, (0x1 << 3));
1434 u16 wlc_phy_bw_state_get(wlc_phy_t *ppi)
1436 phy_info_t *pi = (phy_info_t *) ppi;
1441 void wlc_phy_bw_state_set(wlc_phy_t *ppi, u16 bw)
1443 phy_info_t *pi = (phy_info_t *) ppi;
1448 void wlc_phy_chanspec_radio_set(wlc_phy_t *ppi, chanspec_t newch)
1450 phy_info_t *pi = (phy_info_t *) ppi;
1451 pi->radio_chanspec = newch;
1455 chanspec_t wlc_phy_chanspec_get(wlc_phy_t *ppi)
1457 phy_info_t *pi = (phy_info_t *) ppi;
1459 return pi->radio_chanspec;
1462 void wlc_phy_chanspec_set(wlc_phy_t *ppi, chanspec_t chanspec)
1464 phy_info_t *pi = (phy_info_t *) ppi;
1466 chansetfn_t chanspec_set = NULL;
1468 ASSERT(!wf_chspec_malformed(chanspec));
1470 m_cur_channel = CHSPEC_CHANNEL(chanspec);
1471 if (CHSPEC_IS5G(chanspec))
1472 m_cur_channel |= D11_CURCHANNEL_5G;
1473 if (CHSPEC_IS40(chanspec))
1474 m_cur_channel |= D11_CURCHANNEL_40;
1475 wlapi_bmac_write_shm(pi->sh->physhim, M_CURCHANNEL, m_cur_channel);
1477 chanspec_set = pi->pi_fptr.chanset;
1479 (*chanspec_set) (pi, chanspec);
1483 int wlc_phy_chanspec_freq2bandrange_lpssn(uint freq)
1488 range = WL_CHAN_FREQ_RANGE_2G;
1489 else if (freq <= 5320)
1490 range = WL_CHAN_FREQ_RANGE_5GL;
1491 else if (freq <= 5700)
1492 range = WL_CHAN_FREQ_RANGE_5GM;
1494 range = WL_CHAN_FREQ_RANGE_5GH;
1499 int wlc_phy_chanspec_bandrange_get(phy_info_t *pi, chanspec_t chanspec)
1502 uint channel = CHSPEC_CHANNEL(chanspec);
1503 uint freq = wlc_phy_channel2freq(channel);
1506 range = wlc_phy_get_chan_freq_range_nphy(pi, channel);
1507 } else if (ISLCNPHY(pi)) {
1508 range = wlc_phy_chanspec_freq2bandrange_lpssn(freq);
1515 void wlc_phy_chanspec_ch14_widefilter_set(wlc_phy_t *ppi, bool wide_filter)
1517 phy_info_t *pi = (phy_info_t *) ppi;
1519 pi->channel_14_wide_filter = wide_filter;
1523 int wlc_phy_channel2freq(uint channel)
1527 for (i = 0; i < ARRAY_SIZE(chan_info_all); i++)
1528 if (chan_info_all[i].chan == channel)
1529 return chan_info_all[i].freq;
1534 wlc_phy_chanspec_band_validch(wlc_phy_t *ppi, uint band, chanvec_t *channels)
1536 phy_info_t *pi = (phy_info_t *) ppi;
1540 ASSERT((band == WLC_BAND_2G) || (band == WLC_BAND_5G));
1542 memset(channels, 0, sizeof(chanvec_t));
1544 for (i = 0; i < ARRAY_SIZE(chan_info_all); i++) {
1545 channel = chan_info_all[i].chan;
1547 if ((pi->a_band_high_disable) && (channel >= FIRST_REF5_CHANNUM)
1548 && (channel <= LAST_REF5_CHANNUM))
1551 if (((band == WLC_BAND_2G) && (channel <= CH_MAX_2G_CHANNEL)) ||
1552 ((band == WLC_BAND_5G) && (channel > CH_MAX_2G_CHANNEL)))
1553 setbit(channels->vec, channel);
1557 chanspec_t wlc_phy_chanspec_band_firstch(wlc_phy_t *ppi, uint band)
1559 phy_info_t *pi = (phy_info_t *) ppi;
1564 ASSERT((band == WLC_BAND_2G) || (band == WLC_BAND_5G));
1566 for (i = 0; i < ARRAY_SIZE(chan_info_all); i++) {
1567 channel = chan_info_all[i].chan;
1569 if (ISNPHY(pi) && IS40MHZ(pi)) {
1572 for (j = 0; j < ARRAY_SIZE(chan_info_all); j++) {
1573 if (chan_info_all[j].chan ==
1574 channel + CH_10MHZ_APART)
1578 if (j == ARRAY_SIZE(chan_info_all))
1581 channel = UPPER_20_SB(channel);
1583 channel | WL_CHANSPEC_BW_40 |
1584 WL_CHANSPEC_CTL_SB_LOWER;
1585 if (band == WLC_BAND_2G)
1586 chspec |= WL_CHANSPEC_BAND_2G;
1588 chspec |= WL_CHANSPEC_BAND_5G;
1590 chspec = CH20MHZ_CHSPEC(channel);
1592 if ((pi->a_band_high_disable) && (channel >= FIRST_REF5_CHANNUM)
1593 && (channel <= LAST_REF5_CHANNUM))
1596 if (((band == WLC_BAND_2G) && (channel <= CH_MAX_2G_CHANNEL)) ||
1597 ((band == WLC_BAND_5G) && (channel > CH_MAX_2G_CHANNEL)))
1603 return (chanspec_t) INVCHANSPEC;
1606 int wlc_phy_txpower_get(wlc_phy_t *ppi, uint *qdbm, bool *override)
1608 phy_info_t *pi = (phy_info_t *) ppi;
1610 ASSERT(qdbm != NULL);
1611 *qdbm = pi->tx_user_target[0];
1612 if (override != NULL)
1613 *override = pi->txpwroverride;
1617 void wlc_phy_txpower_target_set(wlc_phy_t *ppi, struct txpwr_limits *txpwr)
1619 bool mac_enabled = false;
1620 phy_info_t *pi = (phy_info_t *) ppi;
1622 bcopy(&txpwr->cck[0], &pi->tx_user_target[TXP_FIRST_CCK],
1625 bcopy(&txpwr->ofdm[0], &pi->tx_user_target[TXP_FIRST_OFDM],
1626 WLC_NUM_RATES_OFDM);
1627 bcopy(&txpwr->ofdm_cdd[0], &pi->tx_user_target[TXP_FIRST_OFDM_20_CDD],
1628 WLC_NUM_RATES_OFDM);
1630 bcopy(&txpwr->ofdm_40_siso[0],
1631 &pi->tx_user_target[TXP_FIRST_OFDM_40_SISO], WLC_NUM_RATES_OFDM);
1632 bcopy(&txpwr->ofdm_40_cdd[0],
1633 &pi->tx_user_target[TXP_FIRST_OFDM_40_CDD], WLC_NUM_RATES_OFDM);
1635 bcopy(&txpwr->mcs_20_siso[0],
1636 &pi->tx_user_target[TXP_FIRST_MCS_20_SISO],
1637 WLC_NUM_RATES_MCS_1_STREAM);
1638 bcopy(&txpwr->mcs_20_cdd[0], &pi->tx_user_target[TXP_FIRST_MCS_20_CDD],
1639 WLC_NUM_RATES_MCS_1_STREAM);
1640 bcopy(&txpwr->mcs_20_stbc[0],
1641 &pi->tx_user_target[TXP_FIRST_MCS_20_STBC],
1642 WLC_NUM_RATES_MCS_1_STREAM);
1643 bcopy(&txpwr->mcs_20_mimo[0], &pi->tx_user_target[TXP_FIRST_MCS_20_SDM],
1644 WLC_NUM_RATES_MCS_2_STREAM);
1646 bcopy(&txpwr->mcs_40_siso[0],
1647 &pi->tx_user_target[TXP_FIRST_MCS_40_SISO],
1648 WLC_NUM_RATES_MCS_1_STREAM);
1649 bcopy(&txpwr->mcs_40_cdd[0], &pi->tx_user_target[TXP_FIRST_MCS_40_CDD],
1650 WLC_NUM_RATES_MCS_1_STREAM);
1651 bcopy(&txpwr->mcs_40_stbc[0],
1652 &pi->tx_user_target[TXP_FIRST_MCS_40_STBC],
1653 WLC_NUM_RATES_MCS_1_STREAM);
1654 bcopy(&txpwr->mcs_40_mimo[0], &pi->tx_user_target[TXP_FIRST_MCS_40_SDM],
1655 WLC_NUM_RATES_MCS_2_STREAM);
1657 if (R_REG(pi->sh->osh, &pi->regs->maccontrol) & MCTL_EN_MAC)
1661 wlapi_suspend_mac_and_wait(pi->sh->physhim);
1663 wlc_phy_txpower_recalc_target(pi);
1664 wlc_phy_cal_txpower_recalc_sw(pi);
1667 wlapi_enable_mac(pi->sh->physhim);
1670 int wlc_phy_txpower_set(wlc_phy_t *ppi, uint qdbm, bool override)
1672 phy_info_t *pi = (phy_info_t *) ppi;
1678 for (i = 0; i < TXP_NUM_RATES; i++)
1679 pi->tx_user_target[i] = (u8) qdbm;
1681 pi->txpwroverride = false;
1684 if (!SCAN_INPROG_PHY(pi)) {
1689 (R_REG(pi->sh->osh, &pi->regs->maccontrol) &
1693 wlapi_suspend_mac_and_wait(pi->sh->physhim);
1695 wlc_phy_txpower_recalc_target(pi);
1696 wlc_phy_cal_txpower_recalc_sw(pi);
1699 wlapi_enable_mac(pi->sh->physhim);
1706 wlc_phy_txpower_sromlimit(wlc_phy_t *ppi, uint channel, u8 *min_pwr,
1707 u8 *max_pwr, int txp_rate_idx)
1709 phy_info_t *pi = (phy_info_t *) ppi;
1712 *min_pwr = pi->min_txpower * WLC_TXPWR_DB_FACTOR;
1715 if (txp_rate_idx < 0)
1716 txp_rate_idx = TXP_FIRST_CCK;
1717 wlc_phy_txpower_sromlimit_get_nphy(pi, channel, max_pwr,
1720 } else if ((channel <= CH_MAX_2G_CHANNEL)) {
1721 if (txp_rate_idx < 0)
1722 txp_rate_idx = TXP_FIRST_CCK;
1723 *max_pwr = pi->tx_srom_max_rate_2g[txp_rate_idx];
1726 *max_pwr = WLC_TXPWR_MAX;
1728 if (txp_rate_idx < 0)
1729 txp_rate_idx = TXP_FIRST_OFDM;
1731 for (i = 0; i < ARRAY_SIZE(chan_info_all); i++) {
1732 if (channel == chan_info_all[i].chan) {
1736 ASSERT(i < ARRAY_SIZE(chan_info_all));
1739 *max_pwr = pi->hwtxpwr[i];
1742 if ((i >= FIRST_MID_5G_CHAN) && (i <= LAST_MID_5G_CHAN))
1744 pi->tx_srom_max_rate_5g_mid[txp_rate_idx];
1745 if ((i >= FIRST_HIGH_5G_CHAN)
1746 && (i <= LAST_HIGH_5G_CHAN))
1748 pi->tx_srom_max_rate_5g_hi[txp_rate_idx];
1749 if ((i >= FIRST_LOW_5G_CHAN) && (i <= LAST_LOW_5G_CHAN))
1751 pi->tx_srom_max_rate_5g_low[txp_rate_idx];
1757 wlc_phy_txpower_sromlimit_max_get(wlc_phy_t *ppi, uint chan, u8 *max_txpwr,
1760 phy_info_t *pi = (phy_info_t *) ppi;
1762 u8 tx_pwr_min = 255;
1764 u8 maxtxpwr, mintxpwr, rate, pactrl;
1768 max_num_rate = ISNPHY(pi) ? TXP_NUM_RATES :
1769 ISLCNPHY(pi) ? (TXP_LAST_SISO_MCS_20 + 1) : (TXP_LAST_OFDM + 1);
1771 for (rate = 0; rate < max_num_rate; rate++) {
1773 wlc_phy_txpower_sromlimit(ppi, chan, &mintxpwr, &maxtxpwr,
1776 maxtxpwr = (maxtxpwr > pactrl) ? (maxtxpwr - pactrl) : 0;
1778 maxtxpwr = (maxtxpwr > 6) ? (maxtxpwr - 6) : 0;
1780 tx_pwr_max = max(tx_pwr_max, maxtxpwr);
1781 tx_pwr_min = min(tx_pwr_min, maxtxpwr);
1783 *max_txpwr = tx_pwr_max;
1784 *min_txpwr = tx_pwr_min;
1788 wlc_phy_txpower_boardlimit_band(wlc_phy_t *ppi, uint bandunit, s32 *max_pwr,
1789 s32 *min_pwr, u32 *step_pwr)
1794 u8 wlc_phy_txpower_get_target_min(wlc_phy_t *ppi)
1796 phy_info_t *pi = (phy_info_t *) ppi;
1798 return pi->tx_power_min;
1801 u8 wlc_phy_txpower_get_target_max(wlc_phy_t *ppi)
1803 phy_info_t *pi = (phy_info_t *) ppi;
1805 return pi->tx_power_max;
1808 void wlc_phy_txpower_recalc_target(phy_info_t *pi)
1810 u8 maxtxpwr, mintxpwr, rate, pactrl;
1812 u8 tx_pwr_target[TXP_NUM_RATES];
1814 u8 tx_pwr_min = 255;
1815 u8 tx_pwr_max_rate_ind = 0;
1819 u32 band = CHSPEC2WLC_BAND(pi->radio_chanspec);
1820 initfn_t txpwr_recalc_fn = NULL;
1822 chspec = pi->radio_chanspec;
1823 if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_NONE)
1824 target_chan = CHSPEC_CHANNEL(chspec);
1825 else if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_UPPER)
1826 target_chan = UPPER_20_SB(CHSPEC_CHANNEL(chspec));
1828 target_chan = LOWER_20_SB(CHSPEC_CHANNEL(chspec));
1834 if (CHSPEC_IS40(pi->radio_chanspec)) {
1835 offset_mcs = pi->mcs40_po;
1836 for (i = TXP_FIRST_SISO_MCS_20;
1837 i <= TXP_LAST_SISO_MCS_20; i++) {
1838 pi->tx_srom_max_rate_2g[i - 8] =
1839 pi->tx_srom_max_2g -
1840 ((offset_mcs & 0xf) * 2);
1844 offset_mcs = pi->mcs20_po;
1845 for (i = TXP_FIRST_SISO_MCS_20;
1846 i <= TXP_LAST_SISO_MCS_20; i++) {
1847 pi->tx_srom_max_rate_2g[i - 8] =
1848 pi->tx_srom_max_2g -
1849 ((offset_mcs & 0xf) * 2);
1855 max_num_rate = ((ISNPHY(pi)) ? (TXP_NUM_RATES) :
1857 (TXP_LAST_SISO_MCS_20 + 1) : (TXP_LAST_OFDM + 1)));
1859 max_num_rate = ((ISNPHY(pi)) ? (TXP_NUM_RATES) : (TXP_LAST_OFDM + 1));
1862 wlc_phy_upd_env_txpwr_rate_limits(pi, band);
1864 for (rate = start_rate; rate < max_num_rate; rate++) {
1866 tx_pwr_target[rate] = pi->tx_user_target[rate];
1868 if (pi->user_txpwr_at_rfport) {
1869 tx_pwr_target[rate] +=
1870 wlc_user_txpwr_antport_to_rfport(pi, target_chan,
1876 wlc_phy_txpower_sromlimit((wlc_phy_t *) pi, target_chan,
1877 &mintxpwr, &maxtxpwr, rate);
1879 maxtxpwr = min(maxtxpwr, pi->txpwr_limit[rate]);
1882 (maxtxpwr > pactrl) ? (maxtxpwr - pactrl) : 0;
1884 maxtxpwr = (maxtxpwr > 6) ? (maxtxpwr - 6) : 0;
1886 maxtxpwr = min(maxtxpwr, tx_pwr_target[rate]);
1888 if (pi->txpwr_percent <= 100)
1889 maxtxpwr = (maxtxpwr * pi->txpwr_percent) / 100;
1891 tx_pwr_target[rate] = max(maxtxpwr, mintxpwr);
1894 tx_pwr_target[rate] =
1895 min(tx_pwr_target[rate], pi->txpwr_env_limit[rate]);
1897 if (tx_pwr_target[rate] > tx_pwr_max)
1898 tx_pwr_max_rate_ind = rate;
1900 tx_pwr_max = max(tx_pwr_max, tx_pwr_target[rate]);
1901 tx_pwr_min = min(tx_pwr_min, tx_pwr_target[rate]);
1904 memset(pi->tx_power_offset, 0, sizeof(pi->tx_power_offset));
1905 pi->tx_power_max = tx_pwr_max;
1906 pi->tx_power_min = tx_pwr_min;
1907 pi->tx_power_max_rate_ind = tx_pwr_max_rate_ind;
1908 for (rate = 0; rate < max_num_rate; rate++) {
1910 pi->tx_power_target[rate] = tx_pwr_target[rate];
1912 if (!pi->hwpwrctrl || ISNPHY(pi)) {
1913 pi->tx_power_offset[rate] =
1914 pi->tx_power_max - pi->tx_power_target[rate];
1916 pi->tx_power_offset[rate] =
1917 pi->tx_power_target[rate] - pi->tx_power_min;
1921 txpwr_recalc_fn = pi->pi_fptr.txpwrrecalc;
1922 if (txpwr_recalc_fn)
1923 (*txpwr_recalc_fn) (pi);
1927 wlc_phy_txpower_reg_limit_calc(phy_info_t *pi, struct txpwr_limits *txpwr,
1928 chanspec_t chanspec)
1930 u8 tmp_txpwr_limit[2 * WLC_NUM_RATES_OFDM];
1931 u8 *txpwr_ptr1 = NULL, *txpwr_ptr2 = NULL;
1932 int rate_start_index = 0, rate1, rate2, k;
1934 for (rate1 = WL_TX_POWER_CCK_FIRST, rate2 = 0;
1935 rate2 < WL_TX_POWER_CCK_NUM; rate1++, rate2++)
1936 pi->txpwr_limit[rate1] = txpwr->cck[rate2];
1938 for (rate1 = WL_TX_POWER_OFDM_FIRST, rate2 = 0;
1939 rate2 < WL_TX_POWER_OFDM_NUM; rate1++, rate2++)
1940 pi->txpwr_limit[rate1] = txpwr->ofdm[rate2];
1944 for (k = 0; k < 4; k++) {
1948 txpwr_ptr1 = txpwr->mcs_20_siso;
1949 txpwr_ptr2 = txpwr->ofdm;
1950 rate_start_index = WL_TX_POWER_OFDM_FIRST;
1954 txpwr_ptr1 = txpwr->mcs_20_cdd;
1955 txpwr_ptr2 = txpwr->ofdm_cdd;
1956 rate_start_index = WL_TX_POWER_OFDM20_CDD_FIRST;
1960 txpwr_ptr1 = txpwr->mcs_40_siso;
1961 txpwr_ptr2 = txpwr->ofdm_40_siso;
1963 WL_TX_POWER_OFDM40_SISO_FIRST;
1967 txpwr_ptr1 = txpwr->mcs_40_cdd;
1968 txpwr_ptr2 = txpwr->ofdm_40_cdd;
1969 rate_start_index = WL_TX_POWER_OFDM40_CDD_FIRST;
1973 for (rate2 = 0; rate2 < WLC_NUM_RATES_OFDM; rate2++) {
1974 tmp_txpwr_limit[rate2] = 0;
1975 tmp_txpwr_limit[WLC_NUM_RATES_OFDM + rate2] =
1978 wlc_phy_mcs_to_ofdm_powers_nphy(tmp_txpwr_limit, 0,
1979 WLC_NUM_RATES_OFDM - 1,
1980 WLC_NUM_RATES_OFDM);
1981 for (rate1 = rate_start_index, rate2 = 0;
1982 rate2 < WLC_NUM_RATES_OFDM; rate1++, rate2++)
1983 pi->txpwr_limit[rate1] =
1984 min(txpwr_ptr2[rate2],
1985 tmp_txpwr_limit[rate2]);
1988 for (k = 0; k < 4; k++) {
1992 txpwr_ptr1 = txpwr->ofdm;
1993 txpwr_ptr2 = txpwr->mcs_20_siso;
1994 rate_start_index = WL_TX_POWER_MCS20_SISO_FIRST;
1998 txpwr_ptr1 = txpwr->ofdm_cdd;
1999 txpwr_ptr2 = txpwr->mcs_20_cdd;
2000 rate_start_index = WL_TX_POWER_MCS20_CDD_FIRST;
2004 txpwr_ptr1 = txpwr->ofdm_40_siso;
2005 txpwr_ptr2 = txpwr->mcs_40_siso;
2006 rate_start_index = WL_TX_POWER_MCS40_SISO_FIRST;
2010 txpwr_ptr1 = txpwr->ofdm_40_cdd;
2011 txpwr_ptr2 = txpwr->mcs_40_cdd;
2012 rate_start_index = WL_TX_POWER_MCS40_CDD_FIRST;
2015 for (rate2 = 0; rate2 < WLC_NUM_RATES_OFDM; rate2++) {
2016 tmp_txpwr_limit[rate2] = 0;
2017 tmp_txpwr_limit[WLC_NUM_RATES_OFDM + rate2] =
2020 wlc_phy_ofdm_to_mcs_powers_nphy(tmp_txpwr_limit, 0,
2021 WLC_NUM_RATES_OFDM - 1,
2022 WLC_NUM_RATES_OFDM);
2023 for (rate1 = rate_start_index, rate2 = 0;
2024 rate2 < WLC_NUM_RATES_MCS_1_STREAM;
2026 pi->txpwr_limit[rate1] =
2027 min(txpwr_ptr2[rate2],
2028 tmp_txpwr_limit[rate2]);
2031 for (k = 0; k < 2; k++) {
2035 rate_start_index = WL_TX_POWER_MCS20_STBC_FIRST;
2036 txpwr_ptr1 = txpwr->mcs_20_stbc;
2040 rate_start_index = WL_TX_POWER_MCS40_STBC_FIRST;
2041 txpwr_ptr1 = txpwr->mcs_40_stbc;
2044 for (rate1 = rate_start_index, rate2 = 0;
2045 rate2 < WLC_NUM_RATES_MCS_1_STREAM;
2047 pi->txpwr_limit[rate1] = txpwr_ptr1[rate2];
2050 for (k = 0; k < 2; k++) {
2054 rate_start_index = WL_TX_POWER_MCS20_SDM_FIRST;
2055 txpwr_ptr1 = txpwr->mcs_20_mimo;
2059 rate_start_index = WL_TX_POWER_MCS40_SDM_FIRST;
2060 txpwr_ptr1 = txpwr->mcs_40_mimo;
2063 for (rate1 = rate_start_index, rate2 = 0;
2064 rate2 < WLC_NUM_RATES_MCS_2_STREAM;
2066 pi->txpwr_limit[rate1] = txpwr_ptr1[rate2];
2069 pi->txpwr_limit[WL_TX_POWER_MCS_32] = txpwr->mcs32;
2071 pi->txpwr_limit[WL_TX_POWER_MCS40_CDD_FIRST] =
2072 min(pi->txpwr_limit[WL_TX_POWER_MCS40_CDD_FIRST],
2073 pi->txpwr_limit[WL_TX_POWER_MCS_32]);
2074 pi->txpwr_limit[WL_TX_POWER_MCS_32] =
2075 pi->txpwr_limit[WL_TX_POWER_MCS40_CDD_FIRST];
2079 void wlc_phy_txpwr_percent_set(wlc_phy_t *ppi, u8 txpwr_percent)
2081 phy_info_t *pi = (phy_info_t *) ppi;
2083 pi->txpwr_percent = txpwr_percent;
2086 void wlc_phy_machwcap_set(wlc_phy_t *ppi, u32 machwcap)
2088 phy_info_t *pi = (phy_info_t *) ppi;
2090 pi->sh->machwcap = machwcap;
2093 void wlc_phy_runbist_config(wlc_phy_t *ppi, bool start_end)
2095 phy_info_t *pi = (phy_info_t *) ppi;
2099 if (start_end == ON) {
2103 if (NREV_IS(pi->pubpi.phy_rev, 3)
2104 || NREV_IS(pi->pubpi.phy_rev, 4)) {
2105 W_REG(pi->sh->osh, &pi->regs->phyregaddr, 0xa0);
2106 (void)R_REG(pi->sh->osh, &pi->regs->phyregaddr);
2107 rxc = R_REG(pi->sh->osh, &pi->regs->phyregdata);
2108 W_REG(pi->sh->osh, &pi->regs->phyregdata,
2112 if (NREV_IS(pi->pubpi.phy_rev, 3)
2113 || NREV_IS(pi->pubpi.phy_rev, 4)) {
2114 W_REG(pi->sh->osh, &pi->regs->phyregaddr, 0xa0);
2115 (void)R_REG(pi->sh->osh, &pi->regs->phyregaddr);
2116 W_REG(pi->sh->osh, &pi->regs->phyregdata, rxc);
2119 wlc_phy_por_inform(ppi);
2124 wlc_phy_txpower_limit_set(wlc_phy_t *ppi, struct txpwr_limits *txpwr,
2125 chanspec_t chanspec)
2127 phy_info_t *pi = (phy_info_t *) ppi;
2129 wlc_phy_txpower_reg_limit_calc(pi, txpwr, chanspec);
2133 for (i = TXP_FIRST_OFDM_20_CDD, j = 0;
2134 j < WLC_NUM_RATES_MCS_1_STREAM; i++, j++) {
2135 if (txpwr->mcs_20_siso[j])
2136 pi->txpwr_limit[i] = txpwr->mcs_20_siso[j];
2138 pi->txpwr_limit[i] = txpwr->ofdm[j];
2142 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2144 wlc_phy_txpower_recalc_target(pi);
2145 wlc_phy_cal_txpower_recalc_sw(pi);
2146 wlapi_enable_mac(pi->sh->physhim);
2149 void wlc_phy_ofdm_rateset_war(wlc_phy_t *pih, bool war)
2151 phy_info_t *pi = (phy_info_t *) pih;
2153 pi->ofdm_rateset_war = war;
2156 void wlc_phy_bf_preempt_enable(wlc_phy_t *pih, bool bf_preempt)
2158 phy_info_t *pi = (phy_info_t *) pih;
2160 pi->bf_preempt_4306 = bf_preempt;
2163 void wlc_phy_txpower_update_shm(phy_info_t *pi)
2174 if (pi->hwpwrctrl) {
2177 wlapi_bmac_write_shm(pi->sh->physhim, M_TXPWR_MAX, 63);
2178 wlapi_bmac_write_shm(pi->sh->physhim, M_TXPWR_N,
2179 1 << NUM_TSSI_FRAMES);
2181 wlapi_bmac_write_shm(pi->sh->physhim, M_TXPWR_TARGET,
2182 pi->tx_power_min << NUM_TSSI_FRAMES);
2184 wlapi_bmac_write_shm(pi->sh->physhim, M_TXPWR_CUR,
2187 for (j = TXP_FIRST_OFDM; j <= TXP_LAST_OFDM; j++) {
2188 const u8 ucode_ofdm_rates[] = {
2189 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c
2191 offset = wlapi_bmac_rate_shm_offset(pi->sh->physhim,
2192 ucode_ofdm_rates[j -
2194 wlapi_bmac_write_shm(pi->sh->physhim, offset + 6,
2195 pi->tx_power_offset[j]);
2196 wlapi_bmac_write_shm(pi->sh->physhim, offset + 14,
2197 -(pi->tx_power_offset[j] / 2));
2200 wlapi_bmac_mhf(pi->sh->physhim, MHF2, MHF2_HWPWRCTL,
2201 MHF2_HWPWRCTL, WLC_BAND_ALL);
2205 for (i = TXP_FIRST_OFDM; i <= TXP_LAST_OFDM; i++)
2206 pi->tx_power_offset[i] =
2207 (u8) roundup(pi->tx_power_offset[i], 8);
2208 wlapi_bmac_write_shm(pi->sh->physhim, M_OFDM_OFFSET,
2210 tx_power_offset[TXP_FIRST_OFDM]
2215 bool wlc_phy_txpower_hw_ctrl_get(wlc_phy_t *ppi)
2217 phy_info_t *pi = (phy_info_t *) ppi;
2220 return pi->nphy_txpwrctrl;
2222 return pi->hwpwrctrl;
2226 void wlc_phy_txpower_hw_ctrl_set(wlc_phy_t *ppi, bool hwpwrctrl)
2228 phy_info_t *pi = (phy_info_t *) ppi;
2229 bool cur_hwpwrctrl = pi->hwpwrctrl;
2232 if (!pi->hwpwrctrl_capable) {
2236 pi->hwpwrctrl = hwpwrctrl;
2237 pi->nphy_txpwrctrl = hwpwrctrl;
2238 pi->txpwrctrl = hwpwrctrl;
2243 (R_REG(pi->sh->osh, &pi->regs->maccontrol) & MCTL_EN_MAC));
2245 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2247 wlc_phy_txpwrctrl_enable_nphy(pi, pi->nphy_txpwrctrl);
2248 if (pi->nphy_txpwrctrl == PHY_TPC_HW_OFF) {
2249 wlc_phy_txpwr_fixpower_nphy(pi);
2252 mod_phy_reg(pi, 0x1e7, (0x7f << 0),
2253 pi->saved_txpwr_idx);
2257 wlapi_enable_mac(pi->sh->physhim);
2258 } else if (hwpwrctrl != cur_hwpwrctrl) {
2264 void wlc_phy_txpower_ipa_upd(phy_info_t *pi)
2267 if (NREV_GE(pi->pubpi.phy_rev, 3)) {
2268 pi->ipa2g_on = (pi->srom_fem2g.extpagain == 2);
2269 pi->ipa5g_on = (pi->srom_fem5g.extpagain == 2);
2271 pi->ipa2g_on = false;
2272 pi->ipa5g_on = false;
2276 static u32 wlc_phy_txpower_est_power_nphy(phy_info_t *pi);
2278 static u32 wlc_phy_txpower_est_power_nphy(phy_info_t *pi)
2280 s16 tx0_status, tx1_status;
2281 u16 estPower1, estPower2;
2282 u8 pwr0, pwr1, adj_pwr0, adj_pwr1;
2285 estPower1 = read_phy_reg(pi, 0x118);
2286 estPower2 = read_phy_reg(pi, 0x119);
2288 if ((estPower1 & (0x1 << 8))
2290 pwr0 = (u8) (estPower1 & (0xff << 0))
2296 if ((estPower2 & (0x1 << 8))
2298 pwr1 = (u8) (estPower2 & (0xff << 0))
2304 tx0_status = read_phy_reg(pi, 0x1ed);
2305 tx1_status = read_phy_reg(pi, 0x1ee);
2307 if ((tx0_status & (0x1 << 15))
2309 adj_pwr0 = (u8) (tx0_status & (0xff << 0))
2314 if ((tx1_status & (0x1 << 15))
2316 adj_pwr1 = (u8) (tx1_status & (0xff << 0))
2323 (u32) ((pwr0 << 24) | (pwr1 << 16) | (adj_pwr0 << 8) | adj_pwr1);
2328 wlc_phy_txpower_get_current(wlc_phy_t *ppi, tx_power_t *power, uint channel)
2330 phy_info_t *pi = (phy_info_t *) ppi;
2331 uint rate, num_rates;
2332 u8 min_pwr, max_pwr;
2334 #if WL_TX_POWER_RATES != TXP_NUM_RATES
2335 #error "tx_power_t struct out of sync with this fn"
2339 power->rf_cores = 2;
2340 power->flags |= (WL_TX_POWER_F_MIMO);
2341 if (pi->nphy_txpwrctrl == PHY_TPC_HW_ON)
2343 (WL_TX_POWER_F_ENABLED | WL_TX_POWER_F_HW);
2344 } else if (ISLCNPHY(pi)) {
2345 power->rf_cores = 1;
2346 power->flags |= (WL_TX_POWER_F_SISO);
2347 if (pi->radiopwr_override == RADIOPWR_OVERRIDE_DEF)
2348 power->flags |= WL_TX_POWER_F_ENABLED;
2350 power->flags |= WL_TX_POWER_F_HW;
2353 num_rates = ((ISNPHY(pi)) ? (TXP_NUM_RATES) :
2355 (TXP_LAST_OFDM_20_CDD + 1) : (TXP_LAST_OFDM + 1)));
2357 for (rate = 0; rate < num_rates; rate++) {
2358 power->user_limit[rate] = pi->tx_user_target[rate];
2359 wlc_phy_txpower_sromlimit(ppi, channel, &min_pwr, &max_pwr,
2361 power->board_limit[rate] = (u8) max_pwr;
2362 power->target[rate] = pi->tx_power_target[rate];
2368 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2369 wlc_phyreg_enter((wlc_phy_t *) pi);
2370 est_pout = wlc_phy_txpower_est_power_nphy(pi);
2371 wlc_phyreg_exit((wlc_phy_t *) pi);
2372 wlapi_enable_mac(pi->sh->physhim);
2374 power->est_Pout[0] = (est_pout >> 8) & 0xff;
2375 power->est_Pout[1] = est_pout & 0xff;
2377 power->est_Pout_act[0] = est_pout >> 24;
2378 power->est_Pout_act[1] = (est_pout >> 16) & 0xff;
2380 if (power->est_Pout[0] == 0x80)
2381 power->est_Pout[0] = 0;
2382 if (power->est_Pout[1] == 0x80)
2383 power->est_Pout[1] = 0;
2385 if (power->est_Pout_act[0] == 0x80)
2386 power->est_Pout_act[0] = 0;
2387 if (power->est_Pout_act[1] == 0x80)
2388 power->est_Pout_act[1] = 0;
2390 power->est_Pout_cck = 0;
2392 power->tx_power_max[0] = pi->tx_power_max;
2393 power->tx_power_max[1] = pi->tx_power_max;
2395 power->tx_power_max_rate_ind[0] = pi->tx_power_max_rate_ind;
2396 power->tx_power_max_rate_ind[1] = pi->tx_power_max_rate_ind;
2397 } else if (!pi->hwpwrctrl) {
2398 } else if (pi->sh->up) {
2400 wlc_phyreg_enter(ppi);
2403 power->tx_power_max[0] = pi->tx_power_max;
2404 power->tx_power_max[1] = pi->tx_power_max;
2406 power->tx_power_max_rate_ind[0] =
2407 pi->tx_power_max_rate_ind;
2408 power->tx_power_max_rate_ind[1] =
2409 pi->tx_power_max_rate_ind;
2411 if (wlc_phy_tpc_isenabled_lcnphy(pi))
2413 (WL_TX_POWER_F_HW | WL_TX_POWER_F_ENABLED);
2416 ~(WL_TX_POWER_F_HW | WL_TX_POWER_F_ENABLED);
2418 wlc_lcnphy_get_tssi(pi, (s8 *) &power->est_Pout[0],
2419 (s8 *) &power->est_Pout_cck);
2421 wlc_phyreg_exit(ppi);
2425 void wlc_phy_antsel_type_set(wlc_phy_t *ppi, u8 antsel_type)
2427 phy_info_t *pi = (phy_info_t *) ppi;
2429 pi->antsel_type = antsel_type;
2432 bool wlc_phy_test_ison(wlc_phy_t *ppi)
2434 phy_info_t *pi = (phy_info_t *) ppi;
2436 return pi->phytest_on;
2439 bool wlc_phy_ant_rxdiv_get(wlc_phy_t *ppi, u8 *pval)
2441 phy_info_t *pi = (phy_info_t *) ppi;
2444 wlc_phyreg_enter(ppi);
2449 } else if (ISLCNPHY(pi)) {
2450 u16 crsctrl = read_phy_reg(pi, 0x410);
2451 u16 div = crsctrl & (0x1 << 1);
2452 *pval = (div | ((crsctrl & (0x1 << 0)) ^ (div >> 1)));
2455 wlc_phyreg_exit(ppi);
2460 void wlc_phy_ant_rxdiv_set(wlc_phy_t *ppi, u8 val)
2462 phy_info_t *pi = (phy_info_t *) ppi;
2465 pi->sh->rx_antdiv = val;
2467 if (!(ISNPHY(pi) && D11REV_IS(pi->sh->corerev, 16))) {
2468 if (val > ANT_RX_DIV_FORCE_1)
2469 wlapi_bmac_mhf(pi->sh->physhim, MHF1, MHF1_ANTDIV,
2470 MHF1_ANTDIV, WLC_BAND_ALL);
2472 wlapi_bmac_mhf(pi->sh->physhim, MHF1, MHF1_ANTDIV, 0,
2485 (0 == (R_REG(pi->sh->osh, &pi->regs->maccontrol) & MCTL_EN_MAC));
2487 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2490 if (val > ANT_RX_DIV_FORCE_1) {
2491 mod_phy_reg(pi, 0x410, (0x1 << 1), 0x01 << 1);
2492 mod_phy_reg(pi, 0x410,
2494 ((ANT_RX_DIV_START_1 == val) ? 1 : 0) << 0);
2496 mod_phy_reg(pi, 0x410, (0x1 << 1), 0x00 << 1);
2497 mod_phy_reg(pi, 0x410, (0x1 << 0), (u16) val << 0);
2504 wlapi_enable_mac(pi->sh->physhim);
2510 wlc_phy_noise_calc_phy(phy_info_t *pi, u32 *cmplx_pwr, s8 *pwr_ant)
2512 s8 cmplx_pwr_dbm[PHY_CORE_MAX];
2515 memset((u8 *) cmplx_pwr_dbm, 0, sizeof(cmplx_pwr_dbm));
2516 ASSERT(pi->pubpi.phy_corenum <= PHY_CORE_MAX);
2517 wlc_phy_compute_dB(cmplx_pwr, cmplx_pwr_dbm, pi->pubpi.phy_corenum);
2519 for (i = 0; i < pi->pubpi.phy_corenum; i++) {
2520 if (NREV_GE(pi->pubpi.phy_rev, 3))
2521 cmplx_pwr_dbm[i] += (s8) PHY_NOISE_OFFSETFACT_4322;
2524 cmplx_pwr_dbm[i] += (s8) (16 - (15) * 3 - 70);
2527 for (i = 0; i < pi->pubpi.phy_corenum; i++) {
2528 pi->nphy_noise_win[i][pi->nphy_noise_index] = cmplx_pwr_dbm[i];
2529 pwr_ant[i] = cmplx_pwr_dbm[i];
2531 pi->nphy_noise_index =
2532 MODINC_POW2(pi->nphy_noise_index, PHY_NOISE_WINDOW_SZ);
2537 wlc_phy_noise_sample_request(wlc_phy_t *pih, u8 reason, u8 ch)
2539 phy_info_t *pi = (phy_info_t *) pih;
2540 s8 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;
2541 bool sampling_in_progress = (pi->phynoise_state != 0);
2542 bool wait_for_intr = true;
2544 if (NORADIO_ENAB(pi->pubpi)) {
2549 case PHY_NOISE_SAMPLE_MON:
2551 pi->phynoise_chan_watchdog = ch;
2552 pi->phynoise_state |= PHY_NOISE_STATE_MON;
2556 case PHY_NOISE_SAMPLE_EXTERNAL:
2558 pi->phynoise_state |= PHY_NOISE_STATE_EXTERNAL;
2566 if (sampling_in_progress)
2569 pi->phynoise_now = pi->sh->now;
2571 if (pi->phy_fixed_noise) {
2573 pi->nphy_noise_win[WL_ANT_IDX_1][pi->nphy_noise_index] =
2574 PHY_NOISE_FIXED_VAL_NPHY;
2575 pi->nphy_noise_win[WL_ANT_IDX_2][pi->nphy_noise_index] =
2576 PHY_NOISE_FIXED_VAL_NPHY;
2577 pi->nphy_noise_index = MODINC_POW2(pi->nphy_noise_index,
2578 PHY_NOISE_WINDOW_SZ);
2580 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;
2583 noise_dbm = PHY_NOISE_FIXED_VAL;
2586 wait_for_intr = false;
2591 if (!pi->phynoise_polling
2592 || (reason == PHY_NOISE_SAMPLE_EXTERNAL)) {
2593 wlapi_bmac_write_shm(pi->sh->physhim, M_JSSI_0, 0);
2594 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP0, 0);
2595 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP1, 0);
2596 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP2, 0);
2597 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP3, 0);
2599 OR_REG(pi->sh->osh, &pi->regs->maccommand,
2602 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2603 wlc_lcnphy_deaf_mode(pi, (bool) 0);
2604 noise_dbm = (s8) wlc_lcnphy_rx_signal_power(pi, 20);
2605 wlc_lcnphy_deaf_mode(pi, (bool) 1);
2606 wlapi_enable_mac(pi->sh->physhim);
2607 wait_for_intr = false;
2609 } else if (ISNPHY(pi)) {
2610 if (!pi->phynoise_polling
2611 || (reason == PHY_NOISE_SAMPLE_EXTERNAL)) {
2613 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP0, 0);
2614 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP1, 0);
2615 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP2, 0);
2616 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP3, 0);
2618 OR_REG(pi->sh->osh, &pi->regs->maccommand,
2621 phy_iq_est_t est[PHY_CORE_MAX];
2622 u32 cmplx_pwr[PHY_CORE_MAX];
2623 s8 noise_dbm_ant[PHY_CORE_MAX];
2624 u16 log_num_samps, num_samps, classif_state = 0;
2629 memset((u8 *) est, 0, sizeof(est));
2630 memset((u8 *) cmplx_pwr, 0, sizeof(cmplx_pwr));
2631 memset((u8 *) noise_dbm_ant, 0, sizeof(noise_dbm_ant));
2633 log_num_samps = PHY_NOISE_SAMPLE_LOG_NUM_NPHY;
2634 num_samps = 1 << log_num_samps;
2636 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2637 classif_state = wlc_phy_classifier_nphy(pi, 0, 0);
2638 wlc_phy_classifier_nphy(pi, 3, 0);
2639 wlc_phy_rx_iq_est_nphy(pi, est, num_samps, wait_time,
2641 wlc_phy_classifier_nphy(pi, (0x7 << 0), classif_state);
2642 wlapi_enable_mac(pi->sh->physhim);
2644 for (i = 0; i < pi->pubpi.phy_corenum; i++)
2647 est[i].q_pwr) >> log_num_samps;
2649 wlc_phy_noise_calc_phy(pi, cmplx_pwr, noise_dbm_ant);
2651 for (i = 0; i < pi->pubpi.phy_corenum; i++) {
2652 pi->nphy_noise_win[i][pi->nphy_noise_index] =
2655 if (noise_dbm_ant[i] > noise_dbm)
2656 noise_dbm = noise_dbm_ant[i];
2658 pi->nphy_noise_index = MODINC_POW2(pi->nphy_noise_index,
2659 PHY_NOISE_WINDOW_SZ);
2661 wait_for_intr = false;
2668 wlc_phy_noise_cb(pi, ch, noise_dbm);
2672 void wlc_phy_noise_sample_request_external(wlc_phy_t *pih)
2676 channel = CHSPEC_CHANNEL(wlc_phy_chanspec_get(pih));
2678 wlc_phy_noise_sample_request(pih, PHY_NOISE_SAMPLE_EXTERNAL, channel);
2681 static void wlc_phy_noise_cb(phy_info_t *pi, u8 channel, s8 noise_dbm)
2683 if (!pi->phynoise_state)
2686 if (pi->phynoise_state & PHY_NOISE_STATE_MON) {
2687 if (pi->phynoise_chan_watchdog == channel) {
2688 pi->sh->phy_noise_window[pi->sh->phy_noise_index] =
2690 pi->sh->phy_noise_index =
2691 MODINC(pi->sh->phy_noise_index, MA_WINDOW_SZ);
2693 pi->phynoise_state &= ~PHY_NOISE_STATE_MON;
2696 if (pi->phynoise_state & PHY_NOISE_STATE_EXTERNAL) {
2697 pi->phynoise_state &= ~PHY_NOISE_STATE_EXTERNAL;
2702 static s8 wlc_phy_noise_read_shmem(phy_info_t *pi)
2704 u32 cmplx_pwr[PHY_CORE_MAX];
2705 s8 noise_dbm_ant[PHY_CORE_MAX];
2707 u32 cmplx_pwr_tot = 0;
2708 s8 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;
2711 ASSERT(pi->pubpi.phy_corenum <= PHY_CORE_MAX);
2712 memset((u8 *) cmplx_pwr, 0, sizeof(cmplx_pwr));
2713 memset((u8 *) noise_dbm_ant, 0, sizeof(noise_dbm_ant));
2715 for (idx = 0, core = 0; core < pi->pubpi.phy_corenum; idx += 2, core++) {
2716 lo = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP(idx));
2717 hi = wlapi_bmac_read_shm(pi->sh->physhim,
2718 M_PWRIND_MAP(idx + 1));
2719 cmplx_pwr[core] = (hi << 16) + lo;
2720 cmplx_pwr_tot += cmplx_pwr[core];
2721 if (cmplx_pwr[core] == 0) {
2722 noise_dbm_ant[core] = PHY_NOISE_FIXED_VAL_NPHY;
2724 cmplx_pwr[core] >>= PHY_NOISE_SAMPLE_LOG_NUM_UCODE;
2727 if (cmplx_pwr_tot != 0)
2728 wlc_phy_noise_calc_phy(pi, cmplx_pwr, noise_dbm_ant);
2730 for (core = 0; core < pi->pubpi.phy_corenum; core++) {
2731 pi->nphy_noise_win[core][pi->nphy_noise_index] =
2732 noise_dbm_ant[core];
2734 if (noise_dbm_ant[core] > noise_dbm)
2735 noise_dbm = noise_dbm_ant[core];
2737 pi->nphy_noise_index =
2738 MODINC_POW2(pi->nphy_noise_index, PHY_NOISE_WINDOW_SZ);
2744 void wlc_phy_noise_sample_intr(wlc_phy_t *pih)
2746 phy_info_t *pi = (phy_info_t *) pih;
2749 s8 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;
2752 u32 cmplx_pwr, cmplx_pwr0, cmplx_pwr1;
2754 s32 pwr_offset_dB, gain_dB;
2755 u16 status_0, status_1;
2757 jssi_aux = wlapi_bmac_read_shm(pi->sh->physhim, M_JSSI_AUX);
2758 channel = jssi_aux & D11_CURCHANNEL_MAX;
2760 lo = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP0);
2761 hi = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP1);
2762 cmplx_pwr0 = (hi << 16) + lo;
2764 lo = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP2);
2765 hi = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP3);
2766 cmplx_pwr1 = (hi << 16) + lo;
2767 cmplx_pwr = (cmplx_pwr0 + cmplx_pwr1) >> 6;
2770 status_1 = wlapi_bmac_read_shm(pi->sh->physhim, M_JSSI_0);
2771 if ((cmplx_pwr > 0 && cmplx_pwr < 500)
2772 && ((status_1 & 0xc000) == 0x4000)) {
2774 wlc_phy_compute_dB(&cmplx_pwr, &noise_dbm,
2775 pi->pubpi.phy_corenum);
2776 pwr_offset_dB = (read_phy_reg(pi, 0x434) & 0xFF);
2777 if (pwr_offset_dB > 127)
2778 pwr_offset_dB -= 256;
2780 noise_dbm += (s8) (pwr_offset_dB - 30);
2782 gain_dB = (status_0 & 0x1ff);
2783 noise_dbm -= (s8) (gain_dB);
2785 noise_dbm = PHY_NOISE_FIXED_VAL_LCNPHY;
2787 } else if (ISNPHY(pi)) {
2789 jssi_aux = wlapi_bmac_read_shm(pi->sh->physhim, M_JSSI_AUX);
2790 channel = jssi_aux & D11_CURCHANNEL_MAX;
2792 noise_dbm = wlc_phy_noise_read_shmem(pi);
2797 wlc_phy_noise_cb(pi, channel, noise_dbm);
2801 s8 lcnphy_gain_index_offset_for_pkt_rssi[] = {
2842 void wlc_phy_compute_dB(u32 *cmplx_pwr, s8 *p_cmplx_pwr_dB, u8 core)
2844 u8 shift_ct, lsb, msb, secondmsb, i;
2847 for (i = 0; i < core; i++) {
2849 shift_ct = msb = secondmsb = 0;
2853 lsb = (u8) (tmp & 1);
2857 secondmsb = (u8) ((cmplx_pwr[i] >> (msb - 1)) & 1);
2858 p_cmplx_pwr_dB[i] = (s8) (3 * msb + 2 * secondmsb);
2862 void BCMFASTPATH wlc_phy_rssi_compute(wlc_phy_t *pih, void *ctx)
2864 wlc_d11rxhdr_t *wlc_rxhdr = (wlc_d11rxhdr_t *) ctx;
2865 d11rxhdr_t *rxh = &wlc_rxhdr->rxhdr;
2866 int rssi = ltoh16(rxh->PhyRxStatus_1) & PRXS1_JSSI_MASK;
2867 uint radioid = pih->radioid;
2868 phy_info_t *pi = (phy_info_t *) pih;
2870 if (NORADIO_ENAB(pi->pubpi)) {
2871 rssi = WLC_RSSI_INVALID;
2875 if ((pi->sh->corerev >= 11)
2876 && !(ltoh16(rxh->RxStatus2) & RXS_PHYRXST_VALID)) {
2877 rssi = WLC_RSSI_INVALID;
2882 u8 gidx = (ltoh16(rxh->PhyRxStatus_2) & 0xFC00) >> 10;
2883 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
2888 rssi = rssi + lcnphy_gain_index_offset_for_pkt_rssi[gidx];
2889 if ((rssi > -46) && (gidx > 18))
2892 rssi = rssi + pi_lcn->lcnphy_pkteng_rssi_slope;
2902 } else if (radioid == BCM2055_ID || radioid == BCM2056_ID
2903 || radioid == BCM2057_ID) {
2905 rssi = wlc_phy_rssi_compute_nphy(pi, wlc_rxhdr);
2907 ASSERT((const char *)"Unknown radio" == NULL);
2911 wlc_rxhdr->rssi = (s8) rssi;
2914 void wlc_phy_freqtrack_start(wlc_phy_t *pih)
2919 void wlc_phy_freqtrack_end(wlc_phy_t *pih)
2924 void wlc_phy_set_deaf(wlc_phy_t *ppi, bool user_flag)
2927 pi = (phy_info_t *) ppi;
2930 wlc_lcnphy_deaf_mode(pi, true);
2931 else if (ISNPHY(pi))
2932 wlc_nphy_deaf_mode(pi, true);
2938 void wlc_phy_watchdog(wlc_phy_t *pih)
2940 phy_info_t *pi = (phy_info_t *) pih;
2941 bool delay_phy_cal = false;
2944 if (!pi->watchdog_override)
2947 if (!(SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi))) {
2948 wlc_phy_noise_sample_request((wlc_phy_t *) pi,
2949 PHY_NOISE_SAMPLE_MON,
2954 if (pi->phynoise_state && (pi->sh->now - pi->phynoise_now) > 5) {
2955 pi->phynoise_state = 0;
2958 if ((!pi->phycal_txpower) ||
2959 ((pi->sh->now - pi->phycal_txpower) >= pi->sh->fast_timer)) {
2961 if (!SCAN_INPROG_PHY(pi) && wlc_phy_cal_txpower_recalc_sw(pi)) {
2962 pi->phycal_txpower = pi->sh->now;
2966 if (NORADIO_ENAB(pi->pubpi))
2969 if ((SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi)
2970 || ASSOC_INPROG_PHY(pi)))
2973 if (ISNPHY(pi) && !pi->disable_percal && !delay_phy_cal) {
2975 if ((pi->nphy_perical != PHY_PERICAL_DISABLE) &&
2976 (pi->nphy_perical != PHY_PERICAL_MANUAL) &&
2977 ((pi->sh->now - pi->nphy_perical_last) >=
2978 pi->sh->glacial_timer))
2979 wlc_phy_cal_perical((wlc_phy_t *) pi,
2980 PHY_PERICAL_WATCHDOG);
2982 wlc_phy_txpwr_papd_cal_nphy(pi);
2986 if (pi->phy_forcecal ||
2987 ((pi->sh->now - pi->phy_lastcal) >=
2988 pi->sh->glacial_timer)) {
2989 if (!(SCAN_RM_IN_PROGRESS(pi) || ASSOC_INPROG_PHY(pi)))
2990 wlc_lcnphy_calib_modes(pi,
2991 LCNPHY_PERICAL_TEMPBASED_TXPWRCTRL);
2993 (SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi)
2994 || ASSOC_INPROG_PHY(pi)
2995 || pi->carrier_suppr_disable
2996 || pi->disable_percal))
2997 wlc_lcnphy_calib_modes(pi,
2998 PHY_PERICAL_WATCHDOG);
3003 void wlc_phy_BSSinit(wlc_phy_t *pih, bool bonlyap, int rssi)
3005 phy_info_t *pi = (phy_info_t *) pih;
3009 for (i = 0; i < MA_WINDOW_SZ; i++) {
3010 pi->sh->phy_noise_window[i] = (s8) (rssi & 0xff);
3013 for (i = 0; i < MA_WINDOW_SZ; i++)
3014 pi->sh->phy_noise_window[i] =
3015 PHY_NOISE_FIXED_VAL_LCNPHY;
3017 pi->sh->phy_noise_index = 0;
3019 for (i = 0; i < PHY_NOISE_WINDOW_SZ; i++) {
3020 for (k = WL_ANT_IDX_1; k < WL_ANT_RX_MAX; k++)
3021 pi->nphy_noise_win[k][i] = PHY_NOISE_FIXED_VAL_NPHY;
3023 pi->nphy_noise_index = 0;
3027 wlc_phy_papd_decode_epsilon(u32 epsilon, s32 *eps_real, s32 *eps_imag)
3029 *eps_imag = (epsilon >> 13);
3030 if (*eps_imag > 0xfff)
3031 *eps_imag -= 0x2000;
3033 *eps_real = (epsilon & 0x1fff);
3034 if (*eps_real > 0xfff)
3035 *eps_real -= 0x2000;
3038 static const fixed AtanTbl[] = {
3059 void wlc_phy_cordic(fixed theta, cs32 *val)
3061 fixed angle, valtmp;
3066 val[0].i = CORDIC_AG;
3070 signtheta = (theta < 0) ? -1 : 1;
3072 ((theta + FIXED(180) * signtheta) % FIXED(360)) -
3073 FIXED(180) * signtheta;
3075 if (FLOAT(theta) > 90) {
3076 theta -= FIXED(180);
3078 } else if (FLOAT(theta) < -90) {
3079 theta += FIXED(180);
3083 for (iter = 0; iter < CORDIC_NI; iter++) {
3084 if (theta > angle) {
3085 valtmp = val[0].i - (val[0].q >> iter);
3086 val[0].q = (val[0].i >> iter) + val[0].q;
3088 angle += AtanTbl[iter];
3090 valtmp = val[0].i + (val[0].q >> iter);
3091 val[0].q = -(val[0].i >> iter) + val[0].q;
3093 angle -= AtanTbl[iter];
3097 val[0].i = val[0].i * signx;
3098 val[0].q = val[0].q * signx;
3101 void wlc_phy_cal_perical_mphase_reset(phy_info_t *pi)
3103 wlapi_del_timer(pi->sh->physhim, pi->phycal_timer);
3105 pi->cal_type_override = PHY_PERICAL_AUTO;
3106 pi->mphase_cal_phase_id = MPHASE_CAL_STATE_IDLE;
3107 pi->mphase_txcal_cmdidx = 0;
3110 static void wlc_phy_cal_perical_mphase_schedule(phy_info_t *pi, uint delay)
3113 if ((pi->nphy_perical != PHY_PERICAL_MPHASE) &&
3114 (pi->nphy_perical != PHY_PERICAL_MANUAL))
3117 wlapi_del_timer(pi->sh->physhim, pi->phycal_timer);
3119 pi->mphase_cal_phase_id = MPHASE_CAL_STATE_INIT;
3120 wlapi_add_timer(pi->sh->physhim, pi->phycal_timer, delay, 0);
3123 void wlc_phy_cal_perical(wlc_phy_t *pih, u8 reason)
3125 s16 nphy_currtemp = 0;
3127 bool do_periodic_cal = true;
3128 phy_info_t *pi = (phy_info_t *) pih;
3133 if ((pi->nphy_perical == PHY_PERICAL_DISABLE) ||
3134 (pi->nphy_perical == PHY_PERICAL_MANUAL))
3138 case PHY_PERICAL_DRIVERUP:
3141 case PHY_PERICAL_PHYINIT:
3142 if (pi->nphy_perical == PHY_PERICAL_MPHASE) {
3143 if (PHY_PERICAL_MPHASE_PENDING(pi)) {
3144 wlc_phy_cal_perical_mphase_reset(pi);
3146 wlc_phy_cal_perical_mphase_schedule(pi,
3147 PHY_PERICAL_INIT_DELAY);
3151 case PHY_PERICAL_JOIN_BSS:
3152 case PHY_PERICAL_START_IBSS:
3153 case PHY_PERICAL_UP_BSS:
3154 if ((pi->nphy_perical == PHY_PERICAL_MPHASE) &&
3155 PHY_PERICAL_MPHASE_PENDING(pi)) {
3156 wlc_phy_cal_perical_mphase_reset(pi);
3159 pi->first_cal_after_assoc = true;
3161 pi->cal_type_override = PHY_PERICAL_FULL;
3163 if (pi->phycal_tempdelta) {
3164 pi->nphy_lastcal_temp = wlc_phy_tempsense_nphy(pi);
3166 wlc_phy_cal_perical_nphy_run(pi, PHY_PERICAL_FULL);
3169 case PHY_PERICAL_WATCHDOG:
3170 if (pi->phycal_tempdelta) {
3171 nphy_currtemp = wlc_phy_tempsense_nphy(pi);
3173 (nphy_currtemp > pi->nphy_lastcal_temp) ?
3174 nphy_currtemp - pi->nphy_lastcal_temp :
3175 pi->nphy_lastcal_temp - nphy_currtemp;
3177 if ((delta_temp < (s16) pi->phycal_tempdelta) &&
3178 (pi->nphy_txiqlocal_chanspec ==
3179 pi->radio_chanspec)) {
3180 do_periodic_cal = false;
3182 pi->nphy_lastcal_temp = nphy_currtemp;
3186 if (do_periodic_cal) {
3188 if (pi->nphy_perical == PHY_PERICAL_MPHASE) {
3190 if (!PHY_PERICAL_MPHASE_PENDING(pi))
3191 wlc_phy_cal_perical_mphase_schedule(pi,
3192 PHY_PERICAL_WDOG_DELAY);
3193 } else if (pi->nphy_perical == PHY_PERICAL_SPHASE)
3194 wlc_phy_cal_perical_nphy_run(pi,
3207 void wlc_phy_cal_perical_mphase_restart(phy_info_t *pi)
3209 pi->mphase_cal_phase_id = MPHASE_CAL_STATE_INIT;
3210 pi->mphase_txcal_cmdidx = 0;
3213 u8 wlc_phy_nbits(s32 value)
3218 abs_val = ABS(value);
3219 while ((abs_val >> nbits) > 0)
3225 u32 wlc_phy_sqrt_int(u32 value)
3227 u32 root = 0, shift = 0;
3229 for (shift = 0; shift < 32; shift += 2) {
3230 if (((0x40000000 >> shift) + root) <= value) {
3231 value -= ((0x40000000 >> shift) + root);
3232 root = (root >> 1) | (0x40000000 >> shift);
3244 void wlc_phy_stf_chain_init(wlc_phy_t *pih, u8 txchain, u8 rxchain)
3246 phy_info_t *pi = (phy_info_t *) pih;
3248 pi->sh->hw_phytxchain = txchain;
3249 pi->sh->hw_phyrxchain = rxchain;
3250 pi->sh->phytxchain = txchain;
3251 pi->sh->phyrxchain = rxchain;
3252 pi->pubpi.phy_corenum = (u8) PHY_BITSCNT(pi->sh->phyrxchain);
3255 void wlc_phy_stf_chain_set(wlc_phy_t *pih, u8 txchain, u8 rxchain)
3257 phy_info_t *pi = (phy_info_t *) pih;
3259 pi->sh->phytxchain = txchain;
3262 wlc_phy_rxcore_setstate_nphy(pih, rxchain);
3264 pi->pubpi.phy_corenum = (u8) PHY_BITSCNT(pi->sh->phyrxchain);
3267 void wlc_phy_stf_chain_get(wlc_phy_t *pih, u8 *txchain, u8 *rxchain)
3269 phy_info_t *pi = (phy_info_t *) pih;
3271 *txchain = pi->sh->phytxchain;
3272 *rxchain = pi->sh->phyrxchain;
3275 u8 wlc_phy_stf_chain_active_get(wlc_phy_t *pih)
3279 phy_info_t *pi = (phy_info_t *) pih;
3281 active_bitmap = (pi->phy_txcore_heatedup) ? 0x31 : 0x33;
3283 if (!pi->watchdog_override)
3284 return active_bitmap;
3286 if (NREV_GE(pi->pubpi.phy_rev, 6)) {
3287 wlapi_suspend_mac_and_wait(pi->sh->physhim);
3288 nphy_currtemp = wlc_phy_tempsense_nphy(pi);
3289 wlapi_enable_mac(pi->sh->physhim);
3291 if (!pi->phy_txcore_heatedup) {
3292 if (nphy_currtemp >= pi->phy_txcore_disable_temp) {
3293 active_bitmap &= 0xFD;
3294 pi->phy_txcore_heatedup = true;
3297 if (nphy_currtemp <= pi->phy_txcore_enable_temp) {
3298 active_bitmap |= 0x2;
3299 pi->phy_txcore_heatedup = false;
3304 return active_bitmap;
3307 s8 wlc_phy_stf_ssmode_get(wlc_phy_t *pih, chanspec_t chanspec)
3309 phy_info_t *pi = (phy_info_t *) pih;
3310 u8 siso_mcs_id, cdd_mcs_id;
3313 (CHSPEC_IS40(chanspec)) ? TXP_FIRST_MCS_40_SISO :
3314 TXP_FIRST_MCS_20_SISO;
3316 (CHSPEC_IS40(chanspec)) ? TXP_FIRST_MCS_40_CDD :
3317 TXP_FIRST_MCS_20_CDD;
3319 if (pi->tx_power_target[siso_mcs_id] >
3320 (pi->tx_power_target[cdd_mcs_id] + 12))
3321 return PHY_TXC1_MODE_SISO;
3323 return PHY_TXC1_MODE_CDD;
3326 const u8 *wlc_phy_get_ofdm_rate_lookup(void)
3328 return ofdm_rate_lookup;
3331 void wlc_lcnphy_epa_switch(phy_info_t *pi, bool mode)
3333 if ((pi->sh->chip == BCM4313_CHIP_ID) &&
3334 (pi->sh->boardflags & BFL_FEM)) {
3337 txant = wlapi_bmac_get_txant(pi->sh->physhim);
3339 mod_phy_reg(pi, 0x44d, (0x1 << 2), (1) << 2);
3341 mod_phy_reg(pi, 0x44c, (0x1 << 2), (1) << 2);
3344 si_corereg(pi->sh->sih, SI_CC_IDX,
3345 offsetof(chipcregs_t, gpiocontrol), ~0x0,
3347 si_corereg(pi->sh->sih, SI_CC_IDX,
3348 offsetof(chipcregs_t, gpioout), 0x40, 0x40);
3349 si_corereg(pi->sh->sih, SI_CC_IDX,
3350 offsetof(chipcregs_t, gpioouten), 0x40,
3353 mod_phy_reg(pi, 0x44c, (0x1 << 2), (0) << 2);
3355 mod_phy_reg(pi, 0x44d, (0x1 << 2), (0) << 2);
3357 si_corereg(pi->sh->sih, SI_CC_IDX,
3358 offsetof(chipcregs_t, gpioout), 0x40, 0x00);
3359 si_corereg(pi->sh->sih, SI_CC_IDX,
3360 offsetof(chipcregs_t, gpioouten), 0x40, 0x0);
3361 si_corereg(pi->sh->sih, SI_CC_IDX,
3362 offsetof(chipcregs_t, gpiocontrol), ~0x0,
3369 wlc_user_txpwr_antport_to_rfport(phy_info_t *pi, uint chan, u32 band,
3374 if (!pi->user_txpwr_at_rfport)
3379 static s8 wlc_phy_env_measure_vbat(phy_info_t *pi)
3382 return wlc_lcnphy_vbatsense(pi, 0);
3387 static s8 wlc_phy_env_measure_temperature(phy_info_t *pi)
3390 return wlc_lcnphy_tempsense_degree(pi, 0);
3395 static void wlc_phy_upd_env_txpwr_rate_limits(phy_info_t *pi, u32 band)
3400 for (i = 0; i < TXP_NUM_RATES; i++)
3401 pi->txpwr_env_limit[i] = WLC_TXPWR_MAX;
3403 vbat = wlc_phy_env_measure_vbat(pi);
3404 temp = wlc_phy_env_measure_temperature(pi);
3408 void wlc_phy_ldpc_override_set(wlc_phy_t *ppi, bool ldpc)
3414 wlc_phy_get_pwrdet_offsets(phy_info_t *pi, s8 *cckoffset, s8 *ofdmoffset)
3420 u32 wlc_phy_qdiv_roundup(u32 dividend, u32 divisor, u8 precision)
3422 u32 quotient, remainder, roundup, rbit;
3426 quotient = dividend / divisor;
3427 remainder = dividend % divisor;
3429 roundup = (divisor >> 1) + rbit;
3431 while (precision--) {
3433 if (remainder >= roundup) {
3435 remainder = ((remainder - roundup) << 1) + rbit;
3441 if (remainder >= roundup)
3447 s8 wlc_phy_upd_rssi_offset(phy_info_t *pi, s8 rssi, chanspec_t chanspec)
3453 bool wlc_phy_txpower_ipa_ison(wlc_phy_t *ppi)
3455 phy_info_t *pi = (phy_info_t *) ppi;
3458 return wlc_phy_n_txpower_ipa_ison(pi);