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