File Index
Files and directories
Sign in
FILE

mhi.c

File preview with syntax highlighting.

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