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 void wlc_phy_ant_rxdiv_set(wlc_phy_t *ppi, u8 val)
2355 phy_info_t *pi = (phy_info_t *) ppi;
2358 pi->sh->rx_antdiv = val;
2360 if (!(ISNPHY(pi) && D11REV_IS(pi->sh->corerev, 16))) {
2361 if (val > ANT_RX_DIV_FORCE_1)
2362 wlapi_bmac_mhf(pi->sh->physhim, MHF1, MHF1_ANTDIV,
2363 MHF1_ANTDIV, WLC_BAND_ALL);
2365 wlapi_bmac_mhf(pi->sh->physhim, MHF1, MHF1_ANTDIV, 0,
2378 (0 == (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC));
2380 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2383 if (val > ANT_RX_DIV_FORCE_1) {
2384 mod_phy_reg(pi, 0x410, (0x1 << 1), 0x01 << 1);
2385 mod_phy_reg(pi, 0x410,
2387 ((ANT_RX_DIV_START_1 == val) ? 1 : 0) << 0);
2389 mod_phy_reg(pi, 0x410, (0x1 << 1), 0x00 << 1);
2390 mod_phy_reg(pi, 0x410, (0x1 << 0), (u16) val << 0);
2395 wlapi_enable_mac(pi->sh->physhim);
2401 wlc_phy_noise_calc_phy(phy_info_t *pi, u32 *cmplx_pwr, s8 *pwr_ant)
2403 s8 cmplx_pwr_dbm[PHY_CORE_MAX];
2406 memset((u8 *) cmplx_pwr_dbm, 0, sizeof(cmplx_pwr_dbm));
2407 wlc_phy_compute_dB(cmplx_pwr, cmplx_pwr_dbm, pi->pubpi.phy_corenum);
2409 for (i = 0; i < pi->pubpi.phy_corenum; i++) {
2410 if (NREV_GE(pi->pubpi.phy_rev, 3))
2411 cmplx_pwr_dbm[i] += (s8) PHY_NOISE_OFFSETFACT_4322;
2414 cmplx_pwr_dbm[i] += (s8) (16 - (15) * 3 - 70);
2417 for (i = 0; i < pi->pubpi.phy_corenum; i++) {
2418 pi->nphy_noise_win[i][pi->nphy_noise_index] = cmplx_pwr_dbm[i];
2419 pwr_ant[i] = cmplx_pwr_dbm[i];
2421 pi->nphy_noise_index =
2422 MODINC_POW2(pi->nphy_noise_index, PHY_NOISE_WINDOW_SZ);
2427 wlc_phy_noise_sample_request(wlc_phy_t *pih, u8 reason, u8 ch)
2429 phy_info_t *pi = (phy_info_t *) pih;
2430 s8 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;
2431 bool sampling_in_progress = (pi->phynoise_state != 0);
2432 bool wait_for_intr = true;
2434 if (NORADIO_ENAB(pi->pubpi)) {
2439 case PHY_NOISE_SAMPLE_MON:
2441 pi->phynoise_chan_watchdog = ch;
2442 pi->phynoise_state |= PHY_NOISE_STATE_MON;
2446 case PHY_NOISE_SAMPLE_EXTERNAL:
2448 pi->phynoise_state |= PHY_NOISE_STATE_EXTERNAL;
2455 if (sampling_in_progress)
2458 pi->phynoise_now = pi->sh->now;
2460 if (pi->phy_fixed_noise) {
2462 pi->nphy_noise_win[WL_ANT_IDX_1][pi->nphy_noise_index] =
2463 PHY_NOISE_FIXED_VAL_NPHY;
2464 pi->nphy_noise_win[WL_ANT_IDX_2][pi->nphy_noise_index] =
2465 PHY_NOISE_FIXED_VAL_NPHY;
2466 pi->nphy_noise_index = MODINC_POW2(pi->nphy_noise_index,
2467 PHY_NOISE_WINDOW_SZ);
2469 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;
2472 noise_dbm = PHY_NOISE_FIXED_VAL;
2475 wait_for_intr = false;
2480 if (!pi->phynoise_polling
2481 || (reason == PHY_NOISE_SAMPLE_EXTERNAL)) {
2482 wlapi_bmac_write_shm(pi->sh->physhim, M_JSSI_0, 0);
2483 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP0, 0);
2484 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP1, 0);
2485 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP2, 0);
2486 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP3, 0);
2488 OR_REG(&pi->regs->maccommand,
2491 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2492 wlc_lcnphy_deaf_mode(pi, (bool) 0);
2493 noise_dbm = (s8) wlc_lcnphy_rx_signal_power(pi, 20);
2494 wlc_lcnphy_deaf_mode(pi, (bool) 1);
2495 wlapi_enable_mac(pi->sh->physhim);
2496 wait_for_intr = false;
2498 } else if (ISNPHY(pi)) {
2499 if (!pi->phynoise_polling
2500 || (reason == PHY_NOISE_SAMPLE_EXTERNAL)) {
2502 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP0, 0);
2503 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP1, 0);
2504 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP2, 0);
2505 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP3, 0);
2507 OR_REG(&pi->regs->maccommand,
2510 phy_iq_est_t est[PHY_CORE_MAX];
2511 u32 cmplx_pwr[PHY_CORE_MAX];
2512 s8 noise_dbm_ant[PHY_CORE_MAX];
2513 u16 log_num_samps, num_samps, classif_state = 0;
2518 memset((u8 *) est, 0, sizeof(est));
2519 memset((u8 *) cmplx_pwr, 0, sizeof(cmplx_pwr));
2520 memset((u8 *) noise_dbm_ant, 0, sizeof(noise_dbm_ant));
2522 log_num_samps = PHY_NOISE_SAMPLE_LOG_NUM_NPHY;
2523 num_samps = 1 << log_num_samps;
2525 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2526 classif_state = wlc_phy_classifier_nphy(pi, 0, 0);
2527 wlc_phy_classifier_nphy(pi, 3, 0);
2528 wlc_phy_rx_iq_est_nphy(pi, est, num_samps, wait_time,
2530 wlc_phy_classifier_nphy(pi, (0x7 << 0), classif_state);
2531 wlapi_enable_mac(pi->sh->physhim);
2533 for (i = 0; i < pi->pubpi.phy_corenum; i++)
2536 est[i].q_pwr) >> log_num_samps;
2538 wlc_phy_noise_calc_phy(pi, cmplx_pwr, noise_dbm_ant);
2540 for (i = 0; i < pi->pubpi.phy_corenum; i++) {
2541 pi->nphy_noise_win[i][pi->nphy_noise_index] =
2544 if (noise_dbm_ant[i] > noise_dbm)
2545 noise_dbm = noise_dbm_ant[i];
2547 pi->nphy_noise_index = MODINC_POW2(pi->nphy_noise_index,
2548 PHY_NOISE_WINDOW_SZ);
2550 wait_for_intr = false;
2557 wlc_phy_noise_cb(pi, ch, noise_dbm);
2561 void wlc_phy_noise_sample_request_external(wlc_phy_t *pih)
2565 channel = CHSPEC_CHANNEL(wlc_phy_chanspec_get(pih));
2567 wlc_phy_noise_sample_request(pih, PHY_NOISE_SAMPLE_EXTERNAL, channel);
2570 static void wlc_phy_noise_cb(phy_info_t *pi, u8 channel, s8 noise_dbm)
2572 if (!pi->phynoise_state)
2575 if (pi->phynoise_state & PHY_NOISE_STATE_MON) {
2576 if (pi->phynoise_chan_watchdog == channel) {
2577 pi->sh->phy_noise_window[pi->sh->phy_noise_index] =
2579 pi->sh->phy_noise_index =
2580 MODINC(pi->sh->phy_noise_index, MA_WINDOW_SZ);
2582 pi->phynoise_state &= ~PHY_NOISE_STATE_MON;
2585 if (pi->phynoise_state & PHY_NOISE_STATE_EXTERNAL) {
2586 pi->phynoise_state &= ~PHY_NOISE_STATE_EXTERNAL;
2591 static s8 wlc_phy_noise_read_shmem(phy_info_t *pi)
2593 u32 cmplx_pwr[PHY_CORE_MAX];
2594 s8 noise_dbm_ant[PHY_CORE_MAX];
2596 u32 cmplx_pwr_tot = 0;
2597 s8 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;
2600 memset((u8 *) cmplx_pwr, 0, sizeof(cmplx_pwr));
2601 memset((u8 *) noise_dbm_ant, 0, sizeof(noise_dbm_ant));
2603 for (idx = 0, core = 0; core < pi->pubpi.phy_corenum; idx += 2, core++) {
2604 lo = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP(idx));
2605 hi = wlapi_bmac_read_shm(pi->sh->physhim,
2606 M_PWRIND_MAP(idx + 1));
2607 cmplx_pwr[core] = (hi << 16) + lo;
2608 cmplx_pwr_tot += cmplx_pwr[core];
2609 if (cmplx_pwr[core] == 0) {
2610 noise_dbm_ant[core] = PHY_NOISE_FIXED_VAL_NPHY;
2612 cmplx_pwr[core] >>= PHY_NOISE_SAMPLE_LOG_NUM_UCODE;
2615 if (cmplx_pwr_tot != 0)
2616 wlc_phy_noise_calc_phy(pi, cmplx_pwr, noise_dbm_ant);
2618 for (core = 0; core < pi->pubpi.phy_corenum; core++) {
2619 pi->nphy_noise_win[core][pi->nphy_noise_index] =
2620 noise_dbm_ant[core];
2622 if (noise_dbm_ant[core] > noise_dbm)
2623 noise_dbm = noise_dbm_ant[core];
2625 pi->nphy_noise_index =
2626 MODINC_POW2(pi->nphy_noise_index, PHY_NOISE_WINDOW_SZ);
2632 void wlc_phy_noise_sample_intr(wlc_phy_t *pih)
2634 phy_info_t *pi = (phy_info_t *) pih;
2637 s8 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;
2640 u32 cmplx_pwr, cmplx_pwr0, cmplx_pwr1;
2642 s32 pwr_offset_dB, gain_dB;
2643 u16 status_0, status_1;
2645 jssi_aux = wlapi_bmac_read_shm(pi->sh->physhim, M_JSSI_AUX);
2646 channel = jssi_aux & D11_CURCHANNEL_MAX;
2648 lo = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP0);
2649 hi = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP1);
2650 cmplx_pwr0 = (hi << 16) + lo;
2652 lo = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP2);
2653 hi = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP3);
2654 cmplx_pwr1 = (hi << 16) + lo;
2655 cmplx_pwr = (cmplx_pwr0 + cmplx_pwr1) >> 6;
2658 status_1 = wlapi_bmac_read_shm(pi->sh->physhim, M_JSSI_0);
2659 if ((cmplx_pwr > 0 && cmplx_pwr < 500)
2660 && ((status_1 & 0xc000) == 0x4000)) {
2662 wlc_phy_compute_dB(&cmplx_pwr, &noise_dbm,
2663 pi->pubpi.phy_corenum);
2664 pwr_offset_dB = (read_phy_reg(pi, 0x434) & 0xFF);
2665 if (pwr_offset_dB > 127)
2666 pwr_offset_dB -= 256;
2668 noise_dbm += (s8) (pwr_offset_dB - 30);
2670 gain_dB = (status_0 & 0x1ff);
2671 noise_dbm -= (s8) (gain_dB);
2673 noise_dbm = PHY_NOISE_FIXED_VAL_LCNPHY;
2675 } else if (ISNPHY(pi)) {
2677 jssi_aux = wlapi_bmac_read_shm(pi->sh->physhim, M_JSSI_AUX);
2678 channel = jssi_aux & D11_CURCHANNEL_MAX;
2680 noise_dbm = wlc_phy_noise_read_shmem(pi);
2683 wlc_phy_noise_cb(pi, channel, noise_dbm);
2687 s8 lcnphy_gain_index_offset_for_pkt_rssi[] = {
2728 void wlc_phy_compute_dB(u32 *cmplx_pwr, s8 *p_cmplx_pwr_dB, u8 core)
2730 u8 msb, secondmsb, i;
2733 for (i = 0; i < core; i++) {
2738 secondmsb = (u8) ((tmp >> (--msb - 1)) & 1);
2739 p_cmplx_pwr_dB[i] = (s8) (3 * msb + 2 * secondmsb);
2743 void wlc_phy_rssi_compute(wlc_phy_t *pih, void *ctx)
2745 wlc_d11rxhdr_t *wlc_rxhdr = (wlc_d11rxhdr_t *) ctx;
2746 d11rxhdr_t *rxh = &wlc_rxhdr->rxhdr;
2747 int rssi = le16_to_cpu(rxh->PhyRxStatus_1) & PRXS1_JSSI_MASK;
2748 uint radioid = pih->radioid;
2749 phy_info_t *pi = (phy_info_t *) pih;
2751 if (NORADIO_ENAB(pi->pubpi)) {
2752 rssi = WLC_RSSI_INVALID;
2756 if ((pi->sh->corerev >= 11)
2757 && !(le16_to_cpu(rxh->RxStatus2) & RXS_PHYRXST_VALID)) {
2758 rssi = WLC_RSSI_INVALID;
2763 u8 gidx = (le16_to_cpu(rxh->PhyRxStatus_2) & 0xFC00) >> 10;
2764 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
2769 rssi = rssi + lcnphy_gain_index_offset_for_pkt_rssi[gidx];
2770 if ((rssi > -46) && (gidx > 18))
2773 rssi = rssi + pi_lcn->lcnphy_pkteng_rssi_slope;
2783 } else if (radioid == BCM2055_ID || radioid == BCM2056_ID
2784 || radioid == BCM2057_ID) {
2785 rssi = wlc_phy_rssi_compute_nphy(pi, wlc_rxhdr);
2789 wlc_rxhdr->rssi = (s8) rssi;
2792 void wlc_phy_freqtrack_start(wlc_phy_t *pih)
2797 void wlc_phy_freqtrack_end(wlc_phy_t *pih)
2802 void wlc_phy_set_deaf(wlc_phy_t *ppi, bool user_flag)
2805 pi = (phy_info_t *) ppi;
2808 wlc_lcnphy_deaf_mode(pi, true);
2809 else if (ISNPHY(pi))
2810 wlc_nphy_deaf_mode(pi, true);
2813 void wlc_phy_watchdog(wlc_phy_t *pih)
2815 phy_info_t *pi = (phy_info_t *) pih;
2816 bool delay_phy_cal = false;
2819 if (!pi->watchdog_override)
2822 if (!(SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi))) {
2823 wlc_phy_noise_sample_request((wlc_phy_t *) pi,
2824 PHY_NOISE_SAMPLE_MON,
2829 if (pi->phynoise_state && (pi->sh->now - pi->phynoise_now) > 5) {
2830 pi->phynoise_state = 0;
2833 if ((!pi->phycal_txpower) ||
2834 ((pi->sh->now - pi->phycal_txpower) >= pi->sh->fast_timer)) {
2836 if (!SCAN_INPROG_PHY(pi) && wlc_phy_cal_txpower_recalc_sw(pi)) {
2837 pi->phycal_txpower = pi->sh->now;
2841 if (NORADIO_ENAB(pi->pubpi))
2844 if ((SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi)
2845 || ASSOC_INPROG_PHY(pi)))
2848 if (ISNPHY(pi) && !pi->disable_percal && !delay_phy_cal) {
2850 if ((pi->nphy_perical != PHY_PERICAL_DISABLE) &&
2851 (pi->nphy_perical != PHY_PERICAL_MANUAL) &&
2852 ((pi->sh->now - pi->nphy_perical_last) >=
2853 pi->sh->glacial_timer))
2854 wlc_phy_cal_perical((wlc_phy_t *) pi,
2855 PHY_PERICAL_WATCHDOG);
2857 wlc_phy_txpwr_papd_cal_nphy(pi);
2861 if (pi->phy_forcecal ||
2862 ((pi->sh->now - pi->phy_lastcal) >=
2863 pi->sh->glacial_timer)) {
2864 if (!(SCAN_RM_IN_PROGRESS(pi) || ASSOC_INPROG_PHY(pi)))
2865 wlc_lcnphy_calib_modes(pi,
2866 LCNPHY_PERICAL_TEMPBASED_TXPWRCTRL);
2868 (SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi)
2869 || ASSOC_INPROG_PHY(pi)
2870 || pi->carrier_suppr_disable
2871 || pi->disable_percal))
2872 wlc_lcnphy_calib_modes(pi,
2873 PHY_PERICAL_WATCHDOG);
2878 void wlc_phy_BSSinit(wlc_phy_t *pih, bool bonlyap, int rssi)
2880 phy_info_t *pi = (phy_info_t *) pih;
2884 for (i = 0; i < MA_WINDOW_SZ; i++) {
2885 pi->sh->phy_noise_window[i] = (s8) (rssi & 0xff);
2888 for (i = 0; i < MA_WINDOW_SZ; i++)
2889 pi->sh->phy_noise_window[i] =
2890 PHY_NOISE_FIXED_VAL_LCNPHY;
2892 pi->sh->phy_noise_index = 0;
2894 for (i = 0; i < PHY_NOISE_WINDOW_SZ; i++) {
2895 for (k = WL_ANT_IDX_1; k < WL_ANT_RX_MAX; k++)
2896 pi->nphy_noise_win[k][i] = PHY_NOISE_FIXED_VAL_NPHY;
2898 pi->nphy_noise_index = 0;
2902 wlc_phy_papd_decode_epsilon(u32 epsilon, s32 *eps_real, s32 *eps_imag)
2904 *eps_imag = (epsilon >> 13);
2905 if (*eps_imag > 0xfff)
2906 *eps_imag -= 0x2000;
2908 *eps_real = (epsilon & 0x1fff);
2909 if (*eps_real > 0xfff)
2910 *eps_real -= 0x2000;
2913 static const fixed AtanTbl[] = {
2934 void wlc_phy_cordic(fixed theta, cs32 *val)
2936 fixed angle, valtmp;
2941 val[0].i = CORDIC_AG;
2945 signtheta = (theta < 0) ? -1 : 1;
2947 ((theta + FIXED(180) * signtheta) % FIXED(360)) -
2948 FIXED(180) * signtheta;
2950 if (FLOAT(theta) > 90) {
2951 theta -= FIXED(180);
2953 } else if (FLOAT(theta) < -90) {
2954 theta += FIXED(180);
2958 for (iter = 0; iter < CORDIC_NI; iter++) {
2959 if (theta > angle) {
2960 valtmp = val[0].i - (val[0].q >> iter);
2961 val[0].q = (val[0].i >> iter) + val[0].q;
2963 angle += AtanTbl[iter];
2965 valtmp = val[0].i + (val[0].q >> iter);
2966 val[0].q = -(val[0].i >> iter) + val[0].q;
2968 angle -= AtanTbl[iter];
2972 val[0].i = val[0].i * signx;
2973 val[0].q = val[0].q * signx;
2976 void wlc_phy_cal_perical_mphase_reset(phy_info_t *pi)
2978 wlapi_del_timer(pi->sh->physhim, pi->phycal_timer);
2980 pi->cal_type_override = PHY_PERICAL_AUTO;
2981 pi->mphase_cal_phase_id = MPHASE_CAL_STATE_IDLE;
2982 pi->mphase_txcal_cmdidx = 0;
2985 static void wlc_phy_cal_perical_mphase_schedule(phy_info_t *pi, uint delay)
2988 if ((pi->nphy_perical != PHY_PERICAL_MPHASE) &&
2989 (pi->nphy_perical != PHY_PERICAL_MANUAL))
2992 wlapi_del_timer(pi->sh->physhim, pi->phycal_timer);
2994 pi->mphase_cal_phase_id = MPHASE_CAL_STATE_INIT;
2995 wlapi_add_timer(pi->sh->physhim, pi->phycal_timer, delay, 0);
2998 void wlc_phy_cal_perical(wlc_phy_t *pih, u8 reason)
3000 s16 nphy_currtemp = 0;
3002 bool do_periodic_cal = true;
3003 phy_info_t *pi = (phy_info_t *) pih;
3008 if ((pi->nphy_perical == PHY_PERICAL_DISABLE) ||
3009 (pi->nphy_perical == PHY_PERICAL_MANUAL))
3013 case PHY_PERICAL_DRIVERUP:
3016 case PHY_PERICAL_PHYINIT:
3017 if (pi->nphy_perical == PHY_PERICAL_MPHASE) {
3018 if (PHY_PERICAL_MPHASE_PENDING(pi)) {
3019 wlc_phy_cal_perical_mphase_reset(pi);
3021 wlc_phy_cal_perical_mphase_schedule(pi,
3022 PHY_PERICAL_INIT_DELAY);
3026 case PHY_PERICAL_JOIN_BSS:
3027 case PHY_PERICAL_START_IBSS:
3028 case PHY_PERICAL_UP_BSS:
3029 if ((pi->nphy_perical == PHY_PERICAL_MPHASE) &&
3030 PHY_PERICAL_MPHASE_PENDING(pi)) {
3031 wlc_phy_cal_perical_mphase_reset(pi);
3034 pi->first_cal_after_assoc = true;
3036 pi->cal_type_override = PHY_PERICAL_FULL;
3038 if (pi->phycal_tempdelta) {
3039 pi->nphy_lastcal_temp = wlc_phy_tempsense_nphy(pi);
3041 wlc_phy_cal_perical_nphy_run(pi, PHY_PERICAL_FULL);
3044 case PHY_PERICAL_WATCHDOG:
3045 if (pi->phycal_tempdelta) {
3046 nphy_currtemp = wlc_phy_tempsense_nphy(pi);
3048 (nphy_currtemp > pi->nphy_lastcal_temp) ?
3049 nphy_currtemp - pi->nphy_lastcal_temp :
3050 pi->nphy_lastcal_temp - nphy_currtemp;
3052 if ((delta_temp < (s16) pi->phycal_tempdelta) &&
3053 (pi->nphy_txiqlocal_chanspec ==
3054 pi->radio_chanspec)) {
3055 do_periodic_cal = false;
3057 pi->nphy_lastcal_temp = nphy_currtemp;
3061 if (do_periodic_cal) {
3063 if (pi->nphy_perical == PHY_PERICAL_MPHASE) {
3065 if (!PHY_PERICAL_MPHASE_PENDING(pi))
3066 wlc_phy_cal_perical_mphase_schedule(pi,
3067 PHY_PERICAL_WDOG_DELAY);
3068 } else if (pi->nphy_perical == PHY_PERICAL_SPHASE)
3069 wlc_phy_cal_perical_nphy_run(pi,
3078 void wlc_phy_cal_perical_mphase_restart(phy_info_t *pi)
3080 pi->mphase_cal_phase_id = MPHASE_CAL_STATE_INIT;
3081 pi->mphase_txcal_cmdidx = 0;
3084 u8 wlc_phy_nbits(s32 value)
3089 abs_val = ABS(value);
3090 while ((abs_val >> nbits) > 0)
3096 void wlc_phy_stf_chain_init(wlc_phy_t *pih, u8 txchain, u8 rxchain)
3098 phy_info_t *pi = (phy_info_t *) pih;
3100 pi->sh->hw_phytxchain = txchain;
3101 pi->sh->hw_phyrxchain = rxchain;
3102 pi->sh->phytxchain = txchain;
3103 pi->sh->phyrxchain = rxchain;
3104 pi->pubpi.phy_corenum = (u8) PHY_BITSCNT(pi->sh->phyrxchain);
3107 void wlc_phy_stf_chain_set(wlc_phy_t *pih, u8 txchain, u8 rxchain)
3109 phy_info_t *pi = (phy_info_t *) pih;
3111 pi->sh->phytxchain = txchain;
3114 wlc_phy_rxcore_setstate_nphy(pih, rxchain);
3116 pi->pubpi.phy_corenum = (u8) PHY_BITSCNT(pi->sh->phyrxchain);
3119 void wlc_phy_stf_chain_get(wlc_phy_t *pih, u8 *txchain, u8 *rxchain)
3121 phy_info_t *pi = (phy_info_t *) pih;
3123 *txchain = pi->sh->phytxchain;
3124 *rxchain = pi->sh->phyrxchain;
3127 u8 wlc_phy_stf_chain_active_get(wlc_phy_t *pih)
3131 phy_info_t *pi = (phy_info_t *) pih;
3133 active_bitmap = (pi->phy_txcore_heatedup) ? 0x31 : 0x33;
3135 if (!pi->watchdog_override)
3136 return active_bitmap;
3138 if (NREV_GE(pi->pubpi.phy_rev, 6)) {
3139 wlapi_suspend_mac_and_wait(pi->sh->physhim);
3140 nphy_currtemp = wlc_phy_tempsense_nphy(pi);
3141 wlapi_enable_mac(pi->sh->physhim);
3143 if (!pi->phy_txcore_heatedup) {
3144 if (nphy_currtemp >= pi->phy_txcore_disable_temp) {
3145 active_bitmap &= 0xFD;
3146 pi->phy_txcore_heatedup = true;
3149 if (nphy_currtemp <= pi->phy_txcore_enable_temp) {
3150 active_bitmap |= 0x2;
3151 pi->phy_txcore_heatedup = false;
3156 return active_bitmap;
3159 s8 wlc_phy_stf_ssmode_get(wlc_phy_t *pih, chanspec_t chanspec)
3161 phy_info_t *pi = (phy_info_t *) pih;
3162 u8 siso_mcs_id, cdd_mcs_id;
3165 (CHSPEC_IS40(chanspec)) ? TXP_FIRST_MCS_40_SISO :
3166 TXP_FIRST_MCS_20_SISO;
3168 (CHSPEC_IS40(chanspec)) ? TXP_FIRST_MCS_40_CDD :
3169 TXP_FIRST_MCS_20_CDD;
3171 if (pi->tx_power_target[siso_mcs_id] >
3172 (pi->tx_power_target[cdd_mcs_id] + 12))
3173 return PHY_TXC1_MODE_SISO;
3175 return PHY_TXC1_MODE_CDD;
3178 const u8 *wlc_phy_get_ofdm_rate_lookup(void)
3180 return ofdm_rate_lookup;
3183 void wlc_lcnphy_epa_switch(phy_info_t *pi, bool mode)
3185 if ((pi->sh->chip == BCM4313_CHIP_ID) &&
3186 (pi->sh->boardflags & BFL_FEM)) {
3189 txant = wlapi_bmac_get_txant(pi->sh->physhim);
3191 mod_phy_reg(pi, 0x44d, (0x1 << 2), (1) << 2);
3193 mod_phy_reg(pi, 0x44c, (0x1 << 2), (1) << 2);
3196 ai_corereg(pi->sh->sih, SI_CC_IDX,
3197 offsetof(chipcregs_t, gpiocontrol), ~0x0,
3199 ai_corereg(pi->sh->sih, SI_CC_IDX,
3200 offsetof(chipcregs_t, gpioout), 0x40, 0x40);
3201 ai_corereg(pi->sh->sih, SI_CC_IDX,
3202 offsetof(chipcregs_t, gpioouten), 0x40,
3205 mod_phy_reg(pi, 0x44c, (0x1 << 2), (0) << 2);
3207 mod_phy_reg(pi, 0x44d, (0x1 << 2), (0) << 2);
3209 ai_corereg(pi->sh->sih, SI_CC_IDX,
3210 offsetof(chipcregs_t, gpioout), 0x40, 0x00);
3211 ai_corereg(pi->sh->sih, SI_CC_IDX,
3212 offsetof(chipcregs_t, gpioouten), 0x40, 0x0);
3213 ai_corereg(pi->sh->sih, SI_CC_IDX,
3214 offsetof(chipcregs_t, gpiocontrol), ~0x0,
3221 wlc_user_txpwr_antport_to_rfport(phy_info_t *pi, uint chan, u32 band,
3226 if (!pi->user_txpwr_at_rfport)
3231 static s8 wlc_phy_env_measure_vbat(phy_info_t *pi)
3234 return wlc_lcnphy_vbatsense(pi, 0);
3239 static s8 wlc_phy_env_measure_temperature(phy_info_t *pi)
3242 return wlc_lcnphy_tempsense_degree(pi, 0);
3247 static void wlc_phy_upd_env_txpwr_rate_limits(phy_info_t *pi, u32 band)
3252 for (i = 0; i < TXP_NUM_RATES; i++)
3253 pi->txpwr_env_limit[i] = WLC_TXPWR_MAX;
3255 vbat = wlc_phy_env_measure_vbat(pi);
3256 temp = wlc_phy_env_measure_temperature(pi);
3260 void wlc_phy_ldpc_override_set(wlc_phy_t *ppi, bool ldpc)
3266 wlc_phy_get_pwrdet_offsets(phy_info_t *pi, s8 *cckoffset, s8 *ofdmoffset)
3272 s8 wlc_phy_upd_rssi_offset(phy_info_t *pi, s8 rssi, chanspec_t chanspec)
3278 bool wlc_phy_txpower_ipa_ison(wlc_phy_t *ppi)
3280 phy_info_t *pi = (phy_info_t *) ppi;
3283 return wlc_phy_n_txpower_ipa_ison(pi);