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