1 | // SPDX-License-Identifier: BSD-3-Clause-Clear |
2 | /* |
3 | * Copyright (c) 2020-2021 The Linux Foundation. All rights reserved. |
4 | * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. |
5 | */ |
6 | |
7 | #include <linux/msi.h> |
8 | #include <linux/pci.h> |
9 | #include <linux/firmware.h> |
10 | |
11 | #include "core.h" |
12 | #include "debug.h" |
13 | #include "mhi.h" |
14 | #include "pci.h" |
15 | |
16 | #define MHI_TIMEOUT_DEFAULT_MS 90000 |
17 | #define OTP_INVALID_BOARD_ID 0xFFFF |
18 | #define OTP_VALID_DUALMAC_BOARD_ID_MASK 0x1000 |
19 | |
20 | static const struct mhi_channel_config ath12k_mhi_channels_qcn9274[] = { |
21 | { |
22 | .num = 0, |
23 | .name = "LOOPBACK" , |
24 | .num_elements = 32, |
25 | .event_ring = 1, |
26 | .dir = DMA_TO_DEVICE, |
27 | .ee_mask = 0x4, |
28 | .pollcfg = 0, |
29 | .doorbell = MHI_DB_BRST_DISABLE, |
30 | .lpm_notify = false, |
31 | .offload_channel = false, |
32 | .doorbell_mode_switch = false, |
33 | .auto_queue = false, |
34 | }, |
35 | { |
36 | .num = 1, |
37 | .name = "LOOPBACK" , |
38 | .num_elements = 32, |
39 | .event_ring = 1, |
40 | .dir = DMA_FROM_DEVICE, |
41 | .ee_mask = 0x4, |
42 | .pollcfg = 0, |
43 | .doorbell = MHI_DB_BRST_DISABLE, |
44 | .lpm_notify = false, |
45 | .offload_channel = false, |
46 | .doorbell_mode_switch = false, |
47 | .auto_queue = false, |
48 | }, |
49 | { |
50 | .num = 20, |
51 | .name = "IPCR" , |
52 | .num_elements = 32, |
53 | .event_ring = 1, |
54 | .dir = DMA_TO_DEVICE, |
55 | .ee_mask = 0x4, |
56 | .pollcfg = 0, |
57 | .doorbell = MHI_DB_BRST_DISABLE, |
58 | .lpm_notify = false, |
59 | .offload_channel = false, |
60 | .doorbell_mode_switch = false, |
61 | .auto_queue = false, |
62 | }, |
63 | { |
64 | .num = 21, |
65 | .name = "IPCR" , |
66 | .num_elements = 32, |
67 | .event_ring = 1, |
68 | .dir = DMA_FROM_DEVICE, |
69 | .ee_mask = 0x4, |
70 | .pollcfg = 0, |
71 | .doorbell = MHI_DB_BRST_DISABLE, |
72 | .lpm_notify = false, |
73 | .offload_channel = false, |
74 | .doorbell_mode_switch = false, |
75 | .auto_queue = true, |
76 | }, |
77 | }; |
78 | |
79 | static struct mhi_event_config ath12k_mhi_events_qcn9274[] = { |
80 | { |
81 | .num_elements = 32, |
82 | .irq_moderation_ms = 0, |
83 | .irq = 1, |
84 | .data_type = MHI_ER_CTRL, |
85 | .mode = MHI_DB_BRST_DISABLE, |
86 | .hardware_event = false, |
87 | .client_managed = false, |
88 | .offload_channel = false, |
89 | }, |
90 | { |
91 | .num_elements = 256, |
92 | .irq_moderation_ms = 1, |
93 | .irq = 2, |
94 | .mode = MHI_DB_BRST_DISABLE, |
95 | .priority = 1, |
96 | .hardware_event = false, |
97 | .client_managed = false, |
98 | .offload_channel = false, |
99 | }, |
100 | }; |
101 | |
102 | const struct mhi_controller_config ath12k_mhi_config_qcn9274 = { |
103 | .max_channels = 30, |
104 | .timeout_ms = 10000, |
105 | .use_bounce_buf = false, |
106 | .buf_len = 0, |
107 | .num_channels = ARRAY_SIZE(ath12k_mhi_channels_qcn9274), |
108 | .ch_cfg = ath12k_mhi_channels_qcn9274, |
109 | .num_events = ARRAY_SIZE(ath12k_mhi_events_qcn9274), |
110 | .event_cfg = ath12k_mhi_events_qcn9274, |
111 | }; |
112 | |
113 | static const struct mhi_channel_config ath12k_mhi_channels_wcn7850[] = { |
114 | { |
115 | .num = 0, |
116 | .name = "LOOPBACK" , |
117 | .num_elements = 32, |
118 | .event_ring = 0, |
119 | .dir = DMA_TO_DEVICE, |
120 | .ee_mask = 0x4, |
121 | .pollcfg = 0, |
122 | .doorbell = MHI_DB_BRST_DISABLE, |
123 | .lpm_notify = false, |
124 | .offload_channel = false, |
125 | .doorbell_mode_switch = false, |
126 | .auto_queue = false, |
127 | }, |
128 | { |
129 | .num = 1, |
130 | .name = "LOOPBACK" , |
131 | .num_elements = 32, |
132 | .event_ring = 0, |
133 | .dir = DMA_FROM_DEVICE, |
134 | .ee_mask = 0x4, |
135 | .pollcfg = 0, |
136 | .doorbell = MHI_DB_BRST_DISABLE, |
137 | .lpm_notify = false, |
138 | .offload_channel = false, |
139 | .doorbell_mode_switch = false, |
140 | .auto_queue = false, |
141 | }, |
142 | { |
143 | .num = 20, |
144 | .name = "IPCR" , |
145 | .num_elements = 64, |
146 | .event_ring = 1, |
147 | .dir = DMA_TO_DEVICE, |
148 | .ee_mask = 0x4, |
149 | .pollcfg = 0, |
150 | .doorbell = MHI_DB_BRST_DISABLE, |
151 | .lpm_notify = false, |
152 | .offload_channel = false, |
153 | .doorbell_mode_switch = false, |
154 | .auto_queue = false, |
155 | }, |
156 | { |
157 | .num = 21, |
158 | .name = "IPCR" , |
159 | .num_elements = 64, |
160 | .event_ring = 1, |
161 | .dir = DMA_FROM_DEVICE, |
162 | .ee_mask = 0x4, |
163 | .pollcfg = 0, |
164 | .doorbell = MHI_DB_BRST_DISABLE, |
165 | .lpm_notify = false, |
166 | .offload_channel = false, |
167 | .doorbell_mode_switch = false, |
168 | .auto_queue = true, |
169 | }, |
170 | }; |
171 | |
172 | static struct mhi_event_config ath12k_mhi_events_wcn7850[] = { |
173 | { |
174 | .num_elements = 32, |
175 | .irq_moderation_ms = 0, |
176 | .irq = 1, |
177 | .mode = MHI_DB_BRST_DISABLE, |
178 | .data_type = MHI_ER_CTRL, |
179 | .hardware_event = false, |
180 | .client_managed = false, |
181 | .offload_channel = false, |
182 | }, |
183 | { |
184 | .num_elements = 256, |
185 | .irq_moderation_ms = 1, |
186 | .irq = 2, |
187 | .mode = MHI_DB_BRST_DISABLE, |
188 | .priority = 1, |
189 | .hardware_event = false, |
190 | .client_managed = false, |
191 | .offload_channel = false, |
192 | }, |
193 | }; |
194 | |
195 | const struct mhi_controller_config ath12k_mhi_config_wcn7850 = { |
196 | .max_channels = 128, |
197 | .timeout_ms = 2000, |
198 | .use_bounce_buf = false, |
199 | .buf_len = 0, |
200 | .num_channels = ARRAY_SIZE(ath12k_mhi_channels_wcn7850), |
201 | .ch_cfg = ath12k_mhi_channels_wcn7850, |
202 | .num_events = ARRAY_SIZE(ath12k_mhi_events_wcn7850), |
203 | .event_cfg = ath12k_mhi_events_wcn7850, |
204 | }; |
205 | |
206 | void ath12k_mhi_set_mhictrl_reset(struct ath12k_base *ab) |
207 | { |
208 | u32 val; |
209 | |
210 | val = ath12k_pci_read32(ab, MHISTATUS); |
211 | |
212 | ath12k_dbg(ab, ATH12K_DBG_PCI, "MHISTATUS 0x%x\n" , val); |
213 | |
214 | /* Observed on some targets that after SOC_GLOBAL_RESET, MHISTATUS |
215 | * has SYSERR bit set and thus need to set MHICTRL_RESET |
216 | * to clear SYSERR. |
217 | */ |
218 | ath12k_pci_write32(ab, MHICTRL, MHICTRL_RESET_MASK); |
219 | |
220 | mdelay(10); |
221 | } |
222 | |
223 | static void ath12k_mhi_reset_txvecdb(struct ath12k_base *ab) |
224 | { |
225 | ath12k_pci_write32(ab, PCIE_TXVECDB, value: 0); |
226 | } |
227 | |
228 | static void ath12k_mhi_reset_txvecstatus(struct ath12k_base *ab) |
229 | { |
230 | ath12k_pci_write32(ab, PCIE_TXVECSTATUS, value: 0); |
231 | } |
232 | |
233 | static void ath12k_mhi_reset_rxvecdb(struct ath12k_base *ab) |
234 | { |
235 | ath12k_pci_write32(ab, PCIE_RXVECDB, value: 0); |
236 | } |
237 | |
238 | static void ath12k_mhi_reset_rxvecstatus(struct ath12k_base *ab) |
239 | { |
240 | ath12k_pci_write32(ab, PCIE_RXVECSTATUS, value: 0); |
241 | } |
242 | |
243 | void ath12k_mhi_clear_vector(struct ath12k_base *ab) |
244 | { |
245 | ath12k_mhi_reset_txvecdb(ab); |
246 | ath12k_mhi_reset_txvecstatus(ab); |
247 | ath12k_mhi_reset_rxvecdb(ab); |
248 | ath12k_mhi_reset_rxvecstatus(ab); |
249 | } |
250 | |
251 | static int ath12k_mhi_get_msi(struct ath12k_pci *ab_pci) |
252 | { |
253 | struct ath12k_base *ab = ab_pci->ab; |
254 | u32 user_base_data, base_vector; |
255 | int ret, num_vectors, i; |
256 | int *irq; |
257 | unsigned int msi_data; |
258 | |
259 | ret = ath12k_pci_get_user_msi_assignment(ab, |
260 | user_name: "MHI" , num_vectors: &num_vectors, |
261 | user_base_data: &user_base_data, base_vector: &base_vector); |
262 | if (ret) |
263 | return ret; |
264 | |
265 | ath12k_dbg(ab, ATH12K_DBG_PCI, "Number of assigned MSI for MHI is %d, base vector is %d\n" , |
266 | num_vectors, base_vector); |
267 | |
268 | irq = kcalloc(n: num_vectors, size: sizeof(*irq), GFP_KERNEL); |
269 | if (!irq) |
270 | return -ENOMEM; |
271 | |
272 | msi_data = base_vector; |
273 | for (i = 0; i < num_vectors; i++) { |
274 | if (test_bit(ATH12K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags)) |
275 | irq[i] = ath12k_pci_get_msi_irq(dev: ab->dev, |
276 | vector: msi_data++); |
277 | else |
278 | irq[i] = ath12k_pci_get_msi_irq(dev: ab->dev, |
279 | vector: msi_data); |
280 | } |
281 | |
282 | ab_pci->mhi_ctrl->irq = irq; |
283 | ab_pci->mhi_ctrl->nr_irqs = num_vectors; |
284 | |
285 | return 0; |
286 | } |
287 | |
288 | static int ath12k_mhi_op_runtime_get(struct mhi_controller *mhi_cntrl) |
289 | { |
290 | return 0; |
291 | } |
292 | |
293 | static void ath12k_mhi_op_runtime_put(struct mhi_controller *mhi_cntrl) |
294 | { |
295 | } |
296 | |
297 | static char *ath12k_mhi_op_callback_to_str(enum mhi_callback reason) |
298 | { |
299 | switch (reason) { |
300 | case MHI_CB_IDLE: |
301 | return "MHI_CB_IDLE" ; |
302 | case MHI_CB_PENDING_DATA: |
303 | return "MHI_CB_PENDING_DATA" ; |
304 | case MHI_CB_LPM_ENTER: |
305 | return "MHI_CB_LPM_ENTER" ; |
306 | case MHI_CB_LPM_EXIT: |
307 | return "MHI_CB_LPM_EXIT" ; |
308 | case MHI_CB_EE_RDDM: |
309 | return "MHI_CB_EE_RDDM" ; |
310 | case MHI_CB_EE_MISSION_MODE: |
311 | return "MHI_CB_EE_MISSION_MODE" ; |
312 | case MHI_CB_SYS_ERROR: |
313 | return "MHI_CB_SYS_ERROR" ; |
314 | case MHI_CB_FATAL_ERROR: |
315 | return "MHI_CB_FATAL_ERROR" ; |
316 | case MHI_CB_BW_REQ: |
317 | return "MHI_CB_BW_REQ" ; |
318 | default: |
319 | return "UNKNOWN" ; |
320 | } |
321 | } |
322 | |
323 | static void ath12k_mhi_op_status_cb(struct mhi_controller *mhi_cntrl, |
324 | enum mhi_callback cb) |
325 | { |
326 | struct ath12k_base *ab = dev_get_drvdata(dev: mhi_cntrl->cntrl_dev); |
327 | |
328 | ath12k_dbg(ab, ATH12K_DBG_BOOT, "mhi notify status reason %s\n" , |
329 | ath12k_mhi_op_callback_to_str(cb)); |
330 | |
331 | switch (cb) { |
332 | case MHI_CB_SYS_ERROR: |
333 | ath12k_warn(ab, fmt: "firmware crashed: MHI_CB_SYS_ERROR\n" ); |
334 | break; |
335 | case MHI_CB_EE_RDDM: |
336 | if (!(test_bit(ATH12K_FLAG_UNREGISTERING, &ab->dev_flags))) |
337 | queue_work(wq: ab->workqueue_aux, work: &ab->reset_work); |
338 | break; |
339 | default: |
340 | break; |
341 | } |
342 | } |
343 | |
344 | static int ath12k_mhi_op_read_reg(struct mhi_controller *mhi_cntrl, |
345 | void __iomem *addr, |
346 | u32 *out) |
347 | { |
348 | *out = readl(addr); |
349 | |
350 | return 0; |
351 | } |
352 | |
353 | static void ath12k_mhi_op_write_reg(struct mhi_controller *mhi_cntrl, |
354 | void __iomem *addr, |
355 | u32 val) |
356 | { |
357 | writel(val, addr); |
358 | } |
359 | |
360 | int ath12k_mhi_register(struct ath12k_pci *ab_pci) |
361 | { |
362 | struct ath12k_base *ab = ab_pci->ab; |
363 | struct mhi_controller *mhi_ctrl; |
364 | unsigned int board_id; |
365 | int ret; |
366 | bool dualmac = false; |
367 | |
368 | mhi_ctrl = mhi_alloc_controller(); |
369 | if (!mhi_ctrl) |
370 | return -ENOMEM; |
371 | |
372 | ab_pci->mhi_ctrl = mhi_ctrl; |
373 | mhi_ctrl->cntrl_dev = ab->dev; |
374 | mhi_ctrl->regs = ab->mem; |
375 | mhi_ctrl->reg_len = ab->mem_len; |
376 | mhi_ctrl->rddm_size = ab->hw_params->rddm_size; |
377 | |
378 | if (ab->hw_params->otp_board_id_register) { |
379 | board_id = |
380 | ath12k_pci_read32(ab, offset: ab->hw_params->otp_board_id_register); |
381 | board_id = u32_get_bits(v: board_id, OTP_BOARD_ID_MASK); |
382 | |
383 | if (!board_id || (board_id == OTP_INVALID_BOARD_ID)) { |
384 | ath12k_dbg(ab, ATH12K_DBG_BOOT, |
385 | "failed to read board id\n" ); |
386 | } else if (board_id & OTP_VALID_DUALMAC_BOARD_ID_MASK) { |
387 | dualmac = true; |
388 | ab->slo_capable = false; |
389 | ath12k_dbg(ab, ATH12K_DBG_BOOT, |
390 | "dualmac fw selected for board id: %x\n" , board_id); |
391 | } |
392 | } |
393 | |
394 | if (dualmac) { |
395 | if (ab->fw.amss_dualmac_data && ab->fw.amss_dualmac_len > 0) { |
396 | /* use MHI firmware file from firmware-N.bin */ |
397 | mhi_ctrl->fw_data = ab->fw.amss_dualmac_data; |
398 | mhi_ctrl->fw_sz = ab->fw.amss_dualmac_len; |
399 | } else { |
400 | ath12k_warn(ab, fmt: "dualmac firmware IE not present in firmware-N.bin\n" ); |
401 | ret = -ENOENT; |
402 | goto free_controller; |
403 | } |
404 | } else { |
405 | if (ab->fw.amss_data && ab->fw.amss_len > 0) { |
406 | /* use MHI firmware file from firmware-N.bin */ |
407 | mhi_ctrl->fw_data = ab->fw.amss_data; |
408 | mhi_ctrl->fw_sz = ab->fw.amss_len; |
409 | } else { |
410 | /* use the old separate mhi.bin MHI firmware file */ |
411 | ath12k_core_create_firmware_path(ab, ATH12K_AMSS_FILE, |
412 | buf: ab_pci->amss_path, |
413 | buf_len: sizeof(ab_pci->amss_path)); |
414 | mhi_ctrl->fw_image = ab_pci->amss_path; |
415 | } |
416 | } |
417 | |
418 | ret = ath12k_mhi_get_msi(ab_pci); |
419 | if (ret) { |
420 | ath12k_err(ab, fmt: "failed to get msi for mhi\n" ); |
421 | goto free_controller; |
422 | } |
423 | |
424 | if (!test_bit(ATH12K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags)) |
425 | mhi_ctrl->irq_flags = IRQF_SHARED | IRQF_NOBALANCING; |
426 | |
427 | mhi_ctrl->iova_start = 0; |
428 | mhi_ctrl->iova_stop = 0xffffffff; |
429 | mhi_ctrl->sbl_size = SZ_512K; |
430 | mhi_ctrl->seg_len = SZ_512K; |
431 | mhi_ctrl->fbc_download = true; |
432 | mhi_ctrl->runtime_get = ath12k_mhi_op_runtime_get; |
433 | mhi_ctrl->runtime_put = ath12k_mhi_op_runtime_put; |
434 | mhi_ctrl->status_cb = ath12k_mhi_op_status_cb; |
435 | mhi_ctrl->read_reg = ath12k_mhi_op_read_reg; |
436 | mhi_ctrl->write_reg = ath12k_mhi_op_write_reg; |
437 | |
438 | ret = mhi_register_controller(mhi_cntrl: mhi_ctrl, config: ab->hw_params->mhi_config); |
439 | if (ret) { |
440 | ath12k_err(ab, fmt: "failed to register to mhi bus, err = %d\n" , ret); |
441 | goto free_controller; |
442 | } |
443 | |
444 | return 0; |
445 | |
446 | free_controller: |
447 | mhi_free_controller(mhi_cntrl: mhi_ctrl); |
448 | ab_pci->mhi_ctrl = NULL; |
449 | return ret; |
450 | } |
451 | |
452 | void ath12k_mhi_unregister(struct ath12k_pci *ab_pci) |
453 | { |
454 | struct mhi_controller *mhi_ctrl = ab_pci->mhi_ctrl; |
455 | |
456 | mhi_unregister_controller(mhi_cntrl: mhi_ctrl); |
457 | kfree(objp: mhi_ctrl->irq); |
458 | mhi_free_controller(mhi_cntrl: mhi_ctrl); |
459 | ab_pci->mhi_ctrl = NULL; |
460 | } |
461 | |
462 | static char *ath12k_mhi_state_to_str(enum ath12k_mhi_state mhi_state) |
463 | { |
464 | switch (mhi_state) { |
465 | case ATH12K_MHI_INIT: |
466 | return "INIT" ; |
467 | case ATH12K_MHI_DEINIT: |
468 | return "DEINIT" ; |
469 | case ATH12K_MHI_POWER_ON: |
470 | return "POWER_ON" ; |
471 | case ATH12K_MHI_POWER_OFF: |
472 | return "POWER_OFF" ; |
473 | case ATH12K_MHI_FORCE_POWER_OFF: |
474 | return "FORCE_POWER_OFF" ; |
475 | case ATH12K_MHI_SUSPEND: |
476 | return "SUSPEND" ; |
477 | case ATH12K_MHI_RESUME: |
478 | return "RESUME" ; |
479 | case ATH12K_MHI_TRIGGER_RDDM: |
480 | return "TRIGGER_RDDM" ; |
481 | case ATH12K_MHI_RDDM_DONE: |
482 | return "RDDM_DONE" ; |
483 | default: |
484 | return "UNKNOWN" ; |
485 | } |
486 | }; |
487 | |
488 | static void ath12k_mhi_set_state_bit(struct ath12k_pci *ab_pci, |
489 | enum ath12k_mhi_state mhi_state) |
490 | { |
491 | struct ath12k_base *ab = ab_pci->ab; |
492 | |
493 | switch (mhi_state) { |
494 | case ATH12K_MHI_INIT: |
495 | set_bit(nr: ATH12K_MHI_INIT, addr: &ab_pci->mhi_state); |
496 | break; |
497 | case ATH12K_MHI_DEINIT: |
498 | clear_bit(nr: ATH12K_MHI_INIT, addr: &ab_pci->mhi_state); |
499 | break; |
500 | case ATH12K_MHI_POWER_ON: |
501 | set_bit(nr: ATH12K_MHI_POWER_ON, addr: &ab_pci->mhi_state); |
502 | break; |
503 | case ATH12K_MHI_POWER_OFF: |
504 | case ATH12K_MHI_FORCE_POWER_OFF: |
505 | clear_bit(nr: ATH12K_MHI_POWER_ON, addr: &ab_pci->mhi_state); |
506 | clear_bit(nr: ATH12K_MHI_TRIGGER_RDDM, addr: &ab_pci->mhi_state); |
507 | clear_bit(nr: ATH12K_MHI_RDDM_DONE, addr: &ab_pci->mhi_state); |
508 | break; |
509 | case ATH12K_MHI_SUSPEND: |
510 | set_bit(nr: ATH12K_MHI_SUSPEND, addr: &ab_pci->mhi_state); |
511 | break; |
512 | case ATH12K_MHI_RESUME: |
513 | clear_bit(nr: ATH12K_MHI_SUSPEND, addr: &ab_pci->mhi_state); |
514 | break; |
515 | case ATH12K_MHI_TRIGGER_RDDM: |
516 | set_bit(nr: ATH12K_MHI_TRIGGER_RDDM, addr: &ab_pci->mhi_state); |
517 | break; |
518 | case ATH12K_MHI_RDDM_DONE: |
519 | set_bit(nr: ATH12K_MHI_RDDM_DONE, addr: &ab_pci->mhi_state); |
520 | break; |
521 | default: |
522 | ath12k_err(ab, fmt: "unhandled mhi state (%d)\n" , mhi_state); |
523 | } |
524 | } |
525 | |
526 | static int ath12k_mhi_check_state_bit(struct ath12k_pci *ab_pci, |
527 | enum ath12k_mhi_state mhi_state) |
528 | { |
529 | struct ath12k_base *ab = ab_pci->ab; |
530 | |
531 | switch (mhi_state) { |
532 | case ATH12K_MHI_INIT: |
533 | if (!test_bit(ATH12K_MHI_INIT, &ab_pci->mhi_state)) |
534 | return 0; |
535 | break; |
536 | case ATH12K_MHI_DEINIT: |
537 | case ATH12K_MHI_POWER_ON: |
538 | if (test_bit(ATH12K_MHI_INIT, &ab_pci->mhi_state) && |
539 | !test_bit(ATH12K_MHI_POWER_ON, &ab_pci->mhi_state)) |
540 | return 0; |
541 | break; |
542 | case ATH12K_MHI_FORCE_POWER_OFF: |
543 | if (test_bit(ATH12K_MHI_POWER_ON, &ab_pci->mhi_state)) |
544 | return 0; |
545 | break; |
546 | case ATH12K_MHI_POWER_OFF: |
547 | case ATH12K_MHI_SUSPEND: |
548 | if (test_bit(ATH12K_MHI_POWER_ON, &ab_pci->mhi_state) && |
549 | !test_bit(ATH12K_MHI_SUSPEND, &ab_pci->mhi_state)) |
550 | return 0; |
551 | break; |
552 | case ATH12K_MHI_RESUME: |
553 | if (test_bit(ATH12K_MHI_SUSPEND, &ab_pci->mhi_state)) |
554 | return 0; |
555 | break; |
556 | case ATH12K_MHI_TRIGGER_RDDM: |
557 | if (test_bit(ATH12K_MHI_POWER_ON, &ab_pci->mhi_state) && |
558 | !test_bit(ATH12K_MHI_TRIGGER_RDDM, &ab_pci->mhi_state)) |
559 | return 0; |
560 | break; |
561 | case ATH12K_MHI_RDDM_DONE: |
562 | return 0; |
563 | default: |
564 | ath12k_err(ab, fmt: "unhandled mhi state: %s(%d)\n" , |
565 | ath12k_mhi_state_to_str(mhi_state), mhi_state); |
566 | } |
567 | |
568 | ath12k_err(ab, fmt: "failed to set mhi state %s(%d) in current mhi state (0x%lx)\n" , |
569 | ath12k_mhi_state_to_str(mhi_state), mhi_state, |
570 | ab_pci->mhi_state); |
571 | |
572 | return -EINVAL; |
573 | } |
574 | |
575 | static int ath12k_mhi_set_state(struct ath12k_pci *ab_pci, |
576 | enum ath12k_mhi_state mhi_state) |
577 | { |
578 | struct ath12k_base *ab = ab_pci->ab; |
579 | int ret; |
580 | |
581 | ret = ath12k_mhi_check_state_bit(ab_pci, mhi_state); |
582 | if (ret) |
583 | goto out; |
584 | |
585 | ath12k_dbg(ab, ATH12K_DBG_PCI, "setting mhi state: %s(%d)\n" , |
586 | ath12k_mhi_state_to_str(mhi_state), mhi_state); |
587 | |
588 | switch (mhi_state) { |
589 | case ATH12K_MHI_INIT: |
590 | ret = mhi_prepare_for_power_up(mhi_cntrl: ab_pci->mhi_ctrl); |
591 | break; |
592 | case ATH12K_MHI_DEINIT: |
593 | mhi_unprepare_after_power_down(mhi_cntrl: ab_pci->mhi_ctrl); |
594 | ret = 0; |
595 | break; |
596 | case ATH12K_MHI_POWER_ON: |
597 | ret = mhi_async_power_up(mhi_cntrl: ab_pci->mhi_ctrl); |
598 | break; |
599 | case ATH12K_MHI_POWER_OFF: |
600 | mhi_power_down(mhi_cntrl: ab_pci->mhi_ctrl, graceful: true); |
601 | ret = 0; |
602 | break; |
603 | case ATH12K_MHI_FORCE_POWER_OFF: |
604 | mhi_power_down(mhi_cntrl: ab_pci->mhi_ctrl, graceful: false); |
605 | ret = 0; |
606 | break; |
607 | case ATH12K_MHI_SUSPEND: |
608 | ret = mhi_pm_suspend(mhi_cntrl: ab_pci->mhi_ctrl); |
609 | break; |
610 | case ATH12K_MHI_RESUME: |
611 | ret = mhi_pm_resume(mhi_cntrl: ab_pci->mhi_ctrl); |
612 | break; |
613 | case ATH12K_MHI_TRIGGER_RDDM: |
614 | ret = mhi_force_rddm_mode(mhi_cntrl: ab_pci->mhi_ctrl); |
615 | break; |
616 | case ATH12K_MHI_RDDM_DONE: |
617 | break; |
618 | default: |
619 | ath12k_err(ab, fmt: "unhandled MHI state (%d)\n" , mhi_state); |
620 | ret = -EINVAL; |
621 | } |
622 | |
623 | if (ret) |
624 | goto out; |
625 | |
626 | ath12k_mhi_set_state_bit(ab_pci, mhi_state); |
627 | |
628 | return 0; |
629 | |
630 | out: |
631 | ath12k_err(ab, fmt: "failed to set mhi state: %s(%d)\n" , |
632 | ath12k_mhi_state_to_str(mhi_state), mhi_state); |
633 | return ret; |
634 | } |
635 | |
636 | int ath12k_mhi_start(struct ath12k_pci *ab_pci) |
637 | { |
638 | int ret; |
639 | |
640 | ab_pci->mhi_ctrl->timeout_ms = MHI_TIMEOUT_DEFAULT_MS; |
641 | |
642 | ret = ath12k_mhi_set_state(ab_pci, mhi_state: ATH12K_MHI_INIT); |
643 | if (ret) |
644 | goto out; |
645 | |
646 | ret = ath12k_mhi_set_state(ab_pci, mhi_state: ATH12K_MHI_POWER_ON); |
647 | if (ret) |
648 | goto out; |
649 | |
650 | return 0; |
651 | |
652 | out: |
653 | return ret; |
654 | } |
655 | |
656 | void ath12k_mhi_stop(struct ath12k_pci *ab_pci) |
657 | { |
658 | ath12k_mhi_set_state(ab_pci, mhi_state: ATH12K_MHI_POWER_OFF); |
659 | ath12k_mhi_set_state(ab_pci, mhi_state: ATH12K_MHI_DEINIT); |
660 | } |
661 | |
662 | void ath12k_mhi_suspend(struct ath12k_pci *ab_pci) |
663 | { |
664 | ath12k_mhi_set_state(ab_pci, mhi_state: ATH12K_MHI_SUSPEND); |
665 | } |
666 | |
667 | void ath12k_mhi_resume(struct ath12k_pci *ab_pci) |
668 | { |
669 | ath12k_mhi_set_state(ab_pci, mhi_state: ATH12K_MHI_RESUME); |
670 | } |
671 | |