diff options
Diffstat (limited to 'drivers/net/wireless/ath9k/calib.c')
-rw-r--r-- | drivers/net/wireless/ath9k/calib.c | 1021 |
1 files changed, 1021 insertions, 0 deletions
diff --git a/drivers/net/wireless/ath9k/calib.c b/drivers/net/wireless/ath9k/calib.c new file mode 100644 index 000000000000..3c7454fc51bd --- /dev/null +++ b/drivers/net/wireless/ath9k/calib.c | |||
@@ -0,0 +1,1021 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2008 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 "core.h" | ||
18 | #include "hw.h" | ||
19 | #include "reg.h" | ||
20 | #include "phy.h" | ||
21 | |||
22 | static const int16_t NOISE_FLOOR[] = { -96, -93, -98, -96, -93, -96 }; | ||
23 | |||
24 | /* We can tune this as we go by monitoring really low values */ | ||
25 | #define ATH9K_NF_TOO_LOW -60 | ||
26 | |||
27 | /* AR5416 may return very high value (like -31 dBm), in those cases the nf | ||
28 | * is incorrect and we should use the static NF value. Later we can try to | ||
29 | * find out why they are reporting these values */ | ||
30 | |||
31 | static bool ath9k_hw_nf_in_range(struct ath_hal *ah, s16 nf) | ||
32 | { | ||
33 | if (nf > ATH9K_NF_TOO_LOW) { | ||
34 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | ||
35 | "noise floor value detected (%d) is " | ||
36 | "lower than what we think is a " | ||
37 | "reasonable value (%d)\n", | ||
38 | nf, ATH9K_NF_TOO_LOW); | ||
39 | return false; | ||
40 | } | ||
41 | return true; | ||
42 | } | ||
43 | |||
44 | static int16_t ath9k_hw_get_nf_hist_mid(int16_t *nfCalBuffer) | ||
45 | { | ||
46 | int16_t nfval; | ||
47 | int16_t sort[ATH9K_NF_CAL_HIST_MAX]; | ||
48 | int i, j; | ||
49 | |||
50 | for (i = 0; i < ATH9K_NF_CAL_HIST_MAX; i++) | ||
51 | sort[i] = nfCalBuffer[i]; | ||
52 | |||
53 | for (i = 0; i < ATH9K_NF_CAL_HIST_MAX - 1; i++) { | ||
54 | for (j = 1; j < ATH9K_NF_CAL_HIST_MAX - i; j++) { | ||
55 | if (sort[j] > sort[j - 1]) { | ||
56 | nfval = sort[j]; | ||
57 | sort[j] = sort[j - 1]; | ||
58 | sort[j - 1] = nfval; | ||
59 | } | ||
60 | } | ||
61 | } | ||
62 | nfval = sort[(ATH9K_NF_CAL_HIST_MAX - 1) >> 1]; | ||
63 | |||
64 | return nfval; | ||
65 | } | ||
66 | |||
67 | static void ath9k_hw_update_nfcal_hist_buffer(struct ath9k_nfcal_hist *h, | ||
68 | int16_t *nfarray) | ||
69 | { | ||
70 | int i; | ||
71 | |||
72 | for (i = 0; i < NUM_NF_READINGS; i++) { | ||
73 | h[i].nfCalBuffer[h[i].currIndex] = nfarray[i]; | ||
74 | |||
75 | if (++h[i].currIndex >= ATH9K_NF_CAL_HIST_MAX) | ||
76 | h[i].currIndex = 0; | ||
77 | |||
78 | if (h[i].invalidNFcount > 0) { | ||
79 | if (nfarray[i] < AR_PHY_CCA_MIN_BAD_VALUE || | ||
80 | nfarray[i] > AR_PHY_CCA_MAX_HIGH_VALUE) { | ||
81 | h[i].invalidNFcount = ATH9K_NF_CAL_HIST_MAX; | ||
82 | } else { | ||
83 | h[i].invalidNFcount--; | ||
84 | h[i].privNF = nfarray[i]; | ||
85 | } | ||
86 | } else { | ||
87 | h[i].privNF = | ||
88 | ath9k_hw_get_nf_hist_mid(h[i].nfCalBuffer); | ||
89 | } | ||
90 | } | ||
91 | return; | ||
92 | } | ||
93 | |||
94 | static void ath9k_hw_do_getnf(struct ath_hal *ah, | ||
95 | int16_t nfarray[NUM_NF_READINGS]) | ||
96 | { | ||
97 | int16_t nf; | ||
98 | |||
99 | if (AR_SREV_9280_10_OR_LATER(ah)) | ||
100 | nf = MS(REG_READ(ah, AR_PHY_CCA), AR9280_PHY_MINCCA_PWR); | ||
101 | else | ||
102 | nf = MS(REG_READ(ah, AR_PHY_CCA), AR_PHY_MINCCA_PWR); | ||
103 | |||
104 | if (nf & 0x100) | ||
105 | nf = 0 - ((nf ^ 0x1ff) + 1); | ||
106 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | ||
107 | "NF calibrated [ctl] [chain 0] is %d\n", nf); | ||
108 | nfarray[0] = nf; | ||
109 | |||
110 | if (AR_SREV_9280_10_OR_LATER(ah)) | ||
111 | nf = MS(REG_READ(ah, AR_PHY_CH1_CCA), | ||
112 | AR9280_PHY_CH1_MINCCA_PWR); | ||
113 | else | ||
114 | nf = MS(REG_READ(ah, AR_PHY_CH1_CCA), | ||
115 | AR_PHY_CH1_MINCCA_PWR); | ||
116 | |||
117 | if (nf & 0x100) | ||
118 | nf = 0 - ((nf ^ 0x1ff) + 1); | ||
119 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | ||
120 | "NF calibrated [ctl] [chain 1] is %d\n", nf); | ||
121 | nfarray[1] = nf; | ||
122 | |||
123 | if (!AR_SREV_9280(ah)) { | ||
124 | nf = MS(REG_READ(ah, AR_PHY_CH2_CCA), | ||
125 | AR_PHY_CH2_MINCCA_PWR); | ||
126 | if (nf & 0x100) | ||
127 | nf = 0 - ((nf ^ 0x1ff) + 1); | ||
128 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | ||
129 | "NF calibrated [ctl] [chain 2] is %d\n", nf); | ||
130 | nfarray[2] = nf; | ||
131 | } | ||
132 | |||
133 | if (AR_SREV_9280_10_OR_LATER(ah)) | ||
134 | nf = MS(REG_READ(ah, AR_PHY_EXT_CCA), | ||
135 | AR9280_PHY_EXT_MINCCA_PWR); | ||
136 | else | ||
137 | nf = MS(REG_READ(ah, AR_PHY_EXT_CCA), | ||
138 | AR_PHY_EXT_MINCCA_PWR); | ||
139 | |||
140 | if (nf & 0x100) | ||
141 | nf = 0 - ((nf ^ 0x1ff) + 1); | ||
142 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | ||
143 | "NF calibrated [ext] [chain 0] is %d\n", nf); | ||
144 | nfarray[3] = nf; | ||
145 | |||
146 | if (AR_SREV_9280_10_OR_LATER(ah)) | ||
147 | nf = MS(REG_READ(ah, AR_PHY_CH1_EXT_CCA), | ||
148 | AR9280_PHY_CH1_EXT_MINCCA_PWR); | ||
149 | else | ||
150 | nf = MS(REG_READ(ah, AR_PHY_CH1_EXT_CCA), | ||
151 | AR_PHY_CH1_EXT_MINCCA_PWR); | ||
152 | |||
153 | if (nf & 0x100) | ||
154 | nf = 0 - ((nf ^ 0x1ff) + 1); | ||
155 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | ||
156 | "NF calibrated [ext] [chain 1] is %d\n", nf); | ||
157 | nfarray[4] = nf; | ||
158 | |||
159 | if (!AR_SREV_9280(ah)) { | ||
160 | nf = MS(REG_READ(ah, AR_PHY_CH2_EXT_CCA), | ||
161 | AR_PHY_CH2_EXT_MINCCA_PWR); | ||
162 | if (nf & 0x100) | ||
163 | nf = 0 - ((nf ^ 0x1ff) + 1); | ||
164 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | ||
165 | "NF calibrated [ext] [chain 2] is %d\n", nf); | ||
166 | nfarray[5] = nf; | ||
167 | } | ||
168 | } | ||
169 | |||
170 | static bool getNoiseFloorThresh(struct ath_hal *ah, | ||
171 | const struct ath9k_channel *chan, | ||
172 | int16_t *nft) | ||
173 | { | ||
174 | switch (chan->chanmode) { | ||
175 | case CHANNEL_A: | ||
176 | case CHANNEL_A_HT20: | ||
177 | case CHANNEL_A_HT40PLUS: | ||
178 | case CHANNEL_A_HT40MINUS: | ||
179 | *nft = (int8_t)ath9k_hw_get_eeprom(ah, EEP_NFTHRESH_5); | ||
180 | break; | ||
181 | case CHANNEL_B: | ||
182 | case CHANNEL_G: | ||
183 | case CHANNEL_G_HT20: | ||
184 | case CHANNEL_G_HT40PLUS: | ||
185 | case CHANNEL_G_HT40MINUS: | ||
186 | *nft = (int8_t)ath9k_hw_get_eeprom(ah, EEP_NFTHRESH_2); | ||
187 | break; | ||
188 | default: | ||
189 | DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, | ||
190 | "invalid channel flags 0x%x\n", chan->channelFlags); | ||
191 | return false; | ||
192 | } | ||
193 | |||
194 | return true; | ||
195 | } | ||
196 | |||
197 | static void ath9k_hw_setup_calibration(struct ath_hal *ah, | ||
198 | struct hal_cal_list *currCal) | ||
199 | { | ||
200 | REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(0), | ||
201 | AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX, | ||
202 | currCal->calData->calCountMax); | ||
203 | |||
204 | switch (currCal->calData->calType) { | ||
205 | case IQ_MISMATCH_CAL: | ||
206 | REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_IQ); | ||
207 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | ||
208 | "starting IQ Mismatch Calibration\n"); | ||
209 | break; | ||
210 | case ADC_GAIN_CAL: | ||
211 | REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_GAIN); | ||
212 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | ||
213 | "starting ADC Gain Calibration\n"); | ||
214 | break; | ||
215 | case ADC_DC_CAL: | ||
216 | REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_PER); | ||
217 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | ||
218 | "starting ADC DC Calibration\n"); | ||
219 | break; | ||
220 | case ADC_DC_INIT_CAL: | ||
221 | REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_INIT); | ||
222 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | ||
223 | "starting Init ADC DC Calibration\n"); | ||
224 | break; | ||
225 | } | ||
226 | |||
227 | REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4(0), | ||
228 | AR_PHY_TIMING_CTRL4_DO_CAL); | ||
229 | } | ||
230 | |||
231 | static void ath9k_hw_reset_calibration(struct ath_hal *ah, | ||
232 | struct hal_cal_list *currCal) | ||
233 | { | ||
234 | struct ath_hal_5416 *ahp = AH5416(ah); | ||
235 | int i; | ||
236 | |||
237 | ath9k_hw_setup_calibration(ah, currCal); | ||
238 | |||
239 | currCal->calState = CAL_RUNNING; | ||
240 | |||
241 | for (i = 0; i < AR5416_MAX_CHAINS; i++) { | ||
242 | ahp->ah_Meas0.sign[i] = 0; | ||
243 | ahp->ah_Meas1.sign[i] = 0; | ||
244 | ahp->ah_Meas2.sign[i] = 0; | ||
245 | ahp->ah_Meas3.sign[i] = 0; | ||
246 | } | ||
247 | |||
248 | ahp->ah_CalSamples = 0; | ||
249 | } | ||
250 | |||
251 | static void ath9k_hw_per_calibration(struct ath_hal *ah, | ||
252 | struct ath9k_channel *ichan, | ||
253 | u8 rxchainmask, | ||
254 | struct hal_cal_list *currCal, | ||
255 | bool *isCalDone) | ||
256 | { | ||
257 | struct ath_hal_5416 *ahp = AH5416(ah); | ||
258 | |||
259 | *isCalDone = false; | ||
260 | |||
261 | if (currCal->calState == CAL_RUNNING) { | ||
262 | if (!(REG_READ(ah, AR_PHY_TIMING_CTRL4(0)) & | ||
263 | AR_PHY_TIMING_CTRL4_DO_CAL)) { | ||
264 | |||
265 | currCal->calData->calCollect(ah); | ||
266 | ahp->ah_CalSamples++; | ||
267 | |||
268 | if (ahp->ah_CalSamples >= currCal->calData->calNumSamples) { | ||
269 | int i, numChains = 0; | ||
270 | for (i = 0; i < AR5416_MAX_CHAINS; i++) { | ||
271 | if (rxchainmask & (1 << i)) | ||
272 | numChains++; | ||
273 | } | ||
274 | |||
275 | currCal->calData->calPostProc(ah, numChains); | ||
276 | ichan->CalValid |= currCal->calData->calType; | ||
277 | currCal->calState = CAL_DONE; | ||
278 | *isCalDone = true; | ||
279 | } else { | ||
280 | ath9k_hw_setup_calibration(ah, currCal); | ||
281 | } | ||
282 | } | ||
283 | } else if (!(ichan->CalValid & currCal->calData->calType)) { | ||
284 | ath9k_hw_reset_calibration(ah, currCal); | ||
285 | } | ||
286 | } | ||
287 | |||
288 | static bool ath9k_hw_iscal_supported(struct ath_hal *ah, | ||
289 | struct ath9k_channel *chan, | ||
290 | enum hal_cal_types calType) | ||
291 | { | ||
292 | struct ath_hal_5416 *ahp = AH5416(ah); | ||
293 | bool retval = false; | ||
294 | |||
295 | switch (calType & ahp->ah_suppCals) { | ||
296 | case IQ_MISMATCH_CAL: | ||
297 | if (!IS_CHAN_B(chan)) | ||
298 | retval = true; | ||
299 | break; | ||
300 | case ADC_GAIN_CAL: | ||
301 | case ADC_DC_CAL: | ||
302 | if (!IS_CHAN_B(chan) | ||
303 | && !(IS_CHAN_2GHZ(chan) && IS_CHAN_HT20(chan))) | ||
304 | retval = true; | ||
305 | break; | ||
306 | } | ||
307 | |||
308 | return retval; | ||
309 | } | ||
310 | |||
311 | static void ath9k_hw_iqcal_collect(struct ath_hal *ah) | ||
312 | { | ||
313 | struct ath_hal_5416 *ahp = AH5416(ah); | ||
314 | int i; | ||
315 | |||
316 | for (i = 0; i < AR5416_MAX_CHAINS; i++) { | ||
317 | ahp->ah_totalPowerMeasI[i] += | ||
318 | REG_READ(ah, AR_PHY_CAL_MEAS_0(i)); | ||
319 | ahp->ah_totalPowerMeasQ[i] += | ||
320 | REG_READ(ah, AR_PHY_CAL_MEAS_1(i)); | ||
321 | ahp->ah_totalIqCorrMeas[i] += | ||
322 | (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i)); | ||
323 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | ||
324 | "%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n", | ||
325 | ahp->ah_CalSamples, i, ahp->ah_totalPowerMeasI[i], | ||
326 | ahp->ah_totalPowerMeasQ[i], | ||
327 | ahp->ah_totalIqCorrMeas[i]); | ||
328 | } | ||
329 | } | ||
330 | |||
331 | static void ath9k_hw_adc_gaincal_collect(struct ath_hal *ah) | ||
332 | { | ||
333 | struct ath_hal_5416 *ahp = AH5416(ah); | ||
334 | int i; | ||
335 | |||
336 | for (i = 0; i < AR5416_MAX_CHAINS; i++) { | ||
337 | ahp->ah_totalAdcIOddPhase[i] += | ||
338 | REG_READ(ah, AR_PHY_CAL_MEAS_0(i)); | ||
339 | ahp->ah_totalAdcIEvenPhase[i] += | ||
340 | REG_READ(ah, AR_PHY_CAL_MEAS_1(i)); | ||
341 | ahp->ah_totalAdcQOddPhase[i] += | ||
342 | REG_READ(ah, AR_PHY_CAL_MEAS_2(i)); | ||
343 | ahp->ah_totalAdcQEvenPhase[i] += | ||
344 | REG_READ(ah, AR_PHY_CAL_MEAS_3(i)); | ||
345 | |||
346 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | ||
347 | "%d: Chn %d oddi=0x%08x; eveni=0x%08x; " | ||
348 | "oddq=0x%08x; evenq=0x%08x;\n", | ||
349 | ahp->ah_CalSamples, i, | ||
350 | ahp->ah_totalAdcIOddPhase[i], | ||
351 | ahp->ah_totalAdcIEvenPhase[i], | ||
352 | ahp->ah_totalAdcQOddPhase[i], | ||
353 | ahp->ah_totalAdcQEvenPhase[i]); | ||
354 | } | ||
355 | } | ||
356 | |||
357 | static void ath9k_hw_adc_dccal_collect(struct ath_hal *ah) | ||
358 | { | ||
359 | struct ath_hal_5416 *ahp = AH5416(ah); | ||
360 | int i; | ||
361 | |||
362 | for (i = 0; i < AR5416_MAX_CHAINS; i++) { | ||
363 | ahp->ah_totalAdcDcOffsetIOddPhase[i] += | ||
364 | (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_0(i)); | ||
365 | ahp->ah_totalAdcDcOffsetIEvenPhase[i] += | ||
366 | (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_1(i)); | ||
367 | ahp->ah_totalAdcDcOffsetQOddPhase[i] += | ||
368 | (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i)); | ||
369 | ahp->ah_totalAdcDcOffsetQEvenPhase[i] += | ||
370 | (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_3(i)); | ||
371 | |||
372 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | ||
373 | "%d: Chn %d oddi=0x%08x; eveni=0x%08x; " | ||
374 | "oddq=0x%08x; evenq=0x%08x;\n", | ||
375 | ahp->ah_CalSamples, i, | ||
376 | ahp->ah_totalAdcDcOffsetIOddPhase[i], | ||
377 | ahp->ah_totalAdcDcOffsetIEvenPhase[i], | ||
378 | ahp->ah_totalAdcDcOffsetQOddPhase[i], | ||
379 | ahp->ah_totalAdcDcOffsetQEvenPhase[i]); | ||
380 | } | ||
381 | } | ||
382 | |||
383 | static void ath9k_hw_iqcalibrate(struct ath_hal *ah, u8 numChains) | ||
384 | { | ||
385 | struct ath_hal_5416 *ahp = AH5416(ah); | ||
386 | u32 powerMeasQ, powerMeasI, iqCorrMeas; | ||
387 | u32 qCoffDenom, iCoffDenom; | ||
388 | int32_t qCoff, iCoff; | ||
389 | int iqCorrNeg, i; | ||
390 | |||
391 | for (i = 0; i < numChains; i++) { | ||
392 | powerMeasI = ahp->ah_totalPowerMeasI[i]; | ||
393 | powerMeasQ = ahp->ah_totalPowerMeasQ[i]; | ||
394 | iqCorrMeas = ahp->ah_totalIqCorrMeas[i]; | ||
395 | |||
396 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | ||
397 | "Starting IQ Cal and Correction for Chain %d\n", | ||
398 | i); | ||
399 | |||
400 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | ||
401 | "Orignal: Chn %diq_corr_meas = 0x%08x\n", | ||
402 | i, ahp->ah_totalIqCorrMeas[i]); | ||
403 | |||
404 | iqCorrNeg = 0; | ||
405 | |||
406 | if (iqCorrMeas > 0x80000000) { | ||
407 | iqCorrMeas = (0xffffffff - iqCorrMeas) + 1; | ||
408 | iqCorrNeg = 1; | ||
409 | } | ||
410 | |||
411 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | ||
412 | "Chn %d pwr_meas_i = 0x%08x\n", i, powerMeasI); | ||
413 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | ||
414 | "Chn %d pwr_meas_q = 0x%08x\n", i, powerMeasQ); | ||
415 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, "iqCorrNeg is 0x%08x\n", | ||
416 | iqCorrNeg); | ||
417 | |||
418 | iCoffDenom = (powerMeasI / 2 + powerMeasQ / 2) / 128; | ||
419 | qCoffDenom = powerMeasQ / 64; | ||
420 | |||
421 | if (powerMeasQ != 0) { | ||
422 | iCoff = iqCorrMeas / iCoffDenom; | ||
423 | qCoff = powerMeasI / qCoffDenom - 64; | ||
424 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | ||
425 | "Chn %d iCoff = 0x%08x\n", i, iCoff); | ||
426 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | ||
427 | "Chn %d qCoff = 0x%08x\n", i, qCoff); | ||
428 | |||
429 | iCoff = iCoff & 0x3f; | ||
430 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | ||
431 | "New: Chn %d iCoff = 0x%08x\n", i, iCoff); | ||
432 | if (iqCorrNeg == 0x0) | ||
433 | iCoff = 0x40 - iCoff; | ||
434 | |||
435 | if (qCoff > 15) | ||
436 | qCoff = 15; | ||
437 | else if (qCoff <= -16) | ||
438 | qCoff = 16; | ||
439 | |||
440 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | ||
441 | "Chn %d : iCoff = 0x%x qCoff = 0x%x\n", | ||
442 | i, iCoff, qCoff); | ||
443 | |||
444 | REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(i), | ||
445 | AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF, | ||
446 | iCoff); | ||
447 | REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(i), | ||
448 | AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF, | ||
449 | qCoff); | ||
450 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | ||
451 | "IQ Cal and Correction done for Chain %d\n", | ||
452 | i); | ||
453 | } | ||
454 | } | ||
455 | |||
456 | REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4(0), | ||
457 | AR_PHY_TIMING_CTRL4_IQCORR_ENABLE); | ||
458 | } | ||
459 | |||
460 | static void ath9k_hw_adc_gaincal_calibrate(struct ath_hal *ah, u8 numChains) | ||
461 | { | ||
462 | struct ath_hal_5416 *ahp = AH5416(ah); | ||
463 | u32 iOddMeasOffset, iEvenMeasOffset, qOddMeasOffset, qEvenMeasOffset; | ||
464 | u32 qGainMismatch, iGainMismatch, val, i; | ||
465 | |||
466 | for (i = 0; i < numChains; i++) { | ||
467 | iOddMeasOffset = ahp->ah_totalAdcIOddPhase[i]; | ||
468 | iEvenMeasOffset = ahp->ah_totalAdcIEvenPhase[i]; | ||
469 | qOddMeasOffset = ahp->ah_totalAdcQOddPhase[i]; | ||
470 | qEvenMeasOffset = ahp->ah_totalAdcQEvenPhase[i]; | ||
471 | |||
472 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | ||
473 | "Starting ADC Gain Cal for Chain %d\n", i); | ||
474 | |||
475 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | ||
476 | "Chn %d pwr_meas_odd_i = 0x%08x\n", i, | ||
477 | iOddMeasOffset); | ||
478 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | ||
479 | "Chn %d pwr_meas_even_i = 0x%08x\n", i, | ||
480 | iEvenMeasOffset); | ||
481 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | ||
482 | "Chn %d pwr_meas_odd_q = 0x%08x\n", i, | ||
483 | qOddMeasOffset); | ||
484 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | ||
485 | "Chn %d pwr_meas_even_q = 0x%08x\n", i, | ||
486 | qEvenMeasOffset); | ||
487 | |||
488 | if (iOddMeasOffset != 0 && qEvenMeasOffset != 0) { | ||
489 | iGainMismatch = | ||
490 | ((iEvenMeasOffset * 32) / | ||
491 | iOddMeasOffset) & 0x3f; | ||
492 | qGainMismatch = | ||
493 | ((qOddMeasOffset * 32) / | ||
494 | qEvenMeasOffset) & 0x3f; | ||
495 | |||
496 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | ||
497 | "Chn %d gain_mismatch_i = 0x%08x\n", i, | ||
498 | iGainMismatch); | ||
499 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | ||
500 | "Chn %d gain_mismatch_q = 0x%08x\n", i, | ||
501 | qGainMismatch); | ||
502 | |||
503 | val = REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i)); | ||
504 | val &= 0xfffff000; | ||
505 | val |= (qGainMismatch) | (iGainMismatch << 6); | ||
506 | REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val); | ||
507 | |||
508 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | ||
509 | "ADC Gain Cal done for Chain %d\n", i); | ||
510 | } | ||
511 | } | ||
512 | |||
513 | REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0), | ||
514 | REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0)) | | ||
515 | AR_PHY_NEW_ADC_GAIN_CORR_ENABLE); | ||
516 | } | ||
517 | |||
518 | static void ath9k_hw_adc_dccal_calibrate(struct ath_hal *ah, u8 numChains) | ||
519 | { | ||
520 | struct ath_hal_5416 *ahp = AH5416(ah); | ||
521 | u32 iOddMeasOffset, iEvenMeasOffset, val, i; | ||
522 | int32_t qOddMeasOffset, qEvenMeasOffset, qDcMismatch, iDcMismatch; | ||
523 | const struct hal_percal_data *calData = | ||
524 | ahp->ah_cal_list_curr->calData; | ||
525 | u32 numSamples = | ||
526 | (1 << (calData->calCountMax + 5)) * calData->calNumSamples; | ||
527 | |||
528 | for (i = 0; i < numChains; i++) { | ||
529 | iOddMeasOffset = ahp->ah_totalAdcDcOffsetIOddPhase[i]; | ||
530 | iEvenMeasOffset = ahp->ah_totalAdcDcOffsetIEvenPhase[i]; | ||
531 | qOddMeasOffset = ahp->ah_totalAdcDcOffsetQOddPhase[i]; | ||
532 | qEvenMeasOffset = ahp->ah_totalAdcDcOffsetQEvenPhase[i]; | ||
533 | |||
534 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | ||
535 | "Starting ADC DC Offset Cal for Chain %d\n", i); | ||
536 | |||
537 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | ||
538 | "Chn %d pwr_meas_odd_i = %d\n", i, | ||
539 | iOddMeasOffset); | ||
540 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | ||
541 | "Chn %d pwr_meas_even_i = %d\n", i, | ||
542 | iEvenMeasOffset); | ||
543 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | ||
544 | "Chn %d pwr_meas_odd_q = %d\n", i, | ||
545 | qOddMeasOffset); | ||
546 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | ||
547 | "Chn %d pwr_meas_even_q = %d\n", i, | ||
548 | qEvenMeasOffset); | ||
549 | |||
550 | iDcMismatch = (((iEvenMeasOffset - iOddMeasOffset) * 2) / | ||
551 | numSamples) & 0x1ff; | ||
552 | qDcMismatch = (((qOddMeasOffset - qEvenMeasOffset) * 2) / | ||
553 | numSamples) & 0x1ff; | ||
554 | |||
555 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | ||
556 | "Chn %d dc_offset_mismatch_i = 0x%08x\n", i, | ||
557 | iDcMismatch); | ||
558 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | ||
559 | "Chn %d dc_offset_mismatch_q = 0x%08x\n", i, | ||
560 | qDcMismatch); | ||
561 | |||
562 | val = REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i)); | ||
563 | val &= 0xc0000fff; | ||
564 | val |= (qDcMismatch << 12) | (iDcMismatch << 21); | ||
565 | REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val); | ||
566 | |||
567 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | ||
568 | "ADC DC Offset Cal done for Chain %d\n", i); | ||
569 | } | ||
570 | |||
571 | REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0), | ||
572 | REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0)) | | ||
573 | AR_PHY_NEW_ADC_DC_OFFSET_CORR_ENABLE); | ||
574 | } | ||
575 | |||
576 | void ath9k_hw_reset_calvalid(struct ath_hal *ah, struct ath9k_channel *chan, | ||
577 | bool *isCalDone) | ||
578 | { | ||
579 | struct ath_hal_5416 *ahp = AH5416(ah); | ||
580 | struct ath9k_channel *ichan = | ||
581 | ath9k_regd_check_channel(ah, chan); | ||
582 | struct hal_cal_list *currCal = ahp->ah_cal_list_curr; | ||
583 | |||
584 | *isCalDone = true; | ||
585 | |||
586 | if (!AR_SREV_9100(ah) && !AR_SREV_9160_10_OR_LATER(ah)) | ||
587 | return; | ||
588 | |||
589 | if (currCal == NULL) | ||
590 | return; | ||
591 | |||
592 | if (ichan == NULL) { | ||
593 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | ||
594 | "invalid channel %u/0x%x; no mapping\n", | ||
595 | chan->channel, chan->channelFlags); | ||
596 | return; | ||
597 | } | ||
598 | |||
599 | |||
600 | if (currCal->calState != CAL_DONE) { | ||
601 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | ||
602 | "Calibration state incorrect, %d\n", | ||
603 | currCal->calState); | ||
604 | return; | ||
605 | } | ||
606 | |||
607 | |||
608 | if (!ath9k_hw_iscal_supported(ah, chan, currCal->calData->calType)) | ||
609 | return; | ||
610 | |||
611 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | ||
612 | "Resetting Cal %d state for channel %u/0x%x\n", | ||
613 | currCal->calData->calType, chan->channel, | ||
614 | chan->channelFlags); | ||
615 | |||
616 | ichan->CalValid &= ~currCal->calData->calType; | ||
617 | currCal->calState = CAL_WAITING; | ||
618 | |||
619 | *isCalDone = false; | ||
620 | } | ||
621 | |||
622 | void ath9k_hw_start_nfcal(struct ath_hal *ah) | ||
623 | { | ||
624 | REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, | ||
625 | AR_PHY_AGC_CONTROL_ENABLE_NF); | ||
626 | REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, | ||
627 | AR_PHY_AGC_CONTROL_NO_UPDATE_NF); | ||
628 | REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF); | ||
629 | } | ||
630 | |||
631 | void ath9k_hw_loadnf(struct ath_hal *ah, struct ath9k_channel *chan) | ||
632 | { | ||
633 | struct ath9k_nfcal_hist *h; | ||
634 | int i, j; | ||
635 | int32_t val; | ||
636 | const u32 ar5416_cca_regs[6] = { | ||
637 | AR_PHY_CCA, | ||
638 | AR_PHY_CH1_CCA, | ||
639 | AR_PHY_CH2_CCA, | ||
640 | AR_PHY_EXT_CCA, | ||
641 | AR_PHY_CH1_EXT_CCA, | ||
642 | AR_PHY_CH2_EXT_CCA | ||
643 | }; | ||
644 | u8 chainmask; | ||
645 | |||
646 | if (AR_SREV_9280(ah)) | ||
647 | chainmask = 0x1B; | ||
648 | else | ||
649 | chainmask = 0x3F; | ||
650 | |||
651 | #ifdef ATH_NF_PER_CHAN | ||
652 | h = chan->nfCalHist; | ||
653 | #else | ||
654 | h = ah->nfCalHist; | ||
655 | #endif | ||
656 | |||
657 | for (i = 0; i < NUM_NF_READINGS; i++) { | ||
658 | if (chainmask & (1 << i)) { | ||
659 | val = REG_READ(ah, ar5416_cca_regs[i]); | ||
660 | val &= 0xFFFFFE00; | ||
661 | val |= (((u32) (h[i].privNF) << 1) & 0x1ff); | ||
662 | REG_WRITE(ah, ar5416_cca_regs[i], val); | ||
663 | } | ||
664 | } | ||
665 | |||
666 | REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, | ||
667 | AR_PHY_AGC_CONTROL_ENABLE_NF); | ||
668 | REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, | ||
669 | AR_PHY_AGC_CONTROL_NO_UPDATE_NF); | ||
670 | REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF); | ||
671 | |||
672 | for (j = 0; j < 1000; j++) { | ||
673 | if ((REG_READ(ah, AR_PHY_AGC_CONTROL) & | ||
674 | AR_PHY_AGC_CONTROL_NF) == 0) | ||
675 | break; | ||
676 | udelay(10); | ||
677 | } | ||
678 | |||
679 | for (i = 0; i < NUM_NF_READINGS; i++) { | ||
680 | if (chainmask & (1 << i)) { | ||
681 | val = REG_READ(ah, ar5416_cca_regs[i]); | ||
682 | val &= 0xFFFFFE00; | ||
683 | val |= (((u32) (-50) << 1) & 0x1ff); | ||
684 | REG_WRITE(ah, ar5416_cca_regs[i], val); | ||
685 | } | ||
686 | } | ||
687 | } | ||
688 | |||
689 | int16_t ath9k_hw_getnf(struct ath_hal *ah, | ||
690 | struct ath9k_channel *chan) | ||
691 | { | ||
692 | int16_t nf, nfThresh; | ||
693 | int16_t nfarray[NUM_NF_READINGS] = { 0 }; | ||
694 | struct ath9k_nfcal_hist *h; | ||
695 | u8 chainmask; | ||
696 | |||
697 | if (AR_SREV_9280(ah)) | ||
698 | chainmask = 0x1B; | ||
699 | else | ||
700 | chainmask = 0x3F; | ||
701 | |||
702 | chan->channelFlags &= (~CHANNEL_CW_INT); | ||
703 | if (REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) { | ||
704 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | ||
705 | "NF did not complete in calibration window\n"); | ||
706 | nf = 0; | ||
707 | chan->rawNoiseFloor = nf; | ||
708 | return chan->rawNoiseFloor; | ||
709 | } else { | ||
710 | ath9k_hw_do_getnf(ah, nfarray); | ||
711 | nf = nfarray[0]; | ||
712 | if (getNoiseFloorThresh(ah, chan, &nfThresh) | ||
713 | && nf > nfThresh) { | ||
714 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | ||
715 | "noise floor failed detected; " | ||
716 | "detected %d, threshold %d\n", | ||
717 | nf, nfThresh); | ||
718 | chan->channelFlags |= CHANNEL_CW_INT; | ||
719 | } | ||
720 | } | ||
721 | |||
722 | #ifdef ATH_NF_PER_CHAN | ||
723 | h = chan->nfCalHist; | ||
724 | #else | ||
725 | h = ah->nfCalHist; | ||
726 | #endif | ||
727 | |||
728 | ath9k_hw_update_nfcal_hist_buffer(h, nfarray); | ||
729 | chan->rawNoiseFloor = h[0].privNF; | ||
730 | |||
731 | return chan->rawNoiseFloor; | ||
732 | } | ||
733 | |||
734 | void ath9k_init_nfcal_hist_buffer(struct ath_hal *ah) | ||
735 | { | ||
736 | int i, j; | ||
737 | |||
738 | for (i = 0; i < NUM_NF_READINGS; i++) { | ||
739 | ah->nfCalHist[i].currIndex = 0; | ||
740 | ah->nfCalHist[i].privNF = AR_PHY_CCA_MAX_GOOD_VALUE; | ||
741 | ah->nfCalHist[i].invalidNFcount = | ||
742 | AR_PHY_CCA_FILTERWINDOW_LENGTH; | ||
743 | for (j = 0; j < ATH9K_NF_CAL_HIST_MAX; j++) { | ||
744 | ah->nfCalHist[i].nfCalBuffer[j] = | ||
745 | AR_PHY_CCA_MAX_GOOD_VALUE; | ||
746 | } | ||
747 | } | ||
748 | return; | ||
749 | } | ||
750 | |||
751 | s16 ath9k_hw_getchan_noise(struct ath_hal *ah, struct ath9k_channel *chan) | ||
752 | { | ||
753 | struct ath9k_channel *ichan; | ||
754 | s16 nf; | ||
755 | |||
756 | ichan = ath9k_regd_check_channel(ah, chan); | ||
757 | if (ichan == NULL) { | ||
758 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | ||
759 | "invalid channel %u/0x%x; no mapping\n", | ||
760 | chan->channel, chan->channelFlags); | ||
761 | return ATH_DEFAULT_NOISE_FLOOR; | ||
762 | } | ||
763 | if (ichan->rawNoiseFloor == 0) { | ||
764 | enum wireless_mode mode = ath9k_hw_chan2wmode(ah, chan); | ||
765 | nf = NOISE_FLOOR[mode]; | ||
766 | } else | ||
767 | nf = ichan->rawNoiseFloor; | ||
768 | |||
769 | if (!ath9k_hw_nf_in_range(ah, nf)) | ||
770 | nf = ATH_DEFAULT_NOISE_FLOOR; | ||
771 | |||
772 | return nf; | ||
773 | } | ||
774 | |||
775 | bool ath9k_hw_calibrate(struct ath_hal *ah, struct ath9k_channel *chan, | ||
776 | u8 rxchainmask, bool longcal, | ||
777 | bool *isCalDone) | ||
778 | { | ||
779 | struct ath_hal_5416 *ahp = AH5416(ah); | ||
780 | struct hal_cal_list *currCal = ahp->ah_cal_list_curr; | ||
781 | struct ath9k_channel *ichan = ath9k_regd_check_channel(ah, chan); | ||
782 | |||
783 | *isCalDone = true; | ||
784 | |||
785 | if (ichan == NULL) { | ||
786 | DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, | ||
787 | "invalid channel %u/0x%x; no mapping\n", | ||
788 | chan->channel, chan->channelFlags); | ||
789 | return false; | ||
790 | } | ||
791 | |||
792 | if (currCal && | ||
793 | (currCal->calState == CAL_RUNNING || | ||
794 | currCal->calState == CAL_WAITING)) { | ||
795 | ath9k_hw_per_calibration(ah, ichan, rxchainmask, currCal, | ||
796 | isCalDone); | ||
797 | if (*isCalDone) { | ||
798 | ahp->ah_cal_list_curr = currCal = currCal->calNext; | ||
799 | |||
800 | if (currCal->calState == CAL_WAITING) { | ||
801 | *isCalDone = false; | ||
802 | ath9k_hw_reset_calibration(ah, currCal); | ||
803 | } | ||
804 | } | ||
805 | } | ||
806 | |||
807 | if (longcal) { | ||
808 | ath9k_hw_getnf(ah, ichan); | ||
809 | ath9k_hw_loadnf(ah, ah->ah_curchan); | ||
810 | ath9k_hw_start_nfcal(ah); | ||
811 | |||
812 | if ((ichan->channelFlags & CHANNEL_CW_INT) != 0) { | ||
813 | chan->channelFlags |= CHANNEL_CW_INT; | ||
814 | ichan->channelFlags &= ~CHANNEL_CW_INT; | ||
815 | } | ||
816 | } | ||
817 | |||
818 | return true; | ||
819 | } | ||
820 | |||
821 | static inline void ath9k_hw_9285_pa_cal(struct ath_hal *ah) | ||
822 | { | ||
823 | |||
824 | u32 regVal; | ||
825 | int i, offset, offs_6_1, offs_0; | ||
826 | u32 ccomp_org, reg_field; | ||
827 | u32 regList[][2] = { | ||
828 | { 0x786c, 0 }, | ||
829 | { 0x7854, 0 }, | ||
830 | { 0x7820, 0 }, | ||
831 | { 0x7824, 0 }, | ||
832 | { 0x7868, 0 }, | ||
833 | { 0x783c, 0 }, | ||
834 | { 0x7838, 0 }, | ||
835 | }; | ||
836 | |||
837 | if (AR_SREV_9285_11(ah)) { | ||
838 | REG_WRITE(ah, AR9285_AN_TOP4, (AR9285_AN_TOP4_DEFAULT | 0x14)); | ||
839 | udelay(10); | ||
840 | } | ||
841 | |||
842 | for (i = 0; i < ARRAY_SIZE(regList); i++) | ||
843 | regList[i][1] = REG_READ(ah, regList[i][0]); | ||
844 | |||
845 | regVal = REG_READ(ah, 0x7834); | ||
846 | regVal &= (~(0x1)); | ||
847 | REG_WRITE(ah, 0x7834, regVal); | ||
848 | regVal = REG_READ(ah, 0x9808); | ||
849 | regVal |= (0x1 << 27); | ||
850 | REG_WRITE(ah, 0x9808, regVal); | ||
851 | |||
852 | REG_RMW_FIELD(ah, AR9285_AN_TOP3, AR9285_AN_TOP3_PWDDAC, 1); | ||
853 | REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDRXTXBB1, 1); | ||
854 | REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDV2I, 1); | ||
855 | REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDDACIF, 1); | ||
856 | REG_RMW_FIELD(ah, AR9285_AN_RF2G2, AR9285_AN_RF2G2_OFFCAL, 0); | ||
857 | REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PWDDB, 0); | ||
858 | REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_ENPACAL, 0); | ||
859 | REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV1, 1); | ||
860 | REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV2, 0); | ||
861 | REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPAOUT, 0); | ||
862 | REG_RMW_FIELD(ah, AR9285_AN_RF2G8, AR9285_AN_RF2G8_PADRVGN2TAB0, 7); | ||
863 | REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PADRVGN2TAB0, 0); | ||
864 | ccomp_org = MS(REG_READ(ah, AR9285_AN_RF2G6), AR9285_AN_RF2G6_CCOMP); | ||
865 | REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_CCOMP, 7); | ||
866 | |||
867 | REG_WRITE(ah, AR9285_AN_TOP2, 0xca0358a0); | ||
868 | udelay(30); | ||
869 | REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_OFFS, 0); | ||
870 | REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, 0); | ||
871 | |||
872 | for (i = 6; i > 0; i--) { | ||
873 | regVal = REG_READ(ah, 0x7834); | ||
874 | regVal |= (1 << (19 + i)); | ||
875 | REG_WRITE(ah, 0x7834, regVal); | ||
876 | udelay(1); | ||
877 | regVal = REG_READ(ah, 0x7834); | ||
878 | regVal &= (~(0x1 << (19 + i))); | ||
879 | reg_field = MS(REG_READ(ah, 0x7840), AR9285_AN_RXTXBB1_SPARE9); | ||
880 | regVal |= (reg_field << (19 + i)); | ||
881 | REG_WRITE(ah, 0x7834, regVal); | ||
882 | } | ||
883 | |||
884 | REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, 1); | ||
885 | udelay(1); | ||
886 | reg_field = MS(REG_READ(ah, AR9285_AN_RF2G9), AR9285_AN_RXTXBB1_SPARE9); | ||
887 | REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, reg_field); | ||
888 | offs_6_1 = MS(REG_READ(ah, AR9285_AN_RF2G6), AR9285_AN_RF2G6_OFFS); | ||
889 | offs_0 = MS(REG_READ(ah, AR9285_AN_RF2G3), AR9285_AN_RF2G3_PDVCCOMP); | ||
890 | |||
891 | offset = (offs_6_1<<1) | offs_0; | ||
892 | offset = offset - 0; | ||
893 | offs_6_1 = offset>>1; | ||
894 | offs_0 = offset & 1; | ||
895 | |||
896 | REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_OFFS, offs_6_1); | ||
897 | REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, offs_0); | ||
898 | |||
899 | regVal = REG_READ(ah, 0x7834); | ||
900 | regVal |= 0x1; | ||
901 | REG_WRITE(ah, 0x7834, regVal); | ||
902 | regVal = REG_READ(ah, 0x9808); | ||
903 | regVal &= (~(0x1 << 27)); | ||
904 | REG_WRITE(ah, 0x9808, regVal); | ||
905 | |||
906 | for (i = 0; i < ARRAY_SIZE(regList); i++) | ||
907 | REG_WRITE(ah, regList[i][0], regList[i][1]); | ||
908 | |||
909 | REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_CCOMP, ccomp_org); | ||
910 | |||
911 | if (AR_SREV_9285_11(ah)) | ||
912 | REG_WRITE(ah, AR9285_AN_TOP4, AR9285_AN_TOP4_DEFAULT); | ||
913 | |||
914 | } | ||
915 | |||
916 | bool ath9k_hw_init_cal(struct ath_hal *ah, | ||
917 | struct ath9k_channel *chan) | ||
918 | { | ||
919 | struct ath_hal_5416 *ahp = AH5416(ah); | ||
920 | struct ath9k_channel *ichan = ath9k_regd_check_channel(ah, chan); | ||
921 | |||
922 | REG_WRITE(ah, AR_PHY_AGC_CONTROL, | ||
923 | REG_READ(ah, AR_PHY_AGC_CONTROL) | | ||
924 | AR_PHY_AGC_CONTROL_CAL); | ||
925 | |||
926 | if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 0)) { | ||
927 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | ||
928 | "offset calibration failed to complete in 1ms; " | ||
929 | "noisy environment?\n"); | ||
930 | return false; | ||
931 | } | ||
932 | |||
933 | if (AR_SREV_9285(ah) && AR_SREV_9285_11_OR_LATER(ah)) | ||
934 | ath9k_hw_9285_pa_cal(ah); | ||
935 | |||
936 | REG_WRITE(ah, AR_PHY_AGC_CONTROL, | ||
937 | REG_READ(ah, AR_PHY_AGC_CONTROL) | | ||
938 | AR_PHY_AGC_CONTROL_NF); | ||
939 | |||
940 | ahp->ah_cal_list = ahp->ah_cal_list_last = ahp->ah_cal_list_curr = NULL; | ||
941 | |||
942 | if (AR_SREV_9100(ah) || AR_SREV_9160_10_OR_LATER(ah)) { | ||
943 | if (ath9k_hw_iscal_supported(ah, chan, ADC_GAIN_CAL)) { | ||
944 | INIT_CAL(&ahp->ah_adcGainCalData); | ||
945 | INSERT_CAL(ahp, &ahp->ah_adcGainCalData); | ||
946 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | ||
947 | "enabling ADC Gain Calibration.\n"); | ||
948 | } | ||
949 | if (ath9k_hw_iscal_supported(ah, chan, ADC_DC_CAL)) { | ||
950 | INIT_CAL(&ahp->ah_adcDcCalData); | ||
951 | INSERT_CAL(ahp, &ahp->ah_adcDcCalData); | ||
952 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | ||
953 | "enabling ADC DC Calibration.\n"); | ||
954 | } | ||
955 | if (ath9k_hw_iscal_supported(ah, chan, IQ_MISMATCH_CAL)) { | ||
956 | INIT_CAL(&ahp->ah_iqCalData); | ||
957 | INSERT_CAL(ahp, &ahp->ah_iqCalData); | ||
958 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | ||
959 | "enabling IQ Calibration.\n"); | ||
960 | } | ||
961 | |||
962 | ahp->ah_cal_list_curr = ahp->ah_cal_list; | ||
963 | |||
964 | if (ahp->ah_cal_list_curr) | ||
965 | ath9k_hw_reset_calibration(ah, ahp->ah_cal_list_curr); | ||
966 | } | ||
967 | |||
968 | ichan->CalValid = 0; | ||
969 | |||
970 | return true; | ||
971 | } | ||
972 | |||
973 | const struct hal_percal_data iq_cal_multi_sample = { | ||
974 | IQ_MISMATCH_CAL, | ||
975 | MAX_CAL_SAMPLES, | ||
976 | PER_MIN_LOG_COUNT, | ||
977 | ath9k_hw_iqcal_collect, | ||
978 | ath9k_hw_iqcalibrate | ||
979 | }; | ||
980 | const struct hal_percal_data iq_cal_single_sample = { | ||
981 | IQ_MISMATCH_CAL, | ||
982 | MIN_CAL_SAMPLES, | ||
983 | PER_MAX_LOG_COUNT, | ||
984 | ath9k_hw_iqcal_collect, | ||
985 | ath9k_hw_iqcalibrate | ||
986 | }; | ||
987 | const struct hal_percal_data adc_gain_cal_multi_sample = { | ||
988 | ADC_GAIN_CAL, | ||
989 | MAX_CAL_SAMPLES, | ||
990 | PER_MIN_LOG_COUNT, | ||
991 | ath9k_hw_adc_gaincal_collect, | ||
992 | ath9k_hw_adc_gaincal_calibrate | ||
993 | }; | ||
994 | const struct hal_percal_data adc_gain_cal_single_sample = { | ||
995 | ADC_GAIN_CAL, | ||
996 | MIN_CAL_SAMPLES, | ||
997 | PER_MAX_LOG_COUNT, | ||
998 | ath9k_hw_adc_gaincal_collect, | ||
999 | ath9k_hw_adc_gaincal_calibrate | ||
1000 | }; | ||
1001 | const struct hal_percal_data adc_dc_cal_multi_sample = { | ||
1002 | ADC_DC_CAL, | ||
1003 | MAX_CAL_SAMPLES, | ||
1004 | PER_MIN_LOG_COUNT, | ||
1005 | ath9k_hw_adc_dccal_collect, | ||
1006 | ath9k_hw_adc_dccal_calibrate | ||
1007 | }; | ||
1008 | const struct hal_percal_data adc_dc_cal_single_sample = { | ||
1009 | ADC_DC_CAL, | ||
1010 | MIN_CAL_SAMPLES, | ||
1011 | PER_MAX_LOG_COUNT, | ||
1012 | ath9k_hw_adc_dccal_collect, | ||
1013 | ath9k_hw_adc_dccal_calibrate | ||
1014 | }; | ||
1015 | const struct hal_percal_data adc_init_dc_cal = { | ||
1016 | ADC_DC_INIT_CAL, | ||
1017 | MIN_CAL_SAMPLES, | ||
1018 | INIT_LOG_COUNT, | ||
1019 | ath9k_hw_adc_dccal_collect, | ||
1020 | ath9k_hw_adc_dccal_calibrate | ||
1021 | }; | ||