staging: brcm80211: removed unused bus code from softmac
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / drivers / staging / brcm80211 / brcmsmac / phy / phy_cmn.c
blobc00178d18b5ace5e24183c49d7faa50522513074
1 /*
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.
17 #include <linux/delay.h>
19 #include <brcm_hw_ids.h>
20 #include <chipcommon.h>
21 #include <aiutils.h>
22 #include <d11.h>
23 #include <phy_shim.h>
24 #include "phy_hal.h"
25 #include "phy_int.h"
26 #include "phy_radio.h"
27 #include "phy_lcn.h"
28 #include "phyreg_n.h"
30 u32 phyhal_msg_level = PHYHAL_ERROR;
32 struct chan_info_basic {
33 u16 chan;
34 u16 freq;
37 static struct chan_info_basic chan_info_all[] = {
38 {1, 2412},
39 {2, 2417},
40 {3, 2422},
41 {4, 2427},
42 {5, 2432},
43 {6, 2437},
44 {7, 2442},
45 {8, 2447},
46 {9, 2452},
47 {10, 2457},
48 {11, 2462},
49 {12, 2467},
50 {13, 2472},
51 {14, 2484},
53 {34, 5170},
54 {38, 5190},
55 {42, 5210},
56 {46, 5230},
58 {36, 5180},
59 {40, 5200},
60 {44, 5220},
61 {48, 5240},
62 {52, 5260},
63 {56, 5280},
64 {60, 5300},
65 {64, 5320},
67 {100, 5500},
68 {104, 5520},
69 {108, 5540},
70 {112, 5560},
71 {116, 5580},
72 {120, 5600},
73 {124, 5620},
74 {128, 5640},
75 {132, 5660},
76 {136, 5680},
77 {140, 5700},
79 {149, 5745},
80 {153, 5765},
81 {157, 5785},
82 {161, 5805},
83 {165, 5825},
85 {184, 4920},
86 {188, 4940},
87 {192, 4960},
88 {196, 4980},
89 {200, 5000},
90 {204, 5020},
91 {208, 5040},
92 {212, 5060},
93 {216, 50800}
96 u16 ltrn_list[PHY_LTRN_LIST_LEN] = {
97 0x18f9, 0x0d01, 0x00e4, 0xdef4, 0x06f1, 0x0ffc,
98 0xfa27, 0x1dff, 0x10f0, 0x0918, 0xf20a, 0xe010,
99 0x1417, 0x1104, 0xf114, 0xf2fa, 0xf7db, 0xe2fc,
100 0xe1fb, 0x13ee, 0xff0d, 0xe91c, 0x171a, 0x0318,
101 0xda00, 0x03e8, 0x17e6, 0xe9e4, 0xfff3, 0x1312,
102 0xe105, 0xe204, 0xf725, 0xf206, 0xf1ec, 0x11fc,
103 0x14e9, 0xe0f0, 0xf2f6, 0x09e8, 0x1010, 0x1d01,
104 0xfad9, 0x0f04, 0x060f, 0xde0c, 0x001c, 0x0dff,
105 0x1807, 0xf61a, 0xe40e, 0x0f16, 0x05f9, 0x18ec,
106 0x0a1b, 0xff1e, 0x2600, 0xffe2, 0x0ae5, 0x1814,
107 0x0507, 0x0fea, 0xe4f2, 0xf6e6
110 const u8 ofdm_rate_lookup[] = {
112 BRCM_RATE_48M,
113 BRCM_RATE_24M,
114 BRCM_RATE_12M,
115 BRCM_RATE_6M,
116 BRCM_RATE_54M,
117 BRCM_RATE_36M,
118 BRCM_RATE_18M,
119 BRCM_RATE_9M
122 #define PHY_WREG_LIMIT 24
124 static void wlc_set_phy_uninitted(struct brcms_phy *pi);
125 static u32 wlc_phy_get_radio_ver(struct brcms_phy *pi);
126 static void wlc_phy_timercb_phycal(struct brcms_phy *pi);
128 static bool wlc_phy_noise_calc_phy(struct brcms_phy *pi, u32 *cmplx_pwr,
129 s8 *pwr_ant);
131 static void wlc_phy_cal_perical_mphase_schedule(struct brcms_phy *pi,
132 uint delay);
134 static void wlc_phy_noise_cb(struct brcms_phy *pi, u8 channel, s8 noise_dbm);
135 static void wlc_phy_noise_sample_request(struct brcms_phy_pub *pih, u8 reason,
136 u8 ch);
138 static void wlc_phy_txpower_reg_limit_calc(struct brcms_phy *pi,
139 struct txpwr_limits *tp,
140 u16 chanspec);
142 static bool wlc_phy_cal_txpower_recalc_sw(struct brcms_phy *pi);
144 static s8 wlc_user_txpwr_antport_to_rfport(struct brcms_phy *pi, uint chan,
145 u32 band, u8 rate);
146 static void wlc_phy_upd_env_txpwr_rate_limits(struct brcms_phy *pi, u32 band);
147 static s8 wlc_phy_env_measure_vbat(struct brcms_phy *pi);
148 static s8 wlc_phy_env_measure_temperature(struct brcms_phy *pi);
150 char *phy_getvar(struct brcms_phy *pi, const char *name)
152 char *vars = pi->vars;
153 char *s;
154 int len;
156 if (!name)
157 return NULL;
159 len = strlen(name);
160 if (len == 0)
161 return NULL;
163 for (s = vars; s && *s;) {
164 if ((memcmp(s, name, len) == 0) && (s[len] == '='))
165 return &s[len + 1];
167 while (*s++)
171 return NULL;
174 int phy_getintvar(struct brcms_phy *pi, const char *name)
176 char *val;
177 unsigned long res;
179 val = PHY_GETVAR(pi, name);
180 if (val && !kstrtoul(val, 0, &res))
181 return res;
183 return 0;
186 void wlc_phyreg_enter(struct brcms_phy_pub *pih)
188 struct brcms_phy *pi = (struct brcms_phy *) pih;
189 wlapi_bmac_ucode_wake_override_phyreg_set(pi->sh->physhim);
192 void wlc_phyreg_exit(struct brcms_phy_pub *pih)
194 struct brcms_phy *pi = (struct brcms_phy *) pih;
195 wlapi_bmac_ucode_wake_override_phyreg_clear(pi->sh->physhim);
198 void wlc_radioreg_enter(struct brcms_phy_pub *pih)
200 struct brcms_phy *pi = (struct brcms_phy *) pih;
201 wlapi_bmac_mctrl(pi->sh->physhim, MCTL_LOCK_RADIO, MCTL_LOCK_RADIO);
203 udelay(10);
206 void wlc_radioreg_exit(struct brcms_phy_pub *pih)
208 struct brcms_phy *pi = (struct brcms_phy *) pih;
209 u16 dummy;
211 dummy = R_REG(&pi->regs->phyversion);
212 pi->phy_wreg = 0;
213 wlapi_bmac_mctrl(pi->sh->physhim, MCTL_LOCK_RADIO, 0);
216 u16 read_radio_reg(struct brcms_phy *pi, u16 addr)
218 u16 data;
220 if ((addr == RADIO_IDCODE))
221 return 0xffff;
223 if (NORADIO_ENAB(pi->pubpi))
224 return NORADIO_IDCODE & 0xffff;
226 switch (pi->pubpi.phy_type) {
227 case PHY_TYPE_N:
228 CASECHECK(PHYTYPE, PHY_TYPE_N);
229 if (NREV_GE(pi->pubpi.phy_rev, 7))
230 addr |= RADIO_2057_READ_OFF;
231 else
232 addr |= RADIO_2055_READ_OFF;
233 break;
235 case PHY_TYPE_LCN:
236 CASECHECK(PHYTYPE, PHY_TYPE_LCN);
237 addr |= RADIO_2064_READ_OFF;
238 break;
240 default:
241 break;
244 if ((D11REV_GE(pi->sh->corerev, 24)) ||
245 (D11REV_IS(pi->sh->corerev, 22)
246 && (pi->pubpi.phy_type != PHY_TYPE_SSN))) {
247 W_REG_FLUSH(&pi->regs->radioregaddr, addr);
248 data = R_REG(&pi->regs->radioregdata);
249 } else {
250 W_REG_FLUSH(&pi->regs->phy4waddr, addr);
252 #ifdef __ARM_ARCH_4T__
253 __asm__(" .align 4 ");
254 __asm__(" nop ");
255 data = R_REG(&pi->regs->phy4wdatalo);
256 #else
257 data = R_REG(&pi->regs->phy4wdatalo);
258 #endif
261 pi->phy_wreg = 0;
263 return data;
266 void write_radio_reg(struct brcms_phy *pi, u16 addr, u16 val)
268 if (NORADIO_ENAB(pi->pubpi))
269 return;
271 if ((D11REV_GE(pi->sh->corerev, 24)) ||
272 (D11REV_IS(pi->sh->corerev, 22)
273 && (pi->pubpi.phy_type != PHY_TYPE_SSN))) {
275 W_REG_FLUSH(&pi->regs->radioregaddr, addr);
276 W_REG(&pi->regs->radioregdata, val);
277 } else {
278 W_REG_FLUSH(&pi->regs->phy4waddr, addr);
279 W_REG(&pi->regs->phy4wdatalo, val);
282 if (++pi->phy_wreg >= pi->phy_wreg_limit) {
283 (void)R_REG(&pi->regs->maccontrol);
284 pi->phy_wreg = 0;
288 static u32 read_radio_id(struct brcms_phy *pi)
290 u32 id;
292 if (NORADIO_ENAB(pi->pubpi))
293 return NORADIO_IDCODE;
295 if (D11REV_GE(pi->sh->corerev, 24)) {
296 u32 b0, b1, b2;
298 W_REG_FLUSH(&pi->regs->radioregaddr, 0);
299 b0 = (u32) R_REG(&pi->regs->radioregdata);
300 W_REG_FLUSH(&pi->regs->radioregaddr, 1);
301 b1 = (u32) R_REG(&pi->regs->radioregdata);
302 W_REG_FLUSH(&pi->regs->radioregaddr, 2);
303 b2 = (u32) R_REG(&pi->regs->radioregdata);
305 id = ((b0 & 0xf) << 28) | (((b2 << 8) | b1) << 12) | ((b0 >> 4)
306 & 0xf);
307 } else {
308 W_REG_FLUSH(&pi->regs->phy4waddr, RADIO_IDCODE);
309 id = (u32) R_REG(&pi->regs->phy4wdatalo);
310 id |= (u32) R_REG(&pi->regs->phy4wdatahi) << 16;
312 pi->phy_wreg = 0;
313 return id;
316 void and_radio_reg(struct brcms_phy *pi, u16 addr, u16 val)
318 u16 rval;
320 if (NORADIO_ENAB(pi->pubpi))
321 return;
323 rval = read_radio_reg(pi, addr);
324 write_radio_reg(pi, addr, (rval & val));
327 void or_radio_reg(struct brcms_phy *pi, u16 addr, u16 val)
329 u16 rval;
331 if (NORADIO_ENAB(pi->pubpi))
332 return;
334 rval = read_radio_reg(pi, addr);
335 write_radio_reg(pi, addr, (rval | val));
338 void xor_radio_reg(struct brcms_phy *pi, u16 addr, u16 mask)
340 u16 rval;
342 if (NORADIO_ENAB(pi->pubpi))
343 return;
345 rval = read_radio_reg(pi, addr);
346 write_radio_reg(pi, addr, (rval ^ mask));
349 void mod_radio_reg(struct brcms_phy *pi, u16 addr, u16 mask, u16 val)
351 u16 rval;
353 if (NORADIO_ENAB(pi->pubpi))
354 return;
356 rval = read_radio_reg(pi, addr);
357 write_radio_reg(pi, addr, (rval & ~mask) | (val & mask));
360 void write_phy_channel_reg(struct brcms_phy *pi, uint val)
362 W_REG(&pi->regs->phychannel, val);
365 u16 read_phy_reg(struct brcms_phy *pi, u16 addr)
367 struct d11regs *regs;
369 regs = pi->regs;
371 W_REG_FLUSH(&regs->phyregaddr, addr);
373 pi->phy_wreg = 0;
374 return R_REG(&regs->phyregdata);
377 void write_phy_reg(struct brcms_phy *pi, u16 addr, u16 val)
379 struct d11regs *regs;
381 regs = pi->regs;
383 #ifdef __mips__
384 W_REG_FLUSH(&regs->phyregaddr, addr);
385 W_REG(&regs->phyregdata, val);
386 if (addr == 0x72)
387 (void)R_REG(&regs->phyregdata);
388 #else
389 W_REG((u32 *)(&regs->phyregaddr),
390 addr | (val << 16));
391 if (++pi->phy_wreg >= pi->phy_wreg_limit) {
392 pi->phy_wreg = 0;
393 (void)R_REG(&regs->phyversion);
395 #endif
398 void and_phy_reg(struct brcms_phy *pi, u16 addr, u16 val)
400 struct d11regs *regs;
402 regs = pi->regs;
404 W_REG_FLUSH(&regs->phyregaddr, addr);
406 W_REG(&regs->phyregdata, (R_REG(&regs->phyregdata) & val));
407 pi->phy_wreg = 0;
410 void or_phy_reg(struct brcms_phy *pi, u16 addr, u16 val)
412 struct d11regs *regs;
414 regs = pi->regs;
416 W_REG_FLUSH(&regs->phyregaddr, addr);
418 W_REG(&regs->phyregdata, (R_REG(&regs->phyregdata) | val));
419 pi->phy_wreg = 0;
422 void mod_phy_reg(struct brcms_phy *pi, u16 addr, u16 mask, u16 val)
424 struct d11regs *regs;
426 regs = pi->regs;
428 W_REG_FLUSH(&regs->phyregaddr, addr);
430 W_REG(&regs->phyregdata,
431 ((R_REG(&regs->phyregdata) & ~mask) | (val & mask)));
432 pi->phy_wreg = 0;
435 static void wlc_set_phy_uninitted(struct brcms_phy *pi)
437 int i, j;
439 pi->initialized = false;
441 pi->tx_vos = 0xffff;
442 pi->nrssi_table_delta = 0x7fffffff;
443 pi->rc_cal = 0xffff;
444 pi->mintxbias = 0xffff;
445 pi->txpwridx = -1;
446 if (ISNPHY(pi)) {
447 pi->phy_spuravoid = SPURAVOID_DISABLE;
449 if (NREV_GE(pi->pubpi.phy_rev, 3)
450 && NREV_LT(pi->pubpi.phy_rev, 7))
451 pi->phy_spuravoid = SPURAVOID_AUTO;
453 pi->nphy_papd_skip = 0;
454 pi->nphy_papd_epsilon_offset[0] = 0xf588;
455 pi->nphy_papd_epsilon_offset[1] = 0xf588;
456 pi->nphy_txpwr_idx[0] = 128;
457 pi->nphy_txpwr_idx[1] = 128;
458 pi->nphy_txpwrindex[0].index_internal = 40;
459 pi->nphy_txpwrindex[1].index_internal = 40;
460 pi->phy_pabias = 0;
461 } else {
462 pi->phy_spuravoid = SPURAVOID_AUTO;
464 pi->radiopwr = 0xffff;
465 for (i = 0; i < STATIC_NUM_RF; i++) {
466 for (j = 0; j < STATIC_NUM_BB; j++)
467 pi->stats_11b_txpower[i][j] = -1;
471 struct shared_phy *wlc_phy_shared_attach(struct shared_phy_params *shp)
473 struct shared_phy *sh;
475 sh = kzalloc(sizeof(struct shared_phy), GFP_ATOMIC);
476 if (sh == NULL)
477 return NULL;
479 sh->sih = shp->sih;
480 sh->physhim = shp->physhim;
481 sh->unit = shp->unit;
482 sh->corerev = shp->corerev;
484 sh->vid = shp->vid;
485 sh->did = shp->did;
486 sh->chip = shp->chip;
487 sh->chiprev = shp->chiprev;
488 sh->chippkg = shp->chippkg;
489 sh->sromrev = shp->sromrev;
490 sh->boardtype = shp->boardtype;
491 sh->boardrev = shp->boardrev;
492 sh->boardvendor = shp->boardvendor;
493 sh->boardflags = shp->boardflags;
494 sh->boardflags2 = shp->boardflags2;
495 sh->buscorerev = shp->buscorerev;
497 sh->fast_timer = PHY_SW_TIMER_FAST;
498 sh->slow_timer = PHY_SW_TIMER_SLOW;
499 sh->glacial_timer = PHY_SW_TIMER_GLACIAL;
501 sh->rssi_mode = RSSI_ANT_MERGE_MAX;
503 return sh;
506 struct brcms_phy_pub *
507 wlc_phy_attach(struct shared_phy *sh, struct d11regs *regs, int bandtype,
508 char *vars, struct wiphy *wiphy)
510 struct brcms_phy *pi;
511 u32 sflags = 0;
512 uint phyversion;
513 u32 idcode;
514 int i;
516 if (D11REV_IS(sh->corerev, 4))
517 sflags = SISF_2G_PHY | SISF_5G_PHY;
518 else
519 sflags = ai_core_sflags(sh->sih, 0, 0);
521 if (BAND_5G(bandtype)) {
522 if ((sflags & (SISF_5G_PHY | SISF_DB_PHY)) == 0)
523 return NULL;
526 pi = sh->phy_head;
527 if ((sflags & SISF_DB_PHY) && pi) {
528 wlapi_bmac_corereset(pi->sh->physhim, pi->pubpi.coreflags);
529 pi->refcnt++;
530 return &pi->pubpi_ro;
533 pi = kzalloc(sizeof(struct brcms_phy), GFP_ATOMIC);
534 if (pi == NULL)
535 return NULL;
536 pi->wiphy = wiphy;
537 pi->regs = regs;
538 pi->sh = sh;
539 pi->phy_init_por = true;
540 pi->phy_wreg_limit = PHY_WREG_LIMIT;
542 pi->vars = vars;
544 pi->txpwr_percent = 100;
546 pi->do_initcal = true;
548 pi->phycal_tempdelta = 0;
550 if (BAND_2G(bandtype) && (sflags & SISF_2G_PHY))
551 pi->pubpi.coreflags = SICF_GMODE;
553 wlapi_bmac_corereset(pi->sh->physhim, pi->pubpi.coreflags);
554 phyversion = R_REG(&pi->regs->phyversion);
556 pi->pubpi.phy_type = PHY_TYPE(phyversion);
557 pi->pubpi.phy_rev = phyversion & PV_PV_MASK;
559 if (pi->pubpi.phy_type == PHY_TYPE_LCNXN) {
560 pi->pubpi.phy_type = PHY_TYPE_N;
561 pi->pubpi.phy_rev += LCNXN_BASEREV;
563 pi->pubpi.phy_corenum = PHY_CORE_NUM_2;
564 pi->pubpi.ana_rev = (phyversion & PV_AV_MASK) >> PV_AV_SHIFT;
566 if (!VALID_PHYTYPE(pi->pubpi.phy_type))
567 goto err;
569 if (BAND_5G(bandtype)) {
570 if (!ISNPHY(pi))
571 goto err;
572 } else if (!ISNPHY(pi) && !ISLCNPHY(pi)) {
573 goto err;
576 wlc_phy_anacore((struct brcms_phy_pub *) pi, ON);
578 idcode = wlc_phy_get_radio_ver(pi);
579 pi->pubpi.radioid =
580 (idcode & IDCODE_ID_MASK) >> IDCODE_ID_SHIFT;
581 pi->pubpi.radiorev =
582 (idcode & IDCODE_REV_MASK) >> IDCODE_REV_SHIFT;
583 pi->pubpi.radiover =
584 (idcode & IDCODE_VER_MASK) >> IDCODE_VER_SHIFT;
585 if (!VALID_RADIO(pi, pi->pubpi.radioid))
586 goto err;
588 wlc_phy_switch_radio((struct brcms_phy_pub *) pi, OFF);
590 wlc_set_phy_uninitted(pi);
592 pi->bw = WL_CHANSPEC_BW_20;
593 pi->radio_chanspec =
594 BAND_2G(bandtype) ? CH20MHZ_CHSPEC(1) : CH20MHZ_CHSPEC(36);
596 pi->rxiq_samps = PHY_NOISE_SAMPLE_LOG_NUM_NPHY;
597 pi->rxiq_antsel = ANT_RX_DIV_DEF;
599 pi->watchdog_override = true;
601 pi->cal_type_override = PHY_PERICAL_AUTO;
603 pi->nphy_saved_noisevars.bufcount = 0;
605 if (ISNPHY(pi))
606 pi->min_txpower = PHY_TXPWR_MIN_NPHY;
607 else
608 pi->min_txpower = PHY_TXPWR_MIN;
610 pi->sh->phyrxchain = 0x3;
612 pi->rx2tx_biasentry = -1;
614 pi->phy_txcore_disable_temp = PHY_CHAIN_TX_DISABLE_TEMP;
615 pi->phy_txcore_enable_temp =
616 PHY_CHAIN_TX_DISABLE_TEMP - PHY_HYSTERESIS_DELTATEMP;
617 pi->phy_tempsense_offset = 0;
618 pi->phy_txcore_heatedup = false;
620 pi->nphy_lastcal_temp = -50;
622 pi->phynoise_polling = true;
623 if (ISNPHY(pi) || ISLCNPHY(pi))
624 pi->phynoise_polling = false;
626 for (i = 0; i < TXP_NUM_RATES; i++) {
627 pi->txpwr_limit[i] = BRCMS_TXPWR_MAX;
628 pi->txpwr_env_limit[i] = BRCMS_TXPWR_MAX;
629 pi->tx_user_target[i] = BRCMS_TXPWR_MAX;
632 pi->radiopwr_override = RADIOPWR_OVERRIDE_DEF;
634 pi->user_txpwr_at_rfport = false;
636 if (ISNPHY(pi)) {
638 pi->phycal_timer = wlapi_init_timer(pi->sh->physhim,
639 wlc_phy_timercb_phycal,
640 pi, "phycal");
641 if (!pi->phycal_timer)
642 goto err;
644 if (!wlc_phy_attach_nphy(pi))
645 goto err;
647 } else if (ISLCNPHY(pi)) {
648 if (!wlc_phy_attach_lcnphy(pi))
649 goto err;
653 pi->refcnt++;
654 pi->next = pi->sh->phy_head;
655 sh->phy_head = pi;
657 pi->vars = (char *)&pi->vars;
659 memcpy(&pi->pubpi_ro, &pi->pubpi, sizeof(struct brcms_phy_pub));
661 return &pi->pubpi_ro;
663 err:
664 kfree(pi);
665 return NULL;
668 void wlc_phy_detach(struct brcms_phy_pub *pih)
670 struct brcms_phy *pi = (struct brcms_phy *) pih;
672 if (pih) {
673 if (--pi->refcnt)
674 return;
676 if (pi->phycal_timer) {
677 wlapi_free_timer(pi->sh->physhim, pi->phycal_timer);
678 pi->phycal_timer = NULL;
681 if (pi->sh->phy_head == pi)
682 pi->sh->phy_head = pi->next;
683 else if (pi->sh->phy_head->next == pi)
684 pi->sh->phy_head->next = NULL;
686 if (pi->pi_fptr.detach)
687 (pi->pi_fptr.detach)(pi);
689 kfree(pi);
693 bool
694 wlc_phy_get_phyversion(struct brcms_phy_pub *pih, u16 *phytype, u16 *phyrev,
695 u16 *radioid, u16 *radiover)
697 struct brcms_phy *pi = (struct brcms_phy *) pih;
698 *phytype = (u16) pi->pubpi.phy_type;
699 *phyrev = (u16) pi->pubpi.phy_rev;
700 *radioid = pi->pubpi.radioid;
701 *radiover = pi->pubpi.radiorev;
703 return true;
706 bool wlc_phy_get_encore(struct brcms_phy_pub *pih)
708 struct brcms_phy *pi = (struct brcms_phy *) pih;
709 return pi->pubpi.abgphy_encore;
712 u32 wlc_phy_get_coreflags(struct brcms_phy_pub *pih)
714 struct brcms_phy *pi = (struct brcms_phy *) pih;
715 return pi->pubpi.coreflags;
718 static void wlc_phy_timercb_phycal(struct brcms_phy *pi)
720 uint delay = 5;
722 if (PHY_PERICAL_MPHASE_PENDING(pi)) {
723 if (!pi->sh->up) {
724 wlc_phy_cal_perical_mphase_reset(pi);
725 return;
728 if (SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi)) {
730 delay = 1000;
731 wlc_phy_cal_perical_mphase_restart(pi);
732 } else
733 wlc_phy_cal_perical_nphy_run(pi, PHY_PERICAL_AUTO);
734 wlapi_add_timer(pi->sh->physhim, pi->phycal_timer, delay, 0);
735 return;
740 void wlc_phy_anacore(struct brcms_phy_pub *pih, bool on)
742 struct brcms_phy *pi = (struct brcms_phy *) pih;
744 if (ISNPHY(pi)) {
745 if (on) {
746 if (NREV_GE(pi->pubpi.phy_rev, 3)) {
747 write_phy_reg(pi, 0xa6, 0x0d);
748 write_phy_reg(pi, 0x8f, 0x0);
749 write_phy_reg(pi, 0xa7, 0x0d);
750 write_phy_reg(pi, 0xa5, 0x0);
751 } else {
752 write_phy_reg(pi, 0xa5, 0x0);
754 } else {
755 if (NREV_GE(pi->pubpi.phy_rev, 3)) {
756 write_phy_reg(pi, 0x8f, 0x07ff);
757 write_phy_reg(pi, 0xa6, 0x0fd);
758 write_phy_reg(pi, 0xa5, 0x07ff);
759 write_phy_reg(pi, 0xa7, 0x0fd);
760 } else {
761 write_phy_reg(pi, 0xa5, 0x7fff);
764 } else if (ISLCNPHY(pi)) {
765 if (on) {
766 and_phy_reg(pi, 0x43b,
767 ~((0x1 << 0) | (0x1 << 1) | (0x1 << 2)));
768 } else {
769 or_phy_reg(pi, 0x43c,
770 (0x1 << 0) | (0x1 << 1) | (0x1 << 2));
771 or_phy_reg(pi, 0x43b,
772 (0x1 << 0) | (0x1 << 1) | (0x1 << 2));
777 u32 wlc_phy_clk_bwbits(struct brcms_phy_pub *pih)
779 struct brcms_phy *pi = (struct brcms_phy *) pih;
781 u32 phy_bw_clkbits = 0;
783 if (pi && (ISNPHY(pi) || ISLCNPHY(pi))) {
784 switch (pi->bw) {
785 case WL_CHANSPEC_BW_10:
786 phy_bw_clkbits = SICF_BW10;
787 break;
788 case WL_CHANSPEC_BW_20:
789 phy_bw_clkbits = SICF_BW20;
790 break;
791 case WL_CHANSPEC_BW_40:
792 phy_bw_clkbits = SICF_BW40;
793 break;
794 default:
795 break;
799 return phy_bw_clkbits;
802 void wlc_phy_por_inform(struct brcms_phy_pub *ppi)
804 struct brcms_phy *pi = (struct brcms_phy *) ppi;
806 pi->phy_init_por = true;
809 void wlc_phy_edcrs_lock(struct brcms_phy_pub *pih, bool lock)
811 struct brcms_phy *pi = (struct brcms_phy *) pih;
813 pi->edcrs_threshold_lock = lock;
815 write_phy_reg(pi, 0x22c, 0x46b);
816 write_phy_reg(pi, 0x22d, 0x46b);
817 write_phy_reg(pi, 0x22e, 0x3c0);
818 write_phy_reg(pi, 0x22f, 0x3c0);
821 void wlc_phy_initcal_enable(struct brcms_phy_pub *pih, bool initcal)
823 struct brcms_phy *pi = (struct brcms_phy *) pih;
825 pi->do_initcal = initcal;
828 void wlc_phy_hw_clk_state_upd(struct brcms_phy_pub *pih, bool newstate)
830 struct brcms_phy *pi = (struct brcms_phy *) pih;
832 if (!pi || !pi->sh)
833 return;
835 pi->sh->clk = newstate;
838 void wlc_phy_hw_state_upd(struct brcms_phy_pub *pih, bool newstate)
840 struct brcms_phy *pi = (struct brcms_phy *) pih;
842 if (!pi || !pi->sh)
843 return;
845 pi->sh->up = newstate;
848 void wlc_phy_init(struct brcms_phy_pub *pih, u16 chanspec)
850 u32 mc;
851 void (*phy_init)(struct brcms_phy *) = NULL;
852 struct brcms_phy *pi = (struct brcms_phy *) pih;
854 if (pi->init_in_progress)
855 return;
857 pi->init_in_progress = true;
859 pi->radio_chanspec = chanspec;
861 mc = R_REG(&pi->regs->maccontrol);
862 if (WARN(mc & MCTL_EN_MAC, "HW error MAC running on init"))
863 return;
865 if (!(pi->measure_hold & PHY_HOLD_FOR_SCAN))
866 pi->measure_hold |= PHY_HOLD_FOR_NOT_ASSOC;
868 if (WARN(!(ai_core_sflags(pi->sh->sih, 0, 0) & SISF_FCLKA),
869 "HW error SISF_FCLKA\n"))
870 return;
872 phy_init = pi->pi_fptr.init;
874 if (phy_init == NULL)
875 return;
877 wlc_phy_anacore(pih, ON);
879 if (CHSPEC_BW(pi->radio_chanspec) != pi->bw)
880 wlapi_bmac_bw_set(pi->sh->physhim,
881 CHSPEC_BW(pi->radio_chanspec));
883 pi->nphy_gain_boost = true;
885 wlc_phy_switch_radio((struct brcms_phy_pub *) pi, ON);
887 (*phy_init)(pi);
889 pi->phy_init_por = false;
891 if (D11REV_IS(pi->sh->corerev, 11) || D11REV_IS(pi->sh->corerev, 12))
892 wlc_phy_do_dummy_tx(pi, true, OFF);
894 if (!(ISNPHY(pi)))
895 wlc_phy_txpower_update_shm(pi);
897 wlc_phy_ant_rxdiv_set((struct brcms_phy_pub *) pi, pi->sh->rx_antdiv);
899 pi->init_in_progress = false;
902 void wlc_phy_cal_init(struct brcms_phy_pub *pih)
904 struct brcms_phy *pi = (struct brcms_phy *) pih;
905 void (*cal_init)(struct brcms_phy *) = NULL;
907 if (WARN((R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC) != 0,
908 "HW error: MAC enabled during phy cal\n"))
909 return;
911 if (!pi->initialized) {
912 cal_init = pi->pi_fptr.calinit;
913 if (cal_init)
914 (*cal_init)(pi);
916 pi->initialized = true;
920 int wlc_phy_down(struct brcms_phy_pub *pih)
922 struct brcms_phy *pi = (struct brcms_phy *) pih;
923 int callbacks = 0;
925 if (pi->phycal_timer
926 && !wlapi_del_timer(pi->sh->physhim, pi->phycal_timer))
927 callbacks++;
929 pi->nphy_iqcal_chanspec_2G = 0;
930 pi->nphy_iqcal_chanspec_5G = 0;
932 return callbacks;
935 static u32 wlc_phy_get_radio_ver(struct brcms_phy *pi)
937 u32 ver;
939 ver = read_radio_id(pi);
941 return ver;
944 void
945 wlc_phy_table_addr(struct brcms_phy *pi, uint tbl_id, uint tbl_offset,
946 u16 tblAddr, u16 tblDataHi, u16 tblDataLo)
948 write_phy_reg(pi, tblAddr, (tbl_id << 10) | tbl_offset);
950 pi->tbl_data_hi = tblDataHi;
951 pi->tbl_data_lo = tblDataLo;
953 if (pi->sh->chip == BCM43224_CHIP_ID &&
954 pi->sh->chiprev == 1) {
955 pi->tbl_addr = tblAddr;
956 pi->tbl_save_id = tbl_id;
957 pi->tbl_save_offset = tbl_offset;
961 void wlc_phy_table_data_write(struct brcms_phy *pi, uint width, u32 val)
963 if ((pi->sh->chip == BCM43224_CHIP_ID) &&
964 (pi->sh->chiprev == 1) &&
965 (pi->tbl_save_id == NPHY_TBL_ID_ANTSWCTRLLUT)) {
966 read_phy_reg(pi, pi->tbl_data_lo);
968 write_phy_reg(pi, pi->tbl_addr,
969 (pi->tbl_save_id << 10) | pi->tbl_save_offset);
970 pi->tbl_save_offset++;
973 if (width == 32) {
974 write_phy_reg(pi, pi->tbl_data_hi, (u16) (val >> 16));
975 write_phy_reg(pi, pi->tbl_data_lo, (u16) val);
976 } else {
977 write_phy_reg(pi, pi->tbl_data_lo, (u16) val);
981 void
982 wlc_phy_write_table(struct brcms_phy *pi, const struct phytbl_info *ptbl_info,
983 u16 tblAddr, u16 tblDataHi, u16 tblDataLo)
985 uint idx;
986 uint tbl_id = ptbl_info->tbl_id;
987 uint tbl_offset = ptbl_info->tbl_offset;
988 uint tbl_width = ptbl_info->tbl_width;
989 const u8 *ptbl_8b = (const u8 *)ptbl_info->tbl_ptr;
990 const u16 *ptbl_16b = (const u16 *)ptbl_info->tbl_ptr;
991 const u32 *ptbl_32b = (const u32 *)ptbl_info->tbl_ptr;
993 write_phy_reg(pi, tblAddr, (tbl_id << 10) | tbl_offset);
995 for (idx = 0; idx < ptbl_info->tbl_len; idx++) {
997 if ((pi->sh->chip == BCM43224_CHIP_ID) &&
998 (pi->sh->chiprev == 1) &&
999 (tbl_id == NPHY_TBL_ID_ANTSWCTRLLUT)) {
1000 read_phy_reg(pi, tblDataLo);
1002 write_phy_reg(pi, tblAddr,
1003 (tbl_id << 10) | (tbl_offset + idx));
1006 if (tbl_width == 32) {
1007 write_phy_reg(pi, tblDataHi,
1008 (u16) (ptbl_32b[idx] >> 16));
1009 write_phy_reg(pi, tblDataLo, (u16) ptbl_32b[idx]);
1010 } else if (tbl_width == 16) {
1011 write_phy_reg(pi, tblDataLo, ptbl_16b[idx]);
1012 } else {
1013 write_phy_reg(pi, tblDataLo, ptbl_8b[idx]);
1018 void
1019 wlc_phy_read_table(struct brcms_phy *pi, const struct phytbl_info *ptbl_info,
1020 u16 tblAddr, u16 tblDataHi, u16 tblDataLo)
1022 uint idx;
1023 uint tbl_id = ptbl_info->tbl_id;
1024 uint tbl_offset = ptbl_info->tbl_offset;
1025 uint tbl_width = ptbl_info->tbl_width;
1026 u8 *ptbl_8b = (u8 *)ptbl_info->tbl_ptr;
1027 u16 *ptbl_16b = (u16 *)ptbl_info->tbl_ptr;
1028 u32 *ptbl_32b = (u32 *)ptbl_info->tbl_ptr;
1030 write_phy_reg(pi, tblAddr, (tbl_id << 10) | tbl_offset);
1032 for (idx = 0; idx < ptbl_info->tbl_len; idx++) {
1034 if ((pi->sh->chip == BCM43224_CHIP_ID) &&
1035 (pi->sh->chiprev == 1)) {
1036 (void)read_phy_reg(pi, tblDataLo);
1038 write_phy_reg(pi, tblAddr,
1039 (tbl_id << 10) | (tbl_offset + idx));
1042 if (tbl_width == 32) {
1043 ptbl_32b[idx] = read_phy_reg(pi, tblDataLo);
1044 ptbl_32b[idx] |= (read_phy_reg(pi, tblDataHi) << 16);
1045 } else if (tbl_width == 16) {
1046 ptbl_16b[idx] = read_phy_reg(pi, tblDataLo);
1047 } else {
1048 ptbl_8b[idx] = (u8) read_phy_reg(pi, tblDataLo);
1053 uint
1054 wlc_phy_init_radio_regs_allbands(struct brcms_phy *pi,
1055 struct radio_20xx_regs *radioregs)
1057 uint i = 0;
1059 do {
1060 if (radioregs[i].do_init)
1061 write_radio_reg(pi, radioregs[i].address,
1062 (u16) radioregs[i].init);
1064 i++;
1065 } while (radioregs[i].address != 0xffff);
1067 return i;
1070 uint
1071 wlc_phy_init_radio_regs(struct brcms_phy *pi, struct radio_regs *radioregs,
1072 u16 core_offset)
1074 uint i = 0;
1075 uint count = 0;
1077 do {
1078 if (CHSPEC_IS5G(pi->radio_chanspec)) {
1079 if (radioregs[i].do_init_a) {
1080 write_radio_reg(pi,
1081 radioregs[i].
1082 address | core_offset,
1083 (u16) radioregs[i].init_a);
1084 if (ISNPHY(pi) && (++count % 4 == 0))
1085 BRCMS_PHY_WAR_PR51571(pi);
1087 } else {
1088 if (radioregs[i].do_init_g) {
1089 write_radio_reg(pi,
1090 radioregs[i].
1091 address | core_offset,
1092 (u16) radioregs[i].init_g);
1093 if (ISNPHY(pi) && (++count % 4 == 0))
1094 BRCMS_PHY_WAR_PR51571(pi);
1098 i++;
1099 } while (radioregs[i].address != 0xffff);
1101 return i;
1104 void wlc_phy_do_dummy_tx(struct brcms_phy *pi, bool ofdm, bool pa_on)
1106 #define DUMMY_PKT_LEN 20
1107 struct d11regs *regs = pi->regs;
1108 int i, count;
1109 u8 ofdmpkt[DUMMY_PKT_LEN] = {
1110 0xcc, 0x01, 0x02, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00,
1111 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00
1113 u8 cckpkt[DUMMY_PKT_LEN] = {
1114 0x6e, 0x84, 0x0b, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00,
1115 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00
1117 u32 *dummypkt;
1119 dummypkt = (u32 *) (ofdm ? ofdmpkt : cckpkt);
1120 wlapi_bmac_write_template_ram(pi->sh->physhim, 0, DUMMY_PKT_LEN,
1121 dummypkt);
1123 W_REG(&regs->xmtsel, 0);
1125 if (D11REV_GE(pi->sh->corerev, 11))
1126 W_REG(&regs->wepctl, 0x100);
1127 else
1128 W_REG(&regs->wepctl, 0);
1130 W_REG(&regs->txe_phyctl, (ofdm ? 1 : 0) | PHY_TXC_ANT_0);
1131 if (ISNPHY(pi) || ISLCNPHY(pi))
1132 W_REG(&regs->txe_phyctl1, 0x1A02);
1134 W_REG(&regs->txe_wm_0, 0);
1135 W_REG(&regs->txe_wm_1, 0);
1137 W_REG(&regs->xmttplatetxptr, 0);
1138 W_REG(&regs->xmttxcnt, DUMMY_PKT_LEN);
1140 W_REG(&regs->xmtsel, ((8 << 8) | (1 << 5) | (1 << 2) | 2));
1142 W_REG(&regs->txe_ctl, 0);
1144 if (!pa_on) {
1145 if (ISNPHY(pi))
1146 wlc_phy_pa_override_nphy(pi, OFF);
1149 if (ISNPHY(pi) || ISLCNPHY(pi))
1150 W_REG(&regs->txe_aux, 0xD0);
1151 else
1152 W_REG(&regs->txe_aux, ((1 << 5) | (1 << 4)));
1154 (void)R_REG(&regs->txe_aux);
1156 i = 0;
1157 count = ofdm ? 30 : 250;
1158 while ((i++ < count)
1159 && (R_REG(&regs->txe_status) & (1 << 7)))
1160 udelay(10);
1162 i = 0;
1164 while ((i++ < 10)
1165 && ((R_REG(&regs->txe_status) & (1 << 10)) == 0))
1166 udelay(10);
1168 i = 0;
1170 while ((i++ < 10) && ((R_REG(&regs->ifsstat) & (1 << 8))))
1171 udelay(10);
1173 if (!pa_on) {
1174 if (ISNPHY(pi))
1175 wlc_phy_pa_override_nphy(pi, ON);
1179 void wlc_phy_hold_upd(struct brcms_phy_pub *pih, u32 id, bool set)
1181 struct brcms_phy *pi = (struct brcms_phy *) pih;
1183 if (set)
1184 mboolset(pi->measure_hold, id);
1185 else
1186 mboolclr(pi->measure_hold, id);
1188 return;
1191 void wlc_phy_mute_upd(struct brcms_phy_pub *pih, bool mute, u32 flags)
1193 struct brcms_phy *pi = (struct brcms_phy *) pih;
1195 if (mute)
1196 mboolset(pi->measure_hold, PHY_HOLD_FOR_MUTE);
1197 else
1198 mboolclr(pi->measure_hold, PHY_HOLD_FOR_MUTE);
1200 if (!mute && (flags & PHY_MUTE_FOR_PREISM))
1201 pi->nphy_perical_last = pi->sh->now - pi->sh->glacial_timer;
1202 return;
1205 void wlc_phy_clear_tssi(struct brcms_phy_pub *pih)
1207 struct brcms_phy *pi = (struct brcms_phy *) pih;
1209 if (ISNPHY(pi)) {
1210 return;
1211 } else {
1212 wlapi_bmac_write_shm(pi->sh->physhim, M_B_TSSI_0, NULL_TSSI_W);
1213 wlapi_bmac_write_shm(pi->sh->physhim, M_B_TSSI_1, NULL_TSSI_W);
1214 wlapi_bmac_write_shm(pi->sh->physhim, M_G_TSSI_0, NULL_TSSI_W);
1215 wlapi_bmac_write_shm(pi->sh->physhim, M_G_TSSI_1, NULL_TSSI_W);
1219 static bool wlc_phy_cal_txpower_recalc_sw(struct brcms_phy *pi)
1221 return false;
1224 void wlc_phy_switch_radio(struct brcms_phy_pub *pih, bool on)
1226 struct brcms_phy *pi = (struct brcms_phy *) pih;
1228 if (NORADIO_ENAB(pi->pubpi))
1229 return;
1232 uint mc;
1234 mc = R_REG(&pi->regs->maccontrol);
1237 if (ISNPHY(pi)) {
1238 wlc_phy_switch_radio_nphy(pi, on);
1239 } else if (ISLCNPHY(pi)) {
1240 if (on) {
1241 and_phy_reg(pi, 0x44c,
1242 ~((0x1 << 8) |
1243 (0x1 << 9) |
1244 (0x1 << 10) | (0x1 << 11) | (0x1 << 12)));
1245 and_phy_reg(pi, 0x4b0, ~((0x1 << 3) | (0x1 << 11)));
1246 and_phy_reg(pi, 0x4f9, ~(0x1 << 3));
1247 } else {
1248 and_phy_reg(pi, 0x44d,
1249 ~((0x1 << 10) |
1250 (0x1 << 11) |
1251 (0x1 << 12) | (0x1 << 13) | (0x1 << 14)));
1252 or_phy_reg(pi, 0x44c,
1253 (0x1 << 8) |
1254 (0x1 << 9) |
1255 (0x1 << 10) | (0x1 << 11) | (0x1 << 12));
1257 and_phy_reg(pi, 0x4b7, ~((0x7f << 8)));
1258 and_phy_reg(pi, 0x4b1, ~((0x1 << 13)));
1259 or_phy_reg(pi, 0x4b0, (0x1 << 3) | (0x1 << 11));
1260 and_phy_reg(pi, 0x4fa, ~((0x1 << 3)));
1261 or_phy_reg(pi, 0x4f9, (0x1 << 3));
1266 u16 wlc_phy_bw_state_get(struct brcms_phy_pub *ppi)
1268 struct brcms_phy *pi = (struct brcms_phy *) ppi;
1270 return pi->bw;
1273 void wlc_phy_bw_state_set(struct brcms_phy_pub *ppi, u16 bw)
1275 struct brcms_phy *pi = (struct brcms_phy *) ppi;
1277 pi->bw = bw;
1280 void wlc_phy_chanspec_radio_set(struct brcms_phy_pub *ppi, u16 newch)
1282 struct brcms_phy *pi = (struct brcms_phy *) ppi;
1283 pi->radio_chanspec = newch;
1287 u16 wlc_phy_chanspec_get(struct brcms_phy_pub *ppi)
1289 struct brcms_phy *pi = (struct brcms_phy *) ppi;
1291 return pi->radio_chanspec;
1294 void wlc_phy_chanspec_set(struct brcms_phy_pub *ppi, u16 chanspec)
1296 struct brcms_phy *pi = (struct brcms_phy *) ppi;
1297 u16 m_cur_channel;
1298 void (*chanspec_set)(struct brcms_phy *, u16) = NULL;
1299 m_cur_channel = CHSPEC_CHANNEL(chanspec);
1300 if (CHSPEC_IS5G(chanspec))
1301 m_cur_channel |= D11_CURCHANNEL_5G;
1302 if (CHSPEC_IS40(chanspec))
1303 m_cur_channel |= D11_CURCHANNEL_40;
1304 wlapi_bmac_write_shm(pi->sh->physhim, M_CURCHANNEL, m_cur_channel);
1306 chanspec_set = pi->pi_fptr.chanset;
1307 if (chanspec_set)
1308 (*chanspec_set)(pi, chanspec);
1312 int wlc_phy_chanspec_freq2bandrange_lpssn(uint freq)
1314 int range = -1;
1316 if (freq < 2500)
1317 range = WL_CHAN_FREQ_RANGE_2G;
1318 else if (freq <= 5320)
1319 range = WL_CHAN_FREQ_RANGE_5GL;
1320 else if (freq <= 5700)
1321 range = WL_CHAN_FREQ_RANGE_5GM;
1322 else
1323 range = WL_CHAN_FREQ_RANGE_5GH;
1325 return range;
1328 int wlc_phy_chanspec_bandrange_get(struct brcms_phy *pi, u16 chanspec)
1330 int range = -1;
1331 uint channel = CHSPEC_CHANNEL(chanspec);
1332 uint freq = wlc_phy_channel2freq(channel);
1334 if (ISNPHY(pi))
1335 range = wlc_phy_get_chan_freq_range_nphy(pi, channel);
1336 else if (ISLCNPHY(pi))
1337 range = wlc_phy_chanspec_freq2bandrange_lpssn(freq);
1339 return range;
1342 void wlc_phy_chanspec_ch14_widefilter_set(struct brcms_phy_pub *ppi,
1343 bool wide_filter)
1345 struct brcms_phy *pi = (struct brcms_phy *) ppi;
1347 pi->channel_14_wide_filter = wide_filter;
1351 int wlc_phy_channel2freq(uint channel)
1353 uint i;
1355 for (i = 0; i < ARRAY_SIZE(chan_info_all); i++)
1356 if (chan_info_all[i].chan == channel)
1357 return chan_info_all[i].freq;
1358 return 0;
1361 void
1362 wlc_phy_chanspec_band_validch(struct brcms_phy_pub *ppi, uint band,
1363 struct brcms_chanvec *channels)
1365 struct brcms_phy *pi = (struct brcms_phy *) ppi;
1366 uint i;
1367 uint channel;
1369 memset(channels, 0, sizeof(struct brcms_chanvec));
1371 for (i = 0; i < ARRAY_SIZE(chan_info_all); i++) {
1372 channel = chan_info_all[i].chan;
1374 if ((pi->a_band_high_disable) && (channel >= FIRST_REF5_CHANNUM)
1375 && (channel <= LAST_REF5_CHANNUM))
1376 continue;
1378 if ((band == BRCM_BAND_2G && channel <= CH_MAX_2G_CHANNEL) ||
1379 (band == BRCM_BAND_5G && channel > CH_MAX_2G_CHANNEL))
1380 setbit(channels->vec, channel);
1384 u16 wlc_phy_chanspec_band_firstch(struct brcms_phy_pub *ppi, uint band)
1386 struct brcms_phy *pi = (struct brcms_phy *) ppi;
1387 uint i;
1388 uint channel;
1389 u16 chspec;
1391 for (i = 0; i < ARRAY_SIZE(chan_info_all); i++) {
1392 channel = chan_info_all[i].chan;
1394 if (ISNPHY(pi) && IS40MHZ(pi)) {
1395 uint j;
1397 for (j = 0; j < ARRAY_SIZE(chan_info_all); j++) {
1398 if (chan_info_all[j].chan ==
1399 channel + CH_10MHZ_APART)
1400 break;
1403 if (j == ARRAY_SIZE(chan_info_all))
1404 continue;
1406 channel = UPPER_20_SB(channel);
1407 chspec = channel | WL_CHANSPEC_BW_40 |
1408 WL_CHANSPEC_CTL_SB_LOWER;
1409 if (band == BRCM_BAND_2G)
1410 chspec |= WL_CHANSPEC_BAND_2G;
1411 else
1412 chspec |= WL_CHANSPEC_BAND_5G;
1413 } else
1414 chspec = CH20MHZ_CHSPEC(channel);
1416 if ((pi->a_band_high_disable) && (channel >= FIRST_REF5_CHANNUM)
1417 && (channel <= LAST_REF5_CHANNUM))
1418 continue;
1420 if ((band == BRCM_BAND_2G && channel <= CH_MAX_2G_CHANNEL) ||
1421 (band == BRCM_BAND_5G && channel > CH_MAX_2G_CHANNEL))
1422 return chspec;
1425 return (u16) INVCHANSPEC;
1428 int wlc_phy_txpower_get(struct brcms_phy_pub *ppi, uint *qdbm, bool *override)
1430 struct brcms_phy *pi = (struct brcms_phy *) ppi;
1432 *qdbm = pi->tx_user_target[0];
1433 if (override != NULL)
1434 *override = pi->txpwroverride;
1435 return 0;
1438 void wlc_phy_txpower_target_set(struct brcms_phy_pub *ppi,
1439 struct txpwr_limits *txpwr)
1441 bool mac_enabled = false;
1442 struct brcms_phy *pi = (struct brcms_phy *) ppi;
1444 memcpy(&pi->tx_user_target[TXP_FIRST_CCK],
1445 &txpwr->cck[0], BRCMS_NUM_RATES_CCK);
1447 memcpy(&pi->tx_user_target[TXP_FIRST_OFDM],
1448 &txpwr->ofdm[0], BRCMS_NUM_RATES_OFDM);
1449 memcpy(&pi->tx_user_target[TXP_FIRST_OFDM_20_CDD],
1450 &txpwr->ofdm_cdd[0], BRCMS_NUM_RATES_OFDM);
1452 memcpy(&pi->tx_user_target[TXP_FIRST_OFDM_40_SISO],
1453 &txpwr->ofdm_40_siso[0], BRCMS_NUM_RATES_OFDM);
1454 memcpy(&pi->tx_user_target[TXP_FIRST_OFDM_40_CDD],
1455 &txpwr->ofdm_40_cdd[0], BRCMS_NUM_RATES_OFDM);
1457 memcpy(&pi->tx_user_target[TXP_FIRST_MCS_20_SISO],
1458 &txpwr->mcs_20_siso[0], BRCMS_NUM_RATES_MCS_1_STREAM);
1459 memcpy(&pi->tx_user_target[TXP_FIRST_MCS_20_CDD],
1460 &txpwr->mcs_20_cdd[0], BRCMS_NUM_RATES_MCS_1_STREAM);
1461 memcpy(&pi->tx_user_target[TXP_FIRST_MCS_20_STBC],
1462 &txpwr->mcs_20_stbc[0], BRCMS_NUM_RATES_MCS_1_STREAM);
1463 memcpy(&pi->tx_user_target[TXP_FIRST_MCS_20_SDM],
1464 &txpwr->mcs_20_mimo[0], BRCMS_NUM_RATES_MCS_2_STREAM);
1466 memcpy(&pi->tx_user_target[TXP_FIRST_MCS_40_SISO],
1467 &txpwr->mcs_40_siso[0], BRCMS_NUM_RATES_MCS_1_STREAM);
1468 memcpy(&pi->tx_user_target[TXP_FIRST_MCS_40_CDD],
1469 &txpwr->mcs_40_cdd[0], BRCMS_NUM_RATES_MCS_1_STREAM);
1470 memcpy(&pi->tx_user_target[TXP_FIRST_MCS_40_STBC],
1471 &txpwr->mcs_40_stbc[0], BRCMS_NUM_RATES_MCS_1_STREAM);
1472 memcpy(&pi->tx_user_target[TXP_FIRST_MCS_40_SDM],
1473 &txpwr->mcs_40_mimo[0], BRCMS_NUM_RATES_MCS_2_STREAM);
1475 if (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC)
1476 mac_enabled = true;
1478 if (mac_enabled)
1479 wlapi_suspend_mac_and_wait(pi->sh->physhim);
1481 wlc_phy_txpower_recalc_target(pi);
1482 wlc_phy_cal_txpower_recalc_sw(pi);
1484 if (mac_enabled)
1485 wlapi_enable_mac(pi->sh->physhim);
1488 int wlc_phy_txpower_set(struct brcms_phy_pub *ppi, uint qdbm, bool override)
1490 struct brcms_phy *pi = (struct brcms_phy *) ppi;
1491 int i;
1493 if (qdbm > 127)
1494 return 5;
1496 for (i = 0; i < TXP_NUM_RATES; i++)
1497 pi->tx_user_target[i] = (u8) qdbm;
1499 pi->txpwroverride = false;
1501 if (pi->sh->up) {
1502 if (!SCAN_INPROG_PHY(pi)) {
1503 bool suspend;
1505 suspend = (0 == (R_REG(&pi->regs->maccontrol) &
1506 MCTL_EN_MAC));
1508 if (!suspend)
1509 wlapi_suspend_mac_and_wait(pi->sh->physhim);
1511 wlc_phy_txpower_recalc_target(pi);
1512 wlc_phy_cal_txpower_recalc_sw(pi);
1514 if (!suspend)
1515 wlapi_enable_mac(pi->sh->physhim);
1518 return 0;
1521 void
1522 wlc_phy_txpower_sromlimit(struct brcms_phy_pub *ppi, uint channel, u8 *min_pwr,
1523 u8 *max_pwr, int txp_rate_idx)
1525 struct brcms_phy *pi = (struct brcms_phy *) ppi;
1526 uint i;
1528 *min_pwr = pi->min_txpower * BRCMS_TXPWR_DB_FACTOR;
1530 if (ISNPHY(pi)) {
1531 if (txp_rate_idx < 0)
1532 txp_rate_idx = TXP_FIRST_CCK;
1533 wlc_phy_txpower_sromlimit_get_nphy(pi, channel, max_pwr,
1534 (u8) txp_rate_idx);
1536 } else if ((channel <= CH_MAX_2G_CHANNEL)) {
1537 if (txp_rate_idx < 0)
1538 txp_rate_idx = TXP_FIRST_CCK;
1539 *max_pwr = pi->tx_srom_max_rate_2g[txp_rate_idx];
1540 } else {
1542 *max_pwr = BRCMS_TXPWR_MAX;
1544 if (txp_rate_idx < 0)
1545 txp_rate_idx = TXP_FIRST_OFDM;
1547 for (i = 0; i < ARRAY_SIZE(chan_info_all); i++) {
1548 if (channel == chan_info_all[i].chan)
1549 break;
1552 if (pi->hwtxpwr) {
1553 *max_pwr = pi->hwtxpwr[i];
1554 } else {
1556 if ((i >= FIRST_MID_5G_CHAN) && (i <= LAST_MID_5G_CHAN))
1557 *max_pwr =
1558 pi->tx_srom_max_rate_5g_mid[txp_rate_idx];
1559 if ((i >= FIRST_HIGH_5G_CHAN)
1560 && (i <= LAST_HIGH_5G_CHAN))
1561 *max_pwr =
1562 pi->tx_srom_max_rate_5g_hi[txp_rate_idx];
1563 if ((i >= FIRST_LOW_5G_CHAN) && (i <= LAST_LOW_5G_CHAN))
1564 *max_pwr =
1565 pi->tx_srom_max_rate_5g_low[txp_rate_idx];
1570 void
1571 wlc_phy_txpower_sromlimit_max_get(struct brcms_phy_pub *ppi, uint chan,
1572 u8 *max_txpwr, u8 *min_txpwr)
1574 struct brcms_phy *pi = (struct brcms_phy *) ppi;
1575 u8 tx_pwr_max = 0;
1576 u8 tx_pwr_min = 255;
1577 u8 max_num_rate;
1578 u8 maxtxpwr, mintxpwr, rate, pactrl;
1580 pactrl = 0;
1582 max_num_rate = ISNPHY(pi) ? TXP_NUM_RATES :
1583 ISLCNPHY(pi) ? (TXP_LAST_SISO_MCS_20 +
1584 1) : (TXP_LAST_OFDM + 1);
1586 for (rate = 0; rate < max_num_rate; rate++) {
1588 wlc_phy_txpower_sromlimit(ppi, chan, &mintxpwr, &maxtxpwr,
1589 rate);
1591 maxtxpwr = (maxtxpwr > pactrl) ? (maxtxpwr - pactrl) : 0;
1593 maxtxpwr = (maxtxpwr > 6) ? (maxtxpwr - 6) : 0;
1595 tx_pwr_max = max(tx_pwr_max, maxtxpwr);
1596 tx_pwr_min = min(tx_pwr_min, maxtxpwr);
1598 *max_txpwr = tx_pwr_max;
1599 *min_txpwr = tx_pwr_min;
1602 void
1603 wlc_phy_txpower_boardlimit_band(struct brcms_phy_pub *ppi, uint bandunit,
1604 s32 *max_pwr, s32 *min_pwr, u32 *step_pwr)
1606 return;
1609 u8 wlc_phy_txpower_get_target_min(struct brcms_phy_pub *ppi)
1611 struct brcms_phy *pi = (struct brcms_phy *) ppi;
1613 return pi->tx_power_min;
1616 u8 wlc_phy_txpower_get_target_max(struct brcms_phy_pub *ppi)
1618 struct brcms_phy *pi = (struct brcms_phy *) ppi;
1620 return pi->tx_power_max;
1623 void wlc_phy_txpower_recalc_target(struct brcms_phy *pi)
1625 u8 maxtxpwr, mintxpwr, rate, pactrl;
1626 uint target_chan;
1627 u8 tx_pwr_target[TXP_NUM_RATES];
1628 u8 tx_pwr_max = 0;
1629 u8 tx_pwr_min = 255;
1630 u8 tx_pwr_max_rate_ind = 0;
1631 u8 max_num_rate;
1632 u8 start_rate = 0;
1633 u16 chspec;
1634 u32 band = CHSPEC2BAND(pi->radio_chanspec);
1635 void (*txpwr_recalc_fn)(struct brcms_phy *) = NULL;
1637 chspec = pi->radio_chanspec;
1638 if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_NONE)
1639 target_chan = CHSPEC_CHANNEL(chspec);
1640 else if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_UPPER)
1641 target_chan = UPPER_20_SB(CHSPEC_CHANNEL(chspec));
1642 else
1643 target_chan = LOWER_20_SB(CHSPEC_CHANNEL(chspec));
1645 pactrl = 0;
1646 if (ISLCNPHY(pi)) {
1647 u32 offset_mcs, i;
1649 if (CHSPEC_IS40(pi->radio_chanspec)) {
1650 offset_mcs = pi->mcs40_po;
1651 for (i = TXP_FIRST_SISO_MCS_20;
1652 i <= TXP_LAST_SISO_MCS_20; i++) {
1653 pi->tx_srom_max_rate_2g[i - 8] =
1654 pi->tx_srom_max_2g -
1655 ((offset_mcs & 0xf) * 2);
1656 offset_mcs >>= 4;
1658 } else {
1659 offset_mcs = pi->mcs20_po;
1660 for (i = TXP_FIRST_SISO_MCS_20;
1661 i <= TXP_LAST_SISO_MCS_20; i++) {
1662 pi->tx_srom_max_rate_2g[i - 8] =
1663 pi->tx_srom_max_2g -
1664 ((offset_mcs & 0xf) * 2);
1665 offset_mcs >>= 4;
1669 #if WL11N
1670 max_num_rate = ((ISNPHY(pi)) ? (TXP_NUM_RATES) :
1671 ((ISLCNPHY(pi)) ?
1672 (TXP_LAST_SISO_MCS_20 + 1) : (TXP_LAST_OFDM + 1)));
1673 #else
1674 max_num_rate = ((ISNPHY(pi)) ? (TXP_NUM_RATES) : (TXP_LAST_OFDM + 1));
1675 #endif
1677 wlc_phy_upd_env_txpwr_rate_limits(pi, band);
1679 for (rate = start_rate; rate < max_num_rate; rate++) {
1681 tx_pwr_target[rate] = pi->tx_user_target[rate];
1683 if (pi->user_txpwr_at_rfport)
1684 tx_pwr_target[rate] +=
1685 wlc_user_txpwr_antport_to_rfport(pi,
1686 target_chan,
1687 band,
1688 rate);
1692 wlc_phy_txpower_sromlimit((struct brcms_phy_pub *) pi,
1693 target_chan,
1694 &mintxpwr, &maxtxpwr, rate);
1696 maxtxpwr = min(maxtxpwr, pi->txpwr_limit[rate]);
1698 maxtxpwr =
1699 (maxtxpwr > pactrl) ? (maxtxpwr - pactrl) : 0;
1701 maxtxpwr = (maxtxpwr > 6) ? (maxtxpwr - 6) : 0;
1703 maxtxpwr = min(maxtxpwr, tx_pwr_target[rate]);
1705 if (pi->txpwr_percent <= 100)
1706 maxtxpwr = (maxtxpwr * pi->txpwr_percent) / 100;
1708 tx_pwr_target[rate] = max(maxtxpwr, mintxpwr);
1711 tx_pwr_target[rate] =
1712 min(tx_pwr_target[rate], pi->txpwr_env_limit[rate]);
1714 if (tx_pwr_target[rate] > tx_pwr_max)
1715 tx_pwr_max_rate_ind = rate;
1717 tx_pwr_max = max(tx_pwr_max, tx_pwr_target[rate]);
1718 tx_pwr_min = min(tx_pwr_min, tx_pwr_target[rate]);
1721 memset(pi->tx_power_offset, 0, sizeof(pi->tx_power_offset));
1722 pi->tx_power_max = tx_pwr_max;
1723 pi->tx_power_min = tx_pwr_min;
1724 pi->tx_power_max_rate_ind = tx_pwr_max_rate_ind;
1725 for (rate = 0; rate < max_num_rate; rate++) {
1727 pi->tx_power_target[rate] = tx_pwr_target[rate];
1729 if (!pi->hwpwrctrl || ISNPHY(pi))
1730 pi->tx_power_offset[rate] =
1731 pi->tx_power_max - pi->tx_power_target[rate];
1732 else
1733 pi->tx_power_offset[rate] =
1734 pi->tx_power_target[rate] - pi->tx_power_min;
1737 txpwr_recalc_fn = pi->pi_fptr.txpwrrecalc;
1738 if (txpwr_recalc_fn)
1739 (*txpwr_recalc_fn)(pi);
1742 void
1743 wlc_phy_txpower_reg_limit_calc(struct brcms_phy *pi, struct txpwr_limits *txpwr,
1744 u16 chanspec)
1746 u8 tmp_txpwr_limit[2 * BRCMS_NUM_RATES_OFDM];
1747 u8 *txpwr_ptr1 = NULL, *txpwr_ptr2 = NULL;
1748 int rate_start_index = 0, rate1, rate2, k;
1750 for (rate1 = WL_TX_POWER_CCK_FIRST, rate2 = 0;
1751 rate2 < WL_TX_POWER_CCK_NUM; rate1++, rate2++)
1752 pi->txpwr_limit[rate1] = txpwr->cck[rate2];
1754 for (rate1 = WL_TX_POWER_OFDM_FIRST, rate2 = 0;
1755 rate2 < WL_TX_POWER_OFDM_NUM; rate1++, rate2++)
1756 pi->txpwr_limit[rate1] = txpwr->ofdm[rate2];
1758 if (ISNPHY(pi)) {
1760 for (k = 0; k < 4; k++) {
1761 switch (k) {
1762 case 0:
1764 txpwr_ptr1 = txpwr->mcs_20_siso;
1765 txpwr_ptr2 = txpwr->ofdm;
1766 rate_start_index = WL_TX_POWER_OFDM_FIRST;
1767 break;
1768 case 1:
1770 txpwr_ptr1 = txpwr->mcs_20_cdd;
1771 txpwr_ptr2 = txpwr->ofdm_cdd;
1772 rate_start_index = WL_TX_POWER_OFDM20_CDD_FIRST;
1773 break;
1774 case 2:
1776 txpwr_ptr1 = txpwr->mcs_40_siso;
1777 txpwr_ptr2 = txpwr->ofdm_40_siso;
1778 rate_start_index =
1779 WL_TX_POWER_OFDM40_SISO_FIRST;
1780 break;
1781 case 3:
1783 txpwr_ptr1 = txpwr->mcs_40_cdd;
1784 txpwr_ptr2 = txpwr->ofdm_40_cdd;
1785 rate_start_index = WL_TX_POWER_OFDM40_CDD_FIRST;
1786 break;
1789 for (rate2 = 0; rate2 < BRCMS_NUM_RATES_OFDM;
1790 rate2++) {
1791 tmp_txpwr_limit[rate2] = 0;
1792 tmp_txpwr_limit[BRCMS_NUM_RATES_OFDM + rate2] =
1793 txpwr_ptr1[rate2];
1795 wlc_phy_mcs_to_ofdm_powers_nphy(
1796 tmp_txpwr_limit, 0,
1797 BRCMS_NUM_RATES_OFDM -
1798 1, BRCMS_NUM_RATES_OFDM);
1799 for (rate1 = rate_start_index, rate2 = 0;
1800 rate2 < BRCMS_NUM_RATES_OFDM; rate1++, rate2++)
1801 pi->txpwr_limit[rate1] =
1802 min(txpwr_ptr2[rate2],
1803 tmp_txpwr_limit[rate2]);
1806 for (k = 0; k < 4; k++) {
1807 switch (k) {
1808 case 0:
1810 txpwr_ptr1 = txpwr->ofdm;
1811 txpwr_ptr2 = txpwr->mcs_20_siso;
1812 rate_start_index = WL_TX_POWER_MCS20_SISO_FIRST;
1813 break;
1814 case 1:
1816 txpwr_ptr1 = txpwr->ofdm_cdd;
1817 txpwr_ptr2 = txpwr->mcs_20_cdd;
1818 rate_start_index = WL_TX_POWER_MCS20_CDD_FIRST;
1819 break;
1820 case 2:
1822 txpwr_ptr1 = txpwr->ofdm_40_siso;
1823 txpwr_ptr2 = txpwr->mcs_40_siso;
1824 rate_start_index = WL_TX_POWER_MCS40_SISO_FIRST;
1825 break;
1826 case 3:
1828 txpwr_ptr1 = txpwr->ofdm_40_cdd;
1829 txpwr_ptr2 = txpwr->mcs_40_cdd;
1830 rate_start_index = WL_TX_POWER_MCS40_CDD_FIRST;
1831 break;
1833 for (rate2 = 0; rate2 < BRCMS_NUM_RATES_OFDM;
1834 rate2++) {
1835 tmp_txpwr_limit[rate2] = 0;
1836 tmp_txpwr_limit[BRCMS_NUM_RATES_OFDM + rate2] =
1837 txpwr_ptr1[rate2];
1839 wlc_phy_ofdm_to_mcs_powers_nphy(
1840 tmp_txpwr_limit, 0,
1841 BRCMS_NUM_RATES_OFDM -
1842 1, BRCMS_NUM_RATES_OFDM);
1843 for (rate1 = rate_start_index, rate2 = 0;
1844 rate2 < BRCMS_NUM_RATES_MCS_1_STREAM;
1845 rate1++, rate2++)
1846 pi->txpwr_limit[rate1] =
1847 min(txpwr_ptr2[rate2],
1848 tmp_txpwr_limit[rate2]);
1851 for (k = 0; k < 2; k++) {
1852 switch (k) {
1853 case 0:
1855 rate_start_index = WL_TX_POWER_MCS20_STBC_FIRST;
1856 txpwr_ptr1 = txpwr->mcs_20_stbc;
1857 break;
1858 case 1:
1860 rate_start_index = WL_TX_POWER_MCS40_STBC_FIRST;
1861 txpwr_ptr1 = txpwr->mcs_40_stbc;
1862 break;
1864 for (rate1 = rate_start_index, rate2 = 0;
1865 rate2 < BRCMS_NUM_RATES_MCS_1_STREAM;
1866 rate1++, rate2++)
1867 pi->txpwr_limit[rate1] = txpwr_ptr1[rate2];
1870 for (k = 0; k < 2; k++) {
1871 switch (k) {
1872 case 0:
1874 rate_start_index = WL_TX_POWER_MCS20_SDM_FIRST;
1875 txpwr_ptr1 = txpwr->mcs_20_mimo;
1876 break;
1877 case 1:
1879 rate_start_index = WL_TX_POWER_MCS40_SDM_FIRST;
1880 txpwr_ptr1 = txpwr->mcs_40_mimo;
1881 break;
1883 for (rate1 = rate_start_index, rate2 = 0;
1884 rate2 < BRCMS_NUM_RATES_MCS_2_STREAM;
1885 rate1++, rate2++)
1886 pi->txpwr_limit[rate1] = txpwr_ptr1[rate2];
1889 pi->txpwr_limit[WL_TX_POWER_MCS_32] = txpwr->mcs32;
1891 pi->txpwr_limit[WL_TX_POWER_MCS40_CDD_FIRST] =
1892 min(pi->txpwr_limit[WL_TX_POWER_MCS40_CDD_FIRST],
1893 pi->txpwr_limit[WL_TX_POWER_MCS_32]);
1894 pi->txpwr_limit[WL_TX_POWER_MCS_32] =
1895 pi->txpwr_limit[WL_TX_POWER_MCS40_CDD_FIRST];
1899 void wlc_phy_txpwr_percent_set(struct brcms_phy_pub *ppi, u8 txpwr_percent)
1901 struct brcms_phy *pi = (struct brcms_phy *) ppi;
1903 pi->txpwr_percent = txpwr_percent;
1906 void wlc_phy_machwcap_set(struct brcms_phy_pub *ppi, u32 machwcap)
1908 struct brcms_phy *pi = (struct brcms_phy *) ppi;
1910 pi->sh->machwcap = machwcap;
1913 void wlc_phy_runbist_config(struct brcms_phy_pub *ppi, bool start_end)
1915 struct brcms_phy *pi = (struct brcms_phy *) ppi;
1916 u16 rxc;
1917 rxc = 0;
1919 if (start_end == ON) {
1920 if (!ISNPHY(pi))
1921 return;
1923 if (NREV_IS(pi->pubpi.phy_rev, 3)
1924 || NREV_IS(pi->pubpi.phy_rev, 4)) {
1925 W_REG(&pi->regs->phyregaddr, 0xa0);
1926 (void)R_REG(&pi->regs->phyregaddr);
1927 rxc = R_REG(&pi->regs->phyregdata);
1928 W_REG(&pi->regs->phyregdata,
1929 (0x1 << 15) | rxc);
1931 } else {
1932 if (NREV_IS(pi->pubpi.phy_rev, 3)
1933 || NREV_IS(pi->pubpi.phy_rev, 4)) {
1934 W_REG(&pi->regs->phyregaddr, 0xa0);
1935 (void)R_REG(&pi->regs->phyregaddr);
1936 W_REG(&pi->regs->phyregdata, rxc);
1939 wlc_phy_por_inform(ppi);
1943 void
1944 wlc_phy_txpower_limit_set(struct brcms_phy_pub *ppi, struct txpwr_limits *txpwr,
1945 u16 chanspec)
1947 struct brcms_phy *pi = (struct brcms_phy *) ppi;
1949 wlc_phy_txpower_reg_limit_calc(pi, txpwr, chanspec);
1951 if (ISLCNPHY(pi)) {
1952 int i, j;
1953 for (i = TXP_FIRST_OFDM_20_CDD, j = 0;
1954 j < BRCMS_NUM_RATES_MCS_1_STREAM; i++, j++) {
1955 if (txpwr->mcs_20_siso[j])
1956 pi->txpwr_limit[i] = txpwr->mcs_20_siso[j];
1957 else
1958 pi->txpwr_limit[i] = txpwr->ofdm[j];
1962 wlapi_suspend_mac_and_wait(pi->sh->physhim);
1964 wlc_phy_txpower_recalc_target(pi);
1965 wlc_phy_cal_txpower_recalc_sw(pi);
1966 wlapi_enable_mac(pi->sh->physhim);
1969 void wlc_phy_ofdm_rateset_war(struct brcms_phy_pub *pih, bool war)
1971 struct brcms_phy *pi = (struct brcms_phy *) pih;
1973 pi->ofdm_rateset_war = war;
1976 void wlc_phy_bf_preempt_enable(struct brcms_phy_pub *pih, bool bf_preempt)
1978 struct brcms_phy *pi = (struct brcms_phy *) pih;
1980 pi->bf_preempt_4306 = bf_preempt;
1983 void wlc_phy_txpower_update_shm(struct brcms_phy *pi)
1985 int j;
1986 if (ISNPHY(pi))
1987 return;
1989 if (!pi->sh->clk)
1990 return;
1992 if (pi->hwpwrctrl) {
1993 u16 offset;
1995 wlapi_bmac_write_shm(pi->sh->physhim, M_TXPWR_MAX, 63);
1996 wlapi_bmac_write_shm(pi->sh->physhim, M_TXPWR_N,
1997 1 << NUM_TSSI_FRAMES);
1999 wlapi_bmac_write_shm(pi->sh->physhim, M_TXPWR_TARGET,
2000 pi->tx_power_min << NUM_TSSI_FRAMES);
2002 wlapi_bmac_write_shm(pi->sh->physhim, M_TXPWR_CUR,
2003 pi->hwpwr_txcur);
2005 for (j = TXP_FIRST_OFDM; j <= TXP_LAST_OFDM; j++) {
2006 const u8 ucode_ofdm_rates[] = {
2007 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c
2009 offset = wlapi_bmac_rate_shm_offset(
2010 pi->sh->physhim,
2011 ucode_ofdm_rates[j - TXP_FIRST_OFDM]);
2012 wlapi_bmac_write_shm(pi->sh->physhim, offset + 6,
2013 pi->tx_power_offset[j]);
2014 wlapi_bmac_write_shm(pi->sh->physhim, offset + 14,
2015 -(pi->tx_power_offset[j] / 2));
2018 wlapi_bmac_mhf(pi->sh->physhim, MHF2, MHF2_HWPWRCTL,
2019 MHF2_HWPWRCTL, BRCM_BAND_ALL);
2020 } else {
2021 int i;
2023 for (i = TXP_FIRST_OFDM; i <= TXP_LAST_OFDM; i++)
2024 pi->tx_power_offset[i] =
2025 (u8) roundup(pi->tx_power_offset[i], 8);
2026 wlapi_bmac_write_shm(pi->sh->physhim, M_OFDM_OFFSET,
2027 (u16)
2028 ((pi->tx_power_offset[TXP_FIRST_OFDM]
2029 + 7) >> 3));
2033 bool wlc_phy_txpower_hw_ctrl_get(struct brcms_phy_pub *ppi)
2035 struct brcms_phy *pi = (struct brcms_phy *) ppi;
2037 if (ISNPHY(pi))
2038 return pi->nphy_txpwrctrl;
2039 else
2040 return pi->hwpwrctrl;
2043 void wlc_phy_txpower_hw_ctrl_set(struct brcms_phy_pub *ppi, bool hwpwrctrl)
2045 struct brcms_phy *pi = (struct brcms_phy *) ppi;
2046 bool suspend;
2048 if (!pi->hwpwrctrl_capable)
2049 return;
2051 pi->hwpwrctrl = hwpwrctrl;
2052 pi->nphy_txpwrctrl = hwpwrctrl;
2053 pi->txpwrctrl = hwpwrctrl;
2055 if (ISNPHY(pi)) {
2056 suspend = (0 == (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC));
2057 if (!suspend)
2058 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2060 wlc_phy_txpwrctrl_enable_nphy(pi, pi->nphy_txpwrctrl);
2061 if (pi->nphy_txpwrctrl == PHY_TPC_HW_OFF)
2062 wlc_phy_txpwr_fixpower_nphy(pi);
2063 else
2064 mod_phy_reg(pi, 0x1e7, (0x7f << 0),
2065 pi->saved_txpwr_idx);
2067 if (!suspend)
2068 wlapi_enable_mac(pi->sh->physhim);
2072 void wlc_phy_txpower_ipa_upd(struct brcms_phy *pi)
2075 if (NREV_GE(pi->pubpi.phy_rev, 3)) {
2076 pi->ipa2g_on = (pi->srom_fem2g.extpagain == 2);
2077 pi->ipa5g_on = (pi->srom_fem5g.extpagain == 2);
2078 } else {
2079 pi->ipa2g_on = false;
2080 pi->ipa5g_on = false;
2084 static u32 wlc_phy_txpower_est_power_nphy(struct brcms_phy *pi)
2086 s16 tx0_status, tx1_status;
2087 u16 estPower1, estPower2;
2088 u8 pwr0, pwr1, adj_pwr0, adj_pwr1;
2089 u32 est_pwr;
2091 estPower1 = read_phy_reg(pi, 0x118);
2092 estPower2 = read_phy_reg(pi, 0x119);
2094 if ((estPower1 & (0x1 << 8)) == (0x1 << 8))
2095 pwr0 = (u8) (estPower1 & (0xff << 0)) >> 0;
2096 else
2097 pwr0 = 0x80;
2099 if ((estPower2 & (0x1 << 8)) == (0x1 << 8))
2100 pwr1 = (u8) (estPower2 & (0xff << 0)) >> 0;
2101 else
2102 pwr1 = 0x80;
2104 tx0_status = read_phy_reg(pi, 0x1ed);
2105 tx1_status = read_phy_reg(pi, 0x1ee);
2107 if ((tx0_status & (0x1 << 15)) == (0x1 << 15))
2108 adj_pwr0 = (u8) (tx0_status & (0xff << 0)) >> 0;
2109 else
2110 adj_pwr0 = 0x80;
2111 if ((tx1_status & (0x1 << 15)) == (0x1 << 15))
2112 adj_pwr1 = (u8) (tx1_status & (0xff << 0)) >> 0;
2113 else
2114 adj_pwr1 = 0x80;
2116 est_pwr = (u32) ((pwr0 << 24) | (pwr1 << 16) | (adj_pwr0 << 8) |
2117 adj_pwr1);
2119 return est_pwr;
2122 void
2123 wlc_phy_txpower_get_current(struct brcms_phy_pub *ppi, struct tx_power *power,
2124 uint channel)
2126 struct brcms_phy *pi = (struct brcms_phy *) ppi;
2127 uint rate, num_rates;
2128 u8 min_pwr, max_pwr;
2130 #if WL_TX_POWER_RATES != TXP_NUM_RATES
2131 #error "struct tx_power out of sync with this fn"
2132 #endif
2134 if (ISNPHY(pi)) {
2135 power->rf_cores = 2;
2136 power->flags |= (WL_TX_POWER_F_MIMO);
2137 if (pi->nphy_txpwrctrl == PHY_TPC_HW_ON)
2138 power->flags |=
2139 (WL_TX_POWER_F_ENABLED | WL_TX_POWER_F_HW);
2140 } else if (ISLCNPHY(pi)) {
2141 power->rf_cores = 1;
2142 power->flags |= (WL_TX_POWER_F_SISO);
2143 if (pi->radiopwr_override == RADIOPWR_OVERRIDE_DEF)
2144 power->flags |= WL_TX_POWER_F_ENABLED;
2145 if (pi->hwpwrctrl)
2146 power->flags |= WL_TX_POWER_F_HW;
2149 num_rates = ((ISNPHY(pi)) ? (TXP_NUM_RATES) :
2150 ((ISLCNPHY(pi)) ?
2151 (TXP_LAST_OFDM_20_CDD + 1) : (TXP_LAST_OFDM + 1)));
2153 for (rate = 0; rate < num_rates; rate++) {
2154 power->user_limit[rate] = pi->tx_user_target[rate];
2155 wlc_phy_txpower_sromlimit(ppi, channel, &min_pwr, &max_pwr,
2156 rate);
2157 power->board_limit[rate] = (u8) max_pwr;
2158 power->target[rate] = pi->tx_power_target[rate];
2161 if (ISNPHY(pi)) {
2162 u32 est_pout;
2164 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2165 wlc_phyreg_enter((struct brcms_phy_pub *) pi);
2166 est_pout = wlc_phy_txpower_est_power_nphy(pi);
2167 wlc_phyreg_exit((struct brcms_phy_pub *) pi);
2168 wlapi_enable_mac(pi->sh->physhim);
2170 power->est_Pout[0] = (est_pout >> 8) & 0xff;
2171 power->est_Pout[1] = est_pout & 0xff;
2173 power->est_Pout_act[0] = est_pout >> 24;
2174 power->est_Pout_act[1] = (est_pout >> 16) & 0xff;
2176 if (power->est_Pout[0] == 0x80)
2177 power->est_Pout[0] = 0;
2178 if (power->est_Pout[1] == 0x80)
2179 power->est_Pout[1] = 0;
2181 if (power->est_Pout_act[0] == 0x80)
2182 power->est_Pout_act[0] = 0;
2183 if (power->est_Pout_act[1] == 0x80)
2184 power->est_Pout_act[1] = 0;
2186 power->est_Pout_cck = 0;
2188 power->tx_power_max[0] = pi->tx_power_max;
2189 power->tx_power_max[1] = pi->tx_power_max;
2191 power->tx_power_max_rate_ind[0] = pi->tx_power_max_rate_ind;
2192 power->tx_power_max_rate_ind[1] = pi->tx_power_max_rate_ind;
2193 } else if (pi->hwpwrctrl && pi->sh->up) {
2195 wlc_phyreg_enter(ppi);
2196 if (ISLCNPHY(pi)) {
2198 power->tx_power_max[0] = pi->tx_power_max;
2199 power->tx_power_max[1] = pi->tx_power_max;
2201 power->tx_power_max_rate_ind[0] =
2202 pi->tx_power_max_rate_ind;
2203 power->tx_power_max_rate_ind[1] =
2204 pi->tx_power_max_rate_ind;
2206 if (wlc_phy_tpc_isenabled_lcnphy(pi))
2207 power->flags |=
2208 (WL_TX_POWER_F_HW |
2209 WL_TX_POWER_F_ENABLED);
2210 else
2211 power->flags &=
2212 ~(WL_TX_POWER_F_HW |
2213 WL_TX_POWER_F_ENABLED);
2215 wlc_lcnphy_get_tssi(pi, (s8 *) &power->est_Pout[0],
2216 (s8 *) &power->est_Pout_cck);
2218 wlc_phyreg_exit(ppi);
2222 void wlc_phy_antsel_type_set(struct brcms_phy_pub *ppi, u8 antsel_type)
2224 struct brcms_phy *pi = (struct brcms_phy *) ppi;
2226 pi->antsel_type = antsel_type;
2229 bool wlc_phy_test_ison(struct brcms_phy_pub *ppi)
2231 struct brcms_phy *pi = (struct brcms_phy *) ppi;
2233 return pi->phytest_on;
2236 void wlc_phy_ant_rxdiv_set(struct brcms_phy_pub *ppi, u8 val)
2238 struct brcms_phy *pi = (struct brcms_phy *) ppi;
2239 bool suspend;
2241 pi->sh->rx_antdiv = val;
2243 if (!(ISNPHY(pi) && D11REV_IS(pi->sh->corerev, 16))) {
2244 if (val > ANT_RX_DIV_FORCE_1)
2245 wlapi_bmac_mhf(pi->sh->physhim, MHF1, MHF1_ANTDIV,
2246 MHF1_ANTDIV, BRCM_BAND_ALL);
2247 else
2248 wlapi_bmac_mhf(pi->sh->physhim, MHF1, MHF1_ANTDIV, 0,
2249 BRCM_BAND_ALL);
2252 if (ISNPHY(pi))
2253 return;
2255 if (!pi->sh->clk)
2256 return;
2258 suspend = (0 == (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC));
2259 if (!suspend)
2260 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2262 if (ISLCNPHY(pi)) {
2263 if (val > ANT_RX_DIV_FORCE_1) {
2264 mod_phy_reg(pi, 0x410, (0x1 << 1), 0x01 << 1);
2265 mod_phy_reg(pi, 0x410,
2266 (0x1 << 0),
2267 ((ANT_RX_DIV_START_1 == val) ? 1 : 0) << 0);
2268 } else {
2269 mod_phy_reg(pi, 0x410, (0x1 << 1), 0x00 << 1);
2270 mod_phy_reg(pi, 0x410, (0x1 << 0), (u16) val << 0);
2274 if (!suspend)
2275 wlapi_enable_mac(pi->sh->physhim);
2277 return;
2280 static bool
2281 wlc_phy_noise_calc_phy(struct brcms_phy *pi, u32 *cmplx_pwr, s8 *pwr_ant)
2283 s8 cmplx_pwr_dbm[PHY_CORE_MAX];
2284 u8 i;
2286 memset((u8 *) cmplx_pwr_dbm, 0, sizeof(cmplx_pwr_dbm));
2287 wlc_phy_compute_dB(cmplx_pwr, cmplx_pwr_dbm, pi->pubpi.phy_corenum);
2289 for (i = 0; i < pi->pubpi.phy_corenum; i++) {
2290 if (NREV_GE(pi->pubpi.phy_rev, 3))
2291 cmplx_pwr_dbm[i] += (s8) PHY_NOISE_OFFSETFACT_4322;
2292 else
2294 cmplx_pwr_dbm[i] += (s8) (16 - (15) * 3 - 70);
2297 for (i = 0; i < pi->pubpi.phy_corenum; i++) {
2298 pi->nphy_noise_win[i][pi->nphy_noise_index] = cmplx_pwr_dbm[i];
2299 pwr_ant[i] = cmplx_pwr_dbm[i];
2301 pi->nphy_noise_index =
2302 MODINC_POW2(pi->nphy_noise_index, PHY_NOISE_WINDOW_SZ);
2303 return true;
2306 static void
2307 wlc_phy_noise_sample_request(struct brcms_phy_pub *pih, u8 reason, u8 ch)
2309 struct brcms_phy *pi = (struct brcms_phy *) pih;
2310 s8 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;
2311 bool sampling_in_progress = (pi->phynoise_state != 0);
2312 bool wait_for_intr = true;
2314 if (NORADIO_ENAB(pi->pubpi))
2315 return;
2317 switch (reason) {
2318 case PHY_NOISE_SAMPLE_MON:
2319 pi->phynoise_chan_watchdog = ch;
2320 pi->phynoise_state |= PHY_NOISE_STATE_MON;
2321 break;
2323 case PHY_NOISE_SAMPLE_EXTERNAL:
2324 pi->phynoise_state |= PHY_NOISE_STATE_EXTERNAL;
2325 break;
2327 default:
2328 break;
2331 if (sampling_in_progress)
2332 return;
2334 pi->phynoise_now = pi->sh->now;
2336 if (pi->phy_fixed_noise) {
2337 if (ISNPHY(pi)) {
2338 pi->nphy_noise_win[WL_ANT_IDX_1][pi->nphy_noise_index] =
2339 PHY_NOISE_FIXED_VAL_NPHY;
2340 pi->nphy_noise_win[WL_ANT_IDX_2][pi->nphy_noise_index] =
2341 PHY_NOISE_FIXED_VAL_NPHY;
2342 pi->nphy_noise_index = MODINC_POW2(pi->nphy_noise_index,
2343 PHY_NOISE_WINDOW_SZ);
2344 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;
2345 } else {
2346 noise_dbm = PHY_NOISE_FIXED_VAL;
2349 wait_for_intr = false;
2350 goto done;
2353 if (ISLCNPHY(pi)) {
2354 if (!pi->phynoise_polling
2355 || (reason == PHY_NOISE_SAMPLE_EXTERNAL)) {
2356 wlapi_bmac_write_shm(pi->sh->physhim, M_JSSI_0, 0);
2357 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP0, 0);
2358 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP1, 0);
2359 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP2, 0);
2360 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP3, 0);
2362 OR_REG(&pi->regs->maccommand,
2363 MCMD_BG_NOISE);
2364 } else {
2365 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2366 wlc_lcnphy_deaf_mode(pi, (bool) 0);
2367 noise_dbm = (s8) wlc_lcnphy_rx_signal_power(pi, 20);
2368 wlc_lcnphy_deaf_mode(pi, (bool) 1);
2369 wlapi_enable_mac(pi->sh->physhim);
2370 wait_for_intr = false;
2372 } else if (ISNPHY(pi)) {
2373 if (!pi->phynoise_polling
2374 || (reason == PHY_NOISE_SAMPLE_EXTERNAL)) {
2376 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP0, 0);
2377 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP1, 0);
2378 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP2, 0);
2379 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP3, 0);
2381 OR_REG(&pi->regs->maccommand,
2382 MCMD_BG_NOISE);
2383 } else {
2384 struct phy_iq_est est[PHY_CORE_MAX];
2385 u32 cmplx_pwr[PHY_CORE_MAX];
2386 s8 noise_dbm_ant[PHY_CORE_MAX];
2387 u16 log_num_samps, num_samps, classif_state = 0;
2388 u8 wait_time = 32;
2389 u8 wait_crs = 0;
2390 u8 i;
2392 memset((u8 *) est, 0, sizeof(est));
2393 memset((u8 *) cmplx_pwr, 0, sizeof(cmplx_pwr));
2394 memset((u8 *) noise_dbm_ant, 0, sizeof(noise_dbm_ant));
2396 log_num_samps = PHY_NOISE_SAMPLE_LOG_NUM_NPHY;
2397 num_samps = 1 << log_num_samps;
2399 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2400 classif_state = wlc_phy_classifier_nphy(pi, 0, 0);
2401 wlc_phy_classifier_nphy(pi, 3, 0);
2402 wlc_phy_rx_iq_est_nphy(pi, est, num_samps, wait_time,
2403 wait_crs);
2404 wlc_phy_classifier_nphy(pi, (0x7 << 0), classif_state);
2405 wlapi_enable_mac(pi->sh->physhim);
2407 for (i = 0; i < pi->pubpi.phy_corenum; i++)
2408 cmplx_pwr[i] = (est[i].i_pwr + est[i].q_pwr) >>
2409 log_num_samps;
2411 wlc_phy_noise_calc_phy(pi, cmplx_pwr, noise_dbm_ant);
2413 for (i = 0; i < pi->pubpi.phy_corenum; i++) {
2414 pi->nphy_noise_win[i][pi->nphy_noise_index] =
2415 noise_dbm_ant[i];
2417 if (noise_dbm_ant[i] > noise_dbm)
2418 noise_dbm = noise_dbm_ant[i];
2420 pi->nphy_noise_index = MODINC_POW2(pi->nphy_noise_index,
2421 PHY_NOISE_WINDOW_SZ);
2423 wait_for_intr = false;
2427 done:
2429 if (!wait_for_intr)
2430 wlc_phy_noise_cb(pi, ch, noise_dbm);
2434 void wlc_phy_noise_sample_request_external(struct brcms_phy_pub *pih)
2436 u8 channel;
2438 channel = CHSPEC_CHANNEL(wlc_phy_chanspec_get(pih));
2440 wlc_phy_noise_sample_request(pih, PHY_NOISE_SAMPLE_EXTERNAL, channel);
2443 static void wlc_phy_noise_cb(struct brcms_phy *pi, u8 channel, s8 noise_dbm)
2445 if (!pi->phynoise_state)
2446 return;
2448 if (pi->phynoise_state & PHY_NOISE_STATE_MON) {
2449 if (pi->phynoise_chan_watchdog == channel) {
2450 pi->sh->phy_noise_window[pi->sh->phy_noise_index] =
2451 noise_dbm;
2452 pi->sh->phy_noise_index =
2453 MODINC(pi->sh->phy_noise_index, MA_WINDOW_SZ);
2455 pi->phynoise_state &= ~PHY_NOISE_STATE_MON;
2458 if (pi->phynoise_state & PHY_NOISE_STATE_EXTERNAL)
2459 pi->phynoise_state &= ~PHY_NOISE_STATE_EXTERNAL;
2463 static s8 wlc_phy_noise_read_shmem(struct brcms_phy *pi)
2465 u32 cmplx_pwr[PHY_CORE_MAX];
2466 s8 noise_dbm_ant[PHY_CORE_MAX];
2467 u16 lo, hi;
2468 u32 cmplx_pwr_tot = 0;
2469 s8 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;
2470 u8 idx, core;
2472 memset((u8 *) cmplx_pwr, 0, sizeof(cmplx_pwr));
2473 memset((u8 *) noise_dbm_ant, 0, sizeof(noise_dbm_ant));
2475 for (idx = 0, core = 0; core < pi->pubpi.phy_corenum; idx += 2,
2476 core++) {
2477 lo = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP(idx));
2478 hi = wlapi_bmac_read_shm(pi->sh->physhim,
2479 M_PWRIND_MAP(idx + 1));
2480 cmplx_pwr[core] = (hi << 16) + lo;
2481 cmplx_pwr_tot += cmplx_pwr[core];
2482 if (cmplx_pwr[core] == 0)
2483 noise_dbm_ant[core] = PHY_NOISE_FIXED_VAL_NPHY;
2484 else
2485 cmplx_pwr[core] >>= PHY_NOISE_SAMPLE_LOG_NUM_UCODE;
2488 if (cmplx_pwr_tot != 0)
2489 wlc_phy_noise_calc_phy(pi, cmplx_pwr, noise_dbm_ant);
2491 for (core = 0; core < pi->pubpi.phy_corenum; core++) {
2492 pi->nphy_noise_win[core][pi->nphy_noise_index] =
2493 noise_dbm_ant[core];
2495 if (noise_dbm_ant[core] > noise_dbm)
2496 noise_dbm = noise_dbm_ant[core];
2498 pi->nphy_noise_index =
2499 MODINC_POW2(pi->nphy_noise_index, PHY_NOISE_WINDOW_SZ);
2501 return noise_dbm;
2505 void wlc_phy_noise_sample_intr(struct brcms_phy_pub *pih)
2507 struct brcms_phy *pi = (struct brcms_phy *) pih;
2508 u16 jssi_aux;
2509 u8 channel = 0;
2510 s8 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;
2512 if (ISLCNPHY(pi)) {
2513 u32 cmplx_pwr, cmplx_pwr0, cmplx_pwr1;
2514 u16 lo, hi;
2515 s32 pwr_offset_dB, gain_dB;
2516 u16 status_0, status_1;
2518 jssi_aux = wlapi_bmac_read_shm(pi->sh->physhim, M_JSSI_AUX);
2519 channel = jssi_aux & D11_CURCHANNEL_MAX;
2521 lo = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP0);
2522 hi = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP1);
2523 cmplx_pwr0 = (hi << 16) + lo;
2525 lo = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP2);
2526 hi = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP3);
2527 cmplx_pwr1 = (hi << 16) + lo;
2528 cmplx_pwr = (cmplx_pwr0 + cmplx_pwr1) >> 6;
2530 status_0 = 0x44;
2531 status_1 = wlapi_bmac_read_shm(pi->sh->physhim, M_JSSI_0);
2532 if ((cmplx_pwr > 0 && cmplx_pwr < 500)
2533 && ((status_1 & 0xc000) == 0x4000)) {
2535 wlc_phy_compute_dB(&cmplx_pwr, &noise_dbm,
2536 pi->pubpi.phy_corenum);
2537 pwr_offset_dB = (read_phy_reg(pi, 0x434) & 0xFF);
2538 if (pwr_offset_dB > 127)
2539 pwr_offset_dB -= 256;
2541 noise_dbm += (s8) (pwr_offset_dB - 30);
2543 gain_dB = (status_0 & 0x1ff);
2544 noise_dbm -= (s8) (gain_dB);
2545 } else {
2546 noise_dbm = PHY_NOISE_FIXED_VAL_LCNPHY;
2548 } else if (ISNPHY(pi)) {
2550 jssi_aux = wlapi_bmac_read_shm(pi->sh->physhim, M_JSSI_AUX);
2551 channel = jssi_aux & D11_CURCHANNEL_MAX;
2553 noise_dbm = wlc_phy_noise_read_shmem(pi);
2556 wlc_phy_noise_cb(pi, channel, noise_dbm);
2560 s8 lcnphy_gain_index_offset_for_pkt_rssi[] = {
2601 void wlc_phy_compute_dB(u32 *cmplx_pwr, s8 *p_cmplx_pwr_dB, u8 core)
2603 u8 msb, secondmsb, i;
2604 u32 tmp;
2606 for (i = 0; i < core; i++) {
2607 secondmsb = 0;
2608 tmp = cmplx_pwr[i];
2609 msb = fls(tmp);
2610 if (msb)
2611 secondmsb = (u8) ((tmp >> (--msb - 1)) & 1);
2612 p_cmplx_pwr_dB[i] = (s8) (3 * msb + 2 * secondmsb);
2616 void wlc_phy_rssi_compute(struct brcms_phy_pub *pih,
2617 struct brcms_d11rxhdr *wlc_rxhdr)
2619 struct d11rxhdr *rxh = &wlc_rxhdr->rxhdr;
2620 int rssi = le16_to_cpu(rxh->PhyRxStatus_1) & PRXS1_JSSI_MASK;
2621 uint radioid = pih->radioid;
2622 struct brcms_phy *pi = (struct brcms_phy *) pih;
2624 if (NORADIO_ENAB(pi->pubpi)) {
2625 rssi = BRCMS_RSSI_INVALID;
2626 goto end;
2629 if ((pi->sh->corerev >= 11)
2630 && !(le16_to_cpu(rxh->RxStatus2) & RXS_PHYRXST_VALID)) {
2631 rssi = BRCMS_RSSI_INVALID;
2632 goto end;
2635 if (ISLCNPHY(pi)) {
2636 u8 gidx = (le16_to_cpu(rxh->PhyRxStatus_2) & 0xFC00) >> 10;
2637 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
2639 if (rssi > 127)
2640 rssi -= 256;
2642 rssi = rssi + lcnphy_gain_index_offset_for_pkt_rssi[gidx];
2643 if ((rssi > -46) && (gidx > 18))
2644 rssi = rssi + 7;
2646 rssi = rssi + pi_lcn->lcnphy_pkteng_rssi_slope;
2648 rssi = rssi + 2;
2652 if (ISLCNPHY(pi)) {
2653 if (rssi > 127)
2654 rssi -= 256;
2655 } else if (radioid == BCM2055_ID || radioid == BCM2056_ID
2656 || radioid == BCM2057_ID) {
2657 rssi = wlc_phy_rssi_compute_nphy(pi, wlc_rxhdr);
2660 end:
2661 wlc_rxhdr->rssi = (s8) rssi;
2664 void wlc_phy_freqtrack_start(struct brcms_phy_pub *pih)
2666 return;
2669 void wlc_phy_freqtrack_end(struct brcms_phy_pub *pih)
2671 return;
2674 void wlc_phy_set_deaf(struct brcms_phy_pub *ppi, bool user_flag)
2676 struct brcms_phy *pi;
2677 pi = (struct brcms_phy *) ppi;
2679 if (ISLCNPHY(pi))
2680 wlc_lcnphy_deaf_mode(pi, true);
2681 else if (ISNPHY(pi))
2682 wlc_nphy_deaf_mode(pi, true);
2685 void wlc_phy_watchdog(struct brcms_phy_pub *pih)
2687 struct brcms_phy *pi = (struct brcms_phy *) pih;
2688 bool delay_phy_cal = false;
2689 pi->sh->now++;
2691 if (!pi->watchdog_override)
2692 return;
2694 if (!(SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi)))
2695 wlc_phy_noise_sample_request((struct brcms_phy_pub *) pi,
2696 PHY_NOISE_SAMPLE_MON,
2697 CHSPEC_CHANNEL(pi->
2698 radio_chanspec));
2700 if (pi->phynoise_state && (pi->sh->now - pi->phynoise_now) > 5)
2701 pi->phynoise_state = 0;
2703 if ((!pi->phycal_txpower) ||
2704 ((pi->sh->now - pi->phycal_txpower) >= pi->sh->fast_timer)) {
2706 if (!SCAN_INPROG_PHY(pi) && wlc_phy_cal_txpower_recalc_sw(pi))
2707 pi->phycal_txpower = pi->sh->now;
2710 if (NORADIO_ENAB(pi->pubpi))
2711 return;
2713 if ((SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi)
2714 || ASSOC_INPROG_PHY(pi)))
2715 return;
2717 if (ISNPHY(pi) && !pi->disable_percal && !delay_phy_cal) {
2719 if ((pi->nphy_perical != PHY_PERICAL_DISABLE) &&
2720 (pi->nphy_perical != PHY_PERICAL_MANUAL) &&
2721 ((pi->sh->now - pi->nphy_perical_last) >=
2722 pi->sh->glacial_timer))
2723 wlc_phy_cal_perical((struct brcms_phy_pub *) pi,
2724 PHY_PERICAL_WATCHDOG);
2726 wlc_phy_txpwr_papd_cal_nphy(pi);
2729 if (ISLCNPHY(pi)) {
2730 if (pi->phy_forcecal ||
2731 ((pi->sh->now - pi->phy_lastcal) >=
2732 pi->sh->glacial_timer)) {
2733 if (!(SCAN_RM_IN_PROGRESS(pi) || ASSOC_INPROG_PHY(pi)))
2734 wlc_lcnphy_calib_modes(
2736 LCNPHY_PERICAL_TEMPBASED_TXPWRCTRL);
2737 if (!
2738 (SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi)
2739 || ASSOC_INPROG_PHY(pi)
2740 || pi->carrier_suppr_disable
2741 || pi->disable_percal))
2742 wlc_lcnphy_calib_modes(pi,
2743 PHY_PERICAL_WATCHDOG);
2748 void wlc_phy_BSSinit(struct brcms_phy_pub *pih, bool bonlyap, int rssi)
2750 struct brcms_phy *pi = (struct brcms_phy *) pih;
2751 uint i;
2752 uint k;
2754 for (i = 0; i < MA_WINDOW_SZ; i++)
2755 pi->sh->phy_noise_window[i] = (s8) (rssi & 0xff);
2756 if (ISLCNPHY(pi)) {
2757 for (i = 0; i < MA_WINDOW_SZ; i++)
2758 pi->sh->phy_noise_window[i] =
2759 PHY_NOISE_FIXED_VAL_LCNPHY;
2761 pi->sh->phy_noise_index = 0;
2763 for (i = 0; i < PHY_NOISE_WINDOW_SZ; i++) {
2764 for (k = WL_ANT_IDX_1; k < WL_ANT_RX_MAX; k++)
2765 pi->nphy_noise_win[k][i] = PHY_NOISE_FIXED_VAL_NPHY;
2767 pi->nphy_noise_index = 0;
2770 void
2771 wlc_phy_papd_decode_epsilon(u32 epsilon, s32 *eps_real, s32 *eps_imag)
2773 *eps_imag = (epsilon >> 13);
2774 if (*eps_imag > 0xfff)
2775 *eps_imag -= 0x2000;
2777 *eps_real = (epsilon & 0x1fff);
2778 if (*eps_real > 0xfff)
2779 *eps_real -= 0x2000;
2782 static const s32 AtanTbl[] = {
2783 2949120,
2784 1740967,
2785 919879,
2786 466945,
2787 234379,
2788 117304,
2789 58666,
2790 29335,
2791 14668,
2792 7334,
2793 3667,
2794 1833,
2795 917,
2796 458,
2797 229,
2798 115,
2803 void wlc_phy_cordic(s32 theta, struct cs32 *val)
2805 s32 angle, valtmp;
2806 unsigned iter;
2807 int signx = 1;
2808 int signtheta;
2810 val[0].i = CORDIC_AG;
2811 val[0].q = 0;
2812 angle = 0;
2814 signtheta = (theta < 0) ? -1 : 1;
2815 theta = ((theta + FIXED(180) * signtheta) % FIXED(360)) -
2816 FIXED(180) * signtheta;
2818 if (FLOAT(theta) > 90) {
2819 theta -= FIXED(180);
2820 signx = -1;
2821 } else if (FLOAT(theta) < -90) {
2822 theta += FIXED(180);
2823 signx = -1;
2826 for (iter = 0; iter < CORDIC_NI; iter++) {
2827 if (theta > angle) {
2828 valtmp = val[0].i - (val[0].q >> iter);
2829 val[0].q = (val[0].i >> iter) + val[0].q;
2830 val[0].i = valtmp;
2831 angle += AtanTbl[iter];
2832 } else {
2833 valtmp = val[0].i + (val[0].q >> iter);
2834 val[0].q = -(val[0].i >> iter) + val[0].q;
2835 val[0].i = valtmp;
2836 angle -= AtanTbl[iter];
2840 val[0].i = val[0].i * signx;
2841 val[0].q = val[0].q * signx;
2844 void wlc_phy_cal_perical_mphase_reset(struct brcms_phy *pi)
2846 wlapi_del_timer(pi->sh->physhim, pi->phycal_timer);
2848 pi->cal_type_override = PHY_PERICAL_AUTO;
2849 pi->mphase_cal_phase_id = MPHASE_CAL_STATE_IDLE;
2850 pi->mphase_txcal_cmdidx = 0;
2853 static void
2854 wlc_phy_cal_perical_mphase_schedule(struct brcms_phy *pi, uint delay)
2857 if ((pi->nphy_perical != PHY_PERICAL_MPHASE) &&
2858 (pi->nphy_perical != PHY_PERICAL_MANUAL))
2859 return;
2861 wlapi_del_timer(pi->sh->physhim, pi->phycal_timer);
2863 pi->mphase_cal_phase_id = MPHASE_CAL_STATE_INIT;
2864 wlapi_add_timer(pi->sh->physhim, pi->phycal_timer, delay, 0);
2867 void wlc_phy_cal_perical(struct brcms_phy_pub *pih, u8 reason)
2869 s16 nphy_currtemp = 0;
2870 s16 delta_temp = 0;
2871 bool do_periodic_cal = true;
2872 struct brcms_phy *pi = (struct brcms_phy *) pih;
2874 if (!ISNPHY(pi))
2875 return;
2877 if ((pi->nphy_perical == PHY_PERICAL_DISABLE) ||
2878 (pi->nphy_perical == PHY_PERICAL_MANUAL))
2879 return;
2881 switch (reason) {
2882 case PHY_PERICAL_DRIVERUP:
2883 break;
2885 case PHY_PERICAL_PHYINIT:
2886 if (pi->nphy_perical == PHY_PERICAL_MPHASE) {
2887 if (PHY_PERICAL_MPHASE_PENDING(pi))
2888 wlc_phy_cal_perical_mphase_reset(pi);
2890 wlc_phy_cal_perical_mphase_schedule(
2892 PHY_PERICAL_INIT_DELAY);
2894 break;
2896 case PHY_PERICAL_JOIN_BSS:
2897 case PHY_PERICAL_START_IBSS:
2898 case PHY_PERICAL_UP_BSS:
2899 if ((pi->nphy_perical == PHY_PERICAL_MPHASE) &&
2900 PHY_PERICAL_MPHASE_PENDING(pi))
2901 wlc_phy_cal_perical_mphase_reset(pi);
2903 pi->first_cal_after_assoc = true;
2905 pi->cal_type_override = PHY_PERICAL_FULL;
2907 if (pi->phycal_tempdelta)
2908 pi->nphy_lastcal_temp = wlc_phy_tempsense_nphy(pi);
2910 wlc_phy_cal_perical_nphy_run(pi, PHY_PERICAL_FULL);
2911 break;
2913 case PHY_PERICAL_WATCHDOG:
2914 if (pi->phycal_tempdelta) {
2915 nphy_currtemp = wlc_phy_tempsense_nphy(pi);
2916 delta_temp =
2917 (nphy_currtemp > pi->nphy_lastcal_temp) ?
2918 nphy_currtemp - pi->nphy_lastcal_temp :
2919 pi->nphy_lastcal_temp - nphy_currtemp;
2921 if ((delta_temp < (s16) pi->phycal_tempdelta) &&
2922 (pi->nphy_txiqlocal_chanspec ==
2923 pi->radio_chanspec))
2924 do_periodic_cal = false;
2925 else
2926 pi->nphy_lastcal_temp = nphy_currtemp;
2929 if (do_periodic_cal) {
2930 if (pi->nphy_perical == PHY_PERICAL_MPHASE) {
2931 if (!PHY_PERICAL_MPHASE_PENDING(pi))
2932 wlc_phy_cal_perical_mphase_schedule(
2934 PHY_PERICAL_WDOG_DELAY);
2935 } else if (pi->nphy_perical == PHY_PERICAL_SPHASE)
2936 wlc_phy_cal_perical_nphy_run(pi,
2937 PHY_PERICAL_AUTO);
2939 break;
2940 default:
2941 break;
2945 void wlc_phy_cal_perical_mphase_restart(struct brcms_phy *pi)
2947 pi->mphase_cal_phase_id = MPHASE_CAL_STATE_INIT;
2948 pi->mphase_txcal_cmdidx = 0;
2951 u8 wlc_phy_nbits(s32 value)
2953 s32 abs_val;
2954 u8 nbits = 0;
2956 abs_val = ABS(value);
2957 while ((abs_val >> nbits) > 0)
2958 nbits++;
2960 return nbits;
2963 void wlc_phy_stf_chain_init(struct brcms_phy_pub *pih, u8 txchain, u8 rxchain)
2965 struct brcms_phy *pi = (struct brcms_phy *) pih;
2967 pi->sh->hw_phytxchain = txchain;
2968 pi->sh->hw_phyrxchain = rxchain;
2969 pi->sh->phytxchain = txchain;
2970 pi->sh->phyrxchain = rxchain;
2971 pi->pubpi.phy_corenum = (u8) PHY_BITSCNT(pi->sh->phyrxchain);
2974 void wlc_phy_stf_chain_set(struct brcms_phy_pub *pih, u8 txchain, u8 rxchain)
2976 struct brcms_phy *pi = (struct brcms_phy *) pih;
2978 pi->sh->phytxchain = txchain;
2980 if (ISNPHY(pi))
2981 wlc_phy_rxcore_setstate_nphy(pih, rxchain);
2983 pi->pubpi.phy_corenum = (u8) PHY_BITSCNT(pi->sh->phyrxchain);
2986 void wlc_phy_stf_chain_get(struct brcms_phy_pub *pih, u8 *txchain, u8 *rxchain)
2988 struct brcms_phy *pi = (struct brcms_phy *) pih;
2990 *txchain = pi->sh->phytxchain;
2991 *rxchain = pi->sh->phyrxchain;
2994 u8 wlc_phy_stf_chain_active_get(struct brcms_phy_pub *pih)
2996 s16 nphy_currtemp;
2997 u8 active_bitmap;
2998 struct brcms_phy *pi = (struct brcms_phy *) pih;
3000 active_bitmap = (pi->phy_txcore_heatedup) ? 0x31 : 0x33;
3002 if (!pi->watchdog_override)
3003 return active_bitmap;
3005 if (NREV_GE(pi->pubpi.phy_rev, 6)) {
3006 wlapi_suspend_mac_and_wait(pi->sh->physhim);
3007 nphy_currtemp = wlc_phy_tempsense_nphy(pi);
3008 wlapi_enable_mac(pi->sh->physhim);
3010 if (!pi->phy_txcore_heatedup) {
3011 if (nphy_currtemp >= pi->phy_txcore_disable_temp) {
3012 active_bitmap &= 0xFD;
3013 pi->phy_txcore_heatedup = true;
3015 } else {
3016 if (nphy_currtemp <= pi->phy_txcore_enable_temp) {
3017 active_bitmap |= 0x2;
3018 pi->phy_txcore_heatedup = false;
3023 return active_bitmap;
3026 s8 wlc_phy_stf_ssmode_get(struct brcms_phy_pub *pih, u16 chanspec)
3028 struct brcms_phy *pi = (struct brcms_phy *) pih;
3029 u8 siso_mcs_id, cdd_mcs_id;
3031 siso_mcs_id =
3032 (CHSPEC_IS40(chanspec)) ? TXP_FIRST_MCS_40_SISO :
3033 TXP_FIRST_MCS_20_SISO;
3034 cdd_mcs_id =
3035 (CHSPEC_IS40(chanspec)) ? TXP_FIRST_MCS_40_CDD :
3036 TXP_FIRST_MCS_20_CDD;
3038 if (pi->tx_power_target[siso_mcs_id] >
3039 (pi->tx_power_target[cdd_mcs_id] + 12))
3040 return PHY_TXC1_MODE_SISO;
3041 else
3042 return PHY_TXC1_MODE_CDD;
3045 const u8 *wlc_phy_get_ofdm_rate_lookup(void)
3047 return ofdm_rate_lookup;
3050 void wlc_lcnphy_epa_switch(struct brcms_phy *pi, bool mode)
3052 if ((pi->sh->chip == BCM4313_CHIP_ID) &&
3053 (pi->sh->boardflags & BFL_FEM)) {
3054 if (mode) {
3055 u16 txant = 0;
3056 txant = wlapi_bmac_get_txant(pi->sh->physhim);
3057 if (txant == 1) {
3058 mod_phy_reg(pi, 0x44d, (0x1 << 2), (1) << 2);
3060 mod_phy_reg(pi, 0x44c, (0x1 << 2), (1) << 2);
3063 ai_corereg(pi->sh->sih, SI_CC_IDX,
3064 offsetof(struct chipcregs, gpiocontrol),
3065 ~0x0, 0x0);
3066 ai_corereg(pi->sh->sih, SI_CC_IDX,
3067 offsetof(struct chipcregs, gpioout), 0x40,
3068 0x40);
3069 ai_corereg(pi->sh->sih, SI_CC_IDX,
3070 offsetof(struct chipcregs, gpioouten), 0x40,
3071 0x40);
3072 } else {
3073 mod_phy_reg(pi, 0x44c, (0x1 << 2), (0) << 2);
3075 mod_phy_reg(pi, 0x44d, (0x1 << 2), (0) << 2);
3077 ai_corereg(pi->sh->sih, SI_CC_IDX,
3078 offsetof(struct chipcregs, gpioout), 0x40,
3079 0x00);
3080 ai_corereg(pi->sh->sih, SI_CC_IDX,
3081 offsetof(struct chipcregs, gpioouten), 0x40,
3082 0x0);
3083 ai_corereg(pi->sh->sih, SI_CC_IDX,
3084 offsetof(struct chipcregs, gpiocontrol),
3085 ~0x0, 0x40);
3090 static s8
3091 wlc_user_txpwr_antport_to_rfport(struct brcms_phy *pi, uint chan, u32 band,
3092 u8 rate)
3094 s8 offset = 0;
3096 if (!pi->user_txpwr_at_rfport)
3097 return offset;
3098 return offset;
3101 static s8 wlc_phy_env_measure_vbat(struct brcms_phy *pi)
3103 if (ISLCNPHY(pi))
3104 return wlc_lcnphy_vbatsense(pi, 0);
3105 else
3106 return 0;
3109 static s8 wlc_phy_env_measure_temperature(struct brcms_phy *pi)
3111 if (ISLCNPHY(pi))
3112 return wlc_lcnphy_tempsense_degree(pi, 0);
3113 else
3114 return 0;
3117 static void wlc_phy_upd_env_txpwr_rate_limits(struct brcms_phy *pi, u32 band)
3119 u8 i;
3120 s8 temp, vbat;
3122 for (i = 0; i < TXP_NUM_RATES; i++)
3123 pi->txpwr_env_limit[i] = BRCMS_TXPWR_MAX;
3125 vbat = wlc_phy_env_measure_vbat(pi);
3126 temp = wlc_phy_env_measure_temperature(pi);
3130 void wlc_phy_ldpc_override_set(struct brcms_phy_pub *ppi, bool ldpc)
3132 return;
3135 void
3136 wlc_phy_get_pwrdet_offsets(struct brcms_phy *pi, s8 *cckoffset, s8 *ofdmoffset)
3138 *cckoffset = 0;
3139 *ofdmoffset = 0;
3142 s8 wlc_phy_upd_rssi_offset(struct brcms_phy *pi, s8 rssi, u16 chanspec)
3145 return rssi;
3148 bool wlc_phy_txpower_ipa_ison(struct brcms_phy_pub *ppi)
3150 struct brcms_phy *pi = (struct brcms_phy *) ppi;
3152 if (ISNPHY(pi))
3153 return wlc_phy_n_txpower_ipa_ison(pi);
3154 else
3155 return 0;