162306a36Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause-Clear
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (c) 2020-2021 The Linux Foundation. All rights reserved.
462306a36Sopenharmony_ci * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include <linux/msi.h>
862306a36Sopenharmony_ci#include <linux/pci.h>
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include "core.h"
1162306a36Sopenharmony_ci#include "debug.h"
1262306a36Sopenharmony_ci#include "mhi.h"
1362306a36Sopenharmony_ci#include "pci.h"
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#define MHI_TIMEOUT_DEFAULT_MS	90000
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_cistatic const struct mhi_channel_config ath12k_mhi_channels_qcn9274[] = {
1862306a36Sopenharmony_ci	{
1962306a36Sopenharmony_ci		.num = 0,
2062306a36Sopenharmony_ci		.name = "LOOPBACK",
2162306a36Sopenharmony_ci		.num_elements = 32,
2262306a36Sopenharmony_ci		.event_ring = 1,
2362306a36Sopenharmony_ci		.dir = DMA_TO_DEVICE,
2462306a36Sopenharmony_ci		.ee_mask = 0x4,
2562306a36Sopenharmony_ci		.pollcfg = 0,
2662306a36Sopenharmony_ci		.doorbell = MHI_DB_BRST_DISABLE,
2762306a36Sopenharmony_ci		.lpm_notify = false,
2862306a36Sopenharmony_ci		.offload_channel = false,
2962306a36Sopenharmony_ci		.doorbell_mode_switch = false,
3062306a36Sopenharmony_ci		.auto_queue = false,
3162306a36Sopenharmony_ci	},
3262306a36Sopenharmony_ci	{
3362306a36Sopenharmony_ci		.num = 1,
3462306a36Sopenharmony_ci		.name = "LOOPBACK",
3562306a36Sopenharmony_ci		.num_elements = 32,
3662306a36Sopenharmony_ci		.event_ring = 1,
3762306a36Sopenharmony_ci		.dir = DMA_FROM_DEVICE,
3862306a36Sopenharmony_ci		.ee_mask = 0x4,
3962306a36Sopenharmony_ci		.pollcfg = 0,
4062306a36Sopenharmony_ci		.doorbell = MHI_DB_BRST_DISABLE,
4162306a36Sopenharmony_ci		.lpm_notify = false,
4262306a36Sopenharmony_ci		.offload_channel = false,
4362306a36Sopenharmony_ci		.doorbell_mode_switch = false,
4462306a36Sopenharmony_ci		.auto_queue = false,
4562306a36Sopenharmony_ci	},
4662306a36Sopenharmony_ci	{
4762306a36Sopenharmony_ci		.num = 20,
4862306a36Sopenharmony_ci		.name = "IPCR",
4962306a36Sopenharmony_ci		.num_elements = 32,
5062306a36Sopenharmony_ci		.event_ring = 1,
5162306a36Sopenharmony_ci		.dir = DMA_TO_DEVICE,
5262306a36Sopenharmony_ci		.ee_mask = 0x4,
5362306a36Sopenharmony_ci		.pollcfg = 0,
5462306a36Sopenharmony_ci		.doorbell = MHI_DB_BRST_DISABLE,
5562306a36Sopenharmony_ci		.lpm_notify = false,
5662306a36Sopenharmony_ci		.offload_channel = false,
5762306a36Sopenharmony_ci		.doorbell_mode_switch = false,
5862306a36Sopenharmony_ci		.auto_queue = false,
5962306a36Sopenharmony_ci	},
6062306a36Sopenharmony_ci	{
6162306a36Sopenharmony_ci		.num = 21,
6262306a36Sopenharmony_ci		.name = "IPCR",
6362306a36Sopenharmony_ci		.num_elements = 32,
6462306a36Sopenharmony_ci		.event_ring = 1,
6562306a36Sopenharmony_ci		.dir = DMA_FROM_DEVICE,
6662306a36Sopenharmony_ci		.ee_mask = 0x4,
6762306a36Sopenharmony_ci		.pollcfg = 0,
6862306a36Sopenharmony_ci		.doorbell = MHI_DB_BRST_DISABLE,
6962306a36Sopenharmony_ci		.lpm_notify = false,
7062306a36Sopenharmony_ci		.offload_channel = false,
7162306a36Sopenharmony_ci		.doorbell_mode_switch = false,
7262306a36Sopenharmony_ci		.auto_queue = true,
7362306a36Sopenharmony_ci	},
7462306a36Sopenharmony_ci};
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_cistatic struct mhi_event_config ath12k_mhi_events_qcn9274[] = {
7762306a36Sopenharmony_ci	{
7862306a36Sopenharmony_ci		.num_elements = 32,
7962306a36Sopenharmony_ci		.irq_moderation_ms = 0,
8062306a36Sopenharmony_ci		.irq = 1,
8162306a36Sopenharmony_ci		.data_type = MHI_ER_CTRL,
8262306a36Sopenharmony_ci		.mode = MHI_DB_BRST_DISABLE,
8362306a36Sopenharmony_ci		.hardware_event = false,
8462306a36Sopenharmony_ci		.client_managed = false,
8562306a36Sopenharmony_ci		.offload_channel = false,
8662306a36Sopenharmony_ci	},
8762306a36Sopenharmony_ci	{
8862306a36Sopenharmony_ci		.num_elements = 256,
8962306a36Sopenharmony_ci		.irq_moderation_ms = 1,
9062306a36Sopenharmony_ci		.irq = 2,
9162306a36Sopenharmony_ci		.mode = MHI_DB_BRST_DISABLE,
9262306a36Sopenharmony_ci		.priority = 1,
9362306a36Sopenharmony_ci		.hardware_event = false,
9462306a36Sopenharmony_ci		.client_managed = false,
9562306a36Sopenharmony_ci		.offload_channel = false,
9662306a36Sopenharmony_ci	},
9762306a36Sopenharmony_ci};
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ciconst struct mhi_controller_config ath12k_mhi_config_qcn9274 = {
10062306a36Sopenharmony_ci	.max_channels = 30,
10162306a36Sopenharmony_ci	.timeout_ms = 10000,
10262306a36Sopenharmony_ci	.use_bounce_buf = false,
10362306a36Sopenharmony_ci	.buf_len = 0,
10462306a36Sopenharmony_ci	.num_channels = ARRAY_SIZE(ath12k_mhi_channels_qcn9274),
10562306a36Sopenharmony_ci	.ch_cfg = ath12k_mhi_channels_qcn9274,
10662306a36Sopenharmony_ci	.num_events = ARRAY_SIZE(ath12k_mhi_events_qcn9274),
10762306a36Sopenharmony_ci	.event_cfg = ath12k_mhi_events_qcn9274,
10862306a36Sopenharmony_ci};
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_cistatic const struct mhi_channel_config ath12k_mhi_channels_wcn7850[] = {
11162306a36Sopenharmony_ci	{
11262306a36Sopenharmony_ci		.num = 0,
11362306a36Sopenharmony_ci		.name = "LOOPBACK",
11462306a36Sopenharmony_ci		.num_elements = 32,
11562306a36Sopenharmony_ci		.event_ring = 0,
11662306a36Sopenharmony_ci		.dir = DMA_TO_DEVICE,
11762306a36Sopenharmony_ci		.ee_mask = 0x4,
11862306a36Sopenharmony_ci		.pollcfg = 0,
11962306a36Sopenharmony_ci		.doorbell = MHI_DB_BRST_DISABLE,
12062306a36Sopenharmony_ci		.lpm_notify = false,
12162306a36Sopenharmony_ci		.offload_channel = false,
12262306a36Sopenharmony_ci		.doorbell_mode_switch = false,
12362306a36Sopenharmony_ci		.auto_queue = false,
12462306a36Sopenharmony_ci	},
12562306a36Sopenharmony_ci	{
12662306a36Sopenharmony_ci		.num = 1,
12762306a36Sopenharmony_ci		.name = "LOOPBACK",
12862306a36Sopenharmony_ci		.num_elements = 32,
12962306a36Sopenharmony_ci		.event_ring = 0,
13062306a36Sopenharmony_ci		.dir = DMA_FROM_DEVICE,
13162306a36Sopenharmony_ci		.ee_mask = 0x4,
13262306a36Sopenharmony_ci		.pollcfg = 0,
13362306a36Sopenharmony_ci		.doorbell = MHI_DB_BRST_DISABLE,
13462306a36Sopenharmony_ci		.lpm_notify = false,
13562306a36Sopenharmony_ci		.offload_channel = false,
13662306a36Sopenharmony_ci		.doorbell_mode_switch = false,
13762306a36Sopenharmony_ci		.auto_queue = false,
13862306a36Sopenharmony_ci	},
13962306a36Sopenharmony_ci	{
14062306a36Sopenharmony_ci		.num = 20,
14162306a36Sopenharmony_ci		.name = "IPCR",
14262306a36Sopenharmony_ci		.num_elements = 64,
14362306a36Sopenharmony_ci		.event_ring = 1,
14462306a36Sopenharmony_ci		.dir = DMA_TO_DEVICE,
14562306a36Sopenharmony_ci		.ee_mask = 0x4,
14662306a36Sopenharmony_ci		.pollcfg = 0,
14762306a36Sopenharmony_ci		.doorbell = MHI_DB_BRST_DISABLE,
14862306a36Sopenharmony_ci		.lpm_notify = false,
14962306a36Sopenharmony_ci		.offload_channel = false,
15062306a36Sopenharmony_ci		.doorbell_mode_switch = false,
15162306a36Sopenharmony_ci		.auto_queue = false,
15262306a36Sopenharmony_ci	},
15362306a36Sopenharmony_ci	{
15462306a36Sopenharmony_ci		.num = 21,
15562306a36Sopenharmony_ci		.name = "IPCR",
15662306a36Sopenharmony_ci		.num_elements = 64,
15762306a36Sopenharmony_ci		.event_ring = 1,
15862306a36Sopenharmony_ci		.dir = DMA_FROM_DEVICE,
15962306a36Sopenharmony_ci		.ee_mask = 0x4,
16062306a36Sopenharmony_ci		.pollcfg = 0,
16162306a36Sopenharmony_ci		.doorbell = MHI_DB_BRST_DISABLE,
16262306a36Sopenharmony_ci		.lpm_notify = false,
16362306a36Sopenharmony_ci		.offload_channel = false,
16462306a36Sopenharmony_ci		.doorbell_mode_switch = false,
16562306a36Sopenharmony_ci		.auto_queue = true,
16662306a36Sopenharmony_ci	},
16762306a36Sopenharmony_ci};
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_cistatic struct mhi_event_config ath12k_mhi_events_wcn7850[] = {
17062306a36Sopenharmony_ci	{
17162306a36Sopenharmony_ci		.num_elements = 32,
17262306a36Sopenharmony_ci		.irq_moderation_ms = 0,
17362306a36Sopenharmony_ci		.irq = 1,
17462306a36Sopenharmony_ci		.mode = MHI_DB_BRST_DISABLE,
17562306a36Sopenharmony_ci		.data_type = MHI_ER_CTRL,
17662306a36Sopenharmony_ci		.hardware_event = false,
17762306a36Sopenharmony_ci		.client_managed = false,
17862306a36Sopenharmony_ci		.offload_channel = false,
17962306a36Sopenharmony_ci	},
18062306a36Sopenharmony_ci	{
18162306a36Sopenharmony_ci		.num_elements = 256,
18262306a36Sopenharmony_ci		.irq_moderation_ms = 1,
18362306a36Sopenharmony_ci		.irq = 2,
18462306a36Sopenharmony_ci		.mode = MHI_DB_BRST_DISABLE,
18562306a36Sopenharmony_ci		.priority = 1,
18662306a36Sopenharmony_ci		.hardware_event = false,
18762306a36Sopenharmony_ci		.client_managed = false,
18862306a36Sopenharmony_ci		.offload_channel = false,
18962306a36Sopenharmony_ci	},
19062306a36Sopenharmony_ci};
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ciconst struct mhi_controller_config ath12k_mhi_config_wcn7850 = {
19362306a36Sopenharmony_ci	.max_channels = 128,
19462306a36Sopenharmony_ci	.timeout_ms = 2000,
19562306a36Sopenharmony_ci	.use_bounce_buf = false,
19662306a36Sopenharmony_ci	.buf_len = 0,
19762306a36Sopenharmony_ci	.num_channels = ARRAY_SIZE(ath12k_mhi_channels_wcn7850),
19862306a36Sopenharmony_ci	.ch_cfg = ath12k_mhi_channels_wcn7850,
19962306a36Sopenharmony_ci	.num_events = ARRAY_SIZE(ath12k_mhi_events_wcn7850),
20062306a36Sopenharmony_ci	.event_cfg = ath12k_mhi_events_wcn7850,
20162306a36Sopenharmony_ci};
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_civoid ath12k_mhi_set_mhictrl_reset(struct ath12k_base *ab)
20462306a36Sopenharmony_ci{
20562306a36Sopenharmony_ci	u32 val;
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	val = ath12k_pci_read32(ab, MHISTATUS);
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	ath12k_dbg(ab, ATH12K_DBG_PCI, "MHISTATUS 0x%x\n", val);
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	/* Observed on some targets that after SOC_GLOBAL_RESET, MHISTATUS
21262306a36Sopenharmony_ci	 * has SYSERR bit set and thus need to set MHICTRL_RESET
21362306a36Sopenharmony_ci	 * to clear SYSERR.
21462306a36Sopenharmony_ci	 */
21562306a36Sopenharmony_ci	ath12k_pci_write32(ab, MHICTRL, MHICTRL_RESET_MASK);
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci	mdelay(10);
21862306a36Sopenharmony_ci}
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_cistatic void ath12k_mhi_reset_txvecdb(struct ath12k_base *ab)
22162306a36Sopenharmony_ci{
22262306a36Sopenharmony_ci	ath12k_pci_write32(ab, PCIE_TXVECDB, 0);
22362306a36Sopenharmony_ci}
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_cistatic void ath12k_mhi_reset_txvecstatus(struct ath12k_base *ab)
22662306a36Sopenharmony_ci{
22762306a36Sopenharmony_ci	ath12k_pci_write32(ab, PCIE_TXVECSTATUS, 0);
22862306a36Sopenharmony_ci}
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_cistatic void ath12k_mhi_reset_rxvecdb(struct ath12k_base *ab)
23162306a36Sopenharmony_ci{
23262306a36Sopenharmony_ci	ath12k_pci_write32(ab, PCIE_RXVECDB, 0);
23362306a36Sopenharmony_ci}
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_cistatic void ath12k_mhi_reset_rxvecstatus(struct ath12k_base *ab)
23662306a36Sopenharmony_ci{
23762306a36Sopenharmony_ci	ath12k_pci_write32(ab, PCIE_RXVECSTATUS, 0);
23862306a36Sopenharmony_ci}
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_civoid ath12k_mhi_clear_vector(struct ath12k_base *ab)
24162306a36Sopenharmony_ci{
24262306a36Sopenharmony_ci	ath12k_mhi_reset_txvecdb(ab);
24362306a36Sopenharmony_ci	ath12k_mhi_reset_txvecstatus(ab);
24462306a36Sopenharmony_ci	ath12k_mhi_reset_rxvecdb(ab);
24562306a36Sopenharmony_ci	ath12k_mhi_reset_rxvecstatus(ab);
24662306a36Sopenharmony_ci}
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_cistatic int ath12k_mhi_get_msi(struct ath12k_pci *ab_pci)
24962306a36Sopenharmony_ci{
25062306a36Sopenharmony_ci	struct ath12k_base *ab = ab_pci->ab;
25162306a36Sopenharmony_ci	u32 user_base_data, base_vector;
25262306a36Sopenharmony_ci	int ret, num_vectors, i;
25362306a36Sopenharmony_ci	int *irq;
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	ret = ath12k_pci_get_user_msi_assignment(ab,
25662306a36Sopenharmony_ci						 "MHI", &num_vectors,
25762306a36Sopenharmony_ci						 &user_base_data, &base_vector);
25862306a36Sopenharmony_ci	if (ret)
25962306a36Sopenharmony_ci		return ret;
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci	ath12k_dbg(ab, ATH12K_DBG_PCI, "Number of assigned MSI for MHI is %d, base vector is %d\n",
26262306a36Sopenharmony_ci		   num_vectors, base_vector);
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci	irq = kcalloc(num_vectors, sizeof(*irq), GFP_KERNEL);
26562306a36Sopenharmony_ci	if (!irq)
26662306a36Sopenharmony_ci		return -ENOMEM;
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	for (i = 0; i < num_vectors; i++)
26962306a36Sopenharmony_ci		irq[i] = ath12k_pci_get_msi_irq(ab->dev,
27062306a36Sopenharmony_ci						base_vector + i);
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci	ab_pci->mhi_ctrl->irq = irq;
27362306a36Sopenharmony_ci	ab_pci->mhi_ctrl->nr_irqs = num_vectors;
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	return 0;
27662306a36Sopenharmony_ci}
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_cistatic int ath12k_mhi_op_runtime_get(struct mhi_controller *mhi_cntrl)
27962306a36Sopenharmony_ci{
28062306a36Sopenharmony_ci	return 0;
28162306a36Sopenharmony_ci}
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_cistatic void ath12k_mhi_op_runtime_put(struct mhi_controller *mhi_cntrl)
28462306a36Sopenharmony_ci{
28562306a36Sopenharmony_ci}
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_cistatic char *ath12k_mhi_op_callback_to_str(enum mhi_callback reason)
28862306a36Sopenharmony_ci{
28962306a36Sopenharmony_ci	switch (reason) {
29062306a36Sopenharmony_ci	case MHI_CB_IDLE:
29162306a36Sopenharmony_ci		return "MHI_CB_IDLE";
29262306a36Sopenharmony_ci	case MHI_CB_PENDING_DATA:
29362306a36Sopenharmony_ci		return "MHI_CB_PENDING_DATA";
29462306a36Sopenharmony_ci	case MHI_CB_LPM_ENTER:
29562306a36Sopenharmony_ci		return "MHI_CB_LPM_ENTER";
29662306a36Sopenharmony_ci	case MHI_CB_LPM_EXIT:
29762306a36Sopenharmony_ci		return "MHI_CB_LPM_EXIT";
29862306a36Sopenharmony_ci	case MHI_CB_EE_RDDM:
29962306a36Sopenharmony_ci		return "MHI_CB_EE_RDDM";
30062306a36Sopenharmony_ci	case MHI_CB_EE_MISSION_MODE:
30162306a36Sopenharmony_ci		return "MHI_CB_EE_MISSION_MODE";
30262306a36Sopenharmony_ci	case MHI_CB_SYS_ERROR:
30362306a36Sopenharmony_ci		return "MHI_CB_SYS_ERROR";
30462306a36Sopenharmony_ci	case MHI_CB_FATAL_ERROR:
30562306a36Sopenharmony_ci		return "MHI_CB_FATAL_ERROR";
30662306a36Sopenharmony_ci	case MHI_CB_BW_REQ:
30762306a36Sopenharmony_ci		return "MHI_CB_BW_REQ";
30862306a36Sopenharmony_ci	default:
30962306a36Sopenharmony_ci		return "UNKNOWN";
31062306a36Sopenharmony_ci	}
31162306a36Sopenharmony_ci}
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_cistatic void ath12k_mhi_op_status_cb(struct mhi_controller *mhi_cntrl,
31462306a36Sopenharmony_ci				    enum mhi_callback cb)
31562306a36Sopenharmony_ci{
31662306a36Sopenharmony_ci	struct ath12k_base *ab = dev_get_drvdata(mhi_cntrl->cntrl_dev);
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	ath12k_dbg(ab, ATH12K_DBG_BOOT, "mhi notify status reason %s\n",
31962306a36Sopenharmony_ci		   ath12k_mhi_op_callback_to_str(cb));
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	switch (cb) {
32262306a36Sopenharmony_ci	case MHI_CB_SYS_ERROR:
32362306a36Sopenharmony_ci		ath12k_warn(ab, "firmware crashed: MHI_CB_SYS_ERROR\n");
32462306a36Sopenharmony_ci		break;
32562306a36Sopenharmony_ci	case MHI_CB_EE_RDDM:
32662306a36Sopenharmony_ci		if (!(test_bit(ATH12K_FLAG_UNREGISTERING, &ab->dev_flags)))
32762306a36Sopenharmony_ci			queue_work(ab->workqueue_aux, &ab->reset_work);
32862306a36Sopenharmony_ci		break;
32962306a36Sopenharmony_ci	default:
33062306a36Sopenharmony_ci		break;
33162306a36Sopenharmony_ci	}
33262306a36Sopenharmony_ci}
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_cistatic int ath12k_mhi_op_read_reg(struct mhi_controller *mhi_cntrl,
33562306a36Sopenharmony_ci				  void __iomem *addr,
33662306a36Sopenharmony_ci				  u32 *out)
33762306a36Sopenharmony_ci{
33862306a36Sopenharmony_ci	*out = readl(addr);
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	return 0;
34162306a36Sopenharmony_ci}
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_cistatic void ath12k_mhi_op_write_reg(struct mhi_controller *mhi_cntrl,
34462306a36Sopenharmony_ci				    void __iomem *addr,
34562306a36Sopenharmony_ci				    u32 val)
34662306a36Sopenharmony_ci{
34762306a36Sopenharmony_ci	writel(val, addr);
34862306a36Sopenharmony_ci}
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ciint ath12k_mhi_register(struct ath12k_pci *ab_pci)
35162306a36Sopenharmony_ci{
35262306a36Sopenharmony_ci	struct ath12k_base *ab = ab_pci->ab;
35362306a36Sopenharmony_ci	struct mhi_controller *mhi_ctrl;
35462306a36Sopenharmony_ci	int ret;
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	mhi_ctrl = mhi_alloc_controller();
35762306a36Sopenharmony_ci	if (!mhi_ctrl)
35862306a36Sopenharmony_ci		return -ENOMEM;
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci	ath12k_core_create_firmware_path(ab, ATH12K_AMSS_FILE,
36162306a36Sopenharmony_ci					 ab_pci->amss_path,
36262306a36Sopenharmony_ci					 sizeof(ab_pci->amss_path));
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	ab_pci->mhi_ctrl = mhi_ctrl;
36562306a36Sopenharmony_ci	mhi_ctrl->cntrl_dev = ab->dev;
36662306a36Sopenharmony_ci	mhi_ctrl->fw_image = ab_pci->amss_path;
36762306a36Sopenharmony_ci	mhi_ctrl->regs = ab->mem;
36862306a36Sopenharmony_ci	mhi_ctrl->reg_len = ab->mem_len;
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	ret = ath12k_mhi_get_msi(ab_pci);
37162306a36Sopenharmony_ci	if (ret) {
37262306a36Sopenharmony_ci		ath12k_err(ab, "failed to get msi for mhi\n");
37362306a36Sopenharmony_ci		goto free_controller;
37462306a36Sopenharmony_ci	}
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci	mhi_ctrl->iova_start = 0;
37762306a36Sopenharmony_ci	mhi_ctrl->iova_stop = 0xffffffff;
37862306a36Sopenharmony_ci	mhi_ctrl->sbl_size = SZ_512K;
37962306a36Sopenharmony_ci	mhi_ctrl->seg_len = SZ_512K;
38062306a36Sopenharmony_ci	mhi_ctrl->fbc_download = true;
38162306a36Sopenharmony_ci	mhi_ctrl->runtime_get = ath12k_mhi_op_runtime_get;
38262306a36Sopenharmony_ci	mhi_ctrl->runtime_put = ath12k_mhi_op_runtime_put;
38362306a36Sopenharmony_ci	mhi_ctrl->status_cb = ath12k_mhi_op_status_cb;
38462306a36Sopenharmony_ci	mhi_ctrl->read_reg = ath12k_mhi_op_read_reg;
38562306a36Sopenharmony_ci	mhi_ctrl->write_reg = ath12k_mhi_op_write_reg;
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	ret = mhi_register_controller(mhi_ctrl, ab->hw_params->mhi_config);
38862306a36Sopenharmony_ci	if (ret) {
38962306a36Sopenharmony_ci		ath12k_err(ab, "failed to register to mhi bus, err = %d\n", ret);
39062306a36Sopenharmony_ci		goto free_controller;
39162306a36Sopenharmony_ci	}
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci	return 0;
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_cifree_controller:
39662306a36Sopenharmony_ci	mhi_free_controller(mhi_ctrl);
39762306a36Sopenharmony_ci	ab_pci->mhi_ctrl = NULL;
39862306a36Sopenharmony_ci	return ret;
39962306a36Sopenharmony_ci}
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_civoid ath12k_mhi_unregister(struct ath12k_pci *ab_pci)
40262306a36Sopenharmony_ci{
40362306a36Sopenharmony_ci	struct mhi_controller *mhi_ctrl = ab_pci->mhi_ctrl;
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	mhi_unregister_controller(mhi_ctrl);
40662306a36Sopenharmony_ci	kfree(mhi_ctrl->irq);
40762306a36Sopenharmony_ci	mhi_free_controller(mhi_ctrl);
40862306a36Sopenharmony_ci	ab_pci->mhi_ctrl = NULL;
40962306a36Sopenharmony_ci}
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_cistatic char *ath12k_mhi_state_to_str(enum ath12k_mhi_state mhi_state)
41262306a36Sopenharmony_ci{
41362306a36Sopenharmony_ci	switch (mhi_state) {
41462306a36Sopenharmony_ci	case ATH12K_MHI_INIT:
41562306a36Sopenharmony_ci		return "INIT";
41662306a36Sopenharmony_ci	case ATH12K_MHI_DEINIT:
41762306a36Sopenharmony_ci		return "DEINIT";
41862306a36Sopenharmony_ci	case ATH12K_MHI_POWER_ON:
41962306a36Sopenharmony_ci		return "POWER_ON";
42062306a36Sopenharmony_ci	case ATH12K_MHI_POWER_OFF:
42162306a36Sopenharmony_ci		return "POWER_OFF";
42262306a36Sopenharmony_ci	case ATH12K_MHI_FORCE_POWER_OFF:
42362306a36Sopenharmony_ci		return "FORCE_POWER_OFF";
42462306a36Sopenharmony_ci	case ATH12K_MHI_SUSPEND:
42562306a36Sopenharmony_ci		return "SUSPEND";
42662306a36Sopenharmony_ci	case ATH12K_MHI_RESUME:
42762306a36Sopenharmony_ci		return "RESUME";
42862306a36Sopenharmony_ci	case ATH12K_MHI_TRIGGER_RDDM:
42962306a36Sopenharmony_ci		return "TRIGGER_RDDM";
43062306a36Sopenharmony_ci	case ATH12K_MHI_RDDM_DONE:
43162306a36Sopenharmony_ci		return "RDDM_DONE";
43262306a36Sopenharmony_ci	default:
43362306a36Sopenharmony_ci		return "UNKNOWN";
43462306a36Sopenharmony_ci	}
43562306a36Sopenharmony_ci};
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_cistatic void ath12k_mhi_set_state_bit(struct ath12k_pci *ab_pci,
43862306a36Sopenharmony_ci				     enum ath12k_mhi_state mhi_state)
43962306a36Sopenharmony_ci{
44062306a36Sopenharmony_ci	struct ath12k_base *ab = ab_pci->ab;
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci	switch (mhi_state) {
44362306a36Sopenharmony_ci	case ATH12K_MHI_INIT:
44462306a36Sopenharmony_ci		set_bit(ATH12K_MHI_INIT, &ab_pci->mhi_state);
44562306a36Sopenharmony_ci		break;
44662306a36Sopenharmony_ci	case ATH12K_MHI_DEINIT:
44762306a36Sopenharmony_ci		clear_bit(ATH12K_MHI_INIT, &ab_pci->mhi_state);
44862306a36Sopenharmony_ci		break;
44962306a36Sopenharmony_ci	case ATH12K_MHI_POWER_ON:
45062306a36Sopenharmony_ci		set_bit(ATH12K_MHI_POWER_ON, &ab_pci->mhi_state);
45162306a36Sopenharmony_ci		break;
45262306a36Sopenharmony_ci	case ATH12K_MHI_POWER_OFF:
45362306a36Sopenharmony_ci	case ATH12K_MHI_FORCE_POWER_OFF:
45462306a36Sopenharmony_ci		clear_bit(ATH12K_MHI_POWER_ON, &ab_pci->mhi_state);
45562306a36Sopenharmony_ci		clear_bit(ATH12K_MHI_TRIGGER_RDDM, &ab_pci->mhi_state);
45662306a36Sopenharmony_ci		clear_bit(ATH12K_MHI_RDDM_DONE, &ab_pci->mhi_state);
45762306a36Sopenharmony_ci		break;
45862306a36Sopenharmony_ci	case ATH12K_MHI_SUSPEND:
45962306a36Sopenharmony_ci		set_bit(ATH12K_MHI_SUSPEND, &ab_pci->mhi_state);
46062306a36Sopenharmony_ci		break;
46162306a36Sopenharmony_ci	case ATH12K_MHI_RESUME:
46262306a36Sopenharmony_ci		clear_bit(ATH12K_MHI_SUSPEND, &ab_pci->mhi_state);
46362306a36Sopenharmony_ci		break;
46462306a36Sopenharmony_ci	case ATH12K_MHI_TRIGGER_RDDM:
46562306a36Sopenharmony_ci		set_bit(ATH12K_MHI_TRIGGER_RDDM, &ab_pci->mhi_state);
46662306a36Sopenharmony_ci		break;
46762306a36Sopenharmony_ci	case ATH12K_MHI_RDDM_DONE:
46862306a36Sopenharmony_ci		set_bit(ATH12K_MHI_RDDM_DONE, &ab_pci->mhi_state);
46962306a36Sopenharmony_ci		break;
47062306a36Sopenharmony_ci	default:
47162306a36Sopenharmony_ci		ath12k_err(ab, "unhandled mhi state (%d)\n", mhi_state);
47262306a36Sopenharmony_ci	}
47362306a36Sopenharmony_ci}
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_cistatic int ath12k_mhi_check_state_bit(struct ath12k_pci *ab_pci,
47662306a36Sopenharmony_ci				      enum ath12k_mhi_state mhi_state)
47762306a36Sopenharmony_ci{
47862306a36Sopenharmony_ci	struct ath12k_base *ab = ab_pci->ab;
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci	switch (mhi_state) {
48162306a36Sopenharmony_ci	case ATH12K_MHI_INIT:
48262306a36Sopenharmony_ci		if (!test_bit(ATH12K_MHI_INIT, &ab_pci->mhi_state))
48362306a36Sopenharmony_ci			return 0;
48462306a36Sopenharmony_ci		break;
48562306a36Sopenharmony_ci	case ATH12K_MHI_DEINIT:
48662306a36Sopenharmony_ci	case ATH12K_MHI_POWER_ON:
48762306a36Sopenharmony_ci		if (test_bit(ATH12K_MHI_INIT, &ab_pci->mhi_state) &&
48862306a36Sopenharmony_ci		    !test_bit(ATH12K_MHI_POWER_ON, &ab_pci->mhi_state))
48962306a36Sopenharmony_ci			return 0;
49062306a36Sopenharmony_ci		break;
49162306a36Sopenharmony_ci	case ATH12K_MHI_FORCE_POWER_OFF:
49262306a36Sopenharmony_ci		if (test_bit(ATH12K_MHI_POWER_ON, &ab_pci->mhi_state))
49362306a36Sopenharmony_ci			return 0;
49462306a36Sopenharmony_ci		break;
49562306a36Sopenharmony_ci	case ATH12K_MHI_POWER_OFF:
49662306a36Sopenharmony_ci	case ATH12K_MHI_SUSPEND:
49762306a36Sopenharmony_ci		if (test_bit(ATH12K_MHI_POWER_ON, &ab_pci->mhi_state) &&
49862306a36Sopenharmony_ci		    !test_bit(ATH12K_MHI_SUSPEND, &ab_pci->mhi_state))
49962306a36Sopenharmony_ci			return 0;
50062306a36Sopenharmony_ci		break;
50162306a36Sopenharmony_ci	case ATH12K_MHI_RESUME:
50262306a36Sopenharmony_ci		if (test_bit(ATH12K_MHI_SUSPEND, &ab_pci->mhi_state))
50362306a36Sopenharmony_ci			return 0;
50462306a36Sopenharmony_ci		break;
50562306a36Sopenharmony_ci	case ATH12K_MHI_TRIGGER_RDDM:
50662306a36Sopenharmony_ci		if (test_bit(ATH12K_MHI_POWER_ON, &ab_pci->mhi_state) &&
50762306a36Sopenharmony_ci		    !test_bit(ATH12K_MHI_TRIGGER_RDDM, &ab_pci->mhi_state))
50862306a36Sopenharmony_ci			return 0;
50962306a36Sopenharmony_ci		break;
51062306a36Sopenharmony_ci	case ATH12K_MHI_RDDM_DONE:
51162306a36Sopenharmony_ci		return 0;
51262306a36Sopenharmony_ci	default:
51362306a36Sopenharmony_ci		ath12k_err(ab, "unhandled mhi state: %s(%d)\n",
51462306a36Sopenharmony_ci			   ath12k_mhi_state_to_str(mhi_state), mhi_state);
51562306a36Sopenharmony_ci	}
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci	ath12k_err(ab, "failed to set mhi state %s(%d) in current mhi state (0x%lx)\n",
51862306a36Sopenharmony_ci		   ath12k_mhi_state_to_str(mhi_state), mhi_state,
51962306a36Sopenharmony_ci		   ab_pci->mhi_state);
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci	return -EINVAL;
52262306a36Sopenharmony_ci}
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_cistatic int ath12k_mhi_set_state(struct ath12k_pci *ab_pci,
52562306a36Sopenharmony_ci				enum ath12k_mhi_state mhi_state)
52662306a36Sopenharmony_ci{
52762306a36Sopenharmony_ci	struct ath12k_base *ab = ab_pci->ab;
52862306a36Sopenharmony_ci	int ret;
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci	ret = ath12k_mhi_check_state_bit(ab_pci, mhi_state);
53162306a36Sopenharmony_ci	if (ret)
53262306a36Sopenharmony_ci		goto out;
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci	ath12k_dbg(ab, ATH12K_DBG_PCI, "setting mhi state: %s(%d)\n",
53562306a36Sopenharmony_ci		   ath12k_mhi_state_to_str(mhi_state), mhi_state);
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci	switch (mhi_state) {
53862306a36Sopenharmony_ci	case ATH12K_MHI_INIT:
53962306a36Sopenharmony_ci		ret = mhi_prepare_for_power_up(ab_pci->mhi_ctrl);
54062306a36Sopenharmony_ci		break;
54162306a36Sopenharmony_ci	case ATH12K_MHI_DEINIT:
54262306a36Sopenharmony_ci		mhi_unprepare_after_power_down(ab_pci->mhi_ctrl);
54362306a36Sopenharmony_ci		ret = 0;
54462306a36Sopenharmony_ci		break;
54562306a36Sopenharmony_ci	case ATH12K_MHI_POWER_ON:
54662306a36Sopenharmony_ci		ret = mhi_async_power_up(ab_pci->mhi_ctrl);
54762306a36Sopenharmony_ci		break;
54862306a36Sopenharmony_ci	case ATH12K_MHI_POWER_OFF:
54962306a36Sopenharmony_ci		mhi_power_down(ab_pci->mhi_ctrl, true);
55062306a36Sopenharmony_ci		ret = 0;
55162306a36Sopenharmony_ci		break;
55262306a36Sopenharmony_ci	case ATH12K_MHI_FORCE_POWER_OFF:
55362306a36Sopenharmony_ci		mhi_power_down(ab_pci->mhi_ctrl, false);
55462306a36Sopenharmony_ci		ret = 0;
55562306a36Sopenharmony_ci		break;
55662306a36Sopenharmony_ci	case ATH12K_MHI_SUSPEND:
55762306a36Sopenharmony_ci		ret = mhi_pm_suspend(ab_pci->mhi_ctrl);
55862306a36Sopenharmony_ci		break;
55962306a36Sopenharmony_ci	case ATH12K_MHI_RESUME:
56062306a36Sopenharmony_ci		ret = mhi_pm_resume(ab_pci->mhi_ctrl);
56162306a36Sopenharmony_ci		break;
56262306a36Sopenharmony_ci	case ATH12K_MHI_TRIGGER_RDDM:
56362306a36Sopenharmony_ci		ret = mhi_force_rddm_mode(ab_pci->mhi_ctrl);
56462306a36Sopenharmony_ci		break;
56562306a36Sopenharmony_ci	case ATH12K_MHI_RDDM_DONE:
56662306a36Sopenharmony_ci		break;
56762306a36Sopenharmony_ci	default:
56862306a36Sopenharmony_ci		ath12k_err(ab, "unhandled MHI state (%d)\n", mhi_state);
56962306a36Sopenharmony_ci		ret = -EINVAL;
57062306a36Sopenharmony_ci	}
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_ci	if (ret)
57362306a36Sopenharmony_ci		goto out;
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci	ath12k_mhi_set_state_bit(ab_pci, mhi_state);
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_ci	return 0;
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ciout:
58062306a36Sopenharmony_ci	ath12k_err(ab, "failed to set mhi state: %s(%d)\n",
58162306a36Sopenharmony_ci		   ath12k_mhi_state_to_str(mhi_state), mhi_state);
58262306a36Sopenharmony_ci	return ret;
58362306a36Sopenharmony_ci}
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_ciint ath12k_mhi_start(struct ath12k_pci *ab_pci)
58662306a36Sopenharmony_ci{
58762306a36Sopenharmony_ci	int ret;
58862306a36Sopenharmony_ci
58962306a36Sopenharmony_ci	ab_pci->mhi_ctrl->timeout_ms = MHI_TIMEOUT_DEFAULT_MS;
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci	ret = ath12k_mhi_set_state(ab_pci, ATH12K_MHI_INIT);
59262306a36Sopenharmony_ci	if (ret)
59362306a36Sopenharmony_ci		goto out;
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci	ret = ath12k_mhi_set_state(ab_pci, ATH12K_MHI_POWER_ON);
59662306a36Sopenharmony_ci	if (ret)
59762306a36Sopenharmony_ci		goto out;
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_ci	return 0;
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ciout:
60262306a36Sopenharmony_ci	return ret;
60362306a36Sopenharmony_ci}
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_civoid ath12k_mhi_stop(struct ath12k_pci *ab_pci)
60662306a36Sopenharmony_ci{
60762306a36Sopenharmony_ci	ath12k_mhi_set_state(ab_pci, ATH12K_MHI_POWER_OFF);
60862306a36Sopenharmony_ci	ath12k_mhi_set_state(ab_pci, ATH12K_MHI_DEINIT);
60962306a36Sopenharmony_ci}
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_civoid ath12k_mhi_suspend(struct ath12k_pci *ab_pci)
61262306a36Sopenharmony_ci{
61362306a36Sopenharmony_ci	ath12k_mhi_set_state(ab_pci, ATH12K_MHI_SUSPEND);
61462306a36Sopenharmony_ci}
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_civoid ath12k_mhi_resume(struct ath12k_pci *ab_pci)
61762306a36Sopenharmony_ci{
61862306a36Sopenharmony_ci	ath12k_mhi_set_state(ab_pci, ATH12K_MHI_RESUME);
61962306a36Sopenharmony_ci}
620