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