085e1264fbe0d364ce868742ad66b8688587f2a4
[firefly-linux-kernel-4.4.55.git] / drivers / net / wireless / ath / ath9k / calib.c
1 /*
2  * Copyright (c) 2008-2009 Atheros Communications Inc.
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16
17 #include "hw.h"
18 #include "hw-ops.h"
19 #include "ar9002_phy.h"
20
21 /* Common calibration code */
22
23 /* We can tune this as we go by monitoring really low values */
24 #define ATH9K_NF_TOO_LOW        -60
25
26 /* AR5416 may return very high value (like -31 dBm), in those cases the nf
27  * is incorrect and we should use the static NF value. Later we can try to
28  * find out why they are reporting these values */
29
30 static bool ath9k_hw_nf_in_range(struct ath_hw *ah, s16 nf)
31 {
32         if (nf > ATH9K_NF_TOO_LOW) {
33                 ath_print(ath9k_hw_common(ah), ATH_DBG_CALIBRATE,
34                           "noise floor value detected (%d) is "
35                           "lower than what we think is a "
36                           "reasonable value (%d)\n",
37                           nf, ATH9K_NF_TOO_LOW);
38                 return false;
39         }
40         return true;
41 }
42
43 static int16_t ath9k_hw_get_nf_hist_mid(int16_t *nfCalBuffer)
44 {
45         int16_t nfval;
46         int16_t sort[ATH9K_NF_CAL_HIST_MAX];
47         int i, j;
48
49         for (i = 0; i < ATH9K_NF_CAL_HIST_MAX; i++)
50                 sort[i] = nfCalBuffer[i];
51
52         for (i = 0; i < ATH9K_NF_CAL_HIST_MAX - 1; i++) {
53                 for (j = 1; j < ATH9K_NF_CAL_HIST_MAX - i; j++) {
54                         if (sort[j] > sort[j - 1]) {
55                                 nfval = sort[j];
56                                 sort[j] = sort[j - 1];
57                                 sort[j - 1] = nfval;
58                         }
59                 }
60         }
61         nfval = sort[(ATH9K_NF_CAL_HIST_MAX - 1) >> 1];
62
63         return nfval;
64 }
65
66 static void ath9k_hw_update_nfcal_hist_buffer(struct ath9k_nfcal_hist *h,
67                                               int16_t *nfarray)
68 {
69         int i;
70
71         for (i = 0; i < NUM_NF_READINGS; i++) {
72                 h[i].nfCalBuffer[h[i].currIndex] = nfarray[i];
73
74                 if (++h[i].currIndex >= ATH9K_NF_CAL_HIST_MAX)
75                         h[i].currIndex = 0;
76
77                 if (h[i].invalidNFcount > 0) {
78                         if (nfarray[i] < AR_PHY_CCA_MIN_BAD_VALUE ||
79                             nfarray[i] > AR_PHY_CCA_MAX_HIGH_VALUE) {
80                                 h[i].invalidNFcount = ATH9K_NF_CAL_HIST_MAX;
81                         } else {
82                                 h[i].invalidNFcount--;
83                                 h[i].privNF = nfarray[i];
84                         }
85                 } else {
86                         h[i].privNF =
87                                 ath9k_hw_get_nf_hist_mid(h[i].nfCalBuffer);
88                 }
89         }
90         return;
91 }
92
93 static bool ath9k_hw_get_nf_thresh(struct ath_hw *ah,
94                                    enum ieee80211_band band,
95                                    int16_t *nft)
96 {
97         switch (band) {
98         case IEEE80211_BAND_5GHZ:
99                 *nft = (int8_t)ah->eep_ops->get_eeprom(ah, EEP_NFTHRESH_5);
100                 break;
101         case IEEE80211_BAND_2GHZ:
102                 *nft = (int8_t)ah->eep_ops->get_eeprom(ah, EEP_NFTHRESH_2);
103                 break;
104         default:
105                 BUG_ON(1);
106                 return false;
107         }
108
109         return true;
110 }
111
112 void ath9k_hw_reset_calibration(struct ath_hw *ah,
113                                 struct ath9k_cal_list *currCal)
114 {
115         int i;
116
117         ath9k_hw_setup_calibration(ah, currCal);
118
119         currCal->calState = CAL_RUNNING;
120
121         for (i = 0; i < AR5416_MAX_CHAINS; i++) {
122                 ah->meas0.sign[i] = 0;
123                 ah->meas1.sign[i] = 0;
124                 ah->meas2.sign[i] = 0;
125                 ah->meas3.sign[i] = 0;
126         }
127
128         ah->cal_samples = 0;
129 }
130
131 /* This is done for the currently configured channel */
132 bool ath9k_hw_reset_calvalid(struct ath_hw *ah)
133 {
134         struct ath_common *common = ath9k_hw_common(ah);
135         struct ieee80211_conf *conf = &common->hw->conf;
136         struct ath9k_cal_list *currCal = ah->cal_list_curr;
137
138         if (!ah->curchan)
139                 return true;
140
141         if (!AR_SREV_9100(ah) && !AR_SREV_9160_10_OR_LATER(ah))
142                 return true;
143
144         if (currCal == NULL)
145                 return true;
146
147         if (currCal->calState != CAL_DONE) {
148                 ath_print(common, ATH_DBG_CALIBRATE,
149                           "Calibration state incorrect, %d\n",
150                           currCal->calState);
151                 return true;
152         }
153
154         if (!ath9k_hw_iscal_supported(ah, currCal->calData->calType))
155                 return true;
156
157         ath_print(common, ATH_DBG_CALIBRATE,
158                   "Resetting Cal %d state for channel %u\n",
159                   currCal->calData->calType, conf->channel->center_freq);
160
161         ah->curchan->CalValid &= ~currCal->calData->calType;
162         currCal->calState = CAL_WAITING;
163
164         return false;
165 }
166 EXPORT_SYMBOL(ath9k_hw_reset_calvalid);
167
168 void ath9k_hw_start_nfcal(struct ath_hw *ah)
169 {
170         REG_SET_BIT(ah, AR_PHY_AGC_CONTROL,
171                     AR_PHY_AGC_CONTROL_ENABLE_NF);
172         REG_SET_BIT(ah, AR_PHY_AGC_CONTROL,
173                     AR_PHY_AGC_CONTROL_NO_UPDATE_NF);
174         REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
175 }
176
177 void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
178 {
179         struct ath9k_nfcal_hist *h;
180         int i, j;
181         int32_t val;
182         const u32 ar5416_cca_regs[6] = {
183                 AR_PHY_CCA,
184                 AR_PHY_CH1_CCA,
185                 AR_PHY_CH2_CCA,
186                 AR_PHY_EXT_CCA,
187                 AR_PHY_CH1_EXT_CCA,
188                 AR_PHY_CH2_EXT_CCA
189         };
190         u8 chainmask, rx_chain_status;
191
192         rx_chain_status = REG_READ(ah, AR_PHY_RX_CHAINMASK);
193         if (AR_SREV_9285(ah) || AR_SREV_9271(ah))
194                 chainmask = 0x9;
195         else if (AR_SREV_9280(ah) || AR_SREV_9287(ah)) {
196                 if ((rx_chain_status & 0x2) || (rx_chain_status & 0x4))
197                         chainmask = 0x1B;
198                 else
199                         chainmask = 0x09;
200         } else {
201                 if (rx_chain_status & 0x4)
202                         chainmask = 0x3F;
203                 else if (rx_chain_status & 0x2)
204                         chainmask = 0x1B;
205                 else
206                         chainmask = 0x09;
207         }
208
209         h = ah->nfCalHist;
210
211         for (i = 0; i < NUM_NF_READINGS; i++) {
212                 if (chainmask & (1 << i)) {
213                         val = REG_READ(ah, ar5416_cca_regs[i]);
214                         val &= 0xFFFFFE00;
215                         val |= (((u32) (h[i].privNF) << 1) & 0x1ff);
216                         REG_WRITE(ah, ar5416_cca_regs[i], val);
217                 }
218         }
219
220         REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
221                     AR_PHY_AGC_CONTROL_ENABLE_NF);
222         REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
223                     AR_PHY_AGC_CONTROL_NO_UPDATE_NF);
224         REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
225
226         for (j = 0; j < 5; j++) {
227                 if ((REG_READ(ah, AR_PHY_AGC_CONTROL) &
228                      AR_PHY_AGC_CONTROL_NF) == 0)
229                         break;
230                 udelay(50);
231         }
232
233         for (i = 0; i < NUM_NF_READINGS; i++) {
234                 if (chainmask & (1 << i)) {
235                         val = REG_READ(ah, ar5416_cca_regs[i]);
236                         val &= 0xFFFFFE00;
237                         val |= (((u32) (-50) << 1) & 0x1ff);
238                         REG_WRITE(ah, ar5416_cca_regs[i], val);
239                 }
240         }
241 }
242
243 int16_t ath9k_hw_getnf(struct ath_hw *ah,
244                        struct ath9k_channel *chan)
245 {
246         struct ath_common *common = ath9k_hw_common(ah);
247         int16_t nf, nfThresh;
248         int16_t nfarray[NUM_NF_READINGS] = { 0 };
249         struct ath9k_nfcal_hist *h;
250         struct ieee80211_channel *c = chan->chan;
251
252         chan->channelFlags &= (~CHANNEL_CW_INT);
253         if (REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) {
254                 ath_print(common, ATH_DBG_CALIBRATE,
255                           "NF did not complete in calibration window\n");
256                 nf = 0;
257                 chan->rawNoiseFloor = nf;
258                 return chan->rawNoiseFloor;
259         } else {
260                 ath9k_hw_do_getnf(ah, nfarray);
261                 nf = nfarray[0];
262                 if (ath9k_hw_get_nf_thresh(ah, c->band, &nfThresh)
263                     && nf > nfThresh) {
264                         ath_print(common, ATH_DBG_CALIBRATE,
265                                   "noise floor failed detected; "
266                                   "detected %d, threshold %d\n",
267                                   nf, nfThresh);
268                         chan->channelFlags |= CHANNEL_CW_INT;
269                 }
270         }
271
272         h = ah->nfCalHist;
273
274         ath9k_hw_update_nfcal_hist_buffer(h, nfarray);
275         chan->rawNoiseFloor = h[0].privNF;
276
277         return chan->rawNoiseFloor;
278 }
279
280 void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah)
281 {
282         int i, j;
283         s16 noise_floor;
284
285         if (AR_SREV_9280(ah))
286                 noise_floor = AR_PHY_CCA_MAX_AR9280_GOOD_VALUE;
287         else if (AR_SREV_9285(ah) || AR_SREV_9271(ah))
288                 noise_floor = AR_PHY_CCA_MAX_AR9285_GOOD_VALUE;
289         else if (AR_SREV_9287(ah))
290                 noise_floor = AR_PHY_CCA_MAX_AR9287_GOOD_VALUE;
291         else
292                 noise_floor = AR_PHY_CCA_MAX_AR5416_GOOD_VALUE;
293
294         for (i = 0; i < NUM_NF_READINGS; i++) {
295                 ah->nfCalHist[i].currIndex = 0;
296                 ah->nfCalHist[i].privNF = noise_floor;
297                 ah->nfCalHist[i].invalidNFcount =
298                         AR_PHY_CCA_FILTERWINDOW_LENGTH;
299                 for (j = 0; j < ATH9K_NF_CAL_HIST_MAX; j++) {
300                         ah->nfCalHist[i].nfCalBuffer[j] = noise_floor;
301                 }
302         }
303 }
304
305 s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan)
306 {
307         s16 nf;
308
309         if (chan->rawNoiseFloor == 0)
310                 nf = -96;
311         else
312                 nf = chan->rawNoiseFloor;
313
314         if (!ath9k_hw_nf_in_range(ah, nf))
315                 nf = ATH_DEFAULT_NOISE_FLOOR;
316
317         return nf;
318 }
319 EXPORT_SYMBOL(ath9k_hw_getchan_noise);