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