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