xref: /freebsd/sys/contrib/dev/athk/ath11k/ahb.c (revision 28348caeee6ee98251b0aaa026e8d52b5032e92c)
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