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