iwlwifi-5000: add run time calibrations for 5000
This patch adds support for run time calibrations for the 5000 family HW. Those calibrations are sensitivity calibration, and chain noise calibration. Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com> Signed-off-by: Tomas Winkler <tomas.winkler@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
parent
c031bf806f
commit
33fd503346
|
@ -119,6 +119,15 @@ config IWL5000
|
|||
This option enables support for Intel Wireless WiFi Link 5000AGN Family
|
||||
Dependency on 4965 is temporary
|
||||
|
||||
config IWL5000_RUN_TIME_CALIB
|
||||
bool "Enable run time Calibration for 5000 NIC"
|
||||
select IWLWIFI_RUN_TIME_CALIB
|
||||
depends on IWL5000
|
||||
default y
|
||||
---help---
|
||||
This option will enable run time calibration for the iwl5000 driver.
|
||||
These calibrations are Sensitivity and Chain Noise. If unsure, say yes
|
||||
|
||||
|
||||
config IWLWIFI_DEBUGFS
|
||||
bool "Iwlwifi debugfs support"
|
||||
|
|
|
@ -2671,6 +2671,37 @@ struct iwl4965_calibration_cmd {
|
|||
u8 reserved1;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* Phy calibration command for 5000 series */
|
||||
|
||||
enum {
|
||||
IWL5000_PHY_CALIBRATE_DC_CMD = 8,
|
||||
IWL5000_PHY_CALIBRATE_LO_CMD = 9,
|
||||
IWL5000_PHY_CALIBRATE_RX_BB_CMD = 10,
|
||||
IWL5000_PHY_CALIBRATE_TX_IQ_CMD = 11,
|
||||
IWL5000_PHY_CALIBRATE_RX_IQ_CMD = 12,
|
||||
IWL5000_PHY_CALIBRATION_NOISE_CMD = 13,
|
||||
IWL5000_PHY_CALIBRATE_AGC_TABLE_CMD = 14,
|
||||
IWL5000_PHY_CALIBRATE_CRYSTAL_FRQ_CMD = 15,
|
||||
IWL5000_PHY_CALIBRATE_BASE_BAND_CMD = 16,
|
||||
IWL5000_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD = 18,
|
||||
IWL5000_PHY_CALIBRATE_CHAIN_NOISE_GAIN_CMD = 19,
|
||||
};
|
||||
|
||||
struct iwl5000_calibration_chain_noise_reset_cmd {
|
||||
u8 op_code; /* IWL5000_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD */
|
||||
u8 flags; /* not used */
|
||||
__le16 reserved;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct iwl5000_calibration_chain_noise_gain_cmd {
|
||||
u8 op_code; /* IWL5000_PHY_CALIBRATE_CHAIN_NOISE_GAIN_CMD */
|
||||
u8 flags; /* not used */
|
||||
__le16 reserved;
|
||||
u8 delta_gain_1;
|
||||
u8 delta_gain_2;
|
||||
__le16 reserved1;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/******************************************************************************
|
||||
* (12)
|
||||
* Miscellaneous Commands:
|
||||
|
|
|
@ -125,6 +125,100 @@ static u32 eeprom_indirect_address(const struct iwl_priv *priv, u32 address)
|
|||
return (address & ADDRESS_MSK) + (offset << 1);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IWL5000_RUN_TIME_CALIB
|
||||
|
||||
static void iwl5000_gain_computation(struct iwl_priv *priv,
|
||||
u32 average_noise[NUM_RX_CHAINS],
|
||||
u16 min_average_noise_antenna_i,
|
||||
u32 min_average_noise)
|
||||
{
|
||||
int i;
|
||||
s32 delta_g;
|
||||
struct iwl_chain_noise_data *data = &priv->chain_noise_data;
|
||||
|
||||
/* Find Gain Code for the antennas B and C */
|
||||
for (i = 1; i < NUM_RX_CHAINS; i++) {
|
||||
if ((data->disconn_array[i])) {
|
||||
data->delta_gain_code[i] = 0;
|
||||
continue;
|
||||
}
|
||||
delta_g = (1000 * ((s32)average_noise[0] -
|
||||
(s32)average_noise[i])) / 1500;
|
||||
/* bound gain by 2 bits value max, 3rd bit is sign */
|
||||
data->delta_gain_code[i] =
|
||||
min(abs(delta_g), CHAIN_NOISE_MAX_DELTA_GAIN_CODE);
|
||||
|
||||
if (delta_g < 0)
|
||||
/* set negative sign */
|
||||
data->delta_gain_code[i] |= (1 << 2);
|
||||
}
|
||||
|
||||
IWL_DEBUG_CALIB("Delta gains: ANT_B = %d ANT_C = %d\n",
|
||||
data->delta_gain_code[1], data->delta_gain_code[2]);
|
||||
|
||||
if (!data->radio_write) {
|
||||
struct iwl5000_calibration_chain_noise_gain_cmd cmd;
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
|
||||
cmd.op_code = IWL5000_PHY_CALIBRATE_CHAIN_NOISE_GAIN_CMD;
|
||||
cmd.delta_gain_1 = data->delta_gain_code[1];
|
||||
cmd.delta_gain_2 = data->delta_gain_code[2];
|
||||
iwl_send_cmd_pdu_async(priv, REPLY_PHY_CALIBRATION_CMD,
|
||||
sizeof(cmd), &cmd, NULL);
|
||||
|
||||
data->radio_write = 1;
|
||||
data->state = IWL_CHAIN_NOISE_CALIBRATED;
|
||||
}
|
||||
|
||||
data->chain_noise_a = 0;
|
||||
data->chain_noise_b = 0;
|
||||
data->chain_noise_c = 0;
|
||||
data->chain_signal_a = 0;
|
||||
data->chain_signal_b = 0;
|
||||
data->chain_signal_c = 0;
|
||||
data->beacon_count = 0;
|
||||
}
|
||||
|
||||
static void iwl5000_chain_noise_reset(struct iwl_priv *priv)
|
||||
{
|
||||
struct iwl_chain_noise_data *data = &priv->chain_noise_data;
|
||||
|
||||
if ((data->state == IWL_CHAIN_NOISE_ALIVE) && iwl_is_associated(priv)) {
|
||||
struct iwl5000_calibration_chain_noise_reset_cmd cmd;
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.op_code = IWL5000_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD;
|
||||
if (iwl_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD,
|
||||
sizeof(cmd), &cmd))
|
||||
IWL_ERROR("Could not send REPLY_PHY_CALIBRATION_CMD\n");
|
||||
data->state = IWL_CHAIN_NOISE_ACCUMULATE;
|
||||
IWL_DEBUG_CALIB("Run chain_noise_calibrate\n");
|
||||
}
|
||||
}
|
||||
|
||||
static struct iwl_sensitivity_ranges iwl5000_sensitivity = {
|
||||
.min_nrg_cck = 95,
|
||||
.max_nrg_cck = 0,
|
||||
.auto_corr_min_ofdm = 90,
|
||||
.auto_corr_min_ofdm_mrc = 170,
|
||||
.auto_corr_min_ofdm_x1 = 120,
|
||||
.auto_corr_min_ofdm_mrc_x1 = 240,
|
||||
|
||||
.auto_corr_max_ofdm = 120,
|
||||
.auto_corr_max_ofdm_mrc = 210,
|
||||
.auto_corr_max_ofdm_x1 = 155,
|
||||
.auto_corr_max_ofdm_mrc_x1 = 290,
|
||||
|
||||
.auto_corr_min_cck = 125,
|
||||
.auto_corr_max_cck = 200,
|
||||
.auto_corr_min_cck_mrc = 170,
|
||||
.auto_corr_max_cck_mrc = 400,
|
||||
.nrg_th_cck = 95,
|
||||
.nrg_th_ofdm = 95,
|
||||
};
|
||||
|
||||
#endif /* CONFIG_IWL5000_RUN_TIME_CALIB */
|
||||
|
||||
static const u8 *iwl5000_eeprom_query_addr(const struct iwl_priv *priv,
|
||||
size_t offset)
|
||||
{
|
||||
|
@ -159,6 +253,9 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv)
|
|||
priv->hw_params.max_bsm_size = BSM_SRAM_SIZE;
|
||||
priv->hw_params.fat_channel = BIT(IEEE80211_BAND_2GHZ) |
|
||||
BIT(IEEE80211_BAND_5GHZ);
|
||||
#ifdef CONFIG_IWL5000_RUN_TIME_CALIB
|
||||
priv->hw_params.sens = &iwl5000_sensitivity;
|
||||
#endif
|
||||
|
||||
switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) {
|
||||
case CSR_HW_REV_TYPE_5100:
|
||||
|
@ -202,6 +299,10 @@ static struct iwl_hcmd_ops iwl5000_hcmd = {
|
|||
};
|
||||
|
||||
static struct iwl_hcmd_utils_ops iwl5000_hcmd_utils = {
|
||||
#ifdef CONFIG_IWL5000_RUN_TIME_CALIB
|
||||
.gain_computation = iwl5000_gain_computation,
|
||||
.chain_noise_reset = iwl5000_chain_noise_reset,
|
||||
#endif
|
||||
};
|
||||
|
||||
static struct iwl_lib_ops iwl5000_lib = {
|
||||
|
|
Loading…
Reference in New Issue