1dd4f32aeSBjoern A. Zeeb // SPDX-License-Identifier: BSD-3-Clause-Clear
2*28348caeSBjoern A. Zeeb /*
3*28348caeSBjoern A. Zeeb * Copyright (c) 2020 The Linux Foundation. All rights reserved.
4*28348caeSBjoern A. Zeeb * Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc. All rights reserved.
5*28348caeSBjoern A. Zeeb */
6dd4f32aeSBjoern A. Zeeb
7dd4f32aeSBjoern A. Zeeb #include <linux/msi.h>
8dd4f32aeSBjoern A. Zeeb #include <linux/pci.h>
9dd4f32aeSBjoern A. Zeeb #if defined(CONFIG_OF)
10dd4f32aeSBjoern A. Zeeb #include <linux/of.h>
11dd4f32aeSBjoern A. Zeeb #endif
12dd4f32aeSBjoern A. Zeeb #include <linux/of_address.h>
13dd4f32aeSBjoern A. Zeeb #include <linux/ioport.h>
14dd4f32aeSBjoern A. Zeeb #if defined(__FreeBSD__)
15dd4f32aeSBjoern A. Zeeb #include <linux/delay.h>
16dd4f32aeSBjoern A. Zeeb #endif
17dd4f32aeSBjoern A. Zeeb
18dd4f32aeSBjoern A. Zeeb #include "core.h"
19dd4f32aeSBjoern A. Zeeb #include "debug.h"
20dd4f32aeSBjoern A. Zeeb #include "mhi.h"
21dd4f32aeSBjoern A. Zeeb #include "pci.h"
22*28348caeSBjoern A. Zeeb #include "pcic.h"
23dd4f32aeSBjoern A. Zeeb
24*28348caeSBjoern A. Zeeb #define MHI_TIMEOUT_DEFAULT_MS 20000
25*28348caeSBjoern A. Zeeb #define RDDM_DUMP_SIZE 0x420000
26dd4f32aeSBjoern A. Zeeb
27dd4f32aeSBjoern A. Zeeb static struct mhi_channel_config ath11k_mhi_channels_qca6390[] = {
28dd4f32aeSBjoern A. Zeeb {
29dd4f32aeSBjoern A. Zeeb .num = 0,
30dd4f32aeSBjoern A. Zeeb .name = "LOOPBACK",
31dd4f32aeSBjoern A. Zeeb .num_elements = 32,
32dd4f32aeSBjoern A. Zeeb .event_ring = 0,
33dd4f32aeSBjoern A. Zeeb .dir = DMA_TO_DEVICE,
34dd4f32aeSBjoern A. Zeeb .ee_mask = 0x4,
35dd4f32aeSBjoern A. Zeeb .pollcfg = 0,
36dd4f32aeSBjoern A. Zeeb .doorbell = MHI_DB_BRST_DISABLE,
37dd4f32aeSBjoern A. Zeeb .lpm_notify = false,
38dd4f32aeSBjoern A. Zeeb .offload_channel = false,
39dd4f32aeSBjoern A. Zeeb .doorbell_mode_switch = false,
40dd4f32aeSBjoern A. Zeeb .auto_queue = false,
41dd4f32aeSBjoern A. Zeeb },
42dd4f32aeSBjoern A. Zeeb {
43dd4f32aeSBjoern A. Zeeb .num = 1,
44dd4f32aeSBjoern A. Zeeb .name = "LOOPBACK",
45dd4f32aeSBjoern A. Zeeb .num_elements = 32,
46dd4f32aeSBjoern A. Zeeb .event_ring = 0,
47dd4f32aeSBjoern A. Zeeb .dir = DMA_FROM_DEVICE,
48dd4f32aeSBjoern A. Zeeb .ee_mask = 0x4,
49dd4f32aeSBjoern A. Zeeb .pollcfg = 0,
50dd4f32aeSBjoern A. Zeeb .doorbell = MHI_DB_BRST_DISABLE,
51dd4f32aeSBjoern A. Zeeb .lpm_notify = false,
52dd4f32aeSBjoern A. Zeeb .offload_channel = false,
53dd4f32aeSBjoern A. Zeeb .doorbell_mode_switch = false,
54dd4f32aeSBjoern A. Zeeb .auto_queue = false,
55dd4f32aeSBjoern A. Zeeb },
56dd4f32aeSBjoern A. Zeeb {
57dd4f32aeSBjoern A. Zeeb .num = 20,
58dd4f32aeSBjoern A. Zeeb .name = "IPCR",
59dd4f32aeSBjoern A. Zeeb .num_elements = 64,
60dd4f32aeSBjoern A. Zeeb .event_ring = 1,
61dd4f32aeSBjoern A. Zeeb .dir = DMA_TO_DEVICE,
62dd4f32aeSBjoern A. Zeeb .ee_mask = 0x4,
63dd4f32aeSBjoern A. Zeeb .pollcfg = 0,
64dd4f32aeSBjoern A. Zeeb .doorbell = MHI_DB_BRST_DISABLE,
65dd4f32aeSBjoern A. Zeeb .lpm_notify = false,
66dd4f32aeSBjoern A. Zeeb .offload_channel = false,
67dd4f32aeSBjoern A. Zeeb .doorbell_mode_switch = false,
68dd4f32aeSBjoern A. Zeeb .auto_queue = false,
69dd4f32aeSBjoern A. Zeeb },
70dd4f32aeSBjoern A. Zeeb {
71dd4f32aeSBjoern A. Zeeb .num = 21,
72dd4f32aeSBjoern A. Zeeb .name = "IPCR",
73dd4f32aeSBjoern A. Zeeb .num_elements = 64,
74dd4f32aeSBjoern A. Zeeb .event_ring = 1,
75dd4f32aeSBjoern A. Zeeb .dir = DMA_FROM_DEVICE,
76dd4f32aeSBjoern A. Zeeb .ee_mask = 0x4,
77dd4f32aeSBjoern A. Zeeb .pollcfg = 0,
78dd4f32aeSBjoern A. Zeeb .doorbell = MHI_DB_BRST_DISABLE,
79dd4f32aeSBjoern A. Zeeb .lpm_notify = false,
80dd4f32aeSBjoern A. Zeeb .offload_channel = false,
81dd4f32aeSBjoern A. Zeeb .doorbell_mode_switch = false,
82dd4f32aeSBjoern A. Zeeb .auto_queue = true,
83dd4f32aeSBjoern A. Zeeb },
84dd4f32aeSBjoern A. Zeeb };
85dd4f32aeSBjoern A. Zeeb
86dd4f32aeSBjoern A. Zeeb static struct mhi_event_config ath11k_mhi_events_qca6390[] = {
87dd4f32aeSBjoern A. Zeeb {
88dd4f32aeSBjoern A. Zeeb .num_elements = 32,
89dd4f32aeSBjoern A. Zeeb .irq_moderation_ms = 0,
90dd4f32aeSBjoern A. Zeeb .irq = 1,
91dd4f32aeSBjoern A. Zeeb .mode = MHI_DB_BRST_DISABLE,
92dd4f32aeSBjoern A. Zeeb .data_type = MHI_ER_CTRL,
93dd4f32aeSBjoern A. Zeeb .hardware_event = false,
94dd4f32aeSBjoern A. Zeeb .client_managed = false,
95dd4f32aeSBjoern A. Zeeb .offload_channel = false,
96dd4f32aeSBjoern A. Zeeb },
97dd4f32aeSBjoern A. Zeeb {
98dd4f32aeSBjoern A. Zeeb .num_elements = 256,
99dd4f32aeSBjoern A. Zeeb .irq_moderation_ms = 1,
100dd4f32aeSBjoern A. Zeeb .irq = 2,
101dd4f32aeSBjoern A. Zeeb .mode = MHI_DB_BRST_DISABLE,
102dd4f32aeSBjoern A. Zeeb .priority = 1,
103dd4f32aeSBjoern A. Zeeb .hardware_event = false,
104dd4f32aeSBjoern A. Zeeb .client_managed = false,
105dd4f32aeSBjoern A. Zeeb .offload_channel = false,
106dd4f32aeSBjoern A. Zeeb },
107dd4f32aeSBjoern A. Zeeb };
108dd4f32aeSBjoern A. Zeeb
109dd4f32aeSBjoern A. Zeeb static struct mhi_controller_config ath11k_mhi_config_qca6390 = {
110dd4f32aeSBjoern A. Zeeb .max_channels = 128,
111dd4f32aeSBjoern A. Zeeb .timeout_ms = 2000,
112dd4f32aeSBjoern A. Zeeb .use_bounce_buf = false,
113dd4f32aeSBjoern A. Zeeb .buf_len = 0,
114dd4f32aeSBjoern A. Zeeb .num_channels = ARRAY_SIZE(ath11k_mhi_channels_qca6390),
115dd4f32aeSBjoern A. Zeeb .ch_cfg = ath11k_mhi_channels_qca6390,
116dd4f32aeSBjoern A. Zeeb .num_events = ARRAY_SIZE(ath11k_mhi_events_qca6390),
117dd4f32aeSBjoern A. Zeeb .event_cfg = ath11k_mhi_events_qca6390,
118dd4f32aeSBjoern A. Zeeb };
119dd4f32aeSBjoern A. Zeeb
120dd4f32aeSBjoern A. Zeeb static struct mhi_channel_config ath11k_mhi_channels_qcn9074[] = {
121dd4f32aeSBjoern A. Zeeb {
122dd4f32aeSBjoern A. Zeeb .num = 0,
123dd4f32aeSBjoern A. Zeeb .name = "LOOPBACK",
124dd4f32aeSBjoern A. Zeeb .num_elements = 32,
125dd4f32aeSBjoern A. Zeeb .event_ring = 1,
126dd4f32aeSBjoern A. Zeeb .dir = DMA_TO_DEVICE,
127dd4f32aeSBjoern A. Zeeb .ee_mask = 0x14,
128dd4f32aeSBjoern A. Zeeb .pollcfg = 0,
129dd4f32aeSBjoern A. Zeeb .doorbell = MHI_DB_BRST_DISABLE,
130dd4f32aeSBjoern A. Zeeb .lpm_notify = false,
131dd4f32aeSBjoern A. Zeeb .offload_channel = false,
132dd4f32aeSBjoern A. Zeeb .doorbell_mode_switch = false,
133dd4f32aeSBjoern A. Zeeb .auto_queue = false,
134dd4f32aeSBjoern A. Zeeb },
135dd4f32aeSBjoern A. Zeeb {
136dd4f32aeSBjoern A. Zeeb .num = 1,
137dd4f32aeSBjoern A. Zeeb .name = "LOOPBACK",
138dd4f32aeSBjoern A. Zeeb .num_elements = 32,
139dd4f32aeSBjoern A. Zeeb .event_ring = 1,
140dd4f32aeSBjoern A. Zeeb .dir = DMA_FROM_DEVICE,
141dd4f32aeSBjoern A. Zeeb .ee_mask = 0x14,
142dd4f32aeSBjoern A. Zeeb .pollcfg = 0,
143dd4f32aeSBjoern A. Zeeb .doorbell = MHI_DB_BRST_DISABLE,
144dd4f32aeSBjoern A. Zeeb .lpm_notify = false,
145dd4f32aeSBjoern A. Zeeb .offload_channel = false,
146dd4f32aeSBjoern A. Zeeb .doorbell_mode_switch = false,
147dd4f32aeSBjoern A. Zeeb .auto_queue = false,
148dd4f32aeSBjoern A. Zeeb },
149dd4f32aeSBjoern A. Zeeb {
150dd4f32aeSBjoern A. Zeeb .num = 20,
151dd4f32aeSBjoern A. Zeeb .name = "IPCR",
152dd4f32aeSBjoern A. Zeeb .num_elements = 32,
153dd4f32aeSBjoern A. Zeeb .event_ring = 1,
154dd4f32aeSBjoern A. Zeeb .dir = DMA_TO_DEVICE,
155dd4f32aeSBjoern A. Zeeb .ee_mask = 0x14,
156dd4f32aeSBjoern A. Zeeb .pollcfg = 0,
157dd4f32aeSBjoern A. Zeeb .doorbell = MHI_DB_BRST_DISABLE,
158dd4f32aeSBjoern A. Zeeb .lpm_notify = false,
159dd4f32aeSBjoern A. Zeeb .offload_channel = false,
160dd4f32aeSBjoern A. Zeeb .doorbell_mode_switch = false,
161dd4f32aeSBjoern A. Zeeb .auto_queue = false,
162dd4f32aeSBjoern A. Zeeb },
163dd4f32aeSBjoern A. Zeeb {
164dd4f32aeSBjoern A. Zeeb .num = 21,
165dd4f32aeSBjoern A. Zeeb .name = "IPCR",
166dd4f32aeSBjoern A. Zeeb .num_elements = 32,
167dd4f32aeSBjoern A. Zeeb .event_ring = 1,
168dd4f32aeSBjoern A. Zeeb .dir = DMA_FROM_DEVICE,
169dd4f32aeSBjoern A. Zeeb .ee_mask = 0x14,
170dd4f32aeSBjoern A. Zeeb .pollcfg = 0,
171dd4f32aeSBjoern A. Zeeb .doorbell = MHI_DB_BRST_DISABLE,
172dd4f32aeSBjoern A. Zeeb .lpm_notify = false,
173dd4f32aeSBjoern A. Zeeb .offload_channel = false,
174dd4f32aeSBjoern A. Zeeb .doorbell_mode_switch = false,
175dd4f32aeSBjoern A. Zeeb .auto_queue = true,
176dd4f32aeSBjoern A. Zeeb },
177dd4f32aeSBjoern A. Zeeb };
178dd4f32aeSBjoern A. Zeeb
179dd4f32aeSBjoern A. Zeeb static struct mhi_event_config ath11k_mhi_events_qcn9074[] = {
180dd4f32aeSBjoern A. Zeeb {
181dd4f32aeSBjoern A. Zeeb .num_elements = 32,
182dd4f32aeSBjoern A. Zeeb .irq_moderation_ms = 0,
183dd4f32aeSBjoern A. Zeeb .irq = 1,
184dd4f32aeSBjoern A. Zeeb .data_type = MHI_ER_CTRL,
185dd4f32aeSBjoern A. Zeeb .mode = MHI_DB_BRST_DISABLE,
186dd4f32aeSBjoern A. Zeeb .hardware_event = false,
187dd4f32aeSBjoern A. Zeeb .client_managed = false,
188dd4f32aeSBjoern A. Zeeb .offload_channel = false,
189dd4f32aeSBjoern A. Zeeb },
190dd4f32aeSBjoern A. Zeeb {
191dd4f32aeSBjoern A. Zeeb .num_elements = 256,
192dd4f32aeSBjoern A. Zeeb .irq_moderation_ms = 1,
193dd4f32aeSBjoern A. Zeeb .irq = 2,
194dd4f32aeSBjoern A. Zeeb .mode = MHI_DB_BRST_DISABLE,
195dd4f32aeSBjoern A. Zeeb .priority = 1,
196dd4f32aeSBjoern A. Zeeb .hardware_event = false,
197dd4f32aeSBjoern A. Zeeb .client_managed = false,
198dd4f32aeSBjoern A. Zeeb .offload_channel = false,
199dd4f32aeSBjoern A. Zeeb },
200dd4f32aeSBjoern A. Zeeb };
201dd4f32aeSBjoern A. Zeeb
202dd4f32aeSBjoern A. Zeeb static struct mhi_controller_config ath11k_mhi_config_qcn9074 = {
203dd4f32aeSBjoern A. Zeeb .max_channels = 30,
204dd4f32aeSBjoern A. Zeeb .timeout_ms = 10000,
205dd4f32aeSBjoern A. Zeeb .use_bounce_buf = false,
206dd4f32aeSBjoern A. Zeeb .buf_len = 0,
207dd4f32aeSBjoern A. Zeeb .num_channels = ARRAY_SIZE(ath11k_mhi_channels_qcn9074),
208dd4f32aeSBjoern A. Zeeb .ch_cfg = ath11k_mhi_channels_qcn9074,
209dd4f32aeSBjoern A. Zeeb .num_events = ARRAY_SIZE(ath11k_mhi_events_qcn9074),
210dd4f32aeSBjoern A. Zeeb .event_cfg = ath11k_mhi_events_qcn9074,
211dd4f32aeSBjoern A. Zeeb };
212dd4f32aeSBjoern A. Zeeb
ath11k_mhi_set_mhictrl_reset(struct ath11k_base * ab)213dd4f32aeSBjoern A. Zeeb void ath11k_mhi_set_mhictrl_reset(struct ath11k_base *ab)
214dd4f32aeSBjoern A. Zeeb {
215dd4f32aeSBjoern A. Zeeb u32 val;
216dd4f32aeSBjoern A. Zeeb
217*28348caeSBjoern A. Zeeb val = ath11k_pcic_read32(ab, MHISTATUS);
218dd4f32aeSBjoern A. Zeeb
219*28348caeSBjoern A. Zeeb ath11k_dbg(ab, ATH11K_DBG_PCI, "mhistatus 0x%x\n", val);
220dd4f32aeSBjoern A. Zeeb
221dd4f32aeSBjoern A. Zeeb /* Observed on QCA6390 that after SOC_GLOBAL_RESET, MHISTATUS
222dd4f32aeSBjoern A. Zeeb * has SYSERR bit set and thus need to set MHICTRL_RESET
223dd4f32aeSBjoern A. Zeeb * to clear SYSERR.
224dd4f32aeSBjoern A. Zeeb */
225*28348caeSBjoern A. Zeeb ath11k_pcic_write32(ab, MHICTRL, MHICTRL_RESET_MASK);
226dd4f32aeSBjoern A. Zeeb
227dd4f32aeSBjoern A. Zeeb mdelay(10);
228dd4f32aeSBjoern A. Zeeb }
229dd4f32aeSBjoern A. Zeeb
ath11k_mhi_reset_txvecdb(struct ath11k_base * ab)230dd4f32aeSBjoern A. Zeeb static void ath11k_mhi_reset_txvecdb(struct ath11k_base *ab)
231dd4f32aeSBjoern A. Zeeb {
232*28348caeSBjoern A. Zeeb ath11k_pcic_write32(ab, PCIE_TXVECDB, 0);
233dd4f32aeSBjoern A. Zeeb }
234dd4f32aeSBjoern A. Zeeb
ath11k_mhi_reset_txvecstatus(struct ath11k_base * ab)235dd4f32aeSBjoern A. Zeeb static void ath11k_mhi_reset_txvecstatus(struct ath11k_base *ab)
236dd4f32aeSBjoern A. Zeeb {
237*28348caeSBjoern A. Zeeb ath11k_pcic_write32(ab, PCIE_TXVECSTATUS, 0);
238dd4f32aeSBjoern A. Zeeb }
239dd4f32aeSBjoern A. Zeeb
ath11k_mhi_reset_rxvecdb(struct ath11k_base * ab)240dd4f32aeSBjoern A. Zeeb static void ath11k_mhi_reset_rxvecdb(struct ath11k_base *ab)
241dd4f32aeSBjoern A. Zeeb {
242*28348caeSBjoern A. Zeeb ath11k_pcic_write32(ab, PCIE_RXVECDB, 0);
243dd4f32aeSBjoern A. Zeeb }
244dd4f32aeSBjoern A. Zeeb
ath11k_mhi_reset_rxvecstatus(struct ath11k_base * ab)245dd4f32aeSBjoern A. Zeeb static void ath11k_mhi_reset_rxvecstatus(struct ath11k_base *ab)
246dd4f32aeSBjoern A. Zeeb {
247*28348caeSBjoern A. Zeeb ath11k_pcic_write32(ab, PCIE_RXVECSTATUS, 0);
248dd4f32aeSBjoern A. Zeeb }
249dd4f32aeSBjoern A. Zeeb
ath11k_mhi_clear_vector(struct ath11k_base * ab)250dd4f32aeSBjoern A. Zeeb void ath11k_mhi_clear_vector(struct ath11k_base *ab)
251dd4f32aeSBjoern A. Zeeb {
252dd4f32aeSBjoern A. Zeeb ath11k_mhi_reset_txvecdb(ab);
253dd4f32aeSBjoern A. Zeeb ath11k_mhi_reset_txvecstatus(ab);
254dd4f32aeSBjoern A. Zeeb ath11k_mhi_reset_rxvecdb(ab);
255dd4f32aeSBjoern A. Zeeb ath11k_mhi_reset_rxvecstatus(ab);
256dd4f32aeSBjoern A. Zeeb }
257dd4f32aeSBjoern A. Zeeb
ath11k_mhi_get_msi(struct ath11k_pci * ab_pci)258dd4f32aeSBjoern A. Zeeb static int ath11k_mhi_get_msi(struct ath11k_pci *ab_pci)
259dd4f32aeSBjoern A. Zeeb {
260dd4f32aeSBjoern A. Zeeb struct ath11k_base *ab = ab_pci->ab;
261dd4f32aeSBjoern A. Zeeb u32 user_base_data, base_vector;
262dd4f32aeSBjoern A. Zeeb int ret, num_vectors, i;
263dd4f32aeSBjoern A. Zeeb int *irq;
264dd4f32aeSBjoern A. Zeeb unsigned int msi_data;
265dd4f32aeSBjoern A. Zeeb
266*28348caeSBjoern A. Zeeb ret = ath11k_pcic_get_user_msi_assignment(ab, "MHI", &num_vectors,
267dd4f32aeSBjoern A. Zeeb &user_base_data, &base_vector);
268dd4f32aeSBjoern A. Zeeb if (ret)
269dd4f32aeSBjoern A. Zeeb return ret;
270dd4f32aeSBjoern A. Zeeb
271*28348caeSBjoern A. Zeeb ath11k_dbg(ab, ATH11K_DBG_PCI, "num_vectors %d base_vector %d\n",
272dd4f32aeSBjoern A. Zeeb num_vectors, base_vector);
273dd4f32aeSBjoern A. Zeeb
274dd4f32aeSBjoern A. Zeeb irq = kcalloc(num_vectors, sizeof(int), GFP_KERNEL);
275dd4f32aeSBjoern A. Zeeb if (!irq)
276dd4f32aeSBjoern A. Zeeb return -ENOMEM;
277dd4f32aeSBjoern A. Zeeb
278dd4f32aeSBjoern A. Zeeb for (i = 0; i < num_vectors; i++) {
279dd4f32aeSBjoern A. Zeeb msi_data = base_vector;
280dd4f32aeSBjoern A. Zeeb
281*28348caeSBjoern A. Zeeb if (test_bit(ATH11K_FLAG_MULTI_MSI_VECTORS, &ab->dev_flags))
282dd4f32aeSBjoern A. Zeeb msi_data += i;
283dd4f32aeSBjoern A. Zeeb
284*28348caeSBjoern A. Zeeb irq[i] = ath11k_pci_get_msi_irq(ab, msi_data);
285dd4f32aeSBjoern A. Zeeb }
286dd4f32aeSBjoern A. Zeeb
287dd4f32aeSBjoern A. Zeeb ab_pci->mhi_ctrl->irq = irq;
288dd4f32aeSBjoern A. Zeeb ab_pci->mhi_ctrl->nr_irqs = num_vectors;
289dd4f32aeSBjoern A. Zeeb
290dd4f32aeSBjoern A. Zeeb return 0;
291dd4f32aeSBjoern A. Zeeb }
292dd4f32aeSBjoern A. Zeeb
ath11k_mhi_op_runtime_get(struct mhi_controller * mhi_cntrl)293dd4f32aeSBjoern A. Zeeb static int ath11k_mhi_op_runtime_get(struct mhi_controller *mhi_cntrl)
294dd4f32aeSBjoern A. Zeeb {
295dd4f32aeSBjoern A. Zeeb return 0;
296dd4f32aeSBjoern A. Zeeb }
297dd4f32aeSBjoern A. Zeeb
ath11k_mhi_op_runtime_put(struct mhi_controller * mhi_cntrl)298dd4f32aeSBjoern A. Zeeb static void ath11k_mhi_op_runtime_put(struct mhi_controller *mhi_cntrl)
299dd4f32aeSBjoern A. Zeeb {
300dd4f32aeSBjoern A. Zeeb }
301dd4f32aeSBjoern A. Zeeb
ath11k_mhi_op_callback_to_str(enum mhi_callback reason)302*28348caeSBjoern A. Zeeb static char *ath11k_mhi_op_callback_to_str(enum mhi_callback reason)
303*28348caeSBjoern A. Zeeb {
304*28348caeSBjoern A. Zeeb switch (reason) {
305*28348caeSBjoern A. Zeeb case MHI_CB_IDLE:
306*28348caeSBjoern A. Zeeb return "MHI_CB_IDLE";
307*28348caeSBjoern A. Zeeb case MHI_CB_PENDING_DATA:
308*28348caeSBjoern A. Zeeb return "MHI_CB_PENDING_DATA";
309*28348caeSBjoern A. Zeeb case MHI_CB_LPM_ENTER:
310*28348caeSBjoern A. Zeeb return "MHI_CB_LPM_ENTER";
311*28348caeSBjoern A. Zeeb case MHI_CB_LPM_EXIT:
312*28348caeSBjoern A. Zeeb return "MHI_CB_LPM_EXIT";
313*28348caeSBjoern A. Zeeb case MHI_CB_EE_RDDM:
314*28348caeSBjoern A. Zeeb return "MHI_CB_EE_RDDM";
315*28348caeSBjoern A. Zeeb case MHI_CB_EE_MISSION_MODE:
316*28348caeSBjoern A. Zeeb return "MHI_CB_EE_MISSION_MODE";
317*28348caeSBjoern A. Zeeb case MHI_CB_SYS_ERROR:
318*28348caeSBjoern A. Zeeb return "MHI_CB_SYS_ERROR";
319*28348caeSBjoern A. Zeeb case MHI_CB_FATAL_ERROR:
320*28348caeSBjoern A. Zeeb return "MHI_CB_FATAL_ERROR";
321*28348caeSBjoern A. Zeeb case MHI_CB_BW_REQ:
322*28348caeSBjoern A. Zeeb return "MHI_CB_BW_REQ";
323*28348caeSBjoern A. Zeeb default:
324*28348caeSBjoern A. Zeeb return "UNKNOWN";
325*28348caeSBjoern A. Zeeb }
326*28348caeSBjoern A. Zeeb };
327*28348caeSBjoern A. Zeeb
ath11k_mhi_op_status_cb(struct mhi_controller * mhi_cntrl,enum mhi_callback cb)328dd4f32aeSBjoern A. Zeeb static void ath11k_mhi_op_status_cb(struct mhi_controller *mhi_cntrl,
329dd4f32aeSBjoern A. Zeeb enum mhi_callback cb)
330dd4f32aeSBjoern A. Zeeb {
331dd4f32aeSBjoern A. Zeeb struct ath11k_base *ab = dev_get_drvdata(mhi_cntrl->cntrl_dev);
332dd4f32aeSBjoern A. Zeeb
333*28348caeSBjoern A. Zeeb ath11k_dbg(ab, ATH11K_DBG_BOOT, "notify status reason %s\n",
334*28348caeSBjoern A. Zeeb ath11k_mhi_op_callback_to_str(cb));
335*28348caeSBjoern A. Zeeb
336dd4f32aeSBjoern A. Zeeb switch (cb) {
337dd4f32aeSBjoern A. Zeeb case MHI_CB_SYS_ERROR:
338dd4f32aeSBjoern A. Zeeb ath11k_warn(ab, "firmware crashed: MHI_CB_SYS_ERROR\n");
339dd4f32aeSBjoern A. Zeeb break;
340*28348caeSBjoern A. Zeeb case MHI_CB_EE_RDDM:
341*28348caeSBjoern A. Zeeb if (!(test_bit(ATH11K_FLAG_UNREGISTERING, &ab->dev_flags)))
342*28348caeSBjoern A. Zeeb queue_work(ab->workqueue_aux, &ab->reset_work);
343*28348caeSBjoern A. Zeeb break;
344dd4f32aeSBjoern A. Zeeb default:
345dd4f32aeSBjoern A. Zeeb break;
346dd4f32aeSBjoern A. Zeeb }
347dd4f32aeSBjoern A. Zeeb }
348dd4f32aeSBjoern A. Zeeb
ath11k_mhi_op_read_reg(struct mhi_controller * mhi_cntrl,void __iomem * addr,u32 * out)349dd4f32aeSBjoern A. Zeeb static int ath11k_mhi_op_read_reg(struct mhi_controller *mhi_cntrl,
350dd4f32aeSBjoern A. Zeeb void __iomem *addr,
351dd4f32aeSBjoern A. Zeeb u32 *out)
352dd4f32aeSBjoern A. Zeeb {
353dd4f32aeSBjoern A. Zeeb *out = readl(addr);
354dd4f32aeSBjoern A. Zeeb
355dd4f32aeSBjoern A. Zeeb return 0;
356dd4f32aeSBjoern A. Zeeb }
357dd4f32aeSBjoern A. Zeeb
ath11k_mhi_op_write_reg(struct mhi_controller * mhi_cntrl,void __iomem * addr,u32 val)358dd4f32aeSBjoern A. Zeeb static void ath11k_mhi_op_write_reg(struct mhi_controller *mhi_cntrl,
359dd4f32aeSBjoern A. Zeeb void __iomem *addr,
360dd4f32aeSBjoern A. Zeeb u32 val)
361dd4f32aeSBjoern A. Zeeb {
362dd4f32aeSBjoern A. Zeeb writel(val, addr);
363dd4f32aeSBjoern A. Zeeb }
364dd4f32aeSBjoern A. Zeeb
ath11k_mhi_read_addr_from_dt(struct mhi_controller * mhi_ctrl)365dd4f32aeSBjoern A. Zeeb static int ath11k_mhi_read_addr_from_dt(struct mhi_controller *mhi_ctrl)
366dd4f32aeSBjoern A. Zeeb {
367dd4f32aeSBjoern A. Zeeb #if defined(__linux__)
368dd4f32aeSBjoern A. Zeeb struct device_node *np;
369dd4f32aeSBjoern A. Zeeb struct resource res;
370dd4f32aeSBjoern A. Zeeb int ret;
371dd4f32aeSBjoern A. Zeeb
372dd4f32aeSBjoern A. Zeeb np = of_find_node_by_type(NULL, "memory");
373dd4f32aeSBjoern A. Zeeb if (!np)
374dd4f32aeSBjoern A. Zeeb return -ENOENT;
375dd4f32aeSBjoern A. Zeeb
376dd4f32aeSBjoern A. Zeeb ret = of_address_to_resource(np, 0, &res);
377dd4f32aeSBjoern A. Zeeb of_node_put(np);
378dd4f32aeSBjoern A. Zeeb if (ret)
379dd4f32aeSBjoern A. Zeeb return ret;
380dd4f32aeSBjoern A. Zeeb
381dd4f32aeSBjoern A. Zeeb mhi_ctrl->iova_start = res.start + 0x1000000;
382dd4f32aeSBjoern A. Zeeb mhi_ctrl->iova_stop = res.end;
383dd4f32aeSBjoern A. Zeeb
384dd4f32aeSBjoern A. Zeeb return 0;
385dd4f32aeSBjoern A. Zeeb #elif defined(__FreeBSD__)
386dd4f32aeSBjoern A. Zeeb return -ENOENT;
387dd4f32aeSBjoern A. Zeeb #endif
388dd4f32aeSBjoern A. Zeeb }
389dd4f32aeSBjoern A. Zeeb
ath11k_mhi_register(struct ath11k_pci * ab_pci)390dd4f32aeSBjoern A. Zeeb int ath11k_mhi_register(struct ath11k_pci *ab_pci)
391dd4f32aeSBjoern A. Zeeb {
392dd4f32aeSBjoern A. Zeeb struct ath11k_base *ab = ab_pci->ab;
393dd4f32aeSBjoern A. Zeeb struct mhi_controller *mhi_ctrl;
394dd4f32aeSBjoern A. Zeeb struct mhi_controller_config *ath11k_mhi_config;
395dd4f32aeSBjoern A. Zeeb int ret;
396dd4f32aeSBjoern A. Zeeb
397dd4f32aeSBjoern A. Zeeb mhi_ctrl = mhi_alloc_controller();
398dd4f32aeSBjoern A. Zeeb if (!mhi_ctrl)
399dd4f32aeSBjoern A. Zeeb return -ENOMEM;
400dd4f32aeSBjoern A. Zeeb
401dd4f32aeSBjoern A. Zeeb ath11k_core_create_firmware_path(ab, ATH11K_AMSS_FILE,
402dd4f32aeSBjoern A. Zeeb ab_pci->amss_path,
403dd4f32aeSBjoern A. Zeeb sizeof(ab_pci->amss_path));
404dd4f32aeSBjoern A. Zeeb
405dd4f32aeSBjoern A. Zeeb ab_pci->mhi_ctrl = mhi_ctrl;
406dd4f32aeSBjoern A. Zeeb mhi_ctrl->cntrl_dev = ab->dev;
407dd4f32aeSBjoern A. Zeeb mhi_ctrl->fw_image = ab_pci->amss_path;
408dd4f32aeSBjoern A. Zeeb mhi_ctrl->regs = ab->mem;
409dd4f32aeSBjoern A. Zeeb mhi_ctrl->reg_len = ab->mem_len;
410dd4f32aeSBjoern A. Zeeb
411dd4f32aeSBjoern A. Zeeb ret = ath11k_mhi_get_msi(ab_pci);
412dd4f32aeSBjoern A. Zeeb if (ret) {
413dd4f32aeSBjoern A. Zeeb ath11k_err(ab, "failed to get msi for mhi\n");
414*28348caeSBjoern A. Zeeb goto free_controller;
415dd4f32aeSBjoern A. Zeeb }
416dd4f32aeSBjoern A. Zeeb
417*28348caeSBjoern A. Zeeb if (!test_bit(ATH11K_FLAG_MULTI_MSI_VECTORS, &ab->dev_flags))
418dd4f32aeSBjoern A. Zeeb mhi_ctrl->irq_flags = IRQF_SHARED | IRQF_NOBALANCING;
419dd4f32aeSBjoern A. Zeeb
420dd4f32aeSBjoern A. Zeeb if (test_bit(ATH11K_FLAG_FIXED_MEM_RGN, &ab->dev_flags)) {
421dd4f32aeSBjoern A. Zeeb ret = ath11k_mhi_read_addr_from_dt(mhi_ctrl);
422dd4f32aeSBjoern A. Zeeb if (ret < 0)
423*28348caeSBjoern A. Zeeb goto free_controller;
424dd4f32aeSBjoern A. Zeeb } else {
425dd4f32aeSBjoern A. Zeeb mhi_ctrl->iova_start = 0;
426dd4f32aeSBjoern A. Zeeb mhi_ctrl->iova_stop = 0xFFFFFFFF;
427dd4f32aeSBjoern A. Zeeb }
428dd4f32aeSBjoern A. Zeeb
429*28348caeSBjoern A. Zeeb mhi_ctrl->rddm_size = RDDM_DUMP_SIZE;
430dd4f32aeSBjoern A. Zeeb mhi_ctrl->sbl_size = SZ_512K;
431dd4f32aeSBjoern A. Zeeb mhi_ctrl->seg_len = SZ_512K;
432dd4f32aeSBjoern A. Zeeb mhi_ctrl->fbc_download = true;
433dd4f32aeSBjoern A. Zeeb mhi_ctrl->runtime_get = ath11k_mhi_op_runtime_get;
434dd4f32aeSBjoern A. Zeeb mhi_ctrl->runtime_put = ath11k_mhi_op_runtime_put;
435dd4f32aeSBjoern A. Zeeb mhi_ctrl->status_cb = ath11k_mhi_op_status_cb;
436dd4f32aeSBjoern A. Zeeb mhi_ctrl->read_reg = ath11k_mhi_op_read_reg;
437dd4f32aeSBjoern A. Zeeb mhi_ctrl->write_reg = ath11k_mhi_op_write_reg;
438dd4f32aeSBjoern A. Zeeb
439dd4f32aeSBjoern A. Zeeb switch (ab->hw_rev) {
440dd4f32aeSBjoern A. Zeeb case ATH11K_HW_QCN9074_HW10:
441dd4f32aeSBjoern A. Zeeb ath11k_mhi_config = &ath11k_mhi_config_qcn9074;
442dd4f32aeSBjoern A. Zeeb break;
443dd4f32aeSBjoern A. Zeeb case ATH11K_HW_QCA6390_HW20:
444dd4f32aeSBjoern A. Zeeb case ATH11K_HW_WCN6855_HW20:
445dd4f32aeSBjoern A. Zeeb case ATH11K_HW_WCN6855_HW21:
446dd4f32aeSBjoern A. Zeeb ath11k_mhi_config = &ath11k_mhi_config_qca6390;
447dd4f32aeSBjoern A. Zeeb break;
448dd4f32aeSBjoern A. Zeeb default:
449dd4f32aeSBjoern A. Zeeb ath11k_err(ab, "failed assign mhi_config for unknown hw rev %d\n",
450dd4f32aeSBjoern A. Zeeb ab->hw_rev);
451*28348caeSBjoern A. Zeeb ret = -EINVAL;
452*28348caeSBjoern A. Zeeb goto free_controller;
453dd4f32aeSBjoern A. Zeeb }
454dd4f32aeSBjoern A. Zeeb
455dd4f32aeSBjoern A. Zeeb ret = mhi_register_controller(mhi_ctrl, ath11k_mhi_config);
456dd4f32aeSBjoern A. Zeeb if (ret) {
457dd4f32aeSBjoern A. Zeeb ath11k_err(ab, "failed to register to mhi bus, err = %d\n", ret);
458*28348caeSBjoern A. Zeeb goto free_controller;
459dd4f32aeSBjoern A. Zeeb }
460dd4f32aeSBjoern A. Zeeb
461dd4f32aeSBjoern A. Zeeb return 0;
462*28348caeSBjoern A. Zeeb
463*28348caeSBjoern A. Zeeb free_controller:
464*28348caeSBjoern A. Zeeb mhi_free_controller(mhi_ctrl);
465*28348caeSBjoern A. Zeeb ab_pci->mhi_ctrl = NULL;
466*28348caeSBjoern A. Zeeb return ret;
467dd4f32aeSBjoern A. Zeeb }
468dd4f32aeSBjoern A. Zeeb
ath11k_mhi_unregister(struct ath11k_pci * ab_pci)469dd4f32aeSBjoern A. Zeeb void ath11k_mhi_unregister(struct ath11k_pci *ab_pci)
470dd4f32aeSBjoern A. Zeeb {
471dd4f32aeSBjoern A. Zeeb struct mhi_controller *mhi_ctrl = ab_pci->mhi_ctrl;
472dd4f32aeSBjoern A. Zeeb
473dd4f32aeSBjoern A. Zeeb mhi_unregister_controller(mhi_ctrl);
474dd4f32aeSBjoern A. Zeeb kfree(mhi_ctrl->irq);
475dd4f32aeSBjoern A. Zeeb mhi_free_controller(mhi_ctrl);
476dd4f32aeSBjoern A. Zeeb }
477dd4f32aeSBjoern A. Zeeb
ath11k_mhi_start(struct ath11k_pci * ab_pci)478*28348caeSBjoern A. Zeeb int ath11k_mhi_start(struct ath11k_pci *ab_pci)
479dd4f32aeSBjoern A. Zeeb {
480dd4f32aeSBjoern A. Zeeb struct ath11k_base *ab = ab_pci->ab;
481dd4f32aeSBjoern A. Zeeb int ret;
482dd4f32aeSBjoern A. Zeeb
483*28348caeSBjoern A. Zeeb ab_pci->mhi_ctrl->timeout_ms = MHI_TIMEOUT_DEFAULT_MS;
484dd4f32aeSBjoern A. Zeeb
485dd4f32aeSBjoern A. Zeeb ret = mhi_prepare_for_power_up(ab_pci->mhi_ctrl);
486*28348caeSBjoern A. Zeeb if (ret) {
487*28348caeSBjoern A. Zeeb ath11k_warn(ab, "failed to prepare mhi: %d", ret);
488*28348caeSBjoern A. Zeeb return ret;
489*28348caeSBjoern A. Zeeb }
490*28348caeSBjoern A. Zeeb
491*28348caeSBjoern A. Zeeb ret = mhi_sync_power_up(ab_pci->mhi_ctrl);
492*28348caeSBjoern A. Zeeb if (ret) {
493*28348caeSBjoern A. Zeeb ath11k_warn(ab, "failed to power up mhi: %d", ret);
494*28348caeSBjoern A. Zeeb return ret;
495*28348caeSBjoern A. Zeeb }
496*28348caeSBjoern A. Zeeb
497*28348caeSBjoern A. Zeeb return 0;
498*28348caeSBjoern A. Zeeb }
499*28348caeSBjoern A. Zeeb
ath11k_mhi_stop(struct ath11k_pci * ab_pci)500*28348caeSBjoern A. Zeeb void ath11k_mhi_stop(struct ath11k_pci *ab_pci)
501*28348caeSBjoern A. Zeeb {
502dd4f32aeSBjoern A. Zeeb mhi_power_down(ab_pci->mhi_ctrl, true);
503*28348caeSBjoern A. Zeeb mhi_unprepare_after_power_down(ab_pci->mhi_ctrl);
504*28348caeSBjoern A. Zeeb }
505*28348caeSBjoern A. Zeeb
ath11k_mhi_suspend(struct ath11k_pci * ab_pci)506*28348caeSBjoern A. Zeeb int ath11k_mhi_suspend(struct ath11k_pci *ab_pci)
507*28348caeSBjoern A. Zeeb {
508*28348caeSBjoern A. Zeeb struct ath11k_base *ab = ab_pci->ab;
509*28348caeSBjoern A. Zeeb int ret;
510*28348caeSBjoern A. Zeeb
511dd4f32aeSBjoern A. Zeeb ret = mhi_pm_suspend(ab_pci->mhi_ctrl);
512*28348caeSBjoern A. Zeeb if (ret) {
513*28348caeSBjoern A. Zeeb ath11k_warn(ab, "failed to suspend mhi: %d", ret);
514*28348caeSBjoern A. Zeeb return ret;
515*28348caeSBjoern A. Zeeb }
516*28348caeSBjoern A. Zeeb
517*28348caeSBjoern A. Zeeb return 0;
518*28348caeSBjoern A. Zeeb }
519*28348caeSBjoern A. Zeeb
ath11k_mhi_resume(struct ath11k_pci * ab_pci)520*28348caeSBjoern A. Zeeb int ath11k_mhi_resume(struct ath11k_pci *ab_pci)
521*28348caeSBjoern A. Zeeb {
522*28348caeSBjoern A. Zeeb struct ath11k_base *ab = ab_pci->ab;
523*28348caeSBjoern A. Zeeb int ret;
524*28348caeSBjoern A. Zeeb
525dd4f32aeSBjoern A. Zeeb /* Do force MHI resume as some devices like QCA6390, WCN6855
526dd4f32aeSBjoern A. Zeeb * are not in M3 state but they are functional. So just ignore
527dd4f32aeSBjoern A. Zeeb * the MHI state while resuming.
528dd4f32aeSBjoern A. Zeeb */
529dd4f32aeSBjoern A. Zeeb ret = mhi_pm_resume_force(ab_pci->mhi_ctrl);
530*28348caeSBjoern A. Zeeb if (ret) {
531*28348caeSBjoern A. Zeeb ath11k_warn(ab, "failed to resume mhi: %d", ret);
532dd4f32aeSBjoern A. Zeeb return ret;
533dd4f32aeSBjoern A. Zeeb }
534dd4f32aeSBjoern A. Zeeb
535dd4f32aeSBjoern A. Zeeb return 0;
536dd4f32aeSBjoern A. Zeeb }
537