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