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