1d5c65159SKalle Valo // SPDX-License-Identifier: BSD-3-Clause-Clear
2d5c65159SKalle Valo /*
3d5c65159SKalle Valo * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
4b43310e4SGovindaraj Saminathan * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
5d5c65159SKalle Valo */
6d5c65159SKalle Valo
7d5c65159SKalle Valo #include <linux/module.h>
8d5c65159SKalle Valo #include <linux/platform_device.h>
9d5c65159SKalle Valo #include <linux/of_device.h>
10d5c65159SKalle Valo #include <linux/of.h>
11d5c65159SKalle Valo #include <linux/dma-mapping.h>
12f9eec494SManikanta Pubbisetty #include <linux/of_address.h>
13f9eec494SManikanta Pubbisetty #include <linux/iommu.h>
14d5c65159SKalle Valo #include "ahb.h"
15d5c65159SKalle Valo #include "debug.h"
1631858805SGovind Singh #include "hif.h"
17bdfc967bSAnilkumar Kolli #include "qmi.h"
18d5c65159SKalle Valo #include <linux/remoteproc.h>
1900402f49SManikanta Pubbisetty #include "pcic.h"
2069ccee61SManikanta Pubbisetty #include <linux/soc/qcom/smem.h>
2169ccee61SManikanta Pubbisetty #include <linux/soc/qcom/smem_state.h>
22d5c65159SKalle Valo
23d5c65159SKalle Valo static const struct of_device_id ath11k_ahb_of_match[] = {
24d5c65159SKalle Valo /* TODO: Should we change the compatible string to something similar
25d5c65159SKalle Valo * to one that ath10k uses?
26d5c65159SKalle Valo */
27d5c65159SKalle Valo { .compatible = "qcom,ipq8074-wifi",
28d5c65159SKalle Valo .data = (void *)ATH11K_HW_IPQ8074,
29d5c65159SKalle Valo },
30b129699aSAnilkumar Kolli { .compatible = "qcom,ipq6018-wifi",
31b129699aSAnilkumar Kolli .data = (void *)ATH11K_HW_IPQ6018_HW10,
32b129699aSAnilkumar Kolli },
3300402f49SManikanta Pubbisetty { .compatible = "qcom,wcn6750-wifi",
3400402f49SManikanta Pubbisetty .data = (void *)ATH11K_HW_WCN6750_HW10,
3500402f49SManikanta Pubbisetty },
3625edca7bSSriram R { .compatible = "qcom,ipq5018-wifi",
3725edca7bSSriram R .data = (void *)ATH11K_HW_IPQ5018_HW10,
3825edca7bSSriram R },
39d5c65159SKalle Valo { }
40d5c65159SKalle Valo };
41d5c65159SKalle Valo
42d5c65159SKalle Valo MODULE_DEVICE_TABLE(of, ath11k_ahb_of_match);
43d5c65159SKalle Valo
44d5c65159SKalle Valo #define ATH11K_IRQ_CE0_OFFSET 4
45d5c65159SKalle Valo
46d5c65159SKalle Valo static const char *irq_name[ATH11K_IRQ_NUM_MAX] = {
47d5c65159SKalle Valo "misc-pulse1",
48d5c65159SKalle Valo "misc-latch",
49d5c65159SKalle Valo "sw-exception",
50d5c65159SKalle Valo "watchdog",
51d5c65159SKalle Valo "ce0",
52d5c65159SKalle Valo "ce1",
53d5c65159SKalle Valo "ce2",
54d5c65159SKalle Valo "ce3",
55d5c65159SKalle Valo "ce4",
56d5c65159SKalle Valo "ce5",
57d5c65159SKalle Valo "ce6",
58d5c65159SKalle Valo "ce7",
59d5c65159SKalle Valo "ce8",
60d5c65159SKalle Valo "ce9",
61d5c65159SKalle Valo "ce10",
62d5c65159SKalle Valo "ce11",
63d5c65159SKalle Valo "host2wbm-desc-feed",
64d5c65159SKalle Valo "host2reo-re-injection",
65d5c65159SKalle Valo "host2reo-command",
66d5c65159SKalle Valo "host2rxdma-monitor-ring3",
67d5c65159SKalle Valo "host2rxdma-monitor-ring2",
68d5c65159SKalle Valo "host2rxdma-monitor-ring1",
69d5c65159SKalle Valo "reo2ost-exception",
70d5c65159SKalle Valo "wbm2host-rx-release",
71d5c65159SKalle Valo "reo2host-status",
72d5c65159SKalle Valo "reo2host-destination-ring4",
73d5c65159SKalle Valo "reo2host-destination-ring3",
74d5c65159SKalle Valo "reo2host-destination-ring2",
75d5c65159SKalle Valo "reo2host-destination-ring1",
76d5c65159SKalle Valo "rxdma2host-monitor-destination-mac3",
77d5c65159SKalle Valo "rxdma2host-monitor-destination-mac2",
78d5c65159SKalle Valo "rxdma2host-monitor-destination-mac1",
79d5c65159SKalle Valo "ppdu-end-interrupts-mac3",
80d5c65159SKalle Valo "ppdu-end-interrupts-mac2",
81d5c65159SKalle Valo "ppdu-end-interrupts-mac1",
82d5c65159SKalle Valo "rxdma2host-monitor-status-ring-mac3",
83d5c65159SKalle Valo "rxdma2host-monitor-status-ring-mac2",
84d5c65159SKalle Valo "rxdma2host-monitor-status-ring-mac1",
85d5c65159SKalle Valo "host2rxdma-host-buf-ring-mac3",
86d5c65159SKalle Valo "host2rxdma-host-buf-ring-mac2",
87d5c65159SKalle Valo "host2rxdma-host-buf-ring-mac1",
88d5c65159SKalle Valo "rxdma2host-destination-ring-mac3",
89d5c65159SKalle Valo "rxdma2host-destination-ring-mac2",
90d5c65159SKalle Valo "rxdma2host-destination-ring-mac1",
91d5c65159SKalle Valo "host2tcl-input-ring4",
92d5c65159SKalle Valo "host2tcl-input-ring3",
93d5c65159SKalle Valo "host2tcl-input-ring2",
94d5c65159SKalle Valo "host2tcl-input-ring1",
95d5c65159SKalle Valo "wbm2host-tx-completions-ring3",
96d5c65159SKalle Valo "wbm2host-tx-completions-ring2",
97d5c65159SKalle Valo "wbm2host-tx-completions-ring1",
98d5c65159SKalle Valo "tcl2host-status-ring",
99d5c65159SKalle Valo };
100d5c65159SKalle Valo
101d5c65159SKalle Valo /* enum ext_irq_num - irq numbers that can be used by external modules
102d5c65159SKalle Valo * like datapath
103d5c65159SKalle Valo */
104d5c65159SKalle Valo enum ext_irq_num {
105d5c65159SKalle Valo host2wbm_desc_feed = 16,
106d5c65159SKalle Valo host2reo_re_injection,
107d5c65159SKalle Valo host2reo_command,
108d5c65159SKalle Valo host2rxdma_monitor_ring3,
109d5c65159SKalle Valo host2rxdma_monitor_ring2,
110d5c65159SKalle Valo host2rxdma_monitor_ring1,
111d5c65159SKalle Valo reo2host_exception,
112d5c65159SKalle Valo wbm2host_rx_release,
113d5c65159SKalle Valo reo2host_status,
114d5c65159SKalle Valo reo2host_destination_ring4,
115d5c65159SKalle Valo reo2host_destination_ring3,
116d5c65159SKalle Valo reo2host_destination_ring2,
117d5c65159SKalle Valo reo2host_destination_ring1,
118d5c65159SKalle Valo rxdma2host_monitor_destination_mac3,
119d5c65159SKalle Valo rxdma2host_monitor_destination_mac2,
120d5c65159SKalle Valo rxdma2host_monitor_destination_mac1,
121d5c65159SKalle Valo ppdu_end_interrupts_mac3,
122d5c65159SKalle Valo ppdu_end_interrupts_mac2,
123d5c65159SKalle Valo ppdu_end_interrupts_mac1,
124d5c65159SKalle Valo rxdma2host_monitor_status_ring_mac3,
125d5c65159SKalle Valo rxdma2host_monitor_status_ring_mac2,
126d5c65159SKalle Valo rxdma2host_monitor_status_ring_mac1,
127d5c65159SKalle Valo host2rxdma_host_buf_ring_mac3,
128d5c65159SKalle Valo host2rxdma_host_buf_ring_mac2,
129d5c65159SKalle Valo host2rxdma_host_buf_ring_mac1,
130d5c65159SKalle Valo rxdma2host_destination_ring_mac3,
131d5c65159SKalle Valo rxdma2host_destination_ring_mac2,
132d5c65159SKalle Valo rxdma2host_destination_ring_mac1,
133d5c65159SKalle Valo host2tcl_input_ring4,
134d5c65159SKalle Valo host2tcl_input_ring3,
135d5c65159SKalle Valo host2tcl_input_ring2,
136d5c65159SKalle Valo host2tcl_input_ring1,
137d5c65159SKalle Valo wbm2host_tx_completions_ring3,
138d5c65159SKalle Valo wbm2host_tx_completions_ring2,
139d5c65159SKalle Valo wbm2host_tx_completions_ring1,
140d5c65159SKalle Valo tcl2host_status_ring,
141d5c65159SKalle Valo };
142d5c65159SKalle Valo
14300402f49SManikanta Pubbisetty static int
ath11k_ahb_get_msi_irq_wcn6750(struct ath11k_base * ab,unsigned int vector)14400402f49SManikanta Pubbisetty ath11k_ahb_get_msi_irq_wcn6750(struct ath11k_base *ab, unsigned int vector)
14500402f49SManikanta Pubbisetty {
14600402f49SManikanta Pubbisetty return ab->pci.msi.irqs[vector];
14700402f49SManikanta Pubbisetty }
14800402f49SManikanta Pubbisetty
149867f4eeeSManikanta Pubbisetty static inline u32
ath11k_ahb_get_window_start_wcn6750(struct ath11k_base * ab,u32 offset)150867f4eeeSManikanta Pubbisetty ath11k_ahb_get_window_start_wcn6750(struct ath11k_base *ab, u32 offset)
151867f4eeeSManikanta Pubbisetty {
152867f4eeeSManikanta Pubbisetty u32 window_start = 0;
153867f4eeeSManikanta Pubbisetty
154867f4eeeSManikanta Pubbisetty /* If offset lies within DP register range, use 1st window */
155867f4eeeSManikanta Pubbisetty if ((offset ^ HAL_SEQ_WCSS_UMAC_OFFSET) < ATH11K_PCI_WINDOW_RANGE_MASK)
156867f4eeeSManikanta Pubbisetty window_start = ATH11K_PCI_WINDOW_START;
157867f4eeeSManikanta Pubbisetty /* If offset lies within CE register range, use 2nd window */
158867f4eeeSManikanta Pubbisetty else if ((offset ^ HAL_SEQ_WCSS_UMAC_CE0_SRC_REG(ab)) <
159867f4eeeSManikanta Pubbisetty ATH11K_PCI_WINDOW_RANGE_MASK)
160867f4eeeSManikanta Pubbisetty window_start = 2 * ATH11K_PCI_WINDOW_START;
161867f4eeeSManikanta Pubbisetty
162867f4eeeSManikanta Pubbisetty return window_start;
163867f4eeeSManikanta Pubbisetty }
164867f4eeeSManikanta Pubbisetty
165867f4eeeSManikanta Pubbisetty static void
ath11k_ahb_window_write32_wcn6750(struct ath11k_base * ab,u32 offset,u32 value)166867f4eeeSManikanta Pubbisetty ath11k_ahb_window_write32_wcn6750(struct ath11k_base *ab, u32 offset, u32 value)
167867f4eeeSManikanta Pubbisetty {
168867f4eeeSManikanta Pubbisetty u32 window_start;
169867f4eeeSManikanta Pubbisetty
170867f4eeeSManikanta Pubbisetty /* WCN6750 uses static window based register access*/
171867f4eeeSManikanta Pubbisetty window_start = ath11k_ahb_get_window_start_wcn6750(ab, offset);
172867f4eeeSManikanta Pubbisetty
173867f4eeeSManikanta Pubbisetty iowrite32(value, ab->mem + window_start +
174867f4eeeSManikanta Pubbisetty (offset & ATH11K_PCI_WINDOW_RANGE_MASK));
175867f4eeeSManikanta Pubbisetty }
176867f4eeeSManikanta Pubbisetty
ath11k_ahb_window_read32_wcn6750(struct ath11k_base * ab,u32 offset)177867f4eeeSManikanta Pubbisetty static u32 ath11k_ahb_window_read32_wcn6750(struct ath11k_base *ab, u32 offset)
178867f4eeeSManikanta Pubbisetty {
179867f4eeeSManikanta Pubbisetty u32 window_start;
180867f4eeeSManikanta Pubbisetty u32 val;
181867f4eeeSManikanta Pubbisetty
182867f4eeeSManikanta Pubbisetty /* WCN6750 uses static window based register access */
183867f4eeeSManikanta Pubbisetty window_start = ath11k_ahb_get_window_start_wcn6750(ab, offset);
184867f4eeeSManikanta Pubbisetty
185867f4eeeSManikanta Pubbisetty val = ioread32(ab->mem + window_start +
186867f4eeeSManikanta Pubbisetty (offset & ATH11K_PCI_WINDOW_RANGE_MASK));
187867f4eeeSManikanta Pubbisetty return val;
188867f4eeeSManikanta Pubbisetty }
189867f4eeeSManikanta Pubbisetty
19000402f49SManikanta Pubbisetty static const struct ath11k_pci_ops ath11k_ahb_pci_ops_wcn6750 = {
191867f4eeeSManikanta Pubbisetty .wakeup = NULL,
192867f4eeeSManikanta Pubbisetty .release = NULL,
19300402f49SManikanta Pubbisetty .get_msi_irq = ath11k_ahb_get_msi_irq_wcn6750,
194867f4eeeSManikanta Pubbisetty .window_write32 = ath11k_ahb_window_write32_wcn6750,
195867f4eeeSManikanta Pubbisetty .window_read32 = ath11k_ahb_window_read32_wcn6750,
19600402f49SManikanta Pubbisetty };
19700402f49SManikanta Pubbisetty
ath11k_ahb_read32(struct ath11k_base * ab,u32 offset)19831858805SGovind Singh static inline u32 ath11k_ahb_read32(struct ath11k_base *ab, u32 offset)
19931858805SGovind Singh {
20031858805SGovind Singh return ioread32(ab->mem + offset);
20131858805SGovind Singh }
20231858805SGovind Singh
ath11k_ahb_write32(struct ath11k_base * ab,u32 offset,u32 value)20331858805SGovind Singh static inline void ath11k_ahb_write32(struct ath11k_base *ab, u32 offset, u32 value)
20431858805SGovind Singh {
20531858805SGovind Singh iowrite32(value, ab->mem + offset);
20631858805SGovind Singh }
20731858805SGovind Singh
ath11k_ahb_kill_tasklets(struct ath11k_base * ab)208d5c65159SKalle Valo static void ath11k_ahb_kill_tasklets(struct ath11k_base *ab)
209d5c65159SKalle Valo {
210d5c65159SKalle Valo int i;
211d5c65159SKalle Valo
212d9d4b5f3SKalle Valo for (i = 0; i < ab->hw_params.ce_count; i++) {
213d5c65159SKalle Valo struct ath11k_ce_pipe *ce_pipe = &ab->ce.ce_pipe[i];
214d5c65159SKalle Valo
215e3396b8bSCarl Huang if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
216d5c65159SKalle Valo continue;
217d5c65159SKalle Valo
218d5c65159SKalle Valo tasklet_kill(&ce_pipe->intr_tq);
219d5c65159SKalle Valo }
220d5c65159SKalle Valo }
221d5c65159SKalle Valo
ath11k_ahb_ext_grp_disable(struct ath11k_ext_irq_grp * irq_grp)222d5c65159SKalle Valo static void ath11k_ahb_ext_grp_disable(struct ath11k_ext_irq_grp *irq_grp)
223d5c65159SKalle Valo {
224d5c65159SKalle Valo int i;
225d5c65159SKalle Valo
226d5c65159SKalle Valo for (i = 0; i < irq_grp->num_irq; i++)
227d5c65159SKalle Valo disable_irq_nosync(irq_grp->ab->irq_num[irq_grp->irqs[i]]);
228d5c65159SKalle Valo }
229d5c65159SKalle Valo
__ath11k_ahb_ext_irq_disable(struct ath11k_base * ab)230d5c65159SKalle Valo static void __ath11k_ahb_ext_irq_disable(struct ath11k_base *ab)
231d5c65159SKalle Valo {
232d5c65159SKalle Valo int i;
233d5c65159SKalle Valo
234d5c65159SKalle Valo for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
235d5c65159SKalle Valo struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
236d5c65159SKalle Valo
237d5c65159SKalle Valo ath11k_ahb_ext_grp_disable(irq_grp);
238d5c65159SKalle Valo
239d943fdadSBen Greear if (irq_grp->napi_enabled) {
240d5c65159SKalle Valo napi_synchronize(&irq_grp->napi);
241d5c65159SKalle Valo napi_disable(&irq_grp->napi);
242d943fdadSBen Greear irq_grp->napi_enabled = false;
243d943fdadSBen Greear }
244d5c65159SKalle Valo }
245d5c65159SKalle Valo }
246d5c65159SKalle Valo
ath11k_ahb_ext_grp_enable(struct ath11k_ext_irq_grp * irq_grp)247d5c65159SKalle Valo static void ath11k_ahb_ext_grp_enable(struct ath11k_ext_irq_grp *irq_grp)
248d5c65159SKalle Valo {
249d5c65159SKalle Valo int i;
250d5c65159SKalle Valo
251d5c65159SKalle Valo for (i = 0; i < irq_grp->num_irq; i++)
252d5c65159SKalle Valo enable_irq(irq_grp->ab->irq_num[irq_grp->irqs[i]]);
253d5c65159SKalle Valo }
254d5c65159SKalle Valo
ath11k_ahb_setbit32(struct ath11k_base * ab,u8 bit,u32 offset)255d5c65159SKalle Valo static void ath11k_ahb_setbit32(struct ath11k_base *ab, u8 bit, u32 offset)
256d5c65159SKalle Valo {
257d5c65159SKalle Valo u32 val;
258d5c65159SKalle Valo
259d5c65159SKalle Valo val = ath11k_ahb_read32(ab, offset);
260d5c65159SKalle Valo ath11k_ahb_write32(ab, offset, val | BIT(bit));
261d5c65159SKalle Valo }
262d5c65159SKalle Valo
ath11k_ahb_clearbit32(struct ath11k_base * ab,u8 bit,u32 offset)263d5c65159SKalle Valo static void ath11k_ahb_clearbit32(struct ath11k_base *ab, u8 bit, u32 offset)
264d5c65159SKalle Valo {
265d5c65159SKalle Valo u32 val;
266d5c65159SKalle Valo
267d5c65159SKalle Valo val = ath11k_ahb_read32(ab, offset);
268d5c65159SKalle Valo ath11k_ahb_write32(ab, offset, val & ~BIT(bit));
269d5c65159SKalle Valo }
270d5c65159SKalle Valo
ath11k_ahb_ce_irq_enable(struct ath11k_base * ab,u16 ce_id)271d5c65159SKalle Valo static void ath11k_ahb_ce_irq_enable(struct ath11k_base *ab, u16 ce_id)
272d5c65159SKalle Valo {
273b689f091SAnilkumar Kolli const struct ce_attr *ce_attr;
274b42b3678SSriram R const struct ce_ie_addr *ce_ie_addr = ab->hw_params.ce_ie_addr;
275b42b3678SSriram R u32 ie1_reg_addr, ie2_reg_addr, ie3_reg_addr;
276b42b3678SSriram R
277b42b3678SSriram R ie1_reg_addr = ce_ie_addr->ie1_reg_addr + ATH11K_CE_OFFSET(ab);
278b42b3678SSriram R ie2_reg_addr = ce_ie_addr->ie2_reg_addr + ATH11K_CE_OFFSET(ab);
279b42b3678SSriram R ie3_reg_addr = ce_ie_addr->ie3_reg_addr + ATH11K_CE_OFFSET(ab);
280d5c65159SKalle Valo
281b689f091SAnilkumar Kolli ce_attr = &ab->hw_params.host_ce_config[ce_id];
282b689f091SAnilkumar Kolli if (ce_attr->src_nentries)
283b42b3678SSriram R ath11k_ahb_setbit32(ab, ce_id, ie1_reg_addr);
284d5c65159SKalle Valo
285b689f091SAnilkumar Kolli if (ce_attr->dest_nentries) {
286b42b3678SSriram R ath11k_ahb_setbit32(ab, ce_id, ie2_reg_addr);
287d5c65159SKalle Valo ath11k_ahb_setbit32(ab, ce_id + CE_HOST_IE_3_SHIFT,
288b42b3678SSriram R ie3_reg_addr);
289d5c65159SKalle Valo }
290d5c65159SKalle Valo }
291d5c65159SKalle Valo
ath11k_ahb_ce_irq_disable(struct ath11k_base * ab,u16 ce_id)292d5c65159SKalle Valo static void ath11k_ahb_ce_irq_disable(struct ath11k_base *ab, u16 ce_id)
293d5c65159SKalle Valo {
294b689f091SAnilkumar Kolli const struct ce_attr *ce_attr;
295b42b3678SSriram R const struct ce_ie_addr *ce_ie_addr = ab->hw_params.ce_ie_addr;
296b42b3678SSriram R u32 ie1_reg_addr, ie2_reg_addr, ie3_reg_addr;
297b42b3678SSriram R
298b42b3678SSriram R ie1_reg_addr = ce_ie_addr->ie1_reg_addr + ATH11K_CE_OFFSET(ab);
299b42b3678SSriram R ie2_reg_addr = ce_ie_addr->ie2_reg_addr + ATH11K_CE_OFFSET(ab);
300b42b3678SSriram R ie3_reg_addr = ce_ie_addr->ie3_reg_addr + ATH11K_CE_OFFSET(ab);
301d5c65159SKalle Valo
302b689f091SAnilkumar Kolli ce_attr = &ab->hw_params.host_ce_config[ce_id];
303b689f091SAnilkumar Kolli if (ce_attr->src_nentries)
304b42b3678SSriram R ath11k_ahb_clearbit32(ab, ce_id, ie1_reg_addr);
305d5c65159SKalle Valo
306b689f091SAnilkumar Kolli if (ce_attr->dest_nentries) {
307b42b3678SSriram R ath11k_ahb_clearbit32(ab, ce_id, ie2_reg_addr);
308d5c65159SKalle Valo ath11k_ahb_clearbit32(ab, ce_id + CE_HOST_IE_3_SHIFT,
309b42b3678SSriram R ie3_reg_addr);
310d5c65159SKalle Valo }
311d5c65159SKalle Valo }
312d5c65159SKalle Valo
ath11k_ahb_sync_ce_irqs(struct ath11k_base * ab)313d5c65159SKalle Valo static void ath11k_ahb_sync_ce_irqs(struct ath11k_base *ab)
314d5c65159SKalle Valo {
315d5c65159SKalle Valo int i;
316d5c65159SKalle Valo int irq_idx;
317d5c65159SKalle Valo
318d9d4b5f3SKalle Valo for (i = 0; i < ab->hw_params.ce_count; i++) {
319e3396b8bSCarl Huang if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
320d5c65159SKalle Valo continue;
321d5c65159SKalle Valo
322d5c65159SKalle Valo irq_idx = ATH11K_IRQ_CE0_OFFSET + i;
323d5c65159SKalle Valo synchronize_irq(ab->irq_num[irq_idx]);
324d5c65159SKalle Valo }
325d5c65159SKalle Valo }
326d5c65159SKalle Valo
ath11k_ahb_sync_ext_irqs(struct ath11k_base * ab)327d5c65159SKalle Valo static void ath11k_ahb_sync_ext_irqs(struct ath11k_base *ab)
328d5c65159SKalle Valo {
329d5c65159SKalle Valo int i, j;
330d5c65159SKalle Valo int irq_idx;
331d5c65159SKalle Valo
332d5c65159SKalle Valo for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
333d5c65159SKalle Valo struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
334d5c65159SKalle Valo
335d5c65159SKalle Valo for (j = 0; j < irq_grp->num_irq; j++) {
336d5c65159SKalle Valo irq_idx = irq_grp->irqs[j];
337d5c65159SKalle Valo synchronize_irq(ab->irq_num[irq_idx]);
338d5c65159SKalle Valo }
339d5c65159SKalle Valo }
340d5c65159SKalle Valo }
341d5c65159SKalle Valo
ath11k_ahb_ce_irqs_enable(struct ath11k_base * ab)342d5c65159SKalle Valo static void ath11k_ahb_ce_irqs_enable(struct ath11k_base *ab)
343d5c65159SKalle Valo {
344d5c65159SKalle Valo int i;
345d5c65159SKalle Valo
346d9d4b5f3SKalle Valo for (i = 0; i < ab->hw_params.ce_count; i++) {
347e3396b8bSCarl Huang if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
348d5c65159SKalle Valo continue;
349d5c65159SKalle Valo ath11k_ahb_ce_irq_enable(ab, i);
350d5c65159SKalle Valo }
351d5c65159SKalle Valo }
352d5c65159SKalle Valo
ath11k_ahb_ce_irqs_disable(struct ath11k_base * ab)353d5c65159SKalle Valo static void ath11k_ahb_ce_irqs_disable(struct ath11k_base *ab)
354d5c65159SKalle Valo {
355d5c65159SKalle Valo int i;
356d5c65159SKalle Valo
357d9d4b5f3SKalle Valo for (i = 0; i < ab->hw_params.ce_count; i++) {
358e3396b8bSCarl Huang if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
359d5c65159SKalle Valo continue;
360d5c65159SKalle Valo ath11k_ahb_ce_irq_disable(ab, i);
361d5c65159SKalle Valo }
362d5c65159SKalle Valo }
363d5c65159SKalle Valo
ath11k_ahb_start(struct ath11k_base * ab)36431858805SGovind Singh static int ath11k_ahb_start(struct ath11k_base *ab)
365d5c65159SKalle Valo {
366d5c65159SKalle Valo ath11k_ahb_ce_irqs_enable(ab);
367d5c65159SKalle Valo ath11k_ce_rx_post_buf(ab);
368d5c65159SKalle Valo
369d5c65159SKalle Valo return 0;
370d5c65159SKalle Valo }
371d5c65159SKalle Valo
ath11k_ahb_ext_irq_enable(struct ath11k_base * ab)37231858805SGovind Singh static void ath11k_ahb_ext_irq_enable(struct ath11k_base *ab)
373d5c65159SKalle Valo {
374d5c65159SKalle Valo int i;
375d5c65159SKalle Valo
376d5c65159SKalle Valo for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
377d5c65159SKalle Valo struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
378d5c65159SKalle Valo
379d943fdadSBen Greear if (!irq_grp->napi_enabled) {
380d5c65159SKalle Valo napi_enable(&irq_grp->napi);
381d943fdadSBen Greear irq_grp->napi_enabled = true;
382d943fdadSBen Greear }
383d5c65159SKalle Valo ath11k_ahb_ext_grp_enable(irq_grp);
384d5c65159SKalle Valo }
385d5c65159SKalle Valo }
386d5c65159SKalle Valo
ath11k_ahb_ext_irq_disable(struct ath11k_base * ab)38731858805SGovind Singh static void ath11k_ahb_ext_irq_disable(struct ath11k_base *ab)
388d5c65159SKalle Valo {
389d5c65159SKalle Valo __ath11k_ahb_ext_irq_disable(ab);
390d5c65159SKalle Valo ath11k_ahb_sync_ext_irqs(ab);
391d5c65159SKalle Valo }
392d5c65159SKalle Valo
ath11k_ahb_stop(struct ath11k_base * ab)39331858805SGovind Singh static void ath11k_ahb_stop(struct ath11k_base *ab)
394d5c65159SKalle Valo {
395d5c65159SKalle Valo if (!test_bit(ATH11K_FLAG_CRASH_FLUSH, &ab->dev_flags))
396d5c65159SKalle Valo ath11k_ahb_ce_irqs_disable(ab);
397d5c65159SKalle Valo ath11k_ahb_sync_ce_irqs(ab);
398d5c65159SKalle Valo ath11k_ahb_kill_tasklets(ab);
399d5c65159SKalle Valo del_timer_sync(&ab->rx_replenish_retry);
400d5c65159SKalle Valo ath11k_ce_cleanup_pipes(ab);
401d5c65159SKalle Valo }
402d5c65159SKalle Valo
ath11k_ahb_power_up(struct ath11k_base * ab)40331858805SGovind Singh static int ath11k_ahb_power_up(struct ath11k_base *ab)
404d5c65159SKalle Valo {
405ba929d6fSGovind Singh struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab);
406d5c65159SKalle Valo int ret;
407d5c65159SKalle Valo
408ba929d6fSGovind Singh ret = rproc_boot(ab_ahb->tgt_rproc);
409d5c65159SKalle Valo if (ret)
410d5c65159SKalle Valo ath11k_err(ab, "failed to boot the remote processor Q6\n");
411d5c65159SKalle Valo
412d5c65159SKalle Valo return ret;
413d5c65159SKalle Valo }
414d5c65159SKalle Valo
ath11k_ahb_power_down(struct ath11k_base * ab)41531858805SGovind Singh static void ath11k_ahb_power_down(struct ath11k_base *ab)
416d5c65159SKalle Valo {
417ba929d6fSGovind Singh struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab);
418ba929d6fSGovind Singh
419ba929d6fSGovind Singh rproc_shutdown(ab_ahb->tgt_rproc);
420d5c65159SKalle Valo }
421d5c65159SKalle Valo
ath11k_ahb_init_qmi_ce_config(struct ath11k_base * ab)422d5c65159SKalle Valo static void ath11k_ahb_init_qmi_ce_config(struct ath11k_base *ab)
423d5c65159SKalle Valo {
424d5c65159SKalle Valo struct ath11k_qmi_ce_cfg *cfg = &ab->qmi.ce_cfg;
425d5c65159SKalle Valo
426967c1d11SAnilkumar Kolli cfg->tgt_ce_len = ab->hw_params.target_ce_count;
427967c1d11SAnilkumar Kolli cfg->tgt_ce = ab->hw_params.target_ce_config;
428967c1d11SAnilkumar Kolli cfg->svc_to_ce_map_len = ab->hw_params.svc_to_ce_map_len;
429967c1d11SAnilkumar Kolli cfg->svc_to_ce_map = ab->hw_params.svc_to_ce_map;
43016001e4bSAnilkumar Kolli ab->qmi.service_ins_id = ab->hw_params.qmi_service_ins_id;
431d5c65159SKalle Valo }
432d5c65159SKalle Valo
ath11k_ahb_free_ext_irq(struct ath11k_base * ab)433d5c65159SKalle Valo static void ath11k_ahb_free_ext_irq(struct ath11k_base *ab)
434d5c65159SKalle Valo {
435d5c65159SKalle Valo int i, j;
436d5c65159SKalle Valo
437d5c65159SKalle Valo for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
438d5c65159SKalle Valo struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
439d5c65159SKalle Valo
440d5c65159SKalle Valo for (j = 0; j < irq_grp->num_irq; j++)
441d5c65159SKalle Valo free_irq(ab->irq_num[irq_grp->irqs[j]], irq_grp);
44222b59cb9SVenkateswara Naralasetty
44322b59cb9SVenkateswara Naralasetty netif_napi_del(&irq_grp->napi);
444d5c65159SKalle Valo }
445d5c65159SKalle Valo }
446d5c65159SKalle Valo
ath11k_ahb_free_irq(struct ath11k_base * ab)447d5c65159SKalle Valo static void ath11k_ahb_free_irq(struct ath11k_base *ab)
448d5c65159SKalle Valo {
449d5c65159SKalle Valo int irq_idx;
450d5c65159SKalle Valo int i;
451d5c65159SKalle Valo
45200402f49SManikanta Pubbisetty if (ab->hw_params.hybrid_bus_type)
45300402f49SManikanta Pubbisetty return ath11k_pcic_free_irq(ab);
45400402f49SManikanta Pubbisetty
455d9d4b5f3SKalle Valo for (i = 0; i < ab->hw_params.ce_count; i++) {
456e3396b8bSCarl Huang if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
457d5c65159SKalle Valo continue;
458d5c65159SKalle Valo irq_idx = ATH11K_IRQ_CE0_OFFSET + i;
459d5c65159SKalle Valo free_irq(ab->irq_num[irq_idx], &ab->ce.ce_pipe[i]);
460d5c65159SKalle Valo }
461d5c65159SKalle Valo
462d5c65159SKalle Valo ath11k_ahb_free_ext_irq(ab);
463d5c65159SKalle Valo }
464d5c65159SKalle Valo
ath11k_ahb_ce_tasklet(struct tasklet_struct * t)465c08279a9SAllen Pais static void ath11k_ahb_ce_tasklet(struct tasklet_struct *t)
466d5c65159SKalle Valo {
467c08279a9SAllen Pais struct ath11k_ce_pipe *ce_pipe = from_tasklet(ce_pipe, t, intr_tq);
468d5c65159SKalle Valo
469d5c65159SKalle Valo ath11k_ce_per_engine_service(ce_pipe->ab, ce_pipe->pipe_num);
470d5c65159SKalle Valo
471d5c65159SKalle Valo ath11k_ahb_ce_irq_enable(ce_pipe->ab, ce_pipe->pipe_num);
472d5c65159SKalle Valo }
473d5c65159SKalle Valo
ath11k_ahb_ce_interrupt_handler(int irq,void * arg)474d5c65159SKalle Valo static irqreturn_t ath11k_ahb_ce_interrupt_handler(int irq, void *arg)
475d5c65159SKalle Valo {
476d5c65159SKalle Valo struct ath11k_ce_pipe *ce_pipe = arg;
477d5c65159SKalle Valo
4785118935bSManikanta Pubbisetty /* last interrupt received for this CE */
4795118935bSManikanta Pubbisetty ce_pipe->timestamp = jiffies;
4805118935bSManikanta Pubbisetty
481d5c65159SKalle Valo ath11k_ahb_ce_irq_disable(ce_pipe->ab, ce_pipe->pipe_num);
482d5c65159SKalle Valo
483d5c65159SKalle Valo tasklet_schedule(&ce_pipe->intr_tq);
484d5c65159SKalle Valo
485d5c65159SKalle Valo return IRQ_HANDLED;
486d5c65159SKalle Valo }
487d5c65159SKalle Valo
ath11k_ahb_ext_grp_napi_poll(struct napi_struct * napi,int budget)488d5c65159SKalle Valo static int ath11k_ahb_ext_grp_napi_poll(struct napi_struct *napi, int budget)
489d5c65159SKalle Valo {
490d5c65159SKalle Valo struct ath11k_ext_irq_grp *irq_grp = container_of(napi,
491d5c65159SKalle Valo struct ath11k_ext_irq_grp,
492d5c65159SKalle Valo napi);
493d5c65159SKalle Valo struct ath11k_base *ab = irq_grp->ab;
494d5c65159SKalle Valo int work_done;
495d5c65159SKalle Valo
496d5c65159SKalle Valo work_done = ath11k_dp_service_srng(ab, irq_grp, budget);
497d5c65159SKalle Valo if (work_done < budget) {
498d5c65159SKalle Valo napi_complete_done(napi, work_done);
499d5c65159SKalle Valo ath11k_ahb_ext_grp_enable(irq_grp);
500d5c65159SKalle Valo }
501d5c65159SKalle Valo
502d5c65159SKalle Valo if (work_done > budget)
503d5c65159SKalle Valo work_done = budget;
504d5c65159SKalle Valo
505d5c65159SKalle Valo return work_done;
506d5c65159SKalle Valo }
507d5c65159SKalle Valo
ath11k_ahb_ext_interrupt_handler(int irq,void * arg)508d5c65159SKalle Valo static irqreturn_t ath11k_ahb_ext_interrupt_handler(int irq, void *arg)
509d5c65159SKalle Valo {
510d5c65159SKalle Valo struct ath11k_ext_irq_grp *irq_grp = arg;
511d5c65159SKalle Valo
5125118935bSManikanta Pubbisetty /* last interrupt received for this group */
5135118935bSManikanta Pubbisetty irq_grp->timestamp = jiffies;
5145118935bSManikanta Pubbisetty
515d5c65159SKalle Valo ath11k_ahb_ext_grp_disable(irq_grp);
516d5c65159SKalle Valo
517d5c65159SKalle Valo napi_schedule(&irq_grp->napi);
518d5c65159SKalle Valo
519d5c65159SKalle Valo return IRQ_HANDLED;
520d5c65159SKalle Valo }
521d5c65159SKalle Valo
ath11k_ahb_config_ext_irq(struct ath11k_base * ab)522a76ed591SVenkateswara Naralasetty static int ath11k_ahb_config_ext_irq(struct ath11k_base *ab)
523d5c65159SKalle Valo {
524d547ca4cSAnilkumar Kolli struct ath11k_hw_params *hw = &ab->hw_params;
525d5c65159SKalle Valo int i, j;
526d5c65159SKalle Valo int irq;
527d5c65159SKalle Valo int ret;
528d5c65159SKalle Valo
529d5c65159SKalle Valo for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
530d5c65159SKalle Valo struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
531d5c65159SKalle Valo u32 num_irq = 0;
532d5c65159SKalle Valo
533d5c65159SKalle Valo irq_grp->ab = ab;
534d5c65159SKalle Valo irq_grp->grp_id = i;
535d5c65159SKalle Valo init_dummy_netdev(&irq_grp->napi_ndev);
536d5c65159SKalle Valo netif_napi_add(&irq_grp->napi_ndev, &irq_grp->napi,
537b48b89f9SJakub Kicinski ath11k_ahb_ext_grp_napi_poll);
538d5c65159SKalle Valo
539d5c65159SKalle Valo for (j = 0; j < ATH11K_EXT_IRQ_NUM_MAX; j++) {
54034d5a3a8SKalle Valo if (ab->hw_params.ring_mask->tx[i] & BIT(j)) {
541d5c65159SKalle Valo irq_grp->irqs[num_irq++] =
542d5c65159SKalle Valo wbm2host_tx_completions_ring1 - j;
543d5c65159SKalle Valo }
544d5c65159SKalle Valo
54534d5a3a8SKalle Valo if (ab->hw_params.ring_mask->rx[i] & BIT(j)) {
546d5c65159SKalle Valo irq_grp->irqs[num_irq++] =
547d5c65159SKalle Valo reo2host_destination_ring1 - j;
548d5c65159SKalle Valo }
549d5c65159SKalle Valo
55034d5a3a8SKalle Valo if (ab->hw_params.ring_mask->rx_err[i] & BIT(j))
551d5c65159SKalle Valo irq_grp->irqs[num_irq++] = reo2host_exception;
552d5c65159SKalle Valo
55334d5a3a8SKalle Valo if (ab->hw_params.ring_mask->rx_wbm_rel[i] & BIT(j))
554d5c65159SKalle Valo irq_grp->irqs[num_irq++] = wbm2host_rx_release;
555d5c65159SKalle Valo
55634d5a3a8SKalle Valo if (ab->hw_params.ring_mask->reo_status[i] & BIT(j))
557d5c65159SKalle Valo irq_grp->irqs[num_irq++] = reo2host_status;
558d5c65159SKalle Valo
559d547ca4cSAnilkumar Kolli if (j < ab->hw_params.max_radios) {
56034d5a3a8SKalle Valo if (ab->hw_params.ring_mask->rxdma2host[i] & BIT(j)) {
561d5c65159SKalle Valo irq_grp->irqs[num_irq++] =
562d547ca4cSAnilkumar Kolli rxdma2host_destination_ring_mac1 -
563d547ca4cSAnilkumar Kolli ath11k_hw_get_mac_from_pdev_id(hw, j);
564d5c65159SKalle Valo }
565d5c65159SKalle Valo
56634d5a3a8SKalle Valo if (ab->hw_params.ring_mask->host2rxdma[i] & BIT(j)) {
567d5c65159SKalle Valo irq_grp->irqs[num_irq++] =
568d547ca4cSAnilkumar Kolli host2rxdma_host_buf_ring_mac1 -
569d547ca4cSAnilkumar Kolli ath11k_hw_get_mac_from_pdev_id(hw, j);
570d5c65159SKalle Valo }
571d5c65159SKalle Valo
57234d5a3a8SKalle Valo if (ab->hw_params.ring_mask->rx_mon_status[i] & BIT(j)) {
573d5c65159SKalle Valo irq_grp->irqs[num_irq++] =
574d5c65159SKalle Valo ppdu_end_interrupts_mac1 -
575d547ca4cSAnilkumar Kolli ath11k_hw_get_mac_from_pdev_id(hw, j);
576d5c65159SKalle Valo irq_grp->irqs[num_irq++] =
577d5c65159SKalle Valo rxdma2host_monitor_status_ring_mac1 -
578d547ca4cSAnilkumar Kolli ath11k_hw_get_mac_from_pdev_id(hw, j);
579d5c65159SKalle Valo }
580d5c65159SKalle Valo }
581d5c65159SKalle Valo }
582d5c65159SKalle Valo irq_grp->num_irq = num_irq;
583d5c65159SKalle Valo
584d5c65159SKalle Valo for (j = 0; j < irq_grp->num_irq; j++) {
585d5c65159SKalle Valo int irq_idx = irq_grp->irqs[j];
586d5c65159SKalle Valo
587d5c65159SKalle Valo irq = platform_get_irq_byname(ab->pdev,
588d5c65159SKalle Valo irq_name[irq_idx]);
589d5c65159SKalle Valo ab->irq_num[irq_idx] = irq;
59005090864SManikanta Pubbisetty irq_set_status_flags(irq, IRQ_NOAUTOEN | IRQ_DISABLE_UNLAZY);
591d5c65159SKalle Valo ret = request_irq(irq, ath11k_ahb_ext_interrupt_handler,
592d5c65159SKalle Valo IRQF_TRIGGER_RISING,
593d5c65159SKalle Valo irq_name[irq_idx], irq_grp);
594d5c65159SKalle Valo if (ret) {
595d5c65159SKalle Valo ath11k_err(ab, "failed request_irq for %d\n",
596d5c65159SKalle Valo irq);
597d5c65159SKalle Valo }
598d5c65159SKalle Valo }
599d5c65159SKalle Valo }
600d5c65159SKalle Valo
601d5c65159SKalle Valo return 0;
602d5c65159SKalle Valo }
603d5c65159SKalle Valo
ath11k_ahb_config_irq(struct ath11k_base * ab)604d5c65159SKalle Valo static int ath11k_ahb_config_irq(struct ath11k_base *ab)
605d5c65159SKalle Valo {
606d5c65159SKalle Valo int irq, irq_idx, i;
607d5c65159SKalle Valo int ret;
608d5c65159SKalle Valo
60900402f49SManikanta Pubbisetty if (ab->hw_params.hybrid_bus_type)
61000402f49SManikanta Pubbisetty return ath11k_pcic_config_irq(ab);
61100402f49SManikanta Pubbisetty
612d5c65159SKalle Valo /* Configure CE irqs */
613d9d4b5f3SKalle Valo for (i = 0; i < ab->hw_params.ce_count; i++) {
614d5c65159SKalle Valo struct ath11k_ce_pipe *ce_pipe = &ab->ce.ce_pipe[i];
615d5c65159SKalle Valo
616e3396b8bSCarl Huang if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
617d5c65159SKalle Valo continue;
618d5c65159SKalle Valo
619d5c65159SKalle Valo irq_idx = ATH11K_IRQ_CE0_OFFSET + i;
620d5c65159SKalle Valo
621c08279a9SAllen Pais tasklet_setup(&ce_pipe->intr_tq, ath11k_ahb_ce_tasklet);
622d5c65159SKalle Valo irq = platform_get_irq_byname(ab->pdev, irq_name[irq_idx]);
623d5c65159SKalle Valo ret = request_irq(irq, ath11k_ahb_ce_interrupt_handler,
624d5c65159SKalle Valo IRQF_TRIGGER_RISING, irq_name[irq_idx],
625d5c65159SKalle Valo ce_pipe);
626d5c65159SKalle Valo if (ret)
627d5c65159SKalle Valo return ret;
628d5c65159SKalle Valo
629d5c65159SKalle Valo ab->irq_num[irq_idx] = irq;
630d5c65159SKalle Valo }
631d5c65159SKalle Valo
632d5c65159SKalle Valo /* Configure external interrupts */
633a76ed591SVenkateswara Naralasetty ret = ath11k_ahb_config_ext_irq(ab);
634d5c65159SKalle Valo
635d5c65159SKalle Valo return ret;
636d5c65159SKalle Valo }
637d5c65159SKalle Valo
ath11k_ahb_map_service_to_pipe(struct ath11k_base * ab,u16 service_id,u8 * ul_pipe,u8 * dl_pipe)63831858805SGovind Singh static int ath11k_ahb_map_service_to_pipe(struct ath11k_base *ab, u16 service_id,
639d5c65159SKalle Valo u8 *ul_pipe, u8 *dl_pipe)
640d5c65159SKalle Valo {
641d5c65159SKalle Valo const struct service_to_pipe *entry;
642d5c65159SKalle Valo bool ul_set = false, dl_set = false;
643d5c65159SKalle Valo int i;
644d5c65159SKalle Valo
645967c1d11SAnilkumar Kolli for (i = 0; i < ab->hw_params.svc_to_ce_map_len; i++) {
646967c1d11SAnilkumar Kolli entry = &ab->hw_params.svc_to_ce_map[i];
647d5c65159SKalle Valo
648d5c65159SKalle Valo if (__le32_to_cpu(entry->service_id) != service_id)
649d5c65159SKalle Valo continue;
650d5c65159SKalle Valo
651d5c65159SKalle Valo switch (__le32_to_cpu(entry->pipedir)) {
652d5c65159SKalle Valo case PIPEDIR_NONE:
653d5c65159SKalle Valo break;
654d5c65159SKalle Valo case PIPEDIR_IN:
655d5c65159SKalle Valo WARN_ON(dl_set);
656d5c65159SKalle Valo *dl_pipe = __le32_to_cpu(entry->pipenum);
657d5c65159SKalle Valo dl_set = true;
658d5c65159SKalle Valo break;
659d5c65159SKalle Valo case PIPEDIR_OUT:
660d5c65159SKalle Valo WARN_ON(ul_set);
661d5c65159SKalle Valo *ul_pipe = __le32_to_cpu(entry->pipenum);
662d5c65159SKalle Valo ul_set = true;
663d5c65159SKalle Valo break;
664d5c65159SKalle Valo case PIPEDIR_INOUT:
665d5c65159SKalle Valo WARN_ON(dl_set);
666d5c65159SKalle Valo WARN_ON(ul_set);
667d5c65159SKalle Valo *dl_pipe = __le32_to_cpu(entry->pipenum);
668d5c65159SKalle Valo *ul_pipe = __le32_to_cpu(entry->pipenum);
669d5c65159SKalle Valo dl_set = true;
670d5c65159SKalle Valo ul_set = true;
671d5c65159SKalle Valo break;
672d5c65159SKalle Valo }
673d5c65159SKalle Valo }
674d5c65159SKalle Valo
675d5c65159SKalle Valo if (WARN_ON(!ul_set || !dl_set))
676d5c65159SKalle Valo return -ENOENT;
677d5c65159SKalle Valo
678d5c65159SKalle Valo return 0;
679d5c65159SKalle Valo }
680d5c65159SKalle Valo
ath11k_ahb_hif_suspend(struct ath11k_base * ab)68169ccee61SManikanta Pubbisetty static int ath11k_ahb_hif_suspend(struct ath11k_base *ab)
68269ccee61SManikanta Pubbisetty {
68369ccee61SManikanta Pubbisetty struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab);
68469ccee61SManikanta Pubbisetty u32 wake_irq;
68569ccee61SManikanta Pubbisetty u32 value = 0;
68669ccee61SManikanta Pubbisetty int ret;
68769ccee61SManikanta Pubbisetty
68869ccee61SManikanta Pubbisetty if (!device_may_wakeup(ab->dev))
68969ccee61SManikanta Pubbisetty return -EPERM;
69069ccee61SManikanta Pubbisetty
69169ccee61SManikanta Pubbisetty wake_irq = ab->irq_num[ATH11K_PCI_IRQ_CE0_OFFSET + ATH11K_PCI_CE_WAKE_IRQ];
69269ccee61SManikanta Pubbisetty
69369ccee61SManikanta Pubbisetty ret = enable_irq_wake(wake_irq);
69469ccee61SManikanta Pubbisetty if (ret) {
69569ccee61SManikanta Pubbisetty ath11k_err(ab, "failed to enable wakeup irq :%d\n", ret);
69669ccee61SManikanta Pubbisetty return ret;
69769ccee61SManikanta Pubbisetty }
69869ccee61SManikanta Pubbisetty
69969ccee61SManikanta Pubbisetty value = u32_encode_bits(ab_ahb->smp2p_info.seq_no++,
70069ccee61SManikanta Pubbisetty ATH11K_AHB_SMP2P_SMEM_SEQ_NO);
70169ccee61SManikanta Pubbisetty value |= u32_encode_bits(ATH11K_AHB_POWER_SAVE_ENTER,
70269ccee61SManikanta Pubbisetty ATH11K_AHB_SMP2P_SMEM_MSG);
70369ccee61SManikanta Pubbisetty
70469ccee61SManikanta Pubbisetty ret = qcom_smem_state_update_bits(ab_ahb->smp2p_info.smem_state,
70569ccee61SManikanta Pubbisetty ATH11K_AHB_SMP2P_SMEM_VALUE_MASK, value);
70669ccee61SManikanta Pubbisetty if (ret) {
70769ccee61SManikanta Pubbisetty ath11k_err(ab, "failed to send smp2p power save enter cmd :%d\n", ret);
70869ccee61SManikanta Pubbisetty return ret;
70969ccee61SManikanta Pubbisetty }
71069ccee61SManikanta Pubbisetty
711fc3b984aSKalle Valo ath11k_dbg(ab, ATH11K_DBG_AHB, "device suspended\n");
71269ccee61SManikanta Pubbisetty
71369ccee61SManikanta Pubbisetty return ret;
71469ccee61SManikanta Pubbisetty }
71569ccee61SManikanta Pubbisetty
ath11k_ahb_hif_resume(struct ath11k_base * ab)71669ccee61SManikanta Pubbisetty static int ath11k_ahb_hif_resume(struct ath11k_base *ab)
71769ccee61SManikanta Pubbisetty {
71869ccee61SManikanta Pubbisetty struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab);
71969ccee61SManikanta Pubbisetty u32 wake_irq;
72069ccee61SManikanta Pubbisetty u32 value = 0;
72169ccee61SManikanta Pubbisetty int ret;
72269ccee61SManikanta Pubbisetty
72369ccee61SManikanta Pubbisetty if (!device_may_wakeup(ab->dev))
72469ccee61SManikanta Pubbisetty return -EPERM;
72569ccee61SManikanta Pubbisetty
72669ccee61SManikanta Pubbisetty wake_irq = ab->irq_num[ATH11K_PCI_IRQ_CE0_OFFSET + ATH11K_PCI_CE_WAKE_IRQ];
72769ccee61SManikanta Pubbisetty
72869ccee61SManikanta Pubbisetty ret = disable_irq_wake(wake_irq);
72969ccee61SManikanta Pubbisetty if (ret) {
73069ccee61SManikanta Pubbisetty ath11k_err(ab, "failed to disable wakeup irq: %d\n", ret);
73169ccee61SManikanta Pubbisetty return ret;
73269ccee61SManikanta Pubbisetty }
73369ccee61SManikanta Pubbisetty
73469ccee61SManikanta Pubbisetty reinit_completion(&ab->wow.wakeup_completed);
73569ccee61SManikanta Pubbisetty
73669ccee61SManikanta Pubbisetty value = u32_encode_bits(ab_ahb->smp2p_info.seq_no++,
73769ccee61SManikanta Pubbisetty ATH11K_AHB_SMP2P_SMEM_SEQ_NO);
73869ccee61SManikanta Pubbisetty value |= u32_encode_bits(ATH11K_AHB_POWER_SAVE_EXIT,
73969ccee61SManikanta Pubbisetty ATH11K_AHB_SMP2P_SMEM_MSG);
74069ccee61SManikanta Pubbisetty
74169ccee61SManikanta Pubbisetty ret = qcom_smem_state_update_bits(ab_ahb->smp2p_info.smem_state,
74269ccee61SManikanta Pubbisetty ATH11K_AHB_SMP2P_SMEM_VALUE_MASK, value);
74369ccee61SManikanta Pubbisetty if (ret) {
74469ccee61SManikanta Pubbisetty ath11k_err(ab, "failed to send smp2p power save enter cmd :%d\n", ret);
74569ccee61SManikanta Pubbisetty return ret;
74669ccee61SManikanta Pubbisetty }
74769ccee61SManikanta Pubbisetty
74869ccee61SManikanta Pubbisetty ret = wait_for_completion_timeout(&ab->wow.wakeup_completed, 3 * HZ);
74969ccee61SManikanta Pubbisetty if (ret == 0) {
75069ccee61SManikanta Pubbisetty ath11k_warn(ab, "timed out while waiting for wow wakeup completion\n");
75169ccee61SManikanta Pubbisetty return -ETIMEDOUT;
75269ccee61SManikanta Pubbisetty }
75369ccee61SManikanta Pubbisetty
754fc3b984aSKalle Valo ath11k_dbg(ab, ATH11K_DBG_AHB, "device resumed\n");
75569ccee61SManikanta Pubbisetty
75669ccee61SManikanta Pubbisetty return 0;
75769ccee61SManikanta Pubbisetty }
75869ccee61SManikanta Pubbisetty
75900402f49SManikanta Pubbisetty static const struct ath11k_hif_ops ath11k_ahb_hif_ops_ipq8074 = {
76031858805SGovind Singh .start = ath11k_ahb_start,
76131858805SGovind Singh .stop = ath11k_ahb_stop,
76231858805SGovind Singh .read32 = ath11k_ahb_read32,
76331858805SGovind Singh .write32 = ath11k_ahb_write32,
764876eb848SBaochen Qiang .read = NULL,
76531858805SGovind Singh .irq_enable = ath11k_ahb_ext_irq_enable,
76631858805SGovind Singh .irq_disable = ath11k_ahb_ext_irq_disable,
76731858805SGovind Singh .map_service_to_pipe = ath11k_ahb_map_service_to_pipe,
76831858805SGovind Singh .power_down = ath11k_ahb_power_down,
76931858805SGovind Singh .power_up = ath11k_ahb_power_up,
77031858805SGovind Singh };
77131858805SGovind Singh
77200402f49SManikanta Pubbisetty static const struct ath11k_hif_ops ath11k_ahb_hif_ops_wcn6750 = {
77300402f49SManikanta Pubbisetty .start = ath11k_pcic_start,
77400402f49SManikanta Pubbisetty .stop = ath11k_pcic_stop,
77500402f49SManikanta Pubbisetty .read32 = ath11k_pcic_read32,
77600402f49SManikanta Pubbisetty .write32 = ath11k_pcic_write32,
777876eb848SBaochen Qiang .read = NULL,
77800402f49SManikanta Pubbisetty .irq_enable = ath11k_pcic_ext_irq_enable,
77900402f49SManikanta Pubbisetty .irq_disable = ath11k_pcic_ext_irq_disable,
78000402f49SManikanta Pubbisetty .get_msi_address = ath11k_pcic_get_msi_address,
78100402f49SManikanta Pubbisetty .get_user_msi_vector = ath11k_pcic_get_user_msi_assignment,
78200402f49SManikanta Pubbisetty .map_service_to_pipe = ath11k_pcic_map_service_to_pipe,
78300402f49SManikanta Pubbisetty .power_down = ath11k_ahb_power_down,
78400402f49SManikanta Pubbisetty .power_up = ath11k_ahb_power_up,
78569ccee61SManikanta Pubbisetty .suspend = ath11k_ahb_hif_suspend,
78669ccee61SManikanta Pubbisetty .resume = ath11k_ahb_hif_resume,
78769ccee61SManikanta Pubbisetty .ce_irq_enable = ath11k_pci_enable_ce_irqs_except_wake_irq,
78869ccee61SManikanta Pubbisetty .ce_irq_disable = ath11k_pci_disable_ce_irqs_except_wake_irq,
78900402f49SManikanta Pubbisetty };
79000402f49SManikanta Pubbisetty
ath11k_core_get_rproc(struct ath11k_base * ab)791ba929d6fSGovind Singh static int ath11k_core_get_rproc(struct ath11k_base *ab)
792ba929d6fSGovind Singh {
793ba929d6fSGovind Singh struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab);
794ba929d6fSGovind Singh struct device *dev = ab->dev;
795ba929d6fSGovind Singh struct rproc *prproc;
796ba929d6fSGovind Singh phandle rproc_phandle;
797ba929d6fSGovind Singh
798ba929d6fSGovind Singh if (of_property_read_u32(dev->of_node, "qcom,rproc", &rproc_phandle)) {
799ba929d6fSGovind Singh ath11k_err(ab, "failed to get q6_rproc handle\n");
800ba929d6fSGovind Singh return -ENOENT;
801ba929d6fSGovind Singh }
802ba929d6fSGovind Singh
803ba929d6fSGovind Singh prproc = rproc_get_by_phandle(rproc_phandle);
804ba929d6fSGovind Singh if (!prproc) {
805*e9327c72SLuca Weiss ath11k_dbg(ab, ATH11K_DBG_AHB, "failed to get rproc, deferring\n");
806*e9327c72SLuca Weiss return -EPROBE_DEFER;
807ba929d6fSGovind Singh }
808ba929d6fSGovind Singh ab_ahb->tgt_rproc = prproc;
809ba929d6fSGovind Singh
810ba929d6fSGovind Singh return 0;
811ba929d6fSGovind Singh }
812ba929d6fSGovind Singh
ath11k_ahb_setup_msi_resources(struct ath11k_base * ab)81300402f49SManikanta Pubbisetty static int ath11k_ahb_setup_msi_resources(struct ath11k_base *ab)
81400402f49SManikanta Pubbisetty {
81500402f49SManikanta Pubbisetty struct platform_device *pdev = ab->pdev;
81600402f49SManikanta Pubbisetty phys_addr_t msi_addr_pa;
81700402f49SManikanta Pubbisetty dma_addr_t msi_addr_iova;
81800402f49SManikanta Pubbisetty struct resource *res;
81900402f49SManikanta Pubbisetty int int_prop;
82000402f49SManikanta Pubbisetty int ret;
82100402f49SManikanta Pubbisetty int i;
82200402f49SManikanta Pubbisetty
82300402f49SManikanta Pubbisetty ret = ath11k_pcic_init_msi_config(ab);
82400402f49SManikanta Pubbisetty if (ret) {
82500402f49SManikanta Pubbisetty ath11k_err(ab, "failed to init msi config: %d\n", ret);
82600402f49SManikanta Pubbisetty return ret;
82700402f49SManikanta Pubbisetty }
82800402f49SManikanta Pubbisetty
82900402f49SManikanta Pubbisetty res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
83000402f49SManikanta Pubbisetty if (!res) {
83100402f49SManikanta Pubbisetty ath11k_err(ab, "failed to fetch msi_addr\n");
83200402f49SManikanta Pubbisetty return -ENOENT;
83300402f49SManikanta Pubbisetty }
83400402f49SManikanta Pubbisetty
83500402f49SManikanta Pubbisetty msi_addr_pa = res->start;
83600402f49SManikanta Pubbisetty msi_addr_iova = dma_map_resource(ab->dev, msi_addr_pa, PAGE_SIZE,
83700402f49SManikanta Pubbisetty DMA_FROM_DEVICE, 0);
83800402f49SManikanta Pubbisetty if (dma_mapping_error(ab->dev, msi_addr_iova))
83900402f49SManikanta Pubbisetty return -ENOMEM;
84000402f49SManikanta Pubbisetty
84100402f49SManikanta Pubbisetty ab->pci.msi.addr_lo = lower_32_bits(msi_addr_iova);
84200402f49SManikanta Pubbisetty ab->pci.msi.addr_hi = upper_32_bits(msi_addr_iova);
84300402f49SManikanta Pubbisetty
84400402f49SManikanta Pubbisetty ret = of_property_read_u32_index(ab->dev->of_node, "interrupts", 1, &int_prop);
84500402f49SManikanta Pubbisetty if (ret)
84600402f49SManikanta Pubbisetty return ret;
84700402f49SManikanta Pubbisetty
84800402f49SManikanta Pubbisetty ab->pci.msi.ep_base_data = int_prop + 32;
84900402f49SManikanta Pubbisetty
85000402f49SManikanta Pubbisetty for (i = 0; i < ab->pci.msi.config->total_vectors; i++) {
851f1172766SDouglas Anderson ret = platform_get_irq(pdev, i);
852f1172766SDouglas Anderson if (ret < 0)
853f1172766SDouglas Anderson return ret;
85400402f49SManikanta Pubbisetty
855f1172766SDouglas Anderson ab->pci.msi.irqs[i] = ret;
85600402f49SManikanta Pubbisetty }
85700402f49SManikanta Pubbisetty
85800402f49SManikanta Pubbisetty set_bit(ATH11K_FLAG_MULTI_MSI_VECTORS, &ab->dev_flags);
85900402f49SManikanta Pubbisetty
86000402f49SManikanta Pubbisetty return 0;
86100402f49SManikanta Pubbisetty }
86200402f49SManikanta Pubbisetty
ath11k_ahb_setup_smp2p_handle(struct ath11k_base * ab)86369ccee61SManikanta Pubbisetty static int ath11k_ahb_setup_smp2p_handle(struct ath11k_base *ab)
86469ccee61SManikanta Pubbisetty {
86569ccee61SManikanta Pubbisetty struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab);
86669ccee61SManikanta Pubbisetty
86769ccee61SManikanta Pubbisetty if (!ab->hw_params.smp2p_wow_exit)
86869ccee61SManikanta Pubbisetty return 0;
86969ccee61SManikanta Pubbisetty
87069ccee61SManikanta Pubbisetty ab_ahb->smp2p_info.smem_state = qcom_smem_state_get(ab->dev, "wlan-smp2p-out",
87169ccee61SManikanta Pubbisetty &ab_ahb->smp2p_info.smem_bit);
87269ccee61SManikanta Pubbisetty if (IS_ERR(ab_ahb->smp2p_info.smem_state)) {
87369ccee61SManikanta Pubbisetty ath11k_err(ab, "failed to fetch smem state: %ld\n",
87469ccee61SManikanta Pubbisetty PTR_ERR(ab_ahb->smp2p_info.smem_state));
87569ccee61SManikanta Pubbisetty return PTR_ERR(ab_ahb->smp2p_info.smem_state);
87669ccee61SManikanta Pubbisetty }
87769ccee61SManikanta Pubbisetty
87869ccee61SManikanta Pubbisetty return 0;
87969ccee61SManikanta Pubbisetty }
88069ccee61SManikanta Pubbisetty
ath11k_ahb_release_smp2p_handle(struct ath11k_base * ab)88169ccee61SManikanta Pubbisetty static void ath11k_ahb_release_smp2p_handle(struct ath11k_base *ab)
88269ccee61SManikanta Pubbisetty {
88369ccee61SManikanta Pubbisetty struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab);
88469ccee61SManikanta Pubbisetty
88569ccee61SManikanta Pubbisetty if (!ab->hw_params.smp2p_wow_exit)
88669ccee61SManikanta Pubbisetty return;
88769ccee61SManikanta Pubbisetty
88869ccee61SManikanta Pubbisetty qcom_smem_state_put(ab_ahb->smp2p_info.smem_state);
88969ccee61SManikanta Pubbisetty }
89069ccee61SManikanta Pubbisetty
ath11k_ahb_setup_resources(struct ath11k_base * ab)89100402f49SManikanta Pubbisetty static int ath11k_ahb_setup_resources(struct ath11k_base *ab)
89200402f49SManikanta Pubbisetty {
89300402f49SManikanta Pubbisetty struct platform_device *pdev = ab->pdev;
89400402f49SManikanta Pubbisetty struct resource *mem_res;
89500402f49SManikanta Pubbisetty void __iomem *mem;
89600402f49SManikanta Pubbisetty
89700402f49SManikanta Pubbisetty if (ab->hw_params.hybrid_bus_type)
89800402f49SManikanta Pubbisetty return ath11k_ahb_setup_msi_resources(ab);
89900402f49SManikanta Pubbisetty
90000402f49SManikanta Pubbisetty mem = devm_platform_get_and_ioremap_resource(pdev, 0, &mem_res);
90100402f49SManikanta Pubbisetty if (IS_ERR(mem)) {
90200402f49SManikanta Pubbisetty dev_err(&pdev->dev, "ioremap error\n");
90300402f49SManikanta Pubbisetty return PTR_ERR(mem);
90400402f49SManikanta Pubbisetty }
90500402f49SManikanta Pubbisetty
90600402f49SManikanta Pubbisetty ab->mem = mem;
90700402f49SManikanta Pubbisetty ab->mem_len = resource_size(mem_res);
90800402f49SManikanta Pubbisetty
90900402f49SManikanta Pubbisetty return 0;
91000402f49SManikanta Pubbisetty }
91100402f49SManikanta Pubbisetty
ath11k_ahb_setup_msa_resources(struct ath11k_base * ab)912f9eec494SManikanta Pubbisetty static int ath11k_ahb_setup_msa_resources(struct ath11k_base *ab)
913f9eec494SManikanta Pubbisetty {
914f9eec494SManikanta Pubbisetty struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab);
915f9eec494SManikanta Pubbisetty struct device *dev = ab->dev;
916f9eec494SManikanta Pubbisetty struct device_node *node;
917f9eec494SManikanta Pubbisetty struct resource r;
918f9eec494SManikanta Pubbisetty int ret;
919f9eec494SManikanta Pubbisetty
920f9eec494SManikanta Pubbisetty node = of_parse_phandle(dev->of_node, "memory-region", 0);
921f9eec494SManikanta Pubbisetty if (!node)
922f9eec494SManikanta Pubbisetty return -ENOENT;
923f9eec494SManikanta Pubbisetty
924f9eec494SManikanta Pubbisetty ret = of_address_to_resource(node, 0, &r);
925f9eec494SManikanta Pubbisetty of_node_put(node);
926f9eec494SManikanta Pubbisetty if (ret) {
927f9eec494SManikanta Pubbisetty dev_err(dev, "failed to resolve msa fixed region\n");
928f9eec494SManikanta Pubbisetty return ret;
929f9eec494SManikanta Pubbisetty }
930f9eec494SManikanta Pubbisetty
931f9eec494SManikanta Pubbisetty ab_ahb->fw.msa_paddr = r.start;
932f9eec494SManikanta Pubbisetty ab_ahb->fw.msa_size = resource_size(&r);
933f9eec494SManikanta Pubbisetty
934f9eec494SManikanta Pubbisetty node = of_parse_phandle(dev->of_node, "memory-region", 1);
935f9eec494SManikanta Pubbisetty if (!node)
936f9eec494SManikanta Pubbisetty return -ENOENT;
937f9eec494SManikanta Pubbisetty
938f9eec494SManikanta Pubbisetty ret = of_address_to_resource(node, 0, &r);
939f9eec494SManikanta Pubbisetty of_node_put(node);
940f9eec494SManikanta Pubbisetty if (ret) {
941f9eec494SManikanta Pubbisetty dev_err(dev, "failed to resolve ce fixed region\n");
942f9eec494SManikanta Pubbisetty return ret;
943f9eec494SManikanta Pubbisetty }
944f9eec494SManikanta Pubbisetty
945f9eec494SManikanta Pubbisetty ab_ahb->fw.ce_paddr = r.start;
946f9eec494SManikanta Pubbisetty ab_ahb->fw.ce_size = resource_size(&r);
947f9eec494SManikanta Pubbisetty
948f9eec494SManikanta Pubbisetty return 0;
949f9eec494SManikanta Pubbisetty }
950f9eec494SManikanta Pubbisetty
ath11k_ahb_fw_resources_init(struct ath11k_base * ab)951f9eec494SManikanta Pubbisetty static int ath11k_ahb_fw_resources_init(struct ath11k_base *ab)
952f9eec494SManikanta Pubbisetty {
953f9eec494SManikanta Pubbisetty struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab);
954f9eec494SManikanta Pubbisetty struct device *host_dev = ab->dev;
955f9eec494SManikanta Pubbisetty struct platform_device_info info = {0};
956f9eec494SManikanta Pubbisetty struct iommu_domain *iommu_dom;
957f9eec494SManikanta Pubbisetty struct platform_device *pdev;
958f9eec494SManikanta Pubbisetty struct device_node *node;
959f9eec494SManikanta Pubbisetty int ret;
960f9eec494SManikanta Pubbisetty
961f9eec494SManikanta Pubbisetty /* Chipsets not requiring MSA need not initialize
962f9eec494SManikanta Pubbisetty * MSA resources, return success in such cases.
963f9eec494SManikanta Pubbisetty */
964f9eec494SManikanta Pubbisetty if (!ab->hw_params.fixed_fw_mem)
965f9eec494SManikanta Pubbisetty return 0;
966f9eec494SManikanta Pubbisetty
967f9eec494SManikanta Pubbisetty ret = ath11k_ahb_setup_msa_resources(ab);
968f9eec494SManikanta Pubbisetty if (ret) {
969f9eec494SManikanta Pubbisetty ath11k_err(ab, "failed to setup msa resources\n");
970f9eec494SManikanta Pubbisetty return ret;
971f9eec494SManikanta Pubbisetty }
972f9eec494SManikanta Pubbisetty
973f9eec494SManikanta Pubbisetty node = of_get_child_by_name(host_dev->of_node, "wifi-firmware");
974f9eec494SManikanta Pubbisetty if (!node) {
975f9eec494SManikanta Pubbisetty ab_ahb->fw.use_tz = true;
976f9eec494SManikanta Pubbisetty return 0;
977f9eec494SManikanta Pubbisetty }
978f9eec494SManikanta Pubbisetty
979f9eec494SManikanta Pubbisetty info.fwnode = &node->fwnode;
980f9eec494SManikanta Pubbisetty info.parent = host_dev;
981f9eec494SManikanta Pubbisetty info.name = node->name;
982f9eec494SManikanta Pubbisetty info.dma_mask = DMA_BIT_MASK(32);
983f9eec494SManikanta Pubbisetty
984f9eec494SManikanta Pubbisetty pdev = platform_device_register_full(&info);
985f9eec494SManikanta Pubbisetty if (IS_ERR(pdev)) {
986f9eec494SManikanta Pubbisetty of_node_put(node);
987f9eec494SManikanta Pubbisetty return PTR_ERR(pdev);
988f9eec494SManikanta Pubbisetty }
989f9eec494SManikanta Pubbisetty
990f9eec494SManikanta Pubbisetty ret = of_dma_configure(&pdev->dev, node, true);
991f9eec494SManikanta Pubbisetty if (ret) {
992f9eec494SManikanta Pubbisetty ath11k_err(ab, "dma configure fail: %d\n", ret);
993f9eec494SManikanta Pubbisetty goto err_unregister;
994f9eec494SManikanta Pubbisetty }
995f9eec494SManikanta Pubbisetty
996f9eec494SManikanta Pubbisetty ab_ahb->fw.dev = &pdev->dev;
997f9eec494SManikanta Pubbisetty
998f9eec494SManikanta Pubbisetty iommu_dom = iommu_domain_alloc(&platform_bus_type);
999f9eec494SManikanta Pubbisetty if (!iommu_dom) {
1000f9eec494SManikanta Pubbisetty ath11k_err(ab, "failed to allocate iommu domain\n");
1001f9eec494SManikanta Pubbisetty ret = -ENOMEM;
1002f9eec494SManikanta Pubbisetty goto err_unregister;
1003f9eec494SManikanta Pubbisetty }
1004f9eec494SManikanta Pubbisetty
1005f9eec494SManikanta Pubbisetty ret = iommu_attach_device(iommu_dom, ab_ahb->fw.dev);
1006f9eec494SManikanta Pubbisetty if (ret) {
1007f9eec494SManikanta Pubbisetty ath11k_err(ab, "could not attach device: %d\n", ret);
1008f9eec494SManikanta Pubbisetty goto err_iommu_free;
1009f9eec494SManikanta Pubbisetty }
1010f9eec494SManikanta Pubbisetty
1011f9eec494SManikanta Pubbisetty ret = iommu_map(iommu_dom, ab_ahb->fw.msa_paddr,
1012f9eec494SManikanta Pubbisetty ab_ahb->fw.msa_paddr, ab_ahb->fw.msa_size,
10131369459bSJason Gunthorpe IOMMU_READ | IOMMU_WRITE, GFP_KERNEL);
1014f9eec494SManikanta Pubbisetty if (ret) {
1015f9eec494SManikanta Pubbisetty ath11k_err(ab, "failed to map firmware region: %d\n", ret);
1016f9eec494SManikanta Pubbisetty goto err_iommu_detach;
1017f9eec494SManikanta Pubbisetty }
1018f9eec494SManikanta Pubbisetty
1019f9eec494SManikanta Pubbisetty ret = iommu_map(iommu_dom, ab_ahb->fw.ce_paddr,
1020f9eec494SManikanta Pubbisetty ab_ahb->fw.ce_paddr, ab_ahb->fw.ce_size,
10211369459bSJason Gunthorpe IOMMU_READ | IOMMU_WRITE, GFP_KERNEL);
1022f9eec494SManikanta Pubbisetty if (ret) {
1023f9eec494SManikanta Pubbisetty ath11k_err(ab, "failed to map firmware CE region: %d\n", ret);
1024f9eec494SManikanta Pubbisetty goto err_iommu_unmap;
1025f9eec494SManikanta Pubbisetty }
1026f9eec494SManikanta Pubbisetty
1027f9eec494SManikanta Pubbisetty ab_ahb->fw.use_tz = false;
1028f9eec494SManikanta Pubbisetty ab_ahb->fw.iommu_domain = iommu_dom;
1029f9eec494SManikanta Pubbisetty of_node_put(node);
1030f9eec494SManikanta Pubbisetty
1031f9eec494SManikanta Pubbisetty return 0;
1032f9eec494SManikanta Pubbisetty
1033f9eec494SManikanta Pubbisetty err_iommu_unmap:
1034f9eec494SManikanta Pubbisetty iommu_unmap(iommu_dom, ab_ahb->fw.msa_paddr, ab_ahb->fw.msa_size);
1035f9eec494SManikanta Pubbisetty
1036f9eec494SManikanta Pubbisetty err_iommu_detach:
1037f9eec494SManikanta Pubbisetty iommu_detach_device(iommu_dom, ab_ahb->fw.dev);
1038f9eec494SManikanta Pubbisetty
1039f9eec494SManikanta Pubbisetty err_iommu_free:
1040f9eec494SManikanta Pubbisetty iommu_domain_free(iommu_dom);
1041f9eec494SManikanta Pubbisetty
1042f9eec494SManikanta Pubbisetty err_unregister:
1043f9eec494SManikanta Pubbisetty platform_device_unregister(pdev);
1044f9eec494SManikanta Pubbisetty of_node_put(node);
1045f9eec494SManikanta Pubbisetty
1046f9eec494SManikanta Pubbisetty return ret;
1047f9eec494SManikanta Pubbisetty }
1048f9eec494SManikanta Pubbisetty
ath11k_ahb_fw_resource_deinit(struct ath11k_base * ab)1049f9eec494SManikanta Pubbisetty static int ath11k_ahb_fw_resource_deinit(struct ath11k_base *ab)
1050f9eec494SManikanta Pubbisetty {
1051f9eec494SManikanta Pubbisetty struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab);
1052f9eec494SManikanta Pubbisetty struct iommu_domain *iommu;
1053f9eec494SManikanta Pubbisetty size_t unmapped_size;
1054f9eec494SManikanta Pubbisetty
10555a78ac33SAditya Kumar Singh /* Chipsets not requiring MSA would have not initialized
10565a78ac33SAditya Kumar Singh * MSA resources, return success in such cases.
10575a78ac33SAditya Kumar Singh */
10585a78ac33SAditya Kumar Singh if (!ab->hw_params.fixed_fw_mem)
10595a78ac33SAditya Kumar Singh return 0;
10605a78ac33SAditya Kumar Singh
1061f9eec494SManikanta Pubbisetty if (ab_ahb->fw.use_tz)
1062f9eec494SManikanta Pubbisetty return 0;
1063f9eec494SManikanta Pubbisetty
1064f9eec494SManikanta Pubbisetty iommu = ab_ahb->fw.iommu_domain;
1065f9eec494SManikanta Pubbisetty
1066f9eec494SManikanta Pubbisetty unmapped_size = iommu_unmap(iommu, ab_ahb->fw.msa_paddr, ab_ahb->fw.msa_size);
1067f9eec494SManikanta Pubbisetty if (unmapped_size != ab_ahb->fw.msa_size)
1068f9eec494SManikanta Pubbisetty ath11k_err(ab, "failed to unmap firmware: %zu\n",
1069f9eec494SManikanta Pubbisetty unmapped_size);
1070f9eec494SManikanta Pubbisetty
1071f9eec494SManikanta Pubbisetty unmapped_size = iommu_unmap(iommu, ab_ahb->fw.ce_paddr, ab_ahb->fw.ce_size);
1072f9eec494SManikanta Pubbisetty if (unmapped_size != ab_ahb->fw.ce_size)
1073f9eec494SManikanta Pubbisetty ath11k_err(ab, "failed to unmap firmware CE memory: %zu\n",
1074f9eec494SManikanta Pubbisetty unmapped_size);
1075f9eec494SManikanta Pubbisetty
1076f9eec494SManikanta Pubbisetty iommu_detach_device(iommu, ab_ahb->fw.dev);
1077f9eec494SManikanta Pubbisetty iommu_domain_free(iommu);
1078f9eec494SManikanta Pubbisetty
1079f9eec494SManikanta Pubbisetty platform_device_unregister(to_platform_device(ab_ahb->fw.dev));
1080f9eec494SManikanta Pubbisetty
1081f9eec494SManikanta Pubbisetty return 0;
1082f9eec494SManikanta Pubbisetty }
1083f9eec494SManikanta Pubbisetty
ath11k_ahb_probe(struct platform_device * pdev)1084d5c65159SKalle Valo static int ath11k_ahb_probe(struct platform_device *pdev)
1085d5c65159SKalle Valo {
1086d5c65159SKalle Valo struct ath11k_base *ab;
1087d5c65159SKalle Valo const struct of_device_id *of_id;
108800402f49SManikanta Pubbisetty const struct ath11k_hif_ops *hif_ops;
108900402f49SManikanta Pubbisetty const struct ath11k_pci_ops *pci_ops;
109000402f49SManikanta Pubbisetty enum ath11k_hw_rev hw_rev;
1091d5c65159SKalle Valo int ret;
1092d5c65159SKalle Valo
1093d5c65159SKalle Valo of_id = of_match_device(ath11k_ahb_of_match, &pdev->dev);
1094d5c65159SKalle Valo if (!of_id) {
1095d5c65159SKalle Valo dev_err(&pdev->dev, "failed to find matching device tree id\n");
1096d5c65159SKalle Valo return -EINVAL;
1097d5c65159SKalle Valo }
1098d5c65159SKalle Valo
10996763ef19SKrzysztof Kozlowski hw_rev = (uintptr_t)of_id->data;
110000402f49SManikanta Pubbisetty
110100402f49SManikanta Pubbisetty switch (hw_rev) {
110200402f49SManikanta Pubbisetty case ATH11K_HW_IPQ8074:
110300402f49SManikanta Pubbisetty case ATH11K_HW_IPQ6018_HW10:
1104469ddb20SZiyang Huang case ATH11K_HW_IPQ5018_HW10:
110500402f49SManikanta Pubbisetty hif_ops = &ath11k_ahb_hif_ops_ipq8074;
110600402f49SManikanta Pubbisetty pci_ops = NULL;
110700402f49SManikanta Pubbisetty break;
110800402f49SManikanta Pubbisetty case ATH11K_HW_WCN6750_HW10:
110900402f49SManikanta Pubbisetty hif_ops = &ath11k_ahb_hif_ops_wcn6750;
111000402f49SManikanta Pubbisetty pci_ops = &ath11k_ahb_pci_ops_wcn6750;
111100402f49SManikanta Pubbisetty break;
111200402f49SManikanta Pubbisetty default:
111300402f49SManikanta Pubbisetty dev_err(&pdev->dev, "unsupported device type %d\n", hw_rev);
111400402f49SManikanta Pubbisetty return -EOPNOTSUPP;
1115d5c65159SKalle Valo }
1116d5c65159SKalle Valo
1117d5c65159SKalle Valo ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
1118d5c65159SKalle Valo if (ret) {
1119d5c65159SKalle Valo dev_err(&pdev->dev, "failed to set 32-bit consistent dma\n");
1120d5c65159SKalle Valo return ret;
1121d5c65159SKalle Valo }
1122d5c65159SKalle Valo
1123ba929d6fSGovind Singh ab = ath11k_core_alloc(&pdev->dev, sizeof(struct ath11k_ahb),
112492c1858eSManikanta Pubbisetty ATH11K_BUS_AHB);
1125d5c65159SKalle Valo if (!ab) {
1126d5c65159SKalle Valo dev_err(&pdev->dev, "failed to allocate ath11k base\n");
1127d5c65159SKalle Valo return -ENOMEM;
1128d5c65159SKalle Valo }
1129d5c65159SKalle Valo
113000402f49SManikanta Pubbisetty ab->hif.ops = hif_ops;
1131d5c65159SKalle Valo ab->pdev = pdev;
113200402f49SManikanta Pubbisetty ab->hw_rev = hw_rev;
1133b43310e4SGovindaraj Saminathan ab->fw_mode = ATH11K_FIRMWARE_MODE_NORMAL;
1134d5c65159SKalle Valo platform_set_drvdata(pdev, ab);
1135d5c65159SKalle Valo
1136867f4eeeSManikanta Pubbisetty ret = ath11k_pcic_register_pci_ops(ab, pci_ops);
1137867f4eeeSManikanta Pubbisetty if (ret) {
1138867f4eeeSManikanta Pubbisetty ath11k_err(ab, "failed to register PCI ops: %d\n", ret);
1139867f4eeeSManikanta Pubbisetty goto err_core_free;
1140867f4eeeSManikanta Pubbisetty }
1141867f4eeeSManikanta Pubbisetty
1142bebcfd25SManikanta Pubbisetty ret = ath11k_core_pre_init(ab);
114300402f49SManikanta Pubbisetty if (ret)
114400402f49SManikanta Pubbisetty goto err_core_free;
114500402f49SManikanta Pubbisetty
114653a998c4SRaj Kumar Bhagat ret = ath11k_ahb_setup_resources(ab);
114753a998c4SRaj Kumar Bhagat if (ret)
114853a998c4SRaj Kumar Bhagat goto err_core_free;
114953a998c4SRaj Kumar Bhagat
115053a998c4SRaj Kumar Bhagat ab->mem_ce = ab->mem;
115153a998c4SRaj Kumar Bhagat
1152b42b3678SSriram R if (ab->hw_params.ce_remap) {
1153b42b3678SSriram R const struct ce_remap *ce_remap = ab->hw_params.ce_remap;
1154b42b3678SSriram R /* ce register space is moved out of wcss unlike ipq8074 or ipq6018
1155b42b3678SSriram R * and the space is not contiguous, hence remapping the CE registers
1156b42b3678SSriram R * to a new space for accessing them.
1157b42b3678SSriram R */
1158b42b3678SSriram R ab->mem_ce = ioremap(ce_remap->base, ce_remap->size);
1159342fcde9SYang Yingliang if (!ab->mem_ce) {
1160b42b3678SSriram R dev_err(&pdev->dev, "ce ioremap error\n");
1161b42b3678SSriram R ret = -ENOMEM;
1162b42b3678SSriram R goto err_core_free;
1163b42b3678SSriram R }
1164b42b3678SSriram R }
1165b42b3678SSriram R
1166f9eec494SManikanta Pubbisetty ret = ath11k_ahb_fw_resources_init(ab);
1167d5c65159SKalle Valo if (ret)
1168d5c65159SKalle Valo goto err_core_free;
1169d5c65159SKalle Valo
117069ccee61SManikanta Pubbisetty ret = ath11k_ahb_setup_smp2p_handle(ab);
1171f9eec494SManikanta Pubbisetty if (ret)
1172f9eec494SManikanta Pubbisetty goto err_fw_deinit;
1173f9eec494SManikanta Pubbisetty
117469ccee61SManikanta Pubbisetty ret = ath11k_hal_srng_init(ab);
117569ccee61SManikanta Pubbisetty if (ret)
117669ccee61SManikanta Pubbisetty goto err_release_smp2p_handle;
117769ccee61SManikanta Pubbisetty
1178d5c65159SKalle Valo ret = ath11k_ce_alloc_pipes(ab);
1179d5c65159SKalle Valo if (ret) {
1180d5c65159SKalle Valo ath11k_err(ab, "failed to allocate ce pipes: %d\n", ret);
1181d5c65159SKalle Valo goto err_hal_srng_deinit;
1182d5c65159SKalle Valo }
1183d5c65159SKalle Valo
1184d5c65159SKalle Valo ath11k_ahb_init_qmi_ce_config(ab);
1185d5c65159SKalle Valo
1186ba929d6fSGovind Singh ret = ath11k_core_get_rproc(ab);
1187ba929d6fSGovind Singh if (ret) {
1188ba929d6fSGovind Singh ath11k_err(ab, "failed to get rproc: %d\n", ret);
1189ba929d6fSGovind Singh goto err_ce_free;
1190ba929d6fSGovind Singh }
1191ba929d6fSGovind Singh
1192d5c65159SKalle Valo ret = ath11k_core_init(ab);
1193d5c65159SKalle Valo if (ret) {
1194d5c65159SKalle Valo ath11k_err(ab, "failed to init core: %d\n", ret);
1195d5c65159SKalle Valo goto err_ce_free;
1196d5c65159SKalle Valo }
1197d5c65159SKalle Valo
1198166e22b3SAnilkumar Kolli ret = ath11k_ahb_config_irq(ab);
1199166e22b3SAnilkumar Kolli if (ret) {
1200166e22b3SAnilkumar Kolli ath11k_err(ab, "failed to configure irq: %d\n", ret);
1201166e22b3SAnilkumar Kolli goto err_ce_free;
1202166e22b3SAnilkumar Kolli }
1203166e22b3SAnilkumar Kolli
1204bdfc967bSAnilkumar Kolli ath11k_qmi_fwreset_from_cold_boot(ab);
120502f9d3c1SGovindaraj Saminathan
1206d5c65159SKalle Valo return 0;
1207d5c65159SKalle Valo
1208d5c65159SKalle Valo err_ce_free:
1209d5c65159SKalle Valo ath11k_ce_free_pipes(ab);
1210d5c65159SKalle Valo
1211d5c65159SKalle Valo err_hal_srng_deinit:
1212d5c65159SKalle Valo ath11k_hal_srng_deinit(ab);
1213d5c65159SKalle Valo
121469ccee61SManikanta Pubbisetty err_release_smp2p_handle:
121569ccee61SManikanta Pubbisetty ath11k_ahb_release_smp2p_handle(ab);
121669ccee61SManikanta Pubbisetty
1217f9eec494SManikanta Pubbisetty err_fw_deinit:
1218f9eec494SManikanta Pubbisetty ath11k_ahb_fw_resource_deinit(ab);
1219f9eec494SManikanta Pubbisetty
1220d5c65159SKalle Valo err_core_free:
1221d5c65159SKalle Valo ath11k_core_free(ab);
1222d5c65159SKalle Valo platform_set_drvdata(pdev, NULL);
1223d5c65159SKalle Valo
1224d5c65159SKalle Valo return ret;
1225d5c65159SKalle Valo }
1226d5c65159SKalle Valo
ath11k_ahb_remove_prepare(struct ath11k_base * ab)1227ac41c2b6SManikanta Pubbisetty static void ath11k_ahb_remove_prepare(struct ath11k_base *ab)
1228d5c65159SKalle Valo {
122980b892fcSBo YU unsigned long left;
1230d5c65159SKalle Valo
123180b892fcSBo YU if (test_bit(ATH11K_FLAG_RECOVERY, &ab->dev_flags)) {
123280b892fcSBo YU left = wait_for_completion_timeout(&ab->driver_recovery,
1233d5c65159SKalle Valo ATH11K_AHB_RECOVERY_TIMEOUT);
123480b892fcSBo YU if (!left)
123580b892fcSBo YU ath11k_warn(ab, "failed to receive recovery response completion\n");
123680b892fcSBo YU }
1237d5c65159SKalle Valo
1238d5c65159SKalle Valo set_bit(ATH11K_FLAG_UNREGISTERING, &ab->dev_flags);
1239d5c65159SKalle Valo cancel_work_sync(&ab->restart_work);
1240ac41c2b6SManikanta Pubbisetty cancel_work_sync(&ab->qmi.event_work);
1241ac41c2b6SManikanta Pubbisetty }
1242d5c65159SKalle Valo
ath11k_ahb_free_resources(struct ath11k_base * ab)1243ac41c2b6SManikanta Pubbisetty static void ath11k_ahb_free_resources(struct ath11k_base *ab)
1244ac41c2b6SManikanta Pubbisetty {
1245ac41c2b6SManikanta Pubbisetty struct platform_device *pdev = ab->pdev;
1246ac41c2b6SManikanta Pubbisetty
1247d5c65159SKalle Valo ath11k_ahb_free_irq(ab);
1248d5c65159SKalle Valo ath11k_hal_srng_deinit(ab);
124969ccee61SManikanta Pubbisetty ath11k_ahb_release_smp2p_handle(ab);
1250f9eec494SManikanta Pubbisetty ath11k_ahb_fw_resource_deinit(ab);
1251d5c65159SKalle Valo ath11k_ce_free_pipes(ab);
1252b42b3678SSriram R
1253b42b3678SSriram R if (ab->hw_params.ce_remap)
1254b42b3678SSriram R iounmap(ab->mem_ce);
1255b42b3678SSriram R
1256d5c65159SKalle Valo ath11k_core_free(ab);
1257d5c65159SKalle Valo platform_set_drvdata(pdev, NULL);
1258ac41c2b6SManikanta Pubbisetty }
1259ac41c2b6SManikanta Pubbisetty
ath11k_ahb_remove(struct platform_device * pdev)1260ac41c2b6SManikanta Pubbisetty static int ath11k_ahb_remove(struct platform_device *pdev)
1261ac41c2b6SManikanta Pubbisetty {
1262ac41c2b6SManikanta Pubbisetty struct ath11k_base *ab = platform_get_drvdata(pdev);
1263ac41c2b6SManikanta Pubbisetty
1264ac41c2b6SManikanta Pubbisetty if (test_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags)) {
1265ac41c2b6SManikanta Pubbisetty ath11k_ahb_power_down(ab);
1266ac41c2b6SManikanta Pubbisetty ath11k_debugfs_soc_destroy(ab);
1267ac41c2b6SManikanta Pubbisetty ath11k_qmi_deinit_service(ab);
1268ac41c2b6SManikanta Pubbisetty goto qmi_fail;
1269ac41c2b6SManikanta Pubbisetty }
1270ac41c2b6SManikanta Pubbisetty
1271ac41c2b6SManikanta Pubbisetty ath11k_ahb_remove_prepare(ab);
1272ac41c2b6SManikanta Pubbisetty ath11k_core_deinit(ab);
1273ac41c2b6SManikanta Pubbisetty
1274ac41c2b6SManikanta Pubbisetty qmi_fail:
1275ac41c2b6SManikanta Pubbisetty ath11k_ahb_free_resources(ab);
1276d5c65159SKalle Valo
1277d5c65159SKalle Valo return 0;
1278d5c65159SKalle Valo }
1279d5c65159SKalle Valo
ath11k_ahb_shutdown(struct platform_device * pdev)1280ac41c2b6SManikanta Pubbisetty static void ath11k_ahb_shutdown(struct platform_device *pdev)
1281ac41c2b6SManikanta Pubbisetty {
1282ac41c2b6SManikanta Pubbisetty struct ath11k_base *ab = platform_get_drvdata(pdev);
1283ac41c2b6SManikanta Pubbisetty
1284ac41c2b6SManikanta Pubbisetty /* platform shutdown() & remove() are mutually exclusive.
1285ac41c2b6SManikanta Pubbisetty * remove() is invoked during rmmod & shutdown() during
1286ac41c2b6SManikanta Pubbisetty * system reboot/shutdown.
1287ac41c2b6SManikanta Pubbisetty */
1288ac41c2b6SManikanta Pubbisetty ath11k_ahb_remove_prepare(ab);
1289ac41c2b6SManikanta Pubbisetty
1290ac41c2b6SManikanta Pubbisetty if (!(test_bit(ATH11K_FLAG_REGISTERED, &ab->dev_flags)))
1291ac41c2b6SManikanta Pubbisetty goto free_resources;
1292ac41c2b6SManikanta Pubbisetty
1293ac41c2b6SManikanta Pubbisetty ath11k_core_deinit(ab);
1294ac41c2b6SManikanta Pubbisetty
1295ac41c2b6SManikanta Pubbisetty free_resources:
1296ac41c2b6SManikanta Pubbisetty ath11k_ahb_free_resources(ab);
1297ac41c2b6SManikanta Pubbisetty }
1298ac41c2b6SManikanta Pubbisetty
1299d5c65159SKalle Valo static struct platform_driver ath11k_ahb_driver = {
1300d5c65159SKalle Valo .driver = {
1301d5c65159SKalle Valo .name = "ath11k",
1302d5c65159SKalle Valo .of_match_table = ath11k_ahb_of_match,
1303d5c65159SKalle Valo },
1304d5c65159SKalle Valo .probe = ath11k_ahb_probe,
1305d5c65159SKalle Valo .remove = ath11k_ahb_remove,
1306ac41c2b6SManikanta Pubbisetty .shutdown = ath11k_ahb_shutdown,
1307d5c65159SKalle Valo };
1308d5c65159SKalle Valo
1309749a660bSYang Yingliang module_platform_driver(ath11k_ahb_driver);
131031858805SGovind Singh
13116e0355afSGovind Singh MODULE_DESCRIPTION("Driver support for Qualcomm Technologies 802.11ax WLAN AHB devices");
131231858805SGovind Singh MODULE_LICENSE("Dual BSD/GPL");
1313