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