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