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