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