xref: /OK3568_Linux_fs/kernel/drivers/net/wireless/ath/ath9k/ar9003_rtt.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * Copyright (c) 2010-2011 Atheros Communications Inc.
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * Permission to use, copy, modify, and/or distribute this software for any
5*4882a593Smuzhiyun  * purpose with or without fee is hereby granted, provided that the above
6*4882a593Smuzhiyun  * copyright notice and this permission notice appear in all copies.
7*4882a593Smuzhiyun  *
8*4882a593Smuzhiyun  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9*4882a593Smuzhiyun  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10*4882a593Smuzhiyun  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11*4882a593Smuzhiyun  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12*4882a593Smuzhiyun  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13*4882a593Smuzhiyun  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14*4882a593Smuzhiyun  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15*4882a593Smuzhiyun  */
16*4882a593Smuzhiyun 
17*4882a593Smuzhiyun #include "hw.h"
18*4882a593Smuzhiyun #include "hw-ops.h"
19*4882a593Smuzhiyun #include "ar9003_phy.h"
20*4882a593Smuzhiyun #include "ar9003_rtt.h"
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun #define RTT_RESTORE_TIMEOUT          1000
23*4882a593Smuzhiyun #define RTT_ACCESS_TIMEOUT           100
24*4882a593Smuzhiyun #define RTT_BAD_VALUE                0x0bad0bad
25*4882a593Smuzhiyun 
26*4882a593Smuzhiyun /*
27*4882a593Smuzhiyun  * RTT (Radio Retention Table) hardware implementation information
28*4882a593Smuzhiyun  *
29*4882a593Smuzhiyun  * There is an internal table (i.e. the rtt) for each chain (or bank).
30*4882a593Smuzhiyun  * Each table contains 6 entries and each entry is corresponding to
31*4882a593Smuzhiyun  * a specific calibration parameter as depicted below.
32*4882a593Smuzhiyun  *  0~2 - DC offset DAC calibration: loop, low, high (offsetI/Q_...)
33*4882a593Smuzhiyun  *  3   - Filter cal (filterfc)
34*4882a593Smuzhiyun  *  4   - RX gain settings
35*4882a593Smuzhiyun  *  5   - Peak detector offset calibration (agc_caldac)
36*4882a593Smuzhiyun  */
37*4882a593Smuzhiyun 
ar9003_hw_rtt_enable(struct ath_hw * ah)38*4882a593Smuzhiyun void ar9003_hw_rtt_enable(struct ath_hw *ah)
39*4882a593Smuzhiyun {
40*4882a593Smuzhiyun 	REG_WRITE(ah, AR_PHY_RTT_CTRL, 1);
41*4882a593Smuzhiyun }
42*4882a593Smuzhiyun 
ar9003_hw_rtt_disable(struct ath_hw * ah)43*4882a593Smuzhiyun void ar9003_hw_rtt_disable(struct ath_hw *ah)
44*4882a593Smuzhiyun {
45*4882a593Smuzhiyun 	REG_WRITE(ah, AR_PHY_RTT_CTRL, 0);
46*4882a593Smuzhiyun }
47*4882a593Smuzhiyun 
ar9003_hw_rtt_set_mask(struct ath_hw * ah,u32 rtt_mask)48*4882a593Smuzhiyun void ar9003_hw_rtt_set_mask(struct ath_hw *ah, u32 rtt_mask)
49*4882a593Smuzhiyun {
50*4882a593Smuzhiyun 	REG_RMW_FIELD(ah, AR_PHY_RTT_CTRL,
51*4882a593Smuzhiyun 		      AR_PHY_RTT_CTRL_RESTORE_MASK, rtt_mask);
52*4882a593Smuzhiyun }
53*4882a593Smuzhiyun 
ar9003_hw_rtt_force_restore(struct ath_hw * ah)54*4882a593Smuzhiyun bool ar9003_hw_rtt_force_restore(struct ath_hw *ah)
55*4882a593Smuzhiyun {
56*4882a593Smuzhiyun 	if (!ath9k_hw_wait(ah, AR_PHY_RTT_CTRL,
57*4882a593Smuzhiyun 			   AR_PHY_RTT_CTRL_FORCE_RADIO_RESTORE,
58*4882a593Smuzhiyun 			   0, RTT_RESTORE_TIMEOUT))
59*4882a593Smuzhiyun 		return false;
60*4882a593Smuzhiyun 
61*4882a593Smuzhiyun 	REG_RMW_FIELD(ah, AR_PHY_RTT_CTRL,
62*4882a593Smuzhiyun 		      AR_PHY_RTT_CTRL_FORCE_RADIO_RESTORE, 1);
63*4882a593Smuzhiyun 
64*4882a593Smuzhiyun 	if (!ath9k_hw_wait(ah, AR_PHY_RTT_CTRL,
65*4882a593Smuzhiyun 			   AR_PHY_RTT_CTRL_FORCE_RADIO_RESTORE,
66*4882a593Smuzhiyun 			   0, RTT_RESTORE_TIMEOUT))
67*4882a593Smuzhiyun 		return false;
68*4882a593Smuzhiyun 
69*4882a593Smuzhiyun 	return true;
70*4882a593Smuzhiyun }
71*4882a593Smuzhiyun 
ar9003_hw_rtt_load_hist_entry(struct ath_hw * ah,u8 chain,u32 index,u32 data28)72*4882a593Smuzhiyun static void ar9003_hw_rtt_load_hist_entry(struct ath_hw *ah, u8 chain,
73*4882a593Smuzhiyun 					  u32 index, u32 data28)
74*4882a593Smuzhiyun {
75*4882a593Smuzhiyun 	u32 val;
76*4882a593Smuzhiyun 
77*4882a593Smuzhiyun 	val = SM(data28, AR_PHY_RTT_SW_RTT_TABLE_DATA);
78*4882a593Smuzhiyun 	REG_WRITE(ah, AR_PHY_RTT_TABLE_SW_INTF_1_B(chain), val);
79*4882a593Smuzhiyun 
80*4882a593Smuzhiyun 	val = SM(0, AR_PHY_RTT_SW_RTT_TABLE_ACCESS) |
81*4882a593Smuzhiyun 	      SM(1, AR_PHY_RTT_SW_RTT_TABLE_WRITE) |
82*4882a593Smuzhiyun 	      SM(index, AR_PHY_RTT_SW_RTT_TABLE_ADDR);
83*4882a593Smuzhiyun 	REG_WRITE(ah, AR_PHY_RTT_TABLE_SW_INTF_B(chain), val);
84*4882a593Smuzhiyun 	udelay(1);
85*4882a593Smuzhiyun 
86*4882a593Smuzhiyun 	val |= SM(1, AR_PHY_RTT_SW_RTT_TABLE_ACCESS);
87*4882a593Smuzhiyun 	REG_WRITE(ah, AR_PHY_RTT_TABLE_SW_INTF_B(chain), val);
88*4882a593Smuzhiyun 	udelay(1);
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun 	if (!ath9k_hw_wait(ah, AR_PHY_RTT_TABLE_SW_INTF_B(chain),
91*4882a593Smuzhiyun 			   AR_PHY_RTT_SW_RTT_TABLE_ACCESS, 0,
92*4882a593Smuzhiyun 			   RTT_ACCESS_TIMEOUT))
93*4882a593Smuzhiyun 		return;
94*4882a593Smuzhiyun 
95*4882a593Smuzhiyun 	val &= ~SM(1, AR_PHY_RTT_SW_RTT_TABLE_WRITE);
96*4882a593Smuzhiyun 	REG_WRITE(ah, AR_PHY_RTT_TABLE_SW_INTF_B(chain), val);
97*4882a593Smuzhiyun 	udelay(1);
98*4882a593Smuzhiyun 
99*4882a593Smuzhiyun 	ath9k_hw_wait(ah, AR_PHY_RTT_TABLE_SW_INTF_B(chain),
100*4882a593Smuzhiyun 		      AR_PHY_RTT_SW_RTT_TABLE_ACCESS, 0,
101*4882a593Smuzhiyun 		      RTT_ACCESS_TIMEOUT);
102*4882a593Smuzhiyun }
103*4882a593Smuzhiyun 
ar9003_hw_rtt_load_hist(struct ath_hw * ah)104*4882a593Smuzhiyun void ar9003_hw_rtt_load_hist(struct ath_hw *ah)
105*4882a593Smuzhiyun {
106*4882a593Smuzhiyun 	int chain, i;
107*4882a593Smuzhiyun 
108*4882a593Smuzhiyun 	for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) {
109*4882a593Smuzhiyun 		if (!(ah->caps.rx_chainmask & (1 << chain)))
110*4882a593Smuzhiyun 			continue;
111*4882a593Smuzhiyun 		for (i = 0; i < MAX_RTT_TABLE_ENTRY; i++) {
112*4882a593Smuzhiyun 			ar9003_hw_rtt_load_hist_entry(ah, chain, i,
113*4882a593Smuzhiyun 					      ah->caldata->rtt_table[chain][i]);
114*4882a593Smuzhiyun 			ath_dbg(ath9k_hw_common(ah), CALIBRATE,
115*4882a593Smuzhiyun 				"Load RTT value at idx %d, chain %d: 0x%x\n",
116*4882a593Smuzhiyun 				i, chain, ah->caldata->rtt_table[chain][i]);
117*4882a593Smuzhiyun 		}
118*4882a593Smuzhiyun 	}
119*4882a593Smuzhiyun }
120*4882a593Smuzhiyun 
ar9003_hw_patch_rtt(struct ath_hw * ah,int index,int chain)121*4882a593Smuzhiyun static void ar9003_hw_patch_rtt(struct ath_hw *ah, int index, int chain)
122*4882a593Smuzhiyun {
123*4882a593Smuzhiyun 	int agc, caldac;
124*4882a593Smuzhiyun 
125*4882a593Smuzhiyun 	if (!test_bit(SW_PKDET_DONE, &ah->caldata->cal_flags))
126*4882a593Smuzhiyun 		return;
127*4882a593Smuzhiyun 
128*4882a593Smuzhiyun 	if ((index != 5) || (chain >= 2))
129*4882a593Smuzhiyun 		return;
130*4882a593Smuzhiyun 
131*4882a593Smuzhiyun 	agc = REG_READ_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),
132*4882a593Smuzhiyun 			     AR_PHY_65NM_RXRF_AGC_AGC_OVERRIDE);
133*4882a593Smuzhiyun 	if (!agc)
134*4882a593Smuzhiyun 		return;
135*4882a593Smuzhiyun 
136*4882a593Smuzhiyun 	caldac = ah->caldata->caldac[chain];
137*4882a593Smuzhiyun 	ah->caldata->rtt_table[chain][index] &= 0xFFFF05FF;
138*4882a593Smuzhiyun 	caldac = (caldac & 0x20) | ((caldac & 0x1F) << 7);
139*4882a593Smuzhiyun 	ah->caldata->rtt_table[chain][index] |= (caldac << 4);
140*4882a593Smuzhiyun }
141*4882a593Smuzhiyun 
ar9003_hw_rtt_fill_hist_entry(struct ath_hw * ah,u8 chain,u32 index)142*4882a593Smuzhiyun static int ar9003_hw_rtt_fill_hist_entry(struct ath_hw *ah, u8 chain, u32 index)
143*4882a593Smuzhiyun {
144*4882a593Smuzhiyun 	u32 val;
145*4882a593Smuzhiyun 
146*4882a593Smuzhiyun 	val = SM(0, AR_PHY_RTT_SW_RTT_TABLE_ACCESS) |
147*4882a593Smuzhiyun 	      SM(0, AR_PHY_RTT_SW_RTT_TABLE_WRITE) |
148*4882a593Smuzhiyun 	      SM(index, AR_PHY_RTT_SW_RTT_TABLE_ADDR);
149*4882a593Smuzhiyun 
150*4882a593Smuzhiyun 	REG_WRITE(ah, AR_PHY_RTT_TABLE_SW_INTF_B(chain), val);
151*4882a593Smuzhiyun 	udelay(1);
152*4882a593Smuzhiyun 
153*4882a593Smuzhiyun 	val |= SM(1, AR_PHY_RTT_SW_RTT_TABLE_ACCESS);
154*4882a593Smuzhiyun 	REG_WRITE(ah, AR_PHY_RTT_TABLE_SW_INTF_B(chain), val);
155*4882a593Smuzhiyun 	udelay(1);
156*4882a593Smuzhiyun 
157*4882a593Smuzhiyun 	if (!ath9k_hw_wait(ah, AR_PHY_RTT_TABLE_SW_INTF_B(chain),
158*4882a593Smuzhiyun 			   AR_PHY_RTT_SW_RTT_TABLE_ACCESS, 0,
159*4882a593Smuzhiyun 			   RTT_ACCESS_TIMEOUT))
160*4882a593Smuzhiyun 		return RTT_BAD_VALUE;
161*4882a593Smuzhiyun 
162*4882a593Smuzhiyun 	val = MS(REG_READ(ah, AR_PHY_RTT_TABLE_SW_INTF_1_B(chain)),
163*4882a593Smuzhiyun 		 AR_PHY_RTT_SW_RTT_TABLE_DATA);
164*4882a593Smuzhiyun 
165*4882a593Smuzhiyun 
166*4882a593Smuzhiyun 	return val;
167*4882a593Smuzhiyun }
168*4882a593Smuzhiyun 
ar9003_hw_rtt_fill_hist(struct ath_hw * ah)169*4882a593Smuzhiyun void ar9003_hw_rtt_fill_hist(struct ath_hw *ah)
170*4882a593Smuzhiyun {
171*4882a593Smuzhiyun 	int chain, i;
172*4882a593Smuzhiyun 
173*4882a593Smuzhiyun 	for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) {
174*4882a593Smuzhiyun 		if (!(ah->caps.rx_chainmask & (1 << chain)))
175*4882a593Smuzhiyun 			continue;
176*4882a593Smuzhiyun 		for (i = 0; i < MAX_RTT_TABLE_ENTRY; i++) {
177*4882a593Smuzhiyun 			ah->caldata->rtt_table[chain][i] =
178*4882a593Smuzhiyun 				ar9003_hw_rtt_fill_hist_entry(ah, chain, i);
179*4882a593Smuzhiyun 
180*4882a593Smuzhiyun 			ar9003_hw_patch_rtt(ah, i, chain);
181*4882a593Smuzhiyun 
182*4882a593Smuzhiyun 			ath_dbg(ath9k_hw_common(ah), CALIBRATE,
183*4882a593Smuzhiyun 				"RTT value at idx %d, chain %d is: 0x%x\n",
184*4882a593Smuzhiyun 				i, chain, ah->caldata->rtt_table[chain][i]);
185*4882a593Smuzhiyun 		}
186*4882a593Smuzhiyun 	}
187*4882a593Smuzhiyun 
188*4882a593Smuzhiyun 	set_bit(RTT_DONE, &ah->caldata->cal_flags);
189*4882a593Smuzhiyun }
190*4882a593Smuzhiyun 
ar9003_hw_rtt_clear_hist(struct ath_hw * ah)191*4882a593Smuzhiyun void ar9003_hw_rtt_clear_hist(struct ath_hw *ah)
192*4882a593Smuzhiyun {
193*4882a593Smuzhiyun 	int chain, i;
194*4882a593Smuzhiyun 
195*4882a593Smuzhiyun 	for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) {
196*4882a593Smuzhiyun 		if (!(ah->caps.rx_chainmask & (1 << chain)))
197*4882a593Smuzhiyun 			continue;
198*4882a593Smuzhiyun 		for (i = 0; i < MAX_RTT_TABLE_ENTRY; i++)
199*4882a593Smuzhiyun 			ar9003_hw_rtt_load_hist_entry(ah, chain, i, 0);
200*4882a593Smuzhiyun 	}
201*4882a593Smuzhiyun 
202*4882a593Smuzhiyun 	if (ah->caldata)
203*4882a593Smuzhiyun 		clear_bit(RTT_DONE, &ah->caldata->cal_flags);
204*4882a593Smuzhiyun }
205*4882a593Smuzhiyun 
ar9003_hw_rtt_restore(struct ath_hw * ah,struct ath9k_channel * chan)206*4882a593Smuzhiyun bool ar9003_hw_rtt_restore(struct ath_hw *ah, struct ath9k_channel *chan)
207*4882a593Smuzhiyun {
208*4882a593Smuzhiyun 	bool restore;
209*4882a593Smuzhiyun 
210*4882a593Smuzhiyun 	if (!ah->caldata)
211*4882a593Smuzhiyun 		return false;
212*4882a593Smuzhiyun 
213*4882a593Smuzhiyun 	if (test_bit(SW_PKDET_DONE, &ah->caldata->cal_flags)) {
214*4882a593Smuzhiyun 		if (IS_CHAN_2GHZ(chan)){
215*4882a593Smuzhiyun 			REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(0),
216*4882a593Smuzhiyun 				      AR_PHY_65NM_RXRF_AGC_AGC2G_CALDAC_OVR,
217*4882a593Smuzhiyun 				      ah->caldata->caldac[0]);
218*4882a593Smuzhiyun 			REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(1),
219*4882a593Smuzhiyun 				      AR_PHY_65NM_RXRF_AGC_AGC2G_CALDAC_OVR,
220*4882a593Smuzhiyun 				      ah->caldata->caldac[1]);
221*4882a593Smuzhiyun 		} else {
222*4882a593Smuzhiyun 			REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(0),
223*4882a593Smuzhiyun 				      AR_PHY_65NM_RXRF_AGC_AGC5G_CALDAC_OVR,
224*4882a593Smuzhiyun 				      ah->caldata->caldac[0]);
225*4882a593Smuzhiyun 			REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(1),
226*4882a593Smuzhiyun 				      AR_PHY_65NM_RXRF_AGC_AGC5G_CALDAC_OVR,
227*4882a593Smuzhiyun 				      ah->caldata->caldac[1]);
228*4882a593Smuzhiyun 		}
229*4882a593Smuzhiyun 		REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(1),
230*4882a593Smuzhiyun 			      AR_PHY_65NM_RXRF_AGC_AGC_OVERRIDE, 0x1);
231*4882a593Smuzhiyun 		REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(0),
232*4882a593Smuzhiyun 			      AR_PHY_65NM_RXRF_AGC_AGC_OVERRIDE, 0x1);
233*4882a593Smuzhiyun 	}
234*4882a593Smuzhiyun 
235*4882a593Smuzhiyun 	if (!test_bit(RTT_DONE, &ah->caldata->cal_flags))
236*4882a593Smuzhiyun 		return false;
237*4882a593Smuzhiyun 
238*4882a593Smuzhiyun 	ar9003_hw_rtt_enable(ah);
239*4882a593Smuzhiyun 
240*4882a593Smuzhiyun 	if (test_bit(SW_PKDET_DONE, &ah->caldata->cal_flags))
241*4882a593Smuzhiyun 		ar9003_hw_rtt_set_mask(ah, 0x30);
242*4882a593Smuzhiyun 	else
243*4882a593Smuzhiyun 		ar9003_hw_rtt_set_mask(ah, 0x10);
244*4882a593Smuzhiyun 
245*4882a593Smuzhiyun 	if (!ath9k_hw_rfbus_req(ah)) {
246*4882a593Smuzhiyun 		ath_err(ath9k_hw_common(ah), "Could not stop baseband\n");
247*4882a593Smuzhiyun 		restore = false;
248*4882a593Smuzhiyun 		goto fail;
249*4882a593Smuzhiyun 	}
250*4882a593Smuzhiyun 
251*4882a593Smuzhiyun 	ar9003_hw_rtt_load_hist(ah);
252*4882a593Smuzhiyun 	restore = ar9003_hw_rtt_force_restore(ah);
253*4882a593Smuzhiyun 
254*4882a593Smuzhiyun fail:
255*4882a593Smuzhiyun 	ath9k_hw_rfbus_done(ah);
256*4882a593Smuzhiyun 	ar9003_hw_rtt_disable(ah);
257*4882a593Smuzhiyun 	return restore;
258*4882a593Smuzhiyun }
259