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