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