forked from Minki/linux
iwlwifi-5000: implement initial calibration for 5000
This patch adds initial calibration framework for 5000 HW faimily. Signed-off-by: Tomas Winkler <tomas.winkler@intel.com> Signed-off-by: Gregory Greenman <gregory.greenman@intel.com> Signed-off-by: Ron Rindjunsky <ron.rindjunsky@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
parent
c135475439
commit
7c616cba24
@ -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 @@ err:
|
||||
}
|
||||
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";
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user