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