Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 225115
b: refs/heads/master
c: 858b7e3
h: refs/heads/master
i:
  225113: 2f7c929
  225111: 2c596a2
v: v3
  • Loading branch information
Vasanthakumar Thiagarajan authored and John W. Linville committed Dec 7, 2010
1 parent 9e57ff6 commit b1faca7
Show file tree
Hide file tree
Showing 3 changed files with 256 additions and 4 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 31faff815bd9d87c370f799dff03948ed362d260
refs/heads/master: 858b7e36e82cc03cb77b64f096b64446a24a346a
242 changes: 241 additions & 1 deletion trunk/drivers/net/wireless/ath/ath9k/ar9003_calib.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,16 @@
#include "hw-ops.h"
#include "ar9003_phy.h"

#define MPASS 3
#define MAX_MEASUREMENT 8
#define MAX_DIFFERENCE 10

struct coeff {
int mag_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT][MPASS];
int phs_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT][MPASS];
int iqc_coeff[2];
};

enum ar9003_cal_types {
IQ_MISMATCH_CAL = BIT(0),
TEMP_COMP_CAL = BIT(1),
Expand Down Expand Up @@ -712,6 +722,229 @@ static void ar9003_hw_tx_iq_cal(struct ath_hw *ah)
ath_dbg(common, ATH_DBG_CALIBRATE, "Tx IQ Cal failed\n");
}

static bool ar9003_hw_compute_closest_pass_and_avg(int *mp_coeff, int *mp_avg)
{
int diff[MPASS];

diff[0] = abs(mp_coeff[0] - mp_coeff[1]);
diff[1] = abs(mp_coeff[1] - mp_coeff[2]);
diff[2] = abs(mp_coeff[2] - mp_coeff[0]);

if (diff[0] > MAX_MEASUREMENT &&
diff[1] > MAX_MEASUREMENT &&
diff[2] > MAX_MEASUREMENT)
return false;

if (diff[0] <= diff[1] && diff[0] <= diff[2])
*mp_avg = (mp_coeff[0] + mp_coeff[1]) / 2;
else if (diff[1] <= diff[2])
*mp_avg = (mp_coeff[1] + mp_coeff[2]) / 2;
else
*mp_avg = (mp_coeff[2] + mp_coeff[0]) / 2;

return true;
}

static void ar9003_hw_tx_iqcal_load_avg_2_passes(struct ath_hw *ah,
u8 num_chains,
struct coeff *coeff)
{
struct ath_common *common = ath9k_hw_common(ah);
int i, im, nmeasurement;
int magnitude, phase;
u32 tx_corr_coeff[MAX_MEASUREMENT][AR9300_MAX_CHAINS];

memset(tx_corr_coeff, 0, sizeof(tx_corr_coeff));
for (i = 0; i < MAX_MEASUREMENT / 2; i++) {
tx_corr_coeff[i * 2][0] = tx_corr_coeff[(i * 2) + 1][0] =
AR_PHY_TX_IQCAL_CORR_COEFF_B0(i);
if (!AR_SREV_9485(ah)) {
tx_corr_coeff[i * 2][1] =
tx_corr_coeff[(i * 2) + 1][1] =
AR_PHY_TX_IQCAL_CORR_COEFF_B1(i);

tx_corr_coeff[i * 2][2] =
tx_corr_coeff[(i * 2) + 1][2] =
AR_PHY_TX_IQCAL_CORR_COEFF_B2(i);
}
}

/* Load the average of 2 passes */
for (i = 0; i < num_chains; i++) {
if (AR_SREV_9485(ah))
nmeasurement = REG_READ_FIELD(ah,
AR_PHY_TX_IQCAL_STATUS_B0_9485,
AR_PHY_CALIBRATED_GAINS_0);
else
nmeasurement = REG_READ_FIELD(ah,
AR_PHY_TX_IQCAL_STATUS_B0,
AR_PHY_CALIBRATED_GAINS_0);

if (nmeasurement > MAX_MEASUREMENT)
nmeasurement = MAX_MEASUREMENT;

for (im = 0; im < nmeasurement; im++) {
/*
* Determine which 2 passes are closest and compute avg
* magnitude
*/
if (!ar9003_hw_compute_closest_pass_and_avg(coeff->mag_coeff[i][im],
&magnitude))
goto disable_txiqcal;

/*
* Determine which 2 passes are closest and compute avg
* phase
*/
if (!ar9003_hw_compute_closest_pass_and_avg(coeff->phs_coeff[i][im],
&phase))
goto disable_txiqcal;

coeff->iqc_coeff[0] = (magnitude & 0x7f) |
((phase & 0x7f) << 7);

if ((im % 2) == 0)
REG_RMW_FIELD(ah, tx_corr_coeff[im][i],
AR_PHY_TX_IQCAL_CORR_COEFF_00_COEFF_TABLE,
coeff->iqc_coeff[0]);
else
REG_RMW_FIELD(ah, tx_corr_coeff[im][i],
AR_PHY_TX_IQCAL_CORR_COEFF_01_COEFF_TABLE,
coeff->iqc_coeff[0]);
}
}

REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_3,
AR_PHY_TX_IQCAL_CONTROL_3_IQCORR_EN, 0x1);
REG_RMW_FIELD(ah, AR_PHY_RX_IQCAL_CORR_B0,
AR_PHY_RX_IQCAL_CORR_B0_LOOPBACK_IQCORR_EN, 0x1);

return;

disable_txiqcal:
REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_3,
AR_PHY_TX_IQCAL_CONTROL_3_IQCORR_EN, 0x0);
REG_RMW_FIELD(ah, AR_PHY_RX_IQCAL_CORR_B0,
AR_PHY_RX_IQCAL_CORR_B0_LOOPBACK_IQCORR_EN, 0x0);

ath_dbg(common, ATH_DBG_CALIBRATE, "TX IQ Cal disabled\n");
}

static void ar9003_hw_tx_iq_cal_run(struct ath_hw *ah)
{
u8 tx_gain_forced;

REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_1_9485,
AR_PHY_TX_IQCAQL_CONTROL_1_IQCORR_I_Q_COFF_DELPT, DELPT);
tx_gain_forced = REG_READ_FIELD(ah, AR_PHY_TX_FORCED_GAIN,
AR_PHY_TXGAIN_FORCE);
if (tx_gain_forced)
REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN,
AR_PHY_TXGAIN_FORCE, 0);

REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_START_9485,
AR_PHY_TX_IQCAL_START_DO_CAL_9485, 1);
}

static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah)
{
struct ath_common *common = ath9k_hw_common(ah);
const u32 txiqcal_status[AR9300_MAX_CHAINS] = {
AR_PHY_TX_IQCAL_STATUS_B0_9485,
AR_PHY_TX_IQCAL_STATUS_B1,
AR_PHY_TX_IQCAL_STATUS_B2,
};
const u_int32_t chan_info_tab[] = {
AR_PHY_CHAN_INFO_TAB_0,
AR_PHY_CHAN_INFO_TAB_1,
AR_PHY_CHAN_INFO_TAB_2,
};
struct coeff coeff;
s32 iq_res[6];
u8 num_chains = 0;
int i, ip, im, j;
int nmeasurement;

for (i = 0; i < AR9300_MAX_CHAINS; i++) {
if (ah->txchainmask & (1 << i))
num_chains++;
}

for (ip = 0; ip < MPASS; ip++) {
for (i = 0; i < num_chains; i++) {
nmeasurement = REG_READ_FIELD(ah,
AR_PHY_TX_IQCAL_STATUS_B0_9485,
AR_PHY_CALIBRATED_GAINS_0);
if (nmeasurement > MAX_MEASUREMENT)
nmeasurement = MAX_MEASUREMENT;

for (im = 0; im < nmeasurement; im++) {
ath_dbg(common, ATH_DBG_CALIBRATE,
"Doing Tx IQ Cal for chain %d.\n", i);

if (REG_READ(ah, txiqcal_status[i]) &
AR_PHY_TX_IQCAL_STATUS_FAILED) {
ath_dbg(common, ATH_DBG_CALIBRATE,
"Tx IQ Cal failed for chain %d.\n", i);
goto tx_iqcal_fail;
}

for (j = 0; j < 3; j++) {
u32 idx = 2 * j, offset = 4 * (3 * im + j);

REG_RMW_FIELD(ah,
AR_PHY_CHAN_INFO_MEMORY,
AR_PHY_CHAN_INFO_TAB_S2_READ,
0);

/* 32 bits */
iq_res[idx] = REG_READ(ah,
chan_info_tab[i] +
offset);

REG_RMW_FIELD(ah,
AR_PHY_CHAN_INFO_MEMORY,
AR_PHY_CHAN_INFO_TAB_S2_READ,
1);

/* 16 bits */
iq_res[idx + 1] = 0xffff & REG_READ(ah,
chan_info_tab[i] + offset);

ath_dbg(common, ATH_DBG_CALIBRATE,
"IQ RES[%d]=0x%x"
"IQ_RES[%d]=0x%x\n",
idx, iq_res[idx], idx + 1,
iq_res[idx + 1]);
}

if (!ar9003_hw_calc_iq_corr(ah, i, iq_res,
coeff.iqc_coeff)) {
ath_dbg(common, ATH_DBG_CALIBRATE,
"Failed in calculation of IQ correction.\n");
goto tx_iqcal_fail;
}

coeff.mag_coeff[i][im][ip] =
coeff.iqc_coeff[0] & 0x7f;
coeff.phs_coeff[i][im][ip] =
(coeff.iqc_coeff[0] >> 7) & 0x7f;

if (coeff.mag_coeff[i][im][ip] > 63)
coeff.mag_coeff[i][im][ip] -= 128;
if (coeff.phs_coeff[i][im][ip] > 63)
coeff.phs_coeff[i][im][ip] -= 128;
}
}
}
ar9003_hw_tx_iqcal_load_avg_2_passes(ah, num_chains, &coeff);

return;

tx_iqcal_fail:
ath_dbg(common, ATH_DBG_CALIBRATE, "Tx IQ Cal failed\n");
return;
}
static bool ar9003_hw_init_cal(struct ath_hw *ah,
struct ath9k_channel *chan)
{
Expand All @@ -733,7 +966,11 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah,
ar9003_hw_set_chain_masks(ah, 0x7, 0x7);

/* Do Tx IQ Calibration */
ar9003_hw_tx_iq_cal(ah);
if (AR_SREV_9485(ah))
ar9003_hw_tx_iq_cal_run(ah);
else
ar9003_hw_tx_iq_cal(ah);

REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS);
udelay(5);
REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN);
Expand All @@ -751,6 +988,9 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah,
return false;
}

if (AR_SREV_9485(ah))
ar9003_hw_tx_iq_cal_post_proc(ah);

/* Revert chainmasks to their original values before NF cal */
ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask);

Expand Down
16 changes: 14 additions & 2 deletions trunk/drivers/net/wireless/ath/ath9k/ar9003_phy.h
Original file line number Diff line number Diff line change
Expand Up @@ -546,6 +546,12 @@

#define AR_PHY_TXGAIN_TABLE (AR_SM_BASE + 0x300)

#define AR_PHY_TX_IQCAL_START_9485 (AR_SM_BASE + 0x3c4)
#define AR_PHY_TX_IQCAL_START_DO_CAL_9485 0x80000000
#define AR_PHY_TX_IQCAL_START_DO_CAL_9485_S 31
#define AR_PHY_TX_IQCAL_CONTROL_1_9485 (AR_SM_BASE + 0x3c8)
#define AR_PHY_TX_IQCAL_STATUS_B0_9485 (AR_SM_BASE + 0x3f0)

#define AR_PHY_TX_IQCAL_CONTROL_1 (AR_SM_BASE + 0x448)
#define AR_PHY_TX_IQCAL_START (AR_SM_BASE + 0x440)
#define AR_PHY_TX_IQCAL_STATUS_B0 (AR_SM_BASE + 0x48c)
Expand Down Expand Up @@ -713,6 +719,7 @@
#define AR_PHY_TPCGR1_FORCED_DAC_GAIN_S 1
#define AR_PHY_TPCGR1_FORCE_DAC_GAIN 0x00000001
#define AR_PHY_TXGAIN_FORCE 0x00000001
#define AR_PHY_TXGAIN_FORCE_S 0
#define AR_PHY_TXGAIN_FORCED_PADVGNRA 0x00003c00
#define AR_PHY_TXGAIN_FORCED_PADVGNRA_S 10
#define AR_PHY_TXGAIN_FORCED_PADVGNRB 0x0003c000
Expand Down Expand Up @@ -755,8 +762,13 @@
#define AR_PHY_TX_IQCAL_START_DO_CAL_S 0

#define AR_PHY_TX_IQCAL_STATUS_FAILED 0x00000001
#define AR_PHY_TX_IQCAL_CORR_COEFF_01_COEFF_TABLE 0x00003fff
#define AR_PHY_TX_IQCAL_CORR_COEFF_01_COEFF_TABLE_S 0
#define AR_PHY_CALIBRATED_GAINS_0 0x3e
#define AR_PHY_CALIBRATED_GAINS_0_S 1

#define AR_PHY_TX_IQCAL_CORR_COEFF_00_COEFF_TABLE 0x00003fff
#define AR_PHY_TX_IQCAL_CORR_COEFF_00_COEFF_TABLE_S 0
#define AR_PHY_TX_IQCAL_CORR_COEFF_01_COEFF_TABLE 0x0fffc000
#define AR_PHY_TX_IQCAL_CORR_COEFF_01_COEFF_TABLE_S 14

#define AR_PHY_65NM_CH0_RXTX4_THERM_ON 0x10000000
#define AR_PHY_65NM_CH0_RXTX4_THERM_ON_S 28
Expand Down

0 comments on commit b1faca7

Please sign in to comment.