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