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