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