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