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