ucode.c (11380B)
1// SPDX-License-Identifier: GPL-2.0-only 2/****************************************************************************** 3 * 4 * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved. 5 * Copyright(c) 2015 Intel Deutschland GmbH 6 *****************************************************************************/ 7 8#include <linux/kernel.h> 9 10#include "iwl-io.h" 11#include "iwl-agn-hw.h" 12#include "iwl-trans.h" 13#include "iwl-fh.h" 14#include "iwl-op-mode.h" 15 16#include "dev.h" 17#include "agn.h" 18#include "calib.h" 19 20/****************************************************************************** 21 * 22 * uCode download functions 23 * 24 ******************************************************************************/ 25 26/* 27 * Calibration 28 */ 29static int iwl_set_Xtal_calib(struct iwl_priv *priv) 30{ 31 struct iwl_calib_xtal_freq_cmd cmd; 32 __le16 *xtal_calib = priv->nvm_data->xtal_calib; 33 34 iwl_set_calib_hdr(&cmd.hdr, IWL_PHY_CALIBRATE_CRYSTAL_FRQ_CMD); 35 cmd.cap_pin1 = le16_to_cpu(xtal_calib[0]); 36 cmd.cap_pin2 = le16_to_cpu(xtal_calib[1]); 37 return iwl_calib_set(priv, (void *)&cmd, sizeof(cmd)); 38} 39 40static int iwl_set_temperature_offset_calib(struct iwl_priv *priv) 41{ 42 struct iwl_calib_temperature_offset_cmd cmd; 43 44 memset(&cmd, 0, sizeof(cmd)); 45 iwl_set_calib_hdr(&cmd.hdr, IWL_PHY_CALIBRATE_TEMP_OFFSET_CMD); 46 cmd.radio_sensor_offset = priv->nvm_data->raw_temperature; 47 if (!(cmd.radio_sensor_offset)) 48 cmd.radio_sensor_offset = DEFAULT_RADIO_SENSOR_OFFSET; 49 50 IWL_DEBUG_CALIB(priv, "Radio sensor offset: %d\n", 51 le16_to_cpu(cmd.radio_sensor_offset)); 52 return iwl_calib_set(priv, (void *)&cmd, sizeof(cmd)); 53} 54 55static int iwl_set_temperature_offset_calib_v2(struct iwl_priv *priv) 56{ 57 struct iwl_calib_temperature_offset_v2_cmd cmd; 58 59 memset(&cmd, 0, sizeof(cmd)); 60 iwl_set_calib_hdr(&cmd.hdr, IWL_PHY_CALIBRATE_TEMP_OFFSET_CMD); 61 cmd.radio_sensor_offset_high = priv->nvm_data->kelvin_temperature; 62 cmd.radio_sensor_offset_low = priv->nvm_data->raw_temperature; 63 if (!cmd.radio_sensor_offset_low) { 64 IWL_DEBUG_CALIB(priv, "no info in EEPROM, use default\n"); 65 cmd.radio_sensor_offset_low = DEFAULT_RADIO_SENSOR_OFFSET; 66 cmd.radio_sensor_offset_high = DEFAULT_RADIO_SENSOR_OFFSET; 67 } 68 cmd.burntVoltageRef = priv->nvm_data->calib_voltage; 69 70 IWL_DEBUG_CALIB(priv, "Radio sensor offset high: %d\n", 71 le16_to_cpu(cmd.radio_sensor_offset_high)); 72 IWL_DEBUG_CALIB(priv, "Radio sensor offset low: %d\n", 73 le16_to_cpu(cmd.radio_sensor_offset_low)); 74 IWL_DEBUG_CALIB(priv, "Voltage Ref: %d\n", 75 le16_to_cpu(cmd.burntVoltageRef)); 76 77 return iwl_calib_set(priv, (void *)&cmd, sizeof(cmd)); 78} 79 80static int iwl_send_calib_cfg(struct iwl_priv *priv) 81{ 82 struct iwl_calib_cfg_cmd calib_cfg_cmd; 83 struct iwl_host_cmd cmd = { 84 .id = CALIBRATION_CFG_CMD, 85 .len = { sizeof(struct iwl_calib_cfg_cmd), }, 86 .data = { &calib_cfg_cmd, }, 87 }; 88 89 memset(&calib_cfg_cmd, 0, sizeof(calib_cfg_cmd)); 90 calib_cfg_cmd.ucd_calib_cfg.once.is_enable = IWL_CALIB_INIT_CFG_ALL; 91 calib_cfg_cmd.ucd_calib_cfg.once.start = IWL_CALIB_INIT_CFG_ALL; 92 calib_cfg_cmd.ucd_calib_cfg.once.send_res = IWL_CALIB_INIT_CFG_ALL; 93 calib_cfg_cmd.ucd_calib_cfg.flags = 94 IWL_CALIB_CFG_FLAG_SEND_COMPLETE_NTFY_MSK; 95 96 return iwl_dvm_send_cmd(priv, &cmd); 97} 98 99int iwl_init_alive_start(struct iwl_priv *priv) 100{ 101 int ret; 102 103 if (priv->lib->bt_params && 104 priv->lib->bt_params->advanced_bt_coexist) { 105 /* 106 * Tell uCode we are ready to perform calibration 107 * need to perform this before any calibration 108 * no need to close the envlope since we are going 109 * to load the runtime uCode later. 110 */ 111 ret = iwl_send_bt_env(priv, IWL_BT_COEX_ENV_OPEN, 112 BT_COEX_PRIO_TBL_EVT_INIT_CALIB2); 113 if (ret) 114 return ret; 115 116 } 117 118 ret = iwl_send_calib_cfg(priv); 119 if (ret) 120 return ret; 121 122 /** 123 * temperature offset calibration is only needed for runtime ucode, 124 * so prepare the value now. 125 */ 126 if (priv->lib->need_temp_offset_calib) { 127 if (priv->lib->temp_offset_v2) 128 return iwl_set_temperature_offset_calib_v2(priv); 129 else 130 return iwl_set_temperature_offset_calib(priv); 131 } 132 133 return 0; 134} 135 136static int iwl_send_wimax_coex(struct iwl_priv *priv) 137{ 138 struct iwl_wimax_coex_cmd coex_cmd; 139 140 /* coexistence is disabled */ 141 memset(&coex_cmd, 0, sizeof(coex_cmd)); 142 143 return iwl_dvm_send_cmd_pdu(priv, 144 COEX_PRIORITY_TABLE_CMD, 0, 145 sizeof(coex_cmd), &coex_cmd); 146} 147 148static const u8 iwl_bt_prio_tbl[BT_COEX_PRIO_TBL_EVT_MAX] = { 149 ((BT_COEX_PRIO_TBL_PRIO_BYPASS << IWL_BT_COEX_PRIO_TBL_PRIO_POS) | 150 (0 << IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS)), 151 ((BT_COEX_PRIO_TBL_PRIO_BYPASS << IWL_BT_COEX_PRIO_TBL_PRIO_POS) | 152 (1 << IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS)), 153 ((BT_COEX_PRIO_TBL_PRIO_LOW << IWL_BT_COEX_PRIO_TBL_PRIO_POS) | 154 (0 << IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS)), 155 ((BT_COEX_PRIO_TBL_PRIO_LOW << IWL_BT_COEX_PRIO_TBL_PRIO_POS) | 156 (1 << IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS)), 157 ((BT_COEX_PRIO_TBL_PRIO_HIGH << IWL_BT_COEX_PRIO_TBL_PRIO_POS) | 158 (0 << IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS)), 159 ((BT_COEX_PRIO_TBL_PRIO_HIGH << IWL_BT_COEX_PRIO_TBL_PRIO_POS) | 160 (1 << IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS)), 161 ((BT_COEX_PRIO_TBL_PRIO_BYPASS << IWL_BT_COEX_PRIO_TBL_PRIO_POS) | 162 (0 << IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS)), 163 ((BT_COEX_PRIO_TBL_PRIO_COEX_OFF << IWL_BT_COEX_PRIO_TBL_PRIO_POS) | 164 (0 << IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS)), 165 ((BT_COEX_PRIO_TBL_PRIO_COEX_ON << IWL_BT_COEX_PRIO_TBL_PRIO_POS) | 166 (0 << IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS)), 167 0, 0, 0, 0, 0, 0, 0 168}; 169 170void iwl_send_prio_tbl(struct iwl_priv *priv) 171{ 172 struct iwl_bt_coex_prio_table_cmd prio_tbl_cmd; 173 174 memcpy(prio_tbl_cmd.prio_tbl, iwl_bt_prio_tbl, 175 sizeof(iwl_bt_prio_tbl)); 176 if (iwl_dvm_send_cmd_pdu(priv, 177 REPLY_BT_COEX_PRIO_TABLE, 0, 178 sizeof(prio_tbl_cmd), &prio_tbl_cmd)) 179 IWL_ERR(priv, "failed to send BT prio tbl command\n"); 180} 181 182int iwl_send_bt_env(struct iwl_priv *priv, u8 action, u8 type) 183{ 184 struct iwl_bt_coex_prot_env_cmd env_cmd; 185 int ret; 186 187 env_cmd.action = action; 188 env_cmd.type = type; 189 ret = iwl_dvm_send_cmd_pdu(priv, 190 REPLY_BT_COEX_PROT_ENV, 0, 191 sizeof(env_cmd), &env_cmd); 192 if (ret) 193 IWL_ERR(priv, "failed to send BT env command\n"); 194 return ret; 195} 196 197static const u8 iwlagn_default_queue_to_tx_fifo[] = { 198 IWL_TX_FIFO_VO, 199 IWL_TX_FIFO_VI, 200 IWL_TX_FIFO_BE, 201 IWL_TX_FIFO_BK, 202}; 203 204static const u8 iwlagn_ipan_queue_to_tx_fifo[] = { 205 IWL_TX_FIFO_VO, 206 IWL_TX_FIFO_VI, 207 IWL_TX_FIFO_BE, 208 IWL_TX_FIFO_BK, 209 IWL_TX_FIFO_BK_IPAN, 210 IWL_TX_FIFO_BE_IPAN, 211 IWL_TX_FIFO_VI_IPAN, 212 IWL_TX_FIFO_VO_IPAN, 213 IWL_TX_FIFO_BE_IPAN, 214 IWL_TX_FIFO_UNUSED, 215 IWL_TX_FIFO_AUX, 216}; 217 218static int iwl_alive_notify(struct iwl_priv *priv) 219{ 220 const u8 *queue_to_txf; 221 u8 n_queues; 222 int ret; 223 int i; 224 225 iwl_trans_fw_alive(priv->trans, 0); 226 227 if (priv->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PAN && 228 priv->nvm_data->sku_cap_ipan_enable) { 229 n_queues = ARRAY_SIZE(iwlagn_ipan_queue_to_tx_fifo); 230 queue_to_txf = iwlagn_ipan_queue_to_tx_fifo; 231 } else { 232 n_queues = ARRAY_SIZE(iwlagn_default_queue_to_tx_fifo); 233 queue_to_txf = iwlagn_default_queue_to_tx_fifo; 234 } 235 236 for (i = 0; i < n_queues; i++) 237 if (queue_to_txf[i] != IWL_TX_FIFO_UNUSED) 238 iwl_trans_ac_txq_enable(priv->trans, i, 239 queue_to_txf[i], 0); 240 241 priv->passive_no_rx = false; 242 priv->transport_queue_stop = 0; 243 244 ret = iwl_send_wimax_coex(priv); 245 if (ret) 246 return ret; 247 248 if (!priv->lib->no_xtal_calib) { 249 ret = iwl_set_Xtal_calib(priv); 250 if (ret) 251 return ret; 252 } 253 254 return iwl_send_calib_results(priv); 255} 256 257struct iwl_alive_data { 258 bool valid; 259 u8 subtype; 260}; 261 262static bool iwl_alive_fn(struct iwl_notif_wait_data *notif_wait, 263 struct iwl_rx_packet *pkt, void *data) 264{ 265 struct iwl_priv *priv = 266 container_of(notif_wait, struct iwl_priv, notif_wait); 267 struct iwl_alive_data *alive_data = data; 268 struct iwl_alive_resp *palive; 269 270 palive = (void *)pkt->data; 271 272 IWL_DEBUG_FW(priv, "Alive ucode status 0x%08X revision " 273 "0x%01X 0x%01X\n", 274 palive->is_valid, palive->ver_type, 275 palive->ver_subtype); 276 277 priv->device_pointers.error_event_table = 278 le32_to_cpu(palive->error_event_table_ptr); 279 priv->device_pointers.log_event_table = 280 le32_to_cpu(palive->log_event_table_ptr); 281 282 alive_data->subtype = palive->ver_subtype; 283 alive_data->valid = palive->is_valid == UCODE_VALID_OK; 284 285 return true; 286} 287 288#define UCODE_ALIVE_TIMEOUT HZ 289#define UCODE_CALIB_TIMEOUT (2*HZ) 290 291int iwl_load_ucode_wait_alive(struct iwl_priv *priv, 292 enum iwl_ucode_type ucode_type) 293{ 294 struct iwl_notification_wait alive_wait; 295 struct iwl_alive_data alive_data; 296 const struct fw_img *fw; 297 int ret; 298 enum iwl_ucode_type old_type; 299 static const u16 alive_cmd[] = { REPLY_ALIVE }; 300 301 fw = iwl_get_ucode_image(priv->fw, ucode_type); 302 if (WARN_ON(!fw)) 303 return -EINVAL; 304 305 old_type = priv->cur_ucode; 306 priv->cur_ucode = ucode_type; 307 priv->ucode_loaded = false; 308 309 iwl_init_notification_wait(&priv->notif_wait, &alive_wait, 310 alive_cmd, ARRAY_SIZE(alive_cmd), 311 iwl_alive_fn, &alive_data); 312 313 ret = iwl_trans_start_fw(priv->trans, fw, false); 314 if (ret) { 315 priv->cur_ucode = old_type; 316 iwl_remove_notification(&priv->notif_wait, &alive_wait); 317 return ret; 318 } 319 320 /* 321 * Some things may run in the background now, but we 322 * just wait for the ALIVE notification here. 323 */ 324 ret = iwl_wait_notification(&priv->notif_wait, &alive_wait, 325 UCODE_ALIVE_TIMEOUT); 326 if (ret) { 327 priv->cur_ucode = old_type; 328 return ret; 329 } 330 331 if (!alive_data.valid) { 332 IWL_ERR(priv, "Loaded ucode is not valid!\n"); 333 priv->cur_ucode = old_type; 334 return -EIO; 335 } 336 337 priv->ucode_loaded = true; 338 339 if (ucode_type != IWL_UCODE_WOWLAN) { 340 /* delay a bit to give rfkill time to run */ 341 msleep(5); 342 } 343 344 ret = iwl_alive_notify(priv); 345 if (ret) { 346 IWL_WARN(priv, 347 "Could not complete ALIVE transition: %d\n", ret); 348 priv->cur_ucode = old_type; 349 return ret; 350 } 351 352 return 0; 353} 354 355static bool iwlagn_wait_calib(struct iwl_notif_wait_data *notif_wait, 356 struct iwl_rx_packet *pkt, void *data) 357{ 358 struct iwl_priv *priv = data; 359 struct iwl_calib_hdr *hdr; 360 361 if (pkt->hdr.cmd != CALIBRATION_RES_NOTIFICATION) { 362 WARN_ON(pkt->hdr.cmd != CALIBRATION_COMPLETE_NOTIFICATION); 363 return true; 364 } 365 366 hdr = (struct iwl_calib_hdr *)pkt->data; 367 368 if (iwl_calib_set(priv, hdr, iwl_rx_packet_payload_len(pkt))) 369 IWL_ERR(priv, "Failed to record calibration data %d\n", 370 hdr->op_code); 371 372 return false; 373} 374 375int iwl_run_init_ucode(struct iwl_priv *priv) 376{ 377 struct iwl_notification_wait calib_wait; 378 static const u16 calib_complete[] = { 379 CALIBRATION_RES_NOTIFICATION, 380 CALIBRATION_COMPLETE_NOTIFICATION 381 }; 382 int ret; 383 384 lockdep_assert_held(&priv->mutex); 385 386 /* No init ucode required? Curious, but maybe ok */ 387 if (!priv->fw->img[IWL_UCODE_INIT].num_sec) 388 return 0; 389 390 iwl_init_notification_wait(&priv->notif_wait, &calib_wait, 391 calib_complete, ARRAY_SIZE(calib_complete), 392 iwlagn_wait_calib, priv); 393 394 /* Will also start the device */ 395 ret = iwl_load_ucode_wait_alive(priv, IWL_UCODE_INIT); 396 if (ret) 397 goto error; 398 399 ret = iwl_init_alive_start(priv); 400 if (ret) 401 goto error; 402 403 /* 404 * Some things may run in the background now, but we 405 * just wait for the calibration complete notification. 406 */ 407 ret = iwl_wait_notification(&priv->notif_wait, &calib_wait, 408 UCODE_CALIB_TIMEOUT); 409 410 goto out; 411 412 error: 413 iwl_remove_notification(&priv->notif_wait, &calib_wait); 414 out: 415 /* Whatever happened, stop the device */ 416 iwl_trans_stop_device(priv->trans); 417 priv->ucode_loaded = false; 418 419 return ret; 420}