1dd4f32aeSBjoern A. Zeeb // SPDX-License-Identifier: BSD-3-Clause-Clear
2dd4f32aeSBjoern A. Zeeb /*
3dd4f32aeSBjoern A. Zeeb * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
4*28348caeSBjoern A. Zeeb * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
5dd4f32aeSBjoern A. Zeeb */
6dd4f32aeSBjoern A. Zeeb
7dd4f32aeSBjoern A. Zeeb #include <linux/module.h>
8dd4f32aeSBjoern A. Zeeb #include <linux/platform_device.h>
9dd4f32aeSBjoern A. Zeeb #include <linux/of_device.h>
10dd4f32aeSBjoern A. Zeeb #include <linux/of.h>
11dd4f32aeSBjoern A. Zeeb #include <linux/dma-mapping.h>
12*28348caeSBjoern A. Zeeb #include <linux/of_address.h>
13*28348caeSBjoern A. Zeeb #include <linux/iommu.h>
14dd4f32aeSBjoern A. Zeeb #include "ahb.h"
15dd4f32aeSBjoern A. Zeeb #include "debug.h"
16dd4f32aeSBjoern A. Zeeb #include "hif.h"
17*28348caeSBjoern A. Zeeb #include "qmi.h"
18dd4f32aeSBjoern A. Zeeb #include <linux/remoteproc.h>
19*28348caeSBjoern A. Zeeb #include "pcic.h"
20*28348caeSBjoern A. Zeeb #include <linux/soc/qcom/smem.h>
21*28348caeSBjoern A. Zeeb #include <linux/soc/qcom/smem_state.h>
22dd4f32aeSBjoern A. Zeeb
23dd4f32aeSBjoern A. Zeeb static const struct of_device_id ath11k_ahb_of_match[] = {
24dd4f32aeSBjoern A. Zeeb /* TODO: Should we change the compatible string to something similar
25dd4f32aeSBjoern A. Zeeb * to one that ath10k uses?
26dd4f32aeSBjoern A. Zeeb */
27dd4f32aeSBjoern A. Zeeb { .compatible = "qcom,ipq8074-wifi",
28dd4f32aeSBjoern A. Zeeb .data = (void *)ATH11K_HW_IPQ8074,
29dd4f32aeSBjoern A. Zeeb },
30dd4f32aeSBjoern A. Zeeb { .compatible = "qcom,ipq6018-wifi",
31dd4f32aeSBjoern A. Zeeb .data = (void *)ATH11K_HW_IPQ6018_HW10,
32dd4f32aeSBjoern A. Zeeb },
33*28348caeSBjoern A. Zeeb { .compatible = "qcom,wcn6750-wifi",
34*28348caeSBjoern A. Zeeb .data = (void *)ATH11K_HW_WCN6750_HW10,
35*28348caeSBjoern A. Zeeb },
36*28348caeSBjoern A. Zeeb { .compatible = "qcom,ipq5018-wifi",
37*28348caeSBjoern A. Zeeb .data = (void *)ATH11K_HW_IPQ5018_HW10,
38*28348caeSBjoern A. Zeeb },
39dd4f32aeSBjoern A. Zeeb { }
40dd4f32aeSBjoern A. Zeeb };
41dd4f32aeSBjoern A. Zeeb
42dd4f32aeSBjoern A. Zeeb MODULE_DEVICE_TABLE(of, ath11k_ahb_of_match);
43dd4f32aeSBjoern A. Zeeb
44dd4f32aeSBjoern A. Zeeb #define ATH11K_IRQ_CE0_OFFSET 4
45dd4f32aeSBjoern A. Zeeb
46dd4f32aeSBjoern A. Zeeb static const char *irq_name[ATH11K_IRQ_NUM_MAX] = {
47dd4f32aeSBjoern A. Zeeb "misc-pulse1",
48dd4f32aeSBjoern A. Zeeb "misc-latch",
49dd4f32aeSBjoern A. Zeeb "sw-exception",
50dd4f32aeSBjoern A. Zeeb "watchdog",
51dd4f32aeSBjoern A. Zeeb "ce0",
52dd4f32aeSBjoern A. Zeeb "ce1",
53dd4f32aeSBjoern A. Zeeb "ce2",
54dd4f32aeSBjoern A. Zeeb "ce3",
55dd4f32aeSBjoern A. Zeeb "ce4",
56dd4f32aeSBjoern A. Zeeb "ce5",
57dd4f32aeSBjoern A. Zeeb "ce6",
58dd4f32aeSBjoern A. Zeeb "ce7",
59dd4f32aeSBjoern A. Zeeb "ce8",
60dd4f32aeSBjoern A. Zeeb "ce9",
61dd4f32aeSBjoern A. Zeeb "ce10",
62dd4f32aeSBjoern A. Zeeb "ce11",
63dd4f32aeSBjoern A. Zeeb "host2wbm-desc-feed",
64dd4f32aeSBjoern A. Zeeb "host2reo-re-injection",
65dd4f32aeSBjoern A. Zeeb "host2reo-command",
66dd4f32aeSBjoern A. Zeeb "host2rxdma-monitor-ring3",
67dd4f32aeSBjoern A. Zeeb "host2rxdma-monitor-ring2",
68dd4f32aeSBjoern A. Zeeb "host2rxdma-monitor-ring1",
69dd4f32aeSBjoern A. Zeeb "reo2ost-exception",
70dd4f32aeSBjoern A. Zeeb "wbm2host-rx-release",
71dd4f32aeSBjoern A. Zeeb "reo2host-status",
72dd4f32aeSBjoern A. Zeeb "reo2host-destination-ring4",
73dd4f32aeSBjoern A. Zeeb "reo2host-destination-ring3",
74dd4f32aeSBjoern A. Zeeb "reo2host-destination-ring2",
75dd4f32aeSBjoern A. Zeeb "reo2host-destination-ring1",
76dd4f32aeSBjoern A. Zeeb "rxdma2host-monitor-destination-mac3",
77dd4f32aeSBjoern A. Zeeb "rxdma2host-monitor-destination-mac2",
78dd4f32aeSBjoern A. Zeeb "rxdma2host-monitor-destination-mac1",
79dd4f32aeSBjoern A. Zeeb "ppdu-end-interrupts-mac3",
80dd4f32aeSBjoern A. Zeeb "ppdu-end-interrupts-mac2",
81dd4f32aeSBjoern A. Zeeb "ppdu-end-interrupts-mac1",
82dd4f32aeSBjoern A. Zeeb "rxdma2host-monitor-status-ring-mac3",
83dd4f32aeSBjoern A. Zeeb "rxdma2host-monitor-status-ring-mac2",
84dd4f32aeSBjoern A. Zeeb "rxdma2host-monitor-status-ring-mac1",
85dd4f32aeSBjoern A. Zeeb "host2rxdma-host-buf-ring-mac3",
86dd4f32aeSBjoern A. Zeeb "host2rxdma-host-buf-ring-mac2",
87dd4f32aeSBjoern A. Zeeb "host2rxdma-host-buf-ring-mac1",
88dd4f32aeSBjoern A. Zeeb "rxdma2host-destination-ring-mac3",
89dd4f32aeSBjoern A. Zeeb "rxdma2host-destination-ring-mac2",
90dd4f32aeSBjoern A. Zeeb "rxdma2host-destination-ring-mac1",
91dd4f32aeSBjoern A. Zeeb "host2tcl-input-ring4",
92dd4f32aeSBjoern A. Zeeb "host2tcl-input-ring3",
93dd4f32aeSBjoern A. Zeeb "host2tcl-input-ring2",
94dd4f32aeSBjoern A. Zeeb "host2tcl-input-ring1",
95dd4f32aeSBjoern A. Zeeb "wbm2host-tx-completions-ring3",
96dd4f32aeSBjoern A. Zeeb "wbm2host-tx-completions-ring2",
97dd4f32aeSBjoern A. Zeeb "wbm2host-tx-completions-ring1",
98dd4f32aeSBjoern A. Zeeb "tcl2host-status-ring",
99dd4f32aeSBjoern A. Zeeb };
100dd4f32aeSBjoern A. Zeeb
101dd4f32aeSBjoern A. Zeeb /* enum ext_irq_num - irq numbers that can be used by external modules
102dd4f32aeSBjoern A. Zeeb * like datapath
103dd4f32aeSBjoern A. Zeeb */
104dd4f32aeSBjoern A. Zeeb enum ext_irq_num {
105dd4f32aeSBjoern A. Zeeb host2wbm_desc_feed = 16,
106dd4f32aeSBjoern A. Zeeb host2reo_re_injection,
107dd4f32aeSBjoern A. Zeeb host2reo_command,
108dd4f32aeSBjoern A. Zeeb host2rxdma_monitor_ring3,
109dd4f32aeSBjoern A. Zeeb host2rxdma_monitor_ring2,
110dd4f32aeSBjoern A. Zeeb host2rxdma_monitor_ring1,
111dd4f32aeSBjoern A. Zeeb reo2host_exception,
112dd4f32aeSBjoern A. Zeeb wbm2host_rx_release,
113dd4f32aeSBjoern A. Zeeb reo2host_status,
114dd4f32aeSBjoern A. Zeeb reo2host_destination_ring4,
115dd4f32aeSBjoern A. Zeeb reo2host_destination_ring3,
116dd4f32aeSBjoern A. Zeeb reo2host_destination_ring2,
117dd4f32aeSBjoern A. Zeeb reo2host_destination_ring1,
118dd4f32aeSBjoern A. Zeeb rxdma2host_monitor_destination_mac3,
119dd4f32aeSBjoern A. Zeeb rxdma2host_monitor_destination_mac2,
120dd4f32aeSBjoern A. Zeeb rxdma2host_monitor_destination_mac1,
121dd4f32aeSBjoern A. Zeeb ppdu_end_interrupts_mac3,
122dd4f32aeSBjoern A. Zeeb ppdu_end_interrupts_mac2,
123dd4f32aeSBjoern A. Zeeb ppdu_end_interrupts_mac1,
124dd4f32aeSBjoern A. Zeeb rxdma2host_monitor_status_ring_mac3,
125dd4f32aeSBjoern A. Zeeb rxdma2host_monitor_status_ring_mac2,
126dd4f32aeSBjoern A. Zeeb rxdma2host_monitor_status_ring_mac1,
127dd4f32aeSBjoern A. Zeeb host2rxdma_host_buf_ring_mac3,
128dd4f32aeSBjoern A. Zeeb host2rxdma_host_buf_ring_mac2,
129dd4f32aeSBjoern A. Zeeb host2rxdma_host_buf_ring_mac1,
130dd4f32aeSBjoern A. Zeeb rxdma2host_destination_ring_mac3,
131dd4f32aeSBjoern A. Zeeb rxdma2host_destination_ring_mac2,
132dd4f32aeSBjoern A. Zeeb rxdma2host_destination_ring_mac1,
133dd4f32aeSBjoern A. Zeeb host2tcl_input_ring4,
134dd4f32aeSBjoern A. Zeeb host2tcl_input_ring3,
135dd4f32aeSBjoern A. Zeeb host2tcl_input_ring2,
136dd4f32aeSBjoern A. Zeeb host2tcl_input_ring1,
137dd4f32aeSBjoern A. Zeeb wbm2host_tx_completions_ring3,
138dd4f32aeSBjoern A. Zeeb wbm2host_tx_completions_ring2,
139dd4f32aeSBjoern A. Zeeb wbm2host_tx_completions_ring1,
140dd4f32aeSBjoern A. Zeeb tcl2host_status_ring,
141dd4f32aeSBjoern A. Zeeb };
142dd4f32aeSBjoern A. Zeeb
143*28348caeSBjoern A. Zeeb static int
ath11k_ahb_get_msi_irq_wcn6750(struct ath11k_base * ab,unsigned int vector)144*28348caeSBjoern A. Zeeb ath11k_ahb_get_msi_irq_wcn6750(struct ath11k_base *ab, unsigned int vector)
145*28348caeSBjoern A. Zeeb {
146*28348caeSBjoern A. Zeeb return ab->pci.msi.irqs[vector];
147*28348caeSBjoern A. Zeeb }
148*28348caeSBjoern A. Zeeb
149*28348caeSBjoern A. Zeeb static inline u32
ath11k_ahb_get_window_start_wcn6750(struct ath11k_base * ab,u32 offset)150*28348caeSBjoern A. Zeeb ath11k_ahb_get_window_start_wcn6750(struct ath11k_base *ab, u32 offset)
151*28348caeSBjoern A. Zeeb {
152*28348caeSBjoern A. Zeeb u32 window_start = 0;
153*28348caeSBjoern A. Zeeb
154*28348caeSBjoern A. Zeeb /* If offset lies within DP register range, use 1st window */
155*28348caeSBjoern A. Zeeb if ((offset ^ HAL_SEQ_WCSS_UMAC_OFFSET) < ATH11K_PCI_WINDOW_RANGE_MASK)
156*28348caeSBjoern A. Zeeb window_start = ATH11K_PCI_WINDOW_START;
157*28348caeSBjoern A. Zeeb /* If offset lies within CE register range, use 2nd window */
158*28348caeSBjoern A. Zeeb else if ((offset ^ HAL_SEQ_WCSS_UMAC_CE0_SRC_REG(ab)) <
159*28348caeSBjoern A. Zeeb ATH11K_PCI_WINDOW_RANGE_MASK)
160*28348caeSBjoern A. Zeeb window_start = 2 * ATH11K_PCI_WINDOW_START;
161*28348caeSBjoern A. Zeeb
162*28348caeSBjoern A. Zeeb return window_start;
163*28348caeSBjoern A. Zeeb }
164*28348caeSBjoern A. Zeeb
165*28348caeSBjoern A. Zeeb static void
ath11k_ahb_window_write32_wcn6750(struct ath11k_base * ab,u32 offset,u32 value)166*28348caeSBjoern A. Zeeb ath11k_ahb_window_write32_wcn6750(struct ath11k_base *ab, u32 offset, u32 value)
167*28348caeSBjoern A. Zeeb {
168*28348caeSBjoern A. Zeeb u32 window_start;
169*28348caeSBjoern A. Zeeb
170*28348caeSBjoern A. Zeeb /* WCN6750 uses static window based register access*/
171*28348caeSBjoern A. Zeeb window_start = ath11k_ahb_get_window_start_wcn6750(ab, offset);
172*28348caeSBjoern A. Zeeb
173*28348caeSBjoern A. Zeeb iowrite32(value, ab->mem + window_start +
174*28348caeSBjoern A. Zeeb (offset & ATH11K_PCI_WINDOW_RANGE_MASK));
175*28348caeSBjoern A. Zeeb }
176*28348caeSBjoern A. Zeeb
ath11k_ahb_window_read32_wcn6750(struct ath11k_base * ab,u32 offset)177*28348caeSBjoern A. Zeeb static u32 ath11k_ahb_window_read32_wcn6750(struct ath11k_base *ab, u32 offset)
178*28348caeSBjoern A. Zeeb {
179*28348caeSBjoern A. Zeeb u32 window_start;
180*28348caeSBjoern A. Zeeb u32 val;
181*28348caeSBjoern A. Zeeb
182*28348caeSBjoern A. Zeeb /* WCN6750 uses static window based register access */
183*28348caeSBjoern A. Zeeb window_start = ath11k_ahb_get_window_start_wcn6750(ab, offset);
184*28348caeSBjoern A. Zeeb
185*28348caeSBjoern A. Zeeb val = ioread32(ab->mem + window_start +
186*28348caeSBjoern A. Zeeb (offset & ATH11K_PCI_WINDOW_RANGE_MASK));
187*28348caeSBjoern A. Zeeb return val;
188*28348caeSBjoern A. Zeeb }
189*28348caeSBjoern A. Zeeb
190*28348caeSBjoern A. Zeeb static const struct ath11k_pci_ops ath11k_ahb_pci_ops_wcn6750 = {
191*28348caeSBjoern A. Zeeb .wakeup = NULL,
192*28348caeSBjoern A. Zeeb .release = NULL,
193*28348caeSBjoern A. Zeeb .get_msi_irq = ath11k_ahb_get_msi_irq_wcn6750,
194*28348caeSBjoern A. Zeeb .window_write32 = ath11k_ahb_window_write32_wcn6750,
195*28348caeSBjoern A. Zeeb .window_read32 = ath11k_ahb_window_read32_wcn6750,
196*28348caeSBjoern A. Zeeb };
197*28348caeSBjoern A. Zeeb
ath11k_ahb_read32(struct ath11k_base * ab,u32 offset)198dd4f32aeSBjoern A. Zeeb static inline u32 ath11k_ahb_read32(struct ath11k_base *ab, u32 offset)
199dd4f32aeSBjoern A. Zeeb {
200dd4f32aeSBjoern A. Zeeb return ioread32(ab->mem + offset);
201dd4f32aeSBjoern A. Zeeb }
202dd4f32aeSBjoern A. Zeeb
ath11k_ahb_write32(struct ath11k_base * ab,u32 offset,u32 value)203dd4f32aeSBjoern A. Zeeb static inline void ath11k_ahb_write32(struct ath11k_base *ab, u32 offset, u32 value)
204dd4f32aeSBjoern A. Zeeb {
205dd4f32aeSBjoern A. Zeeb iowrite32(value, ab->mem + offset);
206dd4f32aeSBjoern A. Zeeb }
207dd4f32aeSBjoern A. Zeeb
ath11k_ahb_kill_tasklets(struct ath11k_base * ab)208dd4f32aeSBjoern A. Zeeb static void ath11k_ahb_kill_tasklets(struct ath11k_base *ab)
209dd4f32aeSBjoern A. Zeeb {
210dd4f32aeSBjoern A. Zeeb int i;
211dd4f32aeSBjoern A. Zeeb
212dd4f32aeSBjoern A. Zeeb for (i = 0; i < ab->hw_params.ce_count; i++) {
213dd4f32aeSBjoern A. Zeeb struct ath11k_ce_pipe *ce_pipe = &ab->ce.ce_pipe[i];
214dd4f32aeSBjoern A. Zeeb
215dd4f32aeSBjoern A. Zeeb if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
216dd4f32aeSBjoern A. Zeeb continue;
217dd4f32aeSBjoern A. Zeeb
218dd4f32aeSBjoern A. Zeeb tasklet_kill(&ce_pipe->intr_tq);
219dd4f32aeSBjoern A. Zeeb }
220dd4f32aeSBjoern A. Zeeb }
221dd4f32aeSBjoern A. Zeeb
ath11k_ahb_ext_grp_disable(struct ath11k_ext_irq_grp * irq_grp)222dd4f32aeSBjoern A. Zeeb static void ath11k_ahb_ext_grp_disable(struct ath11k_ext_irq_grp *irq_grp)
223dd4f32aeSBjoern A. Zeeb {
224dd4f32aeSBjoern A. Zeeb int i;
225dd4f32aeSBjoern A. Zeeb
226dd4f32aeSBjoern A. Zeeb for (i = 0; i < irq_grp->num_irq; i++)
227dd4f32aeSBjoern A. Zeeb disable_irq_nosync(irq_grp->ab->irq_num[irq_grp->irqs[i]]);
228dd4f32aeSBjoern A. Zeeb }
229dd4f32aeSBjoern A. Zeeb
__ath11k_ahb_ext_irq_disable(struct ath11k_base * ab)230dd4f32aeSBjoern A. Zeeb static void __ath11k_ahb_ext_irq_disable(struct ath11k_base *ab)
231dd4f32aeSBjoern A. Zeeb {
232dd4f32aeSBjoern A. Zeeb int i;
233dd4f32aeSBjoern A. Zeeb
234dd4f32aeSBjoern A. Zeeb for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
235dd4f32aeSBjoern A. Zeeb struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
236dd4f32aeSBjoern A. Zeeb
237dd4f32aeSBjoern A. Zeeb ath11k_ahb_ext_grp_disable(irq_grp);
238dd4f32aeSBjoern A. Zeeb
239dd4f32aeSBjoern A. Zeeb if (irq_grp->napi_enabled) {
240dd4f32aeSBjoern A. Zeeb napi_synchronize(&irq_grp->napi);
241dd4f32aeSBjoern A. Zeeb napi_disable(&irq_grp->napi);
242dd4f32aeSBjoern A. Zeeb irq_grp->napi_enabled = false;
243dd4f32aeSBjoern A. Zeeb }
244dd4f32aeSBjoern A. Zeeb }
245dd4f32aeSBjoern A. Zeeb }
246dd4f32aeSBjoern A. Zeeb
ath11k_ahb_ext_grp_enable(struct ath11k_ext_irq_grp * irq_grp)247dd4f32aeSBjoern A. Zeeb static void ath11k_ahb_ext_grp_enable(struct ath11k_ext_irq_grp *irq_grp)
248dd4f32aeSBjoern A. Zeeb {
249dd4f32aeSBjoern A. Zeeb int i;
250dd4f32aeSBjoern A. Zeeb
251dd4f32aeSBjoern A. Zeeb for (i = 0; i < irq_grp->num_irq; i++)
252dd4f32aeSBjoern A. Zeeb enable_irq(irq_grp->ab->irq_num[irq_grp->irqs[i]]);
253dd4f32aeSBjoern A. Zeeb }
254dd4f32aeSBjoern A. Zeeb
ath11k_ahb_setbit32(struct ath11k_base * ab,u8 bit,u32 offset)255dd4f32aeSBjoern A. Zeeb static void ath11k_ahb_setbit32(struct ath11k_base *ab, u8 bit, u32 offset)
256dd4f32aeSBjoern A. Zeeb {
257dd4f32aeSBjoern A. Zeeb u32 val;
258dd4f32aeSBjoern A. Zeeb
259dd4f32aeSBjoern A. Zeeb val = ath11k_ahb_read32(ab, offset);
260dd4f32aeSBjoern A. Zeeb ath11k_ahb_write32(ab, offset, val | BIT(bit));
261dd4f32aeSBjoern A. Zeeb }
262dd4f32aeSBjoern A. Zeeb
ath11k_ahb_clearbit32(struct ath11k_base * ab,u8 bit,u32 offset)263dd4f32aeSBjoern A. Zeeb static void ath11k_ahb_clearbit32(struct ath11k_base *ab, u8 bit, u32 offset)
264dd4f32aeSBjoern A. Zeeb {
265dd4f32aeSBjoern A. Zeeb u32 val;
266dd4f32aeSBjoern A. Zeeb
267dd4f32aeSBjoern A. Zeeb val = ath11k_ahb_read32(ab, offset);
268dd4f32aeSBjoern A. Zeeb ath11k_ahb_write32(ab, offset, val & ~BIT(bit));
269dd4f32aeSBjoern A. Zeeb }
270dd4f32aeSBjoern A. Zeeb
ath11k_ahb_ce_irq_enable(struct ath11k_base * ab,u16 ce_id)271dd4f32aeSBjoern A. Zeeb static void ath11k_ahb_ce_irq_enable(struct ath11k_base *ab, u16 ce_id)
272dd4f32aeSBjoern A. Zeeb {
273dd4f32aeSBjoern A. Zeeb const struct ce_attr *ce_attr;
274*28348caeSBjoern A. Zeeb const struct ce_ie_addr *ce_ie_addr = ab->hw_params.ce_ie_addr;
275*28348caeSBjoern A. Zeeb u32 ie1_reg_addr, ie2_reg_addr, ie3_reg_addr;
276*28348caeSBjoern A. Zeeb
277*28348caeSBjoern A. Zeeb ie1_reg_addr = ce_ie_addr->ie1_reg_addr + ATH11K_CE_OFFSET(ab);
278*28348caeSBjoern A. Zeeb ie2_reg_addr = ce_ie_addr->ie2_reg_addr + ATH11K_CE_OFFSET(ab);
279*28348caeSBjoern A. Zeeb ie3_reg_addr = ce_ie_addr->ie3_reg_addr + ATH11K_CE_OFFSET(ab);
280dd4f32aeSBjoern A. Zeeb
281dd4f32aeSBjoern A. Zeeb ce_attr = &ab->hw_params.host_ce_config[ce_id];
282dd4f32aeSBjoern A. Zeeb if (ce_attr->src_nentries)
283*28348caeSBjoern A. Zeeb ath11k_ahb_setbit32(ab, ce_id, ie1_reg_addr);
284dd4f32aeSBjoern A. Zeeb
285dd4f32aeSBjoern A. Zeeb if (ce_attr->dest_nentries) {
286*28348caeSBjoern A. Zeeb ath11k_ahb_setbit32(ab, ce_id, ie2_reg_addr);
287dd4f32aeSBjoern A. Zeeb ath11k_ahb_setbit32(ab, ce_id + CE_HOST_IE_3_SHIFT,
288*28348caeSBjoern A. Zeeb ie3_reg_addr);
289dd4f32aeSBjoern A. Zeeb }
290dd4f32aeSBjoern A. Zeeb }
291dd4f32aeSBjoern A. Zeeb
ath11k_ahb_ce_irq_disable(struct ath11k_base * ab,u16 ce_id)292dd4f32aeSBjoern A. Zeeb static void ath11k_ahb_ce_irq_disable(struct ath11k_base *ab, u16 ce_id)
293dd4f32aeSBjoern A. Zeeb {
294dd4f32aeSBjoern A. Zeeb const struct ce_attr *ce_attr;
295*28348caeSBjoern A. Zeeb const struct ce_ie_addr *ce_ie_addr = ab->hw_params.ce_ie_addr;
296*28348caeSBjoern A. Zeeb u32 ie1_reg_addr, ie2_reg_addr, ie3_reg_addr;
297*28348caeSBjoern A. Zeeb
298*28348caeSBjoern A. Zeeb ie1_reg_addr = ce_ie_addr->ie1_reg_addr + ATH11K_CE_OFFSET(ab);
299*28348caeSBjoern A. Zeeb ie2_reg_addr = ce_ie_addr->ie2_reg_addr + ATH11K_CE_OFFSET(ab);
300*28348caeSBjoern A. Zeeb ie3_reg_addr = ce_ie_addr->ie3_reg_addr + ATH11K_CE_OFFSET(ab);
301dd4f32aeSBjoern A. Zeeb
302dd4f32aeSBjoern A. Zeeb ce_attr = &ab->hw_params.host_ce_config[ce_id];
303dd4f32aeSBjoern A. Zeeb if (ce_attr->src_nentries)
304*28348caeSBjoern A. Zeeb ath11k_ahb_clearbit32(ab, ce_id, ie1_reg_addr);
305dd4f32aeSBjoern A. Zeeb
306dd4f32aeSBjoern A. Zeeb if (ce_attr->dest_nentries) {
307*28348caeSBjoern A. Zeeb ath11k_ahb_clearbit32(ab, ce_id, ie2_reg_addr);
308dd4f32aeSBjoern A. Zeeb ath11k_ahb_clearbit32(ab, ce_id + CE_HOST_IE_3_SHIFT,
309*28348caeSBjoern A. Zeeb ie3_reg_addr);
310dd4f32aeSBjoern A. Zeeb }
311dd4f32aeSBjoern A. Zeeb }
312dd4f32aeSBjoern A. Zeeb
ath11k_ahb_sync_ce_irqs(struct ath11k_base * ab)313dd4f32aeSBjoern A. Zeeb static void ath11k_ahb_sync_ce_irqs(struct ath11k_base *ab)
314dd4f32aeSBjoern A. Zeeb {
315dd4f32aeSBjoern A. Zeeb int i;
316dd4f32aeSBjoern A. Zeeb int irq_idx;
317dd4f32aeSBjoern A. Zeeb
318dd4f32aeSBjoern A. Zeeb for (i = 0; i < ab->hw_params.ce_count; i++) {
319dd4f32aeSBjoern A. Zeeb if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
320dd4f32aeSBjoern A. Zeeb continue;
321dd4f32aeSBjoern A. Zeeb
322dd4f32aeSBjoern A. Zeeb irq_idx = ATH11K_IRQ_CE0_OFFSET + i;
323dd4f32aeSBjoern A. Zeeb synchronize_irq(ab->irq_num[irq_idx]);
324dd4f32aeSBjoern A. Zeeb }
325dd4f32aeSBjoern A. Zeeb }
326dd4f32aeSBjoern A. Zeeb
ath11k_ahb_sync_ext_irqs(struct ath11k_base * ab)327dd4f32aeSBjoern A. Zeeb static void ath11k_ahb_sync_ext_irqs(struct ath11k_base *ab)
328dd4f32aeSBjoern A. Zeeb {
329dd4f32aeSBjoern A. Zeeb int i, j;
330dd4f32aeSBjoern A. Zeeb int irq_idx;
331dd4f32aeSBjoern A. Zeeb
332dd4f32aeSBjoern A. Zeeb for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
333dd4f32aeSBjoern A. Zeeb struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
334dd4f32aeSBjoern A. Zeeb
335dd4f32aeSBjoern A. Zeeb for (j = 0; j < irq_grp->num_irq; j++) {
336dd4f32aeSBjoern A. Zeeb irq_idx = irq_grp->irqs[j];
337dd4f32aeSBjoern A. Zeeb synchronize_irq(ab->irq_num[irq_idx]);
338dd4f32aeSBjoern A. Zeeb }
339dd4f32aeSBjoern A. Zeeb }
340dd4f32aeSBjoern A. Zeeb }
341dd4f32aeSBjoern A. Zeeb
ath11k_ahb_ce_irqs_enable(struct ath11k_base * ab)342dd4f32aeSBjoern A. Zeeb static void ath11k_ahb_ce_irqs_enable(struct ath11k_base *ab)
343dd4f32aeSBjoern A. Zeeb {
344dd4f32aeSBjoern A. Zeeb int i;
345dd4f32aeSBjoern A. Zeeb
346dd4f32aeSBjoern A. Zeeb for (i = 0; i < ab->hw_params.ce_count; i++) {
347dd4f32aeSBjoern A. Zeeb if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
348dd4f32aeSBjoern A. Zeeb continue;
349dd4f32aeSBjoern A. Zeeb ath11k_ahb_ce_irq_enable(ab, i);
350dd4f32aeSBjoern A. Zeeb }
351dd4f32aeSBjoern A. Zeeb }
352dd4f32aeSBjoern A. Zeeb
ath11k_ahb_ce_irqs_disable(struct ath11k_base * ab)353dd4f32aeSBjoern A. Zeeb static void ath11k_ahb_ce_irqs_disable(struct ath11k_base *ab)
354dd4f32aeSBjoern A. Zeeb {
355dd4f32aeSBjoern A. Zeeb int i;
356dd4f32aeSBjoern A. Zeeb
357dd4f32aeSBjoern A. Zeeb for (i = 0; i < ab->hw_params.ce_count; i++) {
358dd4f32aeSBjoern A. Zeeb if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
359dd4f32aeSBjoern A. Zeeb continue;
360dd4f32aeSBjoern A. Zeeb ath11k_ahb_ce_irq_disable(ab, i);
361dd4f32aeSBjoern A. Zeeb }
362dd4f32aeSBjoern A. Zeeb }
363dd4f32aeSBjoern A. Zeeb
ath11k_ahb_start(struct ath11k_base * ab)364dd4f32aeSBjoern A. Zeeb static int ath11k_ahb_start(struct ath11k_base *ab)
365dd4f32aeSBjoern A. Zeeb {
366dd4f32aeSBjoern A. Zeeb ath11k_ahb_ce_irqs_enable(ab);
367dd4f32aeSBjoern A. Zeeb ath11k_ce_rx_post_buf(ab);
368dd4f32aeSBjoern A. Zeeb
369dd4f32aeSBjoern A. Zeeb return 0;
370dd4f32aeSBjoern A. Zeeb }
371dd4f32aeSBjoern A. Zeeb
ath11k_ahb_ext_irq_enable(struct ath11k_base * ab)372dd4f32aeSBjoern A. Zeeb static void ath11k_ahb_ext_irq_enable(struct ath11k_base *ab)
373dd4f32aeSBjoern A. Zeeb {
374dd4f32aeSBjoern A. Zeeb int i;
375dd4f32aeSBjoern A. Zeeb
376dd4f32aeSBjoern A. Zeeb for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
377dd4f32aeSBjoern A. Zeeb struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
378dd4f32aeSBjoern A. Zeeb
379dd4f32aeSBjoern A. Zeeb if (!irq_grp->napi_enabled) {
380dd4f32aeSBjoern A. Zeeb napi_enable(&irq_grp->napi);
381dd4f32aeSBjoern A. Zeeb irq_grp->napi_enabled = true;
382dd4f32aeSBjoern A. Zeeb }
383dd4f32aeSBjoern A. Zeeb ath11k_ahb_ext_grp_enable(irq_grp);
384dd4f32aeSBjoern A. Zeeb }
385dd4f32aeSBjoern A. Zeeb }
386dd4f32aeSBjoern A. Zeeb
ath11k_ahb_ext_irq_disable(struct ath11k_base * ab)387dd4f32aeSBjoern A. Zeeb static void ath11k_ahb_ext_irq_disable(struct ath11k_base *ab)
388dd4f32aeSBjoern A. Zeeb {
389dd4f32aeSBjoern A. Zeeb __ath11k_ahb_ext_irq_disable(ab);
390dd4f32aeSBjoern A. Zeeb ath11k_ahb_sync_ext_irqs(ab);
391dd4f32aeSBjoern A. Zeeb }
392dd4f32aeSBjoern A. Zeeb
ath11k_ahb_stop(struct ath11k_base * ab)393dd4f32aeSBjoern A. Zeeb static void ath11k_ahb_stop(struct ath11k_base *ab)
394dd4f32aeSBjoern A. Zeeb {
395dd4f32aeSBjoern A. Zeeb if (!test_bit(ATH11K_FLAG_CRASH_FLUSH, &ab->dev_flags))
396dd4f32aeSBjoern A. Zeeb ath11k_ahb_ce_irqs_disable(ab);
397dd4f32aeSBjoern A. Zeeb ath11k_ahb_sync_ce_irqs(ab);
398dd4f32aeSBjoern A. Zeeb ath11k_ahb_kill_tasklets(ab);
399dd4f32aeSBjoern A. Zeeb del_timer_sync(&ab->rx_replenish_retry);
400dd4f32aeSBjoern A. Zeeb ath11k_ce_cleanup_pipes(ab);
401dd4f32aeSBjoern A. Zeeb }
402dd4f32aeSBjoern A. Zeeb
ath11k_ahb_power_up(struct ath11k_base * ab)403dd4f32aeSBjoern A. Zeeb static int ath11k_ahb_power_up(struct ath11k_base *ab)
404dd4f32aeSBjoern A. Zeeb {
405dd4f32aeSBjoern A. Zeeb struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab);
406dd4f32aeSBjoern A. Zeeb int ret;
407dd4f32aeSBjoern A. Zeeb
408dd4f32aeSBjoern A. Zeeb ret = rproc_boot(ab_ahb->tgt_rproc);
409dd4f32aeSBjoern A. Zeeb if (ret)
410dd4f32aeSBjoern A. Zeeb ath11k_err(ab, "failed to boot the remote processor Q6\n");
411dd4f32aeSBjoern A. Zeeb
412dd4f32aeSBjoern A. Zeeb return ret;
413dd4f32aeSBjoern A. Zeeb }
414dd4f32aeSBjoern A. Zeeb
ath11k_ahb_power_down(struct ath11k_base * ab)415dd4f32aeSBjoern A. Zeeb static void ath11k_ahb_power_down(struct ath11k_base *ab)
416dd4f32aeSBjoern A. Zeeb {
417dd4f32aeSBjoern A. Zeeb struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab);
418dd4f32aeSBjoern A. Zeeb
419dd4f32aeSBjoern A. Zeeb rproc_shutdown(ab_ahb->tgt_rproc);
420dd4f32aeSBjoern A. Zeeb }
421dd4f32aeSBjoern A. Zeeb
ath11k_ahb_init_qmi_ce_config(struct ath11k_base * ab)422dd4f32aeSBjoern A. Zeeb static void ath11k_ahb_init_qmi_ce_config(struct ath11k_base *ab)
423dd4f32aeSBjoern A. Zeeb {
424dd4f32aeSBjoern A. Zeeb struct ath11k_qmi_ce_cfg *cfg = &ab->qmi.ce_cfg;
425dd4f32aeSBjoern A. Zeeb
426dd4f32aeSBjoern A. Zeeb cfg->tgt_ce_len = ab->hw_params.target_ce_count;
427dd4f32aeSBjoern A. Zeeb cfg->tgt_ce = ab->hw_params.target_ce_config;
428dd4f32aeSBjoern A. Zeeb cfg->svc_to_ce_map_len = ab->hw_params.svc_to_ce_map_len;
429dd4f32aeSBjoern A. Zeeb cfg->svc_to_ce_map = ab->hw_params.svc_to_ce_map;
430dd4f32aeSBjoern A. Zeeb ab->qmi.service_ins_id = ab->hw_params.qmi_service_ins_id;
431dd4f32aeSBjoern A. Zeeb }
432dd4f32aeSBjoern A. Zeeb
ath11k_ahb_free_ext_irq(struct ath11k_base * ab)433dd4f32aeSBjoern A. Zeeb static void ath11k_ahb_free_ext_irq(struct ath11k_base *ab)
434dd4f32aeSBjoern A. Zeeb {
435dd4f32aeSBjoern A. Zeeb int i, j;
436dd4f32aeSBjoern A. Zeeb
437dd4f32aeSBjoern A. Zeeb for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
438dd4f32aeSBjoern A. Zeeb struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
439dd4f32aeSBjoern A. Zeeb
440dd4f32aeSBjoern A. Zeeb for (j = 0; j < irq_grp->num_irq; j++)
441dd4f32aeSBjoern A. Zeeb free_irq(ab->irq_num[irq_grp->irqs[j]], irq_grp);
442*28348caeSBjoern A. Zeeb
443*28348caeSBjoern A. Zeeb netif_napi_del(&irq_grp->napi);
444dd4f32aeSBjoern A. Zeeb }
445dd4f32aeSBjoern A. Zeeb }
446dd4f32aeSBjoern A. Zeeb
ath11k_ahb_free_irq(struct ath11k_base * ab)447dd4f32aeSBjoern A. Zeeb static void ath11k_ahb_free_irq(struct ath11k_base *ab)
448dd4f32aeSBjoern A. Zeeb {
449dd4f32aeSBjoern A. Zeeb int irq_idx;
450dd4f32aeSBjoern A. Zeeb int i;
451dd4f32aeSBjoern A. Zeeb
452*28348caeSBjoern A. Zeeb if (ab->hw_params.hybrid_bus_type)
453*28348caeSBjoern A. Zeeb return ath11k_pcic_free_irq(ab);
454*28348caeSBjoern A. Zeeb
455dd4f32aeSBjoern A. Zeeb for (i = 0; i < ab->hw_params.ce_count; i++) {
456dd4f32aeSBjoern A. Zeeb if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
457dd4f32aeSBjoern A. Zeeb continue;
458dd4f32aeSBjoern A. Zeeb irq_idx = ATH11K_IRQ_CE0_OFFSET + i;
459dd4f32aeSBjoern A. Zeeb free_irq(ab->irq_num[irq_idx], &ab->ce.ce_pipe[i]);
460dd4f32aeSBjoern A. Zeeb }
461dd4f32aeSBjoern A. Zeeb
462dd4f32aeSBjoern A. Zeeb ath11k_ahb_free_ext_irq(ab);
463dd4f32aeSBjoern A. Zeeb }
464dd4f32aeSBjoern A. Zeeb
ath11k_ahb_ce_tasklet(struct tasklet_struct * t)465dd4f32aeSBjoern A. Zeeb static void ath11k_ahb_ce_tasklet(struct tasklet_struct *t)
466dd4f32aeSBjoern A. Zeeb {
467dd4f32aeSBjoern A. Zeeb struct ath11k_ce_pipe *ce_pipe = from_tasklet(ce_pipe, t, intr_tq);
468dd4f32aeSBjoern A. Zeeb
469dd4f32aeSBjoern A. Zeeb ath11k_ce_per_engine_service(ce_pipe->ab, ce_pipe->pipe_num);
470dd4f32aeSBjoern A. Zeeb
471dd4f32aeSBjoern A. Zeeb ath11k_ahb_ce_irq_enable(ce_pipe->ab, ce_pipe->pipe_num);
472dd4f32aeSBjoern A. Zeeb }
473dd4f32aeSBjoern A. Zeeb
ath11k_ahb_ce_interrupt_handler(int irq,void * arg)474dd4f32aeSBjoern A. Zeeb static irqreturn_t ath11k_ahb_ce_interrupt_handler(int irq, void *arg)
475dd4f32aeSBjoern A. Zeeb {
476dd4f32aeSBjoern A. Zeeb struct ath11k_ce_pipe *ce_pipe = arg;
477dd4f32aeSBjoern A. Zeeb
478dd4f32aeSBjoern A. Zeeb /* last interrupt received for this CE */
479dd4f32aeSBjoern A. Zeeb ce_pipe->timestamp = jiffies;
480dd4f32aeSBjoern A. Zeeb
481dd4f32aeSBjoern A. Zeeb ath11k_ahb_ce_irq_disable(ce_pipe->ab, ce_pipe->pipe_num);
482dd4f32aeSBjoern A. Zeeb
483dd4f32aeSBjoern A. Zeeb tasklet_schedule(&ce_pipe->intr_tq);
484dd4f32aeSBjoern A. Zeeb
485dd4f32aeSBjoern A. Zeeb return IRQ_HANDLED;
486dd4f32aeSBjoern A. Zeeb }
487dd4f32aeSBjoern A. Zeeb
ath11k_ahb_ext_grp_napi_poll(struct napi_struct * napi,int budget)488dd4f32aeSBjoern A. Zeeb static int ath11k_ahb_ext_grp_napi_poll(struct napi_struct *napi, int budget)
489dd4f32aeSBjoern A. Zeeb {
490dd4f32aeSBjoern A. Zeeb struct ath11k_ext_irq_grp *irq_grp = container_of(napi,
491dd4f32aeSBjoern A. Zeeb struct ath11k_ext_irq_grp,
492dd4f32aeSBjoern A. Zeeb napi);
493dd4f32aeSBjoern A. Zeeb struct ath11k_base *ab = irq_grp->ab;
494dd4f32aeSBjoern A. Zeeb int work_done;
495dd4f32aeSBjoern A. Zeeb
496dd4f32aeSBjoern A. Zeeb work_done = ath11k_dp_service_srng(ab, irq_grp, budget);
497dd4f32aeSBjoern A. Zeeb if (work_done < budget) {
498dd4f32aeSBjoern A. Zeeb napi_complete_done(napi, work_done);
499dd4f32aeSBjoern A. Zeeb ath11k_ahb_ext_grp_enable(irq_grp);
500dd4f32aeSBjoern A. Zeeb }
501dd4f32aeSBjoern A. Zeeb
502dd4f32aeSBjoern A. Zeeb if (work_done > budget)
503dd4f32aeSBjoern A. Zeeb work_done = budget;
504dd4f32aeSBjoern A. Zeeb
505dd4f32aeSBjoern A. Zeeb return work_done;
506dd4f32aeSBjoern A. Zeeb }
507dd4f32aeSBjoern A. Zeeb
ath11k_ahb_ext_interrupt_handler(int irq,void * arg)508dd4f32aeSBjoern A. Zeeb static irqreturn_t ath11k_ahb_ext_interrupt_handler(int irq, void *arg)
509dd4f32aeSBjoern A. Zeeb {
510dd4f32aeSBjoern A. Zeeb struct ath11k_ext_irq_grp *irq_grp = arg;
511dd4f32aeSBjoern A. Zeeb
512dd4f32aeSBjoern A. Zeeb /* last interrupt received for this group */
513dd4f32aeSBjoern A. Zeeb irq_grp->timestamp = jiffies;
514dd4f32aeSBjoern A. Zeeb
515dd4f32aeSBjoern A. Zeeb ath11k_ahb_ext_grp_disable(irq_grp);
516dd4f32aeSBjoern A. Zeeb
517dd4f32aeSBjoern A. Zeeb napi_schedule(&irq_grp->napi);
518dd4f32aeSBjoern A. Zeeb
519dd4f32aeSBjoern A. Zeeb return IRQ_HANDLED;
520dd4f32aeSBjoern A. Zeeb }
521dd4f32aeSBjoern A. Zeeb
ath11k_ahb_config_ext_irq(struct ath11k_base * ab)522*28348caeSBjoern A. Zeeb static int ath11k_ahb_config_ext_irq(struct ath11k_base *ab)
523dd4f32aeSBjoern A. Zeeb {
524dd4f32aeSBjoern A. Zeeb struct ath11k_hw_params *hw = &ab->hw_params;
525dd4f32aeSBjoern A. Zeeb int i, j;
526dd4f32aeSBjoern A. Zeeb int irq;
527dd4f32aeSBjoern A. Zeeb int ret;
528dd4f32aeSBjoern A. Zeeb
529dd4f32aeSBjoern A. Zeeb for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
530dd4f32aeSBjoern A. Zeeb struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
531dd4f32aeSBjoern A. Zeeb u32 num_irq = 0;
532dd4f32aeSBjoern A. Zeeb
533dd4f32aeSBjoern A. Zeeb irq_grp->ab = ab;
534dd4f32aeSBjoern A. Zeeb irq_grp->grp_id = i;
535dd4f32aeSBjoern A. Zeeb init_dummy_netdev(&irq_grp->napi_ndev);
536dd4f32aeSBjoern A. Zeeb netif_napi_add(&irq_grp->napi_ndev, &irq_grp->napi,
537dd4f32aeSBjoern A. Zeeb ath11k_ahb_ext_grp_napi_poll);
538dd4f32aeSBjoern A. Zeeb
539dd4f32aeSBjoern A. Zeeb for (j = 0; j < ATH11K_EXT_IRQ_NUM_MAX; j++) {
540dd4f32aeSBjoern A. Zeeb if (ab->hw_params.ring_mask->tx[i] & BIT(j)) {
541dd4f32aeSBjoern A. Zeeb irq_grp->irqs[num_irq++] =
542dd4f32aeSBjoern A. Zeeb wbm2host_tx_completions_ring1 - j;
543dd4f32aeSBjoern A. Zeeb }
544dd4f32aeSBjoern A. Zeeb
545dd4f32aeSBjoern A. Zeeb if (ab->hw_params.ring_mask->rx[i] & BIT(j)) {
546dd4f32aeSBjoern A. Zeeb irq_grp->irqs[num_irq++] =
547dd4f32aeSBjoern A. Zeeb reo2host_destination_ring1 - j;
548dd4f32aeSBjoern A. Zeeb }
549dd4f32aeSBjoern A. Zeeb
550dd4f32aeSBjoern A. Zeeb if (ab->hw_params.ring_mask->rx_err[i] & BIT(j))
551dd4f32aeSBjoern A. Zeeb irq_grp->irqs[num_irq++] = reo2host_exception;
552dd4f32aeSBjoern A. Zeeb
553dd4f32aeSBjoern A. Zeeb if (ab->hw_params.ring_mask->rx_wbm_rel[i] & BIT(j))
554dd4f32aeSBjoern A. Zeeb irq_grp->irqs[num_irq++] = wbm2host_rx_release;
555dd4f32aeSBjoern A. Zeeb
556dd4f32aeSBjoern A. Zeeb if (ab->hw_params.ring_mask->reo_status[i] & BIT(j))
557dd4f32aeSBjoern A. Zeeb irq_grp->irqs[num_irq++] = reo2host_status;
558dd4f32aeSBjoern A. Zeeb
559dd4f32aeSBjoern A. Zeeb if (j < ab->hw_params.max_radios) {
560dd4f32aeSBjoern A. Zeeb if (ab->hw_params.ring_mask->rxdma2host[i] & BIT(j)) {
561dd4f32aeSBjoern A. Zeeb irq_grp->irqs[num_irq++] =
562dd4f32aeSBjoern A. Zeeb rxdma2host_destination_ring_mac1 -
563dd4f32aeSBjoern A. Zeeb ath11k_hw_get_mac_from_pdev_id(hw, j);
564dd4f32aeSBjoern A. Zeeb }
565dd4f32aeSBjoern A. Zeeb
566dd4f32aeSBjoern A. Zeeb if (ab->hw_params.ring_mask->host2rxdma[i] & BIT(j)) {
567dd4f32aeSBjoern A. Zeeb irq_grp->irqs[num_irq++] =
568dd4f32aeSBjoern A. Zeeb host2rxdma_host_buf_ring_mac1 -
569dd4f32aeSBjoern A. Zeeb ath11k_hw_get_mac_from_pdev_id(hw, j);
570dd4f32aeSBjoern A. Zeeb }
571dd4f32aeSBjoern A. Zeeb
572dd4f32aeSBjoern A. Zeeb if (ab->hw_params.ring_mask->rx_mon_status[i] & BIT(j)) {
573dd4f32aeSBjoern A. Zeeb irq_grp->irqs[num_irq++] =
574dd4f32aeSBjoern A. Zeeb ppdu_end_interrupts_mac1 -
575dd4f32aeSBjoern A. Zeeb ath11k_hw_get_mac_from_pdev_id(hw, j);
576dd4f32aeSBjoern A. Zeeb irq_grp->irqs[num_irq++] =
577dd4f32aeSBjoern A. Zeeb rxdma2host_monitor_status_ring_mac1 -
578dd4f32aeSBjoern A. Zeeb ath11k_hw_get_mac_from_pdev_id(hw, j);
579dd4f32aeSBjoern A. Zeeb }
580dd4f32aeSBjoern A. Zeeb }
581dd4f32aeSBjoern A. Zeeb }
582dd4f32aeSBjoern A. Zeeb irq_grp->num_irq = num_irq;
583dd4f32aeSBjoern A. Zeeb
584dd4f32aeSBjoern A. Zeeb for (j = 0; j < irq_grp->num_irq; j++) {
585dd4f32aeSBjoern A. Zeeb int irq_idx = irq_grp->irqs[j];
586dd4f32aeSBjoern A. Zeeb
587dd4f32aeSBjoern A. Zeeb irq = platform_get_irq_byname(ab->pdev,
588dd4f32aeSBjoern A. Zeeb irq_name[irq_idx]);
589dd4f32aeSBjoern A. Zeeb ab->irq_num[irq_idx] = irq;
590dd4f32aeSBjoern A. Zeeb irq_set_status_flags(irq, IRQ_NOAUTOEN | IRQ_DISABLE_UNLAZY);
591dd4f32aeSBjoern A. Zeeb ret = request_irq(irq, ath11k_ahb_ext_interrupt_handler,
592dd4f32aeSBjoern A. Zeeb IRQF_TRIGGER_RISING,
593dd4f32aeSBjoern A. Zeeb irq_name[irq_idx], irq_grp);
594dd4f32aeSBjoern A. Zeeb if (ret) {
595dd4f32aeSBjoern A. Zeeb ath11k_err(ab, "failed request_irq for %d\n",
596dd4f32aeSBjoern A. Zeeb irq);
597dd4f32aeSBjoern A. Zeeb }
598dd4f32aeSBjoern A. Zeeb }
599dd4f32aeSBjoern A. Zeeb }
600dd4f32aeSBjoern A. Zeeb
601dd4f32aeSBjoern A. Zeeb return 0;
602dd4f32aeSBjoern A. Zeeb }
603dd4f32aeSBjoern A. Zeeb
ath11k_ahb_config_irq(struct ath11k_base * ab)604dd4f32aeSBjoern A. Zeeb static int ath11k_ahb_config_irq(struct ath11k_base *ab)
605dd4f32aeSBjoern A. Zeeb {
606dd4f32aeSBjoern A. Zeeb int irq, irq_idx, i;
607dd4f32aeSBjoern A. Zeeb int ret;
608dd4f32aeSBjoern A. Zeeb
609*28348caeSBjoern A. Zeeb if (ab->hw_params.hybrid_bus_type)
610*28348caeSBjoern A. Zeeb return ath11k_pcic_config_irq(ab);
611*28348caeSBjoern A. Zeeb
612dd4f32aeSBjoern A. Zeeb /* Configure CE irqs */
613dd4f32aeSBjoern A. Zeeb for (i = 0; i < ab->hw_params.ce_count; i++) {
614dd4f32aeSBjoern A. Zeeb struct ath11k_ce_pipe *ce_pipe = &ab->ce.ce_pipe[i];
615dd4f32aeSBjoern A. Zeeb
616dd4f32aeSBjoern A. Zeeb if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
617dd4f32aeSBjoern A. Zeeb continue;
618dd4f32aeSBjoern A. Zeeb
619dd4f32aeSBjoern A. Zeeb irq_idx = ATH11K_IRQ_CE0_OFFSET + i;
620dd4f32aeSBjoern A. Zeeb
621dd4f32aeSBjoern A. Zeeb tasklet_setup(&ce_pipe->intr_tq, ath11k_ahb_ce_tasklet);
622dd4f32aeSBjoern A. Zeeb irq = platform_get_irq_byname(ab->pdev, irq_name[irq_idx]);
623dd4f32aeSBjoern A. Zeeb ret = request_irq(irq, ath11k_ahb_ce_interrupt_handler,
624dd4f32aeSBjoern A. Zeeb IRQF_TRIGGER_RISING, irq_name[irq_idx],
625dd4f32aeSBjoern A. Zeeb ce_pipe);
626dd4f32aeSBjoern A. Zeeb if (ret)
627dd4f32aeSBjoern A. Zeeb return ret;
628dd4f32aeSBjoern A. Zeeb
629dd4f32aeSBjoern A. Zeeb ab->irq_num[irq_idx] = irq;
630dd4f32aeSBjoern A. Zeeb }
631dd4f32aeSBjoern A. Zeeb
632dd4f32aeSBjoern A. Zeeb /* Configure external interrupts */
633*28348caeSBjoern A. Zeeb ret = ath11k_ahb_config_ext_irq(ab);
634dd4f32aeSBjoern A. Zeeb
635dd4f32aeSBjoern A. Zeeb return ret;
636dd4f32aeSBjoern A. Zeeb }
637dd4f32aeSBjoern A. Zeeb
ath11k_ahb_map_service_to_pipe(struct ath11k_base * ab,u16 service_id,u8 * ul_pipe,u8 * dl_pipe)638dd4f32aeSBjoern A. Zeeb static int ath11k_ahb_map_service_to_pipe(struct ath11k_base *ab, u16 service_id,
639dd4f32aeSBjoern A. Zeeb u8 *ul_pipe, u8 *dl_pipe)
640dd4f32aeSBjoern A. Zeeb {
641dd4f32aeSBjoern A. Zeeb const struct service_to_pipe *entry;
642dd4f32aeSBjoern A. Zeeb bool ul_set = false, dl_set = false;
643dd4f32aeSBjoern A. Zeeb int i;
644dd4f32aeSBjoern A. Zeeb
645dd4f32aeSBjoern A. Zeeb for (i = 0; i < ab->hw_params.svc_to_ce_map_len; i++) {
646dd4f32aeSBjoern A. Zeeb entry = &ab->hw_params.svc_to_ce_map[i];
647dd4f32aeSBjoern A. Zeeb
648dd4f32aeSBjoern A. Zeeb if (__le32_to_cpu(entry->service_id) != service_id)
649dd4f32aeSBjoern A. Zeeb continue;
650dd4f32aeSBjoern A. Zeeb
651dd4f32aeSBjoern A. Zeeb switch (__le32_to_cpu(entry->pipedir)) {
652dd4f32aeSBjoern A. Zeeb case PIPEDIR_NONE:
653dd4f32aeSBjoern A. Zeeb break;
654dd4f32aeSBjoern A. Zeeb case PIPEDIR_IN:
655dd4f32aeSBjoern A. Zeeb WARN_ON(dl_set);
656dd4f32aeSBjoern A. Zeeb *dl_pipe = __le32_to_cpu(entry->pipenum);
657dd4f32aeSBjoern A. Zeeb dl_set = true;
658dd4f32aeSBjoern A. Zeeb break;
659dd4f32aeSBjoern A. Zeeb case PIPEDIR_OUT:
660dd4f32aeSBjoern A. Zeeb WARN_ON(ul_set);
661dd4f32aeSBjoern A. Zeeb *ul_pipe = __le32_to_cpu(entry->pipenum);
662dd4f32aeSBjoern A. Zeeb ul_set = true;
663dd4f32aeSBjoern A. Zeeb break;
664dd4f32aeSBjoern A. Zeeb case PIPEDIR_INOUT:
665dd4f32aeSBjoern A. Zeeb WARN_ON(dl_set);
666dd4f32aeSBjoern A. Zeeb WARN_ON(ul_set);
667dd4f32aeSBjoern A. Zeeb *dl_pipe = __le32_to_cpu(entry->pipenum);
668dd4f32aeSBjoern A. Zeeb *ul_pipe = __le32_to_cpu(entry->pipenum);
669dd4f32aeSBjoern A. Zeeb dl_set = true;
670dd4f32aeSBjoern A. Zeeb ul_set = true;
671dd4f32aeSBjoern A. Zeeb break;
672dd4f32aeSBjoern A. Zeeb }
673dd4f32aeSBjoern A. Zeeb }
674dd4f32aeSBjoern A. Zeeb
675dd4f32aeSBjoern A. Zeeb if (WARN_ON(!ul_set || !dl_set))
676dd4f32aeSBjoern A. Zeeb return -ENOENT;
677dd4f32aeSBjoern A. Zeeb
678dd4f32aeSBjoern A. Zeeb return 0;
679dd4f32aeSBjoern A. Zeeb }
680dd4f32aeSBjoern A. Zeeb
ath11k_ahb_hif_suspend(struct ath11k_base * ab)681*28348caeSBjoern A. Zeeb static int ath11k_ahb_hif_suspend(struct ath11k_base *ab)
682*28348caeSBjoern A. Zeeb {
683*28348caeSBjoern A. Zeeb struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab);
684*28348caeSBjoern A. Zeeb u32 wake_irq;
685*28348caeSBjoern A. Zeeb u32 value = 0;
686*28348caeSBjoern A. Zeeb int ret;
687*28348caeSBjoern A. Zeeb
688*28348caeSBjoern A. Zeeb if (!device_may_wakeup(ab->dev))
689*28348caeSBjoern A. Zeeb return -EPERM;
690*28348caeSBjoern A. Zeeb
691*28348caeSBjoern A. Zeeb wake_irq = ab->irq_num[ATH11K_PCI_IRQ_CE0_OFFSET + ATH11K_PCI_CE_WAKE_IRQ];
692*28348caeSBjoern A. Zeeb
693*28348caeSBjoern A. Zeeb ret = enable_irq_wake(wake_irq);
694*28348caeSBjoern A. Zeeb if (ret) {
695*28348caeSBjoern A. Zeeb ath11k_err(ab, "failed to enable wakeup irq :%d\n", ret);
696*28348caeSBjoern A. Zeeb return ret;
697*28348caeSBjoern A. Zeeb }
698*28348caeSBjoern A. Zeeb
699*28348caeSBjoern A. Zeeb value = u32_encode_bits(ab_ahb->smp2p_info.seq_no++,
700*28348caeSBjoern A. Zeeb ATH11K_AHB_SMP2P_SMEM_SEQ_NO);
701*28348caeSBjoern A. Zeeb value |= u32_encode_bits(ATH11K_AHB_POWER_SAVE_ENTER,
702*28348caeSBjoern A. Zeeb ATH11K_AHB_SMP2P_SMEM_MSG);
703*28348caeSBjoern A. Zeeb
704*28348caeSBjoern A. Zeeb ret = qcom_smem_state_update_bits(ab_ahb->smp2p_info.smem_state,
705*28348caeSBjoern A. Zeeb ATH11K_AHB_SMP2P_SMEM_VALUE_MASK, value);
706*28348caeSBjoern A. Zeeb if (ret) {
707*28348caeSBjoern A. Zeeb ath11k_err(ab, "failed to send smp2p power save enter cmd :%d\n", ret);
708*28348caeSBjoern A. Zeeb return ret;
709*28348caeSBjoern A. Zeeb }
710*28348caeSBjoern A. Zeeb
711*28348caeSBjoern A. Zeeb ath11k_dbg(ab, ATH11K_DBG_AHB, "device suspended\n");
712*28348caeSBjoern A. Zeeb
713*28348caeSBjoern A. Zeeb return ret;
714*28348caeSBjoern A. Zeeb }
715*28348caeSBjoern A. Zeeb
ath11k_ahb_hif_resume(struct ath11k_base * ab)716*28348caeSBjoern A. Zeeb static int ath11k_ahb_hif_resume(struct ath11k_base *ab)
717*28348caeSBjoern A. Zeeb {
718*28348caeSBjoern A. Zeeb struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab);
719*28348caeSBjoern A. Zeeb u32 wake_irq;
720*28348caeSBjoern A. Zeeb u32 value = 0;
721*28348caeSBjoern A. Zeeb int ret;
722*28348caeSBjoern A. Zeeb
723*28348caeSBjoern A. Zeeb if (!device_may_wakeup(ab->dev))
724*28348caeSBjoern A. Zeeb return -EPERM;
725*28348caeSBjoern A. Zeeb
726*28348caeSBjoern A. Zeeb wake_irq = ab->irq_num[ATH11K_PCI_IRQ_CE0_OFFSET + ATH11K_PCI_CE_WAKE_IRQ];
727*28348caeSBjoern A. Zeeb
728*28348caeSBjoern A. Zeeb ret = disable_irq_wake(wake_irq);
729*28348caeSBjoern A. Zeeb if (ret) {
730*28348caeSBjoern A. Zeeb ath11k_err(ab, "failed to disable wakeup irq: %d\n", ret);
731*28348caeSBjoern A. Zeeb return ret;
732*28348caeSBjoern A. Zeeb }
733*28348caeSBjoern A. Zeeb
734*28348caeSBjoern A. Zeeb reinit_completion(&ab->wow.wakeup_completed);
735*28348caeSBjoern A. Zeeb
736*28348caeSBjoern A. Zeeb value = u32_encode_bits(ab_ahb->smp2p_info.seq_no++,
737*28348caeSBjoern A. Zeeb ATH11K_AHB_SMP2P_SMEM_SEQ_NO);
738*28348caeSBjoern A. Zeeb value |= u32_encode_bits(ATH11K_AHB_POWER_SAVE_EXIT,
739*28348caeSBjoern A. Zeeb ATH11K_AHB_SMP2P_SMEM_MSG);
740*28348caeSBjoern A. Zeeb
741*28348caeSBjoern A. Zeeb ret = qcom_smem_state_update_bits(ab_ahb->smp2p_info.smem_state,
742*28348caeSBjoern A. Zeeb ATH11K_AHB_SMP2P_SMEM_VALUE_MASK, value);
743*28348caeSBjoern A. Zeeb if (ret) {
744*28348caeSBjoern A. Zeeb ath11k_err(ab, "failed to send smp2p power save enter cmd :%d\n", ret);
745*28348caeSBjoern A. Zeeb return ret;
746*28348caeSBjoern A. Zeeb }
747*28348caeSBjoern A. Zeeb
748*28348caeSBjoern A. Zeeb ret = wait_for_completion_timeout(&ab->wow.wakeup_completed, 3 * HZ);
749*28348caeSBjoern A. Zeeb if (ret == 0) {
750*28348caeSBjoern A. Zeeb ath11k_warn(ab, "timed out while waiting for wow wakeup completion\n");
751*28348caeSBjoern A. Zeeb return -ETIMEDOUT;
752*28348caeSBjoern A. Zeeb }
753*28348caeSBjoern A. Zeeb
754*28348caeSBjoern A. Zeeb ath11k_dbg(ab, ATH11K_DBG_AHB, "device resumed\n");
755*28348caeSBjoern A. Zeeb
756*28348caeSBjoern A. Zeeb return 0;
757*28348caeSBjoern A. Zeeb }
758*28348caeSBjoern A. Zeeb
759*28348caeSBjoern A. Zeeb static const struct ath11k_hif_ops ath11k_ahb_hif_ops_ipq8074 = {
760dd4f32aeSBjoern A. Zeeb .start = ath11k_ahb_start,
761dd4f32aeSBjoern A. Zeeb .stop = ath11k_ahb_stop,
762dd4f32aeSBjoern A. Zeeb .read32 = ath11k_ahb_read32,
763dd4f32aeSBjoern A. Zeeb .write32 = ath11k_ahb_write32,
764*28348caeSBjoern A. Zeeb .read = NULL,
765dd4f32aeSBjoern A. Zeeb .irq_enable = ath11k_ahb_ext_irq_enable,
766dd4f32aeSBjoern A. Zeeb .irq_disable = ath11k_ahb_ext_irq_disable,
767dd4f32aeSBjoern A. Zeeb .map_service_to_pipe = ath11k_ahb_map_service_to_pipe,
768dd4f32aeSBjoern A. Zeeb .power_down = ath11k_ahb_power_down,
769dd4f32aeSBjoern A. Zeeb .power_up = ath11k_ahb_power_up,
770dd4f32aeSBjoern A. Zeeb };
771dd4f32aeSBjoern A. Zeeb
772*28348caeSBjoern A. Zeeb static const struct ath11k_hif_ops ath11k_ahb_hif_ops_wcn6750 = {
773*28348caeSBjoern A. Zeeb .start = ath11k_pcic_start,
774*28348caeSBjoern A. Zeeb .stop = ath11k_pcic_stop,
775*28348caeSBjoern A. Zeeb .read32 = ath11k_pcic_read32,
776*28348caeSBjoern A. Zeeb .write32 = ath11k_pcic_write32,
777*28348caeSBjoern A. Zeeb .read = NULL,
778*28348caeSBjoern A. Zeeb .irq_enable = ath11k_pcic_ext_irq_enable,
779*28348caeSBjoern A. Zeeb .irq_disable = ath11k_pcic_ext_irq_disable,
780*28348caeSBjoern A. Zeeb .get_msi_address = ath11k_pcic_get_msi_address,
781*28348caeSBjoern A. Zeeb .get_user_msi_vector = ath11k_pcic_get_user_msi_assignment,
782*28348caeSBjoern A. Zeeb .map_service_to_pipe = ath11k_pcic_map_service_to_pipe,
783*28348caeSBjoern A. Zeeb .power_down = ath11k_ahb_power_down,
784*28348caeSBjoern A. Zeeb .power_up = ath11k_ahb_power_up,
785*28348caeSBjoern A. Zeeb .suspend = ath11k_ahb_hif_suspend,
786*28348caeSBjoern A. Zeeb .resume = ath11k_ahb_hif_resume,
787*28348caeSBjoern A. Zeeb .ce_irq_enable = ath11k_pci_enable_ce_irqs_except_wake_irq,
788*28348caeSBjoern A. Zeeb .ce_irq_disable = ath11k_pci_disable_ce_irqs_except_wake_irq,
789*28348caeSBjoern A. Zeeb };
790*28348caeSBjoern A. Zeeb
ath11k_core_get_rproc(struct ath11k_base * ab)791dd4f32aeSBjoern A. Zeeb static int ath11k_core_get_rproc(struct ath11k_base *ab)
792dd4f32aeSBjoern A. Zeeb {
793dd4f32aeSBjoern A. Zeeb struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab);
794dd4f32aeSBjoern A. Zeeb struct device *dev = ab->dev;
795dd4f32aeSBjoern A. Zeeb struct rproc *prproc;
796dd4f32aeSBjoern A. Zeeb phandle rproc_phandle;
797dd4f32aeSBjoern A. Zeeb
798dd4f32aeSBjoern A. Zeeb if (of_property_read_u32(dev->of_node, "qcom,rproc", &rproc_phandle)) {
799dd4f32aeSBjoern A. Zeeb ath11k_err(ab, "failed to get q6_rproc handle\n");
800dd4f32aeSBjoern A. Zeeb return -ENOENT;
801dd4f32aeSBjoern A. Zeeb }
802dd4f32aeSBjoern A. Zeeb
803dd4f32aeSBjoern A. Zeeb prproc = rproc_get_by_phandle(rproc_phandle);
804dd4f32aeSBjoern A. Zeeb if (!prproc) {
805dd4f32aeSBjoern A. Zeeb ath11k_err(ab, "failed to get rproc\n");
806dd4f32aeSBjoern A. Zeeb return -EINVAL;
807dd4f32aeSBjoern A. Zeeb }
808dd4f32aeSBjoern A. Zeeb ab_ahb->tgt_rproc = prproc;
809dd4f32aeSBjoern A. Zeeb
810dd4f32aeSBjoern A. Zeeb return 0;
811dd4f32aeSBjoern A. Zeeb }
812dd4f32aeSBjoern A. Zeeb
ath11k_ahb_setup_msi_resources(struct ath11k_base * ab)813*28348caeSBjoern A. Zeeb static int ath11k_ahb_setup_msi_resources(struct ath11k_base *ab)
814*28348caeSBjoern A. Zeeb {
815*28348caeSBjoern A. Zeeb struct platform_device *pdev = ab->pdev;
816*28348caeSBjoern A. Zeeb phys_addr_t msi_addr_pa;
817*28348caeSBjoern A. Zeeb dma_addr_t msi_addr_iova;
818*28348caeSBjoern A. Zeeb struct resource *res;
819*28348caeSBjoern A. Zeeb int int_prop;
820*28348caeSBjoern A. Zeeb int ret;
821*28348caeSBjoern A. Zeeb int i;
822*28348caeSBjoern A. Zeeb
823*28348caeSBjoern A. Zeeb ret = ath11k_pcic_init_msi_config(ab);
824*28348caeSBjoern A. Zeeb if (ret) {
825*28348caeSBjoern A. Zeeb ath11k_err(ab, "failed to init msi config: %d\n", ret);
826*28348caeSBjoern A. Zeeb return ret;
827*28348caeSBjoern A. Zeeb }
828*28348caeSBjoern A. Zeeb
829*28348caeSBjoern A. Zeeb res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
830*28348caeSBjoern A. Zeeb if (!res) {
831*28348caeSBjoern A. Zeeb ath11k_err(ab, "failed to fetch msi_addr\n");
832*28348caeSBjoern A. Zeeb return -ENOENT;
833*28348caeSBjoern A. Zeeb }
834*28348caeSBjoern A. Zeeb
835*28348caeSBjoern A. Zeeb msi_addr_pa = res->start;
836*28348caeSBjoern A. Zeeb msi_addr_iova = dma_map_resource(ab->dev, msi_addr_pa, PAGE_SIZE,
837*28348caeSBjoern A. Zeeb DMA_FROM_DEVICE, 0);
838*28348caeSBjoern A. Zeeb if (dma_mapping_error(ab->dev, msi_addr_iova))
839*28348caeSBjoern A. Zeeb return -ENOMEM;
840*28348caeSBjoern A. Zeeb
841*28348caeSBjoern A. Zeeb ab->pci.msi.addr_lo = lower_32_bits(msi_addr_iova);
842*28348caeSBjoern A. Zeeb ab->pci.msi.addr_hi = upper_32_bits(msi_addr_iova);
843*28348caeSBjoern A. Zeeb
844*28348caeSBjoern A. Zeeb ret = of_property_read_u32_index(ab->dev->of_node, "interrupts", 1, &int_prop);
845*28348caeSBjoern A. Zeeb if (ret)
846*28348caeSBjoern A. Zeeb return ret;
847*28348caeSBjoern A. Zeeb
848*28348caeSBjoern A. Zeeb ab->pci.msi.ep_base_data = int_prop + 32;
849*28348caeSBjoern A. Zeeb
850*28348caeSBjoern A. Zeeb for (i = 0; i < ab->pci.msi.config->total_vectors; i++) {
851*28348caeSBjoern A. Zeeb ret = platform_get_irq(pdev, i);
852*28348caeSBjoern A. Zeeb if (ret < 0)
853*28348caeSBjoern A. Zeeb return ret;
854*28348caeSBjoern A. Zeeb
855*28348caeSBjoern A. Zeeb ab->pci.msi.irqs[i] = ret;
856*28348caeSBjoern A. Zeeb }
857*28348caeSBjoern A. Zeeb
858*28348caeSBjoern A. Zeeb set_bit(ATH11K_FLAG_MULTI_MSI_VECTORS, &ab->dev_flags);
859*28348caeSBjoern A. Zeeb
860*28348caeSBjoern A. Zeeb return 0;
861*28348caeSBjoern A. Zeeb }
862*28348caeSBjoern A. Zeeb
ath11k_ahb_setup_smp2p_handle(struct ath11k_base * ab)863*28348caeSBjoern A. Zeeb static int ath11k_ahb_setup_smp2p_handle(struct ath11k_base *ab)
864*28348caeSBjoern A. Zeeb {
865*28348caeSBjoern A. Zeeb struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab);
866*28348caeSBjoern A. Zeeb
867*28348caeSBjoern A. Zeeb if (!ab->hw_params.smp2p_wow_exit)
868*28348caeSBjoern A. Zeeb return 0;
869*28348caeSBjoern A. Zeeb
870*28348caeSBjoern A. Zeeb ab_ahb->smp2p_info.smem_state = qcom_smem_state_get(ab->dev, "wlan-smp2p-out",
871*28348caeSBjoern A. Zeeb &ab_ahb->smp2p_info.smem_bit);
872*28348caeSBjoern A. Zeeb if (IS_ERR(ab_ahb->smp2p_info.smem_state)) {
873*28348caeSBjoern A. Zeeb ath11k_err(ab, "failed to fetch smem state: %ld\n",
874*28348caeSBjoern A. Zeeb PTR_ERR(ab_ahb->smp2p_info.smem_state));
875*28348caeSBjoern A. Zeeb return PTR_ERR(ab_ahb->smp2p_info.smem_state);
876*28348caeSBjoern A. Zeeb }
877*28348caeSBjoern A. Zeeb
878*28348caeSBjoern A. Zeeb return 0;
879*28348caeSBjoern A. Zeeb }
880*28348caeSBjoern A. Zeeb
ath11k_ahb_release_smp2p_handle(struct ath11k_base * ab)881*28348caeSBjoern A. Zeeb static void ath11k_ahb_release_smp2p_handle(struct ath11k_base *ab)
882*28348caeSBjoern A. Zeeb {
883*28348caeSBjoern A. Zeeb struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab);
884*28348caeSBjoern A. Zeeb
885*28348caeSBjoern A. Zeeb if (!ab->hw_params.smp2p_wow_exit)
886*28348caeSBjoern A. Zeeb return;
887*28348caeSBjoern A. Zeeb
888*28348caeSBjoern A. Zeeb qcom_smem_state_put(ab_ahb->smp2p_info.smem_state);
889*28348caeSBjoern A. Zeeb }
890*28348caeSBjoern A. Zeeb
ath11k_ahb_setup_resources(struct ath11k_base * ab)891*28348caeSBjoern A. Zeeb static int ath11k_ahb_setup_resources(struct ath11k_base *ab)
892*28348caeSBjoern A. Zeeb {
893*28348caeSBjoern A. Zeeb struct platform_device *pdev = ab->pdev;
894*28348caeSBjoern A. Zeeb struct resource *mem_res;
895*28348caeSBjoern A. Zeeb void __iomem *mem;
896*28348caeSBjoern A. Zeeb
897*28348caeSBjoern A. Zeeb if (ab->hw_params.hybrid_bus_type)
898*28348caeSBjoern A. Zeeb return ath11k_ahb_setup_msi_resources(ab);
899*28348caeSBjoern A. Zeeb
900*28348caeSBjoern A. Zeeb mem = devm_platform_get_and_ioremap_resource(pdev, 0, &mem_res);
901*28348caeSBjoern A. Zeeb if (IS_ERR(mem)) {
902*28348caeSBjoern A. Zeeb dev_err(&pdev->dev, "ioremap error\n");
903*28348caeSBjoern A. Zeeb return PTR_ERR(mem);
904*28348caeSBjoern A. Zeeb }
905*28348caeSBjoern A. Zeeb
906*28348caeSBjoern A. Zeeb ab->mem = mem;
907*28348caeSBjoern A. Zeeb ab->mem_len = resource_size(mem_res);
908*28348caeSBjoern A. Zeeb
909*28348caeSBjoern A. Zeeb return 0;
910*28348caeSBjoern A. Zeeb }
911*28348caeSBjoern A. Zeeb
ath11k_ahb_setup_msa_resources(struct ath11k_base * ab)912*28348caeSBjoern A. Zeeb static int ath11k_ahb_setup_msa_resources(struct ath11k_base *ab)
913*28348caeSBjoern A. Zeeb {
914*28348caeSBjoern A. Zeeb struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab);
915*28348caeSBjoern A. Zeeb struct device *dev = ab->dev;
916*28348caeSBjoern A. Zeeb struct device_node *node;
917*28348caeSBjoern A. Zeeb struct resource r;
918*28348caeSBjoern A. Zeeb int ret;
919*28348caeSBjoern A. Zeeb
920*28348caeSBjoern A. Zeeb node = of_parse_phandle(dev->of_node, "memory-region", 0);
921*28348caeSBjoern A. Zeeb if (!node)
922*28348caeSBjoern A. Zeeb return -ENOENT;
923*28348caeSBjoern A. Zeeb
924*28348caeSBjoern A. Zeeb ret = of_address_to_resource(node, 0, &r);
925*28348caeSBjoern A. Zeeb of_node_put(node);
926*28348caeSBjoern A. Zeeb if (ret) {
927*28348caeSBjoern A. Zeeb dev_err(dev, "failed to resolve msa fixed region\n");
928*28348caeSBjoern A. Zeeb return ret;
929*28348caeSBjoern A. Zeeb }
930*28348caeSBjoern A. Zeeb
931*28348caeSBjoern A. Zeeb ab_ahb->fw.msa_paddr = r.start;
932*28348caeSBjoern A. Zeeb ab_ahb->fw.msa_size = resource_size(&r);
933*28348caeSBjoern A. Zeeb
934*28348caeSBjoern A. Zeeb node = of_parse_phandle(dev->of_node, "memory-region", 1);
935*28348caeSBjoern A. Zeeb if (!node)
936*28348caeSBjoern A. Zeeb return -ENOENT;
937*28348caeSBjoern A. Zeeb
938*28348caeSBjoern A. Zeeb ret = of_address_to_resource(node, 0, &r);
939*28348caeSBjoern A. Zeeb of_node_put(node);
940*28348caeSBjoern A. Zeeb if (ret) {
941*28348caeSBjoern A. Zeeb dev_err(dev, "failed to resolve ce fixed region\n");
942*28348caeSBjoern A. Zeeb return ret;
943*28348caeSBjoern A. Zeeb }
944*28348caeSBjoern A. Zeeb
945*28348caeSBjoern A. Zeeb ab_ahb->fw.ce_paddr = r.start;
946*28348caeSBjoern A. Zeeb ab_ahb->fw.ce_size = resource_size(&r);
947*28348caeSBjoern A. Zeeb
948*28348caeSBjoern A. Zeeb return 0;
949*28348caeSBjoern A. Zeeb }
950*28348caeSBjoern A. Zeeb
ath11k_ahb_fw_resources_init(struct ath11k_base * ab)951*28348caeSBjoern A. Zeeb static int ath11k_ahb_fw_resources_init(struct ath11k_base *ab)
952*28348caeSBjoern A. Zeeb {
953*28348caeSBjoern A. Zeeb struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab);
954*28348caeSBjoern A. Zeeb struct device *host_dev = ab->dev;
955*28348caeSBjoern A. Zeeb struct platform_device_info info = {0};
956*28348caeSBjoern A. Zeeb struct iommu_domain *iommu_dom;
957*28348caeSBjoern A. Zeeb struct platform_device *pdev;
958*28348caeSBjoern A. Zeeb struct device_node *node;
959*28348caeSBjoern A. Zeeb int ret;
960*28348caeSBjoern A. Zeeb
961*28348caeSBjoern A. Zeeb /* Chipsets not requiring MSA need not initialize
962*28348caeSBjoern A. Zeeb * MSA resources, return success in such cases.
963*28348caeSBjoern A. Zeeb */
964*28348caeSBjoern A. Zeeb if (!ab->hw_params.fixed_fw_mem)
965*28348caeSBjoern A. Zeeb return 0;
966*28348caeSBjoern A. Zeeb
967*28348caeSBjoern A. Zeeb ret = ath11k_ahb_setup_msa_resources(ab);
968*28348caeSBjoern A. Zeeb if (ret) {
969*28348caeSBjoern A. Zeeb ath11k_err(ab, "failed to setup msa resources\n");
970*28348caeSBjoern A. Zeeb return ret;
971*28348caeSBjoern A. Zeeb }
972*28348caeSBjoern A. Zeeb
973*28348caeSBjoern A. Zeeb node = of_get_child_by_name(host_dev->of_node, "wifi-firmware");
974*28348caeSBjoern A. Zeeb if (!node) {
975*28348caeSBjoern A. Zeeb ab_ahb->fw.use_tz = true;
976*28348caeSBjoern A. Zeeb return 0;
977*28348caeSBjoern A. Zeeb }
978*28348caeSBjoern A. Zeeb
979*28348caeSBjoern A. Zeeb info.fwnode = &node->fwnode;
980*28348caeSBjoern A. Zeeb info.parent = host_dev;
981*28348caeSBjoern A. Zeeb info.name = node->name;
982*28348caeSBjoern A. Zeeb info.dma_mask = DMA_BIT_MASK(32);
983*28348caeSBjoern A. Zeeb
984*28348caeSBjoern A. Zeeb pdev = platform_device_register_full(&info);
985*28348caeSBjoern A. Zeeb if (IS_ERR(pdev)) {
986*28348caeSBjoern A. Zeeb of_node_put(node);
987*28348caeSBjoern A. Zeeb return PTR_ERR(pdev);
988*28348caeSBjoern A. Zeeb }
989*28348caeSBjoern A. Zeeb
990*28348caeSBjoern A. Zeeb ret = of_dma_configure(&pdev->dev, node, true);
991*28348caeSBjoern A. Zeeb if (ret) {
992*28348caeSBjoern A. Zeeb ath11k_err(ab, "dma configure fail: %d\n", ret);
993*28348caeSBjoern A. Zeeb goto err_unregister;
994*28348caeSBjoern A. Zeeb }
995*28348caeSBjoern A. Zeeb
996*28348caeSBjoern A. Zeeb ab_ahb->fw.dev = &pdev->dev;
997*28348caeSBjoern A. Zeeb
998*28348caeSBjoern A. Zeeb iommu_dom = iommu_domain_alloc(&platform_bus_type);
999*28348caeSBjoern A. Zeeb if (!iommu_dom) {
1000*28348caeSBjoern A. Zeeb ath11k_err(ab, "failed to allocate iommu domain\n");
1001*28348caeSBjoern A. Zeeb ret = -ENOMEM;
1002*28348caeSBjoern A. Zeeb goto err_unregister;
1003*28348caeSBjoern A. Zeeb }
1004*28348caeSBjoern A. Zeeb
1005*28348caeSBjoern A. Zeeb ret = iommu_attach_device(iommu_dom, ab_ahb->fw.dev);
1006*28348caeSBjoern A. Zeeb if (ret) {
1007*28348caeSBjoern A. Zeeb ath11k_err(ab, "could not attach device: %d\n", ret);
1008*28348caeSBjoern A. Zeeb goto err_iommu_free;
1009*28348caeSBjoern A. Zeeb }
1010*28348caeSBjoern A. Zeeb
1011*28348caeSBjoern A. Zeeb ret = iommu_map(iommu_dom, ab_ahb->fw.msa_paddr,
1012*28348caeSBjoern A. Zeeb ab_ahb->fw.msa_paddr, ab_ahb->fw.msa_size,
1013*28348caeSBjoern A. Zeeb IOMMU_READ | IOMMU_WRITE, GFP_KERNEL);
1014*28348caeSBjoern A. Zeeb if (ret) {
1015*28348caeSBjoern A. Zeeb ath11k_err(ab, "failed to map firmware region: %d\n", ret);
1016*28348caeSBjoern A. Zeeb goto err_iommu_detach;
1017*28348caeSBjoern A. Zeeb }
1018*28348caeSBjoern A. Zeeb
1019*28348caeSBjoern A. Zeeb ret = iommu_map(iommu_dom, ab_ahb->fw.ce_paddr,
1020*28348caeSBjoern A. Zeeb ab_ahb->fw.ce_paddr, ab_ahb->fw.ce_size,
1021*28348caeSBjoern A. Zeeb IOMMU_READ | IOMMU_WRITE, GFP_KERNEL);
1022*28348caeSBjoern A. Zeeb if (ret) {
1023*28348caeSBjoern A. Zeeb ath11k_err(ab, "failed to map firmware CE region: %d\n", ret);
1024*28348caeSBjoern A. Zeeb goto err_iommu_unmap;
1025*28348caeSBjoern A. Zeeb }
1026*28348caeSBjoern A. Zeeb
1027*28348caeSBjoern A. Zeeb ab_ahb->fw.use_tz = false;
1028*28348caeSBjoern A. Zeeb ab_ahb->fw.iommu_domain = iommu_dom;
1029*28348caeSBjoern A. Zeeb of_node_put(node);
1030*28348caeSBjoern A. Zeeb
1031*28348caeSBjoern A. Zeeb return 0;
1032*28348caeSBjoern A. Zeeb
1033*28348caeSBjoern A. Zeeb err_iommu_unmap:
1034*28348caeSBjoern A. Zeeb iommu_unmap(iommu_dom, ab_ahb->fw.msa_paddr, ab_ahb->fw.msa_size);
1035*28348caeSBjoern A. Zeeb
1036*28348caeSBjoern A. Zeeb err_iommu_detach:
1037*28348caeSBjoern A. Zeeb iommu_detach_device(iommu_dom, ab_ahb->fw.dev);
1038*28348caeSBjoern A. Zeeb
1039*28348caeSBjoern A. Zeeb err_iommu_free:
1040*28348caeSBjoern A. Zeeb iommu_domain_free(iommu_dom);
1041*28348caeSBjoern A. Zeeb
1042*28348caeSBjoern A. Zeeb err_unregister:
1043*28348caeSBjoern A. Zeeb platform_device_unregister(pdev);
1044*28348caeSBjoern A. Zeeb of_node_put(node);
1045*28348caeSBjoern A. Zeeb
1046*28348caeSBjoern A. Zeeb return ret;
1047*28348caeSBjoern A. Zeeb }
1048*28348caeSBjoern A. Zeeb
ath11k_ahb_fw_resource_deinit(struct ath11k_base * ab)1049*28348caeSBjoern A. Zeeb static int ath11k_ahb_fw_resource_deinit(struct ath11k_base *ab)
1050*28348caeSBjoern A. Zeeb {
1051*28348caeSBjoern A. Zeeb struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab);
1052*28348caeSBjoern A. Zeeb struct iommu_domain *iommu;
1053*28348caeSBjoern A. Zeeb size_t unmapped_size;
1054*28348caeSBjoern A. Zeeb
1055*28348caeSBjoern A. Zeeb /* Chipsets not requiring MSA would have not initialized
1056*28348caeSBjoern A. Zeeb * MSA resources, return success in such cases.
1057*28348caeSBjoern A. Zeeb */
1058*28348caeSBjoern A. Zeeb if (!ab->hw_params.fixed_fw_mem)
1059*28348caeSBjoern A. Zeeb return 0;
1060*28348caeSBjoern A. Zeeb
1061*28348caeSBjoern A. Zeeb if (ab_ahb->fw.use_tz)
1062*28348caeSBjoern A. Zeeb return 0;
1063*28348caeSBjoern A. Zeeb
1064*28348caeSBjoern A. Zeeb iommu = ab_ahb->fw.iommu_domain;
1065*28348caeSBjoern A. Zeeb
1066*28348caeSBjoern A. Zeeb unmapped_size = iommu_unmap(iommu, ab_ahb->fw.msa_paddr, ab_ahb->fw.msa_size);
1067*28348caeSBjoern A. Zeeb if (unmapped_size != ab_ahb->fw.msa_size)
1068*28348caeSBjoern A. Zeeb ath11k_err(ab, "failed to unmap firmware: %zu\n",
1069*28348caeSBjoern A. Zeeb unmapped_size);
1070*28348caeSBjoern A. Zeeb
1071*28348caeSBjoern A. Zeeb unmapped_size = iommu_unmap(iommu, ab_ahb->fw.ce_paddr, ab_ahb->fw.ce_size);
1072*28348caeSBjoern A. Zeeb if (unmapped_size != ab_ahb->fw.ce_size)
1073*28348caeSBjoern A. Zeeb ath11k_err(ab, "failed to unmap firmware CE memory: %zu\n",
1074*28348caeSBjoern A. Zeeb unmapped_size);
1075*28348caeSBjoern A. Zeeb
1076*28348caeSBjoern A. Zeeb iommu_detach_device(iommu, ab_ahb->fw.dev);
1077*28348caeSBjoern A. Zeeb iommu_domain_free(iommu);
1078*28348caeSBjoern A. Zeeb
1079*28348caeSBjoern A. Zeeb platform_device_unregister(to_platform_device(ab_ahb->fw.dev));
1080*28348caeSBjoern A. Zeeb
1081*28348caeSBjoern A. Zeeb return 0;
1082*28348caeSBjoern A. Zeeb }
1083*28348caeSBjoern A. Zeeb
ath11k_ahb_probe(struct platform_device * pdev)1084dd4f32aeSBjoern A. Zeeb static int ath11k_ahb_probe(struct platform_device *pdev)
1085dd4f32aeSBjoern A. Zeeb {
1086dd4f32aeSBjoern A. Zeeb struct ath11k_base *ab;
1087dd4f32aeSBjoern A. Zeeb const struct of_device_id *of_id;
1088*28348caeSBjoern A. Zeeb const struct ath11k_hif_ops *hif_ops;
1089*28348caeSBjoern A. Zeeb const struct ath11k_pci_ops *pci_ops;
1090*28348caeSBjoern A. Zeeb enum ath11k_hw_rev hw_rev;
1091dd4f32aeSBjoern A. Zeeb int ret;
1092dd4f32aeSBjoern A. Zeeb
1093dd4f32aeSBjoern A. Zeeb of_id = of_match_device(ath11k_ahb_of_match, &pdev->dev);
1094dd4f32aeSBjoern A. Zeeb if (!of_id) {
1095dd4f32aeSBjoern A. Zeeb dev_err(&pdev->dev, "failed to find matching device tree id\n");
1096dd4f32aeSBjoern A. Zeeb return -EINVAL;
1097dd4f32aeSBjoern A. Zeeb }
1098dd4f32aeSBjoern A. Zeeb
1099*28348caeSBjoern A. Zeeb hw_rev = (enum ath11k_hw_rev)of_id->data;
1100*28348caeSBjoern A. Zeeb
1101*28348caeSBjoern A. Zeeb switch (hw_rev) {
1102*28348caeSBjoern A. Zeeb case ATH11K_HW_IPQ8074:
1103*28348caeSBjoern A. Zeeb case ATH11K_HW_IPQ6018_HW10:
1104*28348caeSBjoern A. Zeeb case ATH11K_HW_IPQ5018_HW10:
1105*28348caeSBjoern A. Zeeb hif_ops = &ath11k_ahb_hif_ops_ipq8074;
1106*28348caeSBjoern A. Zeeb pci_ops = NULL;
1107*28348caeSBjoern A. Zeeb break;
1108*28348caeSBjoern A. Zeeb case ATH11K_HW_WCN6750_HW10:
1109*28348caeSBjoern A. Zeeb hif_ops = &ath11k_ahb_hif_ops_wcn6750;
1110*28348caeSBjoern A. Zeeb pci_ops = &ath11k_ahb_pci_ops_wcn6750;
1111*28348caeSBjoern A. Zeeb break;
1112*28348caeSBjoern A. Zeeb default:
1113*28348caeSBjoern A. Zeeb dev_err(&pdev->dev, "unsupported device type %d\n", hw_rev);
1114*28348caeSBjoern A. Zeeb return -EOPNOTSUPP;
1115dd4f32aeSBjoern A. Zeeb }
1116dd4f32aeSBjoern A. Zeeb
1117dd4f32aeSBjoern A. Zeeb ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
1118dd4f32aeSBjoern A. Zeeb if (ret) {
1119dd4f32aeSBjoern A. Zeeb dev_err(&pdev->dev, "failed to set 32-bit consistent dma\n");
1120dd4f32aeSBjoern A. Zeeb return ret;
1121dd4f32aeSBjoern A. Zeeb }
1122dd4f32aeSBjoern A. Zeeb
1123dd4f32aeSBjoern A. Zeeb ab = ath11k_core_alloc(&pdev->dev, sizeof(struct ath11k_ahb),
1124*28348caeSBjoern A. Zeeb ATH11K_BUS_AHB);
1125dd4f32aeSBjoern A. Zeeb if (!ab) {
1126dd4f32aeSBjoern A. Zeeb dev_err(&pdev->dev, "failed to allocate ath11k base\n");
1127dd4f32aeSBjoern A. Zeeb return -ENOMEM;
1128dd4f32aeSBjoern A. Zeeb }
1129dd4f32aeSBjoern A. Zeeb
1130*28348caeSBjoern A. Zeeb ab->hif.ops = hif_ops;
1131dd4f32aeSBjoern A. Zeeb ab->pdev = pdev;
1132*28348caeSBjoern A. Zeeb ab->hw_rev = hw_rev;
1133*28348caeSBjoern A. Zeeb ab->fw_mode = ATH11K_FIRMWARE_MODE_NORMAL;
1134dd4f32aeSBjoern A. Zeeb platform_set_drvdata(pdev, ab);
1135dd4f32aeSBjoern A. Zeeb
1136*28348caeSBjoern A. Zeeb ret = ath11k_pcic_register_pci_ops(ab, pci_ops);
1137*28348caeSBjoern A. Zeeb if (ret) {
1138*28348caeSBjoern A. Zeeb ath11k_err(ab, "failed to register PCI ops: %d\n", ret);
1139*28348caeSBjoern A. Zeeb goto err_core_free;
1140*28348caeSBjoern A. Zeeb }
1141*28348caeSBjoern A. Zeeb
1142dd4f32aeSBjoern A. Zeeb ret = ath11k_core_pre_init(ab);
1143dd4f32aeSBjoern A. Zeeb if (ret)
1144dd4f32aeSBjoern A. Zeeb goto err_core_free;
1145dd4f32aeSBjoern A. Zeeb
1146*28348caeSBjoern A. Zeeb ret = ath11k_ahb_setup_resources(ab);
1147dd4f32aeSBjoern A. Zeeb if (ret)
1148dd4f32aeSBjoern A. Zeeb goto err_core_free;
1149dd4f32aeSBjoern A. Zeeb
1150*28348caeSBjoern A. Zeeb ab->mem_ce = ab->mem;
1151*28348caeSBjoern A. Zeeb
1152*28348caeSBjoern A. Zeeb if (ab->hw_params.ce_remap) {
1153*28348caeSBjoern A. Zeeb const struct ce_remap *ce_remap = ab->hw_params.ce_remap;
1154*28348caeSBjoern A. Zeeb /* ce register space is moved out of wcss unlike ipq8074 or ipq6018
1155*28348caeSBjoern A. Zeeb * and the space is not contiguous, hence remapping the CE registers
1156*28348caeSBjoern A. Zeeb * to a new space for accessing them.
1157*28348caeSBjoern A. Zeeb */
1158*28348caeSBjoern A. Zeeb ab->mem_ce = ioremap(ce_remap->base, ce_remap->size);
1159*28348caeSBjoern A. Zeeb if (!ab->mem_ce) {
1160*28348caeSBjoern A. Zeeb dev_err(&pdev->dev, "ce ioremap error\n");
1161*28348caeSBjoern A. Zeeb ret = -ENOMEM;
1162*28348caeSBjoern A. Zeeb goto err_core_free;
1163*28348caeSBjoern A. Zeeb }
1164*28348caeSBjoern A. Zeeb }
1165*28348caeSBjoern A. Zeeb
1166*28348caeSBjoern A. Zeeb ret = ath11k_ahb_fw_resources_init(ab);
1167*28348caeSBjoern A. Zeeb if (ret)
1168*28348caeSBjoern A. Zeeb goto err_core_free;
1169*28348caeSBjoern A. Zeeb
1170*28348caeSBjoern A. Zeeb ret = ath11k_ahb_setup_smp2p_handle(ab);
1171*28348caeSBjoern A. Zeeb if (ret)
1172*28348caeSBjoern A. Zeeb goto err_fw_deinit;
1173*28348caeSBjoern A. Zeeb
1174*28348caeSBjoern A. Zeeb ret = ath11k_hal_srng_init(ab);
1175*28348caeSBjoern A. Zeeb if (ret)
1176*28348caeSBjoern A. Zeeb goto err_release_smp2p_handle;
1177*28348caeSBjoern A. Zeeb
1178dd4f32aeSBjoern A. Zeeb ret = ath11k_ce_alloc_pipes(ab);
1179dd4f32aeSBjoern A. Zeeb if (ret) {
1180dd4f32aeSBjoern A. Zeeb ath11k_err(ab, "failed to allocate ce pipes: %d\n", ret);
1181dd4f32aeSBjoern A. Zeeb goto err_hal_srng_deinit;
1182dd4f32aeSBjoern A. Zeeb }
1183dd4f32aeSBjoern A. Zeeb
1184dd4f32aeSBjoern A. Zeeb ath11k_ahb_init_qmi_ce_config(ab);
1185dd4f32aeSBjoern A. Zeeb
1186dd4f32aeSBjoern A. Zeeb ret = ath11k_core_get_rproc(ab);
1187dd4f32aeSBjoern A. Zeeb if (ret) {
1188dd4f32aeSBjoern A. Zeeb ath11k_err(ab, "failed to get rproc: %d\n", ret);
1189dd4f32aeSBjoern A. Zeeb goto err_ce_free;
1190dd4f32aeSBjoern A. Zeeb }
1191dd4f32aeSBjoern A. Zeeb
1192dd4f32aeSBjoern A. Zeeb ret = ath11k_core_init(ab);
1193dd4f32aeSBjoern A. Zeeb if (ret) {
1194dd4f32aeSBjoern A. Zeeb ath11k_err(ab, "failed to init core: %d\n", ret);
1195dd4f32aeSBjoern A. Zeeb goto err_ce_free;
1196dd4f32aeSBjoern A. Zeeb }
1197dd4f32aeSBjoern A. Zeeb
1198dd4f32aeSBjoern A. Zeeb ret = ath11k_ahb_config_irq(ab);
1199dd4f32aeSBjoern A. Zeeb if (ret) {
1200dd4f32aeSBjoern A. Zeeb ath11k_err(ab, "failed to configure irq: %d\n", ret);
1201dd4f32aeSBjoern A. Zeeb goto err_ce_free;
1202dd4f32aeSBjoern A. Zeeb }
1203dd4f32aeSBjoern A. Zeeb
1204*28348caeSBjoern A. Zeeb ath11k_qmi_fwreset_from_cold_boot(ab);
1205dd4f32aeSBjoern A. Zeeb
1206dd4f32aeSBjoern A. Zeeb return 0;
1207dd4f32aeSBjoern A. Zeeb
1208dd4f32aeSBjoern A. Zeeb err_ce_free:
1209dd4f32aeSBjoern A. Zeeb ath11k_ce_free_pipes(ab);
1210dd4f32aeSBjoern A. Zeeb
1211dd4f32aeSBjoern A. Zeeb err_hal_srng_deinit:
1212dd4f32aeSBjoern A. Zeeb ath11k_hal_srng_deinit(ab);
1213dd4f32aeSBjoern A. Zeeb
1214*28348caeSBjoern A. Zeeb err_release_smp2p_handle:
1215*28348caeSBjoern A. Zeeb ath11k_ahb_release_smp2p_handle(ab);
1216*28348caeSBjoern A. Zeeb
1217*28348caeSBjoern A. Zeeb err_fw_deinit:
1218*28348caeSBjoern A. Zeeb ath11k_ahb_fw_resource_deinit(ab);
1219*28348caeSBjoern A. Zeeb
1220dd4f32aeSBjoern A. Zeeb err_core_free:
1221dd4f32aeSBjoern A. Zeeb ath11k_core_free(ab);
1222dd4f32aeSBjoern A. Zeeb platform_set_drvdata(pdev, NULL);
1223dd4f32aeSBjoern A. Zeeb
1224dd4f32aeSBjoern A. Zeeb return ret;
1225dd4f32aeSBjoern A. Zeeb }
1226dd4f32aeSBjoern A. Zeeb
ath11k_ahb_remove_prepare(struct ath11k_base * ab)1227*28348caeSBjoern A. Zeeb static void ath11k_ahb_remove_prepare(struct ath11k_base *ab)
1228dd4f32aeSBjoern A. Zeeb {
1229dd4f32aeSBjoern A. Zeeb unsigned long left;
1230dd4f32aeSBjoern A. Zeeb
1231dd4f32aeSBjoern A. Zeeb if (test_bit(ATH11K_FLAG_RECOVERY, &ab->dev_flags)) {
1232dd4f32aeSBjoern A. Zeeb left = wait_for_completion_timeout(&ab->driver_recovery,
1233dd4f32aeSBjoern A. Zeeb ATH11K_AHB_RECOVERY_TIMEOUT);
1234dd4f32aeSBjoern A. Zeeb if (!left)
1235dd4f32aeSBjoern A. Zeeb ath11k_warn(ab, "failed to receive recovery response completion\n");
1236dd4f32aeSBjoern A. Zeeb }
1237dd4f32aeSBjoern A. Zeeb
1238dd4f32aeSBjoern A. Zeeb set_bit(ATH11K_FLAG_UNREGISTERING, &ab->dev_flags);
1239dd4f32aeSBjoern A. Zeeb cancel_work_sync(&ab->restart_work);
1240*28348caeSBjoern A. Zeeb cancel_work_sync(&ab->qmi.event_work);
1241*28348caeSBjoern A. Zeeb }
1242dd4f32aeSBjoern A. Zeeb
ath11k_ahb_free_resources(struct ath11k_base * ab)1243*28348caeSBjoern A. Zeeb static void ath11k_ahb_free_resources(struct ath11k_base *ab)
1244*28348caeSBjoern A. Zeeb {
1245*28348caeSBjoern A. Zeeb struct platform_device *pdev = ab->pdev;
1246*28348caeSBjoern A. Zeeb
1247dd4f32aeSBjoern A. Zeeb ath11k_ahb_free_irq(ab);
1248dd4f32aeSBjoern A. Zeeb ath11k_hal_srng_deinit(ab);
1249*28348caeSBjoern A. Zeeb ath11k_ahb_release_smp2p_handle(ab);
1250*28348caeSBjoern A. Zeeb ath11k_ahb_fw_resource_deinit(ab);
1251dd4f32aeSBjoern A. Zeeb ath11k_ce_free_pipes(ab);
1252*28348caeSBjoern A. Zeeb
1253*28348caeSBjoern A. Zeeb if (ab->hw_params.ce_remap)
1254*28348caeSBjoern A. Zeeb iounmap(ab->mem_ce);
1255*28348caeSBjoern A. Zeeb
1256dd4f32aeSBjoern A. Zeeb ath11k_core_free(ab);
1257dd4f32aeSBjoern A. Zeeb platform_set_drvdata(pdev, NULL);
1258*28348caeSBjoern A. Zeeb }
1259*28348caeSBjoern A. Zeeb
ath11k_ahb_remove(struct platform_device * pdev)1260*28348caeSBjoern A. Zeeb static int ath11k_ahb_remove(struct platform_device *pdev)
1261*28348caeSBjoern A. Zeeb {
1262*28348caeSBjoern A. Zeeb struct ath11k_base *ab = platform_get_drvdata(pdev);
1263*28348caeSBjoern A. Zeeb
1264*28348caeSBjoern A. Zeeb if (test_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags)) {
1265*28348caeSBjoern A. Zeeb ath11k_ahb_power_down(ab);
1266*28348caeSBjoern A. Zeeb ath11k_debugfs_soc_destroy(ab);
1267*28348caeSBjoern A. Zeeb ath11k_qmi_deinit_service(ab);
1268*28348caeSBjoern A. Zeeb goto qmi_fail;
1269*28348caeSBjoern A. Zeeb }
1270*28348caeSBjoern A. Zeeb
1271*28348caeSBjoern A. Zeeb ath11k_ahb_remove_prepare(ab);
1272*28348caeSBjoern A. Zeeb ath11k_core_deinit(ab);
1273*28348caeSBjoern A. Zeeb
1274*28348caeSBjoern A. Zeeb qmi_fail:
1275*28348caeSBjoern A. Zeeb ath11k_ahb_free_resources(ab);
1276dd4f32aeSBjoern A. Zeeb
1277dd4f32aeSBjoern A. Zeeb return 0;
1278dd4f32aeSBjoern A. Zeeb }
1279dd4f32aeSBjoern A. Zeeb
ath11k_ahb_shutdown(struct platform_device * pdev)1280*28348caeSBjoern A. Zeeb static void ath11k_ahb_shutdown(struct platform_device *pdev)
1281*28348caeSBjoern A. Zeeb {
1282*28348caeSBjoern A. Zeeb struct ath11k_base *ab = platform_get_drvdata(pdev);
1283*28348caeSBjoern A. Zeeb
1284*28348caeSBjoern A. Zeeb /* platform shutdown() & remove() are mutually exclusive.
1285*28348caeSBjoern A. Zeeb * remove() is invoked during rmmod & shutdown() during
1286*28348caeSBjoern A. Zeeb * system reboot/shutdown.
1287*28348caeSBjoern A. Zeeb */
1288*28348caeSBjoern A. Zeeb ath11k_ahb_remove_prepare(ab);
1289*28348caeSBjoern A. Zeeb
1290*28348caeSBjoern A. Zeeb if (!(test_bit(ATH11K_FLAG_REGISTERED, &ab->dev_flags)))
1291*28348caeSBjoern A. Zeeb goto free_resources;
1292*28348caeSBjoern A. Zeeb
1293*28348caeSBjoern A. Zeeb ath11k_core_deinit(ab);
1294*28348caeSBjoern A. Zeeb
1295*28348caeSBjoern A. Zeeb free_resources:
1296*28348caeSBjoern A. Zeeb ath11k_ahb_free_resources(ab);
1297*28348caeSBjoern A. Zeeb }
1298*28348caeSBjoern A. Zeeb
1299dd4f32aeSBjoern A. Zeeb static struct platform_driver ath11k_ahb_driver = {
1300dd4f32aeSBjoern A. Zeeb .driver = {
1301dd4f32aeSBjoern A. Zeeb .name = "ath11k",
1302dd4f32aeSBjoern A. Zeeb .of_match_table = ath11k_ahb_of_match,
1303dd4f32aeSBjoern A. Zeeb },
1304dd4f32aeSBjoern A. Zeeb .probe = ath11k_ahb_probe,
1305dd4f32aeSBjoern A. Zeeb .remove = ath11k_ahb_remove,
1306*28348caeSBjoern A. Zeeb .shutdown = ath11k_ahb_shutdown,
1307dd4f32aeSBjoern A. Zeeb };
1308dd4f32aeSBjoern A. Zeeb
ath11k_ahb_init(void)1309dd4f32aeSBjoern A. Zeeb static int ath11k_ahb_init(void)
1310dd4f32aeSBjoern A. Zeeb {
1311dd4f32aeSBjoern A. Zeeb return platform_driver_register(&ath11k_ahb_driver);
1312dd4f32aeSBjoern A. Zeeb }
1313dd4f32aeSBjoern A. Zeeb module_init(ath11k_ahb_init);
1314dd4f32aeSBjoern A. Zeeb
ath11k_ahb_exit(void)1315dd4f32aeSBjoern A. Zeeb static void ath11k_ahb_exit(void)
1316dd4f32aeSBjoern A. Zeeb {
1317dd4f32aeSBjoern A. Zeeb platform_driver_unregister(&ath11k_ahb_driver);
1318dd4f32aeSBjoern A. Zeeb }
1319dd4f32aeSBjoern A. Zeeb module_exit(ath11k_ahb_exit);
1320dd4f32aeSBjoern A. Zeeb
1321dd4f32aeSBjoern A. Zeeb MODULE_DESCRIPTION("Driver support for Qualcomm Technologies 802.11ax WLAN AHB devices");
1322dd4f32aeSBjoern A. Zeeb MODULE_LICENSE("Dual BSD/GPL");
1323