1// SPDX-License-Identifier: BSD-3-Clause-Clear
2/*
3 * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
4 */
5
6#include <linux/module.h>
7#include <linux/platform_device.h>
8#include <linux/of_device.h>
9#include <linux/of.h>
10#include <linux/dma-mapping.h>
11#include "ahb.h"
12#include "debug.h"
13#include "hif.h"
14#include <linux/remoteproc.h>
15
16static const struct of_device_id ath11k_ahb_of_match[] = {
17	/* TODO: Should we change the compatible string to something similar
18	 * to one that ath10k uses?
19	 */
20	{ .compatible = "qcom,ipq8074-wifi",
21	  .data = (void *)ATH11K_HW_IPQ8074,
22	},
23	{ .compatible = "qcom,ipq6018-wifi",
24	  .data = (void *)ATH11K_HW_IPQ6018_HW10,
25	},
26	{ }
27};
28
29MODULE_DEVICE_TABLE(of, ath11k_ahb_of_match);
30
31static const struct ath11k_bus_params ath11k_ahb_bus_params = {
32	.mhi_support = false,
33	.m3_fw_support = false,
34	.fixed_bdf_addr = true,
35	.fixed_mem_region = true,
36};
37
38#define ATH11K_IRQ_CE0_OFFSET 4
39
40static const char *irq_name[ATH11K_IRQ_NUM_MAX] = {
41	"misc-pulse1",
42	"misc-latch",
43	"sw-exception",
44	"watchdog",
45	"ce0",
46	"ce1",
47	"ce2",
48	"ce3",
49	"ce4",
50	"ce5",
51	"ce6",
52	"ce7",
53	"ce8",
54	"ce9",
55	"ce10",
56	"ce11",
57	"host2wbm-desc-feed",
58	"host2reo-re-injection",
59	"host2reo-command",
60	"host2rxdma-monitor-ring3",
61	"host2rxdma-monitor-ring2",
62	"host2rxdma-monitor-ring1",
63	"reo2ost-exception",
64	"wbm2host-rx-release",
65	"reo2host-status",
66	"reo2host-destination-ring4",
67	"reo2host-destination-ring3",
68	"reo2host-destination-ring2",
69	"reo2host-destination-ring1",
70	"rxdma2host-monitor-destination-mac3",
71	"rxdma2host-monitor-destination-mac2",
72	"rxdma2host-monitor-destination-mac1",
73	"ppdu-end-interrupts-mac3",
74	"ppdu-end-interrupts-mac2",
75	"ppdu-end-interrupts-mac1",
76	"rxdma2host-monitor-status-ring-mac3",
77	"rxdma2host-monitor-status-ring-mac2",
78	"rxdma2host-monitor-status-ring-mac1",
79	"host2rxdma-host-buf-ring-mac3",
80	"host2rxdma-host-buf-ring-mac2",
81	"host2rxdma-host-buf-ring-mac1",
82	"rxdma2host-destination-ring-mac3",
83	"rxdma2host-destination-ring-mac2",
84	"rxdma2host-destination-ring-mac1",
85	"host2tcl-input-ring4",
86	"host2tcl-input-ring3",
87	"host2tcl-input-ring2",
88	"host2tcl-input-ring1",
89	"wbm2host-tx-completions-ring3",
90	"wbm2host-tx-completions-ring2",
91	"wbm2host-tx-completions-ring1",
92	"tcl2host-status-ring",
93};
94
95/* enum ext_irq_num - irq numbers that can be used by external modules
96 * like datapath
97 */
98enum ext_irq_num {
99	host2wbm_desc_feed = 16,
100	host2reo_re_injection,
101	host2reo_command,
102	host2rxdma_monitor_ring3,
103	host2rxdma_monitor_ring2,
104	host2rxdma_monitor_ring1,
105	reo2host_exception,
106	wbm2host_rx_release,
107	reo2host_status,
108	reo2host_destination_ring4,
109	reo2host_destination_ring3,
110	reo2host_destination_ring2,
111	reo2host_destination_ring1,
112	rxdma2host_monitor_destination_mac3,
113	rxdma2host_monitor_destination_mac2,
114	rxdma2host_monitor_destination_mac1,
115	ppdu_end_interrupts_mac3,
116	ppdu_end_interrupts_mac2,
117	ppdu_end_interrupts_mac1,
118	rxdma2host_monitor_status_ring_mac3,
119	rxdma2host_monitor_status_ring_mac2,
120	rxdma2host_monitor_status_ring_mac1,
121	host2rxdma_host_buf_ring_mac3,
122	host2rxdma_host_buf_ring_mac2,
123	host2rxdma_host_buf_ring_mac1,
124	rxdma2host_destination_ring_mac3,
125	rxdma2host_destination_ring_mac2,
126	rxdma2host_destination_ring_mac1,
127	host2tcl_input_ring4,
128	host2tcl_input_ring3,
129	host2tcl_input_ring2,
130	host2tcl_input_ring1,
131	wbm2host_tx_completions_ring3,
132	wbm2host_tx_completions_ring2,
133	wbm2host_tx_completions_ring1,
134	tcl2host_status_ring,
135};
136
137static inline u32 ath11k_ahb_read32(struct ath11k_base *ab, u32 offset)
138{
139	return ioread32(ab->mem + offset);
140}
141
142static inline void ath11k_ahb_write32(struct ath11k_base *ab, u32 offset, u32 value)
143{
144	iowrite32(value, ab->mem + offset);
145}
146
147static void ath11k_ahb_kill_tasklets(struct ath11k_base *ab)
148{
149	int i;
150
151	for (i = 0; i < ab->hw_params.ce_count; i++) {
152		struct ath11k_ce_pipe *ce_pipe = &ab->ce.ce_pipe[i];
153
154		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
155			continue;
156
157		tasklet_kill(&ce_pipe->intr_tq);
158	}
159}
160
161static void ath11k_ahb_ext_grp_disable(struct ath11k_ext_irq_grp *irq_grp)
162{
163	int i;
164
165	for (i = 0; i < irq_grp->num_irq; i++)
166		disable_irq_nosync(irq_grp->ab->irq_num[irq_grp->irqs[i]]);
167}
168
169static void __ath11k_ahb_ext_irq_disable(struct ath11k_base *ab)
170{
171	int i;
172
173	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
174		struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
175
176		ath11k_ahb_ext_grp_disable(irq_grp);
177
178		if (irq_grp->napi_enabled) {
179			napi_synchronize(&irq_grp->napi);
180			napi_disable(&irq_grp->napi);
181			irq_grp->napi_enabled = false;
182		}
183	}
184}
185
186static void ath11k_ahb_ext_grp_enable(struct ath11k_ext_irq_grp *irq_grp)
187{
188	int i;
189
190	for (i = 0; i < irq_grp->num_irq; i++)
191		enable_irq(irq_grp->ab->irq_num[irq_grp->irqs[i]]);
192}
193
194static void ath11k_ahb_setbit32(struct ath11k_base *ab, u8 bit, u32 offset)
195{
196	u32 val;
197
198	val = ath11k_ahb_read32(ab, offset);
199	ath11k_ahb_write32(ab, offset, val | BIT(bit));
200}
201
202static void ath11k_ahb_clearbit32(struct ath11k_base *ab, u8 bit, u32 offset)
203{
204	u32 val;
205
206	val = ath11k_ahb_read32(ab, offset);
207	ath11k_ahb_write32(ab, offset, val & ~BIT(bit));
208}
209
210static void ath11k_ahb_ce_irq_enable(struct ath11k_base *ab, u16 ce_id)
211{
212	const struct ce_attr *ce_attr;
213
214	ce_attr = &ab->hw_params.host_ce_config[ce_id];
215	if (ce_attr->src_nentries)
216		ath11k_ahb_setbit32(ab, ce_id, CE_HOST_IE_ADDRESS);
217
218	if (ce_attr->dest_nentries) {
219		ath11k_ahb_setbit32(ab, ce_id, CE_HOST_IE_2_ADDRESS);
220		ath11k_ahb_setbit32(ab, ce_id + CE_HOST_IE_3_SHIFT,
221				    CE_HOST_IE_3_ADDRESS);
222	}
223}
224
225static void ath11k_ahb_ce_irq_disable(struct ath11k_base *ab, u16 ce_id)
226{
227	const struct ce_attr *ce_attr;
228
229	ce_attr = &ab->hw_params.host_ce_config[ce_id];
230	if (ce_attr->src_nentries)
231		ath11k_ahb_clearbit32(ab, ce_id, CE_HOST_IE_ADDRESS);
232
233	if (ce_attr->dest_nentries) {
234		ath11k_ahb_clearbit32(ab, ce_id, CE_HOST_IE_2_ADDRESS);
235		ath11k_ahb_clearbit32(ab, ce_id + CE_HOST_IE_3_SHIFT,
236				      CE_HOST_IE_3_ADDRESS);
237	}
238}
239
240static void ath11k_ahb_sync_ce_irqs(struct ath11k_base *ab)
241{
242	int i;
243	int irq_idx;
244
245	for (i = 0; i < ab->hw_params.ce_count; i++) {
246		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
247			continue;
248
249		irq_idx = ATH11K_IRQ_CE0_OFFSET + i;
250		synchronize_irq(ab->irq_num[irq_idx]);
251	}
252}
253
254static void ath11k_ahb_sync_ext_irqs(struct ath11k_base *ab)
255{
256	int i, j;
257	int irq_idx;
258
259	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
260		struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
261
262		for (j = 0; j < irq_grp->num_irq; j++) {
263			irq_idx = irq_grp->irqs[j];
264			synchronize_irq(ab->irq_num[irq_idx]);
265		}
266	}
267}
268
269static void ath11k_ahb_ce_irqs_enable(struct ath11k_base *ab)
270{
271	int i;
272
273	for (i = 0; i < ab->hw_params.ce_count; i++) {
274		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
275			continue;
276		ath11k_ahb_ce_irq_enable(ab, i);
277	}
278}
279
280static void ath11k_ahb_ce_irqs_disable(struct ath11k_base *ab)
281{
282	int i;
283
284	for (i = 0; i < ab->hw_params.ce_count; i++) {
285		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
286			continue;
287		ath11k_ahb_ce_irq_disable(ab, i);
288	}
289}
290
291static int ath11k_ahb_start(struct ath11k_base *ab)
292{
293	ath11k_ahb_ce_irqs_enable(ab);
294	ath11k_ce_rx_post_buf(ab);
295
296	return 0;
297}
298
299static void ath11k_ahb_ext_irq_enable(struct ath11k_base *ab)
300{
301	int i;
302
303	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
304		struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
305
306		if (!irq_grp->napi_enabled) {
307			napi_enable(&irq_grp->napi);
308			irq_grp->napi_enabled = true;
309		}
310		ath11k_ahb_ext_grp_enable(irq_grp);
311	}
312}
313
314static void ath11k_ahb_ext_irq_disable(struct ath11k_base *ab)
315{
316	__ath11k_ahb_ext_irq_disable(ab);
317	ath11k_ahb_sync_ext_irqs(ab);
318}
319
320static void ath11k_ahb_stop(struct ath11k_base *ab)
321{
322	if (!test_bit(ATH11K_FLAG_CRASH_FLUSH, &ab->dev_flags))
323		ath11k_ahb_ce_irqs_disable(ab);
324	ath11k_ahb_sync_ce_irqs(ab);
325	ath11k_ahb_kill_tasklets(ab);
326	del_timer_sync(&ab->rx_replenish_retry);
327	ath11k_ce_cleanup_pipes(ab);
328}
329
330static int ath11k_ahb_power_up(struct ath11k_base *ab)
331{
332	struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab);
333	int ret;
334
335	ret = rproc_boot(ab_ahb->tgt_rproc);
336	if (ret)
337		ath11k_err(ab, "failed to boot the remote processor Q6\n");
338
339	return ret;
340}
341
342static void ath11k_ahb_power_down(struct ath11k_base *ab)
343{
344	struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab);
345
346	rproc_shutdown(ab_ahb->tgt_rproc);
347}
348
349static void ath11k_ahb_init_qmi_ce_config(struct ath11k_base *ab)
350{
351	struct ath11k_qmi_ce_cfg *cfg = &ab->qmi.ce_cfg;
352
353	cfg->tgt_ce_len = ab->hw_params.target_ce_count;
354	cfg->tgt_ce = ab->hw_params.target_ce_config;
355	cfg->svc_to_ce_map_len = ab->hw_params.svc_to_ce_map_len;
356	cfg->svc_to_ce_map = ab->hw_params.svc_to_ce_map;
357	ab->qmi.service_ins_id = ATH11K_QMI_WLFW_SERVICE_INS_ID_V01_IPQ8074;
358}
359
360static void ath11k_ahb_free_ext_irq(struct ath11k_base *ab)
361{
362	int i, j;
363
364	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
365		struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
366
367		for (j = 0; j < irq_grp->num_irq; j++)
368			free_irq(ab->irq_num[irq_grp->irqs[j]], irq_grp);
369
370		netif_napi_del(&irq_grp->napi);
371	}
372}
373
374static void ath11k_ahb_free_irq(struct ath11k_base *ab)
375{
376	int irq_idx;
377	int i;
378
379	for (i = 0; i < ab->hw_params.ce_count; i++) {
380		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
381			continue;
382		irq_idx = ATH11K_IRQ_CE0_OFFSET + i;
383		free_irq(ab->irq_num[irq_idx], &ab->ce.ce_pipe[i]);
384	}
385
386	ath11k_ahb_free_ext_irq(ab);
387}
388
389static void ath11k_ahb_ce_tasklet(struct tasklet_struct *t)
390{
391	struct ath11k_ce_pipe *ce_pipe = from_tasklet(ce_pipe, t, intr_tq);
392
393	ath11k_ce_per_engine_service(ce_pipe->ab, ce_pipe->pipe_num);
394
395	ath11k_ahb_ce_irq_enable(ce_pipe->ab, ce_pipe->pipe_num);
396}
397
398static irqreturn_t ath11k_ahb_ce_interrupt_handler(int irq, void *arg)
399{
400	struct ath11k_ce_pipe *ce_pipe = arg;
401
402	/* last interrupt received for this CE */
403	ce_pipe->timestamp = jiffies;
404
405	ath11k_ahb_ce_irq_disable(ce_pipe->ab, ce_pipe->pipe_num);
406
407	tasklet_schedule(&ce_pipe->intr_tq);
408
409	return IRQ_HANDLED;
410}
411
412static int ath11k_ahb_ext_grp_napi_poll(struct napi_struct *napi, int budget)
413{
414	struct ath11k_ext_irq_grp *irq_grp = container_of(napi,
415						struct ath11k_ext_irq_grp,
416						napi);
417	struct ath11k_base *ab = irq_grp->ab;
418	int work_done;
419
420	work_done = ath11k_dp_service_srng(ab, irq_grp, budget);
421	if (work_done < budget) {
422		napi_complete_done(napi, work_done);
423		ath11k_ahb_ext_grp_enable(irq_grp);
424	}
425
426	if (work_done > budget)
427		work_done = budget;
428
429	return work_done;
430}
431
432static irqreturn_t ath11k_ahb_ext_interrupt_handler(int irq, void *arg)
433{
434	struct ath11k_ext_irq_grp *irq_grp = arg;
435
436	/* last interrupt received for this group */
437	irq_grp->timestamp = jiffies;
438
439	ath11k_ahb_ext_grp_disable(irq_grp);
440
441	napi_schedule(&irq_grp->napi);
442
443	return IRQ_HANDLED;
444}
445
446static int ath11k_ahb_ext_irq_config(struct ath11k_base *ab)
447{
448	struct ath11k_hw_params *hw = &ab->hw_params;
449	int i, j;
450	int irq;
451	int ret;
452
453	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
454		struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
455		u32 num_irq = 0;
456
457		irq_grp->ab = ab;
458		irq_grp->grp_id = i;
459		init_dummy_netdev(&irq_grp->napi_ndev);
460		netif_napi_add(&irq_grp->napi_ndev, &irq_grp->napi,
461			       ath11k_ahb_ext_grp_napi_poll, NAPI_POLL_WEIGHT);
462
463		for (j = 0; j < ATH11K_EXT_IRQ_NUM_MAX; j++) {
464			if (ab->hw_params.ring_mask->tx[i] & BIT(j)) {
465				irq_grp->irqs[num_irq++] =
466					wbm2host_tx_completions_ring1 - j;
467			}
468
469			if (ab->hw_params.ring_mask->rx[i] & BIT(j)) {
470				irq_grp->irqs[num_irq++] =
471					reo2host_destination_ring1 - j;
472			}
473
474			if (ab->hw_params.ring_mask->rx_err[i] & BIT(j))
475				irq_grp->irqs[num_irq++] = reo2host_exception;
476
477			if (ab->hw_params.ring_mask->rx_wbm_rel[i] & BIT(j))
478				irq_grp->irqs[num_irq++] = wbm2host_rx_release;
479
480			if (ab->hw_params.ring_mask->reo_status[i] & BIT(j))
481				irq_grp->irqs[num_irq++] = reo2host_status;
482
483			if (j < ab->hw_params.max_radios) {
484				if (ab->hw_params.ring_mask->rxdma2host[i] & BIT(j)) {
485					irq_grp->irqs[num_irq++] =
486						rxdma2host_destination_ring_mac1 -
487						ath11k_hw_get_mac_from_pdev_id(hw, j);
488				}
489
490				if (ab->hw_params.ring_mask->host2rxdma[i] & BIT(j)) {
491					irq_grp->irqs[num_irq++] =
492						host2rxdma_host_buf_ring_mac1 -
493						ath11k_hw_get_mac_from_pdev_id(hw, j);
494				}
495
496				if (ab->hw_params.ring_mask->rx_mon_status[i] & BIT(j)) {
497					irq_grp->irqs[num_irq++] =
498						ppdu_end_interrupts_mac1 -
499						ath11k_hw_get_mac_from_pdev_id(hw, j);
500					irq_grp->irqs[num_irq++] =
501						rxdma2host_monitor_status_ring_mac1 -
502						ath11k_hw_get_mac_from_pdev_id(hw, j);
503				}
504			}
505		}
506		irq_grp->num_irq = num_irq;
507
508		for (j = 0; j < irq_grp->num_irq; j++) {
509			int irq_idx = irq_grp->irqs[j];
510
511			irq = platform_get_irq_byname(ab->pdev,
512						      irq_name[irq_idx]);
513			ab->irq_num[irq_idx] = irq;
514			irq_set_status_flags(irq, IRQ_NOAUTOEN | IRQ_DISABLE_UNLAZY);
515			ret = request_irq(irq, ath11k_ahb_ext_interrupt_handler,
516					  IRQF_TRIGGER_RISING,
517					  irq_name[irq_idx], irq_grp);
518			if (ret) {
519				ath11k_err(ab, "failed request_irq for %d\n",
520					   irq);
521			}
522		}
523	}
524
525	return 0;
526}
527
528static int ath11k_ahb_config_irq(struct ath11k_base *ab)
529{
530	int irq, irq_idx, i;
531	int ret;
532
533	/* Configure CE irqs */
534	for (i = 0; i < ab->hw_params.ce_count; i++) {
535		struct ath11k_ce_pipe *ce_pipe = &ab->ce.ce_pipe[i];
536
537		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
538			continue;
539
540		irq_idx = ATH11K_IRQ_CE0_OFFSET + i;
541
542		tasklet_setup(&ce_pipe->intr_tq, ath11k_ahb_ce_tasklet);
543		irq = platform_get_irq_byname(ab->pdev, irq_name[irq_idx]);
544		ret = request_irq(irq, ath11k_ahb_ce_interrupt_handler,
545				  IRQF_TRIGGER_RISING, irq_name[irq_idx],
546				  ce_pipe);
547		if (ret)
548			return ret;
549
550		ab->irq_num[irq_idx] = irq;
551	}
552
553	/* Configure external interrupts */
554	ret = ath11k_ahb_ext_irq_config(ab);
555
556	return ret;
557}
558
559static int ath11k_ahb_map_service_to_pipe(struct ath11k_base *ab, u16 service_id,
560					  u8 *ul_pipe, u8 *dl_pipe)
561{
562	const struct service_to_pipe *entry;
563	bool ul_set = false, dl_set = false;
564	int i;
565
566	for (i = 0; i < ab->hw_params.svc_to_ce_map_len; i++) {
567		entry = &ab->hw_params.svc_to_ce_map[i];
568
569		if (__le32_to_cpu(entry->service_id) != service_id)
570			continue;
571
572		switch (__le32_to_cpu(entry->pipedir)) {
573		case PIPEDIR_NONE:
574			break;
575		case PIPEDIR_IN:
576			WARN_ON(dl_set);
577			*dl_pipe = __le32_to_cpu(entry->pipenum);
578			dl_set = true;
579			break;
580		case PIPEDIR_OUT:
581			WARN_ON(ul_set);
582			*ul_pipe = __le32_to_cpu(entry->pipenum);
583			ul_set = true;
584			break;
585		case PIPEDIR_INOUT:
586			WARN_ON(dl_set);
587			WARN_ON(ul_set);
588			*dl_pipe = __le32_to_cpu(entry->pipenum);
589			*ul_pipe = __le32_to_cpu(entry->pipenum);
590			dl_set = true;
591			ul_set = true;
592			break;
593		}
594	}
595
596	if (WARN_ON(!ul_set || !dl_set))
597		return -ENOENT;
598
599	return 0;
600}
601
602static const struct ath11k_hif_ops ath11k_ahb_hif_ops = {
603	.start = ath11k_ahb_start,
604	.stop = ath11k_ahb_stop,
605	.read32 = ath11k_ahb_read32,
606	.write32 = ath11k_ahb_write32,
607	.irq_enable = ath11k_ahb_ext_irq_enable,
608	.irq_disable = ath11k_ahb_ext_irq_disable,
609	.map_service_to_pipe = ath11k_ahb_map_service_to_pipe,
610	.power_down = ath11k_ahb_power_down,
611	.power_up = ath11k_ahb_power_up,
612};
613
614static int ath11k_core_get_rproc(struct ath11k_base *ab)
615{
616	struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab);
617	struct device *dev = ab->dev;
618	struct rproc *prproc;
619	phandle rproc_phandle;
620
621	if (of_property_read_u32(dev->of_node, "qcom,rproc", &rproc_phandle)) {
622		ath11k_err(ab, "failed to get q6_rproc handle\n");
623		return -ENOENT;
624	}
625
626	prproc = rproc_get_by_phandle(rproc_phandle);
627	if (!prproc) {
628		ath11k_dbg(ab, ATH11K_DBG_AHB, "failed to get rproc, deferring\n");
629		return -EPROBE_DEFER;
630	}
631	ab_ahb->tgt_rproc = prproc;
632
633	return 0;
634}
635
636static int ath11k_ahb_probe(struct platform_device *pdev)
637{
638	struct ath11k_base *ab;
639	const struct of_device_id *of_id;
640	struct resource *mem_res;
641	void __iomem *mem;
642	int ret;
643
644	of_id = of_match_device(ath11k_ahb_of_match, &pdev->dev);
645	if (!of_id) {
646		dev_err(&pdev->dev, "failed to find matching device tree id\n");
647		return -EINVAL;
648	}
649
650	mem = devm_platform_get_and_ioremap_resource(pdev, 0, &mem_res);
651	if (IS_ERR(mem)) {
652		dev_err(&pdev->dev, "ioremap error\n");
653		return PTR_ERR(mem);
654	}
655
656	ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
657	if (ret) {
658		dev_err(&pdev->dev, "failed to set 32-bit consistent dma\n");
659		return ret;
660	}
661
662	ab = ath11k_core_alloc(&pdev->dev, sizeof(struct ath11k_ahb),
663			       ATH11K_BUS_AHB,
664			       &ath11k_ahb_bus_params);
665	if (!ab) {
666		dev_err(&pdev->dev, "failed to allocate ath11k base\n");
667		return -ENOMEM;
668	}
669
670	ab->hif.ops = &ath11k_ahb_hif_ops;
671	ab->pdev = pdev;
672	ab->hw_rev = (enum ath11k_hw_rev)of_id->data;
673	ab->mem = mem;
674	ab->mem_len = resource_size(mem_res);
675	platform_set_drvdata(pdev, ab);
676
677	ret = ath11k_core_pre_init(ab);
678	if (ret)
679		goto err_core_free;
680
681	ret = ath11k_hal_srng_init(ab);
682	if (ret)
683		goto err_core_free;
684
685	ret = ath11k_ce_alloc_pipes(ab);
686	if (ret) {
687		ath11k_err(ab, "failed to allocate ce pipes: %d\n", ret);
688		goto err_hal_srng_deinit;
689	}
690
691	ath11k_ahb_init_qmi_ce_config(ab);
692
693	ret = ath11k_core_get_rproc(ab);
694	if (ret) {
695		ath11k_err(ab, "failed to get rproc: %d\n", ret);
696		goto err_ce_free;
697	}
698
699	ret = ath11k_core_init(ab);
700	if (ret) {
701		ath11k_err(ab, "failed to init core: %d\n", ret);
702		goto err_ce_free;
703	}
704
705	ret = ath11k_ahb_config_irq(ab);
706	if (ret) {
707		ath11k_err(ab, "failed to configure irq: %d\n", ret);
708		goto err_ce_free;
709	}
710
711	return 0;
712
713err_ce_free:
714	ath11k_ce_free_pipes(ab);
715
716err_hal_srng_deinit:
717	ath11k_hal_srng_deinit(ab);
718
719err_core_free:
720	ath11k_core_free(ab);
721	platform_set_drvdata(pdev, NULL);
722
723	return ret;
724}
725
726static int ath11k_ahb_remove(struct platform_device *pdev)
727{
728	struct ath11k_base *ab = platform_get_drvdata(pdev);
729	unsigned long left;
730
731	reinit_completion(&ab->driver_recovery);
732
733	if (test_bit(ATH11K_FLAG_RECOVERY, &ab->dev_flags)) {
734		left = wait_for_completion_timeout(&ab->driver_recovery,
735						   ATH11K_AHB_RECOVERY_TIMEOUT);
736		if (!left)
737			ath11k_warn(ab, "failed to receive recovery response completion\n");
738	}
739
740	set_bit(ATH11K_FLAG_UNREGISTERING, &ab->dev_flags);
741	cancel_work_sync(&ab->restart_work);
742
743	ath11k_core_deinit(ab);
744	ath11k_ahb_free_irq(ab);
745
746	ath11k_hal_srng_deinit(ab);
747	ath11k_ce_free_pipes(ab);
748	ath11k_core_free(ab);
749	platform_set_drvdata(pdev, NULL);
750
751	return 0;
752}
753
754static struct platform_driver ath11k_ahb_driver = {
755	.driver         = {
756		.name   = "ath11k",
757		.of_match_table = ath11k_ahb_of_match,
758	},
759	.probe  = ath11k_ahb_probe,
760	.remove = ath11k_ahb_remove,
761};
762
763static int ath11k_ahb_init(void)
764{
765	return platform_driver_register(&ath11k_ahb_driver);
766}
767module_init(ath11k_ahb_init);
768
769static void ath11k_ahb_exit(void)
770{
771	platform_driver_unregister(&ath11k_ahb_driver);
772}
773module_exit(ath11k_ahb_exit);
774
775MODULE_DESCRIPTION("Driver support for Qualcomm Technologies 802.11ax WLAN AHB devices");
776MODULE_LICENSE("Dual BSD/GPL");
777