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>
21 #include <linux/bitops.h>
22 #include <linux/delay.h>
23 #include <linux/module.h>
24 #include <linux/pci.h>
32 #include <wlc_phy_int.h>
33 #include <wlc_phyreg_n.h>
34 #include <wlc_phy_radio.h>
35 #include <wlc_phy_lcn.h>
37 u32 phyhal_msg_level = PHYHAL_ERROR;
39 typedef struct _chan_info_basic {
44 static chan_info_basic_t chan_info_all[] = {
104 u16 ltrn_list[PHY_LTRN_LIST_LEN] = {
105 0x18f9, 0x0d01, 0x00e4, 0xdef4, 0x06f1, 0x0ffc,
106 0xfa27, 0x1dff, 0x10f0, 0x0918, 0xf20a, 0xe010,
107 0x1417, 0x1104, 0xf114, 0xf2fa, 0xf7db, 0xe2fc,
108 0xe1fb, 0x13ee, 0xff0d, 0xe91c, 0x171a, 0x0318,
109 0xda00, 0x03e8, 0x17e6, 0xe9e4, 0xfff3, 0x1312,
110 0xe105, 0xe204, 0xf725, 0xf206, 0xf1ec, 0x11fc,
111 0x14e9, 0xe0f0, 0xf2f6, 0x09e8, 0x1010, 0x1d01,
112 0xfad9, 0x0f04, 0x060f, 0xde0c, 0x001c, 0x0dff,
113 0x1807, 0xf61a, 0xe40e, 0x0f16, 0x05f9, 0x18ec,
114 0x0a1b, 0xff1e, 0x2600, 0xffe2, 0x0ae5, 0x1814,
115 0x0507, 0x0fea, 0xe4f2, 0xf6e6
118 const u8 ofdm_rate_lookup[] = {
130 #define PHY_WREG_LIMIT 24
132 static void wlc_set_phy_uninitted(phy_info_t *pi);
133 static u32 wlc_phy_get_radio_ver(phy_info_t *pi);
134 static void wlc_phy_timercb_phycal(void *arg);
136 static bool wlc_phy_noise_calc_phy(phy_info_t *pi, u32 *cmplx_pwr,
139 static void wlc_phy_cal_perical_mphase_schedule(phy_info_t *pi, uint delay);
140 static void wlc_phy_noise_cb(phy_info_t *pi, u8 channel, s8 noise_dbm);
141 static void wlc_phy_noise_sample_request(wlc_phy_t *pih, u8 reason,
144 static void wlc_phy_txpower_reg_limit_calc(phy_info_t *pi,
145 struct txpwr_limits *tp, chanspec_t);
146 static bool wlc_phy_cal_txpower_recalc_sw(phy_info_t *pi);
148 static s8 wlc_user_txpwr_antport_to_rfport(phy_info_t *pi, uint chan,
150 static void wlc_phy_upd_env_txpwr_rate_limits(phy_info_t *pi, u32 band);
151 static s8 wlc_phy_env_measure_vbat(phy_info_t *pi);
152 static s8 wlc_phy_env_measure_temperature(phy_info_t *pi);
154 char *phy_getvar(phy_info_t *pi, const char *name)
156 char *vars = pi->vars;
167 for (s = vars; s && *s;) {
168 if ((memcmp(s, name, len) == 0) && (s[len] == '='))
175 return nvram_get(name);
178 int phy_getintvar(phy_info_t *pi, const char *name)
182 val = PHY_GETVAR(pi, name);
186 return simple_strtoul(val, NULL, 0);
189 void wlc_phyreg_enter(wlc_phy_t *pih)
191 phy_info_t *pi = (phy_info_t *) pih;
192 wlapi_bmac_ucode_wake_override_phyreg_set(pi->sh->physhim);
195 void wlc_phyreg_exit(wlc_phy_t *pih)
197 phy_info_t *pi = (phy_info_t *) pih;
198 wlapi_bmac_ucode_wake_override_phyreg_clear(pi->sh->physhim);
201 void wlc_radioreg_enter(wlc_phy_t *pih)
203 phy_info_t *pi = (phy_info_t *) pih;
204 wlapi_bmac_mctrl(pi->sh->physhim, MCTL_LOCK_RADIO, MCTL_LOCK_RADIO);
209 void wlc_radioreg_exit(wlc_phy_t *pih)
211 phy_info_t *pi = (phy_info_t *) pih;
214 dummy = R_REG(&pi->regs->phyversion);
216 wlapi_bmac_mctrl(pi->sh->physhim, MCTL_LOCK_RADIO, 0);
219 u16 read_radio_reg(phy_info_t *pi, u16 addr)
223 if ((addr == RADIO_IDCODE))
226 if (NORADIO_ENAB(pi->pubpi))
227 return NORADIO_IDCODE & 0xffff;
229 switch (pi->pubpi.phy_type) {
231 CASECHECK(PHYTYPE, PHY_TYPE_N);
232 if (NREV_GE(pi->pubpi.phy_rev, 7))
233 addr |= RADIO_2057_READ_OFF;
235 addr |= RADIO_2055_READ_OFF;
239 CASECHECK(PHYTYPE, PHY_TYPE_LCN);
240 addr |= RADIO_2064_READ_OFF;
247 if ((D11REV_GE(pi->sh->corerev, 24)) ||
248 (D11REV_IS(pi->sh->corerev, 22)
249 && (pi->pubpi.phy_type != PHY_TYPE_SSN))) {
250 W_REG(&pi->regs->radioregaddr, addr);
252 (void)R_REG(&pi->regs->radioregaddr);
254 data = R_REG(&pi->regs->radioregdata);
256 W_REG(&pi->regs->phy4waddr, addr);
258 (void)R_REG(&pi->regs->phy4waddr);
261 #ifdef __ARM_ARCH_4T__
262 __asm__(" .align 4 ");
264 data = R_REG(&pi->regs->phy4wdatalo);
266 data = R_REG(&pi->regs->phy4wdatalo);
275 void write_radio_reg(phy_info_t *pi, u16 addr, u16 val)
277 if (NORADIO_ENAB(pi->pubpi))
280 if ((D11REV_GE(pi->sh->corerev, 24)) ||
281 (D11REV_IS(pi->sh->corerev, 22)
282 && (pi->pubpi.phy_type != PHY_TYPE_SSN))) {
284 W_REG(&pi->regs->radioregaddr, addr);
286 (void)R_REG(&pi->regs->radioregaddr);
288 W_REG(&pi->regs->radioregdata, val);
290 W_REG(&pi->regs->phy4waddr, addr);
292 (void)R_REG(&pi->regs->phy4waddr);
294 W_REG(&pi->regs->phy4wdatalo, val);
297 if (pi->sh->bustype == PCI_BUS) {
298 if (++pi->phy_wreg >= pi->phy_wreg_limit) {
299 (void)R_REG(&pi->regs->maccontrol);
305 static u32 read_radio_id(phy_info_t *pi)
309 if (NORADIO_ENAB(pi->pubpi))
310 return NORADIO_IDCODE;
312 if (D11REV_GE(pi->sh->corerev, 24)) {
315 W_REG(&pi->regs->radioregaddr, 0);
317 (void)R_REG(&pi->regs->radioregaddr);
319 b0 = (u32) R_REG(&pi->regs->radioregdata);
320 W_REG(&pi->regs->radioregaddr, 1);
322 (void)R_REG(&pi->regs->radioregaddr);
324 b1 = (u32) R_REG(&pi->regs->radioregdata);
325 W_REG(&pi->regs->radioregaddr, 2);
327 (void)R_REG(&pi->regs->radioregaddr);
329 b2 = (u32) R_REG(&pi->regs->radioregdata);
331 id = ((b0 & 0xf) << 28) | (((b2 << 8) | b1) << 12) | ((b0 >> 4)
334 W_REG(&pi->regs->phy4waddr, RADIO_IDCODE);
336 (void)R_REG(&pi->regs->phy4waddr);
338 id = (u32) R_REG(&pi->regs->phy4wdatalo);
339 id |= (u32) R_REG(&pi->regs->phy4wdatahi) << 16;
345 void and_radio_reg(phy_info_t *pi, u16 addr, u16 val)
349 if (NORADIO_ENAB(pi->pubpi))
352 rval = read_radio_reg(pi, addr);
353 write_radio_reg(pi, addr, (rval & val));
356 void or_radio_reg(phy_info_t *pi, u16 addr, u16 val)
360 if (NORADIO_ENAB(pi->pubpi))
363 rval = read_radio_reg(pi, addr);
364 write_radio_reg(pi, addr, (rval | val));
367 void xor_radio_reg(phy_info_t *pi, u16 addr, u16 mask)
371 if (NORADIO_ENAB(pi->pubpi))
374 rval = read_radio_reg(pi, addr);
375 write_radio_reg(pi, addr, (rval ^ mask));
378 void mod_radio_reg(phy_info_t *pi, u16 addr, u16 mask, u16 val)
382 if (NORADIO_ENAB(pi->pubpi))
385 rval = read_radio_reg(pi, addr);
386 write_radio_reg(pi, addr, (rval & ~mask) | (val & mask));
389 void write_phy_channel_reg(phy_info_t *pi, uint val)
391 W_REG(&pi->regs->phychannel, val);
394 u16 read_phy_reg(phy_info_t *pi, u16 addr)
400 W_REG(®s->phyregaddr, addr);
402 (void)R_REG(®s->phyregaddr);
406 return R_REG(®s->phyregdata);
409 void write_phy_reg(phy_info_t *pi, u16 addr, u16 val)
416 W_REG(®s->phyregaddr, addr);
417 (void)R_REG(®s->phyregaddr);
418 W_REG(®s->phyregdata, val);
420 (void)R_REG(®s->phyregdata);
422 W_REG((u32 *)(®s->phyregaddr),
424 if (pi->sh->bustype == PCI_BUS) {
425 if (++pi->phy_wreg >= pi->phy_wreg_limit) {
427 (void)R_REG(®s->phyversion);
433 void and_phy_reg(phy_info_t *pi, u16 addr, u16 val)
439 W_REG(®s->phyregaddr, addr);
441 (void)R_REG(®s->phyregaddr);
444 W_REG(®s->phyregdata, (R_REG(®s->phyregdata) & val));
448 void or_phy_reg(phy_info_t *pi, u16 addr, u16 val)
454 W_REG(®s->phyregaddr, addr);
456 (void)R_REG(®s->phyregaddr);
459 W_REG(®s->phyregdata, (R_REG(®s->phyregdata) | val));
463 void mod_phy_reg(phy_info_t *pi, u16 addr, u16 mask, u16 val)
469 W_REG(®s->phyregaddr, addr);
471 (void)R_REG(®s->phyregaddr);
474 W_REG(®s->phyregdata,
475 ((R_REG(®s->phyregdata) & ~mask) | (val & mask)));
479 static void WLBANDINITFN(wlc_set_phy_uninitted) (phy_info_t *pi)
483 pi->initialized = false;
486 pi->nrssi_table_delta = 0x7fffffff;
488 pi->mintxbias = 0xffff;
491 pi->phy_spuravoid = SPURAVOID_DISABLE;
493 if (NREV_GE(pi->pubpi.phy_rev, 3)
494 && NREV_LT(pi->pubpi.phy_rev, 7))
495 pi->phy_spuravoid = SPURAVOID_AUTO;
497 pi->nphy_papd_skip = 0;
498 pi->nphy_papd_epsilon_offset[0] = 0xf588;
499 pi->nphy_papd_epsilon_offset[1] = 0xf588;
500 pi->nphy_txpwr_idx[0] = 128;
501 pi->nphy_txpwr_idx[1] = 128;
502 pi->nphy_txpwrindex[0].index_internal = 40;
503 pi->nphy_txpwrindex[1].index_internal = 40;
506 pi->phy_spuravoid = SPURAVOID_AUTO;
508 pi->radiopwr = 0xffff;
509 for (i = 0; i < STATIC_NUM_RF; i++) {
510 for (j = 0; j < STATIC_NUM_BB; j++) {
511 pi->stats_11b_txpower[i][j] = -1;
516 shared_phy_t *wlc_phy_shared_attach(shared_phy_params_t *shp)
520 sh = kzalloc(sizeof(shared_phy_t), GFP_ATOMIC);
526 sh->physhim = shp->physhim;
527 sh->unit = shp->unit;
528 sh->corerev = shp->corerev;
532 sh->chip = shp->chip;
533 sh->chiprev = shp->chiprev;
534 sh->chippkg = shp->chippkg;
535 sh->sromrev = shp->sromrev;
536 sh->boardtype = shp->boardtype;
537 sh->boardrev = shp->boardrev;
538 sh->boardvendor = shp->boardvendor;
539 sh->boardflags = shp->boardflags;
540 sh->boardflags2 = shp->boardflags2;
541 sh->bustype = shp->bustype;
542 sh->buscorerev = shp->buscorerev;
544 sh->fast_timer = PHY_SW_TIMER_FAST;
545 sh->slow_timer = PHY_SW_TIMER_SLOW;
546 sh->glacial_timer = PHY_SW_TIMER_GLACIAL;
548 sh->rssi_mode = RSSI_ANT_MERGE_MAX;
553 void wlc_phy_shared_detach(shared_phy_t *phy_sh)
560 wlc_phy_t *wlc_phy_attach(shared_phy_t *sh, void *regs, int bandtype,
561 char *vars, struct wiphy *wiphy)
568 if (D11REV_IS(sh->corerev, 4))
569 sflags = SISF_2G_PHY | SISF_5G_PHY;
571 sflags = ai_core_sflags(sh->sih, 0, 0);
573 if (BAND_5G(bandtype)) {
574 if ((sflags & (SISF_5G_PHY | SISF_DB_PHY)) == 0) {
580 if ((sflags & SISF_DB_PHY) && pi) {
582 wlapi_bmac_corereset(pi->sh->physhim, pi->pubpi.coreflags);
584 return &pi->pubpi_ro;
587 pi = kzalloc(sizeof(phy_info_t), GFP_ATOMIC);
592 pi->regs = (d11regs_t *) regs;
594 pi->phy_init_por = true;
595 pi->phy_wreg_limit = PHY_WREG_LIMIT;
599 pi->txpwr_percent = 100;
601 pi->do_initcal = true;
603 pi->phycal_tempdelta = 0;
605 if (BAND_2G(bandtype) && (sflags & SISF_2G_PHY)) {
607 pi->pubpi.coreflags = SICF_GMODE;
610 wlapi_bmac_corereset(pi->sh->physhim, pi->pubpi.coreflags);
611 phyversion = R_REG(&pi->regs->phyversion);
613 pi->pubpi.phy_type = PHY_TYPE(phyversion);
614 pi->pubpi.phy_rev = phyversion & PV_PV_MASK;
616 if (pi->pubpi.phy_type == PHY_TYPE_LCNXN) {
617 pi->pubpi.phy_type = PHY_TYPE_N;
618 pi->pubpi.phy_rev += LCNXN_BASEREV;
620 pi->pubpi.phy_corenum = PHY_CORE_NUM_2;
621 pi->pubpi.ana_rev = (phyversion & PV_AV_MASK) >> PV_AV_SHIFT;
623 if (!VALID_PHYTYPE(pi->pubpi.phy_type)) {
626 if (BAND_5G(bandtype)) {
631 if (!ISNPHY(pi) && !ISLCNPHY(pi)) {
636 if (ISSIM_ENAB(pi->sh->sih)) {
637 pi->pubpi.radioid = NORADIO_ID;
638 pi->pubpi.radiorev = 5;
642 wlc_phy_anacore((wlc_phy_t *) pi, ON);
644 idcode = wlc_phy_get_radio_ver(pi);
646 (idcode & IDCODE_ID_MASK) >> IDCODE_ID_SHIFT;
648 (idcode & IDCODE_REV_MASK) >> IDCODE_REV_SHIFT;
650 (idcode & IDCODE_VER_MASK) >> IDCODE_VER_SHIFT;
651 if (!VALID_RADIO(pi, pi->pubpi.radioid)) {
655 wlc_phy_switch_radio((wlc_phy_t *) pi, OFF);
658 wlc_set_phy_uninitted(pi);
660 pi->bw = WL_CHANSPEC_BW_20;
662 BAND_2G(bandtype) ? CH20MHZ_CHSPEC(1) : CH20MHZ_CHSPEC(36);
664 pi->rxiq_samps = PHY_NOISE_SAMPLE_LOG_NUM_NPHY;
665 pi->rxiq_antsel = ANT_RX_DIV_DEF;
667 pi->watchdog_override = true;
669 pi->cal_type_override = PHY_PERICAL_AUTO;
671 pi->nphy_saved_noisevars.bufcount = 0;
674 pi->min_txpower = PHY_TXPWR_MIN_NPHY;
676 pi->min_txpower = PHY_TXPWR_MIN;
678 pi->sh->phyrxchain = 0x3;
680 pi->rx2tx_biasentry = -1;
682 pi->phy_txcore_disable_temp = PHY_CHAIN_TX_DISABLE_TEMP;
683 pi->phy_txcore_enable_temp =
684 PHY_CHAIN_TX_DISABLE_TEMP - PHY_HYSTERESIS_DELTATEMP;
685 pi->phy_tempsense_offset = 0;
686 pi->phy_txcore_heatedup = false;
688 pi->nphy_lastcal_temp = -50;
690 pi->phynoise_polling = true;
691 if (ISNPHY(pi) || ISLCNPHY(pi))
692 pi->phynoise_polling = false;
694 for (i = 0; i < TXP_NUM_RATES; i++) {
695 pi->txpwr_limit[i] = WLC_TXPWR_MAX;
696 pi->txpwr_env_limit[i] = WLC_TXPWR_MAX;
697 pi->tx_user_target[i] = WLC_TXPWR_MAX;
700 pi->radiopwr_override = RADIOPWR_OVERRIDE_DEF;
702 pi->user_txpwr_at_rfport = false;
706 pi->phycal_timer = wlapi_init_timer(pi->sh->physhim,
707 wlc_phy_timercb_phycal,
709 if (!pi->phycal_timer) {
713 if (!wlc_phy_attach_nphy(pi))
716 } else if (ISLCNPHY(pi)) {
717 if (!wlc_phy_attach_lcnphy(pi))
725 pi->next = pi->sh->phy_head;
728 pi->vars = (char *)&pi->vars;
730 memcpy(&pi->pubpi_ro, &pi->pubpi, sizeof(wlc_phy_t));
732 return &pi->pubpi_ro;
739 void wlc_phy_detach(wlc_phy_t *pih)
741 phy_info_t *pi = (phy_info_t *) pih;
748 if (pi->phycal_timer) {
749 wlapi_free_timer(pi->sh->physhim, pi->phycal_timer);
750 pi->phycal_timer = NULL;
753 if (pi->sh->phy_head == pi)
754 pi->sh->phy_head = pi->next;
755 else if (pi->sh->phy_head->next == pi)
756 pi->sh->phy_head->next = NULL;
758 if (pi->pi_fptr.detach)
759 (pi->pi_fptr.detach) (pi);
766 wlc_phy_get_phyversion(wlc_phy_t *pih, u16 *phytype, u16 *phyrev,
767 u16 *radioid, u16 *radiover)
769 phy_info_t *pi = (phy_info_t *) pih;
770 *phytype = (u16) pi->pubpi.phy_type;
771 *phyrev = (u16) pi->pubpi.phy_rev;
772 *radioid = pi->pubpi.radioid;
773 *radiover = pi->pubpi.radiorev;
778 bool wlc_phy_get_encore(wlc_phy_t *pih)
780 phy_info_t *pi = (phy_info_t *) pih;
781 return pi->pubpi.abgphy_encore;
784 u32 wlc_phy_get_coreflags(wlc_phy_t *pih)
786 phy_info_t *pi = (phy_info_t *) pih;
787 return pi->pubpi.coreflags;
790 static void wlc_phy_timercb_phycal(void *arg)
792 phy_info_t *pi = (phy_info_t *) arg;
795 if (PHY_PERICAL_MPHASE_PENDING(pi)) {
797 wlc_phy_cal_perical_mphase_reset(pi);
801 if (SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi)) {
804 wlc_phy_cal_perical_mphase_restart(pi);
806 wlc_phy_cal_perical_nphy_run(pi, PHY_PERICAL_AUTO);
807 wlapi_add_timer(pi->sh->physhim, pi->phycal_timer, delay, 0);
813 void wlc_phy_anacore(wlc_phy_t *pih, bool on)
815 phy_info_t *pi = (phy_info_t *) pih;
819 if (NREV_GE(pi->pubpi.phy_rev, 3)) {
820 write_phy_reg(pi, 0xa6, 0x0d);
821 write_phy_reg(pi, 0x8f, 0x0);
822 write_phy_reg(pi, 0xa7, 0x0d);
823 write_phy_reg(pi, 0xa5, 0x0);
825 write_phy_reg(pi, 0xa5, 0x0);
828 if (NREV_GE(pi->pubpi.phy_rev, 3)) {
829 write_phy_reg(pi, 0x8f, 0x07ff);
830 write_phy_reg(pi, 0xa6, 0x0fd);
831 write_phy_reg(pi, 0xa5, 0x07ff);
832 write_phy_reg(pi, 0xa7, 0x0fd);
834 write_phy_reg(pi, 0xa5, 0x7fff);
837 } else if (ISLCNPHY(pi)) {
839 and_phy_reg(pi, 0x43b,
840 ~((0x1 << 0) | (0x1 << 1) | (0x1 << 2)));
842 or_phy_reg(pi, 0x43c,
843 (0x1 << 0) | (0x1 << 1) | (0x1 << 2));
844 or_phy_reg(pi, 0x43b,
845 (0x1 << 0) | (0x1 << 1) | (0x1 << 2));
850 u32 wlc_phy_clk_bwbits(wlc_phy_t *pih)
852 phy_info_t *pi = (phy_info_t *) pih;
854 u32 phy_bw_clkbits = 0;
856 if (pi && (ISNPHY(pi) || ISLCNPHY(pi))) {
858 case WL_CHANSPEC_BW_10:
859 phy_bw_clkbits = SICF_BW10;
861 case WL_CHANSPEC_BW_20:
862 phy_bw_clkbits = SICF_BW20;
864 case WL_CHANSPEC_BW_40:
865 phy_bw_clkbits = SICF_BW40;
872 return phy_bw_clkbits;
875 void WLBANDINITFN(wlc_phy_por_inform) (wlc_phy_t *ppi)
877 phy_info_t *pi = (phy_info_t *) ppi;
879 pi->phy_init_por = true;
882 void wlc_phy_edcrs_lock(wlc_phy_t *pih, bool lock)
884 phy_info_t *pi = (phy_info_t *) pih;
886 pi->edcrs_threshold_lock = lock;
888 write_phy_reg(pi, 0x22c, 0x46b);
889 write_phy_reg(pi, 0x22d, 0x46b);
890 write_phy_reg(pi, 0x22e, 0x3c0);
891 write_phy_reg(pi, 0x22f, 0x3c0);
894 void wlc_phy_initcal_enable(wlc_phy_t *pih, bool initcal)
896 phy_info_t *pi = (phy_info_t *) pih;
898 pi->do_initcal = initcal;
901 void wlc_phy_hw_clk_state_upd(wlc_phy_t *pih, bool newstate)
903 phy_info_t *pi = (phy_info_t *) pih;
908 pi->sh->clk = newstate;
911 void wlc_phy_hw_state_upd(wlc_phy_t *pih, bool newstate)
913 phy_info_t *pi = (phy_info_t *) pih;
918 pi->sh->up = newstate;
921 void WLBANDINITFN(wlc_phy_init) (wlc_phy_t *pih, chanspec_t chanspec)
924 initfn_t phy_init = NULL;
925 phy_info_t *pi = (phy_info_t *) pih;
927 if (pi->init_in_progress)
930 pi->init_in_progress = true;
932 pi->radio_chanspec = chanspec;
934 mc = R_REG(&pi->regs->maccontrol);
935 if (WARN(mc & MCTL_EN_MAC, "HW error MAC running on init"))
938 if (!(pi->measure_hold & PHY_HOLD_FOR_SCAN)) {
939 pi->measure_hold |= PHY_HOLD_FOR_NOT_ASSOC;
942 if (WARN(!(ai_core_sflags(pi->sh->sih, 0, 0) & SISF_FCLKA),
943 "HW error SISF_FCLKA\n"))
946 phy_init = pi->pi_fptr.init;
948 if (phy_init == NULL) {
952 wlc_phy_anacore(pih, ON);
954 if (CHSPEC_BW(pi->radio_chanspec) != pi->bw)
955 wlapi_bmac_bw_set(pi->sh->physhim,
956 CHSPEC_BW(pi->radio_chanspec));
958 pi->nphy_gain_boost = true;
960 wlc_phy_switch_radio((wlc_phy_t *) pi, ON);
964 pi->phy_init_por = false;
966 if (D11REV_IS(pi->sh->corerev, 11) || D11REV_IS(pi->sh->corerev, 12))
967 wlc_phy_do_dummy_tx(pi, true, OFF);
970 wlc_phy_txpower_update_shm(pi);
972 wlc_phy_ant_rxdiv_set((wlc_phy_t *) pi, pi->sh->rx_antdiv);
974 pi->init_in_progress = false;
977 void wlc_phy_cal_init(wlc_phy_t *pih)
979 phy_info_t *pi = (phy_info_t *) pih;
980 initfn_t cal_init = NULL;
982 if (WARN((R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC) != 0,
983 "HW error: MAC enabled during phy cal\n"))
986 if (!pi->initialized) {
987 cal_init = pi->pi_fptr.calinit;
991 pi->initialized = true;
995 int wlc_phy_down(wlc_phy_t *pih)
997 phy_info_t *pi = (phy_info_t *) pih;
1000 if (pi->phycal_timer
1001 && !wlapi_del_timer(pi->sh->physhim, pi->phycal_timer))
1004 pi->nphy_iqcal_chanspec_2G = 0;
1005 pi->nphy_iqcal_chanspec_5G = 0;
1010 static u32 wlc_phy_get_radio_ver(phy_info_t *pi)
1014 ver = read_radio_id(pi);
1020 wlc_phy_table_addr(phy_info_t *pi, uint tbl_id, uint tbl_offset,
1021 u16 tblAddr, u16 tblDataHi, u16 tblDataLo)
1023 write_phy_reg(pi, tblAddr, (tbl_id << 10) | tbl_offset);
1025 pi->tbl_data_hi = tblDataHi;
1026 pi->tbl_data_lo = tblDataLo;
1028 if ((pi->sh->chip == BCM43224_CHIP_ID ||
1029 pi->sh->chip == BCM43421_CHIP_ID) &&
1030 (pi->sh->chiprev == 1)) {
1031 pi->tbl_addr = tblAddr;
1032 pi->tbl_save_id = tbl_id;
1033 pi->tbl_save_offset = tbl_offset;
1037 void wlc_phy_table_data_write(phy_info_t *pi, uint width, u32 val)
1039 if ((pi->sh->chip == BCM43224_CHIP_ID ||
1040 pi->sh->chip == BCM43421_CHIP_ID) &&
1041 (pi->sh->chiprev == 1) &&
1042 (pi->tbl_save_id == NPHY_TBL_ID_ANTSWCTRLLUT)) {
1043 read_phy_reg(pi, pi->tbl_data_lo);
1045 write_phy_reg(pi, pi->tbl_addr,
1046 (pi->tbl_save_id << 10) | pi->tbl_save_offset);
1047 pi->tbl_save_offset++;
1052 write_phy_reg(pi, pi->tbl_data_hi, (u16) (val >> 16));
1053 write_phy_reg(pi, pi->tbl_data_lo, (u16) val);
1056 write_phy_reg(pi, pi->tbl_data_lo, (u16) val);
1061 wlc_phy_write_table(phy_info_t *pi, const phytbl_info_t *ptbl_info,
1062 u16 tblAddr, u16 tblDataHi, u16 tblDataLo)
1065 uint tbl_id = ptbl_info->tbl_id;
1066 uint tbl_offset = ptbl_info->tbl_offset;
1067 uint tbl_width = ptbl_info->tbl_width;
1068 const u8 *ptbl_8b = (const u8 *)ptbl_info->tbl_ptr;
1069 const u16 *ptbl_16b = (const u16 *)ptbl_info->tbl_ptr;
1070 const u32 *ptbl_32b = (const u32 *)ptbl_info->tbl_ptr;
1072 write_phy_reg(pi, tblAddr, (tbl_id << 10) | tbl_offset);
1074 for (idx = 0; idx < ptbl_info->tbl_len; idx++) {
1076 if ((pi->sh->chip == BCM43224_CHIP_ID ||
1077 pi->sh->chip == BCM43421_CHIP_ID) &&
1078 (pi->sh->chiprev == 1) &&
1079 (tbl_id == NPHY_TBL_ID_ANTSWCTRLLUT)) {
1080 read_phy_reg(pi, tblDataLo);
1082 write_phy_reg(pi, tblAddr,
1083 (tbl_id << 10) | (tbl_offset + idx));
1086 if (tbl_width == 32) {
1088 write_phy_reg(pi, tblDataHi,
1089 (u16) (ptbl_32b[idx] >> 16));
1090 write_phy_reg(pi, tblDataLo, (u16) ptbl_32b[idx]);
1091 } else if (tbl_width == 16) {
1093 write_phy_reg(pi, tblDataLo, ptbl_16b[idx]);
1096 write_phy_reg(pi, tblDataLo, ptbl_8b[idx]);
1102 wlc_phy_read_table(phy_info_t *pi, const phytbl_info_t *ptbl_info,
1103 u16 tblAddr, u16 tblDataHi, u16 tblDataLo)
1106 uint tbl_id = ptbl_info->tbl_id;
1107 uint tbl_offset = ptbl_info->tbl_offset;
1108 uint tbl_width = ptbl_info->tbl_width;
1109 u8 *ptbl_8b = (u8 *)ptbl_info->tbl_ptr;
1110 u16 *ptbl_16b = (u16 *)ptbl_info->tbl_ptr;
1111 u32 *ptbl_32b = (u32 *)ptbl_info->tbl_ptr;
1113 write_phy_reg(pi, tblAddr, (tbl_id << 10) | tbl_offset);
1115 for (idx = 0; idx < ptbl_info->tbl_len; idx++) {
1117 if ((pi->sh->chip == BCM43224_CHIP_ID ||
1118 pi->sh->chip == BCM43421_CHIP_ID) &&
1119 (pi->sh->chiprev == 1)) {
1120 (void)read_phy_reg(pi, tblDataLo);
1122 write_phy_reg(pi, tblAddr,
1123 (tbl_id << 10) | (tbl_offset + idx));
1126 if (tbl_width == 32) {
1128 ptbl_32b[idx] = read_phy_reg(pi, tblDataLo);
1129 ptbl_32b[idx] |= (read_phy_reg(pi, tblDataHi) << 16);
1130 } else if (tbl_width == 16) {
1132 ptbl_16b[idx] = read_phy_reg(pi, tblDataLo);
1135 ptbl_8b[idx] = (u8) read_phy_reg(pi, tblDataLo);
1141 wlc_phy_init_radio_regs_allbands(phy_info_t *pi, radio_20xx_regs_t *radioregs)
1146 if (radioregs[i].do_init) {
1147 write_radio_reg(pi, radioregs[i].address,
1148 (u16) radioregs[i].init);
1152 } while (radioregs[i].address != 0xffff);
1158 wlc_phy_init_radio_regs(phy_info_t *pi, radio_regs_t *radioregs,
1165 if (CHSPEC_IS5G(pi->radio_chanspec)) {
1166 if (radioregs[i].do_init_a) {
1169 address | core_offset,
1170 (u16) radioregs[i].init_a);
1171 if (ISNPHY(pi) && (++count % 4 == 0))
1172 WLC_PHY_WAR_PR51571(pi);
1175 if (radioregs[i].do_init_g) {
1178 address | core_offset,
1179 (u16) radioregs[i].init_g);
1180 if (ISNPHY(pi) && (++count % 4 == 0))
1181 WLC_PHY_WAR_PR51571(pi);
1186 } while (radioregs[i].address != 0xffff);
1191 void wlc_phy_do_dummy_tx(phy_info_t *pi, bool ofdm, bool pa_on)
1193 #define DUMMY_PKT_LEN 20
1194 d11regs_t *regs = pi->regs;
1196 u8 ofdmpkt[DUMMY_PKT_LEN] = {
1197 0xcc, 0x01, 0x02, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00,
1198 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00
1200 u8 cckpkt[DUMMY_PKT_LEN] = {
1201 0x6e, 0x84, 0x0b, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00,
1202 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00
1206 dummypkt = (u32 *) (ofdm ? ofdmpkt : cckpkt);
1207 wlapi_bmac_write_template_ram(pi->sh->physhim, 0, DUMMY_PKT_LEN,
1210 W_REG(®s->xmtsel, 0);
1212 if (D11REV_GE(pi->sh->corerev, 11))
1213 W_REG(®s->wepctl, 0x100);
1215 W_REG(®s->wepctl, 0);
1217 W_REG(®s->txe_phyctl, (ofdm ? 1 : 0) | PHY_TXC_ANT_0);
1218 if (ISNPHY(pi) || ISLCNPHY(pi)) {
1219 W_REG(®s->txe_phyctl1, 0x1A02);
1222 W_REG(®s->txe_wm_0, 0);
1223 W_REG(®s->txe_wm_1, 0);
1225 W_REG(®s->xmttplatetxptr, 0);
1226 W_REG(®s->xmttxcnt, DUMMY_PKT_LEN);
1228 W_REG(®s->xmtsel, ((8 << 8) | (1 << 5) | (1 << 2) | 2));
1230 W_REG(®s->txe_ctl, 0);
1234 wlc_phy_pa_override_nphy(pi, OFF);
1237 if (ISNPHY(pi) || ISLCNPHY(pi))
1238 W_REG(®s->txe_aux, 0xD0);
1240 W_REG(®s->txe_aux, ((1 << 5) | (1 << 4)));
1242 (void)R_REG(®s->txe_aux);
1245 count = ofdm ? 30 : 250;
1247 if (ISSIM_ENAB(pi->sh->sih)) {
1251 while ((i++ < count)
1252 && (R_REG(®s->txe_status) & (1 << 7))) {
1259 && ((R_REG(®s->txe_status) & (1 << 10)) == 0)) {
1265 while ((i++ < 10) && ((R_REG(®s->ifsstat) & (1 << 8))))
1270 wlc_phy_pa_override_nphy(pi, ON);
1274 void wlc_phy_hold_upd(wlc_phy_t *pih, mbool id, bool set)
1276 phy_info_t *pi = (phy_info_t *) pih;
1279 mboolset(pi->measure_hold, id);
1281 mboolclr(pi->measure_hold, id);
1287 void wlc_phy_mute_upd(wlc_phy_t *pih, bool mute, mbool flags)
1289 phy_info_t *pi = (phy_info_t *) pih;
1292 mboolset(pi->measure_hold, PHY_HOLD_FOR_MUTE);
1294 mboolclr(pi->measure_hold, PHY_HOLD_FOR_MUTE);
1297 if (!mute && (flags & PHY_MUTE_FOR_PREISM))
1298 pi->nphy_perical_last = pi->sh->now - pi->sh->glacial_timer;
1302 void wlc_phy_clear_tssi(wlc_phy_t *pih)
1304 phy_info_t *pi = (phy_info_t *) pih;
1309 wlapi_bmac_write_shm(pi->sh->physhim, M_B_TSSI_0, NULL_TSSI_W);
1310 wlapi_bmac_write_shm(pi->sh->physhim, M_B_TSSI_1, NULL_TSSI_W);
1311 wlapi_bmac_write_shm(pi->sh->physhim, M_G_TSSI_0, NULL_TSSI_W);
1312 wlapi_bmac_write_shm(pi->sh->physhim, M_G_TSSI_1, NULL_TSSI_W);
1316 static bool wlc_phy_cal_txpower_recalc_sw(phy_info_t *pi)
1321 void wlc_phy_switch_radio(wlc_phy_t *pih, bool on)
1323 phy_info_t *pi = (phy_info_t *) pih;
1325 if (NORADIO_ENAB(pi->pubpi))
1331 mc = R_REG(&pi->regs->maccontrol);
1335 wlc_phy_switch_radio_nphy(pi, on);
1337 } else if (ISLCNPHY(pi)) {
1339 and_phy_reg(pi, 0x44c,
1342 (0x1 << 10) | (0x1 << 11) | (0x1 << 12)));
1343 and_phy_reg(pi, 0x4b0, ~((0x1 << 3) | (0x1 << 11)));
1344 and_phy_reg(pi, 0x4f9, ~(0x1 << 3));
1346 and_phy_reg(pi, 0x44d,
1349 (0x1 << 12) | (0x1 << 13) | (0x1 << 14)));
1350 or_phy_reg(pi, 0x44c,
1353 (0x1 << 10) | (0x1 << 11) | (0x1 << 12));
1355 and_phy_reg(pi, 0x4b7, ~((0x7f << 8)));
1356 and_phy_reg(pi, 0x4b1, ~((0x1 << 13)));
1357 or_phy_reg(pi, 0x4b0, (0x1 << 3) | (0x1 << 11));
1358 and_phy_reg(pi, 0x4fa, ~((0x1 << 3)));
1359 or_phy_reg(pi, 0x4f9, (0x1 << 3));
1364 u16 wlc_phy_bw_state_get(wlc_phy_t *ppi)
1366 phy_info_t *pi = (phy_info_t *) ppi;
1371 void wlc_phy_bw_state_set(wlc_phy_t *ppi, u16 bw)
1373 phy_info_t *pi = (phy_info_t *) ppi;
1378 void wlc_phy_chanspec_radio_set(wlc_phy_t *ppi, chanspec_t newch)
1380 phy_info_t *pi = (phy_info_t *) ppi;
1381 pi->radio_chanspec = newch;
1385 chanspec_t wlc_phy_chanspec_get(wlc_phy_t *ppi)
1387 phy_info_t *pi = (phy_info_t *) ppi;
1389 return pi->radio_chanspec;
1392 void wlc_phy_chanspec_set(wlc_phy_t *ppi, chanspec_t chanspec)
1394 phy_info_t *pi = (phy_info_t *) ppi;
1396 chansetfn_t chanspec_set = NULL;
1398 m_cur_channel = CHSPEC_CHANNEL(chanspec);
1399 if (CHSPEC_IS5G(chanspec))
1400 m_cur_channel |= D11_CURCHANNEL_5G;
1401 if (CHSPEC_IS40(chanspec))
1402 m_cur_channel |= D11_CURCHANNEL_40;
1403 wlapi_bmac_write_shm(pi->sh->physhim, M_CURCHANNEL, m_cur_channel);
1405 chanspec_set = pi->pi_fptr.chanset;
1407 (*chanspec_set) (pi, chanspec);
1411 int wlc_phy_chanspec_freq2bandrange_lpssn(uint freq)
1416 range = WL_CHAN_FREQ_RANGE_2G;
1417 else if (freq <= 5320)
1418 range = WL_CHAN_FREQ_RANGE_5GL;
1419 else if (freq <= 5700)
1420 range = WL_CHAN_FREQ_RANGE_5GM;
1422 range = WL_CHAN_FREQ_RANGE_5GH;
1427 int wlc_phy_chanspec_bandrange_get(phy_info_t *pi, chanspec_t chanspec)
1430 uint channel = CHSPEC_CHANNEL(chanspec);
1431 uint freq = wlc_phy_channel2freq(channel);
1434 range = wlc_phy_get_chan_freq_range_nphy(pi, channel);
1435 } else if (ISLCNPHY(pi)) {
1436 range = wlc_phy_chanspec_freq2bandrange_lpssn(freq);
1442 void wlc_phy_chanspec_ch14_widefilter_set(wlc_phy_t *ppi, bool wide_filter)
1444 phy_info_t *pi = (phy_info_t *) ppi;
1446 pi->channel_14_wide_filter = wide_filter;
1450 int wlc_phy_channel2freq(uint channel)
1454 for (i = 0; i < ARRAY_SIZE(chan_info_all); i++)
1455 if (chan_info_all[i].chan == channel)
1456 return chan_info_all[i].freq;
1461 wlc_phy_chanspec_band_validch(wlc_phy_t *ppi, uint band, chanvec_t *channels)
1463 phy_info_t *pi = (phy_info_t *) ppi;
1467 memset(channels, 0, sizeof(chanvec_t));
1469 for (i = 0; i < ARRAY_SIZE(chan_info_all); i++) {
1470 channel = chan_info_all[i].chan;
1472 if ((pi->a_band_high_disable) && (channel >= FIRST_REF5_CHANNUM)
1473 && (channel <= LAST_REF5_CHANNUM))
1476 if (((band == WLC_BAND_2G) && (channel <= CH_MAX_2G_CHANNEL)) ||
1477 ((band == WLC_BAND_5G) && (channel > CH_MAX_2G_CHANNEL)))
1478 setbit(channels->vec, channel);
1482 chanspec_t wlc_phy_chanspec_band_firstch(wlc_phy_t *ppi, uint band)
1484 phy_info_t *pi = (phy_info_t *) ppi;
1489 for (i = 0; i < ARRAY_SIZE(chan_info_all); i++) {
1490 channel = chan_info_all[i].chan;
1492 if (ISNPHY(pi) && IS40MHZ(pi)) {
1495 for (j = 0; j < ARRAY_SIZE(chan_info_all); j++) {
1496 if (chan_info_all[j].chan ==
1497 channel + CH_10MHZ_APART)
1501 if (j == ARRAY_SIZE(chan_info_all))
1504 channel = UPPER_20_SB(channel);
1506 channel | WL_CHANSPEC_BW_40 |
1507 WL_CHANSPEC_CTL_SB_LOWER;
1508 if (band == WLC_BAND_2G)
1509 chspec |= WL_CHANSPEC_BAND_2G;
1511 chspec |= WL_CHANSPEC_BAND_5G;
1513 chspec = CH20MHZ_CHSPEC(channel);
1515 if ((pi->a_band_high_disable) && (channel >= FIRST_REF5_CHANNUM)
1516 && (channel <= LAST_REF5_CHANNUM))
1519 if (((band == WLC_BAND_2G) && (channel <= CH_MAX_2G_CHANNEL)) ||
1520 ((band == WLC_BAND_5G) && (channel > CH_MAX_2G_CHANNEL)))
1524 return (chanspec_t) INVCHANSPEC;
1527 int wlc_phy_txpower_get(wlc_phy_t *ppi, uint *qdbm, bool *override)
1529 phy_info_t *pi = (phy_info_t *) ppi;
1531 *qdbm = pi->tx_user_target[0];
1532 if (override != NULL)
1533 *override = pi->txpwroverride;
1537 void wlc_phy_txpower_target_set(wlc_phy_t *ppi, struct txpwr_limits *txpwr)
1539 bool mac_enabled = false;
1540 phy_info_t *pi = (phy_info_t *) ppi;
1542 memcpy(&pi->tx_user_target[TXP_FIRST_CCK],
1543 &txpwr->cck[0], WLC_NUM_RATES_CCK);
1545 memcpy(&pi->tx_user_target[TXP_FIRST_OFDM],
1546 &txpwr->ofdm[0], WLC_NUM_RATES_OFDM);
1547 memcpy(&pi->tx_user_target[TXP_FIRST_OFDM_20_CDD],
1548 &txpwr->ofdm_cdd[0], WLC_NUM_RATES_OFDM);
1550 memcpy(&pi->tx_user_target[TXP_FIRST_OFDM_40_SISO],
1551 &txpwr->ofdm_40_siso[0], WLC_NUM_RATES_OFDM);
1552 memcpy(&pi->tx_user_target[TXP_FIRST_OFDM_40_CDD],
1553 &txpwr->ofdm_40_cdd[0], WLC_NUM_RATES_OFDM);
1555 memcpy(&pi->tx_user_target[TXP_FIRST_MCS_20_SISO],
1556 &txpwr->mcs_20_siso[0], WLC_NUM_RATES_MCS_1_STREAM);
1557 memcpy(&pi->tx_user_target[TXP_FIRST_MCS_20_CDD],
1558 &txpwr->mcs_20_cdd[0], WLC_NUM_RATES_MCS_1_STREAM);
1559 memcpy(&pi->tx_user_target[TXP_FIRST_MCS_20_STBC],
1560 &txpwr->mcs_20_stbc[0], WLC_NUM_RATES_MCS_1_STREAM);
1561 memcpy(&pi->tx_user_target[TXP_FIRST_MCS_20_SDM],
1562 &txpwr->mcs_20_mimo[0], WLC_NUM_RATES_MCS_2_STREAM);
1564 memcpy(&pi->tx_user_target[TXP_FIRST_MCS_40_SISO],
1565 &txpwr->mcs_40_siso[0], WLC_NUM_RATES_MCS_1_STREAM);
1566 memcpy(&pi->tx_user_target[TXP_FIRST_MCS_40_CDD],
1567 &txpwr->mcs_40_cdd[0], WLC_NUM_RATES_MCS_1_STREAM);
1568 memcpy(&pi->tx_user_target[TXP_FIRST_MCS_40_STBC],
1569 &txpwr->mcs_40_stbc[0], WLC_NUM_RATES_MCS_1_STREAM);
1570 memcpy(&pi->tx_user_target[TXP_FIRST_MCS_40_SDM],
1571 &txpwr->mcs_40_mimo[0], WLC_NUM_RATES_MCS_2_STREAM);
1573 if (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC)
1577 wlapi_suspend_mac_and_wait(pi->sh->physhim);
1579 wlc_phy_txpower_recalc_target(pi);
1580 wlc_phy_cal_txpower_recalc_sw(pi);
1583 wlapi_enable_mac(pi->sh->physhim);
1586 int wlc_phy_txpower_set(wlc_phy_t *ppi, uint qdbm, bool override)
1588 phy_info_t *pi = (phy_info_t *) ppi;
1594 for (i = 0; i < TXP_NUM_RATES; i++)
1595 pi->tx_user_target[i] = (u8) qdbm;
1597 pi->txpwroverride = false;
1600 if (!SCAN_INPROG_PHY(pi)) {
1605 (R_REG(&pi->regs->maccontrol) &
1609 wlapi_suspend_mac_and_wait(pi->sh->physhim);
1611 wlc_phy_txpower_recalc_target(pi);
1612 wlc_phy_cal_txpower_recalc_sw(pi);
1615 wlapi_enable_mac(pi->sh->physhim);
1622 wlc_phy_txpower_sromlimit(wlc_phy_t *ppi, uint channel, u8 *min_pwr,
1623 u8 *max_pwr, int txp_rate_idx)
1625 phy_info_t *pi = (phy_info_t *) ppi;
1628 *min_pwr = pi->min_txpower * WLC_TXPWR_DB_FACTOR;
1631 if (txp_rate_idx < 0)
1632 txp_rate_idx = TXP_FIRST_CCK;
1633 wlc_phy_txpower_sromlimit_get_nphy(pi, channel, max_pwr,
1636 } else if ((channel <= CH_MAX_2G_CHANNEL)) {
1637 if (txp_rate_idx < 0)
1638 txp_rate_idx = TXP_FIRST_CCK;
1639 *max_pwr = pi->tx_srom_max_rate_2g[txp_rate_idx];
1642 *max_pwr = WLC_TXPWR_MAX;
1644 if (txp_rate_idx < 0)
1645 txp_rate_idx = TXP_FIRST_OFDM;
1647 for (i = 0; i < ARRAY_SIZE(chan_info_all); i++) {
1648 if (channel == chan_info_all[i].chan) {
1654 *max_pwr = pi->hwtxpwr[i];
1657 if ((i >= FIRST_MID_5G_CHAN) && (i <= LAST_MID_5G_CHAN))
1659 pi->tx_srom_max_rate_5g_mid[txp_rate_idx];
1660 if ((i >= FIRST_HIGH_5G_CHAN)
1661 && (i <= LAST_HIGH_5G_CHAN))
1663 pi->tx_srom_max_rate_5g_hi[txp_rate_idx];
1664 if ((i >= FIRST_LOW_5G_CHAN) && (i <= LAST_LOW_5G_CHAN))
1666 pi->tx_srom_max_rate_5g_low[txp_rate_idx];
1672 wlc_phy_txpower_sromlimit_max_get(wlc_phy_t *ppi, uint chan, u8 *max_txpwr,
1675 phy_info_t *pi = (phy_info_t *) ppi;
1677 u8 tx_pwr_min = 255;
1679 u8 maxtxpwr, mintxpwr, rate, pactrl;
1683 max_num_rate = ISNPHY(pi) ? TXP_NUM_RATES :
1684 ISLCNPHY(pi) ? (TXP_LAST_SISO_MCS_20 + 1) : (TXP_LAST_OFDM + 1);
1686 for (rate = 0; rate < max_num_rate; rate++) {
1688 wlc_phy_txpower_sromlimit(ppi, chan, &mintxpwr, &maxtxpwr,
1691 maxtxpwr = (maxtxpwr > pactrl) ? (maxtxpwr - pactrl) : 0;
1693 maxtxpwr = (maxtxpwr > 6) ? (maxtxpwr - 6) : 0;
1695 tx_pwr_max = max(tx_pwr_max, maxtxpwr);
1696 tx_pwr_min = min(tx_pwr_min, maxtxpwr);
1698 *max_txpwr = tx_pwr_max;
1699 *min_txpwr = tx_pwr_min;
1703 wlc_phy_txpower_boardlimit_band(wlc_phy_t *ppi, uint bandunit, s32 *max_pwr,
1704 s32 *min_pwr, u32 *step_pwr)
1709 u8 wlc_phy_txpower_get_target_min(wlc_phy_t *ppi)
1711 phy_info_t *pi = (phy_info_t *) ppi;
1713 return pi->tx_power_min;
1716 u8 wlc_phy_txpower_get_target_max(wlc_phy_t *ppi)
1718 phy_info_t *pi = (phy_info_t *) ppi;
1720 return pi->tx_power_max;
1723 void wlc_phy_txpower_recalc_target(phy_info_t *pi)
1725 u8 maxtxpwr, mintxpwr, rate, pactrl;
1727 u8 tx_pwr_target[TXP_NUM_RATES];
1729 u8 tx_pwr_min = 255;
1730 u8 tx_pwr_max_rate_ind = 0;
1734 u32 band = CHSPEC2WLC_BAND(pi->radio_chanspec);
1735 initfn_t txpwr_recalc_fn = NULL;
1737 chspec = pi->radio_chanspec;
1738 if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_NONE)
1739 target_chan = CHSPEC_CHANNEL(chspec);
1740 else if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_UPPER)
1741 target_chan = UPPER_20_SB(CHSPEC_CHANNEL(chspec));
1743 target_chan = LOWER_20_SB(CHSPEC_CHANNEL(chspec));
1749 if (CHSPEC_IS40(pi->radio_chanspec)) {
1750 offset_mcs = pi->mcs40_po;
1751 for (i = TXP_FIRST_SISO_MCS_20;
1752 i <= TXP_LAST_SISO_MCS_20; i++) {
1753 pi->tx_srom_max_rate_2g[i - 8] =
1754 pi->tx_srom_max_2g -
1755 ((offset_mcs & 0xf) * 2);
1759 offset_mcs = pi->mcs20_po;
1760 for (i = TXP_FIRST_SISO_MCS_20;
1761 i <= TXP_LAST_SISO_MCS_20; i++) {
1762 pi->tx_srom_max_rate_2g[i - 8] =
1763 pi->tx_srom_max_2g -
1764 ((offset_mcs & 0xf) * 2);
1770 max_num_rate = ((ISNPHY(pi)) ? (TXP_NUM_RATES) :
1772 (TXP_LAST_SISO_MCS_20 + 1) : (TXP_LAST_OFDM + 1)));
1774 max_num_rate = ((ISNPHY(pi)) ? (TXP_NUM_RATES) : (TXP_LAST_OFDM + 1));
1777 wlc_phy_upd_env_txpwr_rate_limits(pi, band);
1779 for (rate = start_rate; rate < max_num_rate; rate++) {
1781 tx_pwr_target[rate] = pi->tx_user_target[rate];
1783 if (pi->user_txpwr_at_rfport) {
1784 tx_pwr_target[rate] +=
1785 wlc_user_txpwr_antport_to_rfport(pi, target_chan,
1791 wlc_phy_txpower_sromlimit((wlc_phy_t *) pi, target_chan,
1792 &mintxpwr, &maxtxpwr, rate);
1794 maxtxpwr = min(maxtxpwr, pi->txpwr_limit[rate]);
1797 (maxtxpwr > pactrl) ? (maxtxpwr - pactrl) : 0;
1799 maxtxpwr = (maxtxpwr > 6) ? (maxtxpwr - 6) : 0;
1801 maxtxpwr = min(maxtxpwr, tx_pwr_target[rate]);
1803 if (pi->txpwr_percent <= 100)
1804 maxtxpwr = (maxtxpwr * pi->txpwr_percent) / 100;
1806 tx_pwr_target[rate] = max(maxtxpwr, mintxpwr);
1809 tx_pwr_target[rate] =
1810 min(tx_pwr_target[rate], pi->txpwr_env_limit[rate]);
1812 if (tx_pwr_target[rate] > tx_pwr_max)
1813 tx_pwr_max_rate_ind = rate;
1815 tx_pwr_max = max(tx_pwr_max, tx_pwr_target[rate]);
1816 tx_pwr_min = min(tx_pwr_min, tx_pwr_target[rate]);
1819 memset(pi->tx_power_offset, 0, sizeof(pi->tx_power_offset));
1820 pi->tx_power_max = tx_pwr_max;
1821 pi->tx_power_min = tx_pwr_min;
1822 pi->tx_power_max_rate_ind = tx_pwr_max_rate_ind;
1823 for (rate = 0; rate < max_num_rate; rate++) {
1825 pi->tx_power_target[rate] = tx_pwr_target[rate];
1827 if (!pi->hwpwrctrl || ISNPHY(pi)) {
1828 pi->tx_power_offset[rate] =
1829 pi->tx_power_max - pi->tx_power_target[rate];
1831 pi->tx_power_offset[rate] =
1832 pi->tx_power_target[rate] - pi->tx_power_min;
1836 txpwr_recalc_fn = pi->pi_fptr.txpwrrecalc;
1837 if (txpwr_recalc_fn)
1838 (*txpwr_recalc_fn) (pi);
1842 wlc_phy_txpower_reg_limit_calc(phy_info_t *pi, struct txpwr_limits *txpwr,
1843 chanspec_t chanspec)
1845 u8 tmp_txpwr_limit[2 * WLC_NUM_RATES_OFDM];
1846 u8 *txpwr_ptr1 = NULL, *txpwr_ptr2 = NULL;
1847 int rate_start_index = 0, rate1, rate2, k;
1849 for (rate1 = WL_TX_POWER_CCK_FIRST, rate2 = 0;
1850 rate2 < WL_TX_POWER_CCK_NUM; rate1++, rate2++)
1851 pi->txpwr_limit[rate1] = txpwr->cck[rate2];
1853 for (rate1 = WL_TX_POWER_OFDM_FIRST, rate2 = 0;
1854 rate2 < WL_TX_POWER_OFDM_NUM; rate1++, rate2++)
1855 pi->txpwr_limit[rate1] = txpwr->ofdm[rate2];
1859 for (k = 0; k < 4; k++) {
1863 txpwr_ptr1 = txpwr->mcs_20_siso;
1864 txpwr_ptr2 = txpwr->ofdm;
1865 rate_start_index = WL_TX_POWER_OFDM_FIRST;
1869 txpwr_ptr1 = txpwr->mcs_20_cdd;
1870 txpwr_ptr2 = txpwr->ofdm_cdd;
1871 rate_start_index = WL_TX_POWER_OFDM20_CDD_FIRST;
1875 txpwr_ptr1 = txpwr->mcs_40_siso;
1876 txpwr_ptr2 = txpwr->ofdm_40_siso;
1878 WL_TX_POWER_OFDM40_SISO_FIRST;
1882 txpwr_ptr1 = txpwr->mcs_40_cdd;
1883 txpwr_ptr2 = txpwr->ofdm_40_cdd;
1884 rate_start_index = WL_TX_POWER_OFDM40_CDD_FIRST;
1888 for (rate2 = 0; rate2 < WLC_NUM_RATES_OFDM; rate2++) {
1889 tmp_txpwr_limit[rate2] = 0;
1890 tmp_txpwr_limit[WLC_NUM_RATES_OFDM + rate2] =
1893 wlc_phy_mcs_to_ofdm_powers_nphy(tmp_txpwr_limit, 0,
1894 WLC_NUM_RATES_OFDM - 1,
1895 WLC_NUM_RATES_OFDM);
1896 for (rate1 = rate_start_index, rate2 = 0;
1897 rate2 < WLC_NUM_RATES_OFDM; rate1++, rate2++)
1898 pi->txpwr_limit[rate1] =
1899 min(txpwr_ptr2[rate2],
1900 tmp_txpwr_limit[rate2]);
1903 for (k = 0; k < 4; k++) {
1907 txpwr_ptr1 = txpwr->ofdm;
1908 txpwr_ptr2 = txpwr->mcs_20_siso;
1909 rate_start_index = WL_TX_POWER_MCS20_SISO_FIRST;
1913 txpwr_ptr1 = txpwr->ofdm_cdd;
1914 txpwr_ptr2 = txpwr->mcs_20_cdd;
1915 rate_start_index = WL_TX_POWER_MCS20_CDD_FIRST;
1919 txpwr_ptr1 = txpwr->ofdm_40_siso;
1920 txpwr_ptr2 = txpwr->mcs_40_siso;
1921 rate_start_index = WL_TX_POWER_MCS40_SISO_FIRST;
1925 txpwr_ptr1 = txpwr->ofdm_40_cdd;
1926 txpwr_ptr2 = txpwr->mcs_40_cdd;
1927 rate_start_index = WL_TX_POWER_MCS40_CDD_FIRST;
1930 for (rate2 = 0; rate2 < WLC_NUM_RATES_OFDM; rate2++) {
1931 tmp_txpwr_limit[rate2] = 0;
1932 tmp_txpwr_limit[WLC_NUM_RATES_OFDM + rate2] =
1935 wlc_phy_ofdm_to_mcs_powers_nphy(tmp_txpwr_limit, 0,
1936 WLC_NUM_RATES_OFDM - 1,
1937 WLC_NUM_RATES_OFDM);
1938 for (rate1 = rate_start_index, rate2 = 0;
1939 rate2 < WLC_NUM_RATES_MCS_1_STREAM;
1941 pi->txpwr_limit[rate1] =
1942 min(txpwr_ptr2[rate2],
1943 tmp_txpwr_limit[rate2]);
1946 for (k = 0; k < 2; k++) {
1950 rate_start_index = WL_TX_POWER_MCS20_STBC_FIRST;
1951 txpwr_ptr1 = txpwr->mcs_20_stbc;
1955 rate_start_index = WL_TX_POWER_MCS40_STBC_FIRST;
1956 txpwr_ptr1 = txpwr->mcs_40_stbc;
1959 for (rate1 = rate_start_index, rate2 = 0;
1960 rate2 < WLC_NUM_RATES_MCS_1_STREAM;
1962 pi->txpwr_limit[rate1] = txpwr_ptr1[rate2];
1965 for (k = 0; k < 2; k++) {
1969 rate_start_index = WL_TX_POWER_MCS20_SDM_FIRST;
1970 txpwr_ptr1 = txpwr->mcs_20_mimo;
1974 rate_start_index = WL_TX_POWER_MCS40_SDM_FIRST;
1975 txpwr_ptr1 = txpwr->mcs_40_mimo;
1978 for (rate1 = rate_start_index, rate2 = 0;
1979 rate2 < WLC_NUM_RATES_MCS_2_STREAM;
1981 pi->txpwr_limit[rate1] = txpwr_ptr1[rate2];
1984 pi->txpwr_limit[WL_TX_POWER_MCS_32] = txpwr->mcs32;
1986 pi->txpwr_limit[WL_TX_POWER_MCS40_CDD_FIRST] =
1987 min(pi->txpwr_limit[WL_TX_POWER_MCS40_CDD_FIRST],
1988 pi->txpwr_limit[WL_TX_POWER_MCS_32]);
1989 pi->txpwr_limit[WL_TX_POWER_MCS_32] =
1990 pi->txpwr_limit[WL_TX_POWER_MCS40_CDD_FIRST];
1994 void wlc_phy_txpwr_percent_set(wlc_phy_t *ppi, u8 txpwr_percent)
1996 phy_info_t *pi = (phy_info_t *) ppi;
1998 pi->txpwr_percent = txpwr_percent;
2001 void wlc_phy_machwcap_set(wlc_phy_t *ppi, u32 machwcap)
2003 phy_info_t *pi = (phy_info_t *) ppi;
2005 pi->sh->machwcap = machwcap;
2008 void wlc_phy_runbist_config(wlc_phy_t *ppi, bool start_end)
2010 phy_info_t *pi = (phy_info_t *) ppi;
2014 if (start_end == ON) {
2018 if (NREV_IS(pi->pubpi.phy_rev, 3)
2019 || NREV_IS(pi->pubpi.phy_rev, 4)) {
2020 W_REG(&pi->regs->phyregaddr, 0xa0);
2021 (void)R_REG(&pi->regs->phyregaddr);
2022 rxc = R_REG(&pi->regs->phyregdata);
2023 W_REG(&pi->regs->phyregdata,
2027 if (NREV_IS(pi->pubpi.phy_rev, 3)
2028 || NREV_IS(pi->pubpi.phy_rev, 4)) {
2029 W_REG(&pi->regs->phyregaddr, 0xa0);
2030 (void)R_REG(&pi->regs->phyregaddr);
2031 W_REG(&pi->regs->phyregdata, rxc);
2034 wlc_phy_por_inform(ppi);
2039 wlc_phy_txpower_limit_set(wlc_phy_t *ppi, struct txpwr_limits *txpwr,
2040 chanspec_t chanspec)
2042 phy_info_t *pi = (phy_info_t *) ppi;
2044 wlc_phy_txpower_reg_limit_calc(pi, txpwr, chanspec);
2048 for (i = TXP_FIRST_OFDM_20_CDD, j = 0;
2049 j < WLC_NUM_RATES_MCS_1_STREAM; i++, j++) {
2050 if (txpwr->mcs_20_siso[j])
2051 pi->txpwr_limit[i] = txpwr->mcs_20_siso[j];
2053 pi->txpwr_limit[i] = txpwr->ofdm[j];
2057 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2059 wlc_phy_txpower_recalc_target(pi);
2060 wlc_phy_cal_txpower_recalc_sw(pi);
2061 wlapi_enable_mac(pi->sh->physhim);
2064 void wlc_phy_ofdm_rateset_war(wlc_phy_t *pih, bool war)
2066 phy_info_t *pi = (phy_info_t *) pih;
2068 pi->ofdm_rateset_war = war;
2071 void wlc_phy_bf_preempt_enable(wlc_phy_t *pih, bool bf_preempt)
2073 phy_info_t *pi = (phy_info_t *) pih;
2075 pi->bf_preempt_4306 = bf_preempt;
2078 void wlc_phy_txpower_update_shm(phy_info_t *pi)
2088 if (pi->hwpwrctrl) {
2091 wlapi_bmac_write_shm(pi->sh->physhim, M_TXPWR_MAX, 63);
2092 wlapi_bmac_write_shm(pi->sh->physhim, M_TXPWR_N,
2093 1 << NUM_TSSI_FRAMES);
2095 wlapi_bmac_write_shm(pi->sh->physhim, M_TXPWR_TARGET,
2096 pi->tx_power_min << NUM_TSSI_FRAMES);
2098 wlapi_bmac_write_shm(pi->sh->physhim, M_TXPWR_CUR,
2101 for (j = TXP_FIRST_OFDM; j <= TXP_LAST_OFDM; j++) {
2102 const u8 ucode_ofdm_rates[] = {
2103 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c
2105 offset = wlapi_bmac_rate_shm_offset(pi->sh->physhim,
2106 ucode_ofdm_rates[j -
2108 wlapi_bmac_write_shm(pi->sh->physhim, offset + 6,
2109 pi->tx_power_offset[j]);
2110 wlapi_bmac_write_shm(pi->sh->physhim, offset + 14,
2111 -(pi->tx_power_offset[j] / 2));
2114 wlapi_bmac_mhf(pi->sh->physhim, MHF2, MHF2_HWPWRCTL,
2115 MHF2_HWPWRCTL, WLC_BAND_ALL);
2119 for (i = TXP_FIRST_OFDM; i <= TXP_LAST_OFDM; i++)
2120 pi->tx_power_offset[i] =
2121 (u8) roundup(pi->tx_power_offset[i], 8);
2122 wlapi_bmac_write_shm(pi->sh->physhim, M_OFDM_OFFSET,
2124 tx_power_offset[TXP_FIRST_OFDM]
2129 bool wlc_phy_txpower_hw_ctrl_get(wlc_phy_t *ppi)
2131 phy_info_t *pi = (phy_info_t *) ppi;
2134 return pi->nphy_txpwrctrl;
2136 return pi->hwpwrctrl;
2140 void wlc_phy_txpower_hw_ctrl_set(wlc_phy_t *ppi, bool hwpwrctrl)
2142 phy_info_t *pi = (phy_info_t *) ppi;
2143 bool cur_hwpwrctrl = pi->hwpwrctrl;
2146 if (!pi->hwpwrctrl_capable) {
2150 pi->hwpwrctrl = hwpwrctrl;
2151 pi->nphy_txpwrctrl = hwpwrctrl;
2152 pi->txpwrctrl = hwpwrctrl;
2157 (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC));
2159 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2161 wlc_phy_txpwrctrl_enable_nphy(pi, pi->nphy_txpwrctrl);
2162 if (pi->nphy_txpwrctrl == PHY_TPC_HW_OFF) {
2163 wlc_phy_txpwr_fixpower_nphy(pi);
2166 mod_phy_reg(pi, 0x1e7, (0x7f << 0),
2167 pi->saved_txpwr_idx);
2171 wlapi_enable_mac(pi->sh->physhim);
2172 } else if (hwpwrctrl != cur_hwpwrctrl) {
2178 void wlc_phy_txpower_ipa_upd(phy_info_t *pi)
2181 if (NREV_GE(pi->pubpi.phy_rev, 3)) {
2182 pi->ipa2g_on = (pi->srom_fem2g.extpagain == 2);
2183 pi->ipa5g_on = (pi->srom_fem5g.extpagain == 2);
2185 pi->ipa2g_on = false;
2186 pi->ipa5g_on = false;
2190 static u32 wlc_phy_txpower_est_power_nphy(phy_info_t *pi);
2192 static u32 wlc_phy_txpower_est_power_nphy(phy_info_t *pi)
2194 s16 tx0_status, tx1_status;
2195 u16 estPower1, estPower2;
2196 u8 pwr0, pwr1, adj_pwr0, adj_pwr1;
2199 estPower1 = read_phy_reg(pi, 0x118);
2200 estPower2 = read_phy_reg(pi, 0x119);
2202 if ((estPower1 & (0x1 << 8))
2204 pwr0 = (u8) (estPower1 & (0xff << 0))
2210 if ((estPower2 & (0x1 << 8))
2212 pwr1 = (u8) (estPower2 & (0xff << 0))
2218 tx0_status = read_phy_reg(pi, 0x1ed);
2219 tx1_status = read_phy_reg(pi, 0x1ee);
2221 if ((tx0_status & (0x1 << 15))
2223 adj_pwr0 = (u8) (tx0_status & (0xff << 0))
2228 if ((tx1_status & (0x1 << 15))
2230 adj_pwr1 = (u8) (tx1_status & (0xff << 0))
2237 (u32) ((pwr0 << 24) | (pwr1 << 16) | (adj_pwr0 << 8) | adj_pwr1);
2242 wlc_phy_txpower_get_current(wlc_phy_t *ppi, tx_power_t *power, uint channel)
2244 phy_info_t *pi = (phy_info_t *) ppi;
2245 uint rate, num_rates;
2246 u8 min_pwr, max_pwr;
2248 #if WL_TX_POWER_RATES != TXP_NUM_RATES
2249 #error "tx_power_t struct out of sync with this fn"
2253 power->rf_cores = 2;
2254 power->flags |= (WL_TX_POWER_F_MIMO);
2255 if (pi->nphy_txpwrctrl == PHY_TPC_HW_ON)
2257 (WL_TX_POWER_F_ENABLED | WL_TX_POWER_F_HW);
2258 } else if (ISLCNPHY(pi)) {
2259 power->rf_cores = 1;
2260 power->flags |= (WL_TX_POWER_F_SISO);
2261 if (pi->radiopwr_override == RADIOPWR_OVERRIDE_DEF)
2262 power->flags |= WL_TX_POWER_F_ENABLED;
2264 power->flags |= WL_TX_POWER_F_HW;
2267 num_rates = ((ISNPHY(pi)) ? (TXP_NUM_RATES) :
2269 (TXP_LAST_OFDM_20_CDD + 1) : (TXP_LAST_OFDM + 1)));
2271 for (rate = 0; rate < num_rates; rate++) {
2272 power->user_limit[rate] = pi->tx_user_target[rate];
2273 wlc_phy_txpower_sromlimit(ppi, channel, &min_pwr, &max_pwr,
2275 power->board_limit[rate] = (u8) max_pwr;
2276 power->target[rate] = pi->tx_power_target[rate];
2282 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2283 wlc_phyreg_enter((wlc_phy_t *) pi);
2284 est_pout = wlc_phy_txpower_est_power_nphy(pi);
2285 wlc_phyreg_exit((wlc_phy_t *) pi);
2286 wlapi_enable_mac(pi->sh->physhim);
2288 power->est_Pout[0] = (est_pout >> 8) & 0xff;
2289 power->est_Pout[1] = est_pout & 0xff;
2291 power->est_Pout_act[0] = est_pout >> 24;
2292 power->est_Pout_act[1] = (est_pout >> 16) & 0xff;
2294 if (power->est_Pout[0] == 0x80)
2295 power->est_Pout[0] = 0;
2296 if (power->est_Pout[1] == 0x80)
2297 power->est_Pout[1] = 0;
2299 if (power->est_Pout_act[0] == 0x80)
2300 power->est_Pout_act[0] = 0;
2301 if (power->est_Pout_act[1] == 0x80)
2302 power->est_Pout_act[1] = 0;
2304 power->est_Pout_cck = 0;
2306 power->tx_power_max[0] = pi->tx_power_max;
2307 power->tx_power_max[1] = pi->tx_power_max;
2309 power->tx_power_max_rate_ind[0] = pi->tx_power_max_rate_ind;
2310 power->tx_power_max_rate_ind[1] = pi->tx_power_max_rate_ind;
2311 } else if (!pi->hwpwrctrl) {
2312 } else if (pi->sh->up) {
2314 wlc_phyreg_enter(ppi);
2317 power->tx_power_max[0] = pi->tx_power_max;
2318 power->tx_power_max[1] = pi->tx_power_max;
2320 power->tx_power_max_rate_ind[0] =
2321 pi->tx_power_max_rate_ind;
2322 power->tx_power_max_rate_ind[1] =
2323 pi->tx_power_max_rate_ind;
2325 if (wlc_phy_tpc_isenabled_lcnphy(pi))
2327 (WL_TX_POWER_F_HW | WL_TX_POWER_F_ENABLED);
2330 ~(WL_TX_POWER_F_HW | WL_TX_POWER_F_ENABLED);
2332 wlc_lcnphy_get_tssi(pi, (s8 *) &power->est_Pout[0],
2333 (s8 *) &power->est_Pout_cck);
2335 wlc_phyreg_exit(ppi);
2339 void wlc_phy_antsel_type_set(wlc_phy_t *ppi, u8 antsel_type)
2341 phy_info_t *pi = (phy_info_t *) ppi;
2343 pi->antsel_type = antsel_type;
2346 bool wlc_phy_test_ison(wlc_phy_t *ppi)
2348 phy_info_t *pi = (phy_info_t *) ppi;
2350 return pi->phytest_on;
2353 bool wlc_phy_ant_rxdiv_get(wlc_phy_t *ppi, u8 *pval)
2355 phy_info_t *pi = (phy_info_t *) ppi;
2358 wlc_phyreg_enter(ppi);
2363 } else if (ISLCNPHY(pi)) {
2364 u16 crsctrl = read_phy_reg(pi, 0x410);
2365 u16 div = crsctrl & (0x1 << 1);
2366 *pval = (div | ((crsctrl & (0x1 << 0)) ^ (div >> 1)));
2369 wlc_phyreg_exit(ppi);
2374 void wlc_phy_ant_rxdiv_set(wlc_phy_t *ppi, u8 val)
2376 phy_info_t *pi = (phy_info_t *) ppi;
2379 pi->sh->rx_antdiv = val;
2381 if (!(ISNPHY(pi) && D11REV_IS(pi->sh->corerev, 16))) {
2382 if (val > ANT_RX_DIV_FORCE_1)
2383 wlapi_bmac_mhf(pi->sh->physhim, MHF1, MHF1_ANTDIV,
2384 MHF1_ANTDIV, WLC_BAND_ALL);
2386 wlapi_bmac_mhf(pi->sh->physhim, MHF1, MHF1_ANTDIV, 0,
2399 (0 == (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC));
2401 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2404 if (val > ANT_RX_DIV_FORCE_1) {
2405 mod_phy_reg(pi, 0x410, (0x1 << 1), 0x01 << 1);
2406 mod_phy_reg(pi, 0x410,
2408 ((ANT_RX_DIV_START_1 == val) ? 1 : 0) << 0);
2410 mod_phy_reg(pi, 0x410, (0x1 << 1), 0x00 << 1);
2411 mod_phy_reg(pi, 0x410, (0x1 << 0), (u16) val << 0);
2416 wlapi_enable_mac(pi->sh->physhim);
2422 wlc_phy_noise_calc_phy(phy_info_t *pi, u32 *cmplx_pwr, s8 *pwr_ant)
2424 s8 cmplx_pwr_dbm[PHY_CORE_MAX];
2427 memset((u8 *) cmplx_pwr_dbm, 0, sizeof(cmplx_pwr_dbm));
2428 wlc_phy_compute_dB(cmplx_pwr, cmplx_pwr_dbm, pi->pubpi.phy_corenum);
2430 for (i = 0; i < pi->pubpi.phy_corenum; i++) {
2431 if (NREV_GE(pi->pubpi.phy_rev, 3))
2432 cmplx_pwr_dbm[i] += (s8) PHY_NOISE_OFFSETFACT_4322;
2435 cmplx_pwr_dbm[i] += (s8) (16 - (15) * 3 - 70);
2438 for (i = 0; i < pi->pubpi.phy_corenum; i++) {
2439 pi->nphy_noise_win[i][pi->nphy_noise_index] = cmplx_pwr_dbm[i];
2440 pwr_ant[i] = cmplx_pwr_dbm[i];
2442 pi->nphy_noise_index =
2443 MODINC_POW2(pi->nphy_noise_index, PHY_NOISE_WINDOW_SZ);
2448 wlc_phy_noise_sample_request(wlc_phy_t *pih, u8 reason, u8 ch)
2450 phy_info_t *pi = (phy_info_t *) pih;
2451 s8 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;
2452 bool sampling_in_progress = (pi->phynoise_state != 0);
2453 bool wait_for_intr = true;
2455 if (NORADIO_ENAB(pi->pubpi)) {
2460 case PHY_NOISE_SAMPLE_MON:
2462 pi->phynoise_chan_watchdog = ch;
2463 pi->phynoise_state |= PHY_NOISE_STATE_MON;
2467 case PHY_NOISE_SAMPLE_EXTERNAL:
2469 pi->phynoise_state |= PHY_NOISE_STATE_EXTERNAL;
2476 if (sampling_in_progress)
2479 pi->phynoise_now = pi->sh->now;
2481 if (pi->phy_fixed_noise) {
2483 pi->nphy_noise_win[WL_ANT_IDX_1][pi->nphy_noise_index] =
2484 PHY_NOISE_FIXED_VAL_NPHY;
2485 pi->nphy_noise_win[WL_ANT_IDX_2][pi->nphy_noise_index] =
2486 PHY_NOISE_FIXED_VAL_NPHY;
2487 pi->nphy_noise_index = MODINC_POW2(pi->nphy_noise_index,
2488 PHY_NOISE_WINDOW_SZ);
2490 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;
2493 noise_dbm = PHY_NOISE_FIXED_VAL;
2496 wait_for_intr = false;
2501 if (!pi->phynoise_polling
2502 || (reason == PHY_NOISE_SAMPLE_EXTERNAL)) {
2503 wlapi_bmac_write_shm(pi->sh->physhim, M_JSSI_0, 0);
2504 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP0, 0);
2505 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP1, 0);
2506 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP2, 0);
2507 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP3, 0);
2509 OR_REG(&pi->regs->maccommand,
2512 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2513 wlc_lcnphy_deaf_mode(pi, (bool) 0);
2514 noise_dbm = (s8) wlc_lcnphy_rx_signal_power(pi, 20);
2515 wlc_lcnphy_deaf_mode(pi, (bool) 1);
2516 wlapi_enable_mac(pi->sh->physhim);
2517 wait_for_intr = false;
2519 } else if (ISNPHY(pi)) {
2520 if (!pi->phynoise_polling
2521 || (reason == PHY_NOISE_SAMPLE_EXTERNAL)) {
2523 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP0, 0);
2524 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP1, 0);
2525 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP2, 0);
2526 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP3, 0);
2528 OR_REG(&pi->regs->maccommand,
2531 phy_iq_est_t est[PHY_CORE_MAX];
2532 u32 cmplx_pwr[PHY_CORE_MAX];
2533 s8 noise_dbm_ant[PHY_CORE_MAX];
2534 u16 log_num_samps, num_samps, classif_state = 0;
2539 memset((u8 *) est, 0, sizeof(est));
2540 memset((u8 *) cmplx_pwr, 0, sizeof(cmplx_pwr));
2541 memset((u8 *) noise_dbm_ant, 0, sizeof(noise_dbm_ant));
2543 log_num_samps = PHY_NOISE_SAMPLE_LOG_NUM_NPHY;
2544 num_samps = 1 << log_num_samps;
2546 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2547 classif_state = wlc_phy_classifier_nphy(pi, 0, 0);
2548 wlc_phy_classifier_nphy(pi, 3, 0);
2549 wlc_phy_rx_iq_est_nphy(pi, est, num_samps, wait_time,
2551 wlc_phy_classifier_nphy(pi, (0x7 << 0), classif_state);
2552 wlapi_enable_mac(pi->sh->physhim);
2554 for (i = 0; i < pi->pubpi.phy_corenum; i++)
2557 est[i].q_pwr) >> log_num_samps;
2559 wlc_phy_noise_calc_phy(pi, cmplx_pwr, noise_dbm_ant);
2561 for (i = 0; i < pi->pubpi.phy_corenum; i++) {
2562 pi->nphy_noise_win[i][pi->nphy_noise_index] =
2565 if (noise_dbm_ant[i] > noise_dbm)
2566 noise_dbm = noise_dbm_ant[i];
2568 pi->nphy_noise_index = MODINC_POW2(pi->nphy_noise_index,
2569 PHY_NOISE_WINDOW_SZ);
2571 wait_for_intr = false;
2578 wlc_phy_noise_cb(pi, ch, noise_dbm);
2582 void wlc_phy_noise_sample_request_external(wlc_phy_t *pih)
2586 channel = CHSPEC_CHANNEL(wlc_phy_chanspec_get(pih));
2588 wlc_phy_noise_sample_request(pih, PHY_NOISE_SAMPLE_EXTERNAL, channel);
2591 static void wlc_phy_noise_cb(phy_info_t *pi, u8 channel, s8 noise_dbm)
2593 if (!pi->phynoise_state)
2596 if (pi->phynoise_state & PHY_NOISE_STATE_MON) {
2597 if (pi->phynoise_chan_watchdog == channel) {
2598 pi->sh->phy_noise_window[pi->sh->phy_noise_index] =
2600 pi->sh->phy_noise_index =
2601 MODINC(pi->sh->phy_noise_index, MA_WINDOW_SZ);
2603 pi->phynoise_state &= ~PHY_NOISE_STATE_MON;
2606 if (pi->phynoise_state & PHY_NOISE_STATE_EXTERNAL) {
2607 pi->phynoise_state &= ~PHY_NOISE_STATE_EXTERNAL;
2612 static s8 wlc_phy_noise_read_shmem(phy_info_t *pi)
2614 u32 cmplx_pwr[PHY_CORE_MAX];
2615 s8 noise_dbm_ant[PHY_CORE_MAX];
2617 u32 cmplx_pwr_tot = 0;
2618 s8 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;
2621 memset((u8 *) cmplx_pwr, 0, sizeof(cmplx_pwr));
2622 memset((u8 *) noise_dbm_ant, 0, sizeof(noise_dbm_ant));
2624 for (idx = 0, core = 0; core < pi->pubpi.phy_corenum; idx += 2, core++) {
2625 lo = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP(idx));
2626 hi = wlapi_bmac_read_shm(pi->sh->physhim,
2627 M_PWRIND_MAP(idx + 1));
2628 cmplx_pwr[core] = (hi << 16) + lo;
2629 cmplx_pwr_tot += cmplx_pwr[core];
2630 if (cmplx_pwr[core] == 0) {
2631 noise_dbm_ant[core] = PHY_NOISE_FIXED_VAL_NPHY;
2633 cmplx_pwr[core] >>= PHY_NOISE_SAMPLE_LOG_NUM_UCODE;
2636 if (cmplx_pwr_tot != 0)
2637 wlc_phy_noise_calc_phy(pi, cmplx_pwr, noise_dbm_ant);
2639 for (core = 0; core < pi->pubpi.phy_corenum; core++) {
2640 pi->nphy_noise_win[core][pi->nphy_noise_index] =
2641 noise_dbm_ant[core];
2643 if (noise_dbm_ant[core] > noise_dbm)
2644 noise_dbm = noise_dbm_ant[core];
2646 pi->nphy_noise_index =
2647 MODINC_POW2(pi->nphy_noise_index, PHY_NOISE_WINDOW_SZ);
2653 void wlc_phy_noise_sample_intr(wlc_phy_t *pih)
2655 phy_info_t *pi = (phy_info_t *) pih;
2658 s8 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;
2661 u32 cmplx_pwr, cmplx_pwr0, cmplx_pwr1;
2663 s32 pwr_offset_dB, gain_dB;
2664 u16 status_0, status_1;
2666 jssi_aux = wlapi_bmac_read_shm(pi->sh->physhim, M_JSSI_AUX);
2667 channel = jssi_aux & D11_CURCHANNEL_MAX;
2669 lo = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP0);
2670 hi = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP1);
2671 cmplx_pwr0 = (hi << 16) + lo;
2673 lo = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP2);
2674 hi = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP3);
2675 cmplx_pwr1 = (hi << 16) + lo;
2676 cmplx_pwr = (cmplx_pwr0 + cmplx_pwr1) >> 6;
2679 status_1 = wlapi_bmac_read_shm(pi->sh->physhim, M_JSSI_0);
2680 if ((cmplx_pwr > 0 && cmplx_pwr < 500)
2681 && ((status_1 & 0xc000) == 0x4000)) {
2683 wlc_phy_compute_dB(&cmplx_pwr, &noise_dbm,
2684 pi->pubpi.phy_corenum);
2685 pwr_offset_dB = (read_phy_reg(pi, 0x434) & 0xFF);
2686 if (pwr_offset_dB > 127)
2687 pwr_offset_dB -= 256;
2689 noise_dbm += (s8) (pwr_offset_dB - 30);
2691 gain_dB = (status_0 & 0x1ff);
2692 noise_dbm -= (s8) (gain_dB);
2694 noise_dbm = PHY_NOISE_FIXED_VAL_LCNPHY;
2696 } else if (ISNPHY(pi)) {
2698 jssi_aux = wlapi_bmac_read_shm(pi->sh->physhim, M_JSSI_AUX);
2699 channel = jssi_aux & D11_CURCHANNEL_MAX;
2701 noise_dbm = wlc_phy_noise_read_shmem(pi);
2704 wlc_phy_noise_cb(pi, channel, noise_dbm);
2708 s8 lcnphy_gain_index_offset_for_pkt_rssi[] = {
2749 void wlc_phy_compute_dB(u32 *cmplx_pwr, s8 *p_cmplx_pwr_dB, u8 core)
2751 u8 msb, secondmsb, i;
2754 for (i = 0; i < core; i++) {
2759 secondmsb = (u8) ((tmp >> (--msb - 1)) & 1);
2760 p_cmplx_pwr_dB[i] = (s8) (3 * msb + 2 * secondmsb);
2764 void wlc_phy_rssi_compute(wlc_phy_t *pih, void *ctx)
2766 wlc_d11rxhdr_t *wlc_rxhdr = (wlc_d11rxhdr_t *) ctx;
2767 d11rxhdr_t *rxh = &wlc_rxhdr->rxhdr;
2768 int rssi = le16_to_cpu(rxh->PhyRxStatus_1) & PRXS1_JSSI_MASK;
2769 uint radioid = pih->radioid;
2770 phy_info_t *pi = (phy_info_t *) pih;
2772 if (NORADIO_ENAB(pi->pubpi)) {
2773 rssi = WLC_RSSI_INVALID;
2777 if ((pi->sh->corerev >= 11)
2778 && !(le16_to_cpu(rxh->RxStatus2) & RXS_PHYRXST_VALID)) {
2779 rssi = WLC_RSSI_INVALID;
2784 u8 gidx = (le16_to_cpu(rxh->PhyRxStatus_2) & 0xFC00) >> 10;
2785 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
2790 rssi = rssi + lcnphy_gain_index_offset_for_pkt_rssi[gidx];
2791 if ((rssi > -46) && (gidx > 18))
2794 rssi = rssi + pi_lcn->lcnphy_pkteng_rssi_slope;
2804 } else if (radioid == BCM2055_ID || radioid == BCM2056_ID
2805 || radioid == BCM2057_ID) {
2806 rssi = wlc_phy_rssi_compute_nphy(pi, wlc_rxhdr);
2810 wlc_rxhdr->rssi = (s8) rssi;
2813 void wlc_phy_freqtrack_start(wlc_phy_t *pih)
2818 void wlc_phy_freqtrack_end(wlc_phy_t *pih)
2823 void wlc_phy_set_deaf(wlc_phy_t *ppi, bool user_flag)
2826 pi = (phy_info_t *) ppi;
2829 wlc_lcnphy_deaf_mode(pi, true);
2830 else if (ISNPHY(pi))
2831 wlc_nphy_deaf_mode(pi, true);
2834 void wlc_phy_watchdog(wlc_phy_t *pih)
2836 phy_info_t *pi = (phy_info_t *) pih;
2837 bool delay_phy_cal = false;
2840 if (!pi->watchdog_override)
2843 if (!(SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi))) {
2844 wlc_phy_noise_sample_request((wlc_phy_t *) pi,
2845 PHY_NOISE_SAMPLE_MON,
2850 if (pi->phynoise_state && (pi->sh->now - pi->phynoise_now) > 5) {
2851 pi->phynoise_state = 0;
2854 if ((!pi->phycal_txpower) ||
2855 ((pi->sh->now - pi->phycal_txpower) >= pi->sh->fast_timer)) {
2857 if (!SCAN_INPROG_PHY(pi) && wlc_phy_cal_txpower_recalc_sw(pi)) {
2858 pi->phycal_txpower = pi->sh->now;
2862 if (NORADIO_ENAB(pi->pubpi))
2865 if ((SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi)
2866 || ASSOC_INPROG_PHY(pi)))
2869 if (ISNPHY(pi) && !pi->disable_percal && !delay_phy_cal) {
2871 if ((pi->nphy_perical != PHY_PERICAL_DISABLE) &&
2872 (pi->nphy_perical != PHY_PERICAL_MANUAL) &&
2873 ((pi->sh->now - pi->nphy_perical_last) >=
2874 pi->sh->glacial_timer))
2875 wlc_phy_cal_perical((wlc_phy_t *) pi,
2876 PHY_PERICAL_WATCHDOG);
2878 wlc_phy_txpwr_papd_cal_nphy(pi);
2882 if (pi->phy_forcecal ||
2883 ((pi->sh->now - pi->phy_lastcal) >=
2884 pi->sh->glacial_timer)) {
2885 if (!(SCAN_RM_IN_PROGRESS(pi) || ASSOC_INPROG_PHY(pi)))
2886 wlc_lcnphy_calib_modes(pi,
2887 LCNPHY_PERICAL_TEMPBASED_TXPWRCTRL);
2889 (SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi)
2890 || ASSOC_INPROG_PHY(pi)
2891 || pi->carrier_suppr_disable
2892 || pi->disable_percal))
2893 wlc_lcnphy_calib_modes(pi,
2894 PHY_PERICAL_WATCHDOG);
2899 void wlc_phy_BSSinit(wlc_phy_t *pih, bool bonlyap, int rssi)
2901 phy_info_t *pi = (phy_info_t *) pih;
2905 for (i = 0; i < MA_WINDOW_SZ; i++) {
2906 pi->sh->phy_noise_window[i] = (s8) (rssi & 0xff);
2909 for (i = 0; i < MA_WINDOW_SZ; i++)
2910 pi->sh->phy_noise_window[i] =
2911 PHY_NOISE_FIXED_VAL_LCNPHY;
2913 pi->sh->phy_noise_index = 0;
2915 for (i = 0; i < PHY_NOISE_WINDOW_SZ; i++) {
2916 for (k = WL_ANT_IDX_1; k < WL_ANT_RX_MAX; k++)
2917 pi->nphy_noise_win[k][i] = PHY_NOISE_FIXED_VAL_NPHY;
2919 pi->nphy_noise_index = 0;
2923 wlc_phy_papd_decode_epsilon(u32 epsilon, s32 *eps_real, s32 *eps_imag)
2925 *eps_imag = (epsilon >> 13);
2926 if (*eps_imag > 0xfff)
2927 *eps_imag -= 0x2000;
2929 *eps_real = (epsilon & 0x1fff);
2930 if (*eps_real > 0xfff)
2931 *eps_real -= 0x2000;
2934 static const fixed AtanTbl[] = {
2955 void wlc_phy_cordic(fixed theta, cs32 *val)
2957 fixed angle, valtmp;
2962 val[0].i = CORDIC_AG;
2966 signtheta = (theta < 0) ? -1 : 1;
2968 ((theta + FIXED(180) * signtheta) % FIXED(360)) -
2969 FIXED(180) * signtheta;
2971 if (FLOAT(theta) > 90) {
2972 theta -= FIXED(180);
2974 } else if (FLOAT(theta) < -90) {
2975 theta += FIXED(180);
2979 for (iter = 0; iter < CORDIC_NI; iter++) {
2980 if (theta > angle) {
2981 valtmp = val[0].i - (val[0].q >> iter);
2982 val[0].q = (val[0].i >> iter) + val[0].q;
2984 angle += AtanTbl[iter];
2986 valtmp = val[0].i + (val[0].q >> iter);
2987 val[0].q = -(val[0].i >> iter) + val[0].q;
2989 angle -= AtanTbl[iter];
2993 val[0].i = val[0].i * signx;
2994 val[0].q = val[0].q * signx;
2997 void wlc_phy_cal_perical_mphase_reset(phy_info_t *pi)
2999 wlapi_del_timer(pi->sh->physhim, pi->phycal_timer);
3001 pi->cal_type_override = PHY_PERICAL_AUTO;
3002 pi->mphase_cal_phase_id = MPHASE_CAL_STATE_IDLE;
3003 pi->mphase_txcal_cmdidx = 0;
3006 static void wlc_phy_cal_perical_mphase_schedule(phy_info_t *pi, uint delay)
3009 if ((pi->nphy_perical != PHY_PERICAL_MPHASE) &&
3010 (pi->nphy_perical != PHY_PERICAL_MANUAL))
3013 wlapi_del_timer(pi->sh->physhim, pi->phycal_timer);
3015 pi->mphase_cal_phase_id = MPHASE_CAL_STATE_INIT;
3016 wlapi_add_timer(pi->sh->physhim, pi->phycal_timer, delay, 0);
3019 void wlc_phy_cal_perical(wlc_phy_t *pih, u8 reason)
3021 s16 nphy_currtemp = 0;
3023 bool do_periodic_cal = true;
3024 phy_info_t *pi = (phy_info_t *) pih;
3029 if ((pi->nphy_perical == PHY_PERICAL_DISABLE) ||
3030 (pi->nphy_perical == PHY_PERICAL_MANUAL))
3034 case PHY_PERICAL_DRIVERUP:
3037 case PHY_PERICAL_PHYINIT:
3038 if (pi->nphy_perical == PHY_PERICAL_MPHASE) {
3039 if (PHY_PERICAL_MPHASE_PENDING(pi)) {
3040 wlc_phy_cal_perical_mphase_reset(pi);
3042 wlc_phy_cal_perical_mphase_schedule(pi,
3043 PHY_PERICAL_INIT_DELAY);
3047 case PHY_PERICAL_JOIN_BSS:
3048 case PHY_PERICAL_START_IBSS:
3049 case PHY_PERICAL_UP_BSS:
3050 if ((pi->nphy_perical == PHY_PERICAL_MPHASE) &&
3051 PHY_PERICAL_MPHASE_PENDING(pi)) {
3052 wlc_phy_cal_perical_mphase_reset(pi);
3055 pi->first_cal_after_assoc = true;
3057 pi->cal_type_override = PHY_PERICAL_FULL;
3059 if (pi->phycal_tempdelta) {
3060 pi->nphy_lastcal_temp = wlc_phy_tempsense_nphy(pi);
3062 wlc_phy_cal_perical_nphy_run(pi, PHY_PERICAL_FULL);
3065 case PHY_PERICAL_WATCHDOG:
3066 if (pi->phycal_tempdelta) {
3067 nphy_currtemp = wlc_phy_tempsense_nphy(pi);
3069 (nphy_currtemp > pi->nphy_lastcal_temp) ?
3070 nphy_currtemp - pi->nphy_lastcal_temp :
3071 pi->nphy_lastcal_temp - nphy_currtemp;
3073 if ((delta_temp < (s16) pi->phycal_tempdelta) &&
3074 (pi->nphy_txiqlocal_chanspec ==
3075 pi->radio_chanspec)) {
3076 do_periodic_cal = false;
3078 pi->nphy_lastcal_temp = nphy_currtemp;
3082 if (do_periodic_cal) {
3084 if (pi->nphy_perical == PHY_PERICAL_MPHASE) {
3086 if (!PHY_PERICAL_MPHASE_PENDING(pi))
3087 wlc_phy_cal_perical_mphase_schedule(pi,
3088 PHY_PERICAL_WDOG_DELAY);
3089 } else if (pi->nphy_perical == PHY_PERICAL_SPHASE)
3090 wlc_phy_cal_perical_nphy_run(pi,
3099 void wlc_phy_cal_perical_mphase_restart(phy_info_t *pi)
3101 pi->mphase_cal_phase_id = MPHASE_CAL_STATE_INIT;
3102 pi->mphase_txcal_cmdidx = 0;
3105 u8 wlc_phy_nbits(s32 value)
3110 abs_val = ABS(value);
3111 while ((abs_val >> nbits) > 0)
3117 void wlc_phy_stf_chain_init(wlc_phy_t *pih, u8 txchain, u8 rxchain)
3119 phy_info_t *pi = (phy_info_t *) pih;
3121 pi->sh->hw_phytxchain = txchain;
3122 pi->sh->hw_phyrxchain = rxchain;
3123 pi->sh->phytxchain = txchain;
3124 pi->sh->phyrxchain = rxchain;
3125 pi->pubpi.phy_corenum = (u8) PHY_BITSCNT(pi->sh->phyrxchain);
3128 void wlc_phy_stf_chain_set(wlc_phy_t *pih, u8 txchain, u8 rxchain)
3130 phy_info_t *pi = (phy_info_t *) pih;
3132 pi->sh->phytxchain = txchain;
3135 wlc_phy_rxcore_setstate_nphy(pih, rxchain);
3137 pi->pubpi.phy_corenum = (u8) PHY_BITSCNT(pi->sh->phyrxchain);
3140 void wlc_phy_stf_chain_get(wlc_phy_t *pih, u8 *txchain, u8 *rxchain)
3142 phy_info_t *pi = (phy_info_t *) pih;
3144 *txchain = pi->sh->phytxchain;
3145 *rxchain = pi->sh->phyrxchain;
3148 u8 wlc_phy_stf_chain_active_get(wlc_phy_t *pih)
3152 phy_info_t *pi = (phy_info_t *) pih;
3154 active_bitmap = (pi->phy_txcore_heatedup) ? 0x31 : 0x33;
3156 if (!pi->watchdog_override)
3157 return active_bitmap;
3159 if (NREV_GE(pi->pubpi.phy_rev, 6)) {
3160 wlapi_suspend_mac_and_wait(pi->sh->physhim);
3161 nphy_currtemp = wlc_phy_tempsense_nphy(pi);
3162 wlapi_enable_mac(pi->sh->physhim);
3164 if (!pi->phy_txcore_heatedup) {
3165 if (nphy_currtemp >= pi->phy_txcore_disable_temp) {
3166 active_bitmap &= 0xFD;
3167 pi->phy_txcore_heatedup = true;
3170 if (nphy_currtemp <= pi->phy_txcore_enable_temp) {
3171 active_bitmap |= 0x2;
3172 pi->phy_txcore_heatedup = false;
3177 return active_bitmap;
3180 s8 wlc_phy_stf_ssmode_get(wlc_phy_t *pih, chanspec_t chanspec)
3182 phy_info_t *pi = (phy_info_t *) pih;
3183 u8 siso_mcs_id, cdd_mcs_id;
3186 (CHSPEC_IS40(chanspec)) ? TXP_FIRST_MCS_40_SISO :
3187 TXP_FIRST_MCS_20_SISO;
3189 (CHSPEC_IS40(chanspec)) ? TXP_FIRST_MCS_40_CDD :
3190 TXP_FIRST_MCS_20_CDD;
3192 if (pi->tx_power_target[siso_mcs_id] >
3193 (pi->tx_power_target[cdd_mcs_id] + 12))
3194 return PHY_TXC1_MODE_SISO;
3196 return PHY_TXC1_MODE_CDD;
3199 const u8 *wlc_phy_get_ofdm_rate_lookup(void)
3201 return ofdm_rate_lookup;
3204 void wlc_lcnphy_epa_switch(phy_info_t *pi, bool mode)
3206 if ((pi->sh->chip == BCM4313_CHIP_ID) &&
3207 (pi->sh->boardflags & BFL_FEM)) {
3210 txant = wlapi_bmac_get_txant(pi->sh->physhim);
3212 mod_phy_reg(pi, 0x44d, (0x1 << 2), (1) << 2);
3214 mod_phy_reg(pi, 0x44c, (0x1 << 2), (1) << 2);
3217 ai_corereg(pi->sh->sih, SI_CC_IDX,
3218 offsetof(chipcregs_t, gpiocontrol), ~0x0,
3220 ai_corereg(pi->sh->sih, SI_CC_IDX,
3221 offsetof(chipcregs_t, gpioout), 0x40, 0x40);
3222 ai_corereg(pi->sh->sih, SI_CC_IDX,
3223 offsetof(chipcregs_t, gpioouten), 0x40,
3226 mod_phy_reg(pi, 0x44c, (0x1 << 2), (0) << 2);
3228 mod_phy_reg(pi, 0x44d, (0x1 << 2), (0) << 2);
3230 ai_corereg(pi->sh->sih, SI_CC_IDX,
3231 offsetof(chipcregs_t, gpioout), 0x40, 0x00);
3232 ai_corereg(pi->sh->sih, SI_CC_IDX,
3233 offsetof(chipcregs_t, gpioouten), 0x40, 0x0);
3234 ai_corereg(pi->sh->sih, SI_CC_IDX,
3235 offsetof(chipcregs_t, gpiocontrol), ~0x0,
3242 wlc_user_txpwr_antport_to_rfport(phy_info_t *pi, uint chan, u32 band,
3247 if (!pi->user_txpwr_at_rfport)
3252 static s8 wlc_phy_env_measure_vbat(phy_info_t *pi)
3255 return wlc_lcnphy_vbatsense(pi, 0);
3260 static s8 wlc_phy_env_measure_temperature(phy_info_t *pi)
3263 return wlc_lcnphy_tempsense_degree(pi, 0);
3268 static void wlc_phy_upd_env_txpwr_rate_limits(phy_info_t *pi, u32 band)
3273 for (i = 0; i < TXP_NUM_RATES; i++)
3274 pi->txpwr_env_limit[i] = WLC_TXPWR_MAX;
3276 vbat = wlc_phy_env_measure_vbat(pi);
3277 temp = wlc_phy_env_measure_temperature(pi);
3281 void wlc_phy_ldpc_override_set(wlc_phy_t *ppi, bool ldpc)
3287 wlc_phy_get_pwrdet_offsets(phy_info_t *pi, s8 *cckoffset, s8 *ofdmoffset)
3293 s8 wlc_phy_upd_rssi_offset(phy_info_t *pi, s8 rssi, chanspec_t chanspec)
3299 bool wlc_phy_txpower_ipa_ison(wlc_phy_t *ppi)
3301 phy_info_t *pi = (phy_info_t *) ppi;
3304 return wlc_phy_n_txpower_ipa_ison(pi);