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