Commit 7c616cba authored by Tomas Winkler's avatar Tomas Winkler Committed by John W. Linville

iwlwifi-5000: implement initial calibration for 5000

This patch adds initial calibration framework for 5000 HW faimily.
Signed-off-by: default avatarTomas Winkler <tomas.winkler@intel.com>
Signed-off-by: default avatarGregory Greenman <gregory.greenman@intel.com>
Signed-off-by: default avatarRon Rindjunsky <ron.rindjunsky@intel.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent c1354754
......@@ -395,6 +395,8 @@ static struct iwl_sensitivity_ranges iwl5000_sensitivity = {
#endif /* CONFIG_IWL5000_RUN_TIME_CALIB */
static const u8 *iwl5000_eeprom_query_addr(const struct iwl_priv *priv,
size_t offset)
{
......@@ -403,6 +405,118 @@ static const u8 *iwl5000_eeprom_query_addr(const struct iwl_priv *priv,
return &priv->eeprom[address];
}
/*
* Calibration
*/
static int iwl5000_send_Xtal_calib(struct iwl_priv *priv)
{
u16 *xtal_calib = (u16 *)iwl_eeprom_query_addr(priv, EEPROM_5000_XTAL);
struct iwl5000_calibration cal_cmd = {
.op_code = IWL5000_PHY_CALIBRATE_CRYSTAL_FRQ_CMD,
.data = {
(u8)xtal_calib[0],
(u8)xtal_calib[1],
}
};
return iwl_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD,
sizeof(cal_cmd), &cal_cmd);
}
static int iwl5000_send_calib_results(struct iwl_priv *priv)
{
int ret = 0;
if (priv->calib_results.lo_res)
ret = iwl_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD,
priv->calib_results.lo_res_len,
priv->calib_results.lo_res);
if (ret)
goto err;
if (priv->calib_results.tx_iq_res)
ret = iwl_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD,
priv->calib_results.tx_iq_res_len,
priv->calib_results.tx_iq_res);
if (ret)
goto err;
if (priv->calib_results.tx_iq_perd_res)
ret = iwl_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD,
priv->calib_results.tx_iq_perd_res_len,
priv->calib_results.tx_iq_perd_res);
if (ret)
goto err;
return 0;
err:
IWL_ERROR("Error %d\n", ret);
return ret;
}
static int iwl5000_send_calib_cfg(struct iwl_priv *priv)
{
struct iwl5000_calib_cfg_cmd calib_cfg_cmd;
struct iwl_host_cmd cmd = {
.id = CALIBRATION_CFG_CMD,
.len = sizeof(struct iwl5000_calib_cfg_cmd),
.data = &calib_cfg_cmd,
};
memset(&calib_cfg_cmd, 0, sizeof(calib_cfg_cmd));
calib_cfg_cmd.ucd_calib_cfg.once.is_enable = IWL_CALIB_INIT_CFG_ALL;
calib_cfg_cmd.ucd_calib_cfg.once.start = IWL_CALIB_INIT_CFG_ALL;
calib_cfg_cmd.ucd_calib_cfg.once.send_res = IWL_CALIB_INIT_CFG_ALL;
calib_cfg_cmd.ucd_calib_cfg.flags = IWL_CALIB_INIT_CFG_ALL;
return iwl_send_cmd(priv, &cmd);
}
static void iwl5000_rx_calib_result(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb)
{
struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
struct iwl5000_calib_hdr *hdr = (struct iwl5000_calib_hdr *)pkt->u.raw;
int len = le32_to_cpu(pkt->len) & FH_RSCSR_FRAME_SIZE_MSK;
iwl_free_calib_results(priv);
/* reduce the size of the length field itself */
len -= 4;
switch (hdr->op_code) {
case IWL5000_PHY_CALIBRATE_LO_CMD:
priv->calib_results.lo_res = kzalloc(len, GFP_ATOMIC);
priv->calib_results.lo_res_len = len;
memcpy(priv->calib_results.lo_res, pkt->u.raw, len);
break;
case IWL5000_PHY_CALIBRATE_TX_IQ_CMD:
priv->calib_results.tx_iq_res = kzalloc(len, GFP_ATOMIC);
priv->calib_results.tx_iq_res_len = len;
memcpy(priv->calib_results.tx_iq_res, pkt->u.raw, len);
break;
case IWL5000_PHY_CALIBRATE_TX_IQ_PERD_CMD:
priv->calib_results.tx_iq_perd_res = kzalloc(len, GFP_ATOMIC);
priv->calib_results.tx_iq_perd_res_len = len;
memcpy(priv->calib_results.tx_iq_perd_res, pkt->u.raw, len);
break;
default:
IWL_ERROR("Unknown calibration notification %d\n",
hdr->op_code);
return;
}
}
static void iwl5000_rx_calib_complete(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb)
{
IWL_DEBUG_INFO("Init. calibration is completed, restarting fw.\n");
queue_work(priv->workqueue, &priv->restart);
}
/*
* ucode
*/
......@@ -565,6 +679,7 @@ static void iwl5000_init_alive_start(struct iwl_priv *priv)
goto restart;
}
iwl5000_send_calib_cfg(priv);
return;
restart:
......@@ -684,8 +799,14 @@ static int iwl5000_alive_notify(struct iwl_priv *priv)
iwl_release_nic_access(priv);
spin_unlock_irqrestore(&priv->lock, flags);
iwl5000_send_wimax_coex(priv);
iwl5000_send_Xtal_calib(priv);
if (priv->ucode_type == UCODE_RT)
iwl5000_send_calib_results(priv);
return 0;
}
......@@ -856,8 +977,14 @@ static u16 iwl5000_get_hcmd_size(u8 cmd_id, u16 len)
static void iwl5000_rx_handler_setup(struct iwl_priv *priv)
{
/* init calibration handlers */
priv->rx_handlers[CALIBRATION_RES_NOTIFICATION] =
iwl5000_rx_calib_result;
priv->rx_handlers[CALIBRATION_COMPLETE_NOTIFICATION] =
iwl5000_rx_calib_complete;
}
static int iwl5000_hw_valid_rtc_data_addr(u32 addr)
{
return (addr >= RTC_DATA_LOWER_BOUND) &&
......
......@@ -2778,10 +2778,59 @@ enum {
IWL5000_PHY_CALIBRATE_AGC_TABLE_CMD = 14,
IWL5000_PHY_CALIBRATE_CRYSTAL_FRQ_CMD = 15,
IWL5000_PHY_CALIBRATE_BASE_BAND_CMD = 16,
IWL5000_PHY_CALIBRATE_TX_IQ_PERD_CMD = 17,
IWL5000_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD = 18,
IWL5000_PHY_CALIBRATE_CHAIN_NOISE_GAIN_CMD = 19,
};
enum {
CALIBRATION_CFG_CMD = 0x65,
CALIBRATION_RES_NOTIFICATION = 0x66,
CALIBRATION_COMPLETE_NOTIFICATION = 0x67
};
struct iwl_cal_crystal_freq_cmd {
u8 cap_pin1;
u8 cap_pin2;
} __attribute__ ((packed));
struct iwl5000_calibration {
u8 op_code;
u8 first_group;
u8 num_groups;
u8 all_data_valid;
struct iwl_cal_crystal_freq_cmd data;
} __attribute__ ((packed));
#define IWL_CALIB_INIT_CFG_ALL __constant_cpu_to_le32(0xffffffff)
struct iwl_calib_cfg_elmnt_s {
__le32 is_enable;
__le32 start;
__le32 send_res;
__le32 apply_res;
__le32 reserved;
} __attribute__ ((packed));
struct iwl_calib_cfg_status_s {
struct iwl_calib_cfg_elmnt_s once;
struct iwl_calib_cfg_elmnt_s perd;
__le32 flags;
} __attribute__ ((packed));
struct iwl5000_calib_cfg_cmd {
struct iwl_calib_cfg_status_s ucd_calib_cfg;
struct iwl_calib_cfg_status_s drv_calib_cfg;
__le32 reserved1;
} __attribute__ ((packed));
struct iwl5000_calib_hdr {
u8 op_code;
u8 first_group;
u8 groups_num;
u8 data_valid;
} __attribute__ ((packed));
struct iwl5000_calibration_chain_noise_reset_cmd {
u8 op_code; /* IWL5000_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD */
u8 flags; /* not used */
......@@ -2894,6 +2943,7 @@ struct iwl_rx_packet {
struct iwl4965_notif_statistics stats;
struct iwl4965_compressed_ba_resp compressed_ba;
struct iwl4965_missed_beacon_notif missed_beacon;
struct iwl5000_calibration calib;
__le32 status;
u8 raw[0];
} u;
......
......@@ -871,9 +871,25 @@ int iwl_init_drv(struct iwl_priv *priv)
}
EXPORT_SYMBOL(iwl_init_drv);
void iwl_free_calib_results(struct iwl_priv *priv)
{
kfree(priv->calib_results.lo_res);
priv->calib_results.lo_res = NULL;
priv->calib_results.lo_res_len = 0;
kfree(priv->calib_results.tx_iq_res);
priv->calib_results.tx_iq_res = NULL;
priv->calib_results.tx_iq_res_len = 0;
kfree(priv->calib_results.tx_iq_perd_res);
priv->calib_results.tx_iq_perd_res = NULL;
priv->calib_results.tx_iq_perd_res_len = 0;
}
EXPORT_SYMBOL(iwl_free_calib_results);
void iwl_uninit_drv(struct iwl_priv *priv)
{
iwl_free_calib_results(priv);
iwlcore_free_geos(priv);
iwl_free_channel_map(priv);
}
......
......@@ -172,6 +172,7 @@ struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg,
void iwl_hw_detect(struct iwl_priv *priv);
void iwlcore_clear_stations_table(struct iwl_priv *priv);
void iwl_free_calib_results(struct iwl_priv *priv);
void iwl_reset_qos(struct iwl_priv *priv);
void iwl_set_rxon_chain(struct iwl_priv *priv);
int iwl_set_rxon_channel(struct iwl_priv *priv,
......
......@@ -876,6 +876,15 @@ struct statistics_general_data {
u32 beacon_energy_c;
};
struct iwl_calib_results {
void *tx_iq_res;
void *tx_iq_perd_res;
void *lo_res;
u32 tx_iq_res_len;
u32 tx_iq_perd_res_len;
u32 lo_res_len;
};
enum ucode_type {
UCODE_NONE = 0,
UCODE_INIT,
......@@ -983,6 +992,9 @@ struct iwl_priv {
s32 temperature; /* degrees Kelvin */
s32 last_temperature;
/* init calibration results */
struct iwl_calib_results calib_results;
/* Scan related variables */
unsigned long last_scan_jiffies;
unsigned long next_scan_jiffies;
......
......@@ -146,6 +146,7 @@ struct iwl_eeprom_channel {
/*5000 calibrations */
#define EEPROM_5000_CALIB_ALL (INDIRECT_ADDRESS | INDIRECT_CALIBRATION)
#define EEPROM_5000_XTAL ((2*0x128) | EEPROM_5000_CALIB_ALL)
/* 5000 links */
#define EEPROM_5000_LINK_HOST (2*0x64)
......
......@@ -56,6 +56,7 @@ const char *get_cmd_string(u8 cmd)
IWL_CMD(REPLY_RATE_SCALE);
IWL_CMD(REPLY_LEDS_CMD);
IWL_CMD(REPLY_TX_LINK_QUALITY_CMD);
IWL_CMD(COEX_PRIORITY_TABLE_CMD);
IWL_CMD(RADAR_NOTIFICATION);
IWL_CMD(REPLY_QUIET_CMD);
IWL_CMD(REPLY_CHANNEL_SWITCH);
......@@ -89,6 +90,9 @@ const char *get_cmd_string(u8 cmd)
IWL_CMD(REPLY_RX_MPDU_CMD);
IWL_CMD(REPLY_RX);
IWL_CMD(REPLY_COMPRESSED_BA);
IWL_CMD(CALIBRATION_CFG_CMD);
IWL_CMD(CALIBRATION_RES_NOTIFICATION);
IWL_CMD(CALIBRATION_COMPLETE_NOTIFICATION);
default:
return "UNKNOWN";
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment