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