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