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