blob: 8287261120f4993eaaafe8c2c7d19e092e3f6006 [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 Rudley33279892010-10-01 18:03:27 -070023#include <linuxver.h>
Henry Ptasinskia9533e72010-09-08 21:04:42 -070024#include <bcmendian.h>
25#include <bcmnvram.h>
26#include <sbchipc.h>
27
28#include <wlc_phy_int.h>
29#include <wlc_phyreg_n.h>
30#include <wlc_phy_radio.h>
31#include <wlc_phy_lcn.h>
32
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -070033u32 phyhal_msg_level = PHYHAL_ERROR;
Henry Ptasinskia9533e72010-09-08 21:04:42 -070034
35typedef struct _chan_info_basic {
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -070036 u16 chan;
37 u16 freq;
Henry Ptasinskia9533e72010-09-08 21:04:42 -070038} chan_info_basic_t;
39
40static chan_info_basic_t chan_info_all[] = {
41
42 {1, 2412},
43 {2, 2417},
44 {3, 2422},
45 {4, 2427},
46 {5, 2432},
47 {6, 2437},
48 {7, 2442},
49 {8, 2447},
50 {9, 2452},
51 {10, 2457},
52 {11, 2462},
53 {12, 2467},
54 {13, 2472},
55 {14, 2484},
56
57 {34, 5170},
58 {38, 5190},
59 {42, 5210},
60 {46, 5230},
61
62 {36, 5180},
63 {40, 5200},
64 {44, 5220},
65 {48, 5240},
66 {52, 5260},
67 {56, 5280},
68 {60, 5300},
69 {64, 5320},
70
71 {100, 5500},
72 {104, 5520},
73 {108, 5540},
74 {112, 5560},
75 {116, 5580},
76 {120, 5600},
77 {124, 5620},
78 {128, 5640},
79 {132, 5660},
80 {136, 5680},
81 {140, 5700},
82
83 {149, 5745},
84 {153, 5765},
85 {157, 5785},
86 {161, 5805},
87 {165, 5825},
88
89 {184, 4920},
90 {188, 4940},
91 {192, 4960},
92 {196, 4980},
93 {200, 5000},
94 {204, 5020},
95 {208, 5040},
96 {212, 5060},
97 {216, 50800}
98};
99
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -0700100u16 ltrn_list[PHY_LTRN_LIST_LEN] = {
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700101 0x18f9, 0x0d01, 0x00e4, 0xdef4, 0x06f1, 0x0ffc,
102 0xfa27, 0x1dff, 0x10f0, 0x0918, 0xf20a, 0xe010,
103 0x1417, 0x1104, 0xf114, 0xf2fa, 0xf7db, 0xe2fc,
104 0xe1fb, 0x13ee, 0xff0d, 0xe91c, 0x171a, 0x0318,
105 0xda00, 0x03e8, 0x17e6, 0xe9e4, 0xfff3, 0x1312,
106 0xe105, 0xe204, 0xf725, 0xf206, 0xf1ec, 0x11fc,
107 0x14e9, 0xe0f0, 0xf2f6, 0x09e8, 0x1010, 0x1d01,
108 0xfad9, 0x0f04, 0x060f, 0xde0c, 0x001c, 0x0dff,
109 0x1807, 0xf61a, 0xe40e, 0x0f16, 0x05f9, 0x18ec,
110 0x0a1b, 0xff1e, 0x2600, 0xffe2, 0x0ae5, 0x1814,
111 0x0507, 0x0fea, 0xe4f2, 0xf6e6
112};
113
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -0700114const u8 ofdm_rate_lookup[] = {
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700115
116 WLC_RATE_48M,
117 WLC_RATE_24M,
118 WLC_RATE_12M,
119 WLC_RATE_6M,
120 WLC_RATE_54M,
121 WLC_RATE_36M,
122 WLC_RATE_18M,
123 WLC_RATE_9M
124};
125
126#define PHY_WREG_LIMIT 24
127
Jason Cooper7cc4a4c2010-09-14 09:45:30 -0400128static void wlc_set_phy_uninitted(phy_info_t *pi);
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -0700129static u32 wlc_phy_get_radio_ver(phy_info_t *pi);
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700130static void wlc_phy_timercb_phycal(void *arg);
131
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -0700132static bool wlc_phy_noise_calc_phy(phy_info_t *pi, u32 *cmplx_pwr,
Greg Kroah-Hartman562c8852010-10-05 11:04:17 -0700133 s8 *pwr_ant);
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700134
Jason Cooper7cc4a4c2010-09-14 09:45:30 -0400135static void wlc_phy_cal_perical_mphase_schedule(phy_info_t *pi, uint delay);
Greg Kroah-Hartman562c8852010-10-05 11:04:17 -0700136static void wlc_phy_noise_cb(phy_info_t *pi, u8 channel, s8 noise_dbm);
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -0700137static void wlc_phy_noise_sample_request(wlc_phy_t *pih, u8 reason,
138 u8 ch);
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700139
Jason Cooper7cc4a4c2010-09-14 09:45:30 -0400140static void wlc_phy_txpower_reg_limit_calc(phy_info_t *pi,
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700141 struct txpwr_limits *tp, chanspec_t);
Jason Cooper7cc4a4c2010-09-14 09:45:30 -0400142static bool wlc_phy_cal_txpower_recalc_sw(phy_info_t *pi);
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700143
Greg Kroah-Hartman562c8852010-10-05 11:04:17 -0700144static s8 wlc_user_txpwr_antport_to_rfport(phy_info_t *pi, uint chan,
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -0700145 u32 band, u8 rate);
146static void wlc_phy_upd_env_txpwr_rate_limits(phy_info_t *pi, u32 band);
Greg Kroah-Hartman562c8852010-10-05 11:04:17 -0700147static s8 wlc_phy_env_measure_vbat(phy_info_t *pi);
148static s8 wlc_phy_env_measure_temperature(phy_info_t *pi);
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700149
Jason Cooper7cc4a4c2010-09-14 09:45:30 -0400150char *phy_getvar(phy_info_t *pi, const char *name)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700151{
152 char *vars = pi->vars;
153 char *s;
154 int len;
155
156 ASSERT(pi->vars != (char *)&pi->vars);
157
158 if (!name)
159 return NULL;
160
161 len = strlen(name);
162 if (len == 0)
163 return NULL;
164
165 for (s = vars; s && *s;) {
166 if ((bcmp(s, name, len) == 0) && (s[len] == '='))
Jason Cooper90ea2292010-09-14 09:45:32 -0400167 return &s[len + 1];
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700168
Jason Cooper62145822010-09-14 09:45:34 -0400169 while (*s++)
170 ;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700171 }
172
Jason Cooper90ea2292010-09-14 09:45:32 -0400173 return nvram_get(name);
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700174}
175
Jason Cooper7cc4a4c2010-09-14 09:45:30 -0400176int phy_getintvar(phy_info_t *pi, const char *name)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700177{
178 char *val;
179
Jason Cooperca8c1e52010-09-14 09:45:33 -0400180 val = PHY_GETVAR(pi, name);
181 if (val == NULL)
Jason Cooper90ea2292010-09-14 09:45:32 -0400182 return 0;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700183
Andy Shevchenko48c51a82010-09-15 12:47:18 +0300184 return simple_strtoul(val, NULL, 0);
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700185}
186
Jason Cooper7cc4a4c2010-09-14 09:45:30 -0400187void wlc_phyreg_enter(wlc_phy_t *pih)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700188{
189 phy_info_t *pi = (phy_info_t *) pih;
190 wlapi_bmac_ucode_wake_override_phyreg_set(pi->sh->physhim);
191}
192
Jason Cooper7cc4a4c2010-09-14 09:45:30 -0400193void wlc_phyreg_exit(wlc_phy_t *pih)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700194{
195 phy_info_t *pi = (phy_info_t *) pih;
196 wlapi_bmac_ucode_wake_override_phyreg_clear(pi->sh->physhim);
197}
198
Jason Cooper7cc4a4c2010-09-14 09:45:30 -0400199void wlc_radioreg_enter(wlc_phy_t *pih)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700200{
201 phy_info_t *pi = (phy_info_t *) pih;
202 wlapi_bmac_mctrl(pi->sh->physhim, MCTL_LOCK_RADIO, MCTL_LOCK_RADIO);
203
mike.rapoport@gmail.com73831412010-10-13 00:09:07 +0200204 udelay(10);
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700205}
206
Jason Cooper7cc4a4c2010-09-14 09:45:30 -0400207void wlc_radioreg_exit(wlc_phy_t *pih)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700208{
209 phy_info_t *pi = (phy_info_t *) pih;
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -0700210 volatile u16 dummy;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700211
212 dummy = R_REG(pi->sh->osh, &pi->regs->phyversion);
213 pi->phy_wreg = 0;
214 wlapi_bmac_mctrl(pi->sh->physhim, MCTL_LOCK_RADIO, 0);
215}
216
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -0700217u16 read_radio_reg(phy_info_t *pi, u16 addr)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700218{
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -0700219 u16 data;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700220
221 if ((addr == RADIO_IDCODE))
222 return 0xffff;
223
224 if (NORADIO_ENAB(pi->pubpi))
Jason Cooper90ea2292010-09-14 09:45:32 -0400225 return NORADIO_IDCODE & 0xffff;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700226
227 switch (pi->pubpi.phy_type) {
228 case PHY_TYPE_N:
229 CASECHECK(PHYTYPE, PHY_TYPE_N);
230 if (NREV_GE(pi->pubpi.phy_rev, 7))
231 addr |= RADIO_2057_READ_OFF;
232 else
233 addr |= RADIO_2055_READ_OFF;
234 break;
235
236 case PHY_TYPE_LCN:
237 CASECHECK(PHYTYPE, PHY_TYPE_LCN);
238 addr |= RADIO_2064_READ_OFF;
239 break;
240
241 default:
242 ASSERT(VALID_PHYTYPE(pi->pubpi.phy_type));
243 }
244
245 if ((D11REV_GE(pi->sh->corerev, 24)) ||
246 (D11REV_IS(pi->sh->corerev, 22)
247 && (pi->pubpi.phy_type != PHY_TYPE_SSN))) {
248 W_REG(pi->sh->osh, &pi->regs->radioregaddr, addr);
249#ifdef __mips__
250 (void)R_REG(pi->sh->osh, &pi->regs->radioregaddr);
251#endif
252 data = R_REG(pi->sh->osh, &pi->regs->radioregdata);
253 } else {
254 W_REG(pi->sh->osh, &pi->regs->phy4waddr, addr);
255#ifdef __mips__
256 (void)R_REG(pi->sh->osh, &pi->regs->phy4waddr);
257#endif
258
259#ifdef __ARM_ARCH_4T__
260 __asm__(" .align 4 ");
261 __asm__(" nop ");
262 data = R_REG(pi->sh->osh, &pi->regs->phy4wdatalo);
263#else
264 data = R_REG(pi->sh->osh, &pi->regs->phy4wdatalo);
265#endif
266
267 }
268 pi->phy_wreg = 0;
269
270 return data;
271}
272
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -0700273void write_radio_reg(phy_info_t *pi, u16 addr, u16 val)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700274{
275 osl_t *osh;
276
277 if (NORADIO_ENAB(pi->pubpi))
278 return;
279
280 osh = pi->sh->osh;
281
282 if ((D11REV_GE(pi->sh->corerev, 24)) ||
283 (D11REV_IS(pi->sh->corerev, 22)
284 && (pi->pubpi.phy_type != PHY_TYPE_SSN))) {
285
286 W_REG(osh, &pi->regs->radioregaddr, addr);
287#ifdef __mips__
288 (void)R_REG(osh, &pi->regs->radioregaddr);
289#endif
290 W_REG(osh, &pi->regs->radioregdata, val);
291 } else {
292 W_REG(osh, &pi->regs->phy4waddr, addr);
293#ifdef __mips__
294 (void)R_REG(osh, &pi->regs->phy4waddr);
295#endif
296 W_REG(osh, &pi->regs->phy4wdatalo, val);
297 }
298
299 if (BUSTYPE(pi->sh->bustype) == PCI_BUS) {
300 if (++pi->phy_wreg >= pi->phy_wreg_limit) {
301 (void)R_REG(osh, &pi->regs->maccontrol);
302 pi->phy_wreg = 0;
303 }
304 }
305}
306
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -0700307static u32 read_radio_id(phy_info_t *pi)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700308{
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -0700309 u32 id;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700310
311 if (NORADIO_ENAB(pi->pubpi))
Jason Cooper90ea2292010-09-14 09:45:32 -0400312 return NORADIO_IDCODE;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700313
314 if (D11REV_GE(pi->sh->corerev, 24)) {
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -0700315 u32 b0, b1, b2;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700316
317 W_REG(pi->sh->osh, &pi->regs->radioregaddr, 0);
318#ifdef __mips__
319 (void)R_REG(pi->sh->osh, &pi->regs->radioregaddr);
320#endif
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -0700321 b0 = (u32) R_REG(pi->sh->osh, &pi->regs->radioregdata);
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700322 W_REG(pi->sh->osh, &pi->regs->radioregaddr, 1);
323#ifdef __mips__
324 (void)R_REG(pi->sh->osh, &pi->regs->radioregaddr);
325#endif
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -0700326 b1 = (u32) R_REG(pi->sh->osh, &pi->regs->radioregdata);
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700327 W_REG(pi->sh->osh, &pi->regs->radioregaddr, 2);
328#ifdef __mips__
329 (void)R_REG(pi->sh->osh, &pi->regs->radioregaddr);
330#endif
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -0700331 b2 = (u32) R_REG(pi->sh->osh, &pi->regs->radioregdata);
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700332
333 id = ((b0 & 0xf) << 28) | (((b2 << 8) | b1) << 12) | ((b0 >> 4)
334 & 0xf);
335 } else {
336 W_REG(pi->sh->osh, &pi->regs->phy4waddr, RADIO_IDCODE);
337#ifdef __mips__
338 (void)R_REG(pi->sh->osh, &pi->regs->phy4waddr);
339#endif
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -0700340 id = (u32) R_REG(pi->sh->osh, &pi->regs->phy4wdatalo);
341 id |= (u32) R_REG(pi->sh->osh, &pi->regs->phy4wdatahi) << 16;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700342 }
343 pi->phy_wreg = 0;
344 return id;
345}
346
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -0700347void and_radio_reg(phy_info_t *pi, u16 addr, u16 val)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700348{
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -0700349 u16 rval;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700350
351 if (NORADIO_ENAB(pi->pubpi))
352 return;
353
354 rval = read_radio_reg(pi, addr);
355 write_radio_reg(pi, addr, (rval & val));
356}
357
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -0700358void or_radio_reg(phy_info_t *pi, u16 addr, u16 val)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700359{
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -0700360 u16 rval;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700361
362 if (NORADIO_ENAB(pi->pubpi))
363 return;
364
365 rval = read_radio_reg(pi, addr);
366 write_radio_reg(pi, addr, (rval | val));
367}
368
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -0700369void xor_radio_reg(phy_info_t *pi, u16 addr, u16 mask)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700370{
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -0700371 u16 rval;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700372
373 if (NORADIO_ENAB(pi->pubpi))
374 return;
375
376 rval = read_radio_reg(pi, addr);
377 write_radio_reg(pi, addr, (rval ^ mask));
378}
379
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -0700380void mod_radio_reg(phy_info_t *pi, u16 addr, u16 mask, u16 val)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700381{
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -0700382 u16 rval;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700383
384 if (NORADIO_ENAB(pi->pubpi))
385 return;
386
387 rval = read_radio_reg(pi, addr);
388 write_radio_reg(pi, addr, (rval & ~mask) | (val & mask));
389}
390
Jason Cooper7cc4a4c2010-09-14 09:45:30 -0400391void write_phy_channel_reg(phy_info_t *pi, uint val)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700392{
393 W_REG(pi->sh->osh, &pi->regs->phychannel, val);
394}
395
396#if defined(BCMDBG)
Jason Cooper7cc4a4c2010-09-14 09:45:30 -0400397static bool wlc_phy_war41476(phy_info_t *pi)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700398{
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -0700399 u32 mc = R_REG(pi->sh->osh, &pi->regs->maccontrol);
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700400
401 return ((mc & MCTL_EN_MAC) == 0)
402 || ((mc & MCTL_PHYLOCK) == MCTL_PHYLOCK);
403}
404#endif
405
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -0700406u16 read_phy_reg(phy_info_t *pi, u16 addr)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700407{
408 osl_t *osh;
409 d11regs_t *regs;
410
411 osh = pi->sh->osh;
412 regs = pi->regs;
413
414 W_REG(osh, &regs->phyregaddr, addr);
415#ifdef __mips__
416 (void)R_REG(osh, &regs->phyregaddr);
417#endif
418
419 ASSERT(!
420 (D11REV_IS(pi->sh->corerev, 11)
421 || D11REV_IS(pi->sh->corerev, 12)) || wlc_phy_war41476(pi));
422
423 pi->phy_wreg = 0;
Jason Cooper90ea2292010-09-14 09:45:32 -0400424 return R_REG(osh, &regs->phyregdata);
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700425}
426
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -0700427void write_phy_reg(phy_info_t *pi, u16 addr, u16 val)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700428{
429 osl_t *osh;
430 d11regs_t *regs;
431
432 osh = pi->sh->osh;
433 regs = pi->regs;
434
435#ifdef __mips__
436 W_REG(osh, &regs->phyregaddr, addr);
437 (void)R_REG(osh, &regs->phyregaddr);
438 W_REG(osh, &regs->phyregdata, val);
439 if (addr == 0x72)
440 (void)R_REG(osh, &regs->phyregdata);
441#else
Greg Kroah-Hartman159a3b72010-10-12 13:20:00 -0700442 W_REG(osh, (volatile u32 *)(&regs->phyregaddr),
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700443 addr | (val << 16));
444 if (BUSTYPE(pi->sh->bustype) == PCI_BUS) {
445 if (++pi->phy_wreg >= pi->phy_wreg_limit) {
446 pi->phy_wreg = 0;
447 (void)R_REG(osh, &regs->phyversion);
448 }
449 }
450#endif
451}
452
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -0700453void and_phy_reg(phy_info_t *pi, u16 addr, u16 val)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700454{
455 osl_t *osh;
456 d11regs_t *regs;
457
458 osh = pi->sh->osh;
459 regs = pi->regs;
460
461 W_REG(osh, &regs->phyregaddr, addr);
462#ifdef __mips__
463 (void)R_REG(osh, &regs->phyregaddr);
464#endif
465
466 ASSERT(!
467 (D11REV_IS(pi->sh->corerev, 11)
468 || D11REV_IS(pi->sh->corerev, 12)) || wlc_phy_war41476(pi));
469
470 W_REG(osh, &regs->phyregdata, (R_REG(osh, &regs->phyregdata) & val));
471 pi->phy_wreg = 0;
472}
473
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -0700474void or_phy_reg(phy_info_t *pi, u16 addr, u16 val)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700475{
476 osl_t *osh;
477 d11regs_t *regs;
478
479 osh = pi->sh->osh;
480 regs = pi->regs;
481
482 W_REG(osh, &regs->phyregaddr, addr);
483#ifdef __mips__
484 (void)R_REG(osh, &regs->phyregaddr);
485#endif
486
487 ASSERT(!
488 (D11REV_IS(pi->sh->corerev, 11)
489 || D11REV_IS(pi->sh->corerev, 12)) || wlc_phy_war41476(pi));
490
491 W_REG(osh, &regs->phyregdata, (R_REG(osh, &regs->phyregdata) | val));
492 pi->phy_wreg = 0;
493}
494
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -0700495void mod_phy_reg(phy_info_t *pi, u16 addr, u16 mask, u16 val)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700496{
497 osl_t *osh;
498 d11regs_t *regs;
499
500 osh = pi->sh->osh;
501 regs = pi->regs;
502
503 W_REG(osh, &regs->phyregaddr, addr);
504#ifdef __mips__
505 (void)R_REG(osh, &regs->phyregaddr);
506#endif
507
508 ASSERT(!
509 (D11REV_IS(pi->sh->corerev, 11)
510 || D11REV_IS(pi->sh->corerev, 12)) || wlc_phy_war41476(pi));
511
512 W_REG(osh, &regs->phyregdata,
513 ((R_REG(osh, &regs->phyregdata) & ~mask) | (val & mask)));
514 pi->phy_wreg = 0;
515}
516
Jason Coopera2627bc2010-09-14 09:45:31 -0400517static void WLBANDINITFN(wlc_set_phy_uninitted) (phy_info_t *pi)
518{
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700519 int i, j;
520
Greg Kroah-Hartman0965ae82010-10-12 12:50:15 -0700521 pi->initialized = false;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700522
523 pi->tx_vos = 0xffff;
524 pi->nrssi_table_delta = 0x7fffffff;
525 pi->rc_cal = 0xffff;
526 pi->mintxbias = 0xffff;
527 pi->txpwridx = -1;
528 if (ISNPHY(pi)) {
529 pi->phy_spuravoid = SPURAVOID_DISABLE;
530
531 if (NREV_GE(pi->pubpi.phy_rev, 3)
532 && NREV_LT(pi->pubpi.phy_rev, 7))
533 pi->phy_spuravoid = SPURAVOID_AUTO;
534
535 pi->nphy_papd_skip = 0;
536 pi->nphy_papd_epsilon_offset[0] = 0xf588;
537 pi->nphy_papd_epsilon_offset[1] = 0xf588;
538 pi->nphy_txpwr_idx[0] = 128;
539 pi->nphy_txpwr_idx[1] = 128;
540 pi->nphy_txpwrindex[0].index_internal = 40;
541 pi->nphy_txpwrindex[1].index_internal = 40;
542 pi->phy_pabias = 0;
543 } else {
544 pi->phy_spuravoid = SPURAVOID_AUTO;
545 }
546 pi->radiopwr = 0xffff;
547 for (i = 0; i < STATIC_NUM_RF; i++) {
548 for (j = 0; j < STATIC_NUM_BB; j++) {
549 pi->stats_11b_txpower[i][j] = -1;
550 }
551 }
552}
553
Greg Kroah-Hartman0d2f0722010-10-08 14:28:21 -0700554shared_phy_t *wlc_phy_shared_attach(shared_phy_params_t *shp)
Jason Coopera2627bc2010-09-14 09:45:31 -0400555{
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700556 shared_phy_t *sh;
557
mike.rapoport@gmail.com5fcc1fc2010-10-13 00:09:10 +0200558 sh = kzalloc(sizeof(shared_phy_t), GFP_ATOMIC);
Jason Cooperca8c1e52010-09-14 09:45:33 -0400559 if (sh == NULL) {
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700560 return NULL;
561 }
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700562
563 sh->osh = shp->osh;
564 sh->sih = shp->sih;
565 sh->physhim = shp->physhim;
566 sh->unit = shp->unit;
567 sh->corerev = shp->corerev;
568
569 sh->vid = shp->vid;
570 sh->did = shp->did;
571 sh->chip = shp->chip;
572 sh->chiprev = shp->chiprev;
573 sh->chippkg = shp->chippkg;
574 sh->sromrev = shp->sromrev;
575 sh->boardtype = shp->boardtype;
576 sh->boardrev = shp->boardrev;
577 sh->boardvendor = shp->boardvendor;
578 sh->boardflags = shp->boardflags;
579 sh->boardflags2 = shp->boardflags2;
580 sh->bustype = shp->bustype;
581 sh->buscorerev = shp->buscorerev;
582
583 sh->fast_timer = PHY_SW_TIMER_FAST;
584 sh->slow_timer = PHY_SW_TIMER_SLOW;
585 sh->glacial_timer = PHY_SW_TIMER_GLACIAL;
586
587 sh->rssi_mode = RSSI_ANT_MERGE_MAX;
588
589 return sh;
590}
591
Greg Kroah-Hartman0d2f0722010-10-08 14:28:21 -0700592void wlc_phy_shared_detach(shared_phy_t *phy_sh)
Jason Coopera2627bc2010-09-14 09:45:31 -0400593{
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700594 osl_t *osh;
595
596 if (phy_sh) {
597 osh = phy_sh->osh;
598
599 if (phy_sh->phy_head) {
600 ASSERT(!phy_sh->phy_head);
601 }
mike.rapoport@gmail.com182acb32010-10-13 00:09:12 +0200602 kfree(phy_sh);
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700603 }
604}
605
Greg Kroah-Hartman0d2f0722010-10-08 14:28:21 -0700606wlc_phy_t *wlc_phy_attach(shared_phy_t *sh, void *regs, int bandtype, char *vars)
607{
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700608 phy_info_t *pi;
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -0700609 u32 sflags = 0;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700610 uint phyversion;
611 int i;
612 osl_t *osh;
613
614 osh = sh->osh;
615
616 if (D11REV_IS(sh->corerev, 4))
617 sflags = SISF_2G_PHY | SISF_5G_PHY;
618 else
619 sflags = si_core_sflags(sh->sih, 0, 0);
620
621 if (BAND_5G(bandtype)) {
622 if ((sflags & (SISF_5G_PHY | SISF_DB_PHY)) == 0) {
623 return NULL;
624 }
625 }
626
Jason Cooperca8c1e52010-09-14 09:45:33 -0400627 pi = sh->phy_head;
628 if ((sflags & SISF_DB_PHY) && pi) {
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700629
630 wlapi_bmac_corereset(pi->sh->physhim, pi->pubpi.coreflags);
631 pi->refcnt++;
632 return &pi->pubpi_ro;
633 }
634
mike.rapoport@gmail.com5fcc1fc2010-10-13 00:09:10 +0200635 pi = kzalloc(sizeof(phy_info_t), GFP_ATOMIC);
Jason Cooperca8c1e52010-09-14 09:45:33 -0400636 if (pi == NULL) {
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700637 return NULL;
638 }
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700639 pi->regs = (d11regs_t *) regs;
640 pi->sh = sh;
Greg Kroah-Hartman0f0881b2010-10-12 12:15:18 -0700641 pi->phy_init_por = true;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700642 pi->phy_wreg_limit = PHY_WREG_LIMIT;
643
644 pi->vars = vars;
645
646 pi->txpwr_percent = 100;
647
Greg Kroah-Hartman0f0881b2010-10-12 12:15:18 -0700648 pi->do_initcal = true;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700649
650 pi->phycal_tempdelta = 0;
651
652 if (BAND_2G(bandtype) && (sflags & SISF_2G_PHY)) {
653
654 pi->pubpi.coreflags = SICF_GMODE;
655 }
656
657 wlapi_bmac_corereset(pi->sh->physhim, pi->pubpi.coreflags);
658 phyversion = R_REG(osh, &pi->regs->phyversion);
659
660 pi->pubpi.phy_type = PHY_TYPE(phyversion);
661 pi->pubpi.phy_rev = phyversion & PV_PV_MASK;
662
663 if (pi->pubpi.phy_type == PHY_TYPE_LCNXN) {
664 pi->pubpi.phy_type = PHY_TYPE_N;
665 pi->pubpi.phy_rev += LCNXN_BASEREV;
666 }
667 pi->pubpi.phy_corenum = PHY_CORE_NUM_2;
668 pi->pubpi.ana_rev = (phyversion & PV_AV_MASK) >> PV_AV_SHIFT;
669
670 if (!VALID_PHYTYPE(pi->pubpi.phy_type)) {
671 goto err;
672 }
673 if (BAND_5G(bandtype)) {
674 if (!ISNPHY(pi)) {
675 goto err;
676 }
677 } else {
678 if (!ISNPHY(pi) && !ISLCNPHY(pi)) {
679 goto err;
680 }
681 }
682
683 if (ISSIM_ENAB(pi->sh->sih)) {
684 pi->pubpi.radioid = NORADIO_ID;
685 pi->pubpi.radiorev = 5;
686 } else {
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -0700687 u32 idcode;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700688
689 wlc_phy_anacore((wlc_phy_t *) pi, ON);
690
691 idcode = wlc_phy_get_radio_ver(pi);
692 pi->pubpi.radioid =
693 (idcode & IDCODE_ID_MASK) >> IDCODE_ID_SHIFT;
694 pi->pubpi.radiorev =
695 (idcode & IDCODE_REV_MASK) >> IDCODE_REV_SHIFT;
696 pi->pubpi.radiover =
697 (idcode & IDCODE_VER_MASK) >> IDCODE_VER_SHIFT;
698 if (!VALID_RADIO(pi, pi->pubpi.radioid)) {
699 goto err;
700 }
701
702 wlc_phy_switch_radio((wlc_phy_t *) pi, OFF);
703 }
704
705 wlc_set_phy_uninitted(pi);
706
707 pi->bw = WL_CHANSPEC_BW_20;
708 pi->radio_chanspec =
709 BAND_2G(bandtype) ? CH20MHZ_CHSPEC(1) : CH20MHZ_CHSPEC(36);
710
711 pi->rxiq_samps = PHY_NOISE_SAMPLE_LOG_NUM_NPHY;
712 pi->rxiq_antsel = ANT_RX_DIV_DEF;
713
Greg Kroah-Hartman0f0881b2010-10-12 12:15:18 -0700714 pi->watchdog_override = true;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700715
716 pi->cal_type_override = PHY_PERICAL_AUTO;
717
718 pi->nphy_saved_noisevars.bufcount = 0;
719
720 if (ISNPHY(pi))
721 pi->min_txpower = PHY_TXPWR_MIN_NPHY;
722 else
723 pi->min_txpower = PHY_TXPWR_MIN;
724
725 pi->sh->phyrxchain = 0x3;
726
727 pi->rx2tx_biasentry = -1;
728
729 pi->phy_txcore_disable_temp = PHY_CHAIN_TX_DISABLE_TEMP;
730 pi->phy_txcore_enable_temp =
731 PHY_CHAIN_TX_DISABLE_TEMP - PHY_HYSTERESIS_DELTATEMP;
732 pi->phy_tempsense_offset = 0;
Greg Kroah-Hartman0965ae82010-10-12 12:50:15 -0700733 pi->phy_txcore_heatedup = false;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700734
735 pi->nphy_lastcal_temp = -50;
736
Greg Kroah-Hartman0f0881b2010-10-12 12:15:18 -0700737 pi->phynoise_polling = true;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700738 if (ISNPHY(pi) || ISLCNPHY(pi))
Greg Kroah-Hartman0965ae82010-10-12 12:50:15 -0700739 pi->phynoise_polling = false;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700740
741 for (i = 0; i < TXP_NUM_RATES; i++) {
742 pi->txpwr_limit[i] = WLC_TXPWR_MAX;
743 pi->txpwr_env_limit[i] = WLC_TXPWR_MAX;
744 pi->tx_user_target[i] = WLC_TXPWR_MAX;
745 }
746
747 pi->radiopwr_override = RADIOPWR_OVERRIDE_DEF;
748
Greg Kroah-Hartman0965ae82010-10-12 12:50:15 -0700749 pi->user_txpwr_at_rfport = false;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700750
751 if (ISNPHY(pi)) {
752
Jason Cooperca8c1e52010-09-14 09:45:33 -0400753 pi->phycal_timer = wlapi_init_timer(pi->sh->physhim,
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700754 wlc_phy_timercb_phycal,
Jason Cooperca8c1e52010-09-14 09:45:33 -0400755 pi, "phycal");
756 if (!pi->phycal_timer) {
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700757 goto err;
758 }
759
760 if (!wlc_phy_attach_nphy(pi))
761 goto err;
762
763 } else if (ISLCNPHY(pi)) {
764 if (!wlc_phy_attach_lcnphy(pi))
765 goto err;
766
767 } else {
768
769 }
770
771 pi->refcnt++;
772 pi->next = pi->sh->phy_head;
773 sh->phy_head = pi;
774
775 pi->vars = (char *)&pi->vars;
776
777 bcopy(&pi->pubpi, &pi->pubpi_ro, sizeof(wlc_phy_t));
778
779 return &pi->pubpi_ro;
780
781 err:
782 if (pi)
mike.rapoport@gmail.com182acb32010-10-13 00:09:12 +0200783 kfree(pi);
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700784 return NULL;
785}
786
Greg Kroah-Hartman0d2f0722010-10-08 14:28:21 -0700787void wlc_phy_detach(wlc_phy_t *pih)
Jason Coopera2627bc2010-09-14 09:45:31 -0400788{
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700789 phy_info_t *pi = (phy_info_t *) pih;
790
791 if (pih) {
792 if (--pi->refcnt) {
793 return;
794 }
795
796 if (pi->phycal_timer) {
797 wlapi_free_timer(pi->sh->physhim, pi->phycal_timer);
798 pi->phycal_timer = NULL;
799 }
800
801 if (pi->sh->phy_head == pi)
802 pi->sh->phy_head = pi->next;
803 else if (pi->sh->phy_head->next == pi)
804 pi->sh->phy_head->next = NULL;
805 else
806 ASSERT(0);
807
808 if (pi->pi_fptr.detach)
809 (pi->pi_fptr.detach) (pi);
810
mike.rapoport@gmail.com182acb32010-10-13 00:09:12 +0200811 kfree(pi);
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700812 }
813}
814
815bool
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -0700816wlc_phy_get_phyversion(wlc_phy_t *pih, u16 *phytype, u16 *phyrev,
817 u16 *radioid, u16 *radiover)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700818{
819 phy_info_t *pi = (phy_info_t *) pih;
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -0700820 *phytype = (u16) pi->pubpi.phy_type;
821 *phyrev = (u16) pi->pubpi.phy_rev;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700822 *radioid = pi->pubpi.radioid;
823 *radiover = pi->pubpi.radiorev;
824
Greg Kroah-Hartman0f0881b2010-10-12 12:15:18 -0700825 return true;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700826}
827
Jason Cooper7cc4a4c2010-09-14 09:45:30 -0400828bool wlc_phy_get_encore(wlc_phy_t *pih)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700829{
830 phy_info_t *pi = (phy_info_t *) pih;
831 return pi->pubpi.abgphy_encore;
832}
833
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -0700834u32 wlc_phy_get_coreflags(wlc_phy_t *pih)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700835{
836 phy_info_t *pi = (phy_info_t *) pih;
837 return pi->pubpi.coreflags;
838}
839
840static void wlc_phy_timercb_phycal(void *arg)
841{
842 phy_info_t *pi = (phy_info_t *) arg;
843 uint delay = 5;
844
845 if (PHY_PERICAL_MPHASE_PENDING(pi)) {
846 if (!pi->sh->up) {
847 wlc_phy_cal_perical_mphase_reset(pi);
848 return;
849 }
850
851 if (SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi)) {
852
853 delay = 1000;
854 wlc_phy_cal_perical_mphase_restart(pi);
855 } else
856 wlc_phy_cal_perical_nphy_run(pi, PHY_PERICAL_AUTO);
857 wlapi_add_timer(pi->sh->physhim, pi->phycal_timer, delay, 0);
858 return;
859 }
860
861}
862
Jason Cooper7cc4a4c2010-09-14 09:45:30 -0400863void wlc_phy_anacore(wlc_phy_t *pih, bool on)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700864{
865 phy_info_t *pi = (phy_info_t *) pih;
866
867 if (ISNPHY(pi)) {
868 if (on) {
869 if (NREV_GE(pi->pubpi.phy_rev, 3)) {
870 write_phy_reg(pi, 0xa6, 0x0d);
871 write_phy_reg(pi, 0x8f, 0x0);
872 write_phy_reg(pi, 0xa7, 0x0d);
873 write_phy_reg(pi, 0xa5, 0x0);
874 } else {
875 write_phy_reg(pi, 0xa5, 0x0);
876 }
877 } else {
878 if (NREV_GE(pi->pubpi.phy_rev, 3)) {
879 write_phy_reg(pi, 0x8f, 0x07ff);
880 write_phy_reg(pi, 0xa6, 0x0fd);
881 write_phy_reg(pi, 0xa5, 0x07ff);
882 write_phy_reg(pi, 0xa7, 0x0fd);
883 } else {
884 write_phy_reg(pi, 0xa5, 0x7fff);
885 }
886 }
887 } else if (ISLCNPHY(pi)) {
888 if (on) {
889 and_phy_reg(pi, 0x43b,
890 ~((0x1 << 0) | (0x1 << 1) | (0x1 << 2)));
891 } else {
892 or_phy_reg(pi, 0x43c,
893 (0x1 << 0) | (0x1 << 1) | (0x1 << 2));
894 or_phy_reg(pi, 0x43b,
895 (0x1 << 0) | (0x1 << 1) | (0x1 << 2));
896 }
897 }
898}
899
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -0700900u32 wlc_phy_clk_bwbits(wlc_phy_t *pih)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700901{
902 phy_info_t *pi = (phy_info_t *) pih;
903
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -0700904 u32 phy_bw_clkbits = 0;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700905
906 if (pi && (ISNPHY(pi) || ISLCNPHY(pi))) {
907 switch (pi->bw) {
908 case WL_CHANSPEC_BW_10:
909 phy_bw_clkbits = SICF_BW10;
910 break;
911 case WL_CHANSPEC_BW_20:
912 phy_bw_clkbits = SICF_BW20;
913 break;
914 case WL_CHANSPEC_BW_40:
915 phy_bw_clkbits = SICF_BW40;
916 break;
917 default:
918 ASSERT(0);
919 break;
920 }
921 }
922
923 return phy_bw_clkbits;
924}
925
Jason Coopera2627bc2010-09-14 09:45:31 -0400926void WLBANDINITFN(wlc_phy_por_inform) (wlc_phy_t *ppi)
927{
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700928 phy_info_t *pi = (phy_info_t *) ppi;
929
Greg Kroah-Hartman0f0881b2010-10-12 12:15:18 -0700930 pi->phy_init_por = true;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700931}
932
Jason Cooper7cc4a4c2010-09-14 09:45:30 -0400933void wlc_phy_edcrs_lock(wlc_phy_t *pih, bool lock)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700934{
935 phy_info_t *pi = (phy_info_t *) pih;
936
937 pi->edcrs_threshold_lock = lock;
938
939 write_phy_reg(pi, 0x22c, 0x46b);
940 write_phy_reg(pi, 0x22d, 0x46b);
941 write_phy_reg(pi, 0x22e, 0x3c0);
942 write_phy_reg(pi, 0x22f, 0x3c0);
943}
944
Jason Cooper7cc4a4c2010-09-14 09:45:30 -0400945void wlc_phy_initcal_enable(wlc_phy_t *pih, bool initcal)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700946{
947 phy_info_t *pi = (phy_info_t *) pih;
948
949 pi->do_initcal = initcal;
950}
951
Jason Cooper7cc4a4c2010-09-14 09:45:30 -0400952void wlc_phy_hw_clk_state_upd(wlc_phy_t *pih, bool newstate)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700953{
954 phy_info_t *pi = (phy_info_t *) pih;
955
956 if (!pi || !pi->sh)
957 return;
958
959 pi->sh->clk = newstate;
960}
961
Jason Cooper7cc4a4c2010-09-14 09:45:30 -0400962void wlc_phy_hw_state_upd(wlc_phy_t *pih, bool newstate)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700963{
964 phy_info_t *pi = (phy_info_t *) pih;
965
966 if (!pi || !pi->sh)
967 return;
968
969 pi->sh->up = newstate;
970}
971
Jason Coopera2627bc2010-09-14 09:45:31 -0400972void WLBANDINITFN(wlc_phy_init) (wlc_phy_t *pih, chanspec_t chanspec)
973{
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -0700974 u32 mc;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700975 initfn_t phy_init = NULL;
976 phy_info_t *pi = (phy_info_t *) pih;
977
978 if (pi->init_in_progress)
979 return;
980
Greg Kroah-Hartman0f0881b2010-10-12 12:15:18 -0700981 pi->init_in_progress = true;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700982
983 pi->radio_chanspec = chanspec;
984
985 mc = R_REG(pi->sh->osh, &pi->regs->maccontrol);
986 if ((mc & MCTL_EN_MAC) != 0) {
987 ASSERT((const char *)
988 "wlc_phy_init: Called with the MAC running!" == NULL);
989 }
990
991 ASSERT(pi != NULL);
992
993 if (!(pi->measure_hold & PHY_HOLD_FOR_SCAN)) {
994 pi->measure_hold |= PHY_HOLD_FOR_NOT_ASSOC;
995 }
996
997 if (D11REV_GE(pi->sh->corerev, 5))
998 ASSERT(si_core_sflags(pi->sh->sih, 0, 0) & SISF_FCLKA);
999
1000 phy_init = pi->pi_fptr.init;
1001
1002 if (phy_init == NULL) {
1003 ASSERT(phy_init != NULL);
1004 return;
1005 }
1006
1007 wlc_phy_anacore(pih, ON);
1008
1009 if (CHSPEC_BW(pi->radio_chanspec) != pi->bw)
1010 wlapi_bmac_bw_set(pi->sh->physhim,
1011 CHSPEC_BW(pi->radio_chanspec));
1012
Greg Kroah-Hartman0f0881b2010-10-12 12:15:18 -07001013 pi->nphy_gain_boost = true;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001014
1015 wlc_phy_switch_radio((wlc_phy_t *) pi, ON);
1016
1017 (*phy_init) (pi);
1018
Greg Kroah-Hartman0965ae82010-10-12 12:50:15 -07001019 pi->phy_init_por = false;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001020
1021 if (D11REV_IS(pi->sh->corerev, 11) || D11REV_IS(pi->sh->corerev, 12))
Greg Kroah-Hartman0f0881b2010-10-12 12:15:18 -07001022 wlc_phy_do_dummy_tx(pi, true, OFF);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001023
1024 if (!(ISNPHY(pi)))
1025 wlc_phy_txpower_update_shm(pi);
1026
1027 wlc_phy_ant_rxdiv_set((wlc_phy_t *) pi, pi->sh->rx_antdiv);
1028
Greg Kroah-Hartman0965ae82010-10-12 12:50:15 -07001029 pi->init_in_progress = false;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001030}
1031
Jason Cooperb4f790e2010-10-11 10:02:58 -04001032void wlc_phy_cal_init(wlc_phy_t *pih)
Jason Coopera2627bc2010-09-14 09:45:31 -04001033{
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001034 phy_info_t *pi = (phy_info_t *) pih;
1035 initfn_t cal_init = NULL;
1036
1037 ASSERT((R_REG(pi->sh->osh, &pi->regs->maccontrol) & MCTL_EN_MAC) == 0);
1038
1039 if (!pi->initialized) {
1040 cal_init = pi->pi_fptr.calinit;
1041 if (cal_init)
1042 (*cal_init) (pi);
1043
Greg Kroah-Hartman0f0881b2010-10-12 12:15:18 -07001044 pi->initialized = true;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001045 }
1046}
1047
Jason Cooper9927fc22010-10-11 10:02:59 -04001048int wlc_phy_down(wlc_phy_t *pih)
Jason Coopera2627bc2010-09-14 09:45:31 -04001049{
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001050 phy_info_t *pi = (phy_info_t *) pih;
1051 int callbacks = 0;
1052
Greg Kroah-Hartman0965ae82010-10-12 12:50:15 -07001053 ASSERT(pi->phytest_on == false);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001054
1055 if (pi->phycal_timer
1056 && !wlapi_del_timer(pi->sh->physhim, pi->phycal_timer))
1057 callbacks++;
1058
1059 pi->nphy_iqcal_chanspec_2G = 0;
1060 pi->nphy_iqcal_chanspec_5G = 0;
1061
1062 return callbacks;
1063}
1064
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -07001065static u32 wlc_phy_get_radio_ver(phy_info_t *pi)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001066{
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -07001067 u32 ver;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001068
1069 ver = read_radio_id(pi);
1070
1071 return ver;
1072}
1073
1074void
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04001075wlc_phy_table_addr(phy_info_t *pi, uint tbl_id, uint tbl_offset,
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -07001076 u16 tblAddr, u16 tblDataHi, u16 tblDataLo)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001077{
1078 write_phy_reg(pi, tblAddr, (tbl_id << 10) | tbl_offset);
1079
1080 pi->tbl_data_hi = tblDataHi;
1081 pi->tbl_data_lo = tblDataLo;
1082
1083 if ((CHIPID(pi->sh->chip) == BCM43224_CHIP_ID ||
1084 CHIPID(pi->sh->chip) == BCM43421_CHIP_ID) &&
1085 (pi->sh->chiprev == 1)) {
1086 pi->tbl_addr = tblAddr;
1087 pi->tbl_save_id = tbl_id;
1088 pi->tbl_save_offset = tbl_offset;
1089 }
1090}
1091
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -07001092void wlc_phy_table_data_write(phy_info_t *pi, uint width, u32 val)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001093{
1094 ASSERT((width == 8) || (width == 16) || (width == 32));
1095
1096 if ((CHIPID(pi->sh->chip) == BCM43224_CHIP_ID ||
1097 CHIPID(pi->sh->chip) == BCM43421_CHIP_ID) &&
1098 (pi->sh->chiprev == 1) &&
1099 (pi->tbl_save_id == NPHY_TBL_ID_ANTSWCTRLLUT)) {
1100 read_phy_reg(pi, pi->tbl_data_lo);
1101
1102 write_phy_reg(pi, pi->tbl_addr,
1103 (pi->tbl_save_id << 10) | pi->tbl_save_offset);
1104 pi->tbl_save_offset++;
1105 }
1106
1107 if (width == 32) {
1108
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -07001109 write_phy_reg(pi, pi->tbl_data_hi, (u16) (val >> 16));
1110 write_phy_reg(pi, pi->tbl_data_lo, (u16) val);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001111 } else {
1112
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -07001113 write_phy_reg(pi, pi->tbl_data_lo, (u16) val);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001114 }
1115}
1116
1117void
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04001118wlc_phy_write_table(phy_info_t *pi, const phytbl_info_t *ptbl_info,
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -07001119 u16 tblAddr, u16 tblDataHi, u16 tblDataLo)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001120{
1121 uint idx;
1122 uint tbl_id = ptbl_info->tbl_id;
1123 uint tbl_offset = ptbl_info->tbl_offset;
1124 uint tbl_width = ptbl_info->tbl_width;
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07001125 const u8 *ptbl_8b = (const u8 *)ptbl_info->tbl_ptr;
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -07001126 const u16 *ptbl_16b = (const u16 *)ptbl_info->tbl_ptr;
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -07001127 const u32 *ptbl_32b = (const u32 *)ptbl_info->tbl_ptr;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001128
1129 ASSERT((tbl_width == 8) || (tbl_width == 16) || (tbl_width == 32));
1130
1131 write_phy_reg(pi, tblAddr, (tbl_id << 10) | tbl_offset);
1132
1133 for (idx = 0; idx < ptbl_info->tbl_len; idx++) {
1134
1135 if ((CHIPID(pi->sh->chip) == BCM43224_CHIP_ID ||
1136 CHIPID(pi->sh->chip) == BCM43421_CHIP_ID) &&
1137 (pi->sh->chiprev == 1) &&
1138 (tbl_id == NPHY_TBL_ID_ANTSWCTRLLUT)) {
1139 read_phy_reg(pi, tblDataLo);
1140
1141 write_phy_reg(pi, tblAddr,
1142 (tbl_id << 10) | (tbl_offset + idx));
1143 }
1144
1145 if (tbl_width == 32) {
1146
1147 write_phy_reg(pi, tblDataHi,
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -07001148 (u16) (ptbl_32b[idx] >> 16));
1149 write_phy_reg(pi, tblDataLo, (u16) ptbl_32b[idx]);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001150 } else if (tbl_width == 16) {
1151
1152 write_phy_reg(pi, tblDataLo, ptbl_16b[idx]);
1153 } else {
1154
1155 write_phy_reg(pi, tblDataLo, ptbl_8b[idx]);
1156 }
1157 }
1158}
1159
1160void
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04001161wlc_phy_read_table(phy_info_t *pi, const phytbl_info_t *ptbl_info,
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -07001162 u16 tblAddr, u16 tblDataHi, u16 tblDataLo)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001163{
1164 uint idx;
1165 uint tbl_id = ptbl_info->tbl_id;
1166 uint tbl_offset = ptbl_info->tbl_offset;
1167 uint tbl_width = ptbl_info->tbl_width;
Greg Kroah-Hartman159a3b72010-10-12 13:20:00 -07001168 u8 *ptbl_8b = (u8 *)ptbl_info->tbl_ptr;
1169 u16 *ptbl_16b = (u16 *)ptbl_info->tbl_ptr;
1170 u32 *ptbl_32b = (u32 *)ptbl_info->tbl_ptr;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001171
1172 ASSERT((tbl_width == 8) || (tbl_width == 16) || (tbl_width == 32));
1173
1174 write_phy_reg(pi, tblAddr, (tbl_id << 10) | tbl_offset);
1175
1176 for (idx = 0; idx < ptbl_info->tbl_len; idx++) {
1177
1178 if ((CHIPID(pi->sh->chip) == BCM43224_CHIP_ID ||
1179 CHIPID(pi->sh->chip) == BCM43421_CHIP_ID) &&
1180 (pi->sh->chiprev == 1)) {
1181 (void)read_phy_reg(pi, tblDataLo);
1182
1183 write_phy_reg(pi, tblAddr,
1184 (tbl_id << 10) | (tbl_offset + idx));
1185 }
1186
1187 if (tbl_width == 32) {
1188
1189 ptbl_32b[idx] = read_phy_reg(pi, tblDataLo);
1190 ptbl_32b[idx] |= (read_phy_reg(pi, tblDataHi) << 16);
1191 } else if (tbl_width == 16) {
1192
1193 ptbl_16b[idx] = read_phy_reg(pi, tblDataLo);
1194 } else {
1195
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07001196 ptbl_8b[idx] = (u8) read_phy_reg(pi, tblDataLo);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001197 }
1198 }
1199}
1200
1201uint
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04001202wlc_phy_init_radio_regs_allbands(phy_info_t *pi, radio_20xx_regs_t *radioregs)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001203{
1204 uint i = 0;
1205
1206 do {
1207 if (radioregs[i].do_init) {
1208 write_radio_reg(pi, radioregs[i].address,
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -07001209 (u16) radioregs[i].init);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001210 }
1211
1212 i++;
1213 } while (radioregs[i].address != 0xffff);
1214
1215 return i;
1216}
1217
1218uint
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04001219wlc_phy_init_radio_regs(phy_info_t *pi, radio_regs_t *radioregs,
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -07001220 u16 core_offset)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001221{
1222 uint i = 0;
1223 uint count = 0;
1224
1225 do {
1226 if (CHSPEC_IS5G(pi->radio_chanspec)) {
1227 if (radioregs[i].do_init_a) {
1228 write_radio_reg(pi,
1229 radioregs[i].
1230 address | core_offset,
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -07001231 (u16) radioregs[i].init_a);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001232 if (ISNPHY(pi) && (++count % 4 == 0))
1233 WLC_PHY_WAR_PR51571(pi);
1234 }
1235 } else {
1236 if (radioregs[i].do_init_g) {
1237 write_radio_reg(pi,
1238 radioregs[i].
1239 address | core_offset,
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -07001240 (u16) radioregs[i].init_g);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001241 if (ISNPHY(pi) && (++count % 4 == 0))
1242 WLC_PHY_WAR_PR51571(pi);
1243 }
1244 }
1245
1246 i++;
1247 } while (radioregs[i].address != 0xffff);
1248
1249 return i;
1250}
1251
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04001252void wlc_phy_do_dummy_tx(phy_info_t *pi, bool ofdm, bool pa_on)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001253{
1254#define DUMMY_PKT_LEN 20
1255 d11regs_t *regs = pi->regs;
1256 int i, count;
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07001257 u8 ofdmpkt[DUMMY_PKT_LEN] = {
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001258 0xcc, 0x01, 0x02, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00,
1259 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00
1260 };
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07001261 u8 cckpkt[DUMMY_PKT_LEN] = {
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001262 0x6e, 0x84, 0x0b, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00,
1263 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00
1264 };
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -07001265 u32 *dummypkt;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001266
1267 ASSERT((R_REG(pi->sh->osh, &pi->regs->maccontrol) & MCTL_EN_MAC) == 0);
1268
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -07001269 dummypkt = (u32 *) (ofdm ? ofdmpkt : cckpkt);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001270 wlapi_bmac_write_template_ram(pi->sh->physhim, 0, DUMMY_PKT_LEN,
1271 dummypkt);
1272
1273 W_REG(pi->sh->osh, &regs->xmtsel, 0);
1274
1275 if (D11REV_GE(pi->sh->corerev, 11))
1276 W_REG(pi->sh->osh, &regs->wepctl, 0x100);
1277 else
1278 W_REG(pi->sh->osh, &regs->wepctl, 0);
1279
1280 W_REG(pi->sh->osh, &regs->txe_phyctl, (ofdm ? 1 : 0) | PHY_TXC_ANT_0);
1281 if (ISNPHY(pi) || ISLCNPHY(pi)) {
1282 ASSERT(ofdm);
1283 W_REG(pi->sh->osh, &regs->txe_phyctl1, 0x1A02);
1284 }
1285
1286 W_REG(pi->sh->osh, &regs->txe_wm_0, 0);
1287 W_REG(pi->sh->osh, &regs->txe_wm_1, 0);
1288
1289 W_REG(pi->sh->osh, &regs->xmttplatetxptr, 0);
1290 W_REG(pi->sh->osh, &regs->xmttxcnt, DUMMY_PKT_LEN);
1291
1292 W_REG(pi->sh->osh, &regs->xmtsel, ((8 << 8) | (1 << 5) | (1 << 2) | 2));
1293
1294 W_REG(pi->sh->osh, &regs->txe_ctl, 0);
1295
1296 if (!pa_on) {
1297 if (ISNPHY(pi))
1298 wlc_phy_pa_override_nphy(pi, OFF);
1299 }
1300
1301 if (ISNPHY(pi) || ISLCNPHY(pi))
1302 W_REG(pi->sh->osh, &regs->txe_aux, 0xD0);
1303 else
1304 W_REG(pi->sh->osh, &regs->txe_aux, ((1 << 5) | (1 << 4)));
1305
1306 (void)R_REG(pi->sh->osh, &regs->txe_aux);
1307
1308 i = 0;
1309 count = ofdm ? 30 : 250;
1310
1311 if (ISSIM_ENAB(pi->sh->sih)) {
1312 count *= 100;
1313 }
1314
1315 while ((i++ < count)
1316 && (R_REG(pi->sh->osh, &regs->txe_status) & (1 << 7))) {
mike.rapoport@gmail.com73831412010-10-13 00:09:07 +02001317 udelay(10);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001318 }
1319
1320 i = 0;
1321
1322 while ((i++ < 10)
1323 && ((R_REG(pi->sh->osh, &regs->txe_status) & (1 << 10)) == 0)) {
mike.rapoport@gmail.com73831412010-10-13 00:09:07 +02001324 udelay(10);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001325 }
1326
1327 i = 0;
1328
1329 while ((i++ < 10) && ((R_REG(pi->sh->osh, &regs->ifsstat) & (1 << 8)))) {
mike.rapoport@gmail.com73831412010-10-13 00:09:07 +02001330 udelay(10);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001331 }
1332 if (!pa_on) {
1333 if (ISNPHY(pi))
1334 wlc_phy_pa_override_nphy(pi, ON);
1335 }
1336}
1337
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04001338void wlc_phy_hold_upd(wlc_phy_t *pih, mbool id, bool set)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001339{
1340 phy_info_t *pi = (phy_info_t *) pih;
1341 ASSERT(id);
1342
1343 if (set) {
1344 mboolset(pi->measure_hold, id);
1345 } else {
1346 mboolclr(pi->measure_hold, id);
1347 }
1348
1349 return;
1350}
1351
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04001352void wlc_phy_mute_upd(wlc_phy_t *pih, bool mute, mbool flags)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001353{
1354 phy_info_t *pi = (phy_info_t *) pih;
1355
1356 if (mute) {
1357 mboolset(pi->measure_hold, PHY_HOLD_FOR_MUTE);
1358 } else {
1359 mboolclr(pi->measure_hold, PHY_HOLD_FOR_MUTE);
1360 }
1361
1362 if (!mute && (flags & PHY_MUTE_FOR_PREISM))
1363 pi->nphy_perical_last = pi->sh->now - pi->sh->glacial_timer;
1364 return;
1365}
1366
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04001367void wlc_phy_clear_tssi(wlc_phy_t *pih)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001368{
1369 phy_info_t *pi = (phy_info_t *) pih;
1370
1371 if (ISNPHY(pi)) {
1372 return;
1373 } else {
1374 wlapi_bmac_write_shm(pi->sh->physhim, M_B_TSSI_0, NULL_TSSI_W);
1375 wlapi_bmac_write_shm(pi->sh->physhim, M_B_TSSI_1, NULL_TSSI_W);
1376 wlapi_bmac_write_shm(pi->sh->physhim, M_G_TSSI_0, NULL_TSSI_W);
1377 wlapi_bmac_write_shm(pi->sh->physhim, M_G_TSSI_1, NULL_TSSI_W);
1378 }
1379}
1380
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04001381static bool wlc_phy_cal_txpower_recalc_sw(phy_info_t *pi)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001382{
Greg Kroah-Hartman0965ae82010-10-12 12:50:15 -07001383 return false;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001384}
1385
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04001386void wlc_phy_switch_radio(wlc_phy_t *pih, bool on)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001387{
1388 phy_info_t *pi = (phy_info_t *) pih;
1389
1390 if (NORADIO_ENAB(pi->pubpi))
1391 return;
1392
1393 {
1394 uint mc;
1395
1396 mc = R_REG(pi->sh->osh, &pi->regs->maccontrol);
1397 }
1398
1399 if (ISNPHY(pi)) {
1400 wlc_phy_switch_radio_nphy(pi, on);
1401
1402 } else if (ISLCNPHY(pi)) {
1403 if (on) {
1404 and_phy_reg(pi, 0x44c,
1405 ~((0x1 << 8) |
1406 (0x1 << 9) |
1407 (0x1 << 10) | (0x1 << 11) | (0x1 << 12)));
1408 and_phy_reg(pi, 0x4b0, ~((0x1 << 3) | (0x1 << 11)));
1409 and_phy_reg(pi, 0x4f9, ~(0x1 << 3));
1410 } else {
1411 and_phy_reg(pi, 0x44d,
1412 ~((0x1 << 10) |
1413 (0x1 << 11) |
1414 (0x1 << 12) | (0x1 << 13) | (0x1 << 14)));
1415 or_phy_reg(pi, 0x44c,
1416 (0x1 << 8) |
1417 (0x1 << 9) |
1418 (0x1 << 10) | (0x1 << 11) | (0x1 << 12));
1419
1420 and_phy_reg(pi, 0x4b7, ~((0x7f << 8)));
1421 and_phy_reg(pi, 0x4b1, ~((0x1 << 13)));
1422 or_phy_reg(pi, 0x4b0, (0x1 << 3) | (0x1 << 11));
1423 and_phy_reg(pi, 0x4fa, ~((0x1 << 3)));
1424 or_phy_reg(pi, 0x4f9, (0x1 << 3));
1425 }
1426 }
1427}
1428
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -07001429u16 wlc_phy_bw_state_get(wlc_phy_t *ppi)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001430{
1431 phy_info_t *pi = (phy_info_t *) ppi;
1432
1433 return pi->bw;
1434}
1435
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -07001436void wlc_phy_bw_state_set(wlc_phy_t *ppi, u16 bw)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001437{
1438 phy_info_t *pi = (phy_info_t *) ppi;
1439
1440 pi->bw = bw;
1441}
1442
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04001443void wlc_phy_chanspec_radio_set(wlc_phy_t *ppi, chanspec_t newch)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001444{
1445 phy_info_t *pi = (phy_info_t *) ppi;
1446 pi->radio_chanspec = newch;
1447
1448}
1449
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04001450chanspec_t wlc_phy_chanspec_get(wlc_phy_t *ppi)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001451{
1452 phy_info_t *pi = (phy_info_t *) ppi;
1453
1454 return pi->radio_chanspec;
1455}
1456
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04001457void wlc_phy_chanspec_set(wlc_phy_t *ppi, chanspec_t chanspec)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001458{
1459 phy_info_t *pi = (phy_info_t *) ppi;
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -07001460 u16 m_cur_channel;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001461 chansetfn_t chanspec_set = NULL;
1462
1463 ASSERT(!wf_chspec_malformed(chanspec));
1464
1465 m_cur_channel = CHSPEC_CHANNEL(chanspec);
1466 if (CHSPEC_IS5G(chanspec))
1467 m_cur_channel |= D11_CURCHANNEL_5G;
1468 if (CHSPEC_IS40(chanspec))
1469 m_cur_channel |= D11_CURCHANNEL_40;
1470 wlapi_bmac_write_shm(pi->sh->physhim, M_CURCHANNEL, m_cur_channel);
1471
1472 chanspec_set = pi->pi_fptr.chanset;
1473 if (chanspec_set)
1474 (*chanspec_set) (pi, chanspec);
1475
1476}
1477
1478int wlc_phy_chanspec_freq2bandrange_lpssn(uint freq)
1479{
1480 int range = -1;
1481
1482 if (freq < 2500)
1483 range = WL_CHAN_FREQ_RANGE_2G;
1484 else if (freq <= 5320)
1485 range = WL_CHAN_FREQ_RANGE_5GL;
1486 else if (freq <= 5700)
1487 range = WL_CHAN_FREQ_RANGE_5GM;
1488 else
1489 range = WL_CHAN_FREQ_RANGE_5GH;
1490
1491 return range;
1492}
1493
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04001494int wlc_phy_chanspec_bandrange_get(phy_info_t *pi, chanspec_t chanspec)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001495{
1496 int range = -1;
1497 uint channel = CHSPEC_CHANNEL(chanspec);
1498 uint freq = wlc_phy_channel2freq(channel);
1499
1500 if (ISNPHY(pi)) {
1501 range = wlc_phy_get_chan_freq_range_nphy(pi, channel);
1502 } else if (ISLCNPHY(pi)) {
1503 range = wlc_phy_chanspec_freq2bandrange_lpssn(freq);
1504 } else
1505 ASSERT(0);
1506
1507 return range;
1508}
1509
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04001510void wlc_phy_chanspec_ch14_widefilter_set(wlc_phy_t *ppi, bool wide_filter)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001511{
1512 phy_info_t *pi = (phy_info_t *) ppi;
1513
1514 pi->channel_14_wide_filter = wide_filter;
1515
1516}
1517
1518int wlc_phy_channel2freq(uint channel)
1519{
1520 uint i;
1521
Greg Kroah-Hartman8d3d6a62010-10-08 11:47:11 -07001522 for (i = 0; i < ARRAY_SIZE(chan_info_all); i++)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001523 if (chan_info_all[i].chan == channel)
Jason Cooper90ea2292010-09-14 09:45:32 -04001524 return chan_info_all[i].freq;
1525 return 0;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001526}
1527
1528void
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04001529wlc_phy_chanspec_band_validch(wlc_phy_t *ppi, uint band, chanvec_t *channels)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001530{
1531 phy_info_t *pi = (phy_info_t *) ppi;
1532 uint i;
1533 uint channel;
1534
1535 ASSERT((band == WLC_BAND_2G) || (band == WLC_BAND_5G));
1536
1537 bzero(channels, sizeof(chanvec_t));
1538
Greg Kroah-Hartman8d3d6a62010-10-08 11:47:11 -07001539 for (i = 0; i < ARRAY_SIZE(chan_info_all); i++) {
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001540 channel = chan_info_all[i].chan;
1541
1542 if ((pi->a_band_high_disable) && (channel >= FIRST_REF5_CHANNUM)
1543 && (channel <= LAST_REF5_CHANNUM))
1544 continue;
1545
1546 if (((band == WLC_BAND_2G) && (channel <= CH_MAX_2G_CHANNEL)) ||
1547 ((band == WLC_BAND_5G) && (channel > CH_MAX_2G_CHANNEL)))
1548 setbit(channels->vec, channel);
1549 }
1550}
1551
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04001552chanspec_t wlc_phy_chanspec_band_firstch(wlc_phy_t *ppi, uint band)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001553{
1554 phy_info_t *pi = (phy_info_t *) ppi;
1555 uint i;
1556 uint channel;
1557 chanspec_t chspec;
1558
1559 ASSERT((band == WLC_BAND_2G) || (band == WLC_BAND_5G));
1560
Greg Kroah-Hartman8d3d6a62010-10-08 11:47:11 -07001561 for (i = 0; i < ARRAY_SIZE(chan_info_all); i++) {
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001562 channel = chan_info_all[i].chan;
1563
1564 if (ISNPHY(pi) && IS40MHZ(pi)) {
1565 uint j;
1566
Greg Kroah-Hartman8d3d6a62010-10-08 11:47:11 -07001567 for (j = 0; j < ARRAY_SIZE(chan_info_all); j++) {
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001568 if (chan_info_all[j].chan ==
1569 channel + CH_10MHZ_APART)
1570 break;
1571 }
1572
Greg Kroah-Hartman8d3d6a62010-10-08 11:47:11 -07001573 if (j == ARRAY_SIZE(chan_info_all))
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001574 continue;
1575
1576 channel = UPPER_20_SB(channel);
1577 chspec =
1578 channel | WL_CHANSPEC_BW_40 |
1579 WL_CHANSPEC_CTL_SB_LOWER;
1580 if (band == WLC_BAND_2G)
1581 chspec |= WL_CHANSPEC_BAND_2G;
1582 else
1583 chspec |= WL_CHANSPEC_BAND_5G;
1584 } else
1585 chspec = CH20MHZ_CHSPEC(channel);
1586
1587 if ((pi->a_band_high_disable) && (channel >= FIRST_REF5_CHANNUM)
1588 && (channel <= LAST_REF5_CHANNUM))
1589 continue;
1590
1591 if (((band == WLC_BAND_2G) && (channel <= CH_MAX_2G_CHANNEL)) ||
1592 ((band == WLC_BAND_5G) && (channel > CH_MAX_2G_CHANNEL)))
1593 return chspec;
1594 }
1595
1596 ASSERT(0);
1597
1598 return (chanspec_t) INVCHANSPEC;
1599}
1600
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04001601int wlc_phy_txpower_get(wlc_phy_t *ppi, uint *qdbm, bool *override)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001602{
1603 phy_info_t *pi = (phy_info_t *) ppi;
1604
1605 ASSERT(qdbm != NULL);
1606 *qdbm = pi->tx_user_target[0];
1607 if (override != NULL)
1608 *override = pi->txpwroverride;
Jason Cooper90ea2292010-09-14 09:45:32 -04001609 return 0;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001610}
1611
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04001612void wlc_phy_txpower_target_set(wlc_phy_t *ppi, struct txpwr_limits *txpwr)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001613{
Greg Kroah-Hartman0965ae82010-10-12 12:50:15 -07001614 bool mac_enabled = false;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001615 phy_info_t *pi = (phy_info_t *) ppi;
1616
1617 bcopy(&txpwr->cck[0], &pi->tx_user_target[TXP_FIRST_CCK],
1618 WLC_NUM_RATES_CCK);
1619
1620 bcopy(&txpwr->ofdm[0], &pi->tx_user_target[TXP_FIRST_OFDM],
1621 WLC_NUM_RATES_OFDM);
1622 bcopy(&txpwr->ofdm_cdd[0], &pi->tx_user_target[TXP_FIRST_OFDM_20_CDD],
1623 WLC_NUM_RATES_OFDM);
1624
1625 bcopy(&txpwr->ofdm_40_siso[0],
1626 &pi->tx_user_target[TXP_FIRST_OFDM_40_SISO], WLC_NUM_RATES_OFDM);
1627 bcopy(&txpwr->ofdm_40_cdd[0],
1628 &pi->tx_user_target[TXP_FIRST_OFDM_40_CDD], WLC_NUM_RATES_OFDM);
1629
1630 bcopy(&txpwr->mcs_20_siso[0],
1631 &pi->tx_user_target[TXP_FIRST_MCS_20_SISO],
1632 WLC_NUM_RATES_MCS_1_STREAM);
1633 bcopy(&txpwr->mcs_20_cdd[0], &pi->tx_user_target[TXP_FIRST_MCS_20_CDD],
1634 WLC_NUM_RATES_MCS_1_STREAM);
1635 bcopy(&txpwr->mcs_20_stbc[0],
1636 &pi->tx_user_target[TXP_FIRST_MCS_20_STBC],
1637 WLC_NUM_RATES_MCS_1_STREAM);
1638 bcopy(&txpwr->mcs_20_mimo[0], &pi->tx_user_target[TXP_FIRST_MCS_20_SDM],
1639 WLC_NUM_RATES_MCS_2_STREAM);
1640
1641 bcopy(&txpwr->mcs_40_siso[0],
1642 &pi->tx_user_target[TXP_FIRST_MCS_40_SISO],
1643 WLC_NUM_RATES_MCS_1_STREAM);
1644 bcopy(&txpwr->mcs_40_cdd[0], &pi->tx_user_target[TXP_FIRST_MCS_40_CDD],
1645 WLC_NUM_RATES_MCS_1_STREAM);
1646 bcopy(&txpwr->mcs_40_stbc[0],
1647 &pi->tx_user_target[TXP_FIRST_MCS_40_STBC],
1648 WLC_NUM_RATES_MCS_1_STREAM);
1649 bcopy(&txpwr->mcs_40_mimo[0], &pi->tx_user_target[TXP_FIRST_MCS_40_SDM],
1650 WLC_NUM_RATES_MCS_2_STREAM);
1651
1652 if (R_REG(pi->sh->osh, &pi->regs->maccontrol) & MCTL_EN_MAC)
Greg Kroah-Hartman0f0881b2010-10-12 12:15:18 -07001653 mac_enabled = true;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001654
1655 if (mac_enabled)
1656 wlapi_suspend_mac_and_wait(pi->sh->physhim);
1657
1658 wlc_phy_txpower_recalc_target(pi);
1659 wlc_phy_cal_txpower_recalc_sw(pi);
1660
1661 if (mac_enabled)
1662 wlapi_enable_mac(pi->sh->physhim);
1663}
1664
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04001665int wlc_phy_txpower_set(wlc_phy_t *ppi, uint qdbm, bool override)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001666{
1667 phy_info_t *pi = (phy_info_t *) ppi;
1668 int i;
1669
1670 if (qdbm > 127)
1671 return 5;
1672
1673 for (i = 0; i < TXP_NUM_RATES; i++)
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07001674 pi->tx_user_target[i] = (u8) qdbm;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001675
Greg Kroah-Hartman0965ae82010-10-12 12:50:15 -07001676 pi->txpwroverride = false;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001677
1678 if (pi->sh->up) {
1679 if (!SCAN_INPROG_PHY(pi)) {
1680 bool suspend;
1681
1682 suspend =
1683 (0 ==
1684 (R_REG(pi->sh->osh, &pi->regs->maccontrol) &
1685 MCTL_EN_MAC));
1686
1687 if (!suspend)
1688 wlapi_suspend_mac_and_wait(pi->sh->physhim);
1689
1690 wlc_phy_txpower_recalc_target(pi);
1691 wlc_phy_cal_txpower_recalc_sw(pi);
1692
1693 if (!suspend)
1694 wlapi_enable_mac(pi->sh->physhim);
1695 }
1696 }
Jason Cooper90ea2292010-09-14 09:45:32 -04001697 return 0;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001698}
1699
1700void
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07001701wlc_phy_txpower_sromlimit(wlc_phy_t *ppi, uint channel, u8 *min_pwr,
1702 u8 *max_pwr, int txp_rate_idx)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001703{
1704 phy_info_t *pi = (phy_info_t *) ppi;
1705 uint i;
1706
1707 *min_pwr = pi->min_txpower * WLC_TXPWR_DB_FACTOR;
1708
1709 if (ISNPHY(pi)) {
1710 if (txp_rate_idx < 0)
1711 txp_rate_idx = TXP_FIRST_CCK;
1712 wlc_phy_txpower_sromlimit_get_nphy(pi, channel, max_pwr,
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07001713 (u8) txp_rate_idx);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001714
1715 } else if ((channel <= CH_MAX_2G_CHANNEL)) {
1716 if (txp_rate_idx < 0)
1717 txp_rate_idx = TXP_FIRST_CCK;
1718 *max_pwr = pi->tx_srom_max_rate_2g[txp_rate_idx];
1719 } else {
1720
1721 *max_pwr = WLC_TXPWR_MAX;
1722
1723 if (txp_rate_idx < 0)
1724 txp_rate_idx = TXP_FIRST_OFDM;
1725
Greg Kroah-Hartman8d3d6a62010-10-08 11:47:11 -07001726 for (i = 0; i < ARRAY_SIZE(chan_info_all); i++) {
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001727 if (channel == chan_info_all[i].chan) {
1728 break;
1729 }
1730 }
Greg Kroah-Hartman8d3d6a62010-10-08 11:47:11 -07001731 ASSERT(i < ARRAY_SIZE(chan_info_all));
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001732
1733 if (pi->hwtxpwr) {
1734 *max_pwr = pi->hwtxpwr[i];
1735 } else {
1736
1737 if ((i >= FIRST_MID_5G_CHAN) && (i <= LAST_MID_5G_CHAN))
1738 *max_pwr =
1739 pi->tx_srom_max_rate_5g_mid[txp_rate_idx];
1740 if ((i >= FIRST_HIGH_5G_CHAN)
1741 && (i <= LAST_HIGH_5G_CHAN))
1742 *max_pwr =
1743 pi->tx_srom_max_rate_5g_hi[txp_rate_idx];
1744 if ((i >= FIRST_LOW_5G_CHAN) && (i <= LAST_LOW_5G_CHAN))
1745 *max_pwr =
1746 pi->tx_srom_max_rate_5g_low[txp_rate_idx];
1747 }
1748 }
1749}
1750
1751void
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07001752wlc_phy_txpower_sromlimit_max_get(wlc_phy_t *ppi, uint chan, u8 *max_txpwr,
1753 u8 *min_txpwr)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001754{
1755 phy_info_t *pi = (phy_info_t *) ppi;
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07001756 u8 tx_pwr_max = 0;
1757 u8 tx_pwr_min = 255;
1758 u8 max_num_rate;
1759 u8 maxtxpwr, mintxpwr, rate, pactrl;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001760
1761 pactrl = 0;
1762
1763 max_num_rate = ISNPHY(pi) ? TXP_NUM_RATES :
1764 ISLCNPHY(pi) ? (TXP_LAST_SISO_MCS_20 + 1) : (TXP_LAST_OFDM + 1);
1765
1766 for (rate = 0; rate < max_num_rate; rate++) {
1767
1768 wlc_phy_txpower_sromlimit(ppi, chan, &mintxpwr, &maxtxpwr,
1769 rate);
1770
1771 maxtxpwr = (maxtxpwr > pactrl) ? (maxtxpwr - pactrl) : 0;
1772
1773 maxtxpwr = (maxtxpwr > 6) ? (maxtxpwr - 6) : 0;
1774
Greg Kroah-Hartman3ea2f4d2010-10-08 11:39:43 -07001775 tx_pwr_max = max(tx_pwr_max, maxtxpwr);
Greg Kroah-Hartman7068c2f2010-10-08 11:34:59 -07001776 tx_pwr_min = min(tx_pwr_min, maxtxpwr);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001777 }
1778 *max_txpwr = tx_pwr_max;
1779 *min_txpwr = tx_pwr_min;
1780}
1781
1782void
Greg Kroah-Hartman3e264162010-10-08 11:11:13 -07001783wlc_phy_txpower_boardlimit_band(wlc_phy_t *ppi, uint bandunit, s32 *max_pwr,
1784 s32 *min_pwr, u32 *step_pwr)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001785{
1786 return;
1787}
1788
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07001789u8 wlc_phy_txpower_get_target_min(wlc_phy_t *ppi)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001790{
1791 phy_info_t *pi = (phy_info_t *) ppi;
1792
1793 return pi->tx_power_min;
1794}
1795
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07001796u8 wlc_phy_txpower_get_target_max(wlc_phy_t *ppi)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001797{
1798 phy_info_t *pi = (phy_info_t *) ppi;
1799
1800 return pi->tx_power_max;
1801}
1802
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04001803void wlc_phy_txpower_recalc_target(phy_info_t *pi)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001804{
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07001805 u8 maxtxpwr, mintxpwr, rate, pactrl;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001806 uint target_chan;
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07001807 u8 tx_pwr_target[TXP_NUM_RATES];
1808 u8 tx_pwr_max = 0;
1809 u8 tx_pwr_min = 255;
1810 u8 tx_pwr_max_rate_ind = 0;
1811 u8 max_num_rate;
1812 u8 start_rate = 0;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001813 chanspec_t chspec;
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -07001814 u32 band = CHSPEC2WLC_BAND(pi->radio_chanspec);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001815 initfn_t txpwr_recalc_fn = NULL;
1816
1817 chspec = pi->radio_chanspec;
1818 if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_NONE)
1819 target_chan = CHSPEC_CHANNEL(chspec);
1820 else if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_UPPER)
1821 target_chan = UPPER_20_SB(CHSPEC_CHANNEL(chspec));
1822 else
1823 target_chan = LOWER_20_SB(CHSPEC_CHANNEL(chspec));
1824
1825 pactrl = 0;
1826 if (ISLCNPHY(pi)) {
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -07001827 u32 offset_mcs, i;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001828
1829 if (CHSPEC_IS40(pi->radio_chanspec)) {
1830 offset_mcs = pi->mcs40_po;
1831 for (i = TXP_FIRST_SISO_MCS_20;
1832 i <= TXP_LAST_SISO_MCS_20; i++) {
1833 pi->tx_srom_max_rate_2g[i - 8] =
1834 pi->tx_srom_max_2g -
1835 ((offset_mcs & 0xf) * 2);
1836 offset_mcs >>= 4;
1837 }
1838 } else {
1839 offset_mcs = pi->mcs20_po;
1840 for (i = TXP_FIRST_SISO_MCS_20;
1841 i <= TXP_LAST_SISO_MCS_20; i++) {
1842 pi->tx_srom_max_rate_2g[i - 8] =
1843 pi->tx_srom_max_2g -
1844 ((offset_mcs & 0xf) * 2);
1845 offset_mcs >>= 4;
1846 }
1847 }
1848 }
1849#if WL11N
1850 max_num_rate = ((ISNPHY(pi)) ? (TXP_NUM_RATES) :
1851 ((ISLCNPHY(pi)) ?
1852 (TXP_LAST_SISO_MCS_20 + 1) : (TXP_LAST_OFDM + 1)));
1853#else
1854 max_num_rate = ((ISNPHY(pi)) ? (TXP_NUM_RATES) : (TXP_LAST_OFDM + 1));
1855#endif
1856
1857 wlc_phy_upd_env_txpwr_rate_limits(pi, band);
1858
1859 for (rate = start_rate; rate < max_num_rate; rate++) {
1860
1861 tx_pwr_target[rate] = pi->tx_user_target[rate];
1862
1863 if (pi->user_txpwr_at_rfport) {
1864 tx_pwr_target[rate] +=
1865 wlc_user_txpwr_antport_to_rfport(pi, target_chan,
1866 band, rate);
1867 }
1868
1869 {
1870
1871 wlc_phy_txpower_sromlimit((wlc_phy_t *) pi, target_chan,
1872 &mintxpwr, &maxtxpwr, rate);
1873
Greg Kroah-Hartman7068c2f2010-10-08 11:34:59 -07001874 maxtxpwr = min(maxtxpwr, pi->txpwr_limit[rate]);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001875
1876 maxtxpwr =
1877 (maxtxpwr > pactrl) ? (maxtxpwr - pactrl) : 0;
1878
1879 maxtxpwr = (maxtxpwr > 6) ? (maxtxpwr - 6) : 0;
1880
Greg Kroah-Hartman7068c2f2010-10-08 11:34:59 -07001881 maxtxpwr = min(maxtxpwr, tx_pwr_target[rate]);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001882
1883 if (pi->txpwr_percent <= 100)
1884 maxtxpwr = (maxtxpwr * pi->txpwr_percent) / 100;
1885
Greg Kroah-Hartman3ea2f4d2010-10-08 11:39:43 -07001886 tx_pwr_target[rate] = max(maxtxpwr, mintxpwr);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001887 }
1888
1889 tx_pwr_target[rate] =
Greg Kroah-Hartman7068c2f2010-10-08 11:34:59 -07001890 min(tx_pwr_target[rate], pi->txpwr_env_limit[rate]);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001891
1892 if (tx_pwr_target[rate] > tx_pwr_max)
1893 tx_pwr_max_rate_ind = rate;
1894
Greg Kroah-Hartman3ea2f4d2010-10-08 11:39:43 -07001895 tx_pwr_max = max(tx_pwr_max, tx_pwr_target[rate]);
Greg Kroah-Hartman7068c2f2010-10-08 11:34:59 -07001896 tx_pwr_min = min(tx_pwr_min, tx_pwr_target[rate]);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001897 }
1898
1899 bzero(pi->tx_power_offset, sizeof(pi->tx_power_offset));
1900 pi->tx_power_max = tx_pwr_max;
1901 pi->tx_power_min = tx_pwr_min;
1902 pi->tx_power_max_rate_ind = tx_pwr_max_rate_ind;
1903 for (rate = 0; rate < max_num_rate; rate++) {
1904
1905 pi->tx_power_target[rate] = tx_pwr_target[rate];
1906
1907 if (!pi->hwpwrctrl || ISNPHY(pi)) {
1908 pi->tx_power_offset[rate] =
1909 pi->tx_power_max - pi->tx_power_target[rate];
1910 } else {
1911 pi->tx_power_offset[rate] =
1912 pi->tx_power_target[rate] - pi->tx_power_min;
1913 }
1914 }
1915
1916 txpwr_recalc_fn = pi->pi_fptr.txpwrrecalc;
1917 if (txpwr_recalc_fn)
1918 (*txpwr_recalc_fn) (pi);
1919}
1920
1921void
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04001922wlc_phy_txpower_reg_limit_calc(phy_info_t *pi, struct txpwr_limits *txpwr,
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001923 chanspec_t chanspec)
1924{
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07001925 u8 tmp_txpwr_limit[2 * WLC_NUM_RATES_OFDM];
1926 u8 *txpwr_ptr1 = NULL, *txpwr_ptr2 = NULL;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001927 int rate_start_index = 0, rate1, rate2, k;
1928
1929 for (rate1 = WL_TX_POWER_CCK_FIRST, rate2 = 0;
1930 rate2 < WL_TX_POWER_CCK_NUM; rate1++, rate2++)
1931 pi->txpwr_limit[rate1] = txpwr->cck[rate2];
1932
1933 for (rate1 = WL_TX_POWER_OFDM_FIRST, rate2 = 0;
1934 rate2 < WL_TX_POWER_OFDM_NUM; rate1++, rate2++)
1935 pi->txpwr_limit[rate1] = txpwr->ofdm[rate2];
1936
1937 if (ISNPHY(pi)) {
1938
1939 for (k = 0; k < 4; k++) {
1940 switch (k) {
1941 case 0:
1942
1943 txpwr_ptr1 = txpwr->mcs_20_siso;
1944 txpwr_ptr2 = txpwr->ofdm;
1945 rate_start_index = WL_TX_POWER_OFDM_FIRST;
1946 break;
1947 case 1:
1948
1949 txpwr_ptr1 = txpwr->mcs_20_cdd;
1950 txpwr_ptr2 = txpwr->ofdm_cdd;
1951 rate_start_index = WL_TX_POWER_OFDM20_CDD_FIRST;
1952 break;
1953 case 2:
1954
1955 txpwr_ptr1 = txpwr->mcs_40_siso;
1956 txpwr_ptr2 = txpwr->ofdm_40_siso;
1957 rate_start_index =
1958 WL_TX_POWER_OFDM40_SISO_FIRST;
1959 break;
1960 case 3:
1961
1962 txpwr_ptr1 = txpwr->mcs_40_cdd;
1963 txpwr_ptr2 = txpwr->ofdm_40_cdd;
1964 rate_start_index = WL_TX_POWER_OFDM40_CDD_FIRST;
1965 break;
1966 }
1967
1968 for (rate2 = 0; rate2 < WLC_NUM_RATES_OFDM; rate2++) {
1969 tmp_txpwr_limit[rate2] = 0;
1970 tmp_txpwr_limit[WLC_NUM_RATES_OFDM + rate2] =
1971 txpwr_ptr1[rate2];
1972 }
1973 wlc_phy_mcs_to_ofdm_powers_nphy(tmp_txpwr_limit, 0,
1974 WLC_NUM_RATES_OFDM - 1,
1975 WLC_NUM_RATES_OFDM);
1976 for (rate1 = rate_start_index, rate2 = 0;
1977 rate2 < WLC_NUM_RATES_OFDM; rate1++, rate2++)
1978 pi->txpwr_limit[rate1] =
Greg Kroah-Hartman7068c2f2010-10-08 11:34:59 -07001979 min(txpwr_ptr2[rate2],
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001980 tmp_txpwr_limit[rate2]);
1981 }
1982
1983 for (k = 0; k < 4; k++) {
1984 switch (k) {
1985 case 0:
1986
1987 txpwr_ptr1 = txpwr->ofdm;
1988 txpwr_ptr2 = txpwr->mcs_20_siso;
1989 rate_start_index = WL_TX_POWER_MCS20_SISO_FIRST;
1990 break;
1991 case 1:
1992
1993 txpwr_ptr1 = txpwr->ofdm_cdd;
1994 txpwr_ptr2 = txpwr->mcs_20_cdd;
1995 rate_start_index = WL_TX_POWER_MCS20_CDD_FIRST;
1996 break;
1997 case 2:
1998
1999 txpwr_ptr1 = txpwr->ofdm_40_siso;
2000 txpwr_ptr2 = txpwr->mcs_40_siso;
2001 rate_start_index = WL_TX_POWER_MCS40_SISO_FIRST;
2002 break;
2003 case 3:
2004
2005 txpwr_ptr1 = txpwr->ofdm_40_cdd;
2006 txpwr_ptr2 = txpwr->mcs_40_cdd;
2007 rate_start_index = WL_TX_POWER_MCS40_CDD_FIRST;
2008 break;
2009 }
2010 for (rate2 = 0; rate2 < WLC_NUM_RATES_OFDM; rate2++) {
2011 tmp_txpwr_limit[rate2] = 0;
2012 tmp_txpwr_limit[WLC_NUM_RATES_OFDM + rate2] =
2013 txpwr_ptr1[rate2];
2014 }
2015 wlc_phy_ofdm_to_mcs_powers_nphy(tmp_txpwr_limit, 0,
2016 WLC_NUM_RATES_OFDM - 1,
2017 WLC_NUM_RATES_OFDM);
2018 for (rate1 = rate_start_index, rate2 = 0;
2019 rate2 < WLC_NUM_RATES_MCS_1_STREAM;
2020 rate1++, rate2++)
2021 pi->txpwr_limit[rate1] =
Greg Kroah-Hartman7068c2f2010-10-08 11:34:59 -07002022 min(txpwr_ptr2[rate2],
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002023 tmp_txpwr_limit[rate2]);
2024 }
2025
2026 for (k = 0; k < 2; k++) {
2027 switch (k) {
2028 case 0:
2029
2030 rate_start_index = WL_TX_POWER_MCS20_STBC_FIRST;
2031 txpwr_ptr1 = txpwr->mcs_20_stbc;
2032 break;
2033 case 1:
2034
2035 rate_start_index = WL_TX_POWER_MCS40_STBC_FIRST;
2036 txpwr_ptr1 = txpwr->mcs_40_stbc;
2037 break;
2038 }
2039 for (rate1 = rate_start_index, rate2 = 0;
2040 rate2 < WLC_NUM_RATES_MCS_1_STREAM;
2041 rate1++, rate2++)
2042 pi->txpwr_limit[rate1] = txpwr_ptr1[rate2];
2043 }
2044
2045 for (k = 0; k < 2; k++) {
2046 switch (k) {
2047 case 0:
2048
2049 rate_start_index = WL_TX_POWER_MCS20_SDM_FIRST;
2050 txpwr_ptr1 = txpwr->mcs_20_mimo;
2051 break;
2052 case 1:
2053
2054 rate_start_index = WL_TX_POWER_MCS40_SDM_FIRST;
2055 txpwr_ptr1 = txpwr->mcs_40_mimo;
2056 break;
2057 }
2058 for (rate1 = rate_start_index, rate2 = 0;
2059 rate2 < WLC_NUM_RATES_MCS_2_STREAM;
2060 rate1++, rate2++)
2061 pi->txpwr_limit[rate1] = txpwr_ptr1[rate2];
2062 }
2063
2064 pi->txpwr_limit[WL_TX_POWER_MCS_32] = txpwr->mcs32;
2065
2066 pi->txpwr_limit[WL_TX_POWER_MCS40_CDD_FIRST] =
Greg Kroah-Hartman7068c2f2010-10-08 11:34:59 -07002067 min(pi->txpwr_limit[WL_TX_POWER_MCS40_CDD_FIRST],
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002068 pi->txpwr_limit[WL_TX_POWER_MCS_32]);
2069 pi->txpwr_limit[WL_TX_POWER_MCS_32] =
2070 pi->txpwr_limit[WL_TX_POWER_MCS40_CDD_FIRST];
2071 }
2072}
2073
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07002074void wlc_phy_txpwr_percent_set(wlc_phy_t *ppi, u8 txpwr_percent)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002075{
2076 phy_info_t *pi = (phy_info_t *) ppi;
2077
2078 pi->txpwr_percent = txpwr_percent;
2079}
2080
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -07002081void wlc_phy_machwcap_set(wlc_phy_t *ppi, u32 machwcap)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002082{
2083 phy_info_t *pi = (phy_info_t *) ppi;
2084
2085 pi->sh->machwcap = machwcap;
2086}
2087
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04002088void wlc_phy_runbist_config(wlc_phy_t *ppi, bool start_end)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002089{
2090 phy_info_t *pi = (phy_info_t *) ppi;
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -07002091 u16 rxc;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002092 rxc = 0;
2093
2094 if (start_end == ON) {
2095 if (!ISNPHY(pi))
2096 return;
2097
2098 if (NREV_IS(pi->pubpi.phy_rev, 3)
2099 || NREV_IS(pi->pubpi.phy_rev, 4)) {
2100 W_REG(pi->sh->osh, &pi->regs->phyregaddr, 0xa0);
2101 (void)R_REG(pi->sh->osh, &pi->regs->phyregaddr);
2102 rxc = R_REG(pi->sh->osh, &pi->regs->phyregdata);
2103 W_REG(pi->sh->osh, &pi->regs->phyregdata,
2104 (0x1 << 15) | rxc);
2105 }
2106 } else {
2107 if (NREV_IS(pi->pubpi.phy_rev, 3)
2108 || NREV_IS(pi->pubpi.phy_rev, 4)) {
2109 W_REG(pi->sh->osh, &pi->regs->phyregaddr, 0xa0);
2110 (void)R_REG(pi->sh->osh, &pi->regs->phyregaddr);
2111 W_REG(pi->sh->osh, &pi->regs->phyregdata, rxc);
2112 }
2113
2114 wlc_phy_por_inform(ppi);
2115 }
2116}
2117
2118void
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04002119wlc_phy_txpower_limit_set(wlc_phy_t *ppi, struct txpwr_limits *txpwr,
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002120 chanspec_t chanspec)
2121{
2122 phy_info_t *pi = (phy_info_t *) ppi;
2123
2124 wlc_phy_txpower_reg_limit_calc(pi, txpwr, chanspec);
2125
2126 if (ISLCNPHY(pi)) {
2127 int i, j;
2128 for (i = TXP_FIRST_OFDM_20_CDD, j = 0;
2129 j < WLC_NUM_RATES_MCS_1_STREAM; i++, j++) {
2130 if (txpwr->mcs_20_siso[j])
2131 pi->txpwr_limit[i] = txpwr->mcs_20_siso[j];
2132 else
2133 pi->txpwr_limit[i] = txpwr->ofdm[j];
2134 }
2135 }
2136
2137 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2138
2139 wlc_phy_txpower_recalc_target(pi);
2140 wlc_phy_cal_txpower_recalc_sw(pi);
2141 wlapi_enable_mac(pi->sh->physhim);
2142}
2143
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04002144void wlc_phy_ofdm_rateset_war(wlc_phy_t *pih, bool war)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002145{
2146 phy_info_t *pi = (phy_info_t *) pih;
2147
2148 pi->ofdm_rateset_war = war;
2149}
2150
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04002151void wlc_phy_bf_preempt_enable(wlc_phy_t *pih, bool bf_preempt)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002152{
2153 phy_info_t *pi = (phy_info_t *) pih;
2154
2155 pi->bf_preempt_4306 = bf_preempt;
2156}
2157
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04002158void wlc_phy_txpower_update_shm(phy_info_t *pi)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002159{
2160 int j;
2161 if (ISNPHY(pi)) {
2162 ASSERT(0);
2163 return;
2164 }
2165
2166 if (!pi->sh->clk)
2167 return;
2168
2169 if (pi->hwpwrctrl) {
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -07002170 u16 offset;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002171
2172 wlapi_bmac_write_shm(pi->sh->physhim, M_TXPWR_MAX, 63);
2173 wlapi_bmac_write_shm(pi->sh->physhim, M_TXPWR_N,
2174 1 << NUM_TSSI_FRAMES);
2175
2176 wlapi_bmac_write_shm(pi->sh->physhim, M_TXPWR_TARGET,
2177 pi->tx_power_min << NUM_TSSI_FRAMES);
2178
2179 wlapi_bmac_write_shm(pi->sh->physhim, M_TXPWR_CUR,
2180 pi->hwpwr_txcur);
2181
2182 for (j = TXP_FIRST_OFDM; j <= TXP_LAST_OFDM; j++) {
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07002183 const u8 ucode_ofdm_rates[] = {
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002184 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c
2185 };
2186 offset = wlapi_bmac_rate_shm_offset(pi->sh->physhim,
2187 ucode_ofdm_rates[j -
2188 TXP_FIRST_OFDM]);
2189 wlapi_bmac_write_shm(pi->sh->physhim, offset + 6,
2190 pi->tx_power_offset[j]);
2191 wlapi_bmac_write_shm(pi->sh->physhim, offset + 14,
2192 -(pi->tx_power_offset[j] / 2));
2193 }
2194
2195 wlapi_bmac_mhf(pi->sh->physhim, MHF2, MHF2_HWPWRCTL,
2196 MHF2_HWPWRCTL, WLC_BAND_ALL);
2197 } else {
2198 int i;
2199
2200 for (i = TXP_FIRST_OFDM; i <= TXP_LAST_OFDM; i++)
2201 pi->tx_power_offset[i] =
Greg Kroah-Hartmane18d5312010-10-08 11:59:06 -07002202 (u8) roundup(pi->tx_power_offset[i], 8);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002203 wlapi_bmac_write_shm(pi->sh->physhim, M_OFDM_OFFSET,
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -07002204 (u16) ((pi->
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002205 tx_power_offset[TXP_FIRST_OFDM]
2206 + 7) >> 3));
2207 }
2208}
2209
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04002210bool wlc_phy_txpower_hw_ctrl_get(wlc_phy_t *ppi)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002211{
2212 phy_info_t *pi = (phy_info_t *) ppi;
2213
2214 if (ISNPHY(pi)) {
2215 return pi->nphy_txpwrctrl;
2216 } else {
2217 return pi->hwpwrctrl;
2218 }
2219}
2220
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04002221void wlc_phy_txpower_hw_ctrl_set(wlc_phy_t *ppi, bool hwpwrctrl)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002222{
2223 phy_info_t *pi = (phy_info_t *) ppi;
2224 bool cur_hwpwrctrl = pi->hwpwrctrl;
2225 bool suspend;
2226
2227 if (!pi->hwpwrctrl_capable) {
2228 return;
2229 }
2230
2231 pi->hwpwrctrl = hwpwrctrl;
2232 pi->nphy_txpwrctrl = hwpwrctrl;
2233 pi->txpwrctrl = hwpwrctrl;
2234
2235 if (ISNPHY(pi)) {
2236 suspend =
2237 (0 ==
2238 (R_REG(pi->sh->osh, &pi->regs->maccontrol) & MCTL_EN_MAC));
2239 if (!suspend)
2240 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2241
2242 wlc_phy_txpwrctrl_enable_nphy(pi, pi->nphy_txpwrctrl);
2243 if (pi->nphy_txpwrctrl == PHY_TPC_HW_OFF) {
2244 wlc_phy_txpwr_fixpower_nphy(pi);
2245 } else {
2246
2247 mod_phy_reg(pi, 0x1e7, (0x7f << 0),
2248 pi->saved_txpwr_idx);
2249 }
2250
2251 if (!suspend)
2252 wlapi_enable_mac(pi->sh->physhim);
2253 } else if (hwpwrctrl != cur_hwpwrctrl) {
2254
2255 return;
2256 }
2257}
2258
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04002259void wlc_phy_txpower_ipa_upd(phy_info_t *pi)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002260{
2261
2262 if (NREV_GE(pi->pubpi.phy_rev, 3)) {
2263 pi->ipa2g_on = (pi->srom_fem2g.extpagain == 2);
2264 pi->ipa5g_on = (pi->srom_fem5g.extpagain == 2);
2265 } else {
Greg Kroah-Hartman0965ae82010-10-12 12:50:15 -07002266 pi->ipa2g_on = false;
2267 pi->ipa5g_on = false;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002268 }
2269}
2270
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -07002271static u32 wlc_phy_txpower_est_power_nphy(phy_info_t *pi);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002272
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -07002273static u32 wlc_phy_txpower_est_power_nphy(phy_info_t *pi)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002274{
Greg Kroah-Hartmane59fe082010-10-07 17:08:21 -07002275 s16 tx0_status, tx1_status;
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -07002276 u16 estPower1, estPower2;
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07002277 u8 pwr0, pwr1, adj_pwr0, adj_pwr1;
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -07002278 u32 est_pwr;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002279
2280 estPower1 = read_phy_reg(pi, 0x118);
2281 estPower2 = read_phy_reg(pi, 0x119);
2282
2283 if ((estPower1 & (0x1 << 8))
2284 == (0x1 << 8)) {
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07002285 pwr0 = (u8) (estPower1 & (0xff << 0))
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002286 >> 0;
2287 } else {
2288 pwr0 = 0x80;
2289 }
2290
2291 if ((estPower2 & (0x1 << 8))
2292 == (0x1 << 8)) {
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07002293 pwr1 = (u8) (estPower2 & (0xff << 0))
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002294 >> 0;
2295 } else {
2296 pwr1 = 0x80;
2297 }
2298
2299 tx0_status = read_phy_reg(pi, 0x1ed);
2300 tx1_status = read_phy_reg(pi, 0x1ee);
2301
2302 if ((tx0_status & (0x1 << 15))
2303 == (0x1 << 15)) {
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07002304 adj_pwr0 = (u8) (tx0_status & (0xff << 0))
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002305 >> 0;
2306 } else {
2307 adj_pwr0 = 0x80;
2308 }
2309 if ((tx1_status & (0x1 << 15))
2310 == (0x1 << 15)) {
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07002311 adj_pwr1 = (u8) (tx1_status & (0xff << 0))
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002312 >> 0;
2313 } else {
2314 adj_pwr1 = 0x80;
2315 }
2316
2317 est_pwr =
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -07002318 (u32) ((pwr0 << 24) | (pwr1 << 16) | (adj_pwr0 << 8) | adj_pwr1);
Jason Cooper90ea2292010-09-14 09:45:32 -04002319 return est_pwr;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002320}
2321
2322void
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04002323wlc_phy_txpower_get_current(wlc_phy_t *ppi, tx_power_t *power, uint channel)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002324{
2325 phy_info_t *pi = (phy_info_t *) ppi;
2326 uint rate, num_rates;
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07002327 u8 min_pwr, max_pwr;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002328
2329#if WL_TX_POWER_RATES != TXP_NUM_RATES
2330#error "tx_power_t struct out of sync with this fn"
2331#endif
2332
2333 if (ISNPHY(pi)) {
2334 power->rf_cores = 2;
2335 power->flags |= (WL_TX_POWER_F_MIMO);
2336 if (pi->nphy_txpwrctrl == PHY_TPC_HW_ON)
2337 power->flags |=
2338 (WL_TX_POWER_F_ENABLED | WL_TX_POWER_F_HW);
2339 } else if (ISLCNPHY(pi)) {
2340 power->rf_cores = 1;
2341 power->flags |= (WL_TX_POWER_F_SISO);
2342 if (pi->radiopwr_override == RADIOPWR_OVERRIDE_DEF)
2343 power->flags |= WL_TX_POWER_F_ENABLED;
2344 if (pi->hwpwrctrl)
2345 power->flags |= WL_TX_POWER_F_HW;
2346 }
2347
2348 num_rates = ((ISNPHY(pi)) ? (TXP_NUM_RATES) :
2349 ((ISLCNPHY(pi)) ?
2350 (TXP_LAST_OFDM_20_CDD + 1) : (TXP_LAST_OFDM + 1)));
2351
2352 for (rate = 0; rate < num_rates; rate++) {
2353 power->user_limit[rate] = pi->tx_user_target[rate];
2354 wlc_phy_txpower_sromlimit(ppi, channel, &min_pwr, &max_pwr,
2355 rate);
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07002356 power->board_limit[rate] = (u8) max_pwr;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002357 power->target[rate] = pi->tx_power_target[rate];
2358 }
2359
2360 if (ISNPHY(pi)) {
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -07002361 u32 est_pout;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002362
2363 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2364 wlc_phyreg_enter((wlc_phy_t *) pi);
2365 est_pout = wlc_phy_txpower_est_power_nphy(pi);
2366 wlc_phyreg_exit((wlc_phy_t *) pi);
2367 wlapi_enable_mac(pi->sh->physhim);
2368
2369 power->est_Pout[0] = (est_pout >> 8) & 0xff;
2370 power->est_Pout[1] = est_pout & 0xff;
2371
2372 power->est_Pout_act[0] = est_pout >> 24;
2373 power->est_Pout_act[1] = (est_pout >> 16) & 0xff;
2374
2375 if (power->est_Pout[0] == 0x80)
2376 power->est_Pout[0] = 0;
2377 if (power->est_Pout[1] == 0x80)
2378 power->est_Pout[1] = 0;
2379
2380 if (power->est_Pout_act[0] == 0x80)
2381 power->est_Pout_act[0] = 0;
2382 if (power->est_Pout_act[1] == 0x80)
2383 power->est_Pout_act[1] = 0;
2384
2385 power->est_Pout_cck = 0;
2386
2387 power->tx_power_max[0] = pi->tx_power_max;
2388 power->tx_power_max[1] = pi->tx_power_max;
2389
2390 power->tx_power_max_rate_ind[0] = pi->tx_power_max_rate_ind;
2391 power->tx_power_max_rate_ind[1] = pi->tx_power_max_rate_ind;
2392 } else if (!pi->hwpwrctrl) {
2393 } else if (pi->sh->up) {
2394
2395 wlc_phyreg_enter(ppi);
2396 if (ISLCNPHY(pi)) {
2397
2398 power->tx_power_max[0] = pi->tx_power_max;
2399 power->tx_power_max[1] = pi->tx_power_max;
2400
2401 power->tx_power_max_rate_ind[0] =
2402 pi->tx_power_max_rate_ind;
2403 power->tx_power_max_rate_ind[1] =
2404 pi->tx_power_max_rate_ind;
2405
2406 if (wlc_phy_tpc_isenabled_lcnphy(pi))
2407 power->flags |=
2408 (WL_TX_POWER_F_HW | WL_TX_POWER_F_ENABLED);
2409 else
2410 power->flags &=
2411 ~(WL_TX_POWER_F_HW | WL_TX_POWER_F_ENABLED);
2412
Greg Kroah-Hartman562c8852010-10-05 11:04:17 -07002413 wlc_lcnphy_get_tssi(pi, (s8 *) &power->est_Pout[0],
2414 (s8 *) &power->est_Pout_cck);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002415 }
2416 wlc_phyreg_exit(ppi);
2417 }
2418}
2419
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07002420void wlc_phy_antsel_type_set(wlc_phy_t *ppi, u8 antsel_type)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002421{
2422 phy_info_t *pi = (phy_info_t *) ppi;
2423
2424 pi->antsel_type = antsel_type;
2425}
2426
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04002427bool wlc_phy_test_ison(wlc_phy_t *ppi)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002428{
2429 phy_info_t *pi = (phy_info_t *) ppi;
2430
Jason Cooper90ea2292010-09-14 09:45:32 -04002431 return pi->phytest_on;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002432}
2433
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07002434bool wlc_phy_ant_rxdiv_get(wlc_phy_t *ppi, u8 *pval)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002435{
2436 phy_info_t *pi = (phy_info_t *) ppi;
Greg Kroah-Hartman0f0881b2010-10-12 12:15:18 -07002437 bool ret = true;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002438
2439 wlc_phyreg_enter(ppi);
2440
2441 if (ISNPHY(pi)) {
2442
Greg Kroah-Hartman0965ae82010-10-12 12:50:15 -07002443 ret = false;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002444 } else if (ISLCNPHY(pi)) {
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -07002445 u16 crsctrl = read_phy_reg(pi, 0x410);
2446 u16 div = crsctrl & (0x1 << 1);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002447 *pval = (div | ((crsctrl & (0x1 << 0)) ^ (div >> 1)));
2448 }
2449
2450 wlc_phyreg_exit(ppi);
2451
2452 return ret;
2453}
2454
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07002455void wlc_phy_ant_rxdiv_set(wlc_phy_t *ppi, u8 val)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002456{
2457 phy_info_t *pi = (phy_info_t *) ppi;
2458 bool suspend;
2459
2460 pi->sh->rx_antdiv = val;
2461
2462 if (!(ISNPHY(pi) && D11REV_IS(pi->sh->corerev, 16))) {
2463 if (val > ANT_RX_DIV_FORCE_1)
2464 wlapi_bmac_mhf(pi->sh->physhim, MHF1, MHF1_ANTDIV,
2465 MHF1_ANTDIV, WLC_BAND_ALL);
2466 else
2467 wlapi_bmac_mhf(pi->sh->physhim, MHF1, MHF1_ANTDIV, 0,
2468 WLC_BAND_ALL);
2469 }
2470
2471 if (ISNPHY(pi)) {
2472
2473 return;
2474 }
2475
2476 if (!pi->sh->clk)
2477 return;
2478
2479 suspend =
2480 (0 == (R_REG(pi->sh->osh, &pi->regs->maccontrol) & MCTL_EN_MAC));
2481 if (!suspend)
2482 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2483
2484 if (ISLCNPHY(pi)) {
2485 if (val > ANT_RX_DIV_FORCE_1) {
2486 mod_phy_reg(pi, 0x410, (0x1 << 1), 0x01 << 1);
2487 mod_phy_reg(pi, 0x410,
2488 (0x1 << 0),
2489 ((ANT_RX_DIV_START_1 == val) ? 1 : 0) << 0);
2490 } else {
2491 mod_phy_reg(pi, 0x410, (0x1 << 1), 0x00 << 1);
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -07002492 mod_phy_reg(pi, 0x410, (0x1 << 0), (u16) val << 0);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002493 }
2494 } else {
2495 ASSERT(0);
2496 }
2497
2498 if (!suspend)
2499 wlapi_enable_mac(pi->sh->physhim);
2500
2501 return;
2502}
2503
2504static bool
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -07002505wlc_phy_noise_calc_phy(phy_info_t *pi, u32 *cmplx_pwr, s8 *pwr_ant)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002506{
Greg Kroah-Hartman562c8852010-10-05 11:04:17 -07002507 s8 cmplx_pwr_dbm[PHY_CORE_MAX];
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07002508 u8 i;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002509
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07002510 bzero((u8 *) cmplx_pwr_dbm, sizeof(cmplx_pwr_dbm));
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002511 ASSERT(pi->pubpi.phy_corenum <= PHY_CORE_MAX);
2512 wlc_phy_compute_dB(cmplx_pwr, cmplx_pwr_dbm, pi->pubpi.phy_corenum);
2513
2514 for (i = 0; i < pi->pubpi.phy_corenum; i++) {
2515 if (NREV_GE(pi->pubpi.phy_rev, 3))
Greg Kroah-Hartman562c8852010-10-05 11:04:17 -07002516 cmplx_pwr_dbm[i] += (s8) PHY_NOISE_OFFSETFACT_4322;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002517 else
2518
Greg Kroah-Hartman562c8852010-10-05 11:04:17 -07002519 cmplx_pwr_dbm[i] += (s8) (16 - (15) * 3 - 70);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002520 }
2521
2522 for (i = 0; i < pi->pubpi.phy_corenum; i++) {
2523 pi->nphy_noise_win[i][pi->nphy_noise_index] = cmplx_pwr_dbm[i];
2524 pwr_ant[i] = cmplx_pwr_dbm[i];
2525 }
2526 pi->nphy_noise_index =
2527 MODINC_POW2(pi->nphy_noise_index, PHY_NOISE_WINDOW_SZ);
Greg Kroah-Hartman0f0881b2010-10-12 12:15:18 -07002528 return true;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002529}
2530
2531static void
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07002532wlc_phy_noise_sample_request(wlc_phy_t *pih, u8 reason, u8 ch)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002533{
2534 phy_info_t *pi = (phy_info_t *) pih;
Greg Kroah-Hartman562c8852010-10-05 11:04:17 -07002535 s8 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002536 bool sampling_in_progress = (pi->phynoise_state != 0);
Greg Kroah-Hartman0f0881b2010-10-12 12:15:18 -07002537 bool wait_for_intr = true;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002538
2539 if (NORADIO_ENAB(pi->pubpi)) {
2540 return;
2541 }
2542
2543 switch (reason) {
2544 case PHY_NOISE_SAMPLE_MON:
2545
2546 pi->phynoise_chan_watchdog = ch;
2547 pi->phynoise_state |= PHY_NOISE_STATE_MON;
2548
2549 break;
2550
2551 case PHY_NOISE_SAMPLE_EXTERNAL:
2552
2553 pi->phynoise_state |= PHY_NOISE_STATE_EXTERNAL;
2554 break;
2555
2556 default:
2557 ASSERT(0);
2558 break;
2559 }
2560
2561 if (sampling_in_progress)
2562 return;
2563
2564 pi->phynoise_now = pi->sh->now;
2565
2566 if (pi->phy_fixed_noise) {
2567 if (ISNPHY(pi)) {
2568 pi->nphy_noise_win[WL_ANT_IDX_1][pi->nphy_noise_index] =
2569 PHY_NOISE_FIXED_VAL_NPHY;
2570 pi->nphy_noise_win[WL_ANT_IDX_2][pi->nphy_noise_index] =
2571 PHY_NOISE_FIXED_VAL_NPHY;
2572 pi->nphy_noise_index = MODINC_POW2(pi->nphy_noise_index,
2573 PHY_NOISE_WINDOW_SZ);
2574
2575 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;
2576 } else {
2577
2578 noise_dbm = PHY_NOISE_FIXED_VAL;
2579 }
2580
Greg Kroah-Hartman0965ae82010-10-12 12:50:15 -07002581 wait_for_intr = false;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002582 goto done;
2583 }
2584
2585 if (ISLCNPHY(pi)) {
2586 if (!pi->phynoise_polling
2587 || (reason == PHY_NOISE_SAMPLE_EXTERNAL)) {
2588 wlapi_bmac_write_shm(pi->sh->physhim, M_JSSI_0, 0);
2589 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP0, 0);
2590 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP1, 0);
2591 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP2, 0);
2592 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP3, 0);
2593
2594 OR_REG(pi->sh->osh, &pi->regs->maccommand,
2595 MCMD_BG_NOISE);
2596 } else {
2597 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2598 wlc_lcnphy_deaf_mode(pi, (bool) 0);
Greg Kroah-Hartman562c8852010-10-05 11:04:17 -07002599 noise_dbm = (s8) wlc_lcnphy_rx_signal_power(pi, 20);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002600 wlc_lcnphy_deaf_mode(pi, (bool) 1);
2601 wlapi_enable_mac(pi->sh->physhim);
Greg Kroah-Hartman0965ae82010-10-12 12:50:15 -07002602 wait_for_intr = false;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002603 }
2604 } else if (ISNPHY(pi)) {
2605 if (!pi->phynoise_polling
2606 || (reason == PHY_NOISE_SAMPLE_EXTERNAL)) {
2607
2608 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP0, 0);
2609 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP1, 0);
2610 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP2, 0);
2611 wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP3, 0);
2612
2613 OR_REG(pi->sh->osh, &pi->regs->maccommand,
2614 MCMD_BG_NOISE);
2615 } else {
2616 phy_iq_est_t est[PHY_CORE_MAX];
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -07002617 u32 cmplx_pwr[PHY_CORE_MAX];
Greg Kroah-Hartman562c8852010-10-05 11:04:17 -07002618 s8 noise_dbm_ant[PHY_CORE_MAX];
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -07002619 u16 log_num_samps, num_samps, classif_state = 0;
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07002620 u8 wait_time = 32;
2621 u8 wait_crs = 0;
2622 u8 i;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002623
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07002624 bzero((u8 *) est, sizeof(est));
2625 bzero((u8 *) cmplx_pwr, sizeof(cmplx_pwr));
2626 bzero((u8 *) noise_dbm_ant, sizeof(noise_dbm_ant));
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002627
2628 log_num_samps = PHY_NOISE_SAMPLE_LOG_NUM_NPHY;
2629 num_samps = 1 << log_num_samps;
2630
2631 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2632 classif_state = wlc_phy_classifier_nphy(pi, 0, 0);
2633 wlc_phy_classifier_nphy(pi, 3, 0);
2634 wlc_phy_rx_iq_est_nphy(pi, est, num_samps, wait_time,
2635 wait_crs);
2636 wlc_phy_classifier_nphy(pi, (0x7 << 0), classif_state);
2637 wlapi_enable_mac(pi->sh->physhim);
2638
2639 for (i = 0; i < pi->pubpi.phy_corenum; i++)
2640 cmplx_pwr[i] =
2641 (est[i].i_pwr +
2642 est[i].q_pwr) >> log_num_samps;
2643
2644 wlc_phy_noise_calc_phy(pi, cmplx_pwr, noise_dbm_ant);
2645
2646 for (i = 0; i < pi->pubpi.phy_corenum; i++) {
2647 pi->nphy_noise_win[i][pi->nphy_noise_index] =
2648 noise_dbm_ant[i];
2649
2650 if (noise_dbm_ant[i] > noise_dbm)
2651 noise_dbm = noise_dbm_ant[i];
2652 }
2653 pi->nphy_noise_index = MODINC_POW2(pi->nphy_noise_index,
2654 PHY_NOISE_WINDOW_SZ);
2655
Greg Kroah-Hartman0965ae82010-10-12 12:50:15 -07002656 wait_for_intr = false;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002657 }
2658 }
2659
2660 done:
2661
2662 if (!wait_for_intr)
2663 wlc_phy_noise_cb(pi, ch, noise_dbm);
2664
2665}
2666
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04002667void wlc_phy_noise_sample_request_external(wlc_phy_t *pih)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002668{
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07002669 u8 channel;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002670
2671 channel = CHSPEC_CHANNEL(wlc_phy_chanspec_get(pih));
2672
2673 wlc_phy_noise_sample_request(pih, PHY_NOISE_SAMPLE_EXTERNAL, channel);
2674}
2675
Greg Kroah-Hartman562c8852010-10-05 11:04:17 -07002676static void wlc_phy_noise_cb(phy_info_t *pi, u8 channel, s8 noise_dbm)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002677{
2678 if (!pi->phynoise_state)
2679 return;
2680
2681 if (pi->phynoise_state & PHY_NOISE_STATE_MON) {
2682 if (pi->phynoise_chan_watchdog == channel) {
2683 pi->sh->phy_noise_window[pi->sh->phy_noise_index] =
2684 noise_dbm;
2685 pi->sh->phy_noise_index =
2686 MODINC(pi->sh->phy_noise_index, MA_WINDOW_SZ);
2687 }
2688 pi->phynoise_state &= ~PHY_NOISE_STATE_MON;
2689 }
2690
2691 if (pi->phynoise_state & PHY_NOISE_STATE_EXTERNAL) {
2692 pi->phynoise_state &= ~PHY_NOISE_STATE_EXTERNAL;
2693 }
2694
2695}
2696
Greg Kroah-Hartman562c8852010-10-05 11:04:17 -07002697static s8 wlc_phy_noise_read_shmem(phy_info_t *pi)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002698{
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -07002699 u32 cmplx_pwr[PHY_CORE_MAX];
Greg Kroah-Hartman562c8852010-10-05 11:04:17 -07002700 s8 noise_dbm_ant[PHY_CORE_MAX];
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -07002701 u16 lo, hi;
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -07002702 u32 cmplx_pwr_tot = 0;
Greg Kroah-Hartman562c8852010-10-05 11:04:17 -07002703 s8 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07002704 u8 idx, core;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002705
2706 ASSERT(pi->pubpi.phy_corenum <= PHY_CORE_MAX);
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07002707 bzero((u8 *) cmplx_pwr, sizeof(cmplx_pwr));
2708 bzero((u8 *) noise_dbm_ant, sizeof(noise_dbm_ant));
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002709
2710 for (idx = 0, core = 0; core < pi->pubpi.phy_corenum; idx += 2, core++) {
2711 lo = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP(idx));
2712 hi = wlapi_bmac_read_shm(pi->sh->physhim,
2713 M_PWRIND_MAP(idx + 1));
2714 cmplx_pwr[core] = (hi << 16) + lo;
2715 cmplx_pwr_tot += cmplx_pwr[core];
2716 if (cmplx_pwr[core] == 0) {
2717 noise_dbm_ant[core] = PHY_NOISE_FIXED_VAL_NPHY;
2718 } else
2719 cmplx_pwr[core] >>= PHY_NOISE_SAMPLE_LOG_NUM_UCODE;
2720 }
2721
2722 if (cmplx_pwr_tot != 0)
2723 wlc_phy_noise_calc_phy(pi, cmplx_pwr, noise_dbm_ant);
2724
2725 for (core = 0; core < pi->pubpi.phy_corenum; core++) {
2726 pi->nphy_noise_win[core][pi->nphy_noise_index] =
2727 noise_dbm_ant[core];
2728
2729 if (noise_dbm_ant[core] > noise_dbm)
2730 noise_dbm = noise_dbm_ant[core];
2731 }
2732 pi->nphy_noise_index =
2733 MODINC_POW2(pi->nphy_noise_index, PHY_NOISE_WINDOW_SZ);
2734
2735 return noise_dbm;
2736
2737}
2738
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04002739void wlc_phy_noise_sample_intr(wlc_phy_t *pih)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002740{
2741 phy_info_t *pi = (phy_info_t *) pih;
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -07002742 u16 jssi_aux;
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07002743 u8 channel = 0;
Greg Kroah-Hartman562c8852010-10-05 11:04:17 -07002744 s8 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002745
2746 if (ISLCNPHY(pi)) {
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -07002747 u32 cmplx_pwr, cmplx_pwr0, cmplx_pwr1;
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -07002748 u16 lo, hi;
Greg Kroah-Hartman3e264162010-10-08 11:11:13 -07002749 s32 pwr_offset_dB, gain_dB;
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -07002750 u16 status_0, status_1;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002751
2752 jssi_aux = wlapi_bmac_read_shm(pi->sh->physhim, M_JSSI_AUX);
2753 channel = jssi_aux & D11_CURCHANNEL_MAX;
2754
2755 lo = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP0);
2756 hi = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP1);
2757 cmplx_pwr0 = (hi << 16) + lo;
2758
2759 lo = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP2);
2760 hi = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP3);
2761 cmplx_pwr1 = (hi << 16) + lo;
2762 cmplx_pwr = (cmplx_pwr0 + cmplx_pwr1) >> 6;
2763
2764 status_0 = 0x44;
2765 status_1 = wlapi_bmac_read_shm(pi->sh->physhim, M_JSSI_0);
2766 if ((cmplx_pwr > 0 && cmplx_pwr < 500)
2767 && ((status_1 & 0xc000) == 0x4000)) {
2768
2769 wlc_phy_compute_dB(&cmplx_pwr, &noise_dbm,
2770 pi->pubpi.phy_corenum);
2771 pwr_offset_dB = (read_phy_reg(pi, 0x434) & 0xFF);
2772 if (pwr_offset_dB > 127)
2773 pwr_offset_dB -= 256;
2774
Greg Kroah-Hartman562c8852010-10-05 11:04:17 -07002775 noise_dbm += (s8) (pwr_offset_dB - 30);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002776
2777 gain_dB = (status_0 & 0x1ff);
Greg Kroah-Hartman562c8852010-10-05 11:04:17 -07002778 noise_dbm -= (s8) (gain_dB);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002779 } else {
2780 noise_dbm = PHY_NOISE_FIXED_VAL_LCNPHY;
2781 }
2782 } else if (ISNPHY(pi)) {
2783
2784 jssi_aux = wlapi_bmac_read_shm(pi->sh->physhim, M_JSSI_AUX);
2785 channel = jssi_aux & D11_CURCHANNEL_MAX;
2786
2787 noise_dbm = wlc_phy_noise_read_shmem(pi);
2788 } else {
2789 ASSERT(0);
2790 }
2791
2792 wlc_phy_noise_cb(pi, channel, noise_dbm);
2793
2794}
2795
Greg Kroah-Hartman562c8852010-10-05 11:04:17 -07002796s8 lcnphy_gain_index_offset_for_pkt_rssi[] = {
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002797 8,
2798 8,
2799 8,
2800 8,
2801 8,
2802 8,
2803 8,
2804 9,
2805 10,
2806 8,
2807 8,
2808 7,
2809 7,
2810 1,
2811 2,
2812 2,
2813 2,
2814 2,
2815 2,
2816 2,
2817 2,
2818 2,
2819 2,
2820 2,
2821 2,
2822 2,
2823 2,
2824 2,
2825 2,
2826 2,
2827 2,
2828 2,
2829 1,
2830 1,
2831 0,
2832 0,
2833 0,
2834 0
2835};
2836
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -07002837void wlc_phy_compute_dB(u32 *cmplx_pwr, s8 *p_cmplx_pwr_dB, u8 core)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002838{
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07002839 u8 shift_ct, lsb, msb, secondmsb, i;
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -07002840 u32 tmp;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002841
2842 for (i = 0; i < core; i++) {
2843 tmp = cmplx_pwr[i];
2844 shift_ct = msb = secondmsb = 0;
2845 while (tmp != 0) {
2846 tmp = tmp >> 1;
2847 shift_ct++;
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07002848 lsb = (u8) (tmp & 1);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002849 if (lsb == 1)
2850 msb = shift_ct;
2851 }
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07002852 secondmsb = (u8) ((cmplx_pwr[i] >> (msb - 1)) & 1);
Greg Kroah-Hartman562c8852010-10-05 11:04:17 -07002853 p_cmplx_pwr_dB[i] = (s8) (3 * msb + 2 * secondmsb);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002854 }
2855}
2856
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04002857void BCMFASTPATH wlc_phy_rssi_compute(wlc_phy_t *pih, void *ctx)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002858{
2859 wlc_d11rxhdr_t *wlc_rxhdr = (wlc_d11rxhdr_t *) ctx;
2860 d11rxhdr_t *rxh = &wlc_rxhdr->rxhdr;
2861 int rssi = ltoh16(rxh->PhyRxStatus_1) & PRXS1_JSSI_MASK;
2862 uint radioid = pih->radioid;
2863 phy_info_t *pi = (phy_info_t *) pih;
2864
2865 if (NORADIO_ENAB(pi->pubpi)) {
2866 rssi = WLC_RSSI_INVALID;
2867 goto end;
2868 }
2869
2870 if ((pi->sh->corerev >= 11)
2871 && !(ltoh16(rxh->RxStatus2) & RXS_PHYRXST_VALID)) {
2872 rssi = WLC_RSSI_INVALID;
2873 goto end;
2874 }
2875
2876 if (ISLCNPHY(pi)) {
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07002877 u8 gidx = (ltoh16(rxh->PhyRxStatus_2) & 0xFC00) >> 10;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002878 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
2879
2880 if (rssi > 127)
2881 rssi -= 256;
2882
2883 rssi = rssi + lcnphy_gain_index_offset_for_pkt_rssi[gidx];
2884 if ((rssi > -46) && (gidx > 18))
2885 rssi = rssi + 7;
2886
2887 rssi = rssi + pi_lcn->lcnphy_pkteng_rssi_slope;
2888
2889 rssi = rssi + 2;
2890
2891 }
2892
2893 if (ISLCNPHY(pi)) {
2894
2895 if (rssi > 127)
2896 rssi -= 256;
2897 } else if (radioid == BCM2055_ID || radioid == BCM2056_ID
2898 || radioid == BCM2057_ID) {
2899 ASSERT(ISNPHY(pi));
2900 rssi = wlc_phy_rssi_compute_nphy(pi, wlc_rxhdr);
2901 } else {
2902 ASSERT((const char *)"Unknown radio" == NULL);
2903 }
2904
2905 end:
Greg Kroah-Hartman562c8852010-10-05 11:04:17 -07002906 wlc_rxhdr->rssi = (s8) rssi;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002907}
2908
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04002909void wlc_phy_freqtrack_start(wlc_phy_t *pih)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002910{
2911 return;
2912}
2913
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04002914void wlc_phy_freqtrack_end(wlc_phy_t *pih)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002915{
2916 return;
2917}
2918
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04002919void wlc_phy_set_deaf(wlc_phy_t *ppi, bool user_flag)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002920{
2921 phy_info_t *pi;
2922 pi = (phy_info_t *) ppi;
2923
2924 if (ISLCNPHY(pi))
Greg Kroah-Hartman0f0881b2010-10-12 12:15:18 -07002925 wlc_lcnphy_deaf_mode(pi, true);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002926 else if (ISNPHY(pi))
Greg Kroah-Hartman0f0881b2010-10-12 12:15:18 -07002927 wlc_nphy_deaf_mode(pi, true);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002928 else {
2929 ASSERT(0);
2930 }
2931}
2932
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04002933void wlc_phy_watchdog(wlc_phy_t *pih)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002934{
2935 phy_info_t *pi = (phy_info_t *) pih;
Greg Kroah-Hartman0965ae82010-10-12 12:50:15 -07002936 bool delay_phy_cal = false;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002937 pi->sh->now++;
2938
2939 if (!pi->watchdog_override)
2940 return;
2941
2942 if (!(SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi))) {
2943 wlc_phy_noise_sample_request((wlc_phy_t *) pi,
2944 PHY_NOISE_SAMPLE_MON,
2945 CHSPEC_CHANNEL(pi->
2946 radio_chanspec));
2947 }
2948
2949 if (pi->phynoise_state && (pi->sh->now - pi->phynoise_now) > 5) {
2950 pi->phynoise_state = 0;
2951 }
2952
2953 if ((!pi->phycal_txpower) ||
2954 ((pi->sh->now - pi->phycal_txpower) >= pi->sh->fast_timer)) {
2955
2956 if (!SCAN_INPROG_PHY(pi) && wlc_phy_cal_txpower_recalc_sw(pi)) {
2957 pi->phycal_txpower = pi->sh->now;
2958 }
2959 }
2960
2961 if (NORADIO_ENAB(pi->pubpi))
2962 return;
2963
2964 if ((SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi)
2965 || ASSOC_INPROG_PHY(pi)))
2966 return;
2967
2968 if (ISNPHY(pi) && !pi->disable_percal && !delay_phy_cal) {
2969
2970 if ((pi->nphy_perical != PHY_PERICAL_DISABLE) &&
2971 (pi->nphy_perical != PHY_PERICAL_MANUAL) &&
2972 ((pi->sh->now - pi->nphy_perical_last) >=
2973 pi->sh->glacial_timer))
2974 wlc_phy_cal_perical((wlc_phy_t *) pi,
2975 PHY_PERICAL_WATCHDOG);
2976
2977 wlc_phy_txpwr_papd_cal_nphy(pi);
2978 }
2979
2980 if (ISLCNPHY(pi)) {
2981 if (pi->phy_forcecal ||
2982 ((pi->sh->now - pi->phy_lastcal) >=
2983 pi->sh->glacial_timer)) {
2984 if (!(SCAN_RM_IN_PROGRESS(pi) || ASSOC_INPROG_PHY(pi)))
2985 wlc_lcnphy_calib_modes(pi,
2986 LCNPHY_PERICAL_TEMPBASED_TXPWRCTRL);
2987 if (!
2988 (SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi)
2989 || ASSOC_INPROG_PHY(pi)
2990 || pi->carrier_suppr_disable
Brett Rudleya9a60732010-10-08 17:35:02 -07002991 || pi->disable_percal))
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002992 wlc_lcnphy_calib_modes(pi,
2993 PHY_PERICAL_WATCHDOG);
2994 }
2995 }
2996}
2997
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04002998void wlc_phy_BSSinit(wlc_phy_t *pih, bool bonlyap, int rssi)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002999{
3000 phy_info_t *pi = (phy_info_t *) pih;
3001 uint i;
3002 uint k;
3003
3004 for (i = 0; i < MA_WINDOW_SZ; i++) {
Greg Kroah-Hartman562c8852010-10-05 11:04:17 -07003005 pi->sh->phy_noise_window[i] = (s8) (rssi & 0xff);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003006 }
3007 if (ISLCNPHY(pi)) {
3008 for (i = 0; i < MA_WINDOW_SZ; i++)
3009 pi->sh->phy_noise_window[i] =
3010 PHY_NOISE_FIXED_VAL_LCNPHY;
3011 }
3012 pi->sh->phy_noise_index = 0;
3013
3014 for (i = 0; i < PHY_NOISE_WINDOW_SZ; i++) {
3015 for (k = WL_ANT_IDX_1; k < WL_ANT_RX_MAX; k++)
3016 pi->nphy_noise_win[k][i] = PHY_NOISE_FIXED_VAL_NPHY;
3017 }
3018 pi->nphy_noise_index = 0;
3019}
3020
3021void
Greg Kroah-Hartman3e264162010-10-08 11:11:13 -07003022wlc_phy_papd_decode_epsilon(u32 epsilon, s32 *eps_real, s32 *eps_imag)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003023{
Jason Cooperca8c1e52010-09-14 09:45:33 -04003024 *eps_imag = (epsilon >> 13);
3025 if (*eps_imag > 0xfff)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003026 *eps_imag -= 0x2000;
Jason Cooperca8c1e52010-09-14 09:45:33 -04003027
3028 *eps_real = (epsilon & 0x1fff);
3029 if (*eps_real > 0xfff)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003030 *eps_real -= 0x2000;
3031}
3032
3033static const fixed AtanTbl[] = {
3034 2949120,
3035 1740967,
3036 919879,
3037 466945,
3038 234379,
3039 117304,
3040 58666,
3041 29335,
3042 14668,
3043 7334,
3044 3667,
3045 1833,
3046 917,
3047 458,
3048 229,
3049 115,
3050 57,
3051 29
3052};
3053
Greg Kroah-Hartman3e264162010-10-08 11:11:13 -07003054void wlc_phy_cordic(fixed theta, cs32 *val)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003055{
3056 fixed angle, valtmp;
3057 unsigned iter;
3058 int signx = 1;
3059 int signtheta;
3060
3061 val[0].i = CORDIC_AG;
3062 val[0].q = 0;
3063 angle = 0;
3064
3065 signtheta = (theta < 0) ? -1 : 1;
3066 theta =
3067 ((theta + FIXED(180) * signtheta) % FIXED(360)) -
3068 FIXED(180) * signtheta;
3069
3070 if (FLOAT(theta) > 90) {
3071 theta -= FIXED(180);
3072 signx = -1;
3073 } else if (FLOAT(theta) < -90) {
3074 theta += FIXED(180);
3075 signx = -1;
3076 }
3077
3078 for (iter = 0; iter < CORDIC_NI; iter++) {
3079 if (theta > angle) {
3080 valtmp = val[0].i - (val[0].q >> iter);
3081 val[0].q = (val[0].i >> iter) + val[0].q;
3082 val[0].i = valtmp;
3083 angle += AtanTbl[iter];
3084 } else {
3085 valtmp = val[0].i + (val[0].q >> iter);
3086 val[0].q = -(val[0].i >> iter) + val[0].q;
3087 val[0].i = valtmp;
3088 angle -= AtanTbl[iter];
3089 }
3090 }
3091
3092 val[0].i = val[0].i * signx;
3093 val[0].q = val[0].q * signx;
3094}
3095
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04003096void wlc_phy_cal_perical_mphase_reset(phy_info_t *pi)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003097{
3098 wlapi_del_timer(pi->sh->physhim, pi->phycal_timer);
3099
3100 pi->cal_type_override = PHY_PERICAL_AUTO;
3101 pi->mphase_cal_phase_id = MPHASE_CAL_STATE_IDLE;
3102 pi->mphase_txcal_cmdidx = 0;
3103}
3104
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04003105static void wlc_phy_cal_perical_mphase_schedule(phy_info_t *pi, uint delay)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003106{
3107
3108 if ((pi->nphy_perical != PHY_PERICAL_MPHASE) &&
3109 (pi->nphy_perical != PHY_PERICAL_MANUAL))
3110 return;
3111
3112 wlapi_del_timer(pi->sh->physhim, pi->phycal_timer);
3113
3114 pi->mphase_cal_phase_id = MPHASE_CAL_STATE_INIT;
3115 wlapi_add_timer(pi->sh->physhim, pi->phycal_timer, delay, 0);
3116}
3117
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07003118void wlc_phy_cal_perical(wlc_phy_t *pih, u8 reason)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003119{
Greg Kroah-Hartmane59fe082010-10-07 17:08:21 -07003120 s16 nphy_currtemp = 0;
3121 s16 delta_temp = 0;
Greg Kroah-Hartman0f0881b2010-10-12 12:15:18 -07003122 bool do_periodic_cal = true;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003123 phy_info_t *pi = (phy_info_t *) pih;
3124
3125 if (!ISNPHY(pi))
3126 return;
3127
3128 if ((pi->nphy_perical == PHY_PERICAL_DISABLE) ||
3129 (pi->nphy_perical == PHY_PERICAL_MANUAL))
3130 return;
3131
3132 switch (reason) {
3133 case PHY_PERICAL_DRIVERUP:
3134 break;
3135
3136 case PHY_PERICAL_PHYINIT:
3137 if (pi->nphy_perical == PHY_PERICAL_MPHASE) {
3138 if (PHY_PERICAL_MPHASE_PENDING(pi)) {
3139 wlc_phy_cal_perical_mphase_reset(pi);
3140 }
3141 wlc_phy_cal_perical_mphase_schedule(pi,
3142 PHY_PERICAL_INIT_DELAY);
3143 }
3144 break;
3145
3146 case PHY_PERICAL_JOIN_BSS:
3147 case PHY_PERICAL_START_IBSS:
3148 case PHY_PERICAL_UP_BSS:
3149 if ((pi->nphy_perical == PHY_PERICAL_MPHASE) &&
3150 PHY_PERICAL_MPHASE_PENDING(pi)) {
3151 wlc_phy_cal_perical_mphase_reset(pi);
3152 }
3153
Greg Kroah-Hartman0f0881b2010-10-12 12:15:18 -07003154 pi->first_cal_after_assoc = true;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003155
3156 pi->cal_type_override = PHY_PERICAL_FULL;
3157
3158 if (pi->phycal_tempdelta) {
3159 pi->nphy_lastcal_temp = wlc_phy_tempsense_nphy(pi);
3160 }
3161 wlc_phy_cal_perical_nphy_run(pi, PHY_PERICAL_FULL);
3162 break;
3163
3164 case PHY_PERICAL_WATCHDOG:
3165 if (pi->phycal_tempdelta) {
3166 nphy_currtemp = wlc_phy_tempsense_nphy(pi);
3167 delta_temp =
3168 (nphy_currtemp > pi->nphy_lastcal_temp) ?
3169 nphy_currtemp - pi->nphy_lastcal_temp :
3170 pi->nphy_lastcal_temp - nphy_currtemp;
3171
Greg Kroah-Hartmane59fe082010-10-07 17:08:21 -07003172 if ((delta_temp < (s16) pi->phycal_tempdelta) &&
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003173 (pi->nphy_txiqlocal_chanspec ==
3174 pi->radio_chanspec)) {
Greg Kroah-Hartman0965ae82010-10-12 12:50:15 -07003175 do_periodic_cal = false;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003176 } else {
3177 pi->nphy_lastcal_temp = nphy_currtemp;
3178 }
3179 }
3180
3181 if (do_periodic_cal) {
3182
3183 if (pi->nphy_perical == PHY_PERICAL_MPHASE) {
3184
3185 if (!PHY_PERICAL_MPHASE_PENDING(pi))
3186 wlc_phy_cal_perical_mphase_schedule(pi,
3187 PHY_PERICAL_WDOG_DELAY);
3188 } else if (pi->nphy_perical == PHY_PERICAL_SPHASE)
3189 wlc_phy_cal_perical_nphy_run(pi,
3190 PHY_PERICAL_AUTO);
3191 else {
3192 ASSERT(0);
3193 }
3194 }
3195 break;
3196 default:
3197 ASSERT(0);
3198 break;
3199 }
3200}
3201
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04003202void wlc_phy_cal_perical_mphase_restart(phy_info_t *pi)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003203{
3204 pi->mphase_cal_phase_id = MPHASE_CAL_STATE_INIT;
3205 pi->mphase_txcal_cmdidx = 0;
3206}
3207
Greg Kroah-Hartman3e264162010-10-08 11:11:13 -07003208u8 wlc_phy_nbits(s32 value)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003209{
Greg Kroah-Hartman3e264162010-10-08 11:11:13 -07003210 s32 abs_val;
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07003211 u8 nbits = 0;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003212
3213 abs_val = ABS(value);
3214 while ((abs_val >> nbits) > 0)
3215 nbits++;
3216
3217 return nbits;
3218}
3219
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -07003220u32 wlc_phy_sqrt_int(u32 value)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003221{
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -07003222 u32 root = 0, shift = 0;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003223
3224 for (shift = 0; shift < 32; shift += 2) {
3225 if (((0x40000000 >> shift) + root) <= value) {
3226 value -= ((0x40000000 >> shift) + root);
3227 root = (root >> 1) | (0x40000000 >> shift);
3228 } else {
3229 root = root >> 1;
3230 }
3231 }
3232
3233 if (root < value)
3234 ++root;
3235
3236 return root;
3237}
3238
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07003239void wlc_phy_stf_chain_init(wlc_phy_t *pih, u8 txchain, u8 rxchain)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003240{
3241 phy_info_t *pi = (phy_info_t *) pih;
3242
3243 pi->sh->hw_phytxchain = txchain;
3244 pi->sh->hw_phyrxchain = rxchain;
3245 pi->sh->phytxchain = txchain;
3246 pi->sh->phyrxchain = rxchain;
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07003247 pi->pubpi.phy_corenum = (u8) PHY_BITSCNT(pi->sh->phyrxchain);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003248}
3249
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07003250void wlc_phy_stf_chain_set(wlc_phy_t *pih, u8 txchain, u8 rxchain)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003251{
3252 phy_info_t *pi = (phy_info_t *) pih;
3253
3254 pi->sh->phytxchain = txchain;
3255
3256 if (ISNPHY(pi)) {
3257 wlc_phy_rxcore_setstate_nphy(pih, rxchain);
3258 }
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07003259 pi->pubpi.phy_corenum = (u8) PHY_BITSCNT(pi->sh->phyrxchain);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003260}
3261
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07003262void wlc_phy_stf_chain_get(wlc_phy_t *pih, u8 *txchain, u8 *rxchain)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003263{
3264 phy_info_t *pi = (phy_info_t *) pih;
3265
3266 *txchain = pi->sh->phytxchain;
3267 *rxchain = pi->sh->phyrxchain;
3268}
3269
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07003270u8 wlc_phy_stf_chain_active_get(wlc_phy_t *pih)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003271{
Greg Kroah-Hartmane59fe082010-10-07 17:08:21 -07003272 s16 nphy_currtemp;
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07003273 u8 active_bitmap;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003274 phy_info_t *pi = (phy_info_t *) pih;
3275
3276 active_bitmap = (pi->phy_txcore_heatedup) ? 0x31 : 0x33;
3277
3278 if (!pi->watchdog_override)
3279 return active_bitmap;
3280
3281 if (NREV_GE(pi->pubpi.phy_rev, 6)) {
3282 wlapi_suspend_mac_and_wait(pi->sh->physhim);
3283 nphy_currtemp = wlc_phy_tempsense_nphy(pi);
3284 wlapi_enable_mac(pi->sh->physhim);
3285
3286 if (!pi->phy_txcore_heatedup) {
3287 if (nphy_currtemp >= pi->phy_txcore_disable_temp) {
3288 active_bitmap &= 0xFD;
Greg Kroah-Hartman0f0881b2010-10-12 12:15:18 -07003289 pi->phy_txcore_heatedup = true;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003290 }
3291 } else {
3292 if (nphy_currtemp <= pi->phy_txcore_enable_temp) {
3293 active_bitmap |= 0x2;
Greg Kroah-Hartman0965ae82010-10-12 12:50:15 -07003294 pi->phy_txcore_heatedup = false;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003295 }
3296 }
3297 }
3298
3299 return active_bitmap;
3300}
3301
Greg Kroah-Hartman562c8852010-10-05 11:04:17 -07003302s8 wlc_phy_stf_ssmode_get(wlc_phy_t *pih, chanspec_t chanspec)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003303{
3304 phy_info_t *pi = (phy_info_t *) pih;
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07003305 u8 siso_mcs_id, cdd_mcs_id;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003306
3307 siso_mcs_id =
3308 (CHSPEC_IS40(chanspec)) ? TXP_FIRST_MCS_40_SISO :
3309 TXP_FIRST_MCS_20_SISO;
3310 cdd_mcs_id =
3311 (CHSPEC_IS40(chanspec)) ? TXP_FIRST_MCS_40_CDD :
3312 TXP_FIRST_MCS_20_CDD;
3313
3314 if (pi->tx_power_target[siso_mcs_id] >
3315 (pi->tx_power_target[cdd_mcs_id] + 12))
3316 return PHY_TXC1_MODE_SISO;
3317 else
3318 return PHY_TXC1_MODE_CDD;
3319}
3320
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07003321const u8 *wlc_phy_get_ofdm_rate_lookup(void)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003322{
3323 return ofdm_rate_lookup;
3324}
3325
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04003326void wlc_lcnphy_epa_switch(phy_info_t *pi, bool mode)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003327{
3328 if ((CHIPID(pi->sh->chip) == BCM4313_CHIP_ID) &&
3329 (pi->sh->boardflags & BFL_FEM)) {
3330 if (mode) {
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -07003331 u16 txant = 0;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003332 txant = wlapi_bmac_get_txant(pi->sh->physhim);
3333 if (txant == 1) {
3334 mod_phy_reg(pi, 0x44d, (0x1 << 2), (1) << 2);
3335
3336 mod_phy_reg(pi, 0x44c, (0x1 << 2), (1) << 2);
3337
3338 }
3339 si_corereg(pi->sh->sih, SI_CC_IDX,
Greg Kroah-Hartmance0f1b82010-10-08 11:44:45 -07003340 offsetof(chipcregs_t, gpiocontrol), ~0x0,
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003341 0x0);
3342 si_corereg(pi->sh->sih, SI_CC_IDX,
Greg Kroah-Hartmance0f1b82010-10-08 11:44:45 -07003343 offsetof(chipcregs_t, gpioout), 0x40, 0x40);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003344 si_corereg(pi->sh->sih, SI_CC_IDX,
Greg Kroah-Hartmance0f1b82010-10-08 11:44:45 -07003345 offsetof(chipcregs_t, gpioouten), 0x40,
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003346 0x40);
3347 } else {
3348 mod_phy_reg(pi, 0x44c, (0x1 << 2), (0) << 2);
3349
3350 mod_phy_reg(pi, 0x44d, (0x1 << 2), (0) << 2);
3351
3352 si_corereg(pi->sh->sih, SI_CC_IDX,
Greg Kroah-Hartmance0f1b82010-10-08 11:44:45 -07003353 offsetof(chipcregs_t, gpioout), 0x40, 0x00);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003354 si_corereg(pi->sh->sih, SI_CC_IDX,
Greg Kroah-Hartmance0f1b82010-10-08 11:44:45 -07003355 offsetof(chipcregs_t, gpioouten), 0x40, 0x0);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003356 si_corereg(pi->sh->sih, SI_CC_IDX,
Greg Kroah-Hartmance0f1b82010-10-08 11:44:45 -07003357 offsetof(chipcregs_t, gpiocontrol), ~0x0,
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003358 0x40);
3359 }
3360 }
3361}
3362
Greg Kroah-Hartman562c8852010-10-05 11:04:17 -07003363static s8
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -07003364wlc_user_txpwr_antport_to_rfport(phy_info_t *pi, uint chan, u32 band,
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07003365 u8 rate)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003366{
Greg Kroah-Hartman562c8852010-10-05 11:04:17 -07003367 s8 offset = 0;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003368
3369 if (!pi->user_txpwr_at_rfport)
3370 return offset;
3371 return offset;
3372}
3373
Greg Kroah-Hartman562c8852010-10-05 11:04:17 -07003374static s8 wlc_phy_env_measure_vbat(phy_info_t *pi)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003375{
3376 if (ISLCNPHY(pi))
3377 return wlc_lcnphy_vbatsense(pi, 0);
3378 else
3379 return 0;
3380}
3381
Greg Kroah-Hartman562c8852010-10-05 11:04:17 -07003382static s8 wlc_phy_env_measure_temperature(phy_info_t *pi)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003383{
3384 if (ISLCNPHY(pi))
3385 return wlc_lcnphy_tempsense_degree(pi, 0);
3386 else
3387 return 0;
3388}
3389
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -07003390static void wlc_phy_upd_env_txpwr_rate_limits(phy_info_t *pi, u32 band)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003391{
Greg Kroah-Hartmane868ab02010-10-05 10:14:26 -07003392 u8 i;
Greg Kroah-Hartman562c8852010-10-05 11:04:17 -07003393 s8 temp, vbat;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003394
3395 for (i = 0; i < TXP_NUM_RATES; i++)
3396 pi->txpwr_env_limit[i] = WLC_TXPWR_MAX;
3397
3398 vbat = wlc_phy_env_measure_vbat(pi);
3399 temp = wlc_phy_env_measure_temperature(pi);
3400
3401}
3402
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04003403void wlc_phy_ldpc_override_set(wlc_phy_t *ppi, bool ldpc)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003404{
3405 return;
3406}
3407
3408void
Greg Kroah-Hartman562c8852010-10-05 11:04:17 -07003409wlc_phy_get_pwrdet_offsets(phy_info_t *pi, s8 *cckoffset, s8 *ofdmoffset)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003410{
3411 *cckoffset = 0;
3412 *ofdmoffset = 0;
3413}
3414
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -07003415u32 wlc_phy_qdiv_roundup(u32 dividend, u32 divisor, u8 precision)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003416{
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -07003417 u32 quotient, remainder, roundup, rbit;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003418
3419 ASSERT(divisor);
3420
3421 quotient = dividend / divisor;
3422 remainder = dividend % divisor;
3423 rbit = divisor & 1;
3424 roundup = (divisor >> 1) + rbit;
3425
3426 while (precision--) {
3427 quotient <<= 1;
3428 if (remainder >= roundup) {
3429 quotient++;
3430 remainder = ((remainder - roundup) << 1) + rbit;
3431 } else {
3432 remainder <<= 1;
3433 }
3434 }
3435
3436 if (remainder >= roundup)
3437 quotient++;
3438
3439 return quotient;
3440}
3441
Greg Kroah-Hartman562c8852010-10-05 11:04:17 -07003442s8 wlc_phy_upd_rssi_offset(phy_info_t *pi, s8 rssi, chanspec_t chanspec)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003443{
3444
3445 return rssi;
3446}
3447
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04003448bool wlc_phy_txpower_ipa_ison(wlc_phy_t *ppi)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003449{
3450 phy_info_t *pi = (phy_info_t *) ppi;
3451
3452 if (ISNPHY(pi))
Jason Cooper90ea2292010-09-14 09:45:32 -04003453 return wlc_phy_n_txpower_ipa_ison(pi);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07003454 else
3455 return 0;
3456}