iPXE
ath9k_ar9003_calib.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2010-2011 Atheros Communications Inc.
3  *
4  * Modified for iPXE by Scott K Logan <logans@cottsay.net> July 2011
5  * Original from Linux kernel 3.0.1
6  *
7  * Permission to use, copy, modify, and/or distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include <ipxe/io.h>
21 
22 #include "hw.h"
23 #include "hw-ops.h"
24 #include "ar9003_phy.h"
25 
26 #define MAX_MEASUREMENT 8
27 #define MAX_MAG_DELTA 11
28 #define MAX_PHS_DELTA 10
29 
30 struct coeff {
33  int iqc_coeff[2];
34 };
35 
39 };
40 
42  struct ath9k_cal_list *currCal)
43 {
44  /* Select calibration to run */
45  switch (currCal->calData->calType) {
46  case IQ_MISMATCH_CAL:
47  /*
48  * Start calibration with
49  * 2^(INIT_IQCAL_LOG_COUNT_MAX+1) samples
50  */
53  currCal->calData->calCountMax);
55 
56  DBG2("ath9k: "
57  "starting IQ Mismatch Calibration\n");
58 
59  /* Kick-off cal */
61  break;
62  case TEMP_COMP_CAL:
67 
68  DBG2("ath9k: "
69  "starting Temperature Compensation Calibration\n");
70  break;
71  }
72 }
73 
74 /*
75  * Generic calibration routine.
76  * Recalibrate the lower PHY chips to account for temperature/environment
77  * changes.
78  */
79 static int ar9003_hw_per_calibration(struct ath_hw *ah,
80  struct ath9k_channel *ichan __unused,
81  u8 rxchainmask,
82  struct ath9k_cal_list *currCal)
83 {
84  struct ath9k_hw_cal_data *caldata = ah->caldata;
85  /* Cal is assumed not done until explicitly set below */
86  int iscaldone = 0;
87 
88  /* Calibration in progress. */
89  if (currCal->calState == CAL_RUNNING) {
90  /* Check to see if it has finished. */
92  /*
93  * Accumulate cal measures for active chains
94  */
95  currCal->calData->calCollect(ah);
96  ah->cal_samples++;
97 
98  if (ah->cal_samples >=
99  currCal->calData->calNumSamples) {
100  unsigned int i, numChains = 0;
101  for (i = 0; i < AR9300_MAX_CHAINS; i++) {
102  if (rxchainmask & (1 << i))
103  numChains++;
104  }
105 
106  /*
107  * Process accumulated data
108  */
109  currCal->calData->calPostProc(ah, numChains);
110 
111  /* Calibration has finished. */
112  caldata->CalValid |= currCal->calData->calType;
113  currCal->calState = CAL_DONE;
114  iscaldone = 1;
115  } else {
116  /*
117  * Set-up collection of another sub-sample until we
118  * get desired number
119  */
121  }
122  }
123  } else if (!(caldata->CalValid & currCal->calData->calType)) {
124  /* If current cal is marked invalid in channel, kick it off */
125  ath9k_hw_reset_calibration(ah, currCal);
126  }
127 
128  return iscaldone;
129 }
130 
131 static int ar9003_hw_calibrate(struct ath_hw *ah,
132  struct ath9k_channel *chan,
133  u8 rxchainmask,
134  int longcal)
135 {
136  int iscaldone = 1;
137  struct ath9k_cal_list *currCal = ah->cal_list_curr;
138 
139  /*
140  * For given calibration:
141  * 1. Call generic cal routine
142  * 2. When this cal is done (isCalDone) if we have more cals waiting
143  * (eg after reset), mask this to upper layers by not propagating
144  * isCalDone if it is set to TRUE.
145  * Instead, change isCalDone to FALSE and setup the waiting cal(s)
146  * to be run.
147  */
148  if (currCal &&
149  (currCal->calState == CAL_RUNNING ||
150  currCal->calState == CAL_WAITING)) {
151  iscaldone = ar9003_hw_per_calibration(ah, chan,
152  rxchainmask, currCal);
153  if (iscaldone) {
154  ah->cal_list_curr = currCal = currCal->calNext;
155 
156  if (currCal->calState == CAL_WAITING) {
157  iscaldone = 0;
158  ath9k_hw_reset_calibration(ah, currCal);
159  }
160  }
161  }
162 
163  /* Do NF cal only at longer intervals */
164  if (longcal) {
165  /*
166  * Get the value from the previous NF cal and update
167  * history buffer.
168  */
169  ath9k_hw_getnf(ah, chan);
170 
171  /*
172  * Load the NF from history buffer of the current channel.
173  * NF is slow time-variant, so it is OK to use a historical
174  * value.
175  */
176  ath9k_hw_loadnf(ah, ah->curchan);
177 
178  /* start NF calibration, without updating BB NF register */
180  }
181 
182  return iscaldone;
183 }
184 
185 static void ar9003_hw_iqcal_collect(struct ath_hw *ah)
186 {
187  int i;
188 
189  /* Accumulate IQ cal measures for active chains */
190  for (i = 0; i < AR5416_MAX_CHAINS; i++) {
191  if (ah->txchainmask & BIT(i)) {
192  ah->totalPowerMeasI[i] +=
194  ah->totalPowerMeasQ[i] +=
196  ah->totalIqCorrMeas[i] +=
198  DBG2("ath9k: "
199  "%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n",
200  ah->cal_samples, i, ah->totalPowerMeasI[i],
201  ah->totalPowerMeasQ[i],
202  ah->totalIqCorrMeas[i]);
203  }
204  }
205 }
206 
207 static void ar9003_hw_iqcalibrate(struct ath_hw *ah, u8 numChains)
208 {
209  u32 powerMeasQ, powerMeasI, iqCorrMeas;
210  u32 qCoffDenom, iCoffDenom;
211  int32_t qCoff, iCoff;
212  int iqCorrNeg, i;
213  static const uint32_t offset_array[3] = {
217  };
218 
219  for (i = 0; i < numChains; i++) {
220  powerMeasI = ah->totalPowerMeasI[i];
221  powerMeasQ = ah->totalPowerMeasQ[i];
222  iqCorrMeas = ah->totalIqCorrMeas[i];
223 
224  DBG2("ath9k: "
225  "Starting IQ Cal and Correction for Chain %d\n",
226  i);
227 
228  DBG2("ath9k: "
229  "Orignal: Chn %diq_corr_meas = 0x%08x\n",
230  i, ah->totalIqCorrMeas[i]);
231 
232  iqCorrNeg = 0;
233 
234  if (iqCorrMeas > 0x80000000) {
235  iqCorrMeas = (0xffffffff - iqCorrMeas) + 1;
236  iqCorrNeg = 1;
237  }
238 
239  DBG2("ath9k: "
240  "Chn %d pwr_meas_i = 0x%08x\n", i, powerMeasI);
241  DBG2("ath9k: "
242  "Chn %d pwr_meas_q = 0x%08x\n", i, powerMeasQ);
243  DBG2("ath9k: iqCorrNeg is 0x%08x\n",
244  iqCorrNeg);
245 
246  iCoffDenom = (powerMeasI / 2 + powerMeasQ / 2) / 256;
247  qCoffDenom = powerMeasQ / 64;
248 
249  if ((iCoffDenom != 0) && (qCoffDenom != 0)) {
250  iCoff = iqCorrMeas / iCoffDenom;
251  qCoff = powerMeasI / qCoffDenom - 64;
252  DBG2("ath9k: "
253  "Chn %d iCoff = 0x%08x\n", i, iCoff);
254  DBG2("ath9k: "
255  "Chn %d qCoff = 0x%08x\n", i, qCoff);
256 
257  /* Force bounds on iCoff */
258  if (iCoff >= 63)
259  iCoff = 63;
260  else if (iCoff <= -63)
261  iCoff = -63;
262 
263  /* Negate iCoff if iqCorrNeg == 0 */
264  if (iqCorrNeg == 0x0)
265  iCoff = -iCoff;
266 
267  /* Force bounds on qCoff */
268  if (qCoff >= 63)
269  qCoff = 63;
270  else if (qCoff <= -63)
271  qCoff = -63;
272 
273  iCoff = iCoff & 0x7f;
274  qCoff = qCoff & 0x7f;
275 
276  DBG2("ath9k: "
277  "Chn %d : iCoff = 0x%x qCoff = 0x%x\n",
278  i, iCoff, qCoff);
279  DBG2("ath9k: "
280  "Register offset (0x%04x) before update = 0x%x\n",
281  offset_array[i],
282  REG_READ(ah, offset_array[i]));
283 
284  REG_RMW_FIELD(ah, offset_array[i],
286  iCoff);
287  REG_RMW_FIELD(ah, offset_array[i],
289  qCoff);
290  DBG2("ath9k: "
291  "Register offset (0x%04x) QI COFF (bitfields 0x%08x) after update = 0x%x\n",
292  offset_array[i],
294  REG_READ(ah, offset_array[i]));
295  DBG2("ath9k: "
296  "Register offset (0x%04x) QQ COFF (bitfields 0x%08x) after update = 0x%x\n",
297  offset_array[i],
299  REG_READ(ah, offset_array[i]));
300 
301  DBG2("ath9k: "
302  "IQ Cal and Correction done for Chain %d\n", i);
303  }
304  }
305 
308  DBG2("ath9k: "
309  "IQ Cal and Correction (offset 0x%04x) enabled (bit position 0x%08x). New Value 0x%08x\n",
310  (unsigned) (AR_PHY_RX_IQCAL_CORR_B0),
313 }
314 
321 };
322 
324 {
325  ah->iq_caldata.calData = &iq_cal_single_sample;
326 }
327 
328 /*
329  * solve 4x4 linear equation used in loopback iq cal.
330  */
332  s32 sin_2phi_1,
333  s32 cos_2phi_1,
334  s32 sin_2phi_2,
335  s32 cos_2phi_2,
336  s32 mag_a0_d0,
337  s32 phs_a0_d0,
338  s32 mag_a1_d0,
339  s32 phs_a1_d0,
340  s32 solved_eq[])
341 {
342  s32 f1 = cos_2phi_1 - cos_2phi_2,
343  f3 = sin_2phi_1 - sin_2phi_2,
344  f2;
345  s32 mag_tx, phs_tx, mag_rx, phs_rx;
346  const s32 result_shift = 1 << 15;
347 
348  f2 = (f1 * f1 + f3 * f3) / result_shift;
349 
350  if (!f2) {
351  DBG("ath9k: Divide by 0\n");
352  return 0;
353  }
354 
355  /* mag mismatch, tx */
356  mag_tx = f1 * (mag_a0_d0 - mag_a1_d0) + f3 * (phs_a0_d0 - phs_a1_d0);
357  /* phs mismatch, tx */
358  phs_tx = f3 * (-mag_a0_d0 + mag_a1_d0) + f1 * (phs_a0_d0 - phs_a1_d0);
359 
360  mag_tx = (mag_tx / f2);
361  phs_tx = (phs_tx / f2);
362 
363  /* mag mismatch, rx */
364  mag_rx = mag_a0_d0 - (cos_2phi_1 * mag_tx + sin_2phi_1 * phs_tx) /
365  result_shift;
366  /* phs mismatch, rx */
367  phs_rx = phs_a0_d0 + (sin_2phi_1 * mag_tx - cos_2phi_1 * phs_tx) /
368  result_shift;
369 
370  solved_eq[0] = mag_tx;
371  solved_eq[1] = phs_tx;
372  solved_eq[2] = mag_rx;
373  solved_eq[3] = phs_rx;
374 
375  return 1;
376 }
377 
378 static s32 ar9003_hw_find_mag_approx(struct ath_hw *ah __unused, s32 in_re, s32 in_im)
379 {
380  s32 abs_i = abs(in_re),
381  abs_q = abs(in_im),
382  max_abs, min_abs;
383 
384  if (abs_i > abs_q) {
385  max_abs = abs_i;
386  min_abs = abs_q;
387  } else {
388  max_abs = abs_q;
389  min_abs = abs_i;
390  }
391 
392  return max_abs - (max_abs / 32) + (min_abs / 8) + (min_abs / 4);
393 }
394 
395 #define DELPT 32
396 
397 static int ar9003_hw_calc_iq_corr(struct ath_hw *ah,
398  s32 chain_idx,
399  const s32 iq_res[],
400  s32 iqc_coeff[])
401 {
402  s32 i2_m_q2_a0_d0, i2_p_q2_a0_d0, iq_corr_a0_d0,
403  i2_m_q2_a0_d1, i2_p_q2_a0_d1, iq_corr_a0_d1,
404  i2_m_q2_a1_d0, i2_p_q2_a1_d0, iq_corr_a1_d0,
405  i2_m_q2_a1_d1, i2_p_q2_a1_d1, iq_corr_a1_d1;
406  s32 mag_a0_d0, mag_a1_d0, mag_a0_d1, mag_a1_d1,
407  phs_a0_d0, phs_a1_d0, phs_a0_d1, phs_a1_d1,
408  sin_2phi_1, cos_2phi_1,
409  sin_2phi_2, cos_2phi_2;
410  s32 mag_tx, phs_tx, mag_rx, phs_rx;
411  s32 solved_eq[4], mag_corr_tx, phs_corr_tx, mag_corr_rx, phs_corr_rx,
412  q_q_coff, q_i_coff;
413  const s32 res_scale = 1 << 15;
414  const s32 delpt_shift = 1 << 8;
415  s32 mag1, mag2;
416 
417  i2_m_q2_a0_d0 = iq_res[0] & 0xfff;
418  i2_p_q2_a0_d0 = (iq_res[0] >> 12) & 0xfff;
419  iq_corr_a0_d0 = ((iq_res[0] >> 24) & 0xff) + ((iq_res[1] & 0xf) << 8);
420 
421  if (i2_m_q2_a0_d0 > 0x800)
422  i2_m_q2_a0_d0 = -((0xfff - i2_m_q2_a0_d0) + 1);
423 
424  if (i2_p_q2_a0_d0 > 0x800)
425  i2_p_q2_a0_d0 = -((0xfff - i2_p_q2_a0_d0) + 1);
426 
427  if (iq_corr_a0_d0 > 0x800)
428  iq_corr_a0_d0 = -((0xfff - iq_corr_a0_d0) + 1);
429 
430  i2_m_q2_a0_d1 = (iq_res[1] >> 4) & 0xfff;
431  i2_p_q2_a0_d1 = (iq_res[2] & 0xfff);
432  iq_corr_a0_d1 = (iq_res[2] >> 12) & 0xfff;
433 
434  if (i2_m_q2_a0_d1 > 0x800)
435  i2_m_q2_a0_d1 = -((0xfff - i2_m_q2_a0_d1) + 1);
436 
437  if (i2_p_q2_a0_d1 > 0x800)
438  i2_p_q2_a0_d1 = -((0xfff - i2_p_q2_a0_d1) + 1);
439 
440  if (iq_corr_a0_d1 > 0x800)
441  iq_corr_a0_d1 = -((0xfff - iq_corr_a0_d1) + 1);
442 
443  i2_m_q2_a1_d0 = ((iq_res[2] >> 24) & 0xff) + ((iq_res[3] & 0xf) << 8);
444  i2_p_q2_a1_d0 = (iq_res[3] >> 4) & 0xfff;
445  iq_corr_a1_d0 = iq_res[4] & 0xfff;
446 
447  if (i2_m_q2_a1_d0 > 0x800)
448  i2_m_q2_a1_d0 = -((0xfff - i2_m_q2_a1_d0) + 1);
449 
450  if (i2_p_q2_a1_d0 > 0x800)
451  i2_p_q2_a1_d0 = -((0xfff - i2_p_q2_a1_d0) + 1);
452 
453  if (iq_corr_a1_d0 > 0x800)
454  iq_corr_a1_d0 = -((0xfff - iq_corr_a1_d0) + 1);
455 
456  i2_m_q2_a1_d1 = (iq_res[4] >> 12) & 0xfff;
457  i2_p_q2_a1_d1 = ((iq_res[4] >> 24) & 0xff) + ((iq_res[5] & 0xf) << 8);
458  iq_corr_a1_d1 = (iq_res[5] >> 4) & 0xfff;
459 
460  if (i2_m_q2_a1_d1 > 0x800)
461  i2_m_q2_a1_d1 = -((0xfff - i2_m_q2_a1_d1) + 1);
462 
463  if (i2_p_q2_a1_d1 > 0x800)
464  i2_p_q2_a1_d1 = -((0xfff - i2_p_q2_a1_d1) + 1);
465 
466  if (iq_corr_a1_d1 > 0x800)
467  iq_corr_a1_d1 = -((0xfff - iq_corr_a1_d1) + 1);
468 
469  if ((i2_p_q2_a0_d0 == 0) || (i2_p_q2_a0_d1 == 0) ||
470  (i2_p_q2_a1_d0 == 0) || (i2_p_q2_a1_d1 == 0)) {
471  DBG("ath9k: "
472  "Divide by 0:\n"
473  "a0_d0=%d\n"
474  "a0_d1=%d\n"
475  "a2_d0=%d\n"
476  "a1_d1=%d\n",
477  i2_p_q2_a0_d0, i2_p_q2_a0_d1,
478  i2_p_q2_a1_d0, i2_p_q2_a1_d1);
479  return 0;
480  }
481 
482  mag_a0_d0 = (i2_m_q2_a0_d0 * res_scale) / i2_p_q2_a0_d0;
483  phs_a0_d0 = (iq_corr_a0_d0 * res_scale) / i2_p_q2_a0_d0;
484 
485  mag_a0_d1 = (i2_m_q2_a0_d1 * res_scale) / i2_p_q2_a0_d1;
486  phs_a0_d1 = (iq_corr_a0_d1 * res_scale) / i2_p_q2_a0_d1;
487 
488  mag_a1_d0 = (i2_m_q2_a1_d0 * res_scale) / i2_p_q2_a1_d0;
489  phs_a1_d0 = (iq_corr_a1_d0 * res_scale) / i2_p_q2_a1_d0;
490 
491  mag_a1_d1 = (i2_m_q2_a1_d1 * res_scale) / i2_p_q2_a1_d1;
492  phs_a1_d1 = (iq_corr_a1_d1 * res_scale) / i2_p_q2_a1_d1;
493 
494  /* w/o analog phase shift */
495  sin_2phi_1 = (((mag_a0_d0 - mag_a0_d1) * delpt_shift) / DELPT);
496  /* w/o analog phase shift */
497  cos_2phi_1 = (((phs_a0_d1 - phs_a0_d0) * delpt_shift) / DELPT);
498  /* w/ analog phase shift */
499  sin_2phi_2 = (((mag_a1_d0 - mag_a1_d1) * delpt_shift) / DELPT);
500  /* w/ analog phase shift */
501  cos_2phi_2 = (((phs_a1_d1 - phs_a1_d0) * delpt_shift) / DELPT);
502 
503  /*
504  * force sin^2 + cos^2 = 1;
505  * find magnitude by approximation
506  */
507  mag1 = ar9003_hw_find_mag_approx(ah, cos_2phi_1, sin_2phi_1);
508  mag2 = ar9003_hw_find_mag_approx(ah, cos_2phi_2, sin_2phi_2);
509 
510  if ((mag1 == 0) || (mag2 == 0)) {
511  DBG("ath9k: "
512  "Divide by 0: mag1=%d, mag2=%d\n",
513  mag1, mag2);
514  return 0;
515  }
516 
517  /* normalization sin and cos by mag */
518  sin_2phi_1 = (sin_2phi_1 * res_scale / mag1);
519  cos_2phi_1 = (cos_2phi_1 * res_scale / mag1);
520  sin_2phi_2 = (sin_2phi_2 * res_scale / mag2);
521  cos_2phi_2 = (cos_2phi_2 * res_scale / mag2);
522 
523  /* calculate IQ mismatch */
525  sin_2phi_1, cos_2phi_1,
526  sin_2phi_2, cos_2phi_2,
527  mag_a0_d0, phs_a0_d0,
528  mag_a1_d0,
529  phs_a1_d0, solved_eq)) {
530  DBG("ath9k: "
531  "Call to ar9003_hw_solve_iq_cal() failed.\n");
532  return 0;
533  }
534 
535  mag_tx = solved_eq[0];
536  phs_tx = solved_eq[1];
537  mag_rx = solved_eq[2];
538  phs_rx = solved_eq[3];
539 
540  DBG2("ath9k: "
541  "chain %d: mag mismatch=%d phase mismatch=%d\n",
542  chain_idx, mag_tx/res_scale, phs_tx/res_scale);
543 
544  if (res_scale == mag_tx) {
545  DBG("ath9k: "
546  "Divide by 0: mag_tx=%d, res_scale=%d\n",
547  mag_tx, res_scale);
548  return 0;
549  }
550 
551  /* calculate and quantize Tx IQ correction factor */
552  mag_corr_tx = (mag_tx * res_scale) / (res_scale - mag_tx);
553  phs_corr_tx = -phs_tx;
554 
555  q_q_coff = (mag_corr_tx * 128 / res_scale);
556  q_i_coff = (phs_corr_tx * 256 / res_scale);
557 
558  DBG2("ath9k: "
559  "tx chain %d: mag corr=%d phase corr=%d\n",
560  chain_idx, q_q_coff, q_i_coff);
561 
562  if (q_i_coff < -63)
563  q_i_coff = -63;
564  if (q_i_coff > 63)
565  q_i_coff = 63;
566  if (q_q_coff < -63)
567  q_q_coff = -63;
568  if (q_q_coff > 63)
569  q_q_coff = 63;
570 
571  iqc_coeff[0] = (q_q_coff * 128) + q_i_coff;
572 
573  DBG2("ath9k: "
574  "tx chain %d: iq corr coeff=%x\n",
575  chain_idx, iqc_coeff[0]);
576 
577  if (-mag_rx == res_scale) {
578  DBG("ath9k: "
579  "Divide by 0: mag_rx=%d, res_scale=%d\n",
580  mag_rx, res_scale);
581  return 0;
582  }
583 
584  /* calculate and quantize Rx IQ correction factors */
585  mag_corr_rx = (-mag_rx * res_scale) / (res_scale + mag_rx);
586  phs_corr_rx = -phs_rx;
587 
588  q_q_coff = (mag_corr_rx * 128 / res_scale);
589  q_i_coff = (phs_corr_rx * 256 / res_scale);
590 
591  DBG("ath9k: "
592  "rx chain %d: mag corr=%d phase corr=%d\n",
593  chain_idx, q_q_coff, q_i_coff);
594 
595  if (q_i_coff < -63)
596  q_i_coff = -63;
597  if (q_i_coff > 63)
598  q_i_coff = 63;
599  if (q_q_coff < -63)
600  q_q_coff = -63;
601  if (q_q_coff > 63)
602  q_q_coff = 63;
603 
604  iqc_coeff[1] = (q_q_coff * 128) + q_i_coff;
605 
606  DBG2("ath9k: "
607  "rx chain %d: iq corr coeff=%x\n",
608  chain_idx, iqc_coeff[1]);
609 
610  return 1;
611 }
612 
613 static void ar9003_hw_detect_outlier(int *mp_coeff, int nmeasurement,
614  int max_delta)
615 {
616  int mp_max = -64, max_idx = 0;
617  int mp_min = 63, min_idx = 0;
618  int mp_avg = 0, i, outlier_idx = 0;
619 
620  /* find min/max mismatch across all calibrated gains */
621  for (i = 0; i < nmeasurement; i++) {
622  mp_avg += mp_coeff[i];
623  if (mp_coeff[i] > mp_max) {
624  mp_max = mp_coeff[i];
625  max_idx = i;
626  } else if (mp_coeff[i] < mp_min) {
627  mp_min = mp_coeff[i];
628  min_idx = i;
629  }
630  }
631 
632  /* find average (exclude max abs value) */
633  for (i = 0; i < nmeasurement; i++) {
634  if ((abs(mp_coeff[i]) < abs(mp_max)) ||
635  (abs(mp_coeff[i]) < abs(mp_min)))
636  mp_avg += mp_coeff[i];
637  }
638  mp_avg /= (nmeasurement - 1);
639 
640  /* detect outlier */
641  if (abs(mp_max - mp_min) > max_delta) {
642  if (abs(mp_max - mp_avg) > abs(mp_min - mp_avg))
643  outlier_idx = max_idx;
644  else
645  outlier_idx = min_idx;
646  }
647  mp_coeff[outlier_idx] = mp_avg;
648 }
649 
651  u8 num_chains,
652  struct coeff *coeff)
653 {
654  int i, im, nmeasurement;
655  u32 tx_corr_coeff[MAX_MEASUREMENT][AR9300_MAX_CHAINS];
656 
657  memset(tx_corr_coeff, 0, sizeof(tx_corr_coeff));
658  for (i = 0; i < MAX_MEASUREMENT / 2; i++) {
659  tx_corr_coeff[i * 2][0] = tx_corr_coeff[(i * 2) + 1][0] =
661  if (!AR_SREV_9485(ah)) {
662  tx_corr_coeff[i * 2][1] =
663  tx_corr_coeff[(i * 2) + 1][1] =
665 
666  tx_corr_coeff[i * 2][2] =
667  tx_corr_coeff[(i * 2) + 1][2] =
669  }
670  }
671 
672  /* Load the average of 2 passes */
673  for (i = 0; i < num_chains; i++) {
674  nmeasurement = REG_READ_FIELD(ah,
677 
678  if (nmeasurement > MAX_MEASUREMENT)
679  nmeasurement = MAX_MEASUREMENT;
680 
681  /* detect outlier only if nmeasurement > 1 */
682  if (nmeasurement > 1) {
683  /* Detect magnitude outlier */
685  nmeasurement, MAX_MAG_DELTA);
686 
687  /* Detect phase outlier */
689  nmeasurement, MAX_PHS_DELTA);
690  }
691 
692  for (im = 0; im < nmeasurement; im++) {
693 
694  coeff->iqc_coeff[0] = (coeff->mag_coeff[i][im] & 0x7f) |
695  ((coeff->phs_coeff[i][im] & 0x7f) << 7);
696 
697  if ((im % 2) == 0)
698  REG_RMW_FIELD(ah, tx_corr_coeff[im][i],
700  coeff->iqc_coeff[0]);
701  else
702  REG_RMW_FIELD(ah, tx_corr_coeff[im][i],
704  coeff->iqc_coeff[0]);
705  }
706  }
707 
712 
713  return;
714 
715 }
716 
717 static int ar9003_hw_tx_iq_cal_run(struct ath_hw *ah)
718 {
719  u8 tx_gain_forced;
720 
721  tx_gain_forced = REG_READ_FIELD(ah, AR_PHY_TX_FORCED_GAIN,
723  if (tx_gain_forced)
726 
729 
732  AH_WAIT_TIMEOUT)) {
733  DBG2("ath9k: "
734  "Tx IQ Cal is not completed.\n");
735  return 0;
736  }
737  return 1;
738 }
739 
741 {
742  const u32 txiqcal_status[AR9300_MAX_CHAINS] = {
746  };
747  const uint32_t chan_info_tab[] = {
751  };
752  struct coeff coeff;
753  s32 iq_res[6];
754  u8 num_chains = 0;
755  int i, im, j;
756  int nmeasurement;
757 
758  for (i = 0; i < AR9300_MAX_CHAINS; i++) {
759  if (ah->txchainmask & (1 << i))
760  num_chains++;
761  }
762 
763  for (i = 0; i < num_chains; i++) {
764  nmeasurement = REG_READ_FIELD(ah,
767  if (nmeasurement > MAX_MEASUREMENT)
768  nmeasurement = MAX_MEASUREMENT;
769 
770  for (im = 0; im < nmeasurement; im++) {
771  DBG2("ath9k: "
772  "Doing Tx IQ Cal for chain %d.\n", i);
773 
774  if (REG_READ(ah, txiqcal_status[i]) &
776  DBG("ath9k: "
777  "Tx IQ Cal failed for chain %d.\n", i);
778  goto tx_iqcal_fail;
779  }
780 
781  for (j = 0; j < 3; j++) {
782  u32 idx = 2 * j, offset = 4 * (3 * im + j);
783 
787  0);
788 
789  /* 32 bits */
790  iq_res[idx] = REG_READ(ah,
791  chan_info_tab[i] +
792  offset);
793 
797  1);
798 
799  /* 16 bits */
800  iq_res[idx + 1] = 0xffff & REG_READ(ah,
801  chan_info_tab[i] + offset);
802 
803  DBG2("ath9k: "
804  "IQ RES[%d]=0x%x"
805  "IQ_RES[%d]=0x%x\n",
806  idx, iq_res[idx], idx + 1,
807  iq_res[idx + 1]);
808  }
809 
810  if (!ar9003_hw_calc_iq_corr(ah, i, iq_res,
811  coeff.iqc_coeff)) {
812  DBG("ath9k: "
813  "Failed in calculation of \
814  IQ correction.\n");
815  goto tx_iqcal_fail;
816  }
817 
818  coeff.mag_coeff[i][im] = coeff.iqc_coeff[0] & 0x7f;
819  coeff.phs_coeff[i][im] =
820  (coeff.iqc_coeff[0] >> 7) & 0x7f;
821 
822  if (coeff.mag_coeff[i][im] > 63)
823  coeff.mag_coeff[i][im] -= 128;
824  if (coeff.phs_coeff[i][im] > 63)
825  coeff.phs_coeff[i][im] -= 128;
826  }
827  }
829 
830  return;
831 
832 tx_iqcal_fail:
833  DBG("ath9k: Tx IQ Cal failed\n");
834  return;
835 }
836 static int ar9003_hw_init_cal(struct ath_hw *ah,
837  struct ath9k_channel *chan __unused)
838 {
839  struct ath9k_hw_capabilities *pCap = &ah->caps;
840  int val;
841  int txiqcal_done = 0;
842 
844  DBG2("ath9k: ath9k: AR_ENT_OTP 0x%x\n", val);
845 
846  /* Configure rx/tx chains before running AGC/TxiQ cals */
848  ar9003_hw_set_chain_masks(ah, 0x3, 0x3);
849  else
851  pCap->tx_chainmask);
852 
853  /* Do Tx IQ Calibration */
856  DELPT);
857 
858  /*
859  * For AR9485 or later chips, TxIQ cal runs as part of
860  * AGC calibration
861  */
863  txiqcal_done = 1;
864  else {
865  txiqcal_done = ar9003_hw_tx_iq_cal_run(ah);
867  udelay(5);
869  }
870 
871  /* Calibrate the AGC */
875 
876  /* Poll for offset calibration complete */
878  0, AH_WAIT_TIMEOUT)) {
879  DBG("ath9k: "
880  "offset calibration failed to complete in 1ms; noisy environment?\n");
881  return 0;
882  }
883 
884  if (txiqcal_done)
886 
887  /* Revert chainmasks to their original values before NF cal */
888  ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask);
889 
891 
892  /* Initialize list pointers */
893  ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL;
894  ah->supp_cals = IQ_MISMATCH_CAL;
895 
896  if (ah->supp_cals & IQ_MISMATCH_CAL) {
897  INIT_CAL(&ah->iq_caldata);
898  INSERT_CAL(ah, &ah->iq_caldata);
899  DBG2("ath9k: "
900  "enabling IQ Calibration.\n");
901  }
902 
903  if (ah->supp_cals & TEMP_COMP_CAL) {
904  INIT_CAL(&ah->tempCompCalData);
905  INSERT_CAL(ah, &ah->tempCompCalData);
906  DBG2("ath9k: "
907  "enabling Temperature Compensation Calibration.\n");
908  }
909 
910  /* Initialize current pointer to first element in list */
911  ah->cal_list_curr = ah->cal_list;
912 
913  if (ah->cal_list_curr)
914  ath9k_hw_reset_calibration(ah, ah->cal_list_curr);
915 
916  if (ah->caldata)
917  ah->caldata->CalValid = 0;
918 
919  return 1;
920 }
921 
923 {
924  struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
925  struct ath_hw_ops *ops = ath9k_hw_ops(ah);
926 
928  priv_ops->init_cal = ar9003_hw_init_cal;
930 
932 }
#define AR9300_MAX_CHAINS
Definition: ar9003_eeprom.h:49
int mag_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT]
#define DELPT
iPXE I/O API
Definition: hw.h:656
static int ar9003_hw_per_calibration(struct ath_hw *ah, struct ath9k_channel *ichan __unused, u8 rxchainmask, struct ath9k_cal_list *currCal)
static void ar9003_hw_setup_calibration(struct ath_hw *ah, struct ath9k_cal_list *currCal)
#define AR_PHY_CHAN_INFO_TAB_S2_READ
Definition: ar9003_phy.h:199
int32_t s32
Definition: stdint.h:22
static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah)
#define AR_PHY_RX_IQCAL_CORR_B1
Definition: ar9003_phy.h:808
void(* calPostProc)(struct ath_hw *, u8)
Definition: calib.h:84
void ath9k_hw_start_nfcal(struct ath_hw *ah, int update)
Definition: ath9k_calib.c:206
static void ar9003_hw_iqcal_collect(struct ath_hw *ah)
static int ar9003_hw_tx_iq_cal_run(struct ath_hw *ah)
static void ar9003_hw_iqcalibrate(struct ath_hw *ah, u8 numChains)
void(* init_cal_settings)(struct ath_hw *ah)
Definition: hw.h:552
#define AR_PHY_ACTIVE_EN
Definition: ar9002_phy.h:53
#define AR_PHY_RX_IQCAL_CORR_B0_LOOPBACK_IQCORR_EN
Definition: ar9003_phy.h:60
#define AR_PHY_TX_IQCAL_CONTROL_1
Definition: ar9003_phy.h:573
void ar9003_hw_set_chain_masks(struct ath_hw *ah, u8 rx, u8 tx)
int32_t CalValid
Definition: hw.h:335
#define MAX_MEASUREMENT
struct ath9k_cal_list * calNext
Definition: calib.h:90
#define AR_SREV_9485(_ah)
Definition: reg.h:867
#define AR_PHY_CALMODE
Definition: ar9002_phy.h:373
#define AR_PHY_TX_IQCAL_CONTROL_1_IQCORR_I_Q_COFF_DELPT
Definition: ar9003_phy.h:780
struct ath_hw_private_ops - callbacks used internally by hardware code
Definition: hw.h:550
#define AR_PHY_TX_FORCED_GAIN
Definition: ar9003_phy.h:548
#define AR_PHY_ACTIVE
Definition: ar9002_phy.h:52
#define AR_PHY_RX_IQCAL_CORR_B2
Definition: ar9003_phy.h:864
void(* setup_calibration)(struct ath_hw *ah, struct ath9k_cal_list *currCal)
Definition: hw.h:557
#define AR_PHY_RX_IQCAL_CORR_IQCORR_Q_I_COFF
Definition: ar9003_phy.h:203
static int ar9003_hw_solve_iq_cal(struct ath_hw *ah __unused, s32 sin_2phi_1, s32 cos_2phi_1, s32 sin_2phi_2, s32 cos_2phi_2, s32 mag_a0_d0, s32 phs_a0_d0, s32 mag_a1_d0, s32 phs_a1_d0, s32 solved_eq[])
#define MAX_PHS_DELTA
#define MAX_MAG_DELTA
#define AR_ENT_OTP
Definition: reg.h:1107
#define AR_PHY_TX_IQCAL_CORR_COEFF_01_COEFF_TABLE
Definition: ar9003_phy.h:791
#define AR_PHY_AGC_CONTROL_CAL
Definition: reg.h:1910
#define REG_RMW_FIELD(_a, _r, _f, _v)
Definition: hw.h:103
#define AR_PHY_ACTIVE_DIS
Definition: ar9002_phy.h:54
#define AR_PHY_65NM_CH0_THERM_START
Definition: ar9003_phy.h:614
#define abs(x)
Definition: ath.h:44
u32 calNumSamples
Definition: calib.h:81
Definition: calib.h:70
int phs_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT]
#define AR_PHY_TX_IQCAL_CORR_COEFF_B0(_i)
Definition: ar9003_phy.h:579
static void ar9003_hw_init_cal_settings(struct ath_hw *ah)
#define AR_PHY_CHAN_INFO_TAB_0
Definition: ar9003_phy.h:97
#define AR_PHY_TX_IQCAL_STATUS_B2
Definition: ar9003_phy.h:903
#define AR_PHY_CHAN_INFO_TAB_2
Definition: ar9003_phy.h:863
#define AR_PHY_CHAN_INFO_TAB_1
Definition: ar9003_phy.h:807
#define AR_PHY_TXGAIN_FORCE
Definition: ar9003_phy.h:742
#define INIT_CAL(_perCal)
Definition: calib.h:48
#define MIN_CAL_SAMPLES
Definition: calib.h:73
#define AR_PHY_TX_IQCAL_CORR_COEFF_B1(_i)
Definition: ar9003_phy.h:851
#define AR_PHY_TX_IQCAL_CONTROL_3
Definition: ar9003_phy.h:34
#define AR_PHY_65NM_CH0_THERM_LOCAL
Definition: ar9003_phy.h:612
void udelay(unsigned long usecs)
Delay for a fixed number of microseconds.
Definition: timer.c:60
void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
Definition: ath9k_calib.c:224
#define AR_PHY_AGC_CONTROL
Definition: reg.h:1909
static userptr_t size_t offset
Offset of the first segment within the content.
Definition: deflate.h:259
#define AR_PHY_TX_IQCAL_START_DO_CAL
Definition: ar9003_phy.h:782
void(* calCollect)(struct ath_hw *)
Definition: calib.h:83
#define AR_PHY_TIMING4_IQCAL_LOG_COUNT_MAX
Definition: ar9003_phy.h:108
static void ar9003_hw_detect_outlier(int *mp_coeff, int nmeasurement, int max_delta)
#define AR_PHY_TX_IQCAL_START
Definition: ar9003_phy.h:575
#define AR_PHY_65NM_CH0_THERM
Definition: ar9003_phy.h:610
#define AR_PHY_CAL_MEAS_2(_i)
Definition: ar9002_phy.h:382
#define AR_PHY_TX_IQCAL_CORR_COEFF_00_COEFF_TABLE
Definition: ar9003_phy.h:789
struct ath_hw_ops - callbacks used by hardware code and driver code
Definition: hw.h:603
int(* calibrate)(struct ath_hw *ah, struct ath9k_channel *chan, u8 rxchainmask, int longcal)
Definition: hw.h:610
#define INSERT_CAL(_ahp, _perCal)
Definition: calib.h:53
#define AR_PHY_TIMING4_DO_CAL
Definition: ar9003_phy.h:110
#define AR_PHY_TX_IQCAL_CONTROL_3_IQCORR_EN
Definition: ar9003_phy.h:63
const struct ath9k_percal_data * calData
Definition: calib.h:88
void ar9003_hw_attach_calib_ops(struct ath_hw *ah)
#define PER_MAX_LOG_COUNT
Definition: calib.h:77
#define AR_PHY_TX_IQCAL_STATUS_B0
Definition: ar9003_phy.h:577
unsigned int uint32_t
Definition: stdint.h:12
static int ar9003_hw_calc_iq_corr(struct ath_hw *ah, s32 chain_idx, const s32 iq_res[], s32 iqc_coeff[])
#define REG_READ(_ah, _reg)
Definition: hw.h:80
void __asmcall int val
Definition: setjmp.h:28
#define AR5416_MAX_CHAINS
Definition: eeprom.h:159
#define REG_SET_BIT(_a, _r, _f)
Definition: hw.h:107
#define __unused
Declare a variable or data structure as unused.
Definition: compiler.h:573
static struct ath_hw_ops * ath9k_hw_ops(struct ath_hw *ah)
Definition: hw.h:884
#define BIT(nr)
Definition: ath.h:32
signed int int32_t
Definition: stdint.h:17
u32 calCountMax
Definition: calib.h:82
ar9003_cal_types
#define AR_PHY_RX_IQCAL_CORR_IQCORR_Q_Q_COFF
Definition: ar9003_phy.h:201
int ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val, u32 timeout)
Definition: ath9k_hw.c:93
#define REG_WRITE(_ah, _reg, _val)
Definition: hw.h:77
static int ar9003_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan, u8 rxchainmask, int longcal)
#define AR_PHY_CHAN_INFO_MEMORY
Definition: ar9002_phy.h:361
static const struct ath9k_percal_data iq_cal_single_sample
#define AH_WAIT_TIMEOUT
Definition: hw.h:145
#define REG_READ_FIELD(_a, _r, _f)
Definition: hw.h:105
#define AR_PHY_CALIBRATED_GAINS_0
Definition: ar9003_phy.h:786
#define AR_PHY_CAL_MEAS_1(_i)
Definition: ar9002_phy.h:381
int ath9k_hw_getnf(struct ath_hw *ah, struct ath9k_channel *chan)
Definition: ath9k_calib.c:346
uint8_t ah
Definition: registers.h:85
#define AR_PHY_TX_IQCAL_STATUS_FAILED
Definition: ar9003_phy.h:785
static struct ath_hw_private_ops * ath9k_hw_private_ops(struct ath_hw *ah)
Definition: hw.h:879
#define AR_PHY_RX_IQCAL_CORR_B0
Definition: ar9003_phy.h:33
#define DBG(...)
Print a debugging message.
Definition: compiler.h:498
#define AR_PHY_TIMING4
Definition: ar9003_phy.h:28
#define AR_PHY_TX_IQCAL_CORR_COEFF_B2(_i)
Definition: ar9003_phy.h:904
void ath9k_hw_reset_calibration(struct ath_hw *ah, struct ath9k_cal_list *currCal)
Definition: ath9k_calib.c:153
#define NULL
NULL pointer (VOID *)
Definition: Base.h:321
#define AR_PHY_RX_IQCAL_CORR_IQCORR_ENABLE
Definition: ar9003_phy.h:205
#define AR_PHY_CAL_MEAS_0(_i)
Definition: ar9002_phy.h:380
static int ar9003_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan __unused)
static void ar9003_hw_tx_iqcal_load_avg_2_passes(struct ath_hw *ah, u8 num_chains, struct coeff *coeff)
#define AR_PHY_TX_IQCAL_STATUS_B1
Definition: ar9003_phy.h:850
enum ath9k_cal_state calState
Definition: calib.h:89
uint8_t u8
Definition: stdint.h:19
uint32_t u32
Definition: stdint.h:23
int(* init_cal)(struct ath_hw *ah, struct ath9k_channel *chan)
Definition: hw.h:553
#define AR_ENT_OTP_CHAIN2_DISABLE
Definition: reg.h:1108
#define DBG2(...)
Definition: compiler.h:515
int iqc_coeff[2]
#define AR_PHY_CALMODE_IQ
Definition: ar9002_phy.h:375
void * memset(void *dest, int character, size_t len) __nonnull
static s32 ar9003_hw_find_mag_approx(struct ath_hw *ah __unused, s32 in_re, s32 in_im)
#define AR_SREV_9485_OR_LATER(_ah)
Definition: reg.h:875