blob: 6ea4df64d18e9d5751a87905e9a654239df9f539 [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
Andy Shevchenko48c51a82010-09-15 12:47:18 +030019#include <linux/kernel.h>
Brett Rudley33279892010-10-01 18:03:27 -070020#include <linux/string.h>
Greg Kroah-Hartmana1c16ed2010-10-21 11:17:44 -070021#include <bcmdefs.h>
22#include <osl.h>
Brett Rudleyc6ac24e2010-10-26 11:55:23 -070023#include <linux/module.h>
24#include <linux/pci.h>
Henry Ptasinskia9533e72010-09-08 21:04:42 -070025#include <bcmendian.h>
26#include <bcmnvram.h>
27#include <sbchipc.h>
Brett Rudleya52ba662010-10-26 09:17:06 -070028#include <bcmdevs.h>
29#include <sbhndpio.h>
30#include <sbhnddma.h>
Henry Ptasinskia9533e72010-09-08 21:04:42 -070031
32#include <wlc_phy_int.h>
33#include <wlc_phyreg_n.h>
34#include <wlc_phy_radio.h>
35#include <wlc_phy_lcn.h>
36
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -070037u32 phyhal_msg_level = PHYHAL_ERROR;
Henry Ptasinskia9533e72010-09-08 21:04:42 -070038
39typedef struct _chan_info_basic {
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -070040 u16 chan;
41 u16 freq;
Henry Ptasinskia9533e72010-09-08 21:04:42 -070042} chan_info_basic_t;
43
44static chan_info_basic_t chan_info_all[] = {
45
46 {1, 2412},
47 {2, 2417},
48 {3, 2422},
49 {4, 2427},
50 {5, 2432},
51 {6, 2437},
52 {7, 2442},
53 {8, 2447},
54 {9, 2452},
55 {10, 2457},
56 {11, 2462},
57 {12, 2467},
58 {13, 2472},
59 {14, 2484},
60
61 {34, 5170},
62 {38, 5190},
63 {42, 5210},
64 {46, 5230},
65
66 {36, 5180},
67 {40, 5200},
68 {44, 5220},
69 {48, 5240},
70 {52, 5260},
71 {56, 5280},
72 {60, 5300},
73 {64, 5320},
74
75 {100, 5500},
76 {104, 5520},
77 {108, 5540},
78 {112, 5560},
79 {116, 5580},
80 {120, 5600},
81 {124, 5620},
82 {128, 5640},
83 {132, 5660},
84 {136, 5680},
85 {140, 5700},
86
87 {149, 5745},
88 {153, 5765},
89 {157, 5785},
90 {161, 5805},
91 {165, 5825},
92
93 {184, 4920},
94 {188, 4940},
95 {192, 4960},
96 {196, 4980},
97 {200, 5000},
98 {204, 5020},
99 {208, 5040},
100 {212, 5060},
101 {216, 50800}
102};
103
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -0700104u16 ltrn_list[PHY_LTRN_LIST_LEN] = {
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700105 0x18f9, 0x0d01, 0x00e4, 0xdef4, 0x06f1, 0x0ffc,
106 0xfa27, 0x1dff, 0x10f0, 0x0918, 0xf20a, 0xe010,
107 0x1417, 0x1104, 0xf114, 0xf2fa, 0xf7db, 0xe2fc,
108 0xe1fb, 0x13ee, 0xff0d, 0xe91c, 0x171a, 0x0318,
109 0xda00, 0x03e8, 0x17e6, 0xe9e4, 0xfff3, 0x1312,
110 0xe105, 0xe204, 0xf725, 0xf206, 0xf1ec, 0x11fc,
111 0x14e9, 0xe0f0, 0xf2f6, 0x09e8, 0x1010, 0x1d01,
112 0xfad9, 0x0f04, 0x060f, 0xde0c, 0x001c, 0x0dff,
113 0x1807, 0xf61a, 0xe40e, 0x0f16, 0x05f9, 0x18ec,
114 0x0a1b, 0xff1e, 0x2600, 0xffe2, 0x0ae5, 0x1814,
115 0x0507, 0x0fea, 0xe4f2, 0xf6e6
116};
117
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -0700118const u8 ofdm_rate_lookup[] = {
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700119
120 WLC_RATE_48M,
121 WLC_RATE_24M,
122 WLC_RATE_12M,
123 WLC_RATE_6M,
124 WLC_RATE_54M,
125 WLC_RATE_36M,
126 WLC_RATE_18M,
127 WLC_RATE_9M
128};
129
130#define PHY_WREG_LIMIT 24
131
Jason Cooper7cc4a4c2010-09-14 09:45:30 -0400132static void wlc_set_phy_uninitted(phy_info_t *pi);
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -0700133static u32 wlc_phy_get_radio_ver(phy_info_t *pi);
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700134static void wlc_phy_timercb_phycal(void *arg);
135
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -0700136static bool wlc_phy_noise_calc_phy(phy_info_t *pi, u32 *cmplx_pwr,
Greg Kroah-Hartman562c8852010-10-05 11:04:17 -0700137 s8 *pwr_ant);
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700138
Jason Cooper7cc4a4c2010-09-14 09:45:30 -0400139static void wlc_phy_cal_perical_mphase_schedule(phy_info_t *pi, uint delay);
Greg Kroah-Hartman562c8852010-10-05 11:04:17 -0700140static void wlc_phy_noise_cb(phy_info_t *pi, u8 channel, s8 noise_dbm);
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -0700141static void wlc_phy_noise_sample_request(wlc_phy_t *pih, u8 reason,
142 u8 ch);
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700143
Jason Cooper7cc4a4c2010-09-14 09:45:30 -0400144static void wlc_phy_txpower_reg_limit_calc(phy_info_t *pi,
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700145 struct txpwr_limits *tp, chanspec_t);
Jason Cooper7cc4a4c2010-09-14 09:45:30 -0400146static bool wlc_phy_cal_txpower_recalc_sw(phy_info_t *pi);
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700147
Greg Kroah-Hartman562c8852010-10-05 11:04:17 -0700148static s8 wlc_user_txpwr_antport_to_rfport(phy_info_t *pi, uint chan,
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -0700149 u32 band, u8 rate);
150static void wlc_phy_upd_env_txpwr_rate_limits(phy_info_t *pi, u32 band);
Greg Kroah-Hartman562c8852010-10-05 11:04:17 -0700151static s8 wlc_phy_env_measure_vbat(phy_info_t *pi);
152static s8 wlc_phy_env_measure_temperature(phy_info_t *pi);
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700153
Jason Cooper7cc4a4c2010-09-14 09:45:30 -0400154char *phy_getvar(phy_info_t *pi, const char *name)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700155{
156 char *vars = pi->vars;
157 char *s;
158 int len;
159
160 ASSERT(pi->vars != (char *)&pi->vars);
161
162 if (!name)
163 return NULL;
164
165 len = strlen(name);
166 if (len == 0)
167 return NULL;
168
169 for (s = vars; s && *s;) {
170 if ((bcmp(s, name, len) == 0) && (s[len] == '='))
Jason Cooper90ea2292010-09-14 09:45:32 -0400171 return &s[len + 1];
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700172
Jason Cooper62145822010-09-14 09:45:34 -0400173 while (*s++)
174 ;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700175 }
176
Jason Cooper90ea2292010-09-14 09:45:32 -0400177 return nvram_get(name);
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700178}
179
Jason Cooper7cc4a4c2010-09-14 09:45:30 -0400180int phy_getintvar(phy_info_t *pi, const char *name)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700181{
182 char *val;
183
Jason Cooperca8c1e52010-09-14 09:45:33 -0400184 val = PHY_GETVAR(pi, name);
185 if (val == NULL)
Jason Cooper90ea2292010-09-14 09:45:32 -0400186 return 0;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700187
Andy Shevchenko48c51a82010-09-15 12:47:18 +0300188 return simple_strtoul(val, NULL, 0);
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700189}
190
Jason Cooper7cc4a4c2010-09-14 09:45:30 -0400191void wlc_phyreg_enter(wlc_phy_t *pih)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700192{
193 phy_info_t *pi = (phy_info_t *) pih;
194 wlapi_bmac_ucode_wake_override_phyreg_set(pi->sh->physhim);
195}
196
Jason Cooper7cc4a4c2010-09-14 09:45:30 -0400197void wlc_phyreg_exit(wlc_phy_t *pih)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700198{
199 phy_info_t *pi = (phy_info_t *) pih;
200 wlapi_bmac_ucode_wake_override_phyreg_clear(pi->sh->physhim);
201}
202
Jason Cooper7cc4a4c2010-09-14 09:45:30 -0400203void wlc_radioreg_enter(wlc_phy_t *pih)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700204{
205 phy_info_t *pi = (phy_info_t *) pih;
206 wlapi_bmac_mctrl(pi->sh->physhim, MCTL_LOCK_RADIO, MCTL_LOCK_RADIO);
207
mike.rapoport@gmail.com73831412010-10-13 00:09:07 +0200208 udelay(10);
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700209}
210
Jason Cooper7cc4a4c2010-09-14 09:45:30 -0400211void wlc_radioreg_exit(wlc_phy_t *pih)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700212{
213 phy_info_t *pi = (phy_info_t *) pih;
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -0700214 volatile u16 dummy;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700215
216 dummy = R_REG(pi->sh->osh, &pi->regs->phyversion);
217 pi->phy_wreg = 0;
218 wlapi_bmac_mctrl(pi->sh->physhim, MCTL_LOCK_RADIO, 0);
219}
220
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -0700221u16 read_radio_reg(phy_info_t *pi, u16 addr)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700222{
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -0700223 u16 data;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700224
225 if ((addr == RADIO_IDCODE))
226 return 0xffff;
227
228 if (NORADIO_ENAB(pi->pubpi))
Jason Cooper90ea2292010-09-14 09:45:32 -0400229 return NORADIO_IDCODE & 0xffff;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700230
231 switch (pi->pubpi.phy_type) {
232 case PHY_TYPE_N:
233 CASECHECK(PHYTYPE, PHY_TYPE_N);
234 if (NREV_GE(pi->pubpi.phy_rev, 7))
235 addr |= RADIO_2057_READ_OFF;
236 else
237 addr |= RADIO_2055_READ_OFF;
238 break;
239
240 case PHY_TYPE_LCN:
241 CASECHECK(PHYTYPE, PHY_TYPE_LCN);
242 addr |= RADIO_2064_READ_OFF;
243 break;
244
245 default:
246 ASSERT(VALID_PHYTYPE(pi->pubpi.phy_type));
247 }
248
249 if ((D11REV_GE(pi->sh->corerev, 24)) ||
250 (D11REV_IS(pi->sh->corerev, 22)
251 && (pi->pubpi.phy_type != PHY_TYPE_SSN))) {
252 W_REG(pi->sh->osh, &pi->regs->radioregaddr, addr);
253#ifdef __mips__
254 (void)R_REG(pi->sh->osh, &pi->regs->radioregaddr);
255#endif
256 data = R_REG(pi->sh->osh, &pi->regs->radioregdata);
257 } else {
258 W_REG(pi->sh->osh, &pi->regs->phy4waddr, addr);
259#ifdef __mips__
260 (void)R_REG(pi->sh->osh, &pi->regs->phy4waddr);
261#endif
262
263#ifdef __ARM_ARCH_4T__
264 __asm__(" .align 4 ");
265 __asm__(" nop ");
266 data = R_REG(pi->sh->osh, &pi->regs->phy4wdatalo);
267#else
268 data = R_REG(pi->sh->osh, &pi->regs->phy4wdatalo);
269#endif
270
271 }
272 pi->phy_wreg = 0;
273
274 return data;
275}
276
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -0700277void write_radio_reg(phy_info_t *pi, u16 addr, u16 val)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700278{
Brett Rudleye69284f2010-11-16 15:45:48 -0800279 struct osl_info *osh;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700280
281 if (NORADIO_ENAB(pi->pubpi))
282 return;
283
284 osh = pi->sh->osh;
285
286 if ((D11REV_GE(pi->sh->corerev, 24)) ||
287 (D11REV_IS(pi->sh->corerev, 22)
288 && (pi->pubpi.phy_type != PHY_TYPE_SSN))) {
289
290 W_REG(osh, &pi->regs->radioregaddr, addr);
291#ifdef __mips__
292 (void)R_REG(osh, &pi->regs->radioregaddr);
293#endif
294 W_REG(osh, &pi->regs->radioregdata, val);
295 } else {
296 W_REG(osh, &pi->regs->phy4waddr, addr);
297#ifdef __mips__
298 (void)R_REG(osh, &pi->regs->phy4waddr);
299#endif
300 W_REG(osh, &pi->regs->phy4wdatalo, val);
301 }
302
Brett Rudleyfa7a1db2010-11-23 15:30:02 -0800303 if (pi->sh->bustype == PCI_BUS) {
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700304 if (++pi->phy_wreg >= pi->phy_wreg_limit) {
305 (void)R_REG(osh, &pi->regs->maccontrol);
306 pi->phy_wreg = 0;
307 }
308 }
309}
310
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -0700311static u32 read_radio_id(phy_info_t *pi)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700312{
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -0700313 u32 id;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700314
315 if (NORADIO_ENAB(pi->pubpi))
Jason Cooper90ea2292010-09-14 09:45:32 -0400316 return NORADIO_IDCODE;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700317
318 if (D11REV_GE(pi->sh->corerev, 24)) {
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -0700319 u32 b0, b1, b2;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700320
321 W_REG(pi->sh->osh, &pi->regs->radioregaddr, 0);
322#ifdef __mips__
323 (void)R_REG(pi->sh->osh, &pi->regs->radioregaddr);
324#endif
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -0700325 b0 = (u32) R_REG(pi->sh->osh, &pi->regs->radioregdata);
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700326 W_REG(pi->sh->osh, &pi->regs->radioregaddr, 1);
327#ifdef __mips__
328 (void)R_REG(pi->sh->osh, &pi->regs->radioregaddr);
329#endif
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -0700330 b1 = (u32) R_REG(pi->sh->osh, &pi->regs->radioregdata);
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700331 W_REG(pi->sh->osh, &pi->regs->radioregaddr, 2);
332#ifdef __mips__
333 (void)R_REG(pi->sh->osh, &pi->regs->radioregaddr);
334#endif
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -0700335 b2 = (u32) R_REG(pi->sh->osh, &pi->regs->radioregdata);
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700336
337 id = ((b0 & 0xf) << 28) | (((b2 << 8) | b1) << 12) | ((b0 >> 4)
338 & 0xf);
339 } else {
340 W_REG(pi->sh->osh, &pi->regs->phy4waddr, RADIO_IDCODE);
341#ifdef __mips__
342 (void)R_REG(pi->sh->osh, &pi->regs->phy4waddr);
343#endif
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -0700344 id = (u32) R_REG(pi->sh->osh, &pi->regs->phy4wdatalo);
345 id |= (u32) R_REG(pi->sh->osh, &pi->regs->phy4wdatahi) << 16;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700346 }
347 pi->phy_wreg = 0;
348 return id;
349}
350
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -0700351void and_radio_reg(phy_info_t *pi, u16 addr, u16 val)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700352{
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -0700353 u16 rval;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700354
355 if (NORADIO_ENAB(pi->pubpi))
356 return;
357
358 rval = read_radio_reg(pi, addr);
359 write_radio_reg(pi, addr, (rval & val));
360}
361
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -0700362void or_radio_reg(phy_info_t *pi, u16 addr, u16 val)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700363{
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -0700364 u16 rval;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700365
366 if (NORADIO_ENAB(pi->pubpi))
367 return;
368
369 rval = read_radio_reg(pi, addr);
370 write_radio_reg(pi, addr, (rval | val));
371}
372
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -0700373void xor_radio_reg(phy_info_t *pi, u16 addr, u16 mask)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700374{
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -0700375 u16 rval;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700376
377 if (NORADIO_ENAB(pi->pubpi))
378 return;
379
380 rval = read_radio_reg(pi, addr);
381 write_radio_reg(pi, addr, (rval ^ mask));
382}
383
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -0700384void mod_radio_reg(phy_info_t *pi, u16 addr, u16 mask, u16 val)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700385{
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -0700386 u16 rval;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700387
388 if (NORADIO_ENAB(pi->pubpi))
389 return;
390
391 rval = read_radio_reg(pi, addr);
392 write_radio_reg(pi, addr, (rval & ~mask) | (val & mask));
393}
394
Jason Cooper7cc4a4c2010-09-14 09:45:30 -0400395void write_phy_channel_reg(phy_info_t *pi, uint val)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700396{
397 W_REG(pi->sh->osh, &pi->regs->phychannel, val);
398}
399
400#if defined(BCMDBG)
Jason Cooper7cc4a4c2010-09-14 09:45:30 -0400401static bool wlc_phy_war41476(phy_info_t *pi)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700402{
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -0700403 u32 mc = R_REG(pi->sh->osh, &pi->regs->maccontrol);
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700404
405 return ((mc & MCTL_EN_MAC) == 0)
406 || ((mc & MCTL_PHYLOCK) == MCTL_PHYLOCK);
407}
408#endif
409
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -0700410u16 read_phy_reg(phy_info_t *pi, u16 addr)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700411{
Brett Rudleye69284f2010-11-16 15:45:48 -0800412 struct osl_info *osh;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700413 d11regs_t *regs;
414
415 osh = pi->sh->osh;
416 regs = pi->regs;
417
418 W_REG(osh, &regs->phyregaddr, addr);
419#ifdef __mips__
420 (void)R_REG(osh, &regs->phyregaddr);
421#endif
422
423 ASSERT(!
424 (D11REV_IS(pi->sh->corerev, 11)
425 || D11REV_IS(pi->sh->corerev, 12)) || wlc_phy_war41476(pi));
426
427 pi->phy_wreg = 0;
Jason Cooper90ea2292010-09-14 09:45:32 -0400428 return R_REG(osh, &regs->phyregdata);
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700429}
430
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -0700431void write_phy_reg(phy_info_t *pi, u16 addr, u16 val)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700432{
Brett Rudleye69284f2010-11-16 15:45:48 -0800433 struct osl_info *osh;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700434 d11regs_t *regs;
435
436 osh = pi->sh->osh;
437 regs = pi->regs;
438
439#ifdef __mips__
440 W_REG(osh, &regs->phyregaddr, addr);
441 (void)R_REG(osh, &regs->phyregaddr);
442 W_REG(osh, &regs->phyregdata, val);
443 if (addr == 0x72)
444 (void)R_REG(osh, &regs->phyregdata);
445#else
Greg Kroah-Hartman159a3b72010-10-12 13:20:00 -0700446 W_REG(osh, (volatile u32 *)(&regs->phyregaddr),
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700447 addr | (val << 16));
Brett Rudleyfa7a1db2010-11-23 15:30:02 -0800448 if (pi->sh->bustype == PCI_BUS) {
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700449 if (++pi->phy_wreg >= pi->phy_wreg_limit) {
450 pi->phy_wreg = 0;
451 (void)R_REG(osh, &regs->phyversion);
452 }
453 }
454#endif
455}
456
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -0700457void and_phy_reg(phy_info_t *pi, u16 addr, u16 val)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700458{
Brett Rudleye69284f2010-11-16 15:45:48 -0800459 struct osl_info *osh;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700460 d11regs_t *regs;
461
462 osh = pi->sh->osh;
463 regs = pi->regs;
464
465 W_REG(osh, &regs->phyregaddr, addr);
466#ifdef __mips__
467 (void)R_REG(osh, &regs->phyregaddr);
468#endif
469
470 ASSERT(!
471 (D11REV_IS(pi->sh->corerev, 11)
472 || D11REV_IS(pi->sh->corerev, 12)) || wlc_phy_war41476(pi));
473
474 W_REG(osh, &regs->phyregdata, (R_REG(osh, &regs->phyregdata) & val));
475 pi->phy_wreg = 0;
476}
477
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -0700478void or_phy_reg(phy_info_t *pi, u16 addr, u16 val)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700479{
Brett Rudleye69284f2010-11-16 15:45:48 -0800480 struct osl_info *osh;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700481 d11regs_t *regs;
482
483 osh = pi->sh->osh;
484 regs = pi->regs;
485
486 W_REG(osh, &regs->phyregaddr, addr);
487#ifdef __mips__
488 (void)R_REG(osh, &regs->phyregaddr);
489#endif
490
491 ASSERT(!
492 (D11REV_IS(pi->sh->corerev, 11)
493 || D11REV_IS(pi->sh->corerev, 12)) || wlc_phy_war41476(pi));
494
495 W_REG(osh, &regs->phyregdata, (R_REG(osh, &regs->phyregdata) | val));
496 pi->phy_wreg = 0;
497}
498
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -0700499void mod_phy_reg(phy_info_t *pi, u16 addr, u16 mask, u16 val)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700500{
Brett Rudleye69284f2010-11-16 15:45:48 -0800501 struct osl_info *osh;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700502 d11regs_t *regs;
503
504 osh = pi->sh->osh;
505 regs = pi->regs;
506
507 W_REG(osh, &regs->phyregaddr, addr);
508#ifdef __mips__
509 (void)R_REG(osh, &regs->phyregaddr);
510#endif
511
512 ASSERT(!
513 (D11REV_IS(pi->sh->corerev, 11)
514 || D11REV_IS(pi->sh->corerev, 12)) || wlc_phy_war41476(pi));
515
516 W_REG(osh, &regs->phyregdata,
517 ((R_REG(osh, &regs->phyregdata) & ~mask) | (val & mask)));
518 pi->phy_wreg = 0;
519}
520
Jason Coopera2627bc2010-09-14 09:45:31 -0400521static void WLBANDINITFN(wlc_set_phy_uninitted) (phy_info_t *pi)
522{
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700523 int i, j;
524
Greg Kroah-Hartman0965ae82010-10-12 12:50:15 -0700525 pi->initialized = false;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700526
527 pi->tx_vos = 0xffff;
528 pi->nrssi_table_delta = 0x7fffffff;
529 pi->rc_cal = 0xffff;
530 pi->mintxbias = 0xffff;
531 pi->txpwridx = -1;
532 if (ISNPHY(pi)) {
533 pi->phy_spuravoid = SPURAVOID_DISABLE;
534
535 if (NREV_GE(pi->pubpi.phy_rev, 3)
536 && NREV_LT(pi->pubpi.phy_rev, 7))
537 pi->phy_spuravoid = SPURAVOID_AUTO;
538
539 pi->nphy_papd_skip = 0;
540 pi->nphy_papd_epsilon_offset[0] = 0xf588;
541 pi->nphy_papd_epsilon_offset[1] = 0xf588;
542 pi->nphy_txpwr_idx[0] = 128;
543 pi->nphy_txpwr_idx[1] = 128;
544 pi->nphy_txpwrindex[0].index_internal = 40;
545 pi->nphy_txpwrindex[1].index_internal = 40;
546 pi->phy_pabias = 0;
547 } else {
548 pi->phy_spuravoid = SPURAVOID_AUTO;
549 }
550 pi->radiopwr = 0xffff;
551 for (i = 0; i < STATIC_NUM_RF; i++) {
552 for (j = 0; j < STATIC_NUM_BB; j++) {
553 pi->stats_11b_txpower[i][j] = -1;
554 }
555 }
556}
557
Greg Kroah-Hartman0d2f0722010-10-08 14:28:21 -0700558shared_phy_t *wlc_phy_shared_attach(shared_phy_params_t *shp)
Jason Coopera2627bc2010-09-14 09:45:31 -0400559{
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700560 shared_phy_t *sh;
561
mike.rapoport@gmail.com5fcc1fc2010-10-13 00:09:10 +0200562 sh = kzalloc(sizeof(shared_phy_t), GFP_ATOMIC);
Jason Cooperca8c1e52010-09-14 09:45:33 -0400563 if (sh == NULL) {
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700564 return NULL;
565 }
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700566
567 sh->osh = shp->osh;
568 sh->sih = shp->sih;
569 sh->physhim = shp->physhim;
570 sh->unit = shp->unit;
571 sh->corerev = shp->corerev;
572
573 sh->vid = shp->vid;
574 sh->did = shp->did;
575 sh->chip = shp->chip;
576 sh->chiprev = shp->chiprev;
577 sh->chippkg = shp->chippkg;
578 sh->sromrev = shp->sromrev;
579 sh->boardtype = shp->boardtype;
580 sh->boardrev = shp->boardrev;
581 sh->boardvendor = shp->boardvendor;
582 sh->boardflags = shp->boardflags;
583 sh->boardflags2 = shp->boardflags2;
584 sh->bustype = shp->bustype;
585 sh->buscorerev = shp->buscorerev;
586
587 sh->fast_timer = PHY_SW_TIMER_FAST;
588 sh->slow_timer = PHY_SW_TIMER_SLOW;
589 sh->glacial_timer = PHY_SW_TIMER_GLACIAL;
590
591 sh->rssi_mode = RSSI_ANT_MERGE_MAX;
592
593 return sh;
594}
595
Greg Kroah-Hartman0d2f0722010-10-08 14:28:21 -0700596void wlc_phy_shared_detach(shared_phy_t *phy_sh)
Jason Coopera2627bc2010-09-14 09:45:31 -0400597{
Brett Rudleye69284f2010-11-16 15:45:48 -0800598 struct osl_info *osh;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700599
600 if (phy_sh) {
601 osh = phy_sh->osh;
602
603 if (phy_sh->phy_head) {
604 ASSERT(!phy_sh->phy_head);
605 }
mike.rapoport@gmail.com182acb32010-10-13 00:09:12 +0200606 kfree(phy_sh);
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700607 }
608}
609
Greg Kroah-Hartman0d2f0722010-10-08 14:28:21 -0700610wlc_phy_t *wlc_phy_attach(shared_phy_t *sh, void *regs, int bandtype, char *vars)
611{
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700612 phy_info_t *pi;
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -0700613 u32 sflags = 0;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700614 uint phyversion;
615 int i;
Brett Rudleye69284f2010-11-16 15:45:48 -0800616 struct osl_info *osh;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700617
618 osh = sh->osh;
619
620 if (D11REV_IS(sh->corerev, 4))
621 sflags = SISF_2G_PHY | SISF_5G_PHY;
622 else
623 sflags = si_core_sflags(sh->sih, 0, 0);
624
625 if (BAND_5G(bandtype)) {
626 if ((sflags & (SISF_5G_PHY | SISF_DB_PHY)) == 0) {
627 return NULL;
628 }
629 }
630
Jason Cooperca8c1e52010-09-14 09:45:33 -0400631 pi = sh->phy_head;
632 if ((sflags & SISF_DB_PHY) && pi) {
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700633
634 wlapi_bmac_corereset(pi->sh->physhim, pi->pubpi.coreflags);
635 pi->refcnt++;
636 return &pi->pubpi_ro;
637 }
638
mike.rapoport@gmail.com5fcc1fc2010-10-13 00:09:10 +0200639 pi = kzalloc(sizeof(phy_info_t), GFP_ATOMIC);
Jason Cooperca8c1e52010-09-14 09:45:33 -0400640 if (pi == NULL) {
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700641 return NULL;
642 }
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700643 pi->regs = (d11regs_t *) regs;
644 pi->sh = sh;
Greg Kroah-Hartman0f0881b2010-10-12 12:15:18 -0700645 pi->phy_init_por = true;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700646 pi->phy_wreg_limit = PHY_WREG_LIMIT;
647
648 pi->vars = vars;
649
650 pi->txpwr_percent = 100;
651
Greg Kroah-Hartman0f0881b2010-10-12 12:15:18 -0700652 pi->do_initcal = true;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700653
654 pi->phycal_tempdelta = 0;
655
656 if (BAND_2G(bandtype) && (sflags & SISF_2G_PHY)) {
657
658 pi->pubpi.coreflags = SICF_GMODE;
659 }
660
661 wlapi_bmac_corereset(pi->sh->physhim, pi->pubpi.coreflags);
662 phyversion = R_REG(osh, &pi->regs->phyversion);
663
664 pi->pubpi.phy_type = PHY_TYPE(phyversion);
665 pi->pubpi.phy_rev = phyversion & PV_PV_MASK;
666
667 if (pi->pubpi.phy_type == PHY_TYPE_LCNXN) {
668 pi->pubpi.phy_type = PHY_TYPE_N;
669 pi->pubpi.phy_rev += LCNXN_BASEREV;
670 }
671 pi->pubpi.phy_corenum = PHY_CORE_NUM_2;
672 pi->pubpi.ana_rev = (phyversion & PV_AV_MASK) >> PV_AV_SHIFT;
673
674 if (!VALID_PHYTYPE(pi->pubpi.phy_type)) {
675 goto err;
676 }
677 if (BAND_5G(bandtype)) {
678 if (!ISNPHY(pi)) {
679 goto err;
680 }
681 } else {
682 if (!ISNPHY(pi) && !ISLCNPHY(pi)) {
683 goto err;
684 }
685 }
686
687 if (ISSIM_ENAB(pi->sh->sih)) {
688 pi->pubpi.radioid = NORADIO_ID;
689 pi->pubpi.radiorev = 5;
690 } else {
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -0700691 u32 idcode;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700692
693 wlc_phy_anacore((wlc_phy_t *) pi, ON);
694
695 idcode = wlc_phy_get_radio_ver(pi);
696 pi->pubpi.radioid =
697 (idcode & IDCODE_ID_MASK) >> IDCODE_ID_SHIFT;
698 pi->pubpi.radiorev =
699 (idcode & IDCODE_REV_MASK) >> IDCODE_REV_SHIFT;
700 pi->pubpi.radiover =
701 (idcode & IDCODE_VER_MASK) >> IDCODE_VER_SHIFT;
702 if (!VALID_RADIO(pi, pi->pubpi.radioid)) {
703 goto err;
704 }
705
706 wlc_phy_switch_radio((wlc_phy_t *) pi, OFF);
707 }
708
709 wlc_set_phy_uninitted(pi);
710
711 pi->bw = WL_CHANSPEC_BW_20;
712 pi->radio_chanspec =
713 BAND_2G(bandtype) ? CH20MHZ_CHSPEC(1) : CH20MHZ_CHSPEC(36);
714
715 pi->rxiq_samps = PHY_NOISE_SAMPLE_LOG_NUM_NPHY;
716 pi->rxiq_antsel = ANT_RX_DIV_DEF;
717
Greg Kroah-Hartman0f0881b2010-10-12 12:15:18 -0700718 pi->watchdog_override = true;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700719
720 pi->cal_type_override = PHY_PERICAL_AUTO;
721
722 pi->nphy_saved_noisevars.bufcount = 0;
723
724 if (ISNPHY(pi))
725 pi->min_txpower = PHY_TXPWR_MIN_NPHY;
726 else
727 pi->min_txpower = PHY_TXPWR_MIN;
728
729 pi->sh->phyrxchain = 0x3;
730
731 pi->rx2tx_biasentry = -1;
732
733 pi->phy_txcore_disable_temp = PHY_CHAIN_TX_DISABLE_TEMP;
734 pi->phy_txcore_enable_temp =
735 PHY_CHAIN_TX_DISABLE_TEMP - PHY_HYSTERESIS_DELTATEMP;
736 pi->phy_tempsense_offset = 0;
Greg Kroah-Hartman0965ae82010-10-12 12:50:15 -0700737 pi->phy_txcore_heatedup = false;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700738
739 pi->nphy_lastcal_temp = -50;
740
Greg Kroah-Hartman0f0881b2010-10-12 12:15:18 -0700741 pi->phynoise_polling = true;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700742 if (ISNPHY(pi) || ISLCNPHY(pi))
Greg Kroah-Hartman0965ae82010-10-12 12:50:15 -0700743 pi->phynoise_polling = false;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700744
745 for (i = 0; i < TXP_NUM_RATES; i++) {
746 pi->txpwr_limit[i] = WLC_TXPWR_MAX;
747 pi->txpwr_env_limit[i] = WLC_TXPWR_MAX;
748 pi->tx_user_target[i] = WLC_TXPWR_MAX;
749 }
750
751 pi->radiopwr_override = RADIOPWR_OVERRIDE_DEF;
752
Greg Kroah-Hartman0965ae82010-10-12 12:50:15 -0700753 pi->user_txpwr_at_rfport = false;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700754
755 if (ISNPHY(pi)) {
756
Jason Cooperca8c1e52010-09-14 09:45:33 -0400757 pi->phycal_timer = wlapi_init_timer(pi->sh->physhim,
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700758 wlc_phy_timercb_phycal,
Jason Cooperca8c1e52010-09-14 09:45:33 -0400759 pi, "phycal");
760 if (!pi->phycal_timer) {
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700761 goto err;
762 }
763
764 if (!wlc_phy_attach_nphy(pi))
765 goto err;
766
767 } else if (ISLCNPHY(pi)) {
768 if (!wlc_phy_attach_lcnphy(pi))
769 goto err;
770
771 } else {
772
773 }
774
775 pi->refcnt++;
776 pi->next = pi->sh->phy_head;
777 sh->phy_head = pi;
778
779 pi->vars = (char *)&pi->vars;
780
781 bcopy(&pi->pubpi, &pi->pubpi_ro, sizeof(wlc_phy_t));
782
783 return &pi->pubpi_ro;
784
785 err:
786 if (pi)
mike.rapoport@gmail.com182acb32010-10-13 00:09:12 +0200787 kfree(pi);
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700788 return NULL;
789}
790
Greg Kroah-Hartman0d2f0722010-10-08 14:28:21 -0700791void wlc_phy_detach(wlc_phy_t *pih)
Jason Coopera2627bc2010-09-14 09:45:31 -0400792{
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700793 phy_info_t *pi = (phy_info_t *) pih;
794
795 if (pih) {
796 if (--pi->refcnt) {
797 return;
798 }
799
800 if (pi->phycal_timer) {
801 wlapi_free_timer(pi->sh->physhim, pi->phycal_timer);
802 pi->phycal_timer = NULL;
803 }
804
805 if (pi->sh->phy_head == pi)
806 pi->sh->phy_head = pi->next;
807 else if (pi->sh->phy_head->next == pi)
808 pi->sh->phy_head->next = NULL;
809 else
810 ASSERT(0);
811
812 if (pi->pi_fptr.detach)
813 (pi->pi_fptr.detach) (pi);
814
mike.rapoport@gmail.com182acb32010-10-13 00:09:12 +0200815 kfree(pi);
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700816 }
817}
818
819bool
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -0700820wlc_phy_get_phyversion(wlc_phy_t *pih, u16 *phytype, u16 *phyrev,
821 u16 *radioid, u16 *radiover)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700822{
823 phy_info_t *pi = (phy_info_t *) pih;
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -0700824 *phytype = (u16) pi->pubpi.phy_type;
825 *phyrev = (u16) pi->pubpi.phy_rev;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700826 *radioid = pi->pubpi.radioid;
827 *radiover = pi->pubpi.radiorev;
828
Greg Kroah-Hartman0f0881b2010-10-12 12:15:18 -0700829 return true;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700830}
831
Jason Cooper7cc4a4c2010-09-14 09:45:30 -0400832bool wlc_phy_get_encore(wlc_phy_t *pih)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700833{
834 phy_info_t *pi = (phy_info_t *) pih;
835 return pi->pubpi.abgphy_encore;
836}
837
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -0700838u32 wlc_phy_get_coreflags(wlc_phy_t *pih)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700839{
840 phy_info_t *pi = (phy_info_t *) pih;
841 return pi->pubpi.coreflags;
842}
843
844static void wlc_phy_timercb_phycal(void *arg)
845{
846 phy_info_t *pi = (phy_info_t *) arg;
847 uint delay = 5;
848
849 if (PHY_PERICAL_MPHASE_PENDING(pi)) {
850 if (!pi->sh->up) {
851 wlc_phy_cal_perical_mphase_reset(pi);
852 return;
853 }
854
855 if (SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi)) {
856
857 delay = 1000;
858 wlc_phy_cal_perical_mphase_restart(pi);
859 } else
860 wlc_phy_cal_perical_nphy_run(pi, PHY_PERICAL_AUTO);
861 wlapi_add_timer(pi->sh->physhim, pi->phycal_timer, delay, 0);
862 return;
863 }
864
865}
866
Jason Cooper7cc4a4c2010-09-14 09:45:30 -0400867void wlc_phy_anacore(wlc_phy_t *pih, bool on)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700868{
869 phy_info_t *pi = (phy_info_t *) pih;
870
871 if (ISNPHY(pi)) {
872 if (on) {
873 if (NREV_GE(pi->pubpi.phy_rev, 3)) {
874 write_phy_reg(pi, 0xa6, 0x0d);
875 write_phy_reg(pi, 0x8f, 0x0);
876 write_phy_reg(pi, 0xa7, 0x0d);
877 write_phy_reg(pi, 0xa5, 0x0);
878 } else {
879 write_phy_reg(pi, 0xa5, 0x0);
880 }
881 } else {
882 if (NREV_GE(pi->pubpi.phy_rev, 3)) {
883 write_phy_reg(pi, 0x8f, 0x07ff);
884 write_phy_reg(pi, 0xa6, 0x0fd);
885 write_phy_reg(pi, 0xa5, 0x07ff);
886 write_phy_reg(pi, 0xa7, 0x0fd);
887 } else {
888 write_phy_reg(pi, 0xa5, 0x7fff);
889 }
890 }
891 } else if (ISLCNPHY(pi)) {
892 if (on) {
893 and_phy_reg(pi, 0x43b,
894 ~((0x1 << 0) | (0x1 << 1) | (0x1 << 2)));
895 } else {
896 or_phy_reg(pi, 0x43c,
897 (0x1 << 0) | (0x1 << 1) | (0x1 << 2));
898 or_phy_reg(pi, 0x43b,
899 (0x1 << 0) | (0x1 << 1) | (0x1 << 2));
900 }
901 }
902}
903
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -0700904u32 wlc_phy_clk_bwbits(wlc_phy_t *pih)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700905{
906 phy_info_t *pi = (phy_info_t *) pih;
907
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -0700908 u32 phy_bw_clkbits = 0;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700909
910 if (pi && (ISNPHY(pi) || ISLCNPHY(pi))) {
911 switch (pi->bw) {
912 case WL_CHANSPEC_BW_10:
913 phy_bw_clkbits = SICF_BW10;
914 break;
915 case WL_CHANSPEC_BW_20:
916 phy_bw_clkbits = SICF_BW20;
917 break;
918 case WL_CHANSPEC_BW_40:
919 phy_bw_clkbits = SICF_BW40;
920 break;
921 default:
922 ASSERT(0);
923 break;
924 }
925 }
926
927 return phy_bw_clkbits;
928}
929
Jason Coopera2627bc2010-09-14 09:45:31 -0400930void WLBANDINITFN(wlc_phy_por_inform) (wlc_phy_t *ppi)
931{
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700932 phy_info_t *pi = (phy_info_t *) ppi;
933
Greg Kroah-Hartman0f0881b2010-10-12 12:15:18 -0700934 pi->phy_init_por = true;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700935}
936
Jason Cooper7cc4a4c2010-09-14 09:45:30 -0400937void wlc_phy_edcrs_lock(wlc_phy_t *pih, bool lock)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700938{
939 phy_info_t *pi = (phy_info_t *) pih;
940
941 pi->edcrs_threshold_lock = lock;
942
943 write_phy_reg(pi, 0x22c, 0x46b);
944 write_phy_reg(pi, 0x22d, 0x46b);
945 write_phy_reg(pi, 0x22e, 0x3c0);
946 write_phy_reg(pi, 0x22f, 0x3c0);
947}
948
Jason Cooper7cc4a4c2010-09-14 09:45:30 -0400949void wlc_phy_initcal_enable(wlc_phy_t *pih, bool initcal)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700950{
951 phy_info_t *pi = (phy_info_t *) pih;
952
953 pi->do_initcal = initcal;
954}
955
Jason Cooper7cc4a4c2010-09-14 09:45:30 -0400956void wlc_phy_hw_clk_state_upd(wlc_phy_t *pih, bool newstate)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700957{
958 phy_info_t *pi = (phy_info_t *) pih;
959
960 if (!pi || !pi->sh)
961 return;
962
963 pi->sh->clk = newstate;
964}
965
Jason Cooper7cc4a4c2010-09-14 09:45:30 -0400966void wlc_phy_hw_state_upd(wlc_phy_t *pih, bool newstate)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700967{
968 phy_info_t *pi = (phy_info_t *) pih;
969
970 if (!pi || !pi->sh)
971 return;
972
973 pi->sh->up = newstate;
974}
975
Jason Coopera2627bc2010-09-14 09:45:31 -0400976void WLBANDINITFN(wlc_phy_init) (wlc_phy_t *pih, chanspec_t chanspec)
977{
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -0700978 u32 mc;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700979 initfn_t phy_init = NULL;
980 phy_info_t *pi = (phy_info_t *) pih;
981
982 if (pi->init_in_progress)
983 return;
984
Greg Kroah-Hartman0f0881b2010-10-12 12:15:18 -0700985 pi->init_in_progress = true;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700986
987 pi->radio_chanspec = chanspec;
988
989 mc = R_REG(pi->sh->osh, &pi->regs->maccontrol);
990 if ((mc & MCTL_EN_MAC) != 0) {
991 ASSERT((const char *)
992 "wlc_phy_init: Called with the MAC running!" == NULL);
993 }
994
995 ASSERT(pi != NULL);
996
997 if (!(pi->measure_hold & PHY_HOLD_FOR_SCAN)) {
998 pi->measure_hold |= PHY_HOLD_FOR_NOT_ASSOC;
999 }
1000
1001 if (D11REV_GE(pi->sh->corerev, 5))
1002 ASSERT(si_core_sflags(pi->sh->sih, 0, 0) & SISF_FCLKA);
1003
1004 phy_init = pi->pi_fptr.init;
1005
1006 if (phy_init == NULL) {
1007 ASSERT(phy_init != NULL);
1008 return;
1009 }
1010
1011 wlc_phy_anacore(pih, ON);
1012
1013 if (CHSPEC_BW(pi->radio_chanspec) != pi->bw)
1014 wlapi_bmac_bw_set(pi->sh->physhim,
1015 CHSPEC_BW(pi->radio_chanspec));
1016
Greg Kroah-Hartman0f0881b2010-10-12 12:15:18 -07001017 pi->nphy_gain_boost = true;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001018
1019 wlc_phy_switch_radio((wlc_phy_t *) pi, ON);
1020
1021 (*phy_init) (pi);
1022
Greg Kroah-Hartman0965ae82010-10-12 12:50:15 -07001023 pi->phy_init_por = false;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001024
1025 if (D11REV_IS(pi->sh->corerev, 11) || D11REV_IS(pi->sh->corerev, 12))
Greg Kroah-Hartman0f0881b2010-10-12 12:15:18 -07001026 wlc_phy_do_dummy_tx(pi, true, OFF);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001027
1028 if (!(ISNPHY(pi)))
1029 wlc_phy_txpower_update_shm(pi);
1030
1031 wlc_phy_ant_rxdiv_set((wlc_phy_t *) pi, pi->sh->rx_antdiv);
1032
Greg Kroah-Hartman0965ae82010-10-12 12:50:15 -07001033 pi->init_in_progress = false;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001034}
1035
Jason Cooperb4f790e2010-10-11 10:02:58 -04001036void wlc_phy_cal_init(wlc_phy_t *pih)
Jason Coopera2627bc2010-09-14 09:45:31 -04001037{
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001038 phy_info_t *pi = (phy_info_t *) pih;
1039 initfn_t cal_init = NULL;
1040
1041 ASSERT((R_REG(pi->sh->osh, &pi->regs->maccontrol) & MCTL_EN_MAC) == 0);
1042
1043 if (!pi->initialized) {
1044 cal_init = pi->pi_fptr.calinit;
1045 if (cal_init)
1046 (*cal_init) (pi);
1047
Greg Kroah-Hartman0f0881b2010-10-12 12:15:18 -07001048 pi->initialized = true;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001049 }
1050}
1051
Jason Cooper9927fc22010-10-11 10:02:59 -04001052int wlc_phy_down(wlc_phy_t *pih)
Jason Coopera2627bc2010-09-14 09:45:31 -04001053{
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001054 phy_info_t *pi = (phy_info_t *) pih;
1055 int callbacks = 0;
1056
Greg Kroah-Hartman0965ae82010-10-12 12:50:15 -07001057 ASSERT(pi->phytest_on == false);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001058
1059 if (pi->phycal_timer
1060 && !wlapi_del_timer(pi->sh->physhim, pi->phycal_timer))
1061 callbacks++;
1062
1063 pi->nphy_iqcal_chanspec_2G = 0;
1064 pi->nphy_iqcal_chanspec_5G = 0;
1065
1066 return callbacks;
1067}
1068
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -07001069static u32 wlc_phy_get_radio_ver(phy_info_t *pi)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001070{
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -07001071 u32 ver;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001072
1073 ver = read_radio_id(pi);
1074
1075 return ver;
1076}
1077
1078void
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04001079wlc_phy_table_addr(phy_info_t *pi, uint tbl_id, uint tbl_offset,
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -07001080 u16 tblAddr, u16 tblDataHi, u16 tblDataLo)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001081{
1082 write_phy_reg(pi, tblAddr, (tbl_id << 10) | tbl_offset);
1083
1084 pi->tbl_data_hi = tblDataHi;
1085 pi->tbl_data_lo = tblDataLo;
1086
1087 if ((CHIPID(pi->sh->chip) == BCM43224_CHIP_ID ||
1088 CHIPID(pi->sh->chip) == BCM43421_CHIP_ID) &&
1089 (pi->sh->chiprev == 1)) {
1090 pi->tbl_addr = tblAddr;
1091 pi->tbl_save_id = tbl_id;
1092 pi->tbl_save_offset = tbl_offset;
1093 }
1094}
1095
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -07001096void wlc_phy_table_data_write(phy_info_t *pi, uint width, u32 val)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001097{
1098 ASSERT((width == 8) || (width == 16) || (width == 32));
1099
1100 if ((CHIPID(pi->sh->chip) == BCM43224_CHIP_ID ||
1101 CHIPID(pi->sh->chip) == BCM43421_CHIP_ID) &&
1102 (pi->sh->chiprev == 1) &&
1103 (pi->tbl_save_id == NPHY_TBL_ID_ANTSWCTRLLUT)) {
1104 read_phy_reg(pi, pi->tbl_data_lo);
1105
1106 write_phy_reg(pi, pi->tbl_addr,
1107 (pi->tbl_save_id << 10) | pi->tbl_save_offset);
1108 pi->tbl_save_offset++;
1109 }
1110
1111 if (width == 32) {
1112
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -07001113 write_phy_reg(pi, pi->tbl_data_hi, (u16) (val >> 16));
1114 write_phy_reg(pi, pi->tbl_data_lo, (u16) val);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001115 } else {
1116
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -07001117 write_phy_reg(pi, pi->tbl_data_lo, (u16) val);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001118 }
1119}
1120
1121void
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04001122wlc_phy_write_table(phy_info_t *pi, const phytbl_info_t *ptbl_info,
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -07001123 u16 tblAddr, u16 tblDataHi, u16 tblDataLo)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001124{
1125 uint idx;
1126 uint tbl_id = ptbl_info->tbl_id;
1127 uint tbl_offset = ptbl_info->tbl_offset;
1128 uint tbl_width = ptbl_info->tbl_width;
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07001129 const u8 *ptbl_8b = (const u8 *)ptbl_info->tbl_ptr;
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -07001130 const u16 *ptbl_16b = (const u16 *)ptbl_info->tbl_ptr;
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -07001131 const u32 *ptbl_32b = (const u32 *)ptbl_info->tbl_ptr;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001132
1133 ASSERT((tbl_width == 8) || (tbl_width == 16) || (tbl_width == 32));
1134
1135 write_phy_reg(pi, tblAddr, (tbl_id << 10) | tbl_offset);
1136
1137 for (idx = 0; idx < ptbl_info->tbl_len; idx++) {
1138
1139 if ((CHIPID(pi->sh->chip) == BCM43224_CHIP_ID ||
1140 CHIPID(pi->sh->chip) == BCM43421_CHIP_ID) &&
1141 (pi->sh->chiprev == 1) &&
1142 (tbl_id == NPHY_TBL_ID_ANTSWCTRLLUT)) {
1143 read_phy_reg(pi, tblDataLo);
1144
1145 write_phy_reg(pi, tblAddr,
1146 (tbl_id << 10) | (tbl_offset + idx));
1147 }
1148
1149 if (tbl_width == 32) {
1150
1151 write_phy_reg(pi, tblDataHi,
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -07001152 (u16) (ptbl_32b[idx] >> 16));
1153 write_phy_reg(pi, tblDataLo, (u16) ptbl_32b[idx]);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001154 } else if (tbl_width == 16) {
1155
1156 write_phy_reg(pi, tblDataLo, ptbl_16b[idx]);
1157 } else {
1158
1159 write_phy_reg(pi, tblDataLo, ptbl_8b[idx]);
1160 }
1161 }
1162}
1163
1164void
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04001165wlc_phy_read_table(phy_info_t *pi, const phytbl_info_t *ptbl_info,
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -07001166 u16 tblAddr, u16 tblDataHi, u16 tblDataLo)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001167{
1168 uint idx;
1169 uint tbl_id = ptbl_info->tbl_id;
1170 uint tbl_offset = ptbl_info->tbl_offset;
1171 uint tbl_width = ptbl_info->tbl_width;
Greg Kroah-Hartman159a3b72010-10-12 13:20:00 -07001172 u8 *ptbl_8b = (u8 *)ptbl_info->tbl_ptr;
1173 u16 *ptbl_16b = (u16 *)ptbl_info->tbl_ptr;
1174 u32 *ptbl_32b = (u32 *)ptbl_info->tbl_ptr;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001175
1176 ASSERT((tbl_width == 8) || (tbl_width == 16) || (tbl_width == 32));
1177
1178 write_phy_reg(pi, tblAddr, (tbl_id << 10) | tbl_offset);
1179
1180 for (idx = 0; idx < ptbl_info->tbl_len; idx++) {
1181
1182 if ((CHIPID(pi->sh->chip) == BCM43224_CHIP_ID ||
1183 CHIPID(pi->sh->chip) == BCM43421_CHIP_ID) &&
1184 (pi->sh->chiprev == 1)) {
1185 (void)read_phy_reg(pi, tblDataLo);
1186
1187 write_phy_reg(pi, tblAddr,
1188 (tbl_id << 10) | (tbl_offset + idx));
1189 }
1190
1191 if (tbl_width == 32) {
1192
1193 ptbl_32b[idx] = read_phy_reg(pi, tblDataLo);
1194 ptbl_32b[idx] |= (read_phy_reg(pi, tblDataHi) << 16);
1195 } else if (tbl_width == 16) {
1196
1197 ptbl_16b[idx] = read_phy_reg(pi, tblDataLo);
1198 } else {
1199
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07001200 ptbl_8b[idx] = (u8) read_phy_reg(pi, tblDataLo);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001201 }
1202 }
1203}
1204
1205uint
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04001206wlc_phy_init_radio_regs_allbands(phy_info_t *pi, radio_20xx_regs_t *radioregs)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001207{
1208 uint i = 0;
1209
1210 do {
1211 if (radioregs[i].do_init) {
1212 write_radio_reg(pi, radioregs[i].address,
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -07001213 (u16) radioregs[i].init);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001214 }
1215
1216 i++;
1217 } while (radioregs[i].address != 0xffff);
1218
1219 return i;
1220}
1221
1222uint
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04001223wlc_phy_init_radio_regs(phy_info_t *pi, radio_regs_t *radioregs,
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -07001224 u16 core_offset)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001225{
1226 uint i = 0;
1227 uint count = 0;
1228
1229 do {
1230 if (CHSPEC_IS5G(pi->radio_chanspec)) {
1231 if (radioregs[i].do_init_a) {
1232 write_radio_reg(pi,
1233 radioregs[i].
1234 address | core_offset,
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -07001235 (u16) radioregs[i].init_a);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001236 if (ISNPHY(pi) && (++count % 4 == 0))
1237 WLC_PHY_WAR_PR51571(pi);
1238 }
1239 } else {
1240 if (radioregs[i].do_init_g) {
1241 write_radio_reg(pi,
1242 radioregs[i].
1243 address | core_offset,
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -07001244 (u16) radioregs[i].init_g);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001245 if (ISNPHY(pi) && (++count % 4 == 0))
1246 WLC_PHY_WAR_PR51571(pi);
1247 }
1248 }
1249
1250 i++;
1251 } while (radioregs[i].address != 0xffff);
1252
1253 return i;
1254}
1255
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04001256void wlc_phy_do_dummy_tx(phy_info_t *pi, bool ofdm, bool pa_on)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001257{
1258#define DUMMY_PKT_LEN 20
1259 d11regs_t *regs = pi->regs;
1260 int i, count;
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07001261 u8 ofdmpkt[DUMMY_PKT_LEN] = {
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001262 0xcc, 0x01, 0x02, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00,
1263 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00
1264 };
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07001265 u8 cckpkt[DUMMY_PKT_LEN] = {
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001266 0x6e, 0x84, 0x0b, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00,
1267 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00
1268 };
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -07001269 u32 *dummypkt;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001270
1271 ASSERT((R_REG(pi->sh->osh, &pi->regs->maccontrol) & MCTL_EN_MAC) == 0);
1272
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -07001273 dummypkt = (u32 *) (ofdm ? ofdmpkt : cckpkt);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001274 wlapi_bmac_write_template_ram(pi->sh->physhim, 0, DUMMY_PKT_LEN,
1275 dummypkt);
1276
1277 W_REG(pi->sh->osh, &regs->xmtsel, 0);
1278
1279 if (D11REV_GE(pi->sh->corerev, 11))
1280 W_REG(pi->sh->osh, &regs->wepctl, 0x100);
1281 else
1282 W_REG(pi->sh->osh, &regs->wepctl, 0);
1283
1284 W_REG(pi->sh->osh, &regs->txe_phyctl, (ofdm ? 1 : 0) | PHY_TXC_ANT_0);
1285 if (ISNPHY(pi) || ISLCNPHY(pi)) {
1286 ASSERT(ofdm);
1287 W_REG(pi->sh->osh, &regs->txe_phyctl1, 0x1A02);
1288 }
1289
1290 W_REG(pi->sh->osh, &regs->txe_wm_0, 0);
1291 W_REG(pi->sh->osh, &regs->txe_wm_1, 0);
1292
1293 W_REG(pi->sh->osh, &regs->xmttplatetxptr, 0);
1294 W_REG(pi->sh->osh, &regs->xmttxcnt, DUMMY_PKT_LEN);
1295
1296 W_REG(pi->sh->osh, &regs->xmtsel, ((8 << 8) | (1 << 5) | (1 << 2) | 2));
1297
1298 W_REG(pi->sh->osh, &regs->txe_ctl, 0);
1299
1300 if (!pa_on) {
1301 if (ISNPHY(pi))
1302 wlc_phy_pa_override_nphy(pi, OFF);
1303 }
1304
1305 if (ISNPHY(pi) || ISLCNPHY(pi))
1306 W_REG(pi->sh->osh, &regs->txe_aux, 0xD0);
1307 else
1308 W_REG(pi->sh->osh, &regs->txe_aux, ((1 << 5) | (1 << 4)));
1309
1310 (void)R_REG(pi->sh->osh, &regs->txe_aux);
1311
1312 i = 0;
1313 count = ofdm ? 30 : 250;
1314
1315 if (ISSIM_ENAB(pi->sh->sih)) {
1316 count *= 100;
1317 }
1318
1319 while ((i++ < count)
1320 && (R_REG(pi->sh->osh, &regs->txe_status) & (1 << 7))) {
mike.rapoport@gmail.com73831412010-10-13 00:09:07 +02001321 udelay(10);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001322 }
1323
1324 i = 0;
1325
1326 while ((i++ < 10)
1327 && ((R_REG(pi->sh->osh, &regs->txe_status) & (1 << 10)) == 0)) {
mike.rapoport@gmail.com73831412010-10-13 00:09:07 +02001328 udelay(10);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001329 }
1330
1331 i = 0;
1332
1333 while ((i++ < 10) && ((R_REG(pi->sh->osh, &regs->ifsstat) & (1 << 8)))) {
mike.rapoport@gmail.com73831412010-10-13 00:09:07 +02001334 udelay(10);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001335 }
1336 if (!pa_on) {
1337 if (ISNPHY(pi))
1338 wlc_phy_pa_override_nphy(pi, ON);
1339 }
1340}
1341
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04001342void wlc_phy_hold_upd(wlc_phy_t *pih, mbool id, bool set)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001343{
1344 phy_info_t *pi = (phy_info_t *) pih;
1345 ASSERT(id);
1346
1347 if (set) {
1348 mboolset(pi->measure_hold, id);
1349 } else {
1350 mboolclr(pi->measure_hold, id);
1351 }
1352
1353 return;
1354}
1355
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04001356void wlc_phy_mute_upd(wlc_phy_t *pih, bool mute, mbool flags)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001357{
1358 phy_info_t *pi = (phy_info_t *) pih;
1359
1360 if (mute) {
1361 mboolset(pi->measure_hold, PHY_HOLD_FOR_MUTE);
1362 } else {
1363 mboolclr(pi->measure_hold, PHY_HOLD_FOR_MUTE);
1364 }
1365
1366 if (!mute && (flags & PHY_MUTE_FOR_PREISM))
1367 pi->nphy_perical_last = pi->sh->now - pi->sh->glacial_timer;
1368 return;
1369}
1370
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04001371void wlc_phy_clear_tssi(wlc_phy_t *pih)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001372{
1373 phy_info_t *pi = (phy_info_t *) pih;
1374
1375 if (ISNPHY(pi)) {
1376 return;
1377 } else {
1378 wlapi_bmac_write_shm(pi->sh->physhim, M_B_TSSI_0, NULL_TSSI_W);
1379 wlapi_bmac_write_shm(pi->sh->physhim, M_B_TSSI_1, NULL_TSSI_W);
1380 wlapi_bmac_write_shm(pi->sh->physhim, M_G_TSSI_0, NULL_TSSI_W);
1381 wlapi_bmac_write_shm(pi->sh->physhim, M_G_TSSI_1, NULL_TSSI_W);
1382 }
1383}
1384
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04001385static bool wlc_phy_cal_txpower_recalc_sw(phy_info_t *pi)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001386{
Greg Kroah-Hartman0965ae82010-10-12 12:50:15 -07001387 return false;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001388}
1389
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04001390void wlc_phy_switch_radio(wlc_phy_t *pih, bool on)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001391{
1392 phy_info_t *pi = (phy_info_t *) pih;
1393
1394 if (NORADIO_ENAB(pi->pubpi))
1395 return;
1396
1397 {
1398 uint mc;
1399
1400 mc = R_REG(pi->sh->osh, &pi->regs->maccontrol);
1401 }
1402
1403 if (ISNPHY(pi)) {
1404 wlc_phy_switch_radio_nphy(pi, on);
1405
1406 } else if (ISLCNPHY(pi)) {
1407 if (on) {
1408 and_phy_reg(pi, 0x44c,
1409 ~((0x1 << 8) |
1410 (0x1 << 9) |
1411 (0x1 << 10) | (0x1 << 11) | (0x1 << 12)));
1412 and_phy_reg(pi, 0x4b0, ~((0x1 << 3) | (0x1 << 11)));
1413 and_phy_reg(pi, 0x4f9, ~(0x1 << 3));
1414 } else {
1415 and_phy_reg(pi, 0x44d,
1416 ~((0x1 << 10) |
1417 (0x1 << 11) |
1418 (0x1 << 12) | (0x1 << 13) | (0x1 << 14)));
1419 or_phy_reg(pi, 0x44c,
1420 (0x1 << 8) |
1421 (0x1 << 9) |
1422 (0x1 << 10) | (0x1 << 11) | (0x1 << 12));
1423
1424 and_phy_reg(pi, 0x4b7, ~((0x7f << 8)));
1425 and_phy_reg(pi, 0x4b1, ~((0x1 << 13)));
1426 or_phy_reg(pi, 0x4b0, (0x1 << 3) | (0x1 << 11));
1427 and_phy_reg(pi, 0x4fa, ~((0x1 << 3)));
1428 or_phy_reg(pi, 0x4f9, (0x1 << 3));
1429 }
1430 }
1431}
1432
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -07001433u16 wlc_phy_bw_state_get(wlc_phy_t *ppi)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001434{
1435 phy_info_t *pi = (phy_info_t *) ppi;
1436
1437 return pi->bw;
1438}
1439
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -07001440void wlc_phy_bw_state_set(wlc_phy_t *ppi, u16 bw)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001441{
1442 phy_info_t *pi = (phy_info_t *) ppi;
1443
1444 pi->bw = bw;
1445}
1446
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04001447void wlc_phy_chanspec_radio_set(wlc_phy_t *ppi, chanspec_t newch)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001448{
1449 phy_info_t *pi = (phy_info_t *) ppi;
1450 pi->radio_chanspec = newch;
1451
1452}
1453
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04001454chanspec_t wlc_phy_chanspec_get(wlc_phy_t *ppi)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001455{
1456 phy_info_t *pi = (phy_info_t *) ppi;
1457
1458 return pi->radio_chanspec;
1459}
1460
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04001461void wlc_phy_chanspec_set(wlc_phy_t *ppi, chanspec_t chanspec)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001462{
1463 phy_info_t *pi = (phy_info_t *) ppi;
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -07001464 u16 m_cur_channel;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001465 chansetfn_t chanspec_set = NULL;
1466
1467 ASSERT(!wf_chspec_malformed(chanspec));
1468
1469 m_cur_channel = CHSPEC_CHANNEL(chanspec);
1470 if (CHSPEC_IS5G(chanspec))
1471 m_cur_channel |= D11_CURCHANNEL_5G;
1472 if (CHSPEC_IS40(chanspec))
1473 m_cur_channel |= D11_CURCHANNEL_40;
1474 wlapi_bmac_write_shm(pi->sh->physhim, M_CURCHANNEL, m_cur_channel);
1475
1476 chanspec_set = pi->pi_fptr.chanset;
1477 if (chanspec_set)
1478 (*chanspec_set) (pi, chanspec);
1479
1480}
1481
1482int wlc_phy_chanspec_freq2bandrange_lpssn(uint freq)
1483{
1484 int range = -1;
1485
1486 if (freq < 2500)
1487 range = WL_CHAN_FREQ_RANGE_2G;
1488 else if (freq <= 5320)
1489 range = WL_CHAN_FREQ_RANGE_5GL;
1490 else if (freq <= 5700)
1491 range = WL_CHAN_FREQ_RANGE_5GM;
1492 else
1493 range = WL_CHAN_FREQ_RANGE_5GH;
1494
1495 return range;
1496}
1497
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04001498int wlc_phy_chanspec_bandrange_get(phy_info_t *pi, chanspec_t chanspec)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001499{
1500 int range = -1;
1501 uint channel = CHSPEC_CHANNEL(chanspec);
1502 uint freq = wlc_phy_channel2freq(channel);
1503
1504 if (ISNPHY(pi)) {
1505 range = wlc_phy_get_chan_freq_range_nphy(pi, channel);
1506 } else if (ISLCNPHY(pi)) {
1507 range = wlc_phy_chanspec_freq2bandrange_lpssn(freq);
1508 } else
1509 ASSERT(0);
1510
1511 return range;
1512}
1513
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04001514void wlc_phy_chanspec_ch14_widefilter_set(wlc_phy_t *ppi, bool wide_filter)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001515{
1516 phy_info_t *pi = (phy_info_t *) ppi;
1517
1518 pi->channel_14_wide_filter = wide_filter;
1519
1520}
1521
1522int wlc_phy_channel2freq(uint channel)
1523{
1524 uint i;
1525
Greg Kroah-Hartman8d3d6a62010-10-08 11:47:11 -07001526 for (i = 0; i < ARRAY_SIZE(chan_info_all); i++)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001527 if (chan_info_all[i].chan == channel)
Jason Cooper90ea2292010-09-14 09:45:32 -04001528 return chan_info_all[i].freq;
1529 return 0;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001530}
1531
1532void
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04001533wlc_phy_chanspec_band_validch(wlc_phy_t *ppi, uint band, chanvec_t *channels)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001534{
1535 phy_info_t *pi = (phy_info_t *) ppi;
1536 uint i;
1537 uint channel;
1538
1539 ASSERT((band == WLC_BAND_2G) || (band == WLC_BAND_5G));
1540
Brett Rudley9249ede2010-11-30 20:09:49 -08001541 memset(channels, 0, sizeof(chanvec_t));
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001542
Greg Kroah-Hartman8d3d6a62010-10-08 11:47:11 -07001543 for (i = 0; i < ARRAY_SIZE(chan_info_all); i++) {
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001544 channel = chan_info_all[i].chan;
1545
1546 if ((pi->a_band_high_disable) && (channel >= FIRST_REF5_CHANNUM)
1547 && (channel <= LAST_REF5_CHANNUM))
1548 continue;
1549
1550 if (((band == WLC_BAND_2G) && (channel <= CH_MAX_2G_CHANNEL)) ||
1551 ((band == WLC_BAND_5G) && (channel > CH_MAX_2G_CHANNEL)))
1552 setbit(channels->vec, channel);
1553 }
1554}
1555
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04001556chanspec_t wlc_phy_chanspec_band_firstch(wlc_phy_t *ppi, uint band)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001557{
1558 phy_info_t *pi = (phy_info_t *) ppi;
1559 uint i;
1560 uint channel;
1561 chanspec_t chspec;
1562
1563 ASSERT((band == WLC_BAND_2G) || (band == WLC_BAND_5G));
1564
Greg Kroah-Hartman8d3d6a62010-10-08 11:47:11 -07001565 for (i = 0; i < ARRAY_SIZE(chan_info_all); i++) {
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001566 channel = chan_info_all[i].chan;
1567
1568 if (ISNPHY(pi) && IS40MHZ(pi)) {
1569 uint j;
1570
Greg Kroah-Hartman8d3d6a62010-10-08 11:47:11 -07001571 for (j = 0; j < ARRAY_SIZE(chan_info_all); j++) {
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001572 if (chan_info_all[j].chan ==
1573 channel + CH_10MHZ_APART)
1574 break;
1575 }
1576
Greg Kroah-Hartman8d3d6a62010-10-08 11:47:11 -07001577 if (j == ARRAY_SIZE(chan_info_all))
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001578 continue;
1579
1580 channel = UPPER_20_SB(channel);
1581 chspec =
1582 channel | WL_CHANSPEC_BW_40 |
1583 WL_CHANSPEC_CTL_SB_LOWER;
1584 if (band == WLC_BAND_2G)
1585 chspec |= WL_CHANSPEC_BAND_2G;
1586 else
1587 chspec |= WL_CHANSPEC_BAND_5G;
1588 } else
1589 chspec = CH20MHZ_CHSPEC(channel);
1590
1591 if ((pi->a_band_high_disable) && (channel >= FIRST_REF5_CHANNUM)
1592 && (channel <= LAST_REF5_CHANNUM))
1593 continue;
1594
1595 if (((band == WLC_BAND_2G) && (channel <= CH_MAX_2G_CHANNEL)) ||
1596 ((band == WLC_BAND_5G) && (channel > CH_MAX_2G_CHANNEL)))
1597 return chspec;
1598 }
1599
1600 ASSERT(0);
1601
1602 return (chanspec_t) INVCHANSPEC;
1603}
1604
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04001605int wlc_phy_txpower_get(wlc_phy_t *ppi, uint *qdbm, bool *override)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001606{
1607 phy_info_t *pi = (phy_info_t *) ppi;
1608
1609 ASSERT(qdbm != NULL);
1610 *qdbm = pi->tx_user_target[0];
1611 if (override != NULL)
1612 *override = pi->txpwroverride;
Jason Cooper90ea2292010-09-14 09:45:32 -04001613 return 0;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001614}
1615
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04001616void wlc_phy_txpower_target_set(wlc_phy_t *ppi, struct txpwr_limits *txpwr)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001617{
Greg Kroah-Hartman0965ae82010-10-12 12:50:15 -07001618 bool mac_enabled = false;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001619 phy_info_t *pi = (phy_info_t *) ppi;
1620
1621 bcopy(&txpwr->cck[0], &pi->tx_user_target[TXP_FIRST_CCK],
1622 WLC_NUM_RATES_CCK);
1623
1624 bcopy(&txpwr->ofdm[0], &pi->tx_user_target[TXP_FIRST_OFDM],
1625 WLC_NUM_RATES_OFDM);
1626 bcopy(&txpwr->ofdm_cdd[0], &pi->tx_user_target[TXP_FIRST_OFDM_20_CDD],
1627 WLC_NUM_RATES_OFDM);
1628
1629 bcopy(&txpwr->ofdm_40_siso[0],
1630 &pi->tx_user_target[TXP_FIRST_OFDM_40_SISO], WLC_NUM_RATES_OFDM);
1631 bcopy(&txpwr->ofdm_40_cdd[0],
1632 &pi->tx_user_target[TXP_FIRST_OFDM_40_CDD], WLC_NUM_RATES_OFDM);
1633
1634 bcopy(&txpwr->mcs_20_siso[0],
1635 &pi->tx_user_target[TXP_FIRST_MCS_20_SISO],
1636 WLC_NUM_RATES_MCS_1_STREAM);
1637 bcopy(&txpwr->mcs_20_cdd[0], &pi->tx_user_target[TXP_FIRST_MCS_20_CDD],
1638 WLC_NUM_RATES_MCS_1_STREAM);
1639 bcopy(&txpwr->mcs_20_stbc[0],
1640 &pi->tx_user_target[TXP_FIRST_MCS_20_STBC],
1641 WLC_NUM_RATES_MCS_1_STREAM);
1642 bcopy(&txpwr->mcs_20_mimo[0], &pi->tx_user_target[TXP_FIRST_MCS_20_SDM],
1643 WLC_NUM_RATES_MCS_2_STREAM);
1644
1645 bcopy(&txpwr->mcs_40_siso[0],
1646 &pi->tx_user_target[TXP_FIRST_MCS_40_SISO],
1647 WLC_NUM_RATES_MCS_1_STREAM);
1648 bcopy(&txpwr->mcs_40_cdd[0], &pi->tx_user_target[TXP_FIRST_MCS_40_CDD],
1649 WLC_NUM_RATES_MCS_1_STREAM);
1650 bcopy(&txpwr->mcs_40_stbc[0],
1651 &pi->tx_user_target[TXP_FIRST_MCS_40_STBC],
1652 WLC_NUM_RATES_MCS_1_STREAM);
1653 bcopy(&txpwr->mcs_40_mimo[0], &pi->tx_user_target[TXP_FIRST_MCS_40_SDM],
1654 WLC_NUM_RATES_MCS_2_STREAM);
1655
1656 if (R_REG(pi->sh->osh, &pi->regs->maccontrol) & MCTL_EN_MAC)
Greg Kroah-Hartman0f0881b2010-10-12 12:15:18 -07001657 mac_enabled = true;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001658
1659 if (mac_enabled)
1660 wlapi_suspend_mac_and_wait(pi->sh->physhim);
1661
1662 wlc_phy_txpower_recalc_target(pi);
1663 wlc_phy_cal_txpower_recalc_sw(pi);
1664
1665 if (mac_enabled)
1666 wlapi_enable_mac(pi->sh->physhim);
1667}
1668
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04001669int wlc_phy_txpower_set(wlc_phy_t *ppi, uint qdbm, bool override)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001670{
1671 phy_info_t *pi = (phy_info_t *) ppi;
1672 int i;
1673
1674 if (qdbm > 127)
1675 return 5;
1676
1677 for (i = 0; i < TXP_NUM_RATES; i++)
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07001678 pi->tx_user_target[i] = (u8) qdbm;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001679
Greg Kroah-Hartman0965ae82010-10-12 12:50:15 -07001680 pi->txpwroverride = false;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001681
1682 if (pi->sh->up) {
1683 if (!SCAN_INPROG_PHY(pi)) {
1684 bool suspend;
1685
1686 suspend =
1687 (0 ==
1688 (R_REG(pi->sh->osh, &pi->regs->maccontrol) &
1689 MCTL_EN_MAC));
1690
1691 if (!suspend)
1692 wlapi_suspend_mac_and_wait(pi->sh->physhim);
1693
1694 wlc_phy_txpower_recalc_target(pi);
1695 wlc_phy_cal_txpower_recalc_sw(pi);
1696
1697 if (!suspend)
1698 wlapi_enable_mac(pi->sh->physhim);
1699 }
1700 }
Jason Cooper90ea2292010-09-14 09:45:32 -04001701 return 0;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001702}
1703
1704void
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07001705wlc_phy_txpower_sromlimit(wlc_phy_t *ppi, uint channel, u8 *min_pwr,
1706 u8 *max_pwr, int txp_rate_idx)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001707{
1708 phy_info_t *pi = (phy_info_t *) ppi;
1709 uint i;
1710
1711 *min_pwr = pi->min_txpower * WLC_TXPWR_DB_FACTOR;
1712
1713 if (ISNPHY(pi)) {
1714 if (txp_rate_idx < 0)
1715 txp_rate_idx = TXP_FIRST_CCK;
1716 wlc_phy_txpower_sromlimit_get_nphy(pi, channel, max_pwr,
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07001717 (u8) txp_rate_idx);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001718
1719 } else if ((channel <= CH_MAX_2G_CHANNEL)) {
1720 if (txp_rate_idx < 0)
1721 txp_rate_idx = TXP_FIRST_CCK;
1722 *max_pwr = pi->tx_srom_max_rate_2g[txp_rate_idx];
1723 } else {
1724
1725 *max_pwr = WLC_TXPWR_MAX;
1726
1727 if (txp_rate_idx < 0)
1728 txp_rate_idx = TXP_FIRST_OFDM;
1729
Greg Kroah-Hartman8d3d6a62010-10-08 11:47:11 -07001730 for (i = 0; i < ARRAY_SIZE(chan_info_all); i++) {
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001731 if (channel == chan_info_all[i].chan) {
1732 break;
1733 }
1734 }
Greg Kroah-Hartman8d3d6a62010-10-08 11:47:11 -07001735 ASSERT(i < ARRAY_SIZE(chan_info_all));
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001736
1737 if (pi->hwtxpwr) {
1738 *max_pwr = pi->hwtxpwr[i];
1739 } else {
1740
1741 if ((i >= FIRST_MID_5G_CHAN) && (i <= LAST_MID_5G_CHAN))
1742 *max_pwr =
1743 pi->tx_srom_max_rate_5g_mid[txp_rate_idx];
1744 if ((i >= FIRST_HIGH_5G_CHAN)
1745 && (i <= LAST_HIGH_5G_CHAN))
1746 *max_pwr =
1747 pi->tx_srom_max_rate_5g_hi[txp_rate_idx];
1748 if ((i >= FIRST_LOW_5G_CHAN) && (i <= LAST_LOW_5G_CHAN))
1749 *max_pwr =
1750 pi->tx_srom_max_rate_5g_low[txp_rate_idx];
1751 }
1752 }
1753}
1754
1755void
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07001756wlc_phy_txpower_sromlimit_max_get(wlc_phy_t *ppi, uint chan, u8 *max_txpwr,
1757 u8 *min_txpwr)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001758{
1759 phy_info_t *pi = (phy_info_t *) ppi;
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07001760 u8 tx_pwr_max = 0;
1761 u8 tx_pwr_min = 255;
1762 u8 max_num_rate;
1763 u8 maxtxpwr, mintxpwr, rate, pactrl;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001764
1765 pactrl = 0;
1766
1767 max_num_rate = ISNPHY(pi) ? TXP_NUM_RATES :
1768 ISLCNPHY(pi) ? (TXP_LAST_SISO_MCS_20 + 1) : (TXP_LAST_OFDM + 1);
1769
1770 for (rate = 0; rate < max_num_rate; rate++) {
1771
1772 wlc_phy_txpower_sromlimit(ppi, chan, &mintxpwr, &maxtxpwr,
1773 rate);
1774
1775 maxtxpwr = (maxtxpwr > pactrl) ? (maxtxpwr - pactrl) : 0;
1776
1777 maxtxpwr = (maxtxpwr > 6) ? (maxtxpwr - 6) : 0;
1778
Greg Kroah-Hartman3ea2f4d2010-10-08 11:39:43 -07001779 tx_pwr_max = max(tx_pwr_max, maxtxpwr);
Greg Kroah-Hartman7068c2f2010-10-08 11:34:59 -07001780 tx_pwr_min = min(tx_pwr_min, maxtxpwr);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001781 }
1782 *max_txpwr = tx_pwr_max;
1783 *min_txpwr = tx_pwr_min;
1784}
1785
1786void
Greg Kroah-Hartman3e264162010-10-08 11:11:13 -07001787wlc_phy_txpower_boardlimit_band(wlc_phy_t *ppi, uint bandunit, s32 *max_pwr,
1788 s32 *min_pwr, u32 *step_pwr)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001789{
1790 return;
1791}
1792
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07001793u8 wlc_phy_txpower_get_target_min(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_min;
1798}
1799
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07001800u8 wlc_phy_txpower_get_target_max(wlc_phy_t *ppi)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001801{
1802 phy_info_t *pi = (phy_info_t *) ppi;
1803
1804 return pi->tx_power_max;
1805}
1806
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04001807void wlc_phy_txpower_recalc_target(phy_info_t *pi)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001808{
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07001809 u8 maxtxpwr, mintxpwr, rate, pactrl;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001810 uint target_chan;
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07001811 u8 tx_pwr_target[TXP_NUM_RATES];
1812 u8 tx_pwr_max = 0;
1813 u8 tx_pwr_min = 255;
1814 u8 tx_pwr_max_rate_ind = 0;
1815 u8 max_num_rate;
1816 u8 start_rate = 0;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001817 chanspec_t chspec;
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -07001818 u32 band = CHSPEC2WLC_BAND(pi->radio_chanspec);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001819 initfn_t txpwr_recalc_fn = NULL;
1820
1821 chspec = pi->radio_chanspec;
1822 if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_NONE)
1823 target_chan = CHSPEC_CHANNEL(chspec);
1824 else if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_UPPER)
1825 target_chan = UPPER_20_SB(CHSPEC_CHANNEL(chspec));
1826 else
1827 target_chan = LOWER_20_SB(CHSPEC_CHANNEL(chspec));
1828
1829 pactrl = 0;
1830 if (ISLCNPHY(pi)) {
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -07001831 u32 offset_mcs, i;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001832
1833 if (CHSPEC_IS40(pi->radio_chanspec)) {
1834 offset_mcs = pi->mcs40_po;
1835 for (i = TXP_FIRST_SISO_MCS_20;
1836 i <= TXP_LAST_SISO_MCS_20; i++) {
1837 pi->tx_srom_max_rate_2g[i - 8] =
1838 pi->tx_srom_max_2g -
1839 ((offset_mcs & 0xf) * 2);
1840 offset_mcs >>= 4;
1841 }
1842 } else {
1843 offset_mcs = pi->mcs20_po;
1844 for (i = TXP_FIRST_SISO_MCS_20;
1845 i <= TXP_LAST_SISO_MCS_20; i++) {
1846 pi->tx_srom_max_rate_2g[i - 8] =
1847 pi->tx_srom_max_2g -
1848 ((offset_mcs & 0xf) * 2);
1849 offset_mcs >>= 4;
1850 }
1851 }
1852 }
1853#if WL11N
1854 max_num_rate = ((ISNPHY(pi)) ? (TXP_NUM_RATES) :
1855 ((ISLCNPHY(pi)) ?
1856 (TXP_LAST_SISO_MCS_20 + 1) : (TXP_LAST_OFDM + 1)));
1857#else
1858 max_num_rate = ((ISNPHY(pi)) ? (TXP_NUM_RATES) : (TXP_LAST_OFDM + 1));
1859#endif
1860
1861 wlc_phy_upd_env_txpwr_rate_limits(pi, band);
1862
1863 for (rate = start_rate; rate < max_num_rate; rate++) {
1864
1865 tx_pwr_target[rate] = pi->tx_user_target[rate];
1866
1867 if (pi->user_txpwr_at_rfport) {
1868 tx_pwr_target[rate] +=
1869 wlc_user_txpwr_antport_to_rfport(pi, target_chan,
1870 band, rate);
1871 }
1872
1873 {
1874
1875 wlc_phy_txpower_sromlimit((wlc_phy_t *) pi, target_chan,
1876 &mintxpwr, &maxtxpwr, rate);
1877
Greg Kroah-Hartman7068c2f2010-10-08 11:34:59 -07001878 maxtxpwr = min(maxtxpwr, pi->txpwr_limit[rate]);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001879
1880 maxtxpwr =
1881 (maxtxpwr > pactrl) ? (maxtxpwr - pactrl) : 0;
1882
1883 maxtxpwr = (maxtxpwr > 6) ? (maxtxpwr - 6) : 0;
1884
Greg Kroah-Hartman7068c2f2010-10-08 11:34:59 -07001885 maxtxpwr = min(maxtxpwr, tx_pwr_target[rate]);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001886
1887 if (pi->txpwr_percent <= 100)
1888 maxtxpwr = (maxtxpwr * pi->txpwr_percent) / 100;
1889
Greg Kroah-Hartman3ea2f4d2010-10-08 11:39:43 -07001890 tx_pwr_target[rate] = max(maxtxpwr, mintxpwr);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001891 }
1892
1893 tx_pwr_target[rate] =
Greg Kroah-Hartman7068c2f2010-10-08 11:34:59 -07001894 min(tx_pwr_target[rate], pi->txpwr_env_limit[rate]);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001895
1896 if (tx_pwr_target[rate] > tx_pwr_max)
1897 tx_pwr_max_rate_ind = rate;
1898
Greg Kroah-Hartman3ea2f4d2010-10-08 11:39:43 -07001899 tx_pwr_max = max(tx_pwr_max, tx_pwr_target[rate]);
Greg Kroah-Hartman7068c2f2010-10-08 11:34:59 -07001900 tx_pwr_min = min(tx_pwr_min, tx_pwr_target[rate]);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001901 }
1902
Brett Rudley9249ede2010-11-30 20:09:49 -08001903 memset(pi->tx_power_offset, 0, sizeof(pi->tx_power_offset));
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001904 pi->tx_power_max = tx_pwr_max;
1905 pi->tx_power_min = tx_pwr_min;
1906 pi->tx_power_max_rate_ind = tx_pwr_max_rate_ind;
1907 for (rate = 0; rate < max_num_rate; rate++) {
1908
1909 pi->tx_power_target[rate] = tx_pwr_target[rate];
1910
1911 if (!pi->hwpwrctrl || ISNPHY(pi)) {
1912 pi->tx_power_offset[rate] =
1913 pi->tx_power_max - pi->tx_power_target[rate];
1914 } else {
1915 pi->tx_power_offset[rate] =
1916 pi->tx_power_target[rate] - pi->tx_power_min;
1917 }
1918 }
1919
1920 txpwr_recalc_fn = pi->pi_fptr.txpwrrecalc;
1921 if (txpwr_recalc_fn)
1922 (*txpwr_recalc_fn) (pi);
1923}
1924
1925void
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04001926wlc_phy_txpower_reg_limit_calc(phy_info_t *pi, struct txpwr_limits *txpwr,
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001927 chanspec_t chanspec)
1928{
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07001929 u8 tmp_txpwr_limit[2 * WLC_NUM_RATES_OFDM];
1930 u8 *txpwr_ptr1 = NULL, *txpwr_ptr2 = NULL;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001931 int rate_start_index = 0, rate1, rate2, k;
1932
1933 for (rate1 = WL_TX_POWER_CCK_FIRST, rate2 = 0;
1934 rate2 < WL_TX_POWER_CCK_NUM; rate1++, rate2++)
1935 pi->txpwr_limit[rate1] = txpwr->cck[rate2];
1936
1937 for (rate1 = WL_TX_POWER_OFDM_FIRST, rate2 = 0;
1938 rate2 < WL_TX_POWER_OFDM_NUM; rate1++, rate2++)
1939 pi->txpwr_limit[rate1] = txpwr->ofdm[rate2];
1940
1941 if (ISNPHY(pi)) {
1942
1943 for (k = 0; k < 4; k++) {
1944 switch (k) {
1945 case 0:
1946
1947 txpwr_ptr1 = txpwr->mcs_20_siso;
1948 txpwr_ptr2 = txpwr->ofdm;
1949 rate_start_index = WL_TX_POWER_OFDM_FIRST;
1950 break;
1951 case 1:
1952
1953 txpwr_ptr1 = txpwr->mcs_20_cdd;
1954 txpwr_ptr2 = txpwr->ofdm_cdd;
1955 rate_start_index = WL_TX_POWER_OFDM20_CDD_FIRST;
1956 break;
1957 case 2:
1958
1959 txpwr_ptr1 = txpwr->mcs_40_siso;
1960 txpwr_ptr2 = txpwr->ofdm_40_siso;
1961 rate_start_index =
1962 WL_TX_POWER_OFDM40_SISO_FIRST;
1963 break;
1964 case 3:
1965
1966 txpwr_ptr1 = txpwr->mcs_40_cdd;
1967 txpwr_ptr2 = txpwr->ofdm_40_cdd;
1968 rate_start_index = WL_TX_POWER_OFDM40_CDD_FIRST;
1969 break;
1970 }
1971
1972 for (rate2 = 0; rate2 < WLC_NUM_RATES_OFDM; rate2++) {
1973 tmp_txpwr_limit[rate2] = 0;
1974 tmp_txpwr_limit[WLC_NUM_RATES_OFDM + rate2] =
1975 txpwr_ptr1[rate2];
1976 }
1977 wlc_phy_mcs_to_ofdm_powers_nphy(tmp_txpwr_limit, 0,
1978 WLC_NUM_RATES_OFDM - 1,
1979 WLC_NUM_RATES_OFDM);
1980 for (rate1 = rate_start_index, rate2 = 0;
1981 rate2 < WLC_NUM_RATES_OFDM; rate1++, rate2++)
1982 pi->txpwr_limit[rate1] =
Greg Kroah-Hartman7068c2f2010-10-08 11:34:59 -07001983 min(txpwr_ptr2[rate2],
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001984 tmp_txpwr_limit[rate2]);
1985 }
1986
1987 for (k = 0; k < 4; k++) {
1988 switch (k) {
1989 case 0:
1990
1991 txpwr_ptr1 = txpwr->ofdm;
1992 txpwr_ptr2 = txpwr->mcs_20_siso;
1993 rate_start_index = WL_TX_POWER_MCS20_SISO_FIRST;
1994 break;
1995 case 1:
1996
1997 txpwr_ptr1 = txpwr->ofdm_cdd;
1998 txpwr_ptr2 = txpwr->mcs_20_cdd;
1999 rate_start_index = WL_TX_POWER_MCS20_CDD_FIRST;
2000 break;
2001 case 2:
2002
2003 txpwr_ptr1 = txpwr->ofdm_40_siso;
2004 txpwr_ptr2 = txpwr->mcs_40_siso;
2005 rate_start_index = WL_TX_POWER_MCS40_SISO_FIRST;
2006 break;
2007 case 3:
2008
2009 txpwr_ptr1 = txpwr->ofdm_40_cdd;
2010 txpwr_ptr2 = txpwr->mcs_40_cdd;
2011 rate_start_index = WL_TX_POWER_MCS40_CDD_FIRST;
2012 break;
2013 }
2014 for (rate2 = 0; rate2 < WLC_NUM_RATES_OFDM; rate2++) {
2015 tmp_txpwr_limit[rate2] = 0;
2016 tmp_txpwr_limit[WLC_NUM_RATES_OFDM + rate2] =
2017 txpwr_ptr1[rate2];
2018 }
2019 wlc_phy_ofdm_to_mcs_powers_nphy(tmp_txpwr_limit, 0,
2020 WLC_NUM_RATES_OFDM - 1,
2021 WLC_NUM_RATES_OFDM);
2022 for (rate1 = rate_start_index, rate2 = 0;
2023 rate2 < WLC_NUM_RATES_MCS_1_STREAM;
2024 rate1++, rate2++)
2025 pi->txpwr_limit[rate1] =
Greg Kroah-Hartman7068c2f2010-10-08 11:34:59 -07002026 min(txpwr_ptr2[rate2],
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002027 tmp_txpwr_limit[rate2]);
2028 }
2029
2030 for (k = 0; k < 2; k++) {
2031 switch (k) {
2032 case 0:
2033
2034 rate_start_index = WL_TX_POWER_MCS20_STBC_FIRST;
2035 txpwr_ptr1 = txpwr->mcs_20_stbc;
2036 break;
2037 case 1:
2038
2039 rate_start_index = WL_TX_POWER_MCS40_STBC_FIRST;
2040 txpwr_ptr1 = txpwr->mcs_40_stbc;
2041 break;
2042 }
2043 for (rate1 = rate_start_index, rate2 = 0;
2044 rate2 < WLC_NUM_RATES_MCS_1_STREAM;
2045 rate1++, rate2++)
2046 pi->txpwr_limit[rate1] = txpwr_ptr1[rate2];
2047 }
2048
2049 for (k = 0; k < 2; k++) {
2050 switch (k) {
2051 case 0:
2052
2053 rate_start_index = WL_TX_POWER_MCS20_SDM_FIRST;
2054 txpwr_ptr1 = txpwr->mcs_20_mimo;
2055 break;
2056 case 1:
2057
2058 rate_start_index = WL_TX_POWER_MCS40_SDM_FIRST;
2059 txpwr_ptr1 = txpwr->mcs_40_mimo;
2060 break;
2061 }
2062 for (rate1 = rate_start_index, rate2 = 0;
2063 rate2 < WLC_NUM_RATES_MCS_2_STREAM;
2064 rate1++, rate2++)
2065 pi->txpwr_limit[rate1] = txpwr_ptr1[rate2];
2066 }
2067
2068 pi->txpwr_limit[WL_TX_POWER_MCS_32] = txpwr->mcs32;
2069
2070 pi->txpwr_limit[WL_TX_POWER_MCS40_CDD_FIRST] =
Greg Kroah-Hartman7068c2f2010-10-08 11:34:59 -07002071 min(pi->txpwr_limit[WL_TX_POWER_MCS40_CDD_FIRST],
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002072 pi->txpwr_limit[WL_TX_POWER_MCS_32]);
2073 pi->txpwr_limit[WL_TX_POWER_MCS_32] =
2074 pi->txpwr_limit[WL_TX_POWER_MCS40_CDD_FIRST];
2075 }
2076}
2077
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07002078void wlc_phy_txpwr_percent_set(wlc_phy_t *ppi, u8 txpwr_percent)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002079{
2080 phy_info_t *pi = (phy_info_t *) ppi;
2081
2082 pi->txpwr_percent = txpwr_percent;
2083}
2084
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -07002085void wlc_phy_machwcap_set(wlc_phy_t *ppi, u32 machwcap)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002086{
2087 phy_info_t *pi = (phy_info_t *) ppi;
2088
2089 pi->sh->machwcap = machwcap;
2090}
2091
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04002092void wlc_phy_runbist_config(wlc_phy_t *ppi, bool start_end)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002093{
2094 phy_info_t *pi = (phy_info_t *) ppi;
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -07002095 u16 rxc;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002096 rxc = 0;
2097
2098 if (start_end == ON) {
2099 if (!ISNPHY(pi))
2100 return;
2101
2102 if (NREV_IS(pi->pubpi.phy_rev, 3)
2103 || NREV_IS(pi->pubpi.phy_rev, 4)) {
2104 W_REG(pi->sh->osh, &pi->regs->phyregaddr, 0xa0);
2105 (void)R_REG(pi->sh->osh, &pi->regs->phyregaddr);
2106 rxc = R_REG(pi->sh->osh, &pi->regs->phyregdata);
2107 W_REG(pi->sh->osh, &pi->regs->phyregdata,
2108 (0x1 << 15) | rxc);
2109 }
2110 } else {
2111 if (NREV_IS(pi->pubpi.phy_rev, 3)
2112 || NREV_IS(pi->pubpi.phy_rev, 4)) {
2113 W_REG(pi->sh->osh, &pi->regs->phyregaddr, 0xa0);
2114 (void)R_REG(pi->sh->osh, &pi->regs->phyregaddr);
2115 W_REG(pi->sh->osh, &pi->regs->phyregdata, rxc);
2116 }
2117
2118 wlc_phy_por_inform(ppi);
2119 }
2120}
2121
2122void
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04002123wlc_phy_txpower_limit_set(wlc_phy_t *ppi, struct txpwr_limits *txpwr,
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002124 chanspec_t chanspec)
2125{
2126 phy_info_t *pi = (phy_info_t *) ppi;
2127
2128 wlc_phy_txpower_reg_limit_calc(pi, txpwr, chanspec);
2129
2130 if (ISLCNPHY(pi)) {
2131 int i, j;
2132 for (i = TXP_FIRST_OFDM_20_CDD, j = 0;
2133 j < WLC_NUM_RATES_MCS_1_STREAM; i++, j++) {
2134 if (txpwr->mcs_20_siso[j])
2135 pi->txpwr_limit[i] = txpwr->mcs_20_siso[j];
2136 else
2137 pi->txpwr_limit[i] = txpwr->ofdm[j];
2138 }
2139 }
2140
2141 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2142
2143 wlc_phy_txpower_recalc_target(pi);
2144 wlc_phy_cal_txpower_recalc_sw(pi);
2145 wlapi_enable_mac(pi->sh->physhim);
2146}
2147
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04002148void wlc_phy_ofdm_rateset_war(wlc_phy_t *pih, bool war)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002149{
2150 phy_info_t *pi = (phy_info_t *) pih;
2151
2152 pi->ofdm_rateset_war = war;
2153}
2154
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04002155void wlc_phy_bf_preempt_enable(wlc_phy_t *pih, bool bf_preempt)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002156{
2157 phy_info_t *pi = (phy_info_t *) pih;
2158
2159 pi->bf_preempt_4306 = bf_preempt;
2160}
2161
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04002162void wlc_phy_txpower_update_shm(phy_info_t *pi)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002163{
2164 int j;
2165 if (ISNPHY(pi)) {
2166 ASSERT(0);
2167 return;
2168 }
2169
2170 if (!pi->sh->clk)
2171 return;
2172
2173 if (pi->hwpwrctrl) {
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -07002174 u16 offset;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002175
2176 wlapi_bmac_write_shm(pi->sh->physhim, M_TXPWR_MAX, 63);
2177 wlapi_bmac_write_shm(pi->sh->physhim, M_TXPWR_N,
2178 1 << NUM_TSSI_FRAMES);
2179
2180 wlapi_bmac_write_shm(pi->sh->physhim, M_TXPWR_TARGET,
2181 pi->tx_power_min << NUM_TSSI_FRAMES);
2182
2183 wlapi_bmac_write_shm(pi->sh->physhim, M_TXPWR_CUR,
2184 pi->hwpwr_txcur);
2185
2186 for (j = TXP_FIRST_OFDM; j <= TXP_LAST_OFDM; j++) {
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07002187 const u8 ucode_ofdm_rates[] = {
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002188 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c
2189 };
2190 offset = wlapi_bmac_rate_shm_offset(pi->sh->physhim,
2191 ucode_ofdm_rates[j -
2192 TXP_FIRST_OFDM]);
2193 wlapi_bmac_write_shm(pi->sh->physhim, offset + 6,
2194 pi->tx_power_offset[j]);
2195 wlapi_bmac_write_shm(pi->sh->physhim, offset + 14,
2196 -(pi->tx_power_offset[j] / 2));
2197 }
2198
2199 wlapi_bmac_mhf(pi->sh->physhim, MHF2, MHF2_HWPWRCTL,
2200 MHF2_HWPWRCTL, WLC_BAND_ALL);
2201 } else {
2202 int i;
2203
2204 for (i = TXP_FIRST_OFDM; i <= TXP_LAST_OFDM; i++)
2205 pi->tx_power_offset[i] =
Greg Kroah-Hartmane18d5312010-10-08 11:59:06 -07002206 (u8) roundup(pi->tx_power_offset[i], 8);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002207 wlapi_bmac_write_shm(pi->sh->physhim, M_OFDM_OFFSET,
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -07002208 (u16) ((pi->
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002209 tx_power_offset[TXP_FIRST_OFDM]
2210 + 7) >> 3));
2211 }
2212}
2213
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04002214bool wlc_phy_txpower_hw_ctrl_get(wlc_phy_t *ppi)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002215{
2216 phy_info_t *pi = (phy_info_t *) ppi;
2217
2218 if (ISNPHY(pi)) {
2219 return pi->nphy_txpwrctrl;
2220 } else {
2221 return pi->hwpwrctrl;
2222 }
2223}
2224
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04002225void wlc_phy_txpower_hw_ctrl_set(wlc_phy_t *ppi, bool hwpwrctrl)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002226{
2227 phy_info_t *pi = (phy_info_t *) ppi;
2228 bool cur_hwpwrctrl = pi->hwpwrctrl;
2229 bool suspend;
2230
2231 if (!pi->hwpwrctrl_capable) {
2232 return;
2233 }
2234
2235 pi->hwpwrctrl = hwpwrctrl;
2236 pi->nphy_txpwrctrl = hwpwrctrl;
2237 pi->txpwrctrl = hwpwrctrl;
2238
2239 if (ISNPHY(pi)) {
2240 suspend =
2241 (0 ==
2242 (R_REG(pi->sh->osh, &pi->regs->maccontrol) & MCTL_EN_MAC));
2243 if (!suspend)
2244 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2245
2246 wlc_phy_txpwrctrl_enable_nphy(pi, pi->nphy_txpwrctrl);
2247 if (pi->nphy_txpwrctrl == PHY_TPC_HW_OFF) {
2248 wlc_phy_txpwr_fixpower_nphy(pi);
2249 } else {
2250
2251 mod_phy_reg(pi, 0x1e7, (0x7f << 0),
2252 pi->saved_txpwr_idx);
2253 }
2254
2255 if (!suspend)
2256 wlapi_enable_mac(pi->sh->physhim);
2257 } else if (hwpwrctrl != cur_hwpwrctrl) {
2258
2259 return;
2260 }
2261}
2262
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04002263void wlc_phy_txpower_ipa_upd(phy_info_t *pi)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002264{
2265
2266 if (NREV_GE(pi->pubpi.phy_rev, 3)) {
2267 pi->ipa2g_on = (pi->srom_fem2g.extpagain == 2);
2268 pi->ipa5g_on = (pi->srom_fem5g.extpagain == 2);
2269 } else {
Greg Kroah-Hartman0965ae82010-10-12 12:50:15 -07002270 pi->ipa2g_on = false;
2271 pi->ipa5g_on = false;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002272 }
2273}
2274
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -07002275static u32 wlc_phy_txpower_est_power_nphy(phy_info_t *pi);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002276
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -07002277static u32 wlc_phy_txpower_est_power_nphy(phy_info_t *pi)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002278{
Greg Kroah-Hartmane59fe082010-10-07 17:08:21 -07002279 s16 tx0_status, tx1_status;
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -07002280 u16 estPower1, estPower2;
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07002281 u8 pwr0, pwr1, adj_pwr0, adj_pwr1;
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -07002282 u32 est_pwr;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002283
2284 estPower1 = read_phy_reg(pi, 0x118);
2285 estPower2 = read_phy_reg(pi, 0x119);
2286
2287 if ((estPower1 & (0x1 << 8))
2288 == (0x1 << 8)) {
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07002289 pwr0 = (u8) (estPower1 & (0xff << 0))
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002290 >> 0;
2291 } else {
2292 pwr0 = 0x80;
2293 }
2294
2295 if ((estPower2 & (0x1 << 8))
2296 == (0x1 << 8)) {
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07002297 pwr1 = (u8) (estPower2 & (0xff << 0))
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002298 >> 0;
2299 } else {
2300 pwr1 = 0x80;
2301 }
2302
2303 tx0_status = read_phy_reg(pi, 0x1ed);
2304 tx1_status = read_phy_reg(pi, 0x1ee);
2305
2306 if ((tx0_status & (0x1 << 15))
2307 == (0x1 << 15)) {
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07002308 adj_pwr0 = (u8) (tx0_status & (0xff << 0))
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002309 >> 0;
2310 } else {
2311 adj_pwr0 = 0x80;
2312 }
2313 if ((tx1_status & (0x1 << 15))
2314 == (0x1 << 15)) {
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07002315 adj_pwr1 = (u8) (tx1_status & (0xff << 0))
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002316 >> 0;
2317 } else {
2318 adj_pwr1 = 0x80;
2319 }
2320
2321 est_pwr =
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -07002322 (u32) ((pwr0 << 24) | (pwr1 << 16) | (adj_pwr0 << 8) | adj_pwr1);
Jason Cooper90ea2292010-09-14 09:45:32 -04002323 return est_pwr;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002324}
2325
2326void
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04002327wlc_phy_txpower_get_current(wlc_phy_t *ppi, tx_power_t *power, uint channel)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002328{
2329 phy_info_t *pi = (phy_info_t *) ppi;
2330 uint rate, num_rates;
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07002331 u8 min_pwr, max_pwr;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002332
2333#if WL_TX_POWER_RATES != TXP_NUM_RATES
2334#error "tx_power_t struct out of sync with this fn"
2335#endif
2336
2337 if (ISNPHY(pi)) {
2338 power->rf_cores = 2;
2339 power->flags |= (WL_TX_POWER_F_MIMO);
2340 if (pi->nphy_txpwrctrl == PHY_TPC_HW_ON)
2341 power->flags |=
2342 (WL_TX_POWER_F_ENABLED | WL_TX_POWER_F_HW);
2343 } else if (ISLCNPHY(pi)) {
2344 power->rf_cores = 1;
2345 power->flags |= (WL_TX_POWER_F_SISO);
2346 if (pi->radiopwr_override == RADIOPWR_OVERRIDE_DEF)
2347 power->flags |= WL_TX_POWER_F_ENABLED;
2348 if (pi->hwpwrctrl)
2349 power->flags |= WL_TX_POWER_F_HW;
2350 }
2351
2352 num_rates = ((ISNPHY(pi)) ? (TXP_NUM_RATES) :
2353 ((ISLCNPHY(pi)) ?
2354 (TXP_LAST_OFDM_20_CDD + 1) : (TXP_LAST_OFDM + 1)));
2355
2356 for (rate = 0; rate < num_rates; rate++) {
2357 power->user_limit[rate] = pi->tx_user_target[rate];
2358 wlc_phy_txpower_sromlimit(ppi, channel, &min_pwr, &max_pwr,
2359 rate);
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07002360 power->board_limit[rate] = (u8) max_pwr;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002361 power->target[rate] = pi->tx_power_target[rate];
2362 }
2363
2364 if (ISNPHY(pi)) {
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -07002365 u32 est_pout;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002366
2367 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2368 wlc_phyreg_enter((wlc_phy_t *) pi);
2369 est_pout = wlc_phy_txpower_est_power_nphy(pi);
2370 wlc_phyreg_exit((wlc_phy_t *) pi);
2371 wlapi_enable_mac(pi->sh->physhim);
2372
2373 power->est_Pout[0] = (est_pout >> 8) & 0xff;
2374 power->est_Pout[1] = est_pout & 0xff;
2375
2376 power->est_Pout_act[0] = est_pout >> 24;
2377 power->est_Pout_act[1] = (est_pout >> 16) & 0xff;
2378
2379 if (power->est_Pout[0] == 0x80)
2380 power->est_Pout[0] = 0;
2381 if (power->est_Pout[1] == 0x80)
2382 power->est_Pout[1] = 0;
2383
2384 if (power->est_Pout_act[0] == 0x80)
2385 power->est_Pout_act[0] = 0;
2386 if (power->est_Pout_act[1] == 0x80)
2387 power->est_Pout_act[1] = 0;
2388
2389 power->est_Pout_cck = 0;
2390
2391 power->tx_power_max[0] = pi->tx_power_max;
2392 power->tx_power_max[1] = pi->tx_power_max;
2393
2394 power->tx_power_max_rate_ind[0] = pi->tx_power_max_rate_ind;
2395 power->tx_power_max_rate_ind[1] = pi->tx_power_max_rate_ind;
2396 } else if (!pi->hwpwrctrl) {
2397 } else if (pi->sh->up) {
2398
2399 wlc_phyreg_enter(ppi);
2400 if (ISLCNPHY(pi)) {
2401
2402 power->tx_power_max[0] = pi->tx_power_max;
2403 power->tx_power_max[1] = pi->tx_power_max;
2404
2405 power->tx_power_max_rate_ind[0] =
2406 pi->tx_power_max_rate_ind;
2407 power->tx_power_max_rate_ind[1] =
2408 pi->tx_power_max_rate_ind;
2409
2410 if (wlc_phy_tpc_isenabled_lcnphy(pi))
2411 power->flags |=
2412 (WL_TX_POWER_F_HW | WL_TX_POWER_F_ENABLED);
2413 else
2414 power->flags &=
2415 ~(WL_TX_POWER_F_HW | WL_TX_POWER_F_ENABLED);
2416
Greg Kroah-Hartman562c8852010-10-05 11:04:17 -07002417 wlc_lcnphy_get_tssi(pi, (s8 *) &power->est_Pout[0],
2418 (s8 *) &power->est_Pout_cck);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002419 }
2420 wlc_phyreg_exit(ppi);
2421 }
2422}
2423
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07002424void wlc_phy_antsel_type_set(wlc_phy_t *ppi, u8 antsel_type)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002425{
2426 phy_info_t *pi = (phy_info_t *) ppi;
2427
2428 pi->antsel_type = antsel_type;
2429}
2430
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04002431bool wlc_phy_test_ison(wlc_phy_t *ppi)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002432{
2433 phy_info_t *pi = (phy_info_t *) ppi;
2434
Jason Cooper90ea2292010-09-14 09:45:32 -04002435 return pi->phytest_on;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002436}
2437
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07002438bool wlc_phy_ant_rxdiv_get(wlc_phy_t *ppi, u8 *pval)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002439{
2440 phy_info_t *pi = (phy_info_t *) ppi;
Greg Kroah-Hartman0f0881b2010-10-12 12:15:18 -07002441 bool ret = true;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002442
2443 wlc_phyreg_enter(ppi);
2444
2445 if (ISNPHY(pi)) {
2446
Greg Kroah-Hartman0965ae82010-10-12 12:50:15 -07002447 ret = false;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002448 } else if (ISLCNPHY(pi)) {
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -07002449 u16 crsctrl = read_phy_reg(pi, 0x410);
2450 u16 div = crsctrl & (0x1 << 1);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002451 *pval = (div | ((crsctrl & (0x1 << 0)) ^ (div >> 1)));
2452 }
2453
2454 wlc_phyreg_exit(ppi);
2455
2456 return ret;
2457}
2458
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07002459void wlc_phy_ant_rxdiv_set(wlc_phy_t *ppi, u8 val)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002460{
2461 phy_info_t *pi = (phy_info_t *) ppi;
2462 bool suspend;
2463
2464 pi->sh->rx_antdiv = val;
2465
2466 if (!(ISNPHY(pi) && D11REV_IS(pi->sh->corerev, 16))) {
2467 if (val > ANT_RX_DIV_FORCE_1)
2468 wlapi_bmac_mhf(pi->sh->physhim, MHF1, MHF1_ANTDIV,
2469 MHF1_ANTDIV, WLC_BAND_ALL);
2470 else
2471 wlapi_bmac_mhf(pi->sh->physhim, MHF1, MHF1_ANTDIV, 0,
2472 WLC_BAND_ALL);
2473 }
2474
2475 if (ISNPHY(pi)) {
2476
2477 return;
2478 }
2479
2480 if (!pi->sh->clk)
2481 return;
2482
2483 suspend =
2484 (0 == (R_REG(pi->sh->osh, &pi->regs->maccontrol) & MCTL_EN_MAC));
2485 if (!suspend)
2486 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2487
2488 if (ISLCNPHY(pi)) {
2489 if (val > ANT_RX_DIV_FORCE_1) {
2490 mod_phy_reg(pi, 0x410, (0x1 << 1), 0x01 << 1);
2491 mod_phy_reg(pi, 0x410,
2492 (0x1 << 0),
2493 ((ANT_RX_DIV_START_1 == val) ? 1 : 0) << 0);
2494 } else {
2495 mod_phy_reg(pi, 0x410, (0x1 << 1), 0x00 << 1);
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -07002496 mod_phy_reg(pi, 0x410, (0x1 << 0), (u16) val << 0);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002497 }
2498 } else {
2499 ASSERT(0);
2500 }
2501
2502 if (!suspend)
2503 wlapi_enable_mac(pi->sh->physhim);
2504
2505 return;
2506}
2507
2508static bool
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -07002509wlc_phy_noise_calc_phy(phy_info_t *pi, u32 *cmplx_pwr, s8 *pwr_ant)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002510{
Greg Kroah-Hartman562c8852010-10-05 11:04:17 -07002511 s8 cmplx_pwr_dbm[PHY_CORE_MAX];
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07002512 u8 i;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002513
Brett Rudley9249ede2010-11-30 20:09:49 -08002514 memset((u8 *) cmplx_pwr_dbm, 0, sizeof(cmplx_pwr_dbm));
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002515 ASSERT(pi->pubpi.phy_corenum <= PHY_CORE_MAX);
2516 wlc_phy_compute_dB(cmplx_pwr, cmplx_pwr_dbm, pi->pubpi.phy_corenum);
2517
2518 for (i = 0; i < pi->pubpi.phy_corenum; i++) {
2519 if (NREV_GE(pi->pubpi.phy_rev, 3))
Greg Kroah-Hartman562c8852010-10-05 11:04:17 -07002520 cmplx_pwr_dbm[i] += (s8) PHY_NOISE_OFFSETFACT_4322;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002521 else
2522
Greg Kroah-Hartman562c8852010-10-05 11:04:17 -07002523 cmplx_pwr_dbm[i] += (s8) (16 - (15) * 3 - 70);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002524 }
2525
2526 for (i = 0; i < pi->pubpi.phy_corenum; i++) {
2527 pi->nphy_noise_win[i][pi->nphy_noise_index] = cmplx_pwr_dbm[i];
2528 pwr_ant[i] = cmplx_pwr_dbm[i];
2529 }
2530 pi->nphy_noise_index =
2531 MODINC_POW2(pi->nphy_noise_index, PHY_NOISE_WINDOW_SZ);
Greg Kroah-Hartman0f0881b2010-10-12 12:15:18 -07002532 return true;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002533}
2534
2535static void
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07002536wlc_phy_noise_sample_request(wlc_phy_t *pih, u8 reason, u8 ch)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002537{
2538 phy_info_t *pi = (phy_info_t *) pih;
Greg Kroah-Hartman562c8852010-10-05 11:04:17 -07002539 s8 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002540 bool sampling_in_progress = (pi->phynoise_state != 0);
Greg Kroah-Hartman0f0881b2010-10-12 12:15:18 -07002541 bool wait_for_intr = true;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002542
2543 if (NORADIO_ENAB(pi->pubpi)) {
2544 return;
2545 }
2546
2547 switch (reason) {
2548 case PHY_NOISE_SAMPLE_MON:
2549
2550 pi->phynoise_chan_watchdog = ch;
2551 pi->phynoise_state |= PHY_NOISE_STATE_MON;
2552
2553 break;
2554
2555 case PHY_NOISE_SAMPLE_EXTERNAL:
2556
2557 pi->phynoise_state |= PHY_NOISE_STATE_EXTERNAL;
2558 break;
2559
2560 default:
2561 ASSERT(0);
2562 break;
2563 }
2564
2565 if (sampling_in_progress)
2566 return;
2567
2568 pi->phynoise_now = pi->sh->now;
2569
2570 if (pi->phy_fixed_noise) {
2571 if (ISNPHY(pi)) {
2572 pi->nphy_noise_win[WL_ANT_IDX_1][pi->nphy_noise_index] =
2573 PHY_NOISE_FIXED_VAL_NPHY;
2574 pi->nphy_noise_win[WL_ANT_IDX_2][pi->nphy_noise_index] =
2575 PHY_NOISE_FIXED_VAL_NPHY;
2576 pi->nphy_noise_index = MODINC_POW2(pi->nphy_noise_index,
2577 PHY_NOISE_WINDOW_SZ);
2578
2579 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;
2580 } else {
2581
2582 noise_dbm = PHY_NOISE_FIXED_VAL;
2583 }
2584
Greg Kroah-Hartman0965ae82010-10-12 12:50:15 -07002585 wait_for_intr = false;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002586 goto done;
2587 }
2588
2589 if (ISLCNPHY(pi)) {
2590 if (!pi->phynoise_polling
2591 || (reason == PHY_NOISE_SAMPLE_EXTERNAL)) {
2592 wlapi_bmac_write_shm(pi->sh->physhim, M_JSSI_0, 0);
2593 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP0, 0);
2594 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP1, 0);
2595 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP2, 0);
2596 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP3, 0);
2597
2598 OR_REG(pi->sh->osh, &pi->regs->maccommand,
2599 MCMD_BG_NOISE);
2600 } else {
2601 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2602 wlc_lcnphy_deaf_mode(pi, (bool) 0);
Greg Kroah-Hartman562c8852010-10-05 11:04:17 -07002603 noise_dbm = (s8) wlc_lcnphy_rx_signal_power(pi, 20);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002604 wlc_lcnphy_deaf_mode(pi, (bool) 1);
2605 wlapi_enable_mac(pi->sh->physhim);
Greg Kroah-Hartman0965ae82010-10-12 12:50:15 -07002606 wait_for_intr = false;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002607 }
2608 } else if (ISNPHY(pi)) {
2609 if (!pi->phynoise_polling
2610 || (reason == PHY_NOISE_SAMPLE_EXTERNAL)) {
2611
2612 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP0, 0);
2613 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP1, 0);
2614 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP2, 0);
2615 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP3, 0);
2616
2617 OR_REG(pi->sh->osh, &pi->regs->maccommand,
2618 MCMD_BG_NOISE);
2619 } else {
2620 phy_iq_est_t est[PHY_CORE_MAX];
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -07002621 u32 cmplx_pwr[PHY_CORE_MAX];
Greg Kroah-Hartman562c8852010-10-05 11:04:17 -07002622 s8 noise_dbm_ant[PHY_CORE_MAX];
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -07002623 u16 log_num_samps, num_samps, classif_state = 0;
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07002624 u8 wait_time = 32;
2625 u8 wait_crs = 0;
2626 u8 i;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002627
Brett Rudley9249ede2010-11-30 20:09:49 -08002628 memset((u8 *) est, 0, sizeof(est));
2629 memset((u8 *) cmplx_pwr, 0, sizeof(cmplx_pwr));
2630 memset((u8 *) noise_dbm_ant, 0, sizeof(noise_dbm_ant));
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002631
2632 log_num_samps = PHY_NOISE_SAMPLE_LOG_NUM_NPHY;
2633 num_samps = 1 << log_num_samps;
2634
2635 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2636 classif_state = wlc_phy_classifier_nphy(pi, 0, 0);
2637 wlc_phy_classifier_nphy(pi, 3, 0);
2638 wlc_phy_rx_iq_est_nphy(pi, est, num_samps, wait_time,
2639 wait_crs);
2640 wlc_phy_classifier_nphy(pi, (0x7 << 0), classif_state);
2641 wlapi_enable_mac(pi->sh->physhim);
2642
2643 for (i = 0; i < pi->pubpi.phy_corenum; i++)
2644 cmplx_pwr[i] =
2645 (est[i].i_pwr +
2646 est[i].q_pwr) >> log_num_samps;
2647
2648 wlc_phy_noise_calc_phy(pi, cmplx_pwr, noise_dbm_ant);
2649
2650 for (i = 0; i < pi->pubpi.phy_corenum; i++) {
2651 pi->nphy_noise_win[i][pi->nphy_noise_index] =
2652 noise_dbm_ant[i];
2653
2654 if (noise_dbm_ant[i] > noise_dbm)
2655 noise_dbm = noise_dbm_ant[i];
2656 }
2657 pi->nphy_noise_index = MODINC_POW2(pi->nphy_noise_index,
2658 PHY_NOISE_WINDOW_SZ);
2659
Greg Kroah-Hartman0965ae82010-10-12 12:50:15 -07002660 wait_for_intr = false;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002661 }
2662 }
2663
2664 done:
2665
2666 if (!wait_for_intr)
2667 wlc_phy_noise_cb(pi, ch, noise_dbm);
2668
2669}
2670
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04002671void wlc_phy_noise_sample_request_external(wlc_phy_t *pih)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002672{
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07002673 u8 channel;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002674
2675 channel = CHSPEC_CHANNEL(wlc_phy_chanspec_get(pih));
2676
2677 wlc_phy_noise_sample_request(pih, PHY_NOISE_SAMPLE_EXTERNAL, channel);
2678}
2679
Greg Kroah-Hartman562c8852010-10-05 11:04:17 -07002680static void wlc_phy_noise_cb(phy_info_t *pi, u8 channel, s8 noise_dbm)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002681{
2682 if (!pi->phynoise_state)
2683 return;
2684
2685 if (pi->phynoise_state & PHY_NOISE_STATE_MON) {
2686 if (pi->phynoise_chan_watchdog == channel) {
2687 pi->sh->phy_noise_window[pi->sh->phy_noise_index] =
2688 noise_dbm;
2689 pi->sh->phy_noise_index =
2690 MODINC(pi->sh->phy_noise_index, MA_WINDOW_SZ);
2691 }
2692 pi->phynoise_state &= ~PHY_NOISE_STATE_MON;
2693 }
2694
2695 if (pi->phynoise_state & PHY_NOISE_STATE_EXTERNAL) {
2696 pi->phynoise_state &= ~PHY_NOISE_STATE_EXTERNAL;
2697 }
2698
2699}
2700
Greg Kroah-Hartman562c8852010-10-05 11:04:17 -07002701static s8 wlc_phy_noise_read_shmem(phy_info_t *pi)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002702{
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -07002703 u32 cmplx_pwr[PHY_CORE_MAX];
Greg Kroah-Hartman562c8852010-10-05 11:04:17 -07002704 s8 noise_dbm_ant[PHY_CORE_MAX];
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -07002705 u16 lo, hi;
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -07002706 u32 cmplx_pwr_tot = 0;
Greg Kroah-Hartman562c8852010-10-05 11:04:17 -07002707 s8 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07002708 u8 idx, core;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002709
2710 ASSERT(pi->pubpi.phy_corenum <= PHY_CORE_MAX);
Brett Rudley9249ede2010-11-30 20:09:49 -08002711 memset((u8 *) cmplx_pwr, 0, sizeof(cmplx_pwr));
2712 memset((u8 *) noise_dbm_ant, 0, sizeof(noise_dbm_ant));
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002713
2714 for (idx = 0, core = 0; core < pi->pubpi.phy_corenum; idx += 2, core++) {
2715 lo = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP(idx));
2716 hi = wlapi_bmac_read_shm(pi->sh->physhim,
2717 M_PWRIND_MAP(idx + 1));
2718 cmplx_pwr[core] = (hi << 16) + lo;
2719 cmplx_pwr_tot += cmplx_pwr[core];
2720 if (cmplx_pwr[core] == 0) {
2721 noise_dbm_ant[core] = PHY_NOISE_FIXED_VAL_NPHY;
2722 } else
2723 cmplx_pwr[core] >>= PHY_NOISE_SAMPLE_LOG_NUM_UCODE;
2724 }
2725
2726 if (cmplx_pwr_tot != 0)
2727 wlc_phy_noise_calc_phy(pi, cmplx_pwr, noise_dbm_ant);
2728
2729 for (core = 0; core < pi->pubpi.phy_corenum; core++) {
2730 pi->nphy_noise_win[core][pi->nphy_noise_index] =
2731 noise_dbm_ant[core];
2732
2733 if (noise_dbm_ant[core] > noise_dbm)
2734 noise_dbm = noise_dbm_ant[core];
2735 }
2736 pi->nphy_noise_index =
2737 MODINC_POW2(pi->nphy_noise_index, PHY_NOISE_WINDOW_SZ);
2738
2739 return noise_dbm;
2740
2741}
2742
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04002743void wlc_phy_noise_sample_intr(wlc_phy_t *pih)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002744{
2745 phy_info_t *pi = (phy_info_t *) pih;
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -07002746 u16 jssi_aux;
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07002747 u8 channel = 0;
Greg Kroah-Hartman562c8852010-10-05 11:04:17 -07002748 s8 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002749
2750 if (ISLCNPHY(pi)) {
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -07002751 u32 cmplx_pwr, cmplx_pwr0, cmplx_pwr1;
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -07002752 u16 lo, hi;
Greg Kroah-Hartman3e264162010-10-08 11:11:13 -07002753 s32 pwr_offset_dB, gain_dB;
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -07002754 u16 status_0, status_1;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002755
2756 jssi_aux = wlapi_bmac_read_shm(pi->sh->physhim, M_JSSI_AUX);
2757 channel = jssi_aux & D11_CURCHANNEL_MAX;
2758
2759 lo = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP0);
2760 hi = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP1);
2761 cmplx_pwr0 = (hi << 16) + lo;
2762
2763 lo = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP2);
2764 hi = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP3);
2765 cmplx_pwr1 = (hi << 16) + lo;
2766 cmplx_pwr = (cmplx_pwr0 + cmplx_pwr1) >> 6;
2767
2768 status_0 = 0x44;
2769 status_1 = wlapi_bmac_read_shm(pi->sh->physhim, M_JSSI_0);
2770 if ((cmplx_pwr > 0 && cmplx_pwr < 500)
2771 && ((status_1 & 0xc000) == 0x4000)) {
2772
2773 wlc_phy_compute_dB(&cmplx_pwr, &noise_dbm,
2774 pi->pubpi.phy_corenum);
2775 pwr_offset_dB = (read_phy_reg(pi, 0x434) & 0xFF);
2776 if (pwr_offset_dB > 127)
2777 pwr_offset_dB -= 256;
2778
Greg Kroah-Hartman562c8852010-10-05 11:04:17 -07002779 noise_dbm += (s8) (pwr_offset_dB - 30);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002780
2781 gain_dB = (status_0 & 0x1ff);
Greg Kroah-Hartman562c8852010-10-05 11:04:17 -07002782 noise_dbm -= (s8) (gain_dB);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002783 } else {
2784 noise_dbm = PHY_NOISE_FIXED_VAL_LCNPHY;
2785 }
2786 } else if (ISNPHY(pi)) {
2787
2788 jssi_aux = wlapi_bmac_read_shm(pi->sh->physhim, M_JSSI_AUX);
2789 channel = jssi_aux & D11_CURCHANNEL_MAX;
2790
2791 noise_dbm = wlc_phy_noise_read_shmem(pi);
2792 } else {
2793 ASSERT(0);
2794 }
2795
2796 wlc_phy_noise_cb(pi, channel, noise_dbm);
2797
2798}
2799
Greg Kroah-Hartman562c8852010-10-05 11:04:17 -07002800s8 lcnphy_gain_index_offset_for_pkt_rssi[] = {
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002801 8,
2802 8,
2803 8,
2804 8,
2805 8,
2806 8,
2807 8,
2808 9,
2809 10,
2810 8,
2811 8,
2812 7,
2813 7,
2814 1,
2815 2,
2816 2,
2817 2,
2818 2,
2819 2,
2820 2,
2821 2,
2822 2,
2823 2,
2824 2,
2825 2,
2826 2,
2827 2,
2828 2,
2829 2,
2830 2,
2831 2,
2832 2,
2833 1,
2834 1,
2835 0,
2836 0,
2837 0,
2838 0
2839};
2840
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -07002841void wlc_phy_compute_dB(u32 *cmplx_pwr, s8 *p_cmplx_pwr_dB, u8 core)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002842{
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07002843 u8 shift_ct, lsb, msb, secondmsb, i;
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -07002844 u32 tmp;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002845
2846 for (i = 0; i < core; i++) {
2847 tmp = cmplx_pwr[i];
2848 shift_ct = msb = secondmsb = 0;
2849 while (tmp != 0) {
2850 tmp = tmp >> 1;
2851 shift_ct++;
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07002852 lsb = (u8) (tmp & 1);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002853 if (lsb == 1)
2854 msb = shift_ct;
2855 }
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07002856 secondmsb = (u8) ((cmplx_pwr[i] >> (msb - 1)) & 1);
Greg Kroah-Hartman562c8852010-10-05 11:04:17 -07002857 p_cmplx_pwr_dB[i] = (s8) (3 * msb + 2 * secondmsb);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002858 }
2859}
2860
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04002861void BCMFASTPATH wlc_phy_rssi_compute(wlc_phy_t *pih, void *ctx)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002862{
2863 wlc_d11rxhdr_t *wlc_rxhdr = (wlc_d11rxhdr_t *) ctx;
2864 d11rxhdr_t *rxh = &wlc_rxhdr->rxhdr;
2865 int rssi = ltoh16(rxh->PhyRxStatus_1) & PRXS1_JSSI_MASK;
2866 uint radioid = pih->radioid;
2867 phy_info_t *pi = (phy_info_t *) pih;
2868
2869 if (NORADIO_ENAB(pi->pubpi)) {
2870 rssi = WLC_RSSI_INVALID;
2871 goto end;
2872 }
2873
2874 if ((pi->sh->corerev >= 11)
2875 && !(ltoh16(rxh->RxStatus2) & RXS_PHYRXST_VALID)) {
2876 rssi = WLC_RSSI_INVALID;
2877 goto end;
2878 }
2879
2880 if (ISLCNPHY(pi)) {
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07002881 u8 gidx = (ltoh16(rxh->PhyRxStatus_2) & 0xFC00) >> 10;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002882 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
2883
2884 if (rssi > 127)
2885 rssi -= 256;
2886
2887 rssi = rssi + lcnphy_gain_index_offset_for_pkt_rssi[gidx];
2888 if ((rssi > -46) && (gidx > 18))
2889 rssi = rssi + 7;
2890
2891 rssi = rssi + pi_lcn->lcnphy_pkteng_rssi_slope;
2892
2893 rssi = rssi + 2;
2894
2895 }
2896
2897 if (ISLCNPHY(pi)) {
2898
2899 if (rssi > 127)
2900 rssi -= 256;
2901 } else if (radioid == BCM2055_ID || radioid == BCM2056_ID
2902 || radioid == BCM2057_ID) {
2903 ASSERT(ISNPHY(pi));
2904 rssi = wlc_phy_rssi_compute_nphy(pi, wlc_rxhdr);
2905 } else {
2906 ASSERT((const char *)"Unknown radio" == NULL);
2907 }
2908
2909 end:
Greg Kroah-Hartman562c8852010-10-05 11:04:17 -07002910 wlc_rxhdr->rssi = (s8) rssi;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002911}
2912
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04002913void wlc_phy_freqtrack_start(wlc_phy_t *pih)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002914{
2915 return;
2916}
2917
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04002918void wlc_phy_freqtrack_end(wlc_phy_t *pih)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002919{
2920 return;
2921}
2922
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04002923void wlc_phy_set_deaf(wlc_phy_t *ppi, bool user_flag)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002924{
2925 phy_info_t *pi;
2926 pi = (phy_info_t *) ppi;
2927
2928 if (ISLCNPHY(pi))
Greg Kroah-Hartman0f0881b2010-10-12 12:15:18 -07002929 wlc_lcnphy_deaf_mode(pi, true);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002930 else if (ISNPHY(pi))
Greg Kroah-Hartman0f0881b2010-10-12 12:15:18 -07002931 wlc_nphy_deaf_mode(pi, true);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002932 else {
2933 ASSERT(0);
2934 }
2935}
2936
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04002937void wlc_phy_watchdog(wlc_phy_t *pih)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002938{
2939 phy_info_t *pi = (phy_info_t *) pih;
Greg Kroah-Hartman0965ae82010-10-12 12:50:15 -07002940 bool delay_phy_cal = false;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002941 pi->sh->now++;
2942
2943 if (!pi->watchdog_override)
2944 return;
2945
2946 if (!(SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi))) {
2947 wlc_phy_noise_sample_request((wlc_phy_t *) pi,
2948 PHY_NOISE_SAMPLE_MON,
2949 CHSPEC_CHANNEL(pi->
2950 radio_chanspec));
2951 }
2952
2953 if (pi->phynoise_state && (pi->sh->now - pi->phynoise_now) > 5) {
2954 pi->phynoise_state = 0;
2955 }
2956
2957 if ((!pi->phycal_txpower) ||
2958 ((pi->sh->now - pi->phycal_txpower) >= pi->sh->fast_timer)) {
2959
2960 if (!SCAN_INPROG_PHY(pi) && wlc_phy_cal_txpower_recalc_sw(pi)) {
2961 pi->phycal_txpower = pi->sh->now;
2962 }
2963 }
2964
2965 if (NORADIO_ENAB(pi->pubpi))
2966 return;
2967
2968 if ((SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi)
2969 || ASSOC_INPROG_PHY(pi)))
2970 return;
2971
2972 if (ISNPHY(pi) && !pi->disable_percal && !delay_phy_cal) {
2973
2974 if ((pi->nphy_perical != PHY_PERICAL_DISABLE) &&
2975 (pi->nphy_perical != PHY_PERICAL_MANUAL) &&
2976 ((pi->sh->now - pi->nphy_perical_last) >=
2977 pi->sh->glacial_timer))
2978 wlc_phy_cal_perical((wlc_phy_t *) pi,
2979 PHY_PERICAL_WATCHDOG);
2980
2981 wlc_phy_txpwr_papd_cal_nphy(pi);
2982 }
2983
2984 if (ISLCNPHY(pi)) {
2985 if (pi->phy_forcecal ||
2986 ((pi->sh->now - pi->phy_lastcal) >=
2987 pi->sh->glacial_timer)) {
2988 if (!(SCAN_RM_IN_PROGRESS(pi) || ASSOC_INPROG_PHY(pi)))
2989 wlc_lcnphy_calib_modes(pi,
2990 LCNPHY_PERICAL_TEMPBASED_TXPWRCTRL);
2991 if (!
2992 (SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi)
2993 || ASSOC_INPROG_PHY(pi)
2994 || pi->carrier_suppr_disable
Brett Rudleya9a60732010-10-08 17:35:02 -07002995 || pi->disable_percal))
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002996 wlc_lcnphy_calib_modes(pi,
2997 PHY_PERICAL_WATCHDOG);
2998 }
2999 }
3000}
3001
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04003002void wlc_phy_BSSinit(wlc_phy_t *pih, bool bonlyap, int rssi)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003003{
3004 phy_info_t *pi = (phy_info_t *) pih;
3005 uint i;
3006 uint k;
3007
3008 for (i = 0; i < MA_WINDOW_SZ; i++) {
Greg Kroah-Hartman562c8852010-10-05 11:04:17 -07003009 pi->sh->phy_noise_window[i] = (s8) (rssi & 0xff);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003010 }
3011 if (ISLCNPHY(pi)) {
3012 for (i = 0; i < MA_WINDOW_SZ; i++)
3013 pi->sh->phy_noise_window[i] =
3014 PHY_NOISE_FIXED_VAL_LCNPHY;
3015 }
3016 pi->sh->phy_noise_index = 0;
3017
3018 for (i = 0; i < PHY_NOISE_WINDOW_SZ; i++) {
3019 for (k = WL_ANT_IDX_1; k < WL_ANT_RX_MAX; k++)
3020 pi->nphy_noise_win[k][i] = PHY_NOISE_FIXED_VAL_NPHY;
3021 }
3022 pi->nphy_noise_index = 0;
3023}
3024
3025void
Greg Kroah-Hartman3e264162010-10-08 11:11:13 -07003026wlc_phy_papd_decode_epsilon(u32 epsilon, s32 *eps_real, s32 *eps_imag)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003027{
Jason Cooperca8c1e52010-09-14 09:45:33 -04003028 *eps_imag = (epsilon >> 13);
3029 if (*eps_imag > 0xfff)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003030 *eps_imag -= 0x2000;
Jason Cooperca8c1e52010-09-14 09:45:33 -04003031
3032 *eps_real = (epsilon & 0x1fff);
3033 if (*eps_real > 0xfff)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003034 *eps_real -= 0x2000;
3035}
3036
3037static const fixed AtanTbl[] = {
3038 2949120,
3039 1740967,
3040 919879,
3041 466945,
3042 234379,
3043 117304,
3044 58666,
3045 29335,
3046 14668,
3047 7334,
3048 3667,
3049 1833,
3050 917,
3051 458,
3052 229,
3053 115,
3054 57,
3055 29
3056};
3057
Greg Kroah-Hartman3e264162010-10-08 11:11:13 -07003058void wlc_phy_cordic(fixed theta, cs32 *val)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003059{
3060 fixed angle, valtmp;
3061 unsigned iter;
3062 int signx = 1;
3063 int signtheta;
3064
3065 val[0].i = CORDIC_AG;
3066 val[0].q = 0;
3067 angle = 0;
3068
3069 signtheta = (theta < 0) ? -1 : 1;
3070 theta =
3071 ((theta + FIXED(180) * signtheta) % FIXED(360)) -
3072 FIXED(180) * signtheta;
3073
3074 if (FLOAT(theta) > 90) {
3075 theta -= FIXED(180);
3076 signx = -1;
3077 } else if (FLOAT(theta) < -90) {
3078 theta += FIXED(180);
3079 signx = -1;
3080 }
3081
3082 for (iter = 0; iter < CORDIC_NI; iter++) {
3083 if (theta > angle) {
3084 valtmp = val[0].i - (val[0].q >> iter);
3085 val[0].q = (val[0].i >> iter) + val[0].q;
3086 val[0].i = valtmp;
3087 angle += AtanTbl[iter];
3088 } else {
3089 valtmp = val[0].i + (val[0].q >> iter);
3090 val[0].q = -(val[0].i >> iter) + val[0].q;
3091 val[0].i = valtmp;
3092 angle -= AtanTbl[iter];
3093 }
3094 }
3095
3096 val[0].i = val[0].i * signx;
3097 val[0].q = val[0].q * signx;
3098}
3099
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04003100void wlc_phy_cal_perical_mphase_reset(phy_info_t *pi)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003101{
3102 wlapi_del_timer(pi->sh->physhim, pi->phycal_timer);
3103
3104 pi->cal_type_override = PHY_PERICAL_AUTO;
3105 pi->mphase_cal_phase_id = MPHASE_CAL_STATE_IDLE;
3106 pi->mphase_txcal_cmdidx = 0;
3107}
3108
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04003109static void wlc_phy_cal_perical_mphase_schedule(phy_info_t *pi, uint delay)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003110{
3111
3112 if ((pi->nphy_perical != PHY_PERICAL_MPHASE) &&
3113 (pi->nphy_perical != PHY_PERICAL_MANUAL))
3114 return;
3115
3116 wlapi_del_timer(pi->sh->physhim, pi->phycal_timer);
3117
3118 pi->mphase_cal_phase_id = MPHASE_CAL_STATE_INIT;
3119 wlapi_add_timer(pi->sh->physhim, pi->phycal_timer, delay, 0);
3120}
3121
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07003122void wlc_phy_cal_perical(wlc_phy_t *pih, u8 reason)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003123{
Greg Kroah-Hartmane59fe082010-10-07 17:08:21 -07003124 s16 nphy_currtemp = 0;
3125 s16 delta_temp = 0;
Greg Kroah-Hartman0f0881b2010-10-12 12:15:18 -07003126 bool do_periodic_cal = true;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003127 phy_info_t *pi = (phy_info_t *) pih;
3128
3129 if (!ISNPHY(pi))
3130 return;
3131
3132 if ((pi->nphy_perical == PHY_PERICAL_DISABLE) ||
3133 (pi->nphy_perical == PHY_PERICAL_MANUAL))
3134 return;
3135
3136 switch (reason) {
3137 case PHY_PERICAL_DRIVERUP:
3138 break;
3139
3140 case PHY_PERICAL_PHYINIT:
3141 if (pi->nphy_perical == PHY_PERICAL_MPHASE) {
3142 if (PHY_PERICAL_MPHASE_PENDING(pi)) {
3143 wlc_phy_cal_perical_mphase_reset(pi);
3144 }
3145 wlc_phy_cal_perical_mphase_schedule(pi,
3146 PHY_PERICAL_INIT_DELAY);
3147 }
3148 break;
3149
3150 case PHY_PERICAL_JOIN_BSS:
3151 case PHY_PERICAL_START_IBSS:
3152 case PHY_PERICAL_UP_BSS:
3153 if ((pi->nphy_perical == PHY_PERICAL_MPHASE) &&
3154 PHY_PERICAL_MPHASE_PENDING(pi)) {
3155 wlc_phy_cal_perical_mphase_reset(pi);
3156 }
3157
Greg Kroah-Hartman0f0881b2010-10-12 12:15:18 -07003158 pi->first_cal_after_assoc = true;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003159
3160 pi->cal_type_override = PHY_PERICAL_FULL;
3161
3162 if (pi->phycal_tempdelta) {
3163 pi->nphy_lastcal_temp = wlc_phy_tempsense_nphy(pi);
3164 }
3165 wlc_phy_cal_perical_nphy_run(pi, PHY_PERICAL_FULL);
3166 break;
3167
3168 case PHY_PERICAL_WATCHDOG:
3169 if (pi->phycal_tempdelta) {
3170 nphy_currtemp = wlc_phy_tempsense_nphy(pi);
3171 delta_temp =
3172 (nphy_currtemp > pi->nphy_lastcal_temp) ?
3173 nphy_currtemp - pi->nphy_lastcal_temp :
3174 pi->nphy_lastcal_temp - nphy_currtemp;
3175
Greg Kroah-Hartmane59fe082010-10-07 17:08:21 -07003176 if ((delta_temp < (s16) pi->phycal_tempdelta) &&
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003177 (pi->nphy_txiqlocal_chanspec ==
3178 pi->radio_chanspec)) {
Greg Kroah-Hartman0965ae82010-10-12 12:50:15 -07003179 do_periodic_cal = false;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003180 } else {
3181 pi->nphy_lastcal_temp = nphy_currtemp;
3182 }
3183 }
3184
3185 if (do_periodic_cal) {
3186
3187 if (pi->nphy_perical == PHY_PERICAL_MPHASE) {
3188
3189 if (!PHY_PERICAL_MPHASE_PENDING(pi))
3190 wlc_phy_cal_perical_mphase_schedule(pi,
3191 PHY_PERICAL_WDOG_DELAY);
3192 } else if (pi->nphy_perical == PHY_PERICAL_SPHASE)
3193 wlc_phy_cal_perical_nphy_run(pi,
3194 PHY_PERICAL_AUTO);
3195 else {
3196 ASSERT(0);
3197 }
3198 }
3199 break;
3200 default:
3201 ASSERT(0);
3202 break;
3203 }
3204}
3205
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04003206void wlc_phy_cal_perical_mphase_restart(phy_info_t *pi)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003207{
3208 pi->mphase_cal_phase_id = MPHASE_CAL_STATE_INIT;
3209 pi->mphase_txcal_cmdidx = 0;
3210}
3211
Greg Kroah-Hartman3e264162010-10-08 11:11:13 -07003212u8 wlc_phy_nbits(s32 value)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003213{
Greg Kroah-Hartman3e264162010-10-08 11:11:13 -07003214 s32 abs_val;
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07003215 u8 nbits = 0;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003216
3217 abs_val = ABS(value);
3218 while ((abs_val >> nbits) > 0)
3219 nbits++;
3220
3221 return nbits;
3222}
3223
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -07003224u32 wlc_phy_sqrt_int(u32 value)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003225{
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -07003226 u32 root = 0, shift = 0;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003227
3228 for (shift = 0; shift < 32; shift += 2) {
3229 if (((0x40000000 >> shift) + root) <= value) {
3230 value -= ((0x40000000 >> shift) + root);
3231 root = (root >> 1) | (0x40000000 >> shift);
3232 } else {
3233 root = root >> 1;
3234 }
3235 }
3236
3237 if (root < value)
3238 ++root;
3239
3240 return root;
3241}
3242
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07003243void wlc_phy_stf_chain_init(wlc_phy_t *pih, u8 txchain, u8 rxchain)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003244{
3245 phy_info_t *pi = (phy_info_t *) pih;
3246
3247 pi->sh->hw_phytxchain = txchain;
3248 pi->sh->hw_phyrxchain = rxchain;
3249 pi->sh->phytxchain = txchain;
3250 pi->sh->phyrxchain = rxchain;
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07003251 pi->pubpi.phy_corenum = (u8) PHY_BITSCNT(pi->sh->phyrxchain);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003252}
3253
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07003254void wlc_phy_stf_chain_set(wlc_phy_t *pih, u8 txchain, u8 rxchain)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003255{
3256 phy_info_t *pi = (phy_info_t *) pih;
3257
3258 pi->sh->phytxchain = txchain;
3259
3260 if (ISNPHY(pi)) {
3261 wlc_phy_rxcore_setstate_nphy(pih, rxchain);
3262 }
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07003263 pi->pubpi.phy_corenum = (u8) PHY_BITSCNT(pi->sh->phyrxchain);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003264}
3265
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07003266void wlc_phy_stf_chain_get(wlc_phy_t *pih, u8 *txchain, u8 *rxchain)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003267{
3268 phy_info_t *pi = (phy_info_t *) pih;
3269
3270 *txchain = pi->sh->phytxchain;
3271 *rxchain = pi->sh->phyrxchain;
3272}
3273
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07003274u8 wlc_phy_stf_chain_active_get(wlc_phy_t *pih)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003275{
Greg Kroah-Hartmane59fe082010-10-07 17:08:21 -07003276 s16 nphy_currtemp;
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07003277 u8 active_bitmap;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003278 phy_info_t *pi = (phy_info_t *) pih;
3279
3280 active_bitmap = (pi->phy_txcore_heatedup) ? 0x31 : 0x33;
3281
3282 if (!pi->watchdog_override)
3283 return active_bitmap;
3284
3285 if (NREV_GE(pi->pubpi.phy_rev, 6)) {
3286 wlapi_suspend_mac_and_wait(pi->sh->physhim);
3287 nphy_currtemp = wlc_phy_tempsense_nphy(pi);
3288 wlapi_enable_mac(pi->sh->physhim);
3289
3290 if (!pi->phy_txcore_heatedup) {
3291 if (nphy_currtemp >= pi->phy_txcore_disable_temp) {
3292 active_bitmap &= 0xFD;
Greg Kroah-Hartman0f0881b2010-10-12 12:15:18 -07003293 pi->phy_txcore_heatedup = true;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003294 }
3295 } else {
3296 if (nphy_currtemp <= pi->phy_txcore_enable_temp) {
3297 active_bitmap |= 0x2;
Greg Kroah-Hartman0965ae82010-10-12 12:50:15 -07003298 pi->phy_txcore_heatedup = false;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003299 }
3300 }
3301 }
3302
3303 return active_bitmap;
3304}
3305
Greg Kroah-Hartman562c8852010-10-05 11:04:17 -07003306s8 wlc_phy_stf_ssmode_get(wlc_phy_t *pih, chanspec_t chanspec)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003307{
3308 phy_info_t *pi = (phy_info_t *) pih;
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07003309 u8 siso_mcs_id, cdd_mcs_id;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003310
3311 siso_mcs_id =
3312 (CHSPEC_IS40(chanspec)) ? TXP_FIRST_MCS_40_SISO :
3313 TXP_FIRST_MCS_20_SISO;
3314 cdd_mcs_id =
3315 (CHSPEC_IS40(chanspec)) ? TXP_FIRST_MCS_40_CDD :
3316 TXP_FIRST_MCS_20_CDD;
3317
3318 if (pi->tx_power_target[siso_mcs_id] >
3319 (pi->tx_power_target[cdd_mcs_id] + 12))
3320 return PHY_TXC1_MODE_SISO;
3321 else
3322 return PHY_TXC1_MODE_CDD;
3323}
3324
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07003325const u8 *wlc_phy_get_ofdm_rate_lookup(void)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003326{
3327 return ofdm_rate_lookup;
3328}
3329
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04003330void wlc_lcnphy_epa_switch(phy_info_t *pi, bool mode)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003331{
3332 if ((CHIPID(pi->sh->chip) == BCM4313_CHIP_ID) &&
3333 (pi->sh->boardflags & BFL_FEM)) {
3334 if (mode) {
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -07003335 u16 txant = 0;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003336 txant = wlapi_bmac_get_txant(pi->sh->physhim);
3337 if (txant == 1) {
3338 mod_phy_reg(pi, 0x44d, (0x1 << 2), (1) << 2);
3339
3340 mod_phy_reg(pi, 0x44c, (0x1 << 2), (1) << 2);
3341
3342 }
3343 si_corereg(pi->sh->sih, SI_CC_IDX,
Greg Kroah-Hartmance0f1b82010-10-08 11:44:45 -07003344 offsetof(chipcregs_t, gpiocontrol), ~0x0,
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003345 0x0);
3346 si_corereg(pi->sh->sih, SI_CC_IDX,
Greg Kroah-Hartmance0f1b82010-10-08 11:44:45 -07003347 offsetof(chipcregs_t, gpioout), 0x40, 0x40);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003348 si_corereg(pi->sh->sih, SI_CC_IDX,
Greg Kroah-Hartmance0f1b82010-10-08 11:44:45 -07003349 offsetof(chipcregs_t, gpioouten), 0x40,
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003350 0x40);
3351 } else {
3352 mod_phy_reg(pi, 0x44c, (0x1 << 2), (0) << 2);
3353
3354 mod_phy_reg(pi, 0x44d, (0x1 << 2), (0) << 2);
3355
3356 si_corereg(pi->sh->sih, SI_CC_IDX,
Greg Kroah-Hartmance0f1b82010-10-08 11:44:45 -07003357 offsetof(chipcregs_t, gpioout), 0x40, 0x00);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003358 si_corereg(pi->sh->sih, SI_CC_IDX,
Greg Kroah-Hartmance0f1b82010-10-08 11:44:45 -07003359 offsetof(chipcregs_t, gpioouten), 0x40, 0x0);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003360 si_corereg(pi->sh->sih, SI_CC_IDX,
Greg Kroah-Hartmance0f1b82010-10-08 11:44:45 -07003361 offsetof(chipcregs_t, gpiocontrol), ~0x0,
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003362 0x40);
3363 }
3364 }
3365}
3366
Greg Kroah-Hartman562c8852010-10-05 11:04:17 -07003367static s8
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -07003368wlc_user_txpwr_antport_to_rfport(phy_info_t *pi, uint chan, u32 band,
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07003369 u8 rate)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003370{
Greg Kroah-Hartman562c8852010-10-05 11:04:17 -07003371 s8 offset = 0;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003372
3373 if (!pi->user_txpwr_at_rfport)
3374 return offset;
3375 return offset;
3376}
3377
Greg Kroah-Hartman562c8852010-10-05 11:04:17 -07003378static s8 wlc_phy_env_measure_vbat(phy_info_t *pi)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003379{
3380 if (ISLCNPHY(pi))
3381 return wlc_lcnphy_vbatsense(pi, 0);
3382 else
3383 return 0;
3384}
3385
Greg Kroah-Hartman562c8852010-10-05 11:04:17 -07003386static s8 wlc_phy_env_measure_temperature(phy_info_t *pi)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003387{
3388 if (ISLCNPHY(pi))
3389 return wlc_lcnphy_tempsense_degree(pi, 0);
3390 else
3391 return 0;
3392}
3393
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -07003394static void wlc_phy_upd_env_txpwr_rate_limits(phy_info_t *pi, u32 band)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003395{
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07003396 u8 i;
Greg Kroah-Hartman562c8852010-10-05 11:04:17 -07003397 s8 temp, vbat;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003398
3399 for (i = 0; i < TXP_NUM_RATES; i++)
3400 pi->txpwr_env_limit[i] = WLC_TXPWR_MAX;
3401
3402 vbat = wlc_phy_env_measure_vbat(pi);
3403 temp = wlc_phy_env_measure_temperature(pi);
3404
3405}
3406
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04003407void wlc_phy_ldpc_override_set(wlc_phy_t *ppi, bool ldpc)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003408{
3409 return;
3410}
3411
3412void
Greg Kroah-Hartman562c8852010-10-05 11:04:17 -07003413wlc_phy_get_pwrdet_offsets(phy_info_t *pi, s8 *cckoffset, s8 *ofdmoffset)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003414{
3415 *cckoffset = 0;
3416 *ofdmoffset = 0;
3417}
3418
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -07003419u32 wlc_phy_qdiv_roundup(u32 dividend, u32 divisor, u8 precision)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003420{
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -07003421 u32 quotient, remainder, roundup, rbit;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003422
3423 ASSERT(divisor);
3424
3425 quotient = dividend / divisor;
3426 remainder = dividend % divisor;
3427 rbit = divisor & 1;
3428 roundup = (divisor >> 1) + rbit;
3429
3430 while (precision--) {
3431 quotient <<= 1;
3432 if (remainder >= roundup) {
3433 quotient++;
3434 remainder = ((remainder - roundup) << 1) + rbit;
3435 } else {
3436 remainder <<= 1;
3437 }
3438 }
3439
3440 if (remainder >= roundup)
3441 quotient++;
3442
3443 return quotient;
3444}
3445
Greg Kroah-Hartman562c8852010-10-05 11:04:17 -07003446s8 wlc_phy_upd_rssi_offset(phy_info_t *pi, s8 rssi, chanspec_t chanspec)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003447{
3448
3449 return rssi;
3450}
3451
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04003452bool wlc_phy_txpower_ipa_ison(wlc_phy_t *ppi)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003453{
3454 phy_info_t *pi = (phy_info_t *) ppi;
3455
3456 if (ISNPHY(pi))
Jason Cooper90ea2292010-09-14 09:45:32 -04003457 return wlc_phy_n_txpower_ipa_ison(pi);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003458 else
3459 return 0;
3460}