]> Pileus Git - ~andy/linux/blob - drivers/staging/brcm80211/brcmsmac/phy/wlc_phy_cmn.c
staging: brcm80211: use int_sqrt kernel function iso driver implementation
[~andy/linux] / drivers / staging / brcm80211 / brcmsmac / phy / wlc_phy_cmn.c
1 /*
2  * Copyright (c) 2010 Broadcom Corporation
3  *
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.
7  *
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.
15  */
16
17 #include <wlc_cfg.h>
18
19 #include <linux/kernel.h>
20 #include <linux/string.h>
21 #include <bcmdefs.h>
22 #include <linux/delay.h>
23 #include <linux/module.h>
24 #include <linux/pci.h>
25 #include <bcmnvram.h>
26 #include <sbchipc.h>
27 #include <bcmdevs.h>
28 #include <sbhnddma.h>
29
30 #include <wlc_phy_int.h>
31 #include <wlc_phyreg_n.h>
32 #include <wlc_phy_radio.h>
33 #include <wlc_phy_lcn.h>
34
35 u32 phyhal_msg_level = PHYHAL_ERROR;
36
37 typedef struct _chan_info_basic {
38         u16 chan;
39         u16 freq;
40 } chan_info_basic_t;
41
42 static chan_info_basic_t chan_info_all[] = {
43
44         {1, 2412},
45         {2, 2417},
46         {3, 2422},
47         {4, 2427},
48         {5, 2432},
49         {6, 2437},
50         {7, 2442},
51         {8, 2447},
52         {9, 2452},
53         {10, 2457},
54         {11, 2462},
55         {12, 2467},
56         {13, 2472},
57         {14, 2484},
58
59         {34, 5170},
60         {38, 5190},
61         {42, 5210},
62         {46, 5230},
63
64         {36, 5180},
65         {40, 5200},
66         {44, 5220},
67         {48, 5240},
68         {52, 5260},
69         {56, 5280},
70         {60, 5300},
71         {64, 5320},
72
73         {100, 5500},
74         {104, 5520},
75         {108, 5540},
76         {112, 5560},
77         {116, 5580},
78         {120, 5600},
79         {124, 5620},
80         {128, 5640},
81         {132, 5660},
82         {136, 5680},
83         {140, 5700},
84
85         {149, 5745},
86         {153, 5765},
87         {157, 5785},
88         {161, 5805},
89         {165, 5825},
90
91         {184, 4920},
92         {188, 4940},
93         {192, 4960},
94         {196, 4980},
95         {200, 5000},
96         {204, 5020},
97         {208, 5040},
98         {212, 5060},
99         {216, 50800}
100 };
101
102 u16 ltrn_list[PHY_LTRN_LIST_LEN] = {
103         0x18f9, 0x0d01, 0x00e4, 0xdef4, 0x06f1, 0x0ffc,
104         0xfa27, 0x1dff, 0x10f0, 0x0918, 0xf20a, 0xe010,
105         0x1417, 0x1104, 0xf114, 0xf2fa, 0xf7db, 0xe2fc,
106         0xe1fb, 0x13ee, 0xff0d, 0xe91c, 0x171a, 0x0318,
107         0xda00, 0x03e8, 0x17e6, 0xe9e4, 0xfff3, 0x1312,
108         0xe105, 0xe204, 0xf725, 0xf206, 0xf1ec, 0x11fc,
109         0x14e9, 0xe0f0, 0xf2f6, 0x09e8, 0x1010, 0x1d01,
110         0xfad9, 0x0f04, 0x060f, 0xde0c, 0x001c, 0x0dff,
111         0x1807, 0xf61a, 0xe40e, 0x0f16, 0x05f9, 0x18ec,
112         0x0a1b, 0xff1e, 0x2600, 0xffe2, 0x0ae5, 0x1814,
113         0x0507, 0x0fea, 0xe4f2, 0xf6e6
114 };
115
116 const u8 ofdm_rate_lookup[] = {
117
118         WLC_RATE_48M,
119         WLC_RATE_24M,
120         WLC_RATE_12M,
121         WLC_RATE_6M,
122         WLC_RATE_54M,
123         WLC_RATE_36M,
124         WLC_RATE_18M,
125         WLC_RATE_9M
126 };
127
128 #define PHY_WREG_LIMIT  24
129
130 static void wlc_set_phy_uninitted(phy_info_t *pi);
131 static u32 wlc_phy_get_radio_ver(phy_info_t *pi);
132 static void wlc_phy_timercb_phycal(void *arg);
133
134 static bool wlc_phy_noise_calc_phy(phy_info_t *pi, u32 *cmplx_pwr,
135                                    s8 *pwr_ant);
136
137 static void wlc_phy_cal_perical_mphase_schedule(phy_info_t *pi, uint delay);
138 static void wlc_phy_noise_cb(phy_info_t *pi, u8 channel, s8 noise_dbm);
139 static void wlc_phy_noise_sample_request(wlc_phy_t *pih, u8 reason,
140                                          u8 ch);
141
142 static void wlc_phy_txpower_reg_limit_calc(phy_info_t *pi,
143                                            struct txpwr_limits *tp, chanspec_t);
144 static bool wlc_phy_cal_txpower_recalc_sw(phy_info_t *pi);
145
146 static s8 wlc_user_txpwr_antport_to_rfport(phy_info_t *pi, uint chan,
147                                              u32 band, u8 rate);
148 static void wlc_phy_upd_env_txpwr_rate_limits(phy_info_t *pi, u32 band);
149 static s8 wlc_phy_env_measure_vbat(phy_info_t *pi);
150 static s8 wlc_phy_env_measure_temperature(phy_info_t *pi);
151
152 char *phy_getvar(phy_info_t *pi, const char *name)
153 {
154         char *vars = pi->vars;
155         char *s;
156         int len;
157
158         if (!name)
159                 return NULL;
160
161         len = strlen(name);
162         if (len == 0)
163                 return NULL;
164
165         for (s = vars; s && *s;) {
166                 if ((memcmp(s, name, len) == 0) && (s[len] == '='))
167                         return &s[len + 1];
168
169                 while (*s++)
170                         ;
171         }
172
173         return nvram_get(name);
174 }
175
176 int phy_getintvar(phy_info_t *pi, const char *name)
177 {
178         char *val;
179
180         val = PHY_GETVAR(pi, name);
181         if (val == NULL)
182                 return 0;
183
184         return simple_strtoul(val, NULL, 0);
185 }
186
187 void wlc_phyreg_enter(wlc_phy_t *pih)
188 {
189         phy_info_t *pi = (phy_info_t *) pih;
190         wlapi_bmac_ucode_wake_override_phyreg_set(pi->sh->physhim);
191 }
192
193 void wlc_phyreg_exit(wlc_phy_t *pih)
194 {
195         phy_info_t *pi = (phy_info_t *) pih;
196         wlapi_bmac_ucode_wake_override_phyreg_clear(pi->sh->physhim);
197 }
198
199 void wlc_radioreg_enter(wlc_phy_t *pih)
200 {
201         phy_info_t *pi = (phy_info_t *) pih;
202         wlapi_bmac_mctrl(pi->sh->physhim, MCTL_LOCK_RADIO, MCTL_LOCK_RADIO);
203
204         udelay(10);
205 }
206
207 void wlc_radioreg_exit(wlc_phy_t *pih)
208 {
209         phy_info_t *pi = (phy_info_t *) pih;
210         volatile u16 dummy;
211
212         dummy = R_REG(&pi->regs->phyversion);
213         pi->phy_wreg = 0;
214         wlapi_bmac_mctrl(pi->sh->physhim, MCTL_LOCK_RADIO, 0);
215 }
216
217 u16 read_radio_reg(phy_info_t *pi, u16 addr)
218 {
219         u16 data;
220
221         if ((addr == RADIO_IDCODE))
222                 return 0xffff;
223
224         if (NORADIO_ENAB(pi->pubpi))
225                 return NORADIO_IDCODE & 0xffff;
226
227         switch (pi->pubpi.phy_type) {
228         case PHY_TYPE_N:
229                 CASECHECK(PHYTYPE, PHY_TYPE_N);
230                 if (NREV_GE(pi->pubpi.phy_rev, 7))
231                         addr |= RADIO_2057_READ_OFF;
232                 else
233                         addr |= RADIO_2055_READ_OFF;
234                 break;
235
236         case PHY_TYPE_LCN:
237                 CASECHECK(PHYTYPE, PHY_TYPE_LCN);
238                 addr |= RADIO_2064_READ_OFF;
239                 break;
240
241         default:
242                 break;
243         }
244
245         if ((D11REV_GE(pi->sh->corerev, 24)) ||
246             (D11REV_IS(pi->sh->corerev, 22)
247              && (pi->pubpi.phy_type != PHY_TYPE_SSN))) {
248                 W_REG(&pi->regs->radioregaddr, addr);
249 #ifdef __mips__
250                 (void)R_REG(&pi->regs->radioregaddr);
251 #endif
252                 data = R_REG(&pi->regs->radioregdata);
253         } else {
254                 W_REG(&pi->regs->phy4waddr, addr);
255 #ifdef __mips__
256                 (void)R_REG(&pi->regs->phy4waddr);
257 #endif
258
259 #ifdef __ARM_ARCH_4T__
260                 __asm__(" .align 4 ");
261                 __asm__(" nop ");
262                 data = R_REG(&pi->regs->phy4wdatalo);
263 #else
264                 data = R_REG(&pi->regs->phy4wdatalo);
265 #endif
266
267         }
268         pi->phy_wreg = 0;
269
270         return data;
271 }
272
273 void write_radio_reg(phy_info_t *pi, u16 addr, u16 val)
274 {
275         if (NORADIO_ENAB(pi->pubpi))
276                 return;
277
278         if ((D11REV_GE(pi->sh->corerev, 24)) ||
279             (D11REV_IS(pi->sh->corerev, 22)
280              && (pi->pubpi.phy_type != PHY_TYPE_SSN))) {
281
282                 W_REG(&pi->regs->radioregaddr, addr);
283 #ifdef __mips__
284                 (void)R_REG(&pi->regs->radioregaddr);
285 #endif
286                 W_REG(&pi->regs->radioregdata, val);
287         } else {
288                 W_REG(&pi->regs->phy4waddr, addr);
289 #ifdef __mips__
290                 (void)R_REG(&pi->regs->phy4waddr);
291 #endif
292                 W_REG(&pi->regs->phy4wdatalo, val);
293         }
294
295         if (pi->sh->bustype == PCI_BUS) {
296                 if (++pi->phy_wreg >= pi->phy_wreg_limit) {
297                         (void)R_REG(&pi->regs->maccontrol);
298                         pi->phy_wreg = 0;
299                 }
300         }
301 }
302
303 static u32 read_radio_id(phy_info_t *pi)
304 {
305         u32 id;
306
307         if (NORADIO_ENAB(pi->pubpi))
308                 return NORADIO_IDCODE;
309
310         if (D11REV_GE(pi->sh->corerev, 24)) {
311                 u32 b0, b1, b2;
312
313                 W_REG(&pi->regs->radioregaddr, 0);
314 #ifdef __mips__
315                 (void)R_REG(&pi->regs->radioregaddr);
316 #endif
317                 b0 = (u32) R_REG(&pi->regs->radioregdata);
318                 W_REG(&pi->regs->radioregaddr, 1);
319 #ifdef __mips__
320                 (void)R_REG(&pi->regs->radioregaddr);
321 #endif
322                 b1 = (u32) R_REG(&pi->regs->radioregdata);
323                 W_REG(&pi->regs->radioregaddr, 2);
324 #ifdef __mips__
325                 (void)R_REG(&pi->regs->radioregaddr);
326 #endif
327                 b2 = (u32) R_REG(&pi->regs->radioregdata);
328
329                 id = ((b0 & 0xf) << 28) | (((b2 << 8) | b1) << 12) | ((b0 >> 4)
330                                                                       & 0xf);
331         } else {
332                 W_REG(&pi->regs->phy4waddr, RADIO_IDCODE);
333 #ifdef __mips__
334                 (void)R_REG(&pi->regs->phy4waddr);
335 #endif
336                 id = (u32) R_REG(&pi->regs->phy4wdatalo);
337                 id |= (u32) R_REG(&pi->regs->phy4wdatahi) << 16;
338         }
339         pi->phy_wreg = 0;
340         return id;
341 }
342
343 void and_radio_reg(phy_info_t *pi, u16 addr, u16 val)
344 {
345         u16 rval;
346
347         if (NORADIO_ENAB(pi->pubpi))
348                 return;
349
350         rval = read_radio_reg(pi, addr);
351         write_radio_reg(pi, addr, (rval & val));
352 }
353
354 void or_radio_reg(phy_info_t *pi, u16 addr, u16 val)
355 {
356         u16 rval;
357
358         if (NORADIO_ENAB(pi->pubpi))
359                 return;
360
361         rval = read_radio_reg(pi, addr);
362         write_radio_reg(pi, addr, (rval | val));
363 }
364
365 void xor_radio_reg(phy_info_t *pi, u16 addr, u16 mask)
366 {
367         u16 rval;
368
369         if (NORADIO_ENAB(pi->pubpi))
370                 return;
371
372         rval = read_radio_reg(pi, addr);
373         write_radio_reg(pi, addr, (rval ^ mask));
374 }
375
376 void mod_radio_reg(phy_info_t *pi, u16 addr, u16 mask, u16 val)
377 {
378         u16 rval;
379
380         if (NORADIO_ENAB(pi->pubpi))
381                 return;
382
383         rval = read_radio_reg(pi, addr);
384         write_radio_reg(pi, addr, (rval & ~mask) | (val & mask));
385 }
386
387 void write_phy_channel_reg(phy_info_t *pi, uint val)
388 {
389         W_REG(&pi->regs->phychannel, val);
390 }
391
392 u16 read_phy_reg(phy_info_t *pi, u16 addr)
393 {
394         d11regs_t *regs;
395
396         regs = pi->regs;
397
398         W_REG(&regs->phyregaddr, addr);
399 #ifdef __mips__
400         (void)R_REG(&regs->phyregaddr);
401 #endif
402
403         pi->phy_wreg = 0;
404         return R_REG(&regs->phyregdata);
405 }
406
407 void write_phy_reg(phy_info_t *pi, u16 addr, u16 val)
408 {
409         d11regs_t *regs;
410
411         regs = pi->regs;
412
413 #ifdef __mips__
414         W_REG(&regs->phyregaddr, addr);
415         (void)R_REG(&regs->phyregaddr);
416         W_REG(&regs->phyregdata, val);
417         if (addr == 0x72)
418                 (void)R_REG(&regs->phyregdata);
419 #else
420         W_REG((u32 *)(&regs->phyregaddr),
421               addr | (val << 16));
422         if (pi->sh->bustype == PCI_BUS) {
423                 if (++pi->phy_wreg >= pi->phy_wreg_limit) {
424                         pi->phy_wreg = 0;
425                         (void)R_REG(&regs->phyversion);
426                 }
427         }
428 #endif
429 }
430
431 void and_phy_reg(phy_info_t *pi, u16 addr, u16 val)
432 {
433         d11regs_t *regs;
434
435         regs = pi->regs;
436
437         W_REG(&regs->phyregaddr, addr);
438 #ifdef __mips__
439         (void)R_REG(&regs->phyregaddr);
440 #endif
441
442         W_REG(&regs->phyregdata, (R_REG(&regs->phyregdata) & val));
443         pi->phy_wreg = 0;
444 }
445
446 void or_phy_reg(phy_info_t *pi, u16 addr, u16 val)
447 {
448         d11regs_t *regs;
449
450         regs = pi->regs;
451
452         W_REG(&regs->phyregaddr, addr);
453 #ifdef __mips__
454         (void)R_REG(&regs->phyregaddr);
455 #endif
456
457         W_REG(&regs->phyregdata, (R_REG(&regs->phyregdata) | val));
458         pi->phy_wreg = 0;
459 }
460
461 void mod_phy_reg(phy_info_t *pi, u16 addr, u16 mask, u16 val)
462 {
463         d11regs_t *regs;
464
465         regs = pi->regs;
466
467         W_REG(&regs->phyregaddr, addr);
468 #ifdef __mips__
469         (void)R_REG(&regs->phyregaddr);
470 #endif
471
472         W_REG(&regs->phyregdata,
473               ((R_REG(&regs->phyregdata) & ~mask) | (val & mask)));
474         pi->phy_wreg = 0;
475 }
476
477 static void WLBANDINITFN(wlc_set_phy_uninitted) (phy_info_t *pi)
478 {
479         int i, j;
480
481         pi->initialized = false;
482
483         pi->tx_vos = 0xffff;
484         pi->nrssi_table_delta = 0x7fffffff;
485         pi->rc_cal = 0xffff;
486         pi->mintxbias = 0xffff;
487         pi->txpwridx = -1;
488         if (ISNPHY(pi)) {
489                 pi->phy_spuravoid = SPURAVOID_DISABLE;
490
491                 if (NREV_GE(pi->pubpi.phy_rev, 3)
492                     && NREV_LT(pi->pubpi.phy_rev, 7))
493                         pi->phy_spuravoid = SPURAVOID_AUTO;
494
495                 pi->nphy_papd_skip = 0;
496                 pi->nphy_papd_epsilon_offset[0] = 0xf588;
497                 pi->nphy_papd_epsilon_offset[1] = 0xf588;
498                 pi->nphy_txpwr_idx[0] = 128;
499                 pi->nphy_txpwr_idx[1] = 128;
500                 pi->nphy_txpwrindex[0].index_internal = 40;
501                 pi->nphy_txpwrindex[1].index_internal = 40;
502                 pi->phy_pabias = 0;
503         } else {
504                 pi->phy_spuravoid = SPURAVOID_AUTO;
505         }
506         pi->radiopwr = 0xffff;
507         for (i = 0; i < STATIC_NUM_RF; i++) {
508                 for (j = 0; j < STATIC_NUM_BB; j++) {
509                         pi->stats_11b_txpower[i][j] = -1;
510                 }
511         }
512 }
513
514 shared_phy_t *wlc_phy_shared_attach(shared_phy_params_t *shp)
515 {
516         shared_phy_t *sh;
517
518         sh = kzalloc(sizeof(shared_phy_t), GFP_ATOMIC);
519         if (sh == NULL) {
520                 return NULL;
521         }
522
523         sh->sih = shp->sih;
524         sh->physhim = shp->physhim;
525         sh->unit = shp->unit;
526         sh->corerev = shp->corerev;
527
528         sh->vid = shp->vid;
529         sh->did = shp->did;
530         sh->chip = shp->chip;
531         sh->chiprev = shp->chiprev;
532         sh->chippkg = shp->chippkg;
533         sh->sromrev = shp->sromrev;
534         sh->boardtype = shp->boardtype;
535         sh->boardrev = shp->boardrev;
536         sh->boardvendor = shp->boardvendor;
537         sh->boardflags = shp->boardflags;
538         sh->boardflags2 = shp->boardflags2;
539         sh->bustype = shp->bustype;
540         sh->buscorerev = shp->buscorerev;
541
542         sh->fast_timer = PHY_SW_TIMER_FAST;
543         sh->slow_timer = PHY_SW_TIMER_SLOW;
544         sh->glacial_timer = PHY_SW_TIMER_GLACIAL;
545
546         sh->rssi_mode = RSSI_ANT_MERGE_MAX;
547
548         return sh;
549 }
550
551 void wlc_phy_shared_detach(shared_phy_t *phy_sh)
552 {
553         if (phy_sh) {
554                 kfree(phy_sh);
555         }
556 }
557
558 wlc_phy_t *wlc_phy_attach(shared_phy_t *sh, void *regs, int bandtype,
559                           char *vars, struct wiphy *wiphy)
560 {
561         phy_info_t *pi;
562         u32 sflags = 0;
563         uint phyversion;
564         int i;
565
566         if (D11REV_IS(sh->corerev, 4))
567                 sflags = SISF_2G_PHY | SISF_5G_PHY;
568         else
569                 sflags = ai_core_sflags(sh->sih, 0, 0);
570
571         if (BAND_5G(bandtype)) {
572                 if ((sflags & (SISF_5G_PHY | SISF_DB_PHY)) == 0) {
573                         return NULL;
574                 }
575         }
576
577         pi = sh->phy_head;
578         if ((sflags & SISF_DB_PHY) && pi) {
579
580                 wlapi_bmac_corereset(pi->sh->physhim, pi->pubpi.coreflags);
581                 pi->refcnt++;
582                 return &pi->pubpi_ro;
583         }
584
585         pi = kzalloc(sizeof(phy_info_t), GFP_ATOMIC);
586         if (pi == NULL) {
587                 return NULL;
588         }
589         pi->wiphy = wiphy;
590         pi->regs = (d11regs_t *) regs;
591         pi->sh = sh;
592         pi->phy_init_por = true;
593         pi->phy_wreg_limit = PHY_WREG_LIMIT;
594
595         pi->vars = vars;
596
597         pi->txpwr_percent = 100;
598
599         pi->do_initcal = true;
600
601         pi->phycal_tempdelta = 0;
602
603         if (BAND_2G(bandtype) && (sflags & SISF_2G_PHY)) {
604
605                 pi->pubpi.coreflags = SICF_GMODE;
606         }
607
608         wlapi_bmac_corereset(pi->sh->physhim, pi->pubpi.coreflags);
609         phyversion = R_REG(&pi->regs->phyversion);
610
611         pi->pubpi.phy_type = PHY_TYPE(phyversion);
612         pi->pubpi.phy_rev = phyversion & PV_PV_MASK;
613
614         if (pi->pubpi.phy_type == PHY_TYPE_LCNXN) {
615                 pi->pubpi.phy_type = PHY_TYPE_N;
616                 pi->pubpi.phy_rev += LCNXN_BASEREV;
617         }
618         pi->pubpi.phy_corenum = PHY_CORE_NUM_2;
619         pi->pubpi.ana_rev = (phyversion & PV_AV_MASK) >> PV_AV_SHIFT;
620
621         if (!VALID_PHYTYPE(pi->pubpi.phy_type)) {
622                 goto err;
623         }
624         if (BAND_5G(bandtype)) {
625                 if (!ISNPHY(pi)) {
626                         goto err;
627                 }
628         } else {
629                 if (!ISNPHY(pi) && !ISLCNPHY(pi)) {
630                         goto err;
631                 }
632         }
633
634         if (ISSIM_ENAB(pi->sh->sih)) {
635                 pi->pubpi.radioid = NORADIO_ID;
636                 pi->pubpi.radiorev = 5;
637         } else {
638                 u32 idcode;
639
640                 wlc_phy_anacore((wlc_phy_t *) pi, ON);
641
642                 idcode = wlc_phy_get_radio_ver(pi);
643                 pi->pubpi.radioid =
644                     (idcode & IDCODE_ID_MASK) >> IDCODE_ID_SHIFT;
645                 pi->pubpi.radiorev =
646                     (idcode & IDCODE_REV_MASK) >> IDCODE_REV_SHIFT;
647                 pi->pubpi.radiover =
648                     (idcode & IDCODE_VER_MASK) >> IDCODE_VER_SHIFT;
649                 if (!VALID_RADIO(pi, pi->pubpi.radioid)) {
650                         goto err;
651                 }
652
653                 wlc_phy_switch_radio((wlc_phy_t *) pi, OFF);
654         }
655
656         wlc_set_phy_uninitted(pi);
657
658         pi->bw = WL_CHANSPEC_BW_20;
659         pi->radio_chanspec =
660             BAND_2G(bandtype) ? CH20MHZ_CHSPEC(1) : CH20MHZ_CHSPEC(36);
661
662         pi->rxiq_samps = PHY_NOISE_SAMPLE_LOG_NUM_NPHY;
663         pi->rxiq_antsel = ANT_RX_DIV_DEF;
664
665         pi->watchdog_override = true;
666
667         pi->cal_type_override = PHY_PERICAL_AUTO;
668
669         pi->nphy_saved_noisevars.bufcount = 0;
670
671         if (ISNPHY(pi))
672                 pi->min_txpower = PHY_TXPWR_MIN_NPHY;
673         else
674                 pi->min_txpower = PHY_TXPWR_MIN;
675
676         pi->sh->phyrxchain = 0x3;
677
678         pi->rx2tx_biasentry = -1;
679
680         pi->phy_txcore_disable_temp = PHY_CHAIN_TX_DISABLE_TEMP;
681         pi->phy_txcore_enable_temp =
682             PHY_CHAIN_TX_DISABLE_TEMP - PHY_HYSTERESIS_DELTATEMP;
683         pi->phy_tempsense_offset = 0;
684         pi->phy_txcore_heatedup = false;
685
686         pi->nphy_lastcal_temp = -50;
687
688         pi->phynoise_polling = true;
689         if (ISNPHY(pi) || ISLCNPHY(pi))
690                 pi->phynoise_polling = false;
691
692         for (i = 0; i < TXP_NUM_RATES; i++) {
693                 pi->txpwr_limit[i] = WLC_TXPWR_MAX;
694                 pi->txpwr_env_limit[i] = WLC_TXPWR_MAX;
695                 pi->tx_user_target[i] = WLC_TXPWR_MAX;
696         }
697
698         pi->radiopwr_override = RADIOPWR_OVERRIDE_DEF;
699
700         pi->user_txpwr_at_rfport = false;
701
702         if (ISNPHY(pi)) {
703
704                 pi->phycal_timer = wlapi_init_timer(pi->sh->physhim,
705                                                           wlc_phy_timercb_phycal,
706                                                           pi, "phycal");
707                 if (!pi->phycal_timer) {
708                         goto err;
709                 }
710
711                 if (!wlc_phy_attach_nphy(pi))
712                         goto err;
713
714         } else if (ISLCNPHY(pi)) {
715                 if (!wlc_phy_attach_lcnphy(pi))
716                         goto err;
717
718         } else {
719
720         }
721
722         pi->refcnt++;
723         pi->next = pi->sh->phy_head;
724         sh->phy_head = pi;
725
726         pi->vars = (char *)&pi->vars;
727
728         memcpy(&pi->pubpi_ro, &pi->pubpi, sizeof(wlc_phy_t));
729
730         return &pi->pubpi_ro;
731
732  err:
733         kfree(pi);
734         return NULL;
735 }
736
737 void wlc_phy_detach(wlc_phy_t *pih)
738 {
739         phy_info_t *pi = (phy_info_t *) pih;
740
741         if (pih) {
742                 if (--pi->refcnt) {
743                         return;
744                 }
745
746                 if (pi->phycal_timer) {
747                         wlapi_free_timer(pi->sh->physhim, pi->phycal_timer);
748                         pi->phycal_timer = NULL;
749                 }
750
751                 if (pi->sh->phy_head == pi)
752                         pi->sh->phy_head = pi->next;
753                 else if (pi->sh->phy_head->next == pi)
754                         pi->sh->phy_head->next = NULL;
755
756                 if (pi->pi_fptr.detach)
757                         (pi->pi_fptr.detach) (pi);
758
759                 kfree(pi);
760         }
761 }
762
763 bool
764 wlc_phy_get_phyversion(wlc_phy_t *pih, u16 *phytype, u16 *phyrev,
765                        u16 *radioid, u16 *radiover)
766 {
767         phy_info_t *pi = (phy_info_t *) pih;
768         *phytype = (u16) pi->pubpi.phy_type;
769         *phyrev = (u16) pi->pubpi.phy_rev;
770         *radioid = pi->pubpi.radioid;
771         *radiover = pi->pubpi.radiorev;
772
773         return true;
774 }
775
776 bool wlc_phy_get_encore(wlc_phy_t *pih)
777 {
778         phy_info_t *pi = (phy_info_t *) pih;
779         return pi->pubpi.abgphy_encore;
780 }
781
782 u32 wlc_phy_get_coreflags(wlc_phy_t *pih)
783 {
784         phy_info_t *pi = (phy_info_t *) pih;
785         return pi->pubpi.coreflags;
786 }
787
788 static void wlc_phy_timercb_phycal(void *arg)
789 {
790         phy_info_t *pi = (phy_info_t *) arg;
791         uint delay = 5;
792
793         if (PHY_PERICAL_MPHASE_PENDING(pi)) {
794                 if (!pi->sh->up) {
795                         wlc_phy_cal_perical_mphase_reset(pi);
796                         return;
797                 }
798
799                 if (SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi)) {
800
801                         delay = 1000;
802                         wlc_phy_cal_perical_mphase_restart(pi);
803                 } else
804                         wlc_phy_cal_perical_nphy_run(pi, PHY_PERICAL_AUTO);
805                 wlapi_add_timer(pi->sh->physhim, pi->phycal_timer, delay, 0);
806                 return;
807         }
808
809 }
810
811 void wlc_phy_anacore(wlc_phy_t *pih, bool on)
812 {
813         phy_info_t *pi = (phy_info_t *) pih;
814
815         if (ISNPHY(pi)) {
816                 if (on) {
817                         if (NREV_GE(pi->pubpi.phy_rev, 3)) {
818                                 write_phy_reg(pi, 0xa6, 0x0d);
819                                 write_phy_reg(pi, 0x8f, 0x0);
820                                 write_phy_reg(pi, 0xa7, 0x0d);
821                                 write_phy_reg(pi, 0xa5, 0x0);
822                         } else {
823                                 write_phy_reg(pi, 0xa5, 0x0);
824                         }
825                 } else {
826                         if (NREV_GE(pi->pubpi.phy_rev, 3)) {
827                                 write_phy_reg(pi, 0x8f, 0x07ff);
828                                 write_phy_reg(pi, 0xa6, 0x0fd);
829                                 write_phy_reg(pi, 0xa5, 0x07ff);
830                                 write_phy_reg(pi, 0xa7, 0x0fd);
831                         } else {
832                                 write_phy_reg(pi, 0xa5, 0x7fff);
833                         }
834                 }
835         } else if (ISLCNPHY(pi)) {
836                 if (on) {
837                         and_phy_reg(pi, 0x43b,
838                                     ~((0x1 << 0) | (0x1 << 1) | (0x1 << 2)));
839                 } else {
840                         or_phy_reg(pi, 0x43c,
841                                    (0x1 << 0) | (0x1 << 1) | (0x1 << 2));
842                         or_phy_reg(pi, 0x43b,
843                                    (0x1 << 0) | (0x1 << 1) | (0x1 << 2));
844                 }
845         }
846 }
847
848 u32 wlc_phy_clk_bwbits(wlc_phy_t *pih)
849 {
850         phy_info_t *pi = (phy_info_t *) pih;
851
852         u32 phy_bw_clkbits = 0;
853
854         if (pi && (ISNPHY(pi) || ISLCNPHY(pi))) {
855                 switch (pi->bw) {
856                 case WL_CHANSPEC_BW_10:
857                         phy_bw_clkbits = SICF_BW10;
858                         break;
859                 case WL_CHANSPEC_BW_20:
860                         phy_bw_clkbits = SICF_BW20;
861                         break;
862                 case WL_CHANSPEC_BW_40:
863                         phy_bw_clkbits = SICF_BW40;
864                         break;
865                 default:
866                         break;
867                 }
868         }
869
870         return phy_bw_clkbits;
871 }
872
873 void WLBANDINITFN(wlc_phy_por_inform) (wlc_phy_t *ppi)
874 {
875         phy_info_t *pi = (phy_info_t *) ppi;
876
877         pi->phy_init_por = true;
878 }
879
880 void wlc_phy_edcrs_lock(wlc_phy_t *pih, bool lock)
881 {
882         phy_info_t *pi = (phy_info_t *) pih;
883
884         pi->edcrs_threshold_lock = lock;
885
886         write_phy_reg(pi, 0x22c, 0x46b);
887         write_phy_reg(pi, 0x22d, 0x46b);
888         write_phy_reg(pi, 0x22e, 0x3c0);
889         write_phy_reg(pi, 0x22f, 0x3c0);
890 }
891
892 void wlc_phy_initcal_enable(wlc_phy_t *pih, bool initcal)
893 {
894         phy_info_t *pi = (phy_info_t *) pih;
895
896         pi->do_initcal = initcal;
897 }
898
899 void wlc_phy_hw_clk_state_upd(wlc_phy_t *pih, bool newstate)
900 {
901         phy_info_t *pi = (phy_info_t *) pih;
902
903         if (!pi || !pi->sh)
904                 return;
905
906         pi->sh->clk = newstate;
907 }
908
909 void wlc_phy_hw_state_upd(wlc_phy_t *pih, bool newstate)
910 {
911         phy_info_t *pi = (phy_info_t *) pih;
912
913         if (!pi || !pi->sh)
914                 return;
915
916         pi->sh->up = newstate;
917 }
918
919 void WLBANDINITFN(wlc_phy_init) (wlc_phy_t *pih, chanspec_t chanspec)
920 {
921         u32 mc;
922         initfn_t phy_init = NULL;
923         phy_info_t *pi = (phy_info_t *) pih;
924
925         if (pi->init_in_progress)
926                 return;
927
928         pi->init_in_progress = true;
929
930         pi->radio_chanspec = chanspec;
931
932         mc = R_REG(&pi->regs->maccontrol);
933         if (WARN(mc & MCTL_EN_MAC, "HW error MAC running on init"))
934                 return;
935
936         if (!(pi->measure_hold & PHY_HOLD_FOR_SCAN)) {
937                 pi->measure_hold |= PHY_HOLD_FOR_NOT_ASSOC;
938         }
939
940         if (WARN(!(ai_core_sflags(pi->sh->sih, 0, 0) & SISF_FCLKA),
941                  "HW error SISF_FCLKA\n"))
942                 return;
943
944         phy_init = pi->pi_fptr.init;
945
946         if (phy_init == NULL) {
947                 return;
948         }
949
950         wlc_phy_anacore(pih, ON);
951
952         if (CHSPEC_BW(pi->radio_chanspec) != pi->bw)
953                 wlapi_bmac_bw_set(pi->sh->physhim,
954                                   CHSPEC_BW(pi->radio_chanspec));
955
956         pi->nphy_gain_boost = true;
957
958         wlc_phy_switch_radio((wlc_phy_t *) pi, ON);
959
960         (*phy_init) (pi);
961
962         pi->phy_init_por = false;
963
964         if (D11REV_IS(pi->sh->corerev, 11) || D11REV_IS(pi->sh->corerev, 12))
965                 wlc_phy_do_dummy_tx(pi, true, OFF);
966
967         if (!(ISNPHY(pi)))
968                 wlc_phy_txpower_update_shm(pi);
969
970         wlc_phy_ant_rxdiv_set((wlc_phy_t *) pi, pi->sh->rx_antdiv);
971
972         pi->init_in_progress = false;
973 }
974
975 void wlc_phy_cal_init(wlc_phy_t *pih)
976 {
977         phy_info_t *pi = (phy_info_t *) pih;
978         initfn_t cal_init = NULL;
979
980         if (WARN((R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC) != 0,
981                  "HW error: MAC enabled during phy cal\n"))
982                 return;
983
984         if (!pi->initialized) {
985                 cal_init = pi->pi_fptr.calinit;
986                 if (cal_init)
987                         (*cal_init) (pi);
988
989                 pi->initialized = true;
990         }
991 }
992
993 int wlc_phy_down(wlc_phy_t *pih)
994 {
995         phy_info_t *pi = (phy_info_t *) pih;
996         int callbacks = 0;
997
998         if (pi->phycal_timer
999             && !wlapi_del_timer(pi->sh->physhim, pi->phycal_timer))
1000                 callbacks++;
1001
1002         pi->nphy_iqcal_chanspec_2G = 0;
1003         pi->nphy_iqcal_chanspec_5G = 0;
1004
1005         return callbacks;
1006 }
1007
1008 static u32 wlc_phy_get_radio_ver(phy_info_t *pi)
1009 {
1010         u32 ver;
1011
1012         ver = read_radio_id(pi);
1013
1014         return ver;
1015 }
1016
1017 void
1018 wlc_phy_table_addr(phy_info_t *pi, uint tbl_id, uint tbl_offset,
1019                    u16 tblAddr, u16 tblDataHi, u16 tblDataLo)
1020 {
1021         write_phy_reg(pi, tblAddr, (tbl_id << 10) | tbl_offset);
1022
1023         pi->tbl_data_hi = tblDataHi;
1024         pi->tbl_data_lo = tblDataLo;
1025
1026         if ((pi->sh->chip == BCM43224_CHIP_ID ||
1027              pi->sh->chip == BCM43421_CHIP_ID) &&
1028             (pi->sh->chiprev == 1)) {
1029                 pi->tbl_addr = tblAddr;
1030                 pi->tbl_save_id = tbl_id;
1031                 pi->tbl_save_offset = tbl_offset;
1032         }
1033 }
1034
1035 void wlc_phy_table_data_write(phy_info_t *pi, uint width, u32 val)
1036 {
1037         if ((pi->sh->chip == BCM43224_CHIP_ID ||
1038              pi->sh->chip == BCM43421_CHIP_ID) &&
1039             (pi->sh->chiprev == 1) &&
1040             (pi->tbl_save_id == NPHY_TBL_ID_ANTSWCTRLLUT)) {
1041                 read_phy_reg(pi, pi->tbl_data_lo);
1042
1043                 write_phy_reg(pi, pi->tbl_addr,
1044                               (pi->tbl_save_id << 10) | pi->tbl_save_offset);
1045                 pi->tbl_save_offset++;
1046         }
1047
1048         if (width == 32) {
1049
1050                 write_phy_reg(pi, pi->tbl_data_hi, (u16) (val >> 16));
1051                 write_phy_reg(pi, pi->tbl_data_lo, (u16) val);
1052         } else {
1053
1054                 write_phy_reg(pi, pi->tbl_data_lo, (u16) val);
1055         }
1056 }
1057
1058 void
1059 wlc_phy_write_table(phy_info_t *pi, const phytbl_info_t *ptbl_info,
1060                     u16 tblAddr, u16 tblDataHi, u16 tblDataLo)
1061 {
1062         uint idx;
1063         uint tbl_id = ptbl_info->tbl_id;
1064         uint tbl_offset = ptbl_info->tbl_offset;
1065         uint tbl_width = ptbl_info->tbl_width;
1066         const u8 *ptbl_8b = (const u8 *)ptbl_info->tbl_ptr;
1067         const u16 *ptbl_16b = (const u16 *)ptbl_info->tbl_ptr;
1068         const u32 *ptbl_32b = (const u32 *)ptbl_info->tbl_ptr;
1069
1070         write_phy_reg(pi, tblAddr, (tbl_id << 10) | tbl_offset);
1071
1072         for (idx = 0; idx < ptbl_info->tbl_len; idx++) {
1073
1074                 if ((pi->sh->chip == BCM43224_CHIP_ID ||
1075                      pi->sh->chip == BCM43421_CHIP_ID) &&
1076                     (pi->sh->chiprev == 1) &&
1077                     (tbl_id == NPHY_TBL_ID_ANTSWCTRLLUT)) {
1078                         read_phy_reg(pi, tblDataLo);
1079
1080                         write_phy_reg(pi, tblAddr,
1081                                       (tbl_id << 10) | (tbl_offset + idx));
1082                 }
1083
1084                 if (tbl_width == 32) {
1085
1086                         write_phy_reg(pi, tblDataHi,
1087                                       (u16) (ptbl_32b[idx] >> 16));
1088                         write_phy_reg(pi, tblDataLo, (u16) ptbl_32b[idx]);
1089                 } else if (tbl_width == 16) {
1090
1091                         write_phy_reg(pi, tblDataLo, ptbl_16b[idx]);
1092                 } else {
1093
1094                         write_phy_reg(pi, tblDataLo, ptbl_8b[idx]);
1095                 }
1096         }
1097 }
1098
1099 void
1100 wlc_phy_read_table(phy_info_t *pi, const phytbl_info_t *ptbl_info,
1101                    u16 tblAddr, u16 tblDataHi, u16 tblDataLo)
1102 {
1103         uint idx;
1104         uint tbl_id = ptbl_info->tbl_id;
1105         uint tbl_offset = ptbl_info->tbl_offset;
1106         uint tbl_width = ptbl_info->tbl_width;
1107         u8 *ptbl_8b = (u8 *)ptbl_info->tbl_ptr;
1108         u16 *ptbl_16b = (u16 *)ptbl_info->tbl_ptr;
1109         u32 *ptbl_32b = (u32 *)ptbl_info->tbl_ptr;
1110
1111         write_phy_reg(pi, tblAddr, (tbl_id << 10) | tbl_offset);
1112
1113         for (idx = 0; idx < ptbl_info->tbl_len; idx++) {
1114
1115                 if ((pi->sh->chip == BCM43224_CHIP_ID ||
1116                      pi->sh->chip == BCM43421_CHIP_ID) &&
1117                     (pi->sh->chiprev == 1)) {
1118                         (void)read_phy_reg(pi, tblDataLo);
1119
1120                         write_phy_reg(pi, tblAddr,
1121                                       (tbl_id << 10) | (tbl_offset + idx));
1122                 }
1123
1124                 if (tbl_width == 32) {
1125
1126                         ptbl_32b[idx] = read_phy_reg(pi, tblDataLo);
1127                         ptbl_32b[idx] |= (read_phy_reg(pi, tblDataHi) << 16);
1128                 } else if (tbl_width == 16) {
1129
1130                         ptbl_16b[idx] = read_phy_reg(pi, tblDataLo);
1131                 } else {
1132
1133                         ptbl_8b[idx] = (u8) read_phy_reg(pi, tblDataLo);
1134                 }
1135         }
1136 }
1137
1138 uint
1139 wlc_phy_init_radio_regs_allbands(phy_info_t *pi, radio_20xx_regs_t *radioregs)
1140 {
1141         uint i = 0;
1142
1143         do {
1144                 if (radioregs[i].do_init) {
1145                         write_radio_reg(pi, radioregs[i].address,
1146                                         (u16) radioregs[i].init);
1147                 }
1148
1149                 i++;
1150         } while (radioregs[i].address != 0xffff);
1151
1152         return i;
1153 }
1154
1155 uint
1156 wlc_phy_init_radio_regs(phy_info_t *pi, radio_regs_t *radioregs,
1157                         u16 core_offset)
1158 {
1159         uint i = 0;
1160         uint count = 0;
1161
1162         do {
1163                 if (CHSPEC_IS5G(pi->radio_chanspec)) {
1164                         if (radioregs[i].do_init_a) {
1165                                 write_radio_reg(pi,
1166                                                 radioregs[i].
1167                                                 address | core_offset,
1168                                                 (u16) radioregs[i].init_a);
1169                                 if (ISNPHY(pi) && (++count % 4 == 0))
1170                                         WLC_PHY_WAR_PR51571(pi);
1171                         }
1172                 } else {
1173                         if (radioregs[i].do_init_g) {
1174                                 write_radio_reg(pi,
1175                                                 radioregs[i].
1176                                                 address | core_offset,
1177                                                 (u16) radioregs[i].init_g);
1178                                 if (ISNPHY(pi) && (++count % 4 == 0))
1179                                         WLC_PHY_WAR_PR51571(pi);
1180                         }
1181                 }
1182
1183                 i++;
1184         } while (radioregs[i].address != 0xffff);
1185
1186         return i;
1187 }
1188
1189 void wlc_phy_do_dummy_tx(phy_info_t *pi, bool ofdm, bool pa_on)
1190 {
1191 #define DUMMY_PKT_LEN   20
1192         d11regs_t *regs = pi->regs;
1193         int i, count;
1194         u8 ofdmpkt[DUMMY_PKT_LEN] = {
1195                 0xcc, 0x01, 0x02, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00,
1196                 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00
1197         };
1198         u8 cckpkt[DUMMY_PKT_LEN] = {
1199                 0x6e, 0x84, 0x0b, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00,
1200                 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00
1201         };
1202         u32 *dummypkt;
1203
1204         dummypkt = (u32 *) (ofdm ? ofdmpkt : cckpkt);
1205         wlapi_bmac_write_template_ram(pi->sh->physhim, 0, DUMMY_PKT_LEN,
1206                                       dummypkt);
1207
1208         W_REG(&regs->xmtsel, 0);
1209
1210         if (D11REV_GE(pi->sh->corerev, 11))
1211                 W_REG(&regs->wepctl, 0x100);
1212         else
1213                 W_REG(&regs->wepctl, 0);
1214
1215         W_REG(&regs->txe_phyctl, (ofdm ? 1 : 0) | PHY_TXC_ANT_0);
1216         if (ISNPHY(pi) || ISLCNPHY(pi)) {
1217                 W_REG(&regs->txe_phyctl1, 0x1A02);
1218         }
1219
1220         W_REG(&regs->txe_wm_0, 0);
1221         W_REG(&regs->txe_wm_1, 0);
1222
1223         W_REG(&regs->xmttplatetxptr, 0);
1224         W_REG(&regs->xmttxcnt, DUMMY_PKT_LEN);
1225
1226         W_REG(&regs->xmtsel, ((8 << 8) | (1 << 5) | (1 << 2) | 2));
1227
1228         W_REG(&regs->txe_ctl, 0);
1229
1230         if (!pa_on) {
1231                 if (ISNPHY(pi))
1232                         wlc_phy_pa_override_nphy(pi, OFF);
1233         }
1234
1235         if (ISNPHY(pi) || ISLCNPHY(pi))
1236                 W_REG(&regs->txe_aux, 0xD0);
1237         else
1238                 W_REG(&regs->txe_aux, ((1 << 5) | (1 << 4)));
1239
1240         (void)R_REG(&regs->txe_aux);
1241
1242         i = 0;
1243         count = ofdm ? 30 : 250;
1244
1245         if (ISSIM_ENAB(pi->sh->sih)) {
1246                 count *= 100;
1247         }
1248
1249         while ((i++ < count)
1250                && (R_REG(&regs->txe_status) & (1 << 7))) {
1251                 udelay(10);
1252         }
1253
1254         i = 0;
1255
1256         while ((i++ < 10)
1257                && ((R_REG(&regs->txe_status) & (1 << 10)) == 0)) {
1258                 udelay(10);
1259         }
1260
1261         i = 0;
1262
1263         while ((i++ < 10) && ((R_REG(&regs->ifsstat) & (1 << 8))))
1264                 udelay(10);
1265
1266         if (!pa_on) {
1267                 if (ISNPHY(pi))
1268                         wlc_phy_pa_override_nphy(pi, ON);
1269         }
1270 }
1271
1272 void wlc_phy_hold_upd(wlc_phy_t *pih, mbool id, bool set)
1273 {
1274         phy_info_t *pi = (phy_info_t *) pih;
1275
1276         if (set) {
1277                 mboolset(pi->measure_hold, id);
1278         } else {
1279                 mboolclr(pi->measure_hold, id);
1280         }
1281
1282         return;
1283 }
1284
1285 void wlc_phy_mute_upd(wlc_phy_t *pih, bool mute, mbool flags)
1286 {
1287         phy_info_t *pi = (phy_info_t *) pih;
1288
1289         if (mute) {
1290                 mboolset(pi->measure_hold, PHY_HOLD_FOR_MUTE);
1291         } else {
1292                 mboolclr(pi->measure_hold, PHY_HOLD_FOR_MUTE);
1293         }
1294
1295         if (!mute && (flags & PHY_MUTE_FOR_PREISM))
1296                 pi->nphy_perical_last = pi->sh->now - pi->sh->glacial_timer;
1297         return;
1298 }
1299
1300 void wlc_phy_clear_tssi(wlc_phy_t *pih)
1301 {
1302         phy_info_t *pi = (phy_info_t *) pih;
1303
1304         if (ISNPHY(pi)) {
1305                 return;
1306         } else {
1307                 wlapi_bmac_write_shm(pi->sh->physhim, M_B_TSSI_0, NULL_TSSI_W);
1308                 wlapi_bmac_write_shm(pi->sh->physhim, M_B_TSSI_1, NULL_TSSI_W);
1309                 wlapi_bmac_write_shm(pi->sh->physhim, M_G_TSSI_0, NULL_TSSI_W);
1310                 wlapi_bmac_write_shm(pi->sh->physhim, M_G_TSSI_1, NULL_TSSI_W);
1311         }
1312 }
1313
1314 static bool wlc_phy_cal_txpower_recalc_sw(phy_info_t *pi)
1315 {
1316         return false;
1317 }
1318
1319 void wlc_phy_switch_radio(wlc_phy_t *pih, bool on)
1320 {
1321         phy_info_t *pi = (phy_info_t *) pih;
1322
1323         if (NORADIO_ENAB(pi->pubpi))
1324                 return;
1325
1326         {
1327                 uint mc;
1328
1329                 mc = R_REG(&pi->regs->maccontrol);
1330         }
1331
1332         if (ISNPHY(pi)) {
1333                 wlc_phy_switch_radio_nphy(pi, on);
1334
1335         } else if (ISLCNPHY(pi)) {
1336                 if (on) {
1337                         and_phy_reg(pi, 0x44c,
1338                                     ~((0x1 << 8) |
1339                                       (0x1 << 9) |
1340                                       (0x1 << 10) | (0x1 << 11) | (0x1 << 12)));
1341                         and_phy_reg(pi, 0x4b0, ~((0x1 << 3) | (0x1 << 11)));
1342                         and_phy_reg(pi, 0x4f9, ~(0x1 << 3));
1343                 } else {
1344                         and_phy_reg(pi, 0x44d,
1345                                     ~((0x1 << 10) |
1346                                       (0x1 << 11) |
1347                                       (0x1 << 12) | (0x1 << 13) | (0x1 << 14)));
1348                         or_phy_reg(pi, 0x44c,
1349                                    (0x1 << 8) |
1350                                    (0x1 << 9) |
1351                                    (0x1 << 10) | (0x1 << 11) | (0x1 << 12));
1352
1353                         and_phy_reg(pi, 0x4b7, ~((0x7f << 8)));
1354                         and_phy_reg(pi, 0x4b1, ~((0x1 << 13)));
1355                         or_phy_reg(pi, 0x4b0, (0x1 << 3) | (0x1 << 11));
1356                         and_phy_reg(pi, 0x4fa, ~((0x1 << 3)));
1357                         or_phy_reg(pi, 0x4f9, (0x1 << 3));
1358                 }
1359         }
1360 }
1361
1362 u16 wlc_phy_bw_state_get(wlc_phy_t *ppi)
1363 {
1364         phy_info_t *pi = (phy_info_t *) ppi;
1365
1366         return pi->bw;
1367 }
1368
1369 void wlc_phy_bw_state_set(wlc_phy_t *ppi, u16 bw)
1370 {
1371         phy_info_t *pi = (phy_info_t *) ppi;
1372
1373         pi->bw = bw;
1374 }
1375
1376 void wlc_phy_chanspec_radio_set(wlc_phy_t *ppi, chanspec_t newch)
1377 {
1378         phy_info_t *pi = (phy_info_t *) ppi;
1379         pi->radio_chanspec = newch;
1380
1381 }
1382
1383 chanspec_t wlc_phy_chanspec_get(wlc_phy_t *ppi)
1384 {
1385         phy_info_t *pi = (phy_info_t *) ppi;
1386
1387         return pi->radio_chanspec;
1388 }
1389
1390 void wlc_phy_chanspec_set(wlc_phy_t *ppi, chanspec_t chanspec)
1391 {
1392         phy_info_t *pi = (phy_info_t *) ppi;
1393         u16 m_cur_channel;
1394         chansetfn_t chanspec_set = NULL;
1395
1396         m_cur_channel = CHSPEC_CHANNEL(chanspec);
1397         if (CHSPEC_IS5G(chanspec))
1398                 m_cur_channel |= D11_CURCHANNEL_5G;
1399         if (CHSPEC_IS40(chanspec))
1400                 m_cur_channel |= D11_CURCHANNEL_40;
1401         wlapi_bmac_write_shm(pi->sh->physhim, M_CURCHANNEL, m_cur_channel);
1402
1403         chanspec_set = pi->pi_fptr.chanset;
1404         if (chanspec_set)
1405                 (*chanspec_set) (pi, chanspec);
1406
1407 }
1408
1409 int wlc_phy_chanspec_freq2bandrange_lpssn(uint freq)
1410 {
1411         int range = -1;
1412
1413         if (freq < 2500)
1414                 range = WL_CHAN_FREQ_RANGE_2G;
1415         else if (freq <= 5320)
1416                 range = WL_CHAN_FREQ_RANGE_5GL;
1417         else if (freq <= 5700)
1418                 range = WL_CHAN_FREQ_RANGE_5GM;
1419         else
1420                 range = WL_CHAN_FREQ_RANGE_5GH;
1421
1422         return range;
1423 }
1424
1425 int wlc_phy_chanspec_bandrange_get(phy_info_t *pi, chanspec_t chanspec)
1426 {
1427         int range = -1;
1428         uint channel = CHSPEC_CHANNEL(chanspec);
1429         uint freq = wlc_phy_channel2freq(channel);
1430
1431         if (ISNPHY(pi)) {
1432                 range = wlc_phy_get_chan_freq_range_nphy(pi, channel);
1433         } else if (ISLCNPHY(pi)) {
1434                 range = wlc_phy_chanspec_freq2bandrange_lpssn(freq);
1435         }
1436
1437         return range;
1438 }
1439
1440 void wlc_phy_chanspec_ch14_widefilter_set(wlc_phy_t *ppi, bool wide_filter)
1441 {
1442         phy_info_t *pi = (phy_info_t *) ppi;
1443
1444         pi->channel_14_wide_filter = wide_filter;
1445
1446 }
1447
1448 int wlc_phy_channel2freq(uint channel)
1449 {
1450         uint i;
1451
1452         for (i = 0; i < ARRAY_SIZE(chan_info_all); i++)
1453                 if (chan_info_all[i].chan == channel)
1454                         return chan_info_all[i].freq;
1455         return 0;
1456 }
1457
1458 void
1459 wlc_phy_chanspec_band_validch(wlc_phy_t *ppi, uint band, chanvec_t *channels)
1460 {
1461         phy_info_t *pi = (phy_info_t *) ppi;
1462         uint i;
1463         uint channel;
1464
1465         memset(channels, 0, sizeof(chanvec_t));
1466
1467         for (i = 0; i < ARRAY_SIZE(chan_info_all); i++) {
1468                 channel = chan_info_all[i].chan;
1469
1470                 if ((pi->a_band_high_disable) && (channel >= FIRST_REF5_CHANNUM)
1471                     && (channel <= LAST_REF5_CHANNUM))
1472                         continue;
1473
1474                 if (((band == WLC_BAND_2G) && (channel <= CH_MAX_2G_CHANNEL)) ||
1475                     ((band == WLC_BAND_5G) && (channel > CH_MAX_2G_CHANNEL)))
1476                         setbit(channels->vec, channel);
1477         }
1478 }
1479
1480 chanspec_t wlc_phy_chanspec_band_firstch(wlc_phy_t *ppi, uint band)
1481 {
1482         phy_info_t *pi = (phy_info_t *) ppi;
1483         uint i;
1484         uint channel;
1485         chanspec_t chspec;
1486
1487         for (i = 0; i < ARRAY_SIZE(chan_info_all); i++) {
1488                 channel = chan_info_all[i].chan;
1489
1490                 if (ISNPHY(pi) && IS40MHZ(pi)) {
1491                         uint j;
1492
1493                         for (j = 0; j < ARRAY_SIZE(chan_info_all); j++) {
1494                                 if (chan_info_all[j].chan ==
1495                                     channel + CH_10MHZ_APART)
1496                                         break;
1497                         }
1498
1499                         if (j == ARRAY_SIZE(chan_info_all))
1500                                 continue;
1501
1502                         channel = UPPER_20_SB(channel);
1503                         chspec =
1504                             channel | WL_CHANSPEC_BW_40 |
1505                             WL_CHANSPEC_CTL_SB_LOWER;
1506                         if (band == WLC_BAND_2G)
1507                                 chspec |= WL_CHANSPEC_BAND_2G;
1508                         else
1509                                 chspec |= WL_CHANSPEC_BAND_5G;
1510                 } else
1511                         chspec = CH20MHZ_CHSPEC(channel);
1512
1513                 if ((pi->a_band_high_disable) && (channel >= FIRST_REF5_CHANNUM)
1514                     && (channel <= LAST_REF5_CHANNUM))
1515                         continue;
1516
1517                 if (((band == WLC_BAND_2G) && (channel <= CH_MAX_2G_CHANNEL)) ||
1518                     ((band == WLC_BAND_5G) && (channel > CH_MAX_2G_CHANNEL)))
1519                         return chspec;
1520         }
1521
1522         return (chanspec_t) INVCHANSPEC;
1523 }
1524
1525 int wlc_phy_txpower_get(wlc_phy_t *ppi, uint *qdbm, bool *override)
1526 {
1527         phy_info_t *pi = (phy_info_t *) ppi;
1528
1529         *qdbm = pi->tx_user_target[0];
1530         if (override != NULL)
1531                 *override = pi->txpwroverride;
1532         return 0;
1533 }
1534
1535 void wlc_phy_txpower_target_set(wlc_phy_t *ppi, struct txpwr_limits *txpwr)
1536 {
1537         bool mac_enabled = false;
1538         phy_info_t *pi = (phy_info_t *) ppi;
1539
1540         memcpy(&pi->tx_user_target[TXP_FIRST_CCK],
1541                &txpwr->cck[0], WLC_NUM_RATES_CCK);
1542
1543         memcpy(&pi->tx_user_target[TXP_FIRST_OFDM],
1544                &txpwr->ofdm[0], WLC_NUM_RATES_OFDM);
1545         memcpy(&pi->tx_user_target[TXP_FIRST_OFDM_20_CDD],
1546                &txpwr->ofdm_cdd[0], WLC_NUM_RATES_OFDM);
1547
1548         memcpy(&pi->tx_user_target[TXP_FIRST_OFDM_40_SISO],
1549                &txpwr->ofdm_40_siso[0], WLC_NUM_RATES_OFDM);
1550         memcpy(&pi->tx_user_target[TXP_FIRST_OFDM_40_CDD],
1551                &txpwr->ofdm_40_cdd[0], WLC_NUM_RATES_OFDM);
1552
1553         memcpy(&pi->tx_user_target[TXP_FIRST_MCS_20_SISO],
1554                &txpwr->mcs_20_siso[0], WLC_NUM_RATES_MCS_1_STREAM);
1555         memcpy(&pi->tx_user_target[TXP_FIRST_MCS_20_CDD],
1556                &txpwr->mcs_20_cdd[0], WLC_NUM_RATES_MCS_1_STREAM);
1557         memcpy(&pi->tx_user_target[TXP_FIRST_MCS_20_STBC],
1558                &txpwr->mcs_20_stbc[0], WLC_NUM_RATES_MCS_1_STREAM);
1559         memcpy(&pi->tx_user_target[TXP_FIRST_MCS_20_SDM],
1560                &txpwr->mcs_20_mimo[0], WLC_NUM_RATES_MCS_2_STREAM);
1561
1562         memcpy(&pi->tx_user_target[TXP_FIRST_MCS_40_SISO],
1563                &txpwr->mcs_40_siso[0], WLC_NUM_RATES_MCS_1_STREAM);
1564         memcpy(&pi->tx_user_target[TXP_FIRST_MCS_40_CDD],
1565                &txpwr->mcs_40_cdd[0], WLC_NUM_RATES_MCS_1_STREAM);
1566         memcpy(&pi->tx_user_target[TXP_FIRST_MCS_40_STBC],
1567                &txpwr->mcs_40_stbc[0], WLC_NUM_RATES_MCS_1_STREAM);
1568         memcpy(&pi->tx_user_target[TXP_FIRST_MCS_40_SDM],
1569                &txpwr->mcs_40_mimo[0], WLC_NUM_RATES_MCS_2_STREAM);
1570
1571         if (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC)
1572                 mac_enabled = true;
1573
1574         if (mac_enabled)
1575                 wlapi_suspend_mac_and_wait(pi->sh->physhim);
1576
1577         wlc_phy_txpower_recalc_target(pi);
1578         wlc_phy_cal_txpower_recalc_sw(pi);
1579
1580         if (mac_enabled)
1581                 wlapi_enable_mac(pi->sh->physhim);
1582 }
1583
1584 int wlc_phy_txpower_set(wlc_phy_t *ppi, uint qdbm, bool override)
1585 {
1586         phy_info_t *pi = (phy_info_t *) ppi;
1587         int i;
1588
1589         if (qdbm > 127)
1590                 return 5;
1591
1592         for (i = 0; i < TXP_NUM_RATES; i++)
1593                 pi->tx_user_target[i] = (u8) qdbm;
1594
1595         pi->txpwroverride = false;
1596
1597         if (pi->sh->up) {
1598                 if (!SCAN_INPROG_PHY(pi)) {
1599                         bool suspend;
1600
1601                         suspend =
1602                             (0 ==
1603                              (R_REG(&pi->regs->maccontrol) &
1604                               MCTL_EN_MAC));
1605
1606                         if (!suspend)
1607                                 wlapi_suspend_mac_and_wait(pi->sh->physhim);
1608
1609                         wlc_phy_txpower_recalc_target(pi);
1610                         wlc_phy_cal_txpower_recalc_sw(pi);
1611
1612                         if (!suspend)
1613                                 wlapi_enable_mac(pi->sh->physhim);
1614                 }
1615         }
1616         return 0;
1617 }
1618
1619 void
1620 wlc_phy_txpower_sromlimit(wlc_phy_t *ppi, uint channel, u8 *min_pwr,
1621                           u8 *max_pwr, int txp_rate_idx)
1622 {
1623         phy_info_t *pi = (phy_info_t *) ppi;
1624         uint i;
1625
1626         *min_pwr = pi->min_txpower * WLC_TXPWR_DB_FACTOR;
1627
1628         if (ISNPHY(pi)) {
1629                 if (txp_rate_idx < 0)
1630                         txp_rate_idx = TXP_FIRST_CCK;
1631                 wlc_phy_txpower_sromlimit_get_nphy(pi, channel, max_pwr,
1632                                                    (u8) txp_rate_idx);
1633
1634         } else if ((channel <= CH_MAX_2G_CHANNEL)) {
1635                 if (txp_rate_idx < 0)
1636                         txp_rate_idx = TXP_FIRST_CCK;
1637                 *max_pwr = pi->tx_srom_max_rate_2g[txp_rate_idx];
1638         } else {
1639
1640                 *max_pwr = WLC_TXPWR_MAX;
1641
1642                 if (txp_rate_idx < 0)
1643                         txp_rate_idx = TXP_FIRST_OFDM;
1644
1645                 for (i = 0; i < ARRAY_SIZE(chan_info_all); i++) {
1646                         if (channel == chan_info_all[i].chan) {
1647                                 break;
1648                         }
1649                 }
1650
1651                 if (pi->hwtxpwr) {
1652                         *max_pwr = pi->hwtxpwr[i];
1653                 } else {
1654
1655                         if ((i >= FIRST_MID_5G_CHAN) && (i <= LAST_MID_5G_CHAN))
1656                                 *max_pwr =
1657                                     pi->tx_srom_max_rate_5g_mid[txp_rate_idx];
1658                         if ((i >= FIRST_HIGH_5G_CHAN)
1659                             && (i <= LAST_HIGH_5G_CHAN))
1660                                 *max_pwr =
1661                                     pi->tx_srom_max_rate_5g_hi[txp_rate_idx];
1662                         if ((i >= FIRST_LOW_5G_CHAN) && (i <= LAST_LOW_5G_CHAN))
1663                                 *max_pwr =
1664                                     pi->tx_srom_max_rate_5g_low[txp_rate_idx];
1665                 }
1666         }
1667 }
1668
1669 void
1670 wlc_phy_txpower_sromlimit_max_get(wlc_phy_t *ppi, uint chan, u8 *max_txpwr,
1671                                   u8 *min_txpwr)
1672 {
1673         phy_info_t *pi = (phy_info_t *) ppi;
1674         u8 tx_pwr_max = 0;
1675         u8 tx_pwr_min = 255;
1676         u8 max_num_rate;
1677         u8 maxtxpwr, mintxpwr, rate, pactrl;
1678
1679         pactrl = 0;
1680
1681         max_num_rate = ISNPHY(pi) ? TXP_NUM_RATES :
1682             ISLCNPHY(pi) ? (TXP_LAST_SISO_MCS_20 + 1) : (TXP_LAST_OFDM + 1);
1683
1684         for (rate = 0; rate < max_num_rate; rate++) {
1685
1686                 wlc_phy_txpower_sromlimit(ppi, chan, &mintxpwr, &maxtxpwr,
1687                                           rate);
1688
1689                 maxtxpwr = (maxtxpwr > pactrl) ? (maxtxpwr - pactrl) : 0;
1690
1691                 maxtxpwr = (maxtxpwr > 6) ? (maxtxpwr - 6) : 0;
1692
1693                 tx_pwr_max = max(tx_pwr_max, maxtxpwr);
1694                 tx_pwr_min = min(tx_pwr_min, maxtxpwr);
1695         }
1696         *max_txpwr = tx_pwr_max;
1697         *min_txpwr = tx_pwr_min;
1698 }
1699
1700 void
1701 wlc_phy_txpower_boardlimit_band(wlc_phy_t *ppi, uint bandunit, s32 *max_pwr,
1702                                 s32 *min_pwr, u32 *step_pwr)
1703 {
1704         return;
1705 }
1706
1707 u8 wlc_phy_txpower_get_target_min(wlc_phy_t *ppi)
1708 {
1709         phy_info_t *pi = (phy_info_t *) ppi;
1710
1711         return pi->tx_power_min;
1712 }
1713
1714 u8 wlc_phy_txpower_get_target_max(wlc_phy_t *ppi)
1715 {
1716         phy_info_t *pi = (phy_info_t *) ppi;
1717
1718         return pi->tx_power_max;
1719 }
1720
1721 void wlc_phy_txpower_recalc_target(phy_info_t *pi)
1722 {
1723         u8 maxtxpwr, mintxpwr, rate, pactrl;
1724         uint target_chan;
1725         u8 tx_pwr_target[TXP_NUM_RATES];
1726         u8 tx_pwr_max = 0;
1727         u8 tx_pwr_min = 255;
1728         u8 tx_pwr_max_rate_ind = 0;
1729         u8 max_num_rate;
1730         u8 start_rate = 0;
1731         chanspec_t chspec;
1732         u32 band = CHSPEC2WLC_BAND(pi->radio_chanspec);
1733         initfn_t txpwr_recalc_fn = NULL;
1734
1735         chspec = pi->radio_chanspec;
1736         if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_NONE)
1737                 target_chan = CHSPEC_CHANNEL(chspec);
1738         else if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_UPPER)
1739                 target_chan = UPPER_20_SB(CHSPEC_CHANNEL(chspec));
1740         else
1741                 target_chan = LOWER_20_SB(CHSPEC_CHANNEL(chspec));
1742
1743         pactrl = 0;
1744         if (ISLCNPHY(pi)) {
1745                 u32 offset_mcs, i;
1746
1747                 if (CHSPEC_IS40(pi->radio_chanspec)) {
1748                         offset_mcs = pi->mcs40_po;
1749                         for (i = TXP_FIRST_SISO_MCS_20;
1750                              i <= TXP_LAST_SISO_MCS_20; i++) {
1751                                 pi->tx_srom_max_rate_2g[i - 8] =
1752                                     pi->tx_srom_max_2g -
1753                                     ((offset_mcs & 0xf) * 2);
1754                                 offset_mcs >>= 4;
1755                         }
1756                 } else {
1757                         offset_mcs = pi->mcs20_po;
1758                         for (i = TXP_FIRST_SISO_MCS_20;
1759                              i <= TXP_LAST_SISO_MCS_20; i++) {
1760                                 pi->tx_srom_max_rate_2g[i - 8] =
1761                                     pi->tx_srom_max_2g -
1762                                     ((offset_mcs & 0xf) * 2);
1763                                 offset_mcs >>= 4;
1764                         }
1765                 }
1766         }
1767 #if WL11N
1768         max_num_rate = ((ISNPHY(pi)) ? (TXP_NUM_RATES) :
1769                         ((ISLCNPHY(pi)) ?
1770                          (TXP_LAST_SISO_MCS_20 + 1) : (TXP_LAST_OFDM + 1)));
1771 #else
1772         max_num_rate = ((ISNPHY(pi)) ? (TXP_NUM_RATES) : (TXP_LAST_OFDM + 1));
1773 #endif
1774
1775         wlc_phy_upd_env_txpwr_rate_limits(pi, band);
1776
1777         for (rate = start_rate; rate < max_num_rate; rate++) {
1778
1779                 tx_pwr_target[rate] = pi->tx_user_target[rate];
1780
1781                 if (pi->user_txpwr_at_rfport) {
1782                         tx_pwr_target[rate] +=
1783                             wlc_user_txpwr_antport_to_rfport(pi, target_chan,
1784                                                              band, rate);
1785                 }
1786
1787                 {
1788
1789                         wlc_phy_txpower_sromlimit((wlc_phy_t *) pi, target_chan,
1790                                                   &mintxpwr, &maxtxpwr, rate);
1791
1792                         maxtxpwr = min(maxtxpwr, pi->txpwr_limit[rate]);
1793
1794                         maxtxpwr =
1795                             (maxtxpwr > pactrl) ? (maxtxpwr - pactrl) : 0;
1796
1797                         maxtxpwr = (maxtxpwr > 6) ? (maxtxpwr - 6) : 0;
1798
1799                         maxtxpwr = min(maxtxpwr, tx_pwr_target[rate]);
1800
1801                         if (pi->txpwr_percent <= 100)
1802                                 maxtxpwr = (maxtxpwr * pi->txpwr_percent) / 100;
1803
1804                         tx_pwr_target[rate] = max(maxtxpwr, mintxpwr);
1805                 }
1806
1807                 tx_pwr_target[rate] =
1808                     min(tx_pwr_target[rate], pi->txpwr_env_limit[rate]);
1809
1810                 if (tx_pwr_target[rate] > tx_pwr_max)
1811                         tx_pwr_max_rate_ind = rate;
1812
1813                 tx_pwr_max = max(tx_pwr_max, tx_pwr_target[rate]);
1814                 tx_pwr_min = min(tx_pwr_min, tx_pwr_target[rate]);
1815         }
1816
1817         memset(pi->tx_power_offset, 0, sizeof(pi->tx_power_offset));
1818         pi->tx_power_max = tx_pwr_max;
1819         pi->tx_power_min = tx_pwr_min;
1820         pi->tx_power_max_rate_ind = tx_pwr_max_rate_ind;
1821         for (rate = 0; rate < max_num_rate; rate++) {
1822
1823                 pi->tx_power_target[rate] = tx_pwr_target[rate];
1824
1825                 if (!pi->hwpwrctrl || ISNPHY(pi)) {
1826                         pi->tx_power_offset[rate] =
1827                             pi->tx_power_max - pi->tx_power_target[rate];
1828                 } else {
1829                         pi->tx_power_offset[rate] =
1830                             pi->tx_power_target[rate] - pi->tx_power_min;
1831                 }
1832         }
1833
1834         txpwr_recalc_fn = pi->pi_fptr.txpwrrecalc;
1835         if (txpwr_recalc_fn)
1836                 (*txpwr_recalc_fn) (pi);
1837 }
1838
1839 void
1840 wlc_phy_txpower_reg_limit_calc(phy_info_t *pi, struct txpwr_limits *txpwr,
1841                                chanspec_t chanspec)
1842 {
1843         u8 tmp_txpwr_limit[2 * WLC_NUM_RATES_OFDM];
1844         u8 *txpwr_ptr1 = NULL, *txpwr_ptr2 = NULL;
1845         int rate_start_index = 0, rate1, rate2, k;
1846
1847         for (rate1 = WL_TX_POWER_CCK_FIRST, rate2 = 0;
1848              rate2 < WL_TX_POWER_CCK_NUM; rate1++, rate2++)
1849                 pi->txpwr_limit[rate1] = txpwr->cck[rate2];
1850
1851         for (rate1 = WL_TX_POWER_OFDM_FIRST, rate2 = 0;
1852              rate2 < WL_TX_POWER_OFDM_NUM; rate1++, rate2++)
1853                 pi->txpwr_limit[rate1] = txpwr->ofdm[rate2];
1854
1855         if (ISNPHY(pi)) {
1856
1857                 for (k = 0; k < 4; k++) {
1858                         switch (k) {
1859                         case 0:
1860
1861                                 txpwr_ptr1 = txpwr->mcs_20_siso;
1862                                 txpwr_ptr2 = txpwr->ofdm;
1863                                 rate_start_index = WL_TX_POWER_OFDM_FIRST;
1864                                 break;
1865                         case 1:
1866
1867                                 txpwr_ptr1 = txpwr->mcs_20_cdd;
1868                                 txpwr_ptr2 = txpwr->ofdm_cdd;
1869                                 rate_start_index = WL_TX_POWER_OFDM20_CDD_FIRST;
1870                                 break;
1871                         case 2:
1872
1873                                 txpwr_ptr1 = txpwr->mcs_40_siso;
1874                                 txpwr_ptr2 = txpwr->ofdm_40_siso;
1875                                 rate_start_index =
1876                                     WL_TX_POWER_OFDM40_SISO_FIRST;
1877                                 break;
1878                         case 3:
1879
1880                                 txpwr_ptr1 = txpwr->mcs_40_cdd;
1881                                 txpwr_ptr2 = txpwr->ofdm_40_cdd;
1882                                 rate_start_index = WL_TX_POWER_OFDM40_CDD_FIRST;
1883                                 break;
1884                         }
1885
1886                         for (rate2 = 0; rate2 < WLC_NUM_RATES_OFDM; rate2++) {
1887                                 tmp_txpwr_limit[rate2] = 0;
1888                                 tmp_txpwr_limit[WLC_NUM_RATES_OFDM + rate2] =
1889                                     txpwr_ptr1[rate2];
1890                         }
1891                         wlc_phy_mcs_to_ofdm_powers_nphy(tmp_txpwr_limit, 0,
1892                                                         WLC_NUM_RATES_OFDM - 1,
1893                                                         WLC_NUM_RATES_OFDM);
1894                         for (rate1 = rate_start_index, rate2 = 0;
1895                              rate2 < WLC_NUM_RATES_OFDM; rate1++, rate2++)
1896                                 pi->txpwr_limit[rate1] =
1897                                     min(txpwr_ptr2[rate2],
1898                                         tmp_txpwr_limit[rate2]);
1899                 }
1900
1901                 for (k = 0; k < 4; k++) {
1902                         switch (k) {
1903                         case 0:
1904
1905                                 txpwr_ptr1 = txpwr->ofdm;
1906                                 txpwr_ptr2 = txpwr->mcs_20_siso;
1907                                 rate_start_index = WL_TX_POWER_MCS20_SISO_FIRST;
1908                                 break;
1909                         case 1:
1910
1911                                 txpwr_ptr1 = txpwr->ofdm_cdd;
1912                                 txpwr_ptr2 = txpwr->mcs_20_cdd;
1913                                 rate_start_index = WL_TX_POWER_MCS20_CDD_FIRST;
1914                                 break;
1915                         case 2:
1916
1917                                 txpwr_ptr1 = txpwr->ofdm_40_siso;
1918                                 txpwr_ptr2 = txpwr->mcs_40_siso;
1919                                 rate_start_index = WL_TX_POWER_MCS40_SISO_FIRST;
1920                                 break;
1921                         case 3:
1922
1923                                 txpwr_ptr1 = txpwr->ofdm_40_cdd;
1924                                 txpwr_ptr2 = txpwr->mcs_40_cdd;
1925                                 rate_start_index = WL_TX_POWER_MCS40_CDD_FIRST;
1926                                 break;
1927                         }
1928                         for (rate2 = 0; rate2 < WLC_NUM_RATES_OFDM; rate2++) {
1929                                 tmp_txpwr_limit[rate2] = 0;
1930                                 tmp_txpwr_limit[WLC_NUM_RATES_OFDM + rate2] =
1931                                     txpwr_ptr1[rate2];
1932                         }
1933                         wlc_phy_ofdm_to_mcs_powers_nphy(tmp_txpwr_limit, 0,
1934                                                         WLC_NUM_RATES_OFDM - 1,
1935                                                         WLC_NUM_RATES_OFDM);
1936                         for (rate1 = rate_start_index, rate2 = 0;
1937                              rate2 < WLC_NUM_RATES_MCS_1_STREAM;
1938                              rate1++, rate2++)
1939                                 pi->txpwr_limit[rate1] =
1940                                     min(txpwr_ptr2[rate2],
1941                                         tmp_txpwr_limit[rate2]);
1942                 }
1943
1944                 for (k = 0; k < 2; k++) {
1945                         switch (k) {
1946                         case 0:
1947
1948                                 rate_start_index = WL_TX_POWER_MCS20_STBC_FIRST;
1949                                 txpwr_ptr1 = txpwr->mcs_20_stbc;
1950                                 break;
1951                         case 1:
1952
1953                                 rate_start_index = WL_TX_POWER_MCS40_STBC_FIRST;
1954                                 txpwr_ptr1 = txpwr->mcs_40_stbc;
1955                                 break;
1956                         }
1957                         for (rate1 = rate_start_index, rate2 = 0;
1958                              rate2 < WLC_NUM_RATES_MCS_1_STREAM;
1959                              rate1++, rate2++)
1960                                 pi->txpwr_limit[rate1] = txpwr_ptr1[rate2];
1961                 }
1962
1963                 for (k = 0; k < 2; k++) {
1964                         switch (k) {
1965                         case 0:
1966
1967                                 rate_start_index = WL_TX_POWER_MCS20_SDM_FIRST;
1968                                 txpwr_ptr1 = txpwr->mcs_20_mimo;
1969                                 break;
1970                         case 1:
1971
1972                                 rate_start_index = WL_TX_POWER_MCS40_SDM_FIRST;
1973                                 txpwr_ptr1 = txpwr->mcs_40_mimo;
1974                                 break;
1975                         }
1976                         for (rate1 = rate_start_index, rate2 = 0;
1977                              rate2 < WLC_NUM_RATES_MCS_2_STREAM;
1978                              rate1++, rate2++)
1979                                 pi->txpwr_limit[rate1] = txpwr_ptr1[rate2];
1980                 }
1981
1982                 pi->txpwr_limit[WL_TX_POWER_MCS_32] = txpwr->mcs32;
1983
1984                 pi->txpwr_limit[WL_TX_POWER_MCS40_CDD_FIRST] =
1985                     min(pi->txpwr_limit[WL_TX_POWER_MCS40_CDD_FIRST],
1986                         pi->txpwr_limit[WL_TX_POWER_MCS_32]);
1987                 pi->txpwr_limit[WL_TX_POWER_MCS_32] =
1988                     pi->txpwr_limit[WL_TX_POWER_MCS40_CDD_FIRST];
1989         }
1990 }
1991
1992 void wlc_phy_txpwr_percent_set(wlc_phy_t *ppi, u8 txpwr_percent)
1993 {
1994         phy_info_t *pi = (phy_info_t *) ppi;
1995
1996         pi->txpwr_percent = txpwr_percent;
1997 }
1998
1999 void wlc_phy_machwcap_set(wlc_phy_t *ppi, u32 machwcap)
2000 {
2001         phy_info_t *pi = (phy_info_t *) ppi;
2002
2003         pi->sh->machwcap = machwcap;
2004 }
2005
2006 void wlc_phy_runbist_config(wlc_phy_t *ppi, bool start_end)
2007 {
2008         phy_info_t *pi = (phy_info_t *) ppi;
2009         u16 rxc;
2010         rxc = 0;
2011
2012         if (start_end == ON) {
2013                 if (!ISNPHY(pi))
2014                         return;
2015
2016                 if (NREV_IS(pi->pubpi.phy_rev, 3)
2017                     || NREV_IS(pi->pubpi.phy_rev, 4)) {
2018                         W_REG(&pi->regs->phyregaddr, 0xa0);
2019                         (void)R_REG(&pi->regs->phyregaddr);
2020                         rxc = R_REG(&pi->regs->phyregdata);
2021                         W_REG(&pi->regs->phyregdata,
2022                               (0x1 << 15) | rxc);
2023                 }
2024         } else {
2025                 if (NREV_IS(pi->pubpi.phy_rev, 3)
2026                     || NREV_IS(pi->pubpi.phy_rev, 4)) {
2027                         W_REG(&pi->regs->phyregaddr, 0xa0);
2028                         (void)R_REG(&pi->regs->phyregaddr);
2029                         W_REG(&pi->regs->phyregdata, rxc);
2030                 }
2031
2032                 wlc_phy_por_inform(ppi);
2033         }
2034 }
2035
2036 void
2037 wlc_phy_txpower_limit_set(wlc_phy_t *ppi, struct txpwr_limits *txpwr,
2038                           chanspec_t chanspec)
2039 {
2040         phy_info_t *pi = (phy_info_t *) ppi;
2041
2042         wlc_phy_txpower_reg_limit_calc(pi, txpwr, chanspec);
2043
2044         if (ISLCNPHY(pi)) {
2045                 int i, j;
2046                 for (i = TXP_FIRST_OFDM_20_CDD, j = 0;
2047                      j < WLC_NUM_RATES_MCS_1_STREAM; i++, j++) {
2048                         if (txpwr->mcs_20_siso[j])
2049                                 pi->txpwr_limit[i] = txpwr->mcs_20_siso[j];
2050                         else
2051                                 pi->txpwr_limit[i] = txpwr->ofdm[j];
2052                 }
2053         }
2054
2055         wlapi_suspend_mac_and_wait(pi->sh->physhim);
2056
2057         wlc_phy_txpower_recalc_target(pi);
2058         wlc_phy_cal_txpower_recalc_sw(pi);
2059         wlapi_enable_mac(pi->sh->physhim);
2060 }
2061
2062 void wlc_phy_ofdm_rateset_war(wlc_phy_t *pih, bool war)
2063 {
2064         phy_info_t *pi = (phy_info_t *) pih;
2065
2066         pi->ofdm_rateset_war = war;
2067 }
2068
2069 void wlc_phy_bf_preempt_enable(wlc_phy_t *pih, bool bf_preempt)
2070 {
2071         phy_info_t *pi = (phy_info_t *) pih;
2072
2073         pi->bf_preempt_4306 = bf_preempt;
2074 }
2075
2076 void wlc_phy_txpower_update_shm(phy_info_t *pi)
2077 {
2078         int j;
2079         if (ISNPHY(pi)) {
2080                 return;
2081         }
2082
2083         if (!pi->sh->clk)
2084                 return;
2085
2086         if (pi->hwpwrctrl) {
2087                 u16 offset;
2088
2089                 wlapi_bmac_write_shm(pi->sh->physhim, M_TXPWR_MAX, 63);
2090                 wlapi_bmac_write_shm(pi->sh->physhim, M_TXPWR_N,
2091                                      1 << NUM_TSSI_FRAMES);
2092
2093                 wlapi_bmac_write_shm(pi->sh->physhim, M_TXPWR_TARGET,
2094                                      pi->tx_power_min << NUM_TSSI_FRAMES);
2095
2096                 wlapi_bmac_write_shm(pi->sh->physhim, M_TXPWR_CUR,
2097                                      pi->hwpwr_txcur);
2098
2099                 for (j = TXP_FIRST_OFDM; j <= TXP_LAST_OFDM; j++) {
2100                         const u8 ucode_ofdm_rates[] = {
2101                                 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c
2102                         };
2103                         offset = wlapi_bmac_rate_shm_offset(pi->sh->physhim,
2104                                                             ucode_ofdm_rates[j -
2105                                                                              TXP_FIRST_OFDM]);
2106                         wlapi_bmac_write_shm(pi->sh->physhim, offset + 6,
2107                                              pi->tx_power_offset[j]);
2108                         wlapi_bmac_write_shm(pi->sh->physhim, offset + 14,
2109                                              -(pi->tx_power_offset[j] / 2));
2110                 }
2111
2112                 wlapi_bmac_mhf(pi->sh->physhim, MHF2, MHF2_HWPWRCTL,
2113                                MHF2_HWPWRCTL, WLC_BAND_ALL);
2114         } else {
2115                 int i;
2116
2117                 for (i = TXP_FIRST_OFDM; i <= TXP_LAST_OFDM; i++)
2118                         pi->tx_power_offset[i] =
2119                             (u8) roundup(pi->tx_power_offset[i], 8);
2120                 wlapi_bmac_write_shm(pi->sh->physhim, M_OFDM_OFFSET,
2121                                      (u16) ((pi->
2122                                                 tx_power_offset[TXP_FIRST_OFDM]
2123                                                 + 7) >> 3));
2124         }
2125 }
2126
2127 bool wlc_phy_txpower_hw_ctrl_get(wlc_phy_t *ppi)
2128 {
2129         phy_info_t *pi = (phy_info_t *) ppi;
2130
2131         if (ISNPHY(pi)) {
2132                 return pi->nphy_txpwrctrl;
2133         } else {
2134                 return pi->hwpwrctrl;
2135         }
2136 }
2137
2138 void wlc_phy_txpower_hw_ctrl_set(wlc_phy_t *ppi, bool hwpwrctrl)
2139 {
2140         phy_info_t *pi = (phy_info_t *) ppi;
2141         bool cur_hwpwrctrl = pi->hwpwrctrl;
2142         bool suspend;
2143
2144         if (!pi->hwpwrctrl_capable) {
2145                 return;
2146         }
2147
2148         pi->hwpwrctrl = hwpwrctrl;
2149         pi->nphy_txpwrctrl = hwpwrctrl;
2150         pi->txpwrctrl = hwpwrctrl;
2151
2152         if (ISNPHY(pi)) {
2153                 suspend =
2154                     (0 ==
2155                      (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC));
2156                 if (!suspend)
2157                         wlapi_suspend_mac_and_wait(pi->sh->physhim);
2158
2159                 wlc_phy_txpwrctrl_enable_nphy(pi, pi->nphy_txpwrctrl);
2160                 if (pi->nphy_txpwrctrl == PHY_TPC_HW_OFF) {
2161                         wlc_phy_txpwr_fixpower_nphy(pi);
2162                 } else {
2163
2164                         mod_phy_reg(pi, 0x1e7, (0x7f << 0),
2165                                     pi->saved_txpwr_idx);
2166                 }
2167
2168                 if (!suspend)
2169                         wlapi_enable_mac(pi->sh->physhim);
2170         } else if (hwpwrctrl != cur_hwpwrctrl) {
2171
2172                 return;
2173         }
2174 }
2175
2176 void wlc_phy_txpower_ipa_upd(phy_info_t *pi)
2177 {
2178
2179         if (NREV_GE(pi->pubpi.phy_rev, 3)) {
2180                 pi->ipa2g_on = (pi->srom_fem2g.extpagain == 2);
2181                 pi->ipa5g_on = (pi->srom_fem5g.extpagain == 2);
2182         } else {
2183                 pi->ipa2g_on = false;
2184                 pi->ipa5g_on = false;
2185         }
2186 }
2187
2188 static u32 wlc_phy_txpower_est_power_nphy(phy_info_t *pi);
2189
2190 static u32 wlc_phy_txpower_est_power_nphy(phy_info_t *pi)
2191 {
2192         s16 tx0_status, tx1_status;
2193         u16 estPower1, estPower2;
2194         u8 pwr0, pwr1, adj_pwr0, adj_pwr1;
2195         u32 est_pwr;
2196
2197         estPower1 = read_phy_reg(pi, 0x118);
2198         estPower2 = read_phy_reg(pi, 0x119);
2199
2200         if ((estPower1 & (0x1 << 8))
2201             == (0x1 << 8)) {
2202                 pwr0 = (u8) (estPower1 & (0xff << 0))
2203                     >> 0;
2204         } else {
2205                 pwr0 = 0x80;
2206         }
2207
2208         if ((estPower2 & (0x1 << 8))
2209             == (0x1 << 8)) {
2210                 pwr1 = (u8) (estPower2 & (0xff << 0))
2211                     >> 0;
2212         } else {
2213                 pwr1 = 0x80;
2214         }
2215
2216         tx0_status = read_phy_reg(pi, 0x1ed);
2217         tx1_status = read_phy_reg(pi, 0x1ee);
2218
2219         if ((tx0_status & (0x1 << 15))
2220             == (0x1 << 15)) {
2221                 adj_pwr0 = (u8) (tx0_status & (0xff << 0))
2222                     >> 0;
2223         } else {
2224                 adj_pwr0 = 0x80;
2225         }
2226         if ((tx1_status & (0x1 << 15))
2227             == (0x1 << 15)) {
2228                 adj_pwr1 = (u8) (tx1_status & (0xff << 0))
2229                     >> 0;
2230         } else {
2231                 adj_pwr1 = 0x80;
2232         }
2233
2234         est_pwr =
2235             (u32) ((pwr0 << 24) | (pwr1 << 16) | (adj_pwr0 << 8) | adj_pwr1);
2236         return est_pwr;
2237 }
2238
2239 void
2240 wlc_phy_txpower_get_current(wlc_phy_t *ppi, tx_power_t *power, uint channel)
2241 {
2242         phy_info_t *pi = (phy_info_t *) ppi;
2243         uint rate, num_rates;
2244         u8 min_pwr, max_pwr;
2245
2246 #if WL_TX_POWER_RATES != TXP_NUM_RATES
2247 #error "tx_power_t struct out of sync with this fn"
2248 #endif
2249
2250         if (ISNPHY(pi)) {
2251                 power->rf_cores = 2;
2252                 power->flags |= (WL_TX_POWER_F_MIMO);
2253                 if (pi->nphy_txpwrctrl == PHY_TPC_HW_ON)
2254                         power->flags |=
2255                             (WL_TX_POWER_F_ENABLED | WL_TX_POWER_F_HW);
2256         } else if (ISLCNPHY(pi)) {
2257                 power->rf_cores = 1;
2258                 power->flags |= (WL_TX_POWER_F_SISO);
2259                 if (pi->radiopwr_override == RADIOPWR_OVERRIDE_DEF)
2260                         power->flags |= WL_TX_POWER_F_ENABLED;
2261                 if (pi->hwpwrctrl)
2262                         power->flags |= WL_TX_POWER_F_HW;
2263         }
2264
2265         num_rates = ((ISNPHY(pi)) ? (TXP_NUM_RATES) :
2266                      ((ISLCNPHY(pi)) ?
2267                       (TXP_LAST_OFDM_20_CDD + 1) : (TXP_LAST_OFDM + 1)));
2268
2269         for (rate = 0; rate < num_rates; rate++) {
2270                 power->user_limit[rate] = pi->tx_user_target[rate];
2271                 wlc_phy_txpower_sromlimit(ppi, channel, &min_pwr, &max_pwr,
2272                                           rate);
2273                 power->board_limit[rate] = (u8) max_pwr;
2274                 power->target[rate] = pi->tx_power_target[rate];
2275         }
2276
2277         if (ISNPHY(pi)) {
2278                 u32 est_pout;
2279
2280                 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2281                 wlc_phyreg_enter((wlc_phy_t *) pi);
2282                 est_pout = wlc_phy_txpower_est_power_nphy(pi);
2283                 wlc_phyreg_exit((wlc_phy_t *) pi);
2284                 wlapi_enable_mac(pi->sh->physhim);
2285
2286                 power->est_Pout[0] = (est_pout >> 8) & 0xff;
2287                 power->est_Pout[1] = est_pout & 0xff;
2288
2289                 power->est_Pout_act[0] = est_pout >> 24;
2290                 power->est_Pout_act[1] = (est_pout >> 16) & 0xff;
2291
2292                 if (power->est_Pout[0] == 0x80)
2293                         power->est_Pout[0] = 0;
2294                 if (power->est_Pout[1] == 0x80)
2295                         power->est_Pout[1] = 0;
2296
2297                 if (power->est_Pout_act[0] == 0x80)
2298                         power->est_Pout_act[0] = 0;
2299                 if (power->est_Pout_act[1] == 0x80)
2300                         power->est_Pout_act[1] = 0;
2301
2302                 power->est_Pout_cck = 0;
2303
2304                 power->tx_power_max[0] = pi->tx_power_max;
2305                 power->tx_power_max[1] = pi->tx_power_max;
2306
2307                 power->tx_power_max_rate_ind[0] = pi->tx_power_max_rate_ind;
2308                 power->tx_power_max_rate_ind[1] = pi->tx_power_max_rate_ind;
2309         } else if (!pi->hwpwrctrl) {
2310         } else if (pi->sh->up) {
2311
2312                 wlc_phyreg_enter(ppi);
2313                 if (ISLCNPHY(pi)) {
2314
2315                         power->tx_power_max[0] = pi->tx_power_max;
2316                         power->tx_power_max[1] = pi->tx_power_max;
2317
2318                         power->tx_power_max_rate_ind[0] =
2319                             pi->tx_power_max_rate_ind;
2320                         power->tx_power_max_rate_ind[1] =
2321                             pi->tx_power_max_rate_ind;
2322
2323                         if (wlc_phy_tpc_isenabled_lcnphy(pi))
2324                                 power->flags |=
2325                                     (WL_TX_POWER_F_HW | WL_TX_POWER_F_ENABLED);
2326                         else
2327                                 power->flags &=
2328                                     ~(WL_TX_POWER_F_HW | WL_TX_POWER_F_ENABLED);
2329
2330                         wlc_lcnphy_get_tssi(pi, (s8 *) &power->est_Pout[0],
2331                                             (s8 *) &power->est_Pout_cck);
2332                 }
2333                 wlc_phyreg_exit(ppi);
2334         }
2335 }
2336
2337 void wlc_phy_antsel_type_set(wlc_phy_t *ppi, u8 antsel_type)
2338 {
2339         phy_info_t *pi = (phy_info_t *) ppi;
2340
2341         pi->antsel_type = antsel_type;
2342 }
2343
2344 bool wlc_phy_test_ison(wlc_phy_t *ppi)
2345 {
2346         phy_info_t *pi = (phy_info_t *) ppi;
2347
2348         return pi->phytest_on;
2349 }
2350
2351 bool wlc_phy_ant_rxdiv_get(wlc_phy_t *ppi, u8 *pval)
2352 {
2353         phy_info_t *pi = (phy_info_t *) ppi;
2354         bool ret = true;
2355
2356         wlc_phyreg_enter(ppi);
2357
2358         if (ISNPHY(pi)) {
2359
2360                 ret = false;
2361         } else if (ISLCNPHY(pi)) {
2362                 u16 crsctrl = read_phy_reg(pi, 0x410);
2363                 u16 div = crsctrl & (0x1 << 1);
2364                 *pval = (div | ((crsctrl & (0x1 << 0)) ^ (div >> 1)));
2365         }
2366
2367         wlc_phyreg_exit(ppi);
2368
2369         return ret;
2370 }
2371
2372 void wlc_phy_ant_rxdiv_set(wlc_phy_t *ppi, u8 val)
2373 {
2374         phy_info_t *pi = (phy_info_t *) ppi;
2375         bool suspend;
2376
2377         pi->sh->rx_antdiv = val;
2378
2379         if (!(ISNPHY(pi) && D11REV_IS(pi->sh->corerev, 16))) {
2380                 if (val > ANT_RX_DIV_FORCE_1)
2381                         wlapi_bmac_mhf(pi->sh->physhim, MHF1, MHF1_ANTDIV,
2382                                        MHF1_ANTDIV, WLC_BAND_ALL);
2383                 else
2384                         wlapi_bmac_mhf(pi->sh->physhim, MHF1, MHF1_ANTDIV, 0,
2385                                        WLC_BAND_ALL);
2386         }
2387
2388         if (ISNPHY(pi)) {
2389
2390                 return;
2391         }
2392
2393         if (!pi->sh->clk)
2394                 return;
2395
2396         suspend =
2397             (0 == (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC));
2398         if (!suspend)
2399                 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2400
2401         if (ISLCNPHY(pi)) {
2402                 if (val > ANT_RX_DIV_FORCE_1) {
2403                         mod_phy_reg(pi, 0x410, (0x1 << 1), 0x01 << 1);
2404                         mod_phy_reg(pi, 0x410,
2405                                     (0x1 << 0),
2406                                     ((ANT_RX_DIV_START_1 == val) ? 1 : 0) << 0);
2407                 } else {
2408                         mod_phy_reg(pi, 0x410, (0x1 << 1), 0x00 << 1);
2409                         mod_phy_reg(pi, 0x410, (0x1 << 0), (u16) val << 0);
2410                 }
2411         }
2412
2413         if (!suspend)
2414                 wlapi_enable_mac(pi->sh->physhim);
2415
2416         return;
2417 }
2418
2419 static bool
2420 wlc_phy_noise_calc_phy(phy_info_t *pi, u32 *cmplx_pwr, s8 *pwr_ant)
2421 {
2422         s8 cmplx_pwr_dbm[PHY_CORE_MAX];
2423         u8 i;
2424
2425         memset((u8 *) cmplx_pwr_dbm, 0, sizeof(cmplx_pwr_dbm));
2426         wlc_phy_compute_dB(cmplx_pwr, cmplx_pwr_dbm, pi->pubpi.phy_corenum);
2427
2428         for (i = 0; i < pi->pubpi.phy_corenum; i++) {
2429                 if (NREV_GE(pi->pubpi.phy_rev, 3))
2430                         cmplx_pwr_dbm[i] += (s8) PHY_NOISE_OFFSETFACT_4322;
2431                 else
2432
2433                         cmplx_pwr_dbm[i] += (s8) (16 - (15) * 3 - 70);
2434         }
2435
2436         for (i = 0; i < pi->pubpi.phy_corenum; i++) {
2437                 pi->nphy_noise_win[i][pi->nphy_noise_index] = cmplx_pwr_dbm[i];
2438                 pwr_ant[i] = cmplx_pwr_dbm[i];
2439         }
2440         pi->nphy_noise_index =
2441             MODINC_POW2(pi->nphy_noise_index, PHY_NOISE_WINDOW_SZ);
2442         return true;
2443 }
2444
2445 static void
2446 wlc_phy_noise_sample_request(wlc_phy_t *pih, u8 reason, u8 ch)
2447 {
2448         phy_info_t *pi = (phy_info_t *) pih;
2449         s8 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;
2450         bool sampling_in_progress = (pi->phynoise_state != 0);
2451         bool wait_for_intr = true;
2452
2453         if (NORADIO_ENAB(pi->pubpi)) {
2454                 return;
2455         }
2456
2457         switch (reason) {
2458         case PHY_NOISE_SAMPLE_MON:
2459
2460                 pi->phynoise_chan_watchdog = ch;
2461                 pi->phynoise_state |= PHY_NOISE_STATE_MON;
2462
2463                 break;
2464
2465         case PHY_NOISE_SAMPLE_EXTERNAL:
2466
2467                 pi->phynoise_state |= PHY_NOISE_STATE_EXTERNAL;
2468                 break;
2469
2470         default:
2471                 break;
2472         }
2473
2474         if (sampling_in_progress)
2475                 return;
2476
2477         pi->phynoise_now = pi->sh->now;
2478
2479         if (pi->phy_fixed_noise) {
2480                 if (ISNPHY(pi)) {
2481                         pi->nphy_noise_win[WL_ANT_IDX_1][pi->nphy_noise_index] =
2482                             PHY_NOISE_FIXED_VAL_NPHY;
2483                         pi->nphy_noise_win[WL_ANT_IDX_2][pi->nphy_noise_index] =
2484                             PHY_NOISE_FIXED_VAL_NPHY;
2485                         pi->nphy_noise_index = MODINC_POW2(pi->nphy_noise_index,
2486                                                            PHY_NOISE_WINDOW_SZ);
2487
2488                         noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;
2489                 } else {
2490
2491                         noise_dbm = PHY_NOISE_FIXED_VAL;
2492                 }
2493
2494                 wait_for_intr = false;
2495                 goto done;
2496         }
2497
2498         if (ISLCNPHY(pi)) {
2499                 if (!pi->phynoise_polling
2500                     || (reason == PHY_NOISE_SAMPLE_EXTERNAL)) {
2501                         wlapi_bmac_write_shm(pi->sh->physhim, M_JSSI_0, 0);
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);
2506
2507                         OR_REG(&pi->regs->maccommand,
2508                                MCMD_BG_NOISE);
2509                 } else {
2510                         wlapi_suspend_mac_and_wait(pi->sh->physhim);
2511                         wlc_lcnphy_deaf_mode(pi, (bool) 0);
2512                         noise_dbm = (s8) wlc_lcnphy_rx_signal_power(pi, 20);
2513                         wlc_lcnphy_deaf_mode(pi, (bool) 1);
2514                         wlapi_enable_mac(pi->sh->physhim);
2515                         wait_for_intr = false;
2516                 }
2517         } else if (ISNPHY(pi)) {
2518                 if (!pi->phynoise_polling
2519                     || (reason == PHY_NOISE_SAMPLE_EXTERNAL)) {
2520
2521                         wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP0, 0);
2522                         wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP1, 0);
2523                         wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP2, 0);
2524                         wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP3, 0);
2525
2526                         OR_REG(&pi->regs->maccommand,
2527                                MCMD_BG_NOISE);
2528                 } else {
2529                         phy_iq_est_t est[PHY_CORE_MAX];
2530                         u32 cmplx_pwr[PHY_CORE_MAX];
2531                         s8 noise_dbm_ant[PHY_CORE_MAX];
2532                         u16 log_num_samps, num_samps, classif_state = 0;
2533                         u8 wait_time = 32;
2534                         u8 wait_crs = 0;
2535                         u8 i;
2536
2537                         memset((u8 *) est, 0, sizeof(est));
2538                         memset((u8 *) cmplx_pwr, 0, sizeof(cmplx_pwr));
2539                         memset((u8 *) noise_dbm_ant, 0, sizeof(noise_dbm_ant));
2540
2541                         log_num_samps = PHY_NOISE_SAMPLE_LOG_NUM_NPHY;
2542                         num_samps = 1 << log_num_samps;
2543
2544                         wlapi_suspend_mac_and_wait(pi->sh->physhim);
2545                         classif_state = wlc_phy_classifier_nphy(pi, 0, 0);
2546                         wlc_phy_classifier_nphy(pi, 3, 0);
2547                         wlc_phy_rx_iq_est_nphy(pi, est, num_samps, wait_time,
2548                                                wait_crs);
2549                         wlc_phy_classifier_nphy(pi, (0x7 << 0), classif_state);
2550                         wlapi_enable_mac(pi->sh->physhim);
2551
2552                         for (i = 0; i < pi->pubpi.phy_corenum; i++)
2553                                 cmplx_pwr[i] =
2554                                     (est[i].i_pwr +
2555                                      est[i].q_pwr) >> log_num_samps;
2556
2557                         wlc_phy_noise_calc_phy(pi, cmplx_pwr, noise_dbm_ant);
2558
2559                         for (i = 0; i < pi->pubpi.phy_corenum; i++) {
2560                                 pi->nphy_noise_win[i][pi->nphy_noise_index] =
2561                                     noise_dbm_ant[i];
2562
2563                                 if (noise_dbm_ant[i] > noise_dbm)
2564                                         noise_dbm = noise_dbm_ant[i];
2565                         }
2566                         pi->nphy_noise_index = MODINC_POW2(pi->nphy_noise_index,
2567                                                            PHY_NOISE_WINDOW_SZ);
2568
2569                         wait_for_intr = false;
2570                 }
2571         }
2572
2573  done:
2574
2575         if (!wait_for_intr)
2576                 wlc_phy_noise_cb(pi, ch, noise_dbm);
2577
2578 }
2579
2580 void wlc_phy_noise_sample_request_external(wlc_phy_t *pih)
2581 {
2582         u8 channel;
2583
2584         channel = CHSPEC_CHANNEL(wlc_phy_chanspec_get(pih));
2585
2586         wlc_phy_noise_sample_request(pih, PHY_NOISE_SAMPLE_EXTERNAL, channel);
2587 }
2588
2589 static void wlc_phy_noise_cb(phy_info_t *pi, u8 channel, s8 noise_dbm)
2590 {
2591         if (!pi->phynoise_state)
2592                 return;
2593
2594         if (pi->phynoise_state & PHY_NOISE_STATE_MON) {
2595                 if (pi->phynoise_chan_watchdog == channel) {
2596                         pi->sh->phy_noise_window[pi->sh->phy_noise_index] =
2597                             noise_dbm;
2598                         pi->sh->phy_noise_index =
2599                             MODINC(pi->sh->phy_noise_index, MA_WINDOW_SZ);
2600                 }
2601                 pi->phynoise_state &= ~PHY_NOISE_STATE_MON;
2602         }
2603
2604         if (pi->phynoise_state & PHY_NOISE_STATE_EXTERNAL) {
2605                 pi->phynoise_state &= ~PHY_NOISE_STATE_EXTERNAL;
2606         }
2607
2608 }
2609
2610 static s8 wlc_phy_noise_read_shmem(phy_info_t *pi)
2611 {
2612         u32 cmplx_pwr[PHY_CORE_MAX];
2613         s8 noise_dbm_ant[PHY_CORE_MAX];
2614         u16 lo, hi;
2615         u32 cmplx_pwr_tot = 0;
2616         s8 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;
2617         u8 idx, core;
2618
2619         memset((u8 *) cmplx_pwr, 0, sizeof(cmplx_pwr));
2620         memset((u8 *) noise_dbm_ant, 0, sizeof(noise_dbm_ant));
2621
2622         for (idx = 0, core = 0; core < pi->pubpi.phy_corenum; idx += 2, core++) {
2623                 lo = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP(idx));
2624                 hi = wlapi_bmac_read_shm(pi->sh->physhim,
2625                                          M_PWRIND_MAP(idx + 1));
2626                 cmplx_pwr[core] = (hi << 16) + lo;
2627                 cmplx_pwr_tot += cmplx_pwr[core];
2628                 if (cmplx_pwr[core] == 0) {
2629                         noise_dbm_ant[core] = PHY_NOISE_FIXED_VAL_NPHY;
2630                 } else
2631                         cmplx_pwr[core] >>= PHY_NOISE_SAMPLE_LOG_NUM_UCODE;
2632         }
2633
2634         if (cmplx_pwr_tot != 0)
2635                 wlc_phy_noise_calc_phy(pi, cmplx_pwr, noise_dbm_ant);
2636
2637         for (core = 0; core < pi->pubpi.phy_corenum; core++) {
2638                 pi->nphy_noise_win[core][pi->nphy_noise_index] =
2639                     noise_dbm_ant[core];
2640
2641                 if (noise_dbm_ant[core] > noise_dbm)
2642                         noise_dbm = noise_dbm_ant[core];
2643         }
2644         pi->nphy_noise_index =
2645             MODINC_POW2(pi->nphy_noise_index, PHY_NOISE_WINDOW_SZ);
2646
2647         return noise_dbm;
2648
2649 }
2650
2651 void wlc_phy_noise_sample_intr(wlc_phy_t *pih)
2652 {
2653         phy_info_t *pi = (phy_info_t *) pih;
2654         u16 jssi_aux;
2655         u8 channel = 0;
2656         s8 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;
2657
2658         if (ISLCNPHY(pi)) {
2659                 u32 cmplx_pwr, cmplx_pwr0, cmplx_pwr1;
2660                 u16 lo, hi;
2661                 s32 pwr_offset_dB, gain_dB;
2662                 u16 status_0, status_1;
2663
2664                 jssi_aux = wlapi_bmac_read_shm(pi->sh->physhim, M_JSSI_AUX);
2665                 channel = jssi_aux & D11_CURCHANNEL_MAX;
2666
2667                 lo = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP0);
2668                 hi = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP1);
2669                 cmplx_pwr0 = (hi << 16) + lo;
2670
2671                 lo = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP2);
2672                 hi = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP3);
2673                 cmplx_pwr1 = (hi << 16) + lo;
2674                 cmplx_pwr = (cmplx_pwr0 + cmplx_pwr1) >> 6;
2675
2676                 status_0 = 0x44;
2677                 status_1 = wlapi_bmac_read_shm(pi->sh->physhim, M_JSSI_0);
2678                 if ((cmplx_pwr > 0 && cmplx_pwr < 500)
2679                     && ((status_1 & 0xc000) == 0x4000)) {
2680
2681                         wlc_phy_compute_dB(&cmplx_pwr, &noise_dbm,
2682                                            pi->pubpi.phy_corenum);
2683                         pwr_offset_dB = (read_phy_reg(pi, 0x434) & 0xFF);
2684                         if (pwr_offset_dB > 127)
2685                                 pwr_offset_dB -= 256;
2686
2687                         noise_dbm += (s8) (pwr_offset_dB - 30);
2688
2689                         gain_dB = (status_0 & 0x1ff);
2690                         noise_dbm -= (s8) (gain_dB);
2691                 } else {
2692                         noise_dbm = PHY_NOISE_FIXED_VAL_LCNPHY;
2693                 }
2694         } else if (ISNPHY(pi)) {
2695
2696                 jssi_aux = wlapi_bmac_read_shm(pi->sh->physhim, M_JSSI_AUX);
2697                 channel = jssi_aux & D11_CURCHANNEL_MAX;
2698
2699                 noise_dbm = wlc_phy_noise_read_shmem(pi);
2700         }
2701
2702         wlc_phy_noise_cb(pi, channel, noise_dbm);
2703
2704 }
2705
2706 s8 lcnphy_gain_index_offset_for_pkt_rssi[] = {
2707         8,
2708         8,
2709         8,
2710         8,
2711         8,
2712         8,
2713         8,
2714         9,
2715         10,
2716         8,
2717         8,
2718         7,
2719         7,
2720         1,
2721         2,
2722         2,
2723         2,
2724         2,
2725         2,
2726         2,
2727         2,
2728         2,
2729         2,
2730         2,
2731         2,
2732         2,
2733         2,
2734         2,
2735         2,
2736         2,
2737         2,
2738         2,
2739         1,
2740         1,
2741         0,
2742         0,
2743         0,
2744         0
2745 };
2746
2747 void wlc_phy_compute_dB(u32 *cmplx_pwr, s8 *p_cmplx_pwr_dB, u8 core)
2748 {
2749         u8 shift_ct, lsb, msb, secondmsb, i;
2750         u32 tmp;
2751
2752         for (i = 0; i < core; i++) {
2753                 tmp = cmplx_pwr[i];
2754                 shift_ct = msb = secondmsb = 0;
2755                 while (tmp != 0) {
2756                         tmp = tmp >> 1;
2757                         shift_ct++;
2758                         lsb = (u8) (tmp & 1);
2759                         if (lsb == 1)
2760                                 msb = shift_ct;
2761                 }
2762                 secondmsb = (u8) ((cmplx_pwr[i] >> (msb - 1)) & 1);
2763                 p_cmplx_pwr_dB[i] = (s8) (3 * msb + 2 * secondmsb);
2764         }
2765 }
2766
2767 void BCMFASTPATH wlc_phy_rssi_compute(wlc_phy_t *pih, void *ctx)
2768 {
2769         wlc_d11rxhdr_t *wlc_rxhdr = (wlc_d11rxhdr_t *) ctx;
2770         d11rxhdr_t *rxh = &wlc_rxhdr->rxhdr;
2771         int rssi = le16_to_cpu(rxh->PhyRxStatus_1) & PRXS1_JSSI_MASK;
2772         uint radioid = pih->radioid;
2773         phy_info_t *pi = (phy_info_t *) pih;
2774
2775         if (NORADIO_ENAB(pi->pubpi)) {
2776                 rssi = WLC_RSSI_INVALID;
2777                 goto end;
2778         }
2779
2780         if ((pi->sh->corerev >= 11)
2781             && !(le16_to_cpu(rxh->RxStatus2) & RXS_PHYRXST_VALID)) {
2782                 rssi = WLC_RSSI_INVALID;
2783                 goto end;
2784         }
2785
2786         if (ISLCNPHY(pi)) {
2787                 u8 gidx = (le16_to_cpu(rxh->PhyRxStatus_2) & 0xFC00) >> 10;
2788                 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
2789
2790                 if (rssi > 127)
2791                         rssi -= 256;
2792
2793                 rssi = rssi + lcnphy_gain_index_offset_for_pkt_rssi[gidx];
2794                 if ((rssi > -46) && (gidx > 18))
2795                         rssi = rssi + 7;
2796
2797                 rssi = rssi + pi_lcn->lcnphy_pkteng_rssi_slope;
2798
2799                 rssi = rssi + 2;
2800
2801         }
2802
2803         if (ISLCNPHY(pi)) {
2804
2805                 if (rssi > 127)
2806                         rssi -= 256;
2807         } else if (radioid == BCM2055_ID || radioid == BCM2056_ID
2808                    || radioid == BCM2057_ID) {
2809                 rssi = wlc_phy_rssi_compute_nphy(pi, wlc_rxhdr);
2810         }
2811
2812  end:
2813         wlc_rxhdr->rssi = (s8) rssi;
2814 }
2815
2816 void wlc_phy_freqtrack_start(wlc_phy_t *pih)
2817 {
2818         return;
2819 }
2820
2821 void wlc_phy_freqtrack_end(wlc_phy_t *pih)
2822 {
2823         return;
2824 }
2825
2826 void wlc_phy_set_deaf(wlc_phy_t *ppi, bool user_flag)
2827 {
2828         phy_info_t *pi;
2829         pi = (phy_info_t *) ppi;
2830
2831         if (ISLCNPHY(pi))
2832                 wlc_lcnphy_deaf_mode(pi, true);
2833         else if (ISNPHY(pi))
2834                 wlc_nphy_deaf_mode(pi, true);
2835 }
2836
2837 void wlc_phy_watchdog(wlc_phy_t *pih)
2838 {
2839         phy_info_t *pi = (phy_info_t *) pih;
2840         bool delay_phy_cal = false;
2841         pi->sh->now++;
2842
2843         if (!pi->watchdog_override)
2844                 return;
2845
2846         if (!(SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi))) {
2847                 wlc_phy_noise_sample_request((wlc_phy_t *) pi,
2848                                              PHY_NOISE_SAMPLE_MON,
2849                                              CHSPEC_CHANNEL(pi->
2850                                                             radio_chanspec));
2851         }
2852
2853         if (pi->phynoise_state && (pi->sh->now - pi->phynoise_now) > 5) {
2854                 pi->phynoise_state = 0;
2855         }
2856
2857         if ((!pi->phycal_txpower) ||
2858             ((pi->sh->now - pi->phycal_txpower) >= pi->sh->fast_timer)) {
2859
2860                 if (!SCAN_INPROG_PHY(pi) && wlc_phy_cal_txpower_recalc_sw(pi)) {
2861                         pi->phycal_txpower = pi->sh->now;
2862                 }
2863         }
2864
2865         if (NORADIO_ENAB(pi->pubpi))
2866                 return;
2867
2868         if ((SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi)
2869              || ASSOC_INPROG_PHY(pi)))
2870                 return;
2871
2872         if (ISNPHY(pi) && !pi->disable_percal && !delay_phy_cal) {
2873
2874                 if ((pi->nphy_perical != PHY_PERICAL_DISABLE) &&
2875                     (pi->nphy_perical != PHY_PERICAL_MANUAL) &&
2876                     ((pi->sh->now - pi->nphy_perical_last) >=
2877                      pi->sh->glacial_timer))
2878                         wlc_phy_cal_perical((wlc_phy_t *) pi,
2879                                             PHY_PERICAL_WATCHDOG);
2880
2881                 wlc_phy_txpwr_papd_cal_nphy(pi);
2882         }
2883
2884         if (ISLCNPHY(pi)) {
2885                 if (pi->phy_forcecal ||
2886                     ((pi->sh->now - pi->phy_lastcal) >=
2887                      pi->sh->glacial_timer)) {
2888                         if (!(SCAN_RM_IN_PROGRESS(pi) || ASSOC_INPROG_PHY(pi)))
2889                                 wlc_lcnphy_calib_modes(pi,
2890                                                        LCNPHY_PERICAL_TEMPBASED_TXPWRCTRL);
2891                         if (!
2892                             (SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi)
2893                              || ASSOC_INPROG_PHY(pi)
2894                              || pi->carrier_suppr_disable
2895                              || pi->disable_percal))
2896                                 wlc_lcnphy_calib_modes(pi,
2897                                                        PHY_PERICAL_WATCHDOG);
2898                 }
2899         }
2900 }
2901
2902 void wlc_phy_BSSinit(wlc_phy_t *pih, bool bonlyap, int rssi)
2903 {
2904         phy_info_t *pi = (phy_info_t *) pih;
2905         uint i;
2906         uint k;
2907
2908         for (i = 0; i < MA_WINDOW_SZ; i++) {
2909                 pi->sh->phy_noise_window[i] = (s8) (rssi & 0xff);
2910         }
2911         if (ISLCNPHY(pi)) {
2912                 for (i = 0; i < MA_WINDOW_SZ; i++)
2913                         pi->sh->phy_noise_window[i] =
2914                             PHY_NOISE_FIXED_VAL_LCNPHY;
2915         }
2916         pi->sh->phy_noise_index = 0;
2917
2918         for (i = 0; i < PHY_NOISE_WINDOW_SZ; i++) {
2919                 for (k = WL_ANT_IDX_1; k < WL_ANT_RX_MAX; k++)
2920                         pi->nphy_noise_win[k][i] = PHY_NOISE_FIXED_VAL_NPHY;
2921         }
2922         pi->nphy_noise_index = 0;
2923 }
2924
2925 void
2926 wlc_phy_papd_decode_epsilon(u32 epsilon, s32 *eps_real, s32 *eps_imag)
2927 {
2928         *eps_imag = (epsilon >> 13);
2929         if (*eps_imag > 0xfff)
2930                 *eps_imag -= 0x2000;
2931
2932         *eps_real = (epsilon & 0x1fff);
2933         if (*eps_real > 0xfff)
2934                 *eps_real -= 0x2000;
2935 }
2936
2937 static const fixed AtanTbl[] = {
2938         2949120,
2939         1740967,
2940         919879,
2941         466945,
2942         234379,
2943         117304,
2944         58666,
2945         29335,
2946         14668,
2947         7334,
2948         3667,
2949         1833,
2950         917,
2951         458,
2952         229,
2953         115,
2954         57,
2955         29
2956 };
2957
2958 void wlc_phy_cordic(fixed theta, cs32 *val)
2959 {
2960         fixed angle, valtmp;
2961         unsigned iter;
2962         int signx = 1;
2963         int signtheta;
2964
2965         val[0].i = CORDIC_AG;
2966         val[0].q = 0;
2967         angle = 0;
2968
2969         signtheta = (theta < 0) ? -1 : 1;
2970         theta =
2971             ((theta + FIXED(180) * signtheta) % FIXED(360)) -
2972             FIXED(180) * signtheta;
2973
2974         if (FLOAT(theta) > 90) {
2975                 theta -= FIXED(180);
2976                 signx = -1;
2977         } else if (FLOAT(theta) < -90) {
2978                 theta += FIXED(180);
2979                 signx = -1;
2980         }
2981
2982         for (iter = 0; iter < CORDIC_NI; iter++) {
2983                 if (theta > angle) {
2984                         valtmp = val[0].i - (val[0].q >> iter);
2985                         val[0].q = (val[0].i >> iter) + val[0].q;
2986                         val[0].i = valtmp;
2987                         angle += AtanTbl[iter];
2988                 } else {
2989                         valtmp = val[0].i + (val[0].q >> iter);
2990                         val[0].q = -(val[0].i >> iter) + val[0].q;
2991                         val[0].i = valtmp;
2992                         angle -= AtanTbl[iter];
2993                 }
2994         }
2995
2996         val[0].i = val[0].i * signx;
2997         val[0].q = val[0].q * signx;
2998 }
2999
3000 void wlc_phy_cal_perical_mphase_reset(phy_info_t *pi)
3001 {
3002         wlapi_del_timer(pi->sh->physhim, pi->phycal_timer);
3003
3004         pi->cal_type_override = PHY_PERICAL_AUTO;
3005         pi->mphase_cal_phase_id = MPHASE_CAL_STATE_IDLE;
3006         pi->mphase_txcal_cmdidx = 0;
3007 }
3008
3009 static void wlc_phy_cal_perical_mphase_schedule(phy_info_t *pi, uint delay)
3010 {
3011
3012         if ((pi->nphy_perical != PHY_PERICAL_MPHASE) &&
3013             (pi->nphy_perical != PHY_PERICAL_MANUAL))
3014                 return;
3015
3016         wlapi_del_timer(pi->sh->physhim, pi->phycal_timer);
3017
3018         pi->mphase_cal_phase_id = MPHASE_CAL_STATE_INIT;
3019         wlapi_add_timer(pi->sh->physhim, pi->phycal_timer, delay, 0);
3020 }
3021
3022 void wlc_phy_cal_perical(wlc_phy_t *pih, u8 reason)
3023 {
3024         s16 nphy_currtemp = 0;
3025         s16 delta_temp = 0;
3026         bool do_periodic_cal = true;
3027         phy_info_t *pi = (phy_info_t *) pih;
3028
3029         if (!ISNPHY(pi))
3030                 return;
3031
3032         if ((pi->nphy_perical == PHY_PERICAL_DISABLE) ||
3033             (pi->nphy_perical == PHY_PERICAL_MANUAL))
3034                 return;
3035
3036         switch (reason) {
3037         case PHY_PERICAL_DRIVERUP:
3038                 break;
3039
3040         case PHY_PERICAL_PHYINIT:
3041                 if (pi->nphy_perical == PHY_PERICAL_MPHASE) {
3042                         if (PHY_PERICAL_MPHASE_PENDING(pi)) {
3043                                 wlc_phy_cal_perical_mphase_reset(pi);
3044                         }
3045                         wlc_phy_cal_perical_mphase_schedule(pi,
3046                                                             PHY_PERICAL_INIT_DELAY);
3047                 }
3048                 break;
3049
3050         case PHY_PERICAL_JOIN_BSS:
3051         case PHY_PERICAL_START_IBSS:
3052         case PHY_PERICAL_UP_BSS:
3053                 if ((pi->nphy_perical == PHY_PERICAL_MPHASE) &&
3054                     PHY_PERICAL_MPHASE_PENDING(pi)) {
3055                         wlc_phy_cal_perical_mphase_reset(pi);
3056                 }
3057
3058                 pi->first_cal_after_assoc = true;
3059
3060                 pi->cal_type_override = PHY_PERICAL_FULL;
3061
3062                 if (pi->phycal_tempdelta) {
3063                         pi->nphy_lastcal_temp = wlc_phy_tempsense_nphy(pi);
3064                 }
3065                 wlc_phy_cal_perical_nphy_run(pi, PHY_PERICAL_FULL);
3066                 break;
3067
3068         case PHY_PERICAL_WATCHDOG:
3069                 if (pi->phycal_tempdelta) {
3070                         nphy_currtemp = wlc_phy_tempsense_nphy(pi);
3071                         delta_temp =
3072                             (nphy_currtemp > pi->nphy_lastcal_temp) ?
3073                             nphy_currtemp - pi->nphy_lastcal_temp :
3074                             pi->nphy_lastcal_temp - nphy_currtemp;
3075
3076                         if ((delta_temp < (s16) pi->phycal_tempdelta) &&
3077                             (pi->nphy_txiqlocal_chanspec ==
3078                              pi->radio_chanspec)) {
3079                                 do_periodic_cal = false;
3080                         } else {
3081                                 pi->nphy_lastcal_temp = nphy_currtemp;
3082                         }
3083                 }
3084
3085                 if (do_periodic_cal) {
3086
3087                         if (pi->nphy_perical == PHY_PERICAL_MPHASE) {
3088
3089                                 if (!PHY_PERICAL_MPHASE_PENDING(pi))
3090                                         wlc_phy_cal_perical_mphase_schedule(pi,
3091                                                                             PHY_PERICAL_WDOG_DELAY);
3092                         } else if (pi->nphy_perical == PHY_PERICAL_SPHASE)
3093                                 wlc_phy_cal_perical_nphy_run(pi,
3094                                                              PHY_PERICAL_AUTO);
3095                 }
3096                 break;
3097         default:
3098                 break;
3099         }
3100 }
3101
3102 void wlc_phy_cal_perical_mphase_restart(phy_info_t *pi)
3103 {
3104         pi->mphase_cal_phase_id = MPHASE_CAL_STATE_INIT;
3105         pi->mphase_txcal_cmdidx = 0;
3106 }
3107
3108 u8 wlc_phy_nbits(s32 value)
3109 {
3110         s32 abs_val;
3111         u8 nbits = 0;
3112
3113         abs_val = ABS(value);
3114         while ((abs_val >> nbits) > 0)
3115                 nbits++;
3116
3117         return nbits;
3118 }
3119
3120 void wlc_phy_stf_chain_init(wlc_phy_t *pih, u8 txchain, u8 rxchain)
3121 {
3122         phy_info_t *pi = (phy_info_t *) pih;
3123
3124         pi->sh->hw_phytxchain = txchain;
3125         pi->sh->hw_phyrxchain = rxchain;
3126         pi->sh->phytxchain = txchain;
3127         pi->sh->phyrxchain = rxchain;
3128         pi->pubpi.phy_corenum = (u8) PHY_BITSCNT(pi->sh->phyrxchain);
3129 }
3130
3131 void wlc_phy_stf_chain_set(wlc_phy_t *pih, u8 txchain, u8 rxchain)
3132 {
3133         phy_info_t *pi = (phy_info_t *) pih;
3134
3135         pi->sh->phytxchain = txchain;
3136
3137         if (ISNPHY(pi)) {
3138                 wlc_phy_rxcore_setstate_nphy(pih, rxchain);
3139         }
3140         pi->pubpi.phy_corenum = (u8) PHY_BITSCNT(pi->sh->phyrxchain);
3141 }
3142
3143 void wlc_phy_stf_chain_get(wlc_phy_t *pih, u8 *txchain, u8 *rxchain)
3144 {
3145         phy_info_t *pi = (phy_info_t *) pih;
3146
3147         *txchain = pi->sh->phytxchain;
3148         *rxchain = pi->sh->phyrxchain;
3149 }
3150
3151 u8 wlc_phy_stf_chain_active_get(wlc_phy_t *pih)
3152 {
3153         s16 nphy_currtemp;
3154         u8 active_bitmap;
3155         phy_info_t *pi = (phy_info_t *) pih;
3156
3157         active_bitmap = (pi->phy_txcore_heatedup) ? 0x31 : 0x33;
3158
3159         if (!pi->watchdog_override)
3160                 return active_bitmap;
3161
3162         if (NREV_GE(pi->pubpi.phy_rev, 6)) {
3163                 wlapi_suspend_mac_and_wait(pi->sh->physhim);
3164                 nphy_currtemp = wlc_phy_tempsense_nphy(pi);
3165                 wlapi_enable_mac(pi->sh->physhim);
3166
3167                 if (!pi->phy_txcore_heatedup) {
3168                         if (nphy_currtemp >= pi->phy_txcore_disable_temp) {
3169                                 active_bitmap &= 0xFD;
3170                                 pi->phy_txcore_heatedup = true;
3171                         }
3172                 } else {
3173                         if (nphy_currtemp <= pi->phy_txcore_enable_temp) {
3174                                 active_bitmap |= 0x2;
3175                                 pi->phy_txcore_heatedup = false;
3176                         }
3177                 }
3178         }
3179
3180         return active_bitmap;
3181 }
3182
3183 s8 wlc_phy_stf_ssmode_get(wlc_phy_t *pih, chanspec_t chanspec)
3184 {
3185         phy_info_t *pi = (phy_info_t *) pih;
3186         u8 siso_mcs_id, cdd_mcs_id;
3187
3188         siso_mcs_id =
3189             (CHSPEC_IS40(chanspec)) ? TXP_FIRST_MCS_40_SISO :
3190             TXP_FIRST_MCS_20_SISO;
3191         cdd_mcs_id =
3192             (CHSPEC_IS40(chanspec)) ? TXP_FIRST_MCS_40_CDD :
3193             TXP_FIRST_MCS_20_CDD;
3194
3195         if (pi->tx_power_target[siso_mcs_id] >
3196             (pi->tx_power_target[cdd_mcs_id] + 12))
3197                 return PHY_TXC1_MODE_SISO;
3198         else
3199                 return PHY_TXC1_MODE_CDD;
3200 }
3201
3202 const u8 *wlc_phy_get_ofdm_rate_lookup(void)
3203 {
3204         return ofdm_rate_lookup;
3205 }
3206
3207 void wlc_lcnphy_epa_switch(phy_info_t *pi, bool mode)
3208 {
3209         if ((pi->sh->chip == BCM4313_CHIP_ID) &&
3210             (pi->sh->boardflags & BFL_FEM)) {
3211                 if (mode) {
3212                         u16 txant = 0;
3213                         txant = wlapi_bmac_get_txant(pi->sh->physhim);
3214                         if (txant == 1) {
3215                                 mod_phy_reg(pi, 0x44d, (0x1 << 2), (1) << 2);
3216
3217                                 mod_phy_reg(pi, 0x44c, (0x1 << 2), (1) << 2);
3218
3219                         }
3220                         ai_corereg(pi->sh->sih, SI_CC_IDX,
3221                                    offsetof(chipcregs_t, gpiocontrol), ~0x0,
3222                                    0x0);
3223                         ai_corereg(pi->sh->sih, SI_CC_IDX,
3224                                    offsetof(chipcregs_t, gpioout), 0x40, 0x40);
3225                         ai_corereg(pi->sh->sih, SI_CC_IDX,
3226                                    offsetof(chipcregs_t, gpioouten), 0x40,
3227                                    0x40);
3228                 } else {
3229                         mod_phy_reg(pi, 0x44c, (0x1 << 2), (0) << 2);
3230
3231                         mod_phy_reg(pi, 0x44d, (0x1 << 2), (0) << 2);
3232
3233                         ai_corereg(pi->sh->sih, SI_CC_IDX,
3234                                    offsetof(chipcregs_t, gpioout), 0x40, 0x00);
3235                         ai_corereg(pi->sh->sih, SI_CC_IDX,
3236                                    offsetof(chipcregs_t, gpioouten), 0x40, 0x0);
3237                         ai_corereg(pi->sh->sih, SI_CC_IDX,
3238                                    offsetof(chipcregs_t, gpiocontrol), ~0x0,
3239                                    0x40);
3240                 }
3241         }
3242 }
3243
3244 static s8
3245 wlc_user_txpwr_antport_to_rfport(phy_info_t *pi, uint chan, u32 band,
3246                                  u8 rate)
3247 {
3248         s8 offset = 0;
3249
3250         if (!pi->user_txpwr_at_rfport)
3251                 return offset;
3252         return offset;
3253 }
3254
3255 static s8 wlc_phy_env_measure_vbat(phy_info_t *pi)
3256 {
3257         if (ISLCNPHY(pi))
3258                 return wlc_lcnphy_vbatsense(pi, 0);
3259         else
3260                 return 0;
3261 }
3262
3263 static s8 wlc_phy_env_measure_temperature(phy_info_t *pi)
3264 {
3265         if (ISLCNPHY(pi))
3266                 return wlc_lcnphy_tempsense_degree(pi, 0);
3267         else
3268                 return 0;
3269 }
3270
3271 static void wlc_phy_upd_env_txpwr_rate_limits(phy_info_t *pi, u32 band)
3272 {
3273         u8 i;
3274         s8 temp, vbat;
3275
3276         for (i = 0; i < TXP_NUM_RATES; i++)
3277                 pi->txpwr_env_limit[i] = WLC_TXPWR_MAX;
3278
3279         vbat = wlc_phy_env_measure_vbat(pi);
3280         temp = wlc_phy_env_measure_temperature(pi);
3281
3282 }
3283
3284 void wlc_phy_ldpc_override_set(wlc_phy_t *ppi, bool ldpc)
3285 {
3286         return;
3287 }
3288
3289 void
3290 wlc_phy_get_pwrdet_offsets(phy_info_t *pi, s8 *cckoffset, s8 *ofdmoffset)
3291 {
3292         *cckoffset = 0;
3293         *ofdmoffset = 0;
3294 }
3295
3296 s8 wlc_phy_upd_rssi_offset(phy_info_t *pi, s8 rssi, chanspec_t chanspec)
3297 {
3298
3299         return rssi;
3300 }
3301
3302 bool wlc_phy_txpower_ipa_ison(wlc_phy_t *ppi)
3303 {
3304         phy_info_t *pi = (phy_info_t *) ppi;
3305
3306         if (ISNPHY(pi))
3307                 return wlc_phy_n_txpower_ipa_ison(pi);
3308         else
3309                 return 0;
3310 }