162306a36Sopenharmony_ci// SPDX-License-Identifier: ISC
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (c) 2018 The Linux Foundation. All rights reserved.
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <linux/bits.h>
762306a36Sopenharmony_ci#include <linux/clk.h>
862306a36Sopenharmony_ci#include <linux/kernel.h>
962306a36Sopenharmony_ci#include <linux/module.h>
1062306a36Sopenharmony_ci#include <linux/of.h>
1162306a36Sopenharmony_ci#include <linux/of_device.h>
1262306a36Sopenharmony_ci#include <linux/platform_device.h>
1362306a36Sopenharmony_ci#include <linux/property.h>
1462306a36Sopenharmony_ci#include <linux/regulator/consumer.h>
1562306a36Sopenharmony_ci#include <linux/remoteproc/qcom_rproc.h>
1662306a36Sopenharmony_ci#include <linux/of_address.h>
1762306a36Sopenharmony_ci#include <linux/iommu.h>
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci#include "ce.h"
2062306a36Sopenharmony_ci#include "coredump.h"
2162306a36Sopenharmony_ci#include "debug.h"
2262306a36Sopenharmony_ci#include "hif.h"
2362306a36Sopenharmony_ci#include "htc.h"
2462306a36Sopenharmony_ci#include "snoc.h"
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci#define ATH10K_SNOC_RX_POST_RETRY_MS 50
2762306a36Sopenharmony_ci#define CE_POLL_PIPE 4
2862306a36Sopenharmony_ci#define ATH10K_SNOC_WAKE_IRQ 2
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_cistatic char *const ce_name[] = {
3162306a36Sopenharmony_ci	"WLAN_CE_0",
3262306a36Sopenharmony_ci	"WLAN_CE_1",
3362306a36Sopenharmony_ci	"WLAN_CE_2",
3462306a36Sopenharmony_ci	"WLAN_CE_3",
3562306a36Sopenharmony_ci	"WLAN_CE_4",
3662306a36Sopenharmony_ci	"WLAN_CE_5",
3762306a36Sopenharmony_ci	"WLAN_CE_6",
3862306a36Sopenharmony_ci	"WLAN_CE_7",
3962306a36Sopenharmony_ci	"WLAN_CE_8",
4062306a36Sopenharmony_ci	"WLAN_CE_9",
4162306a36Sopenharmony_ci	"WLAN_CE_10",
4262306a36Sopenharmony_ci	"WLAN_CE_11",
4362306a36Sopenharmony_ci};
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_cistatic const char * const ath10k_regulators[] = {
4662306a36Sopenharmony_ci	"vdd-0.8-cx-mx",
4762306a36Sopenharmony_ci	"vdd-1.8-xo",
4862306a36Sopenharmony_ci	"vdd-1.3-rfa",
4962306a36Sopenharmony_ci	"vdd-3.3-ch0",
5062306a36Sopenharmony_ci	"vdd-3.3-ch1",
5162306a36Sopenharmony_ci};
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_cistatic const char * const ath10k_clocks[] = {
5462306a36Sopenharmony_ci	"cxo_ref_clk_pin", "qdss",
5562306a36Sopenharmony_ci};
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_cistatic void ath10k_snoc_htc_tx_cb(struct ath10k_ce_pipe *ce_state);
5862306a36Sopenharmony_cistatic void ath10k_snoc_htt_tx_cb(struct ath10k_ce_pipe *ce_state);
5962306a36Sopenharmony_cistatic void ath10k_snoc_htc_rx_cb(struct ath10k_ce_pipe *ce_state);
6062306a36Sopenharmony_cistatic void ath10k_snoc_htt_rx_cb(struct ath10k_ce_pipe *ce_state);
6162306a36Sopenharmony_cistatic void ath10k_snoc_htt_htc_rx_cb(struct ath10k_ce_pipe *ce_state);
6262306a36Sopenharmony_cistatic void ath10k_snoc_pktlog_rx_cb(struct ath10k_ce_pipe *ce_state);
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_cistatic const struct ath10k_snoc_drv_priv drv_priv = {
6562306a36Sopenharmony_ci	.hw_rev = ATH10K_HW_WCN3990,
6662306a36Sopenharmony_ci	.dma_mask = DMA_BIT_MASK(35),
6762306a36Sopenharmony_ci	.msa_size = 0x100000,
6862306a36Sopenharmony_ci};
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci#define WCN3990_SRC_WR_IDX_OFFSET 0x3C
7162306a36Sopenharmony_ci#define WCN3990_DST_WR_IDX_OFFSET 0x40
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_cistatic struct ath10k_shadow_reg_cfg target_shadow_reg_cfg_map[] = {
7462306a36Sopenharmony_ci		{
7562306a36Sopenharmony_ci			.ce_id = __cpu_to_le16(0),
7662306a36Sopenharmony_ci			.reg_offset = __cpu_to_le16(WCN3990_SRC_WR_IDX_OFFSET),
7762306a36Sopenharmony_ci		},
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci		{
8062306a36Sopenharmony_ci			.ce_id = __cpu_to_le16(3),
8162306a36Sopenharmony_ci			.reg_offset = __cpu_to_le16(WCN3990_SRC_WR_IDX_OFFSET),
8262306a36Sopenharmony_ci		},
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci		{
8562306a36Sopenharmony_ci			.ce_id = __cpu_to_le16(4),
8662306a36Sopenharmony_ci			.reg_offset = __cpu_to_le16(WCN3990_SRC_WR_IDX_OFFSET),
8762306a36Sopenharmony_ci		},
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci		{
9062306a36Sopenharmony_ci			.ce_id = __cpu_to_le16(5),
9162306a36Sopenharmony_ci			.reg_offset =  __cpu_to_le16(WCN3990_SRC_WR_IDX_OFFSET),
9262306a36Sopenharmony_ci		},
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci		{
9562306a36Sopenharmony_ci			.ce_id = __cpu_to_le16(7),
9662306a36Sopenharmony_ci			.reg_offset = __cpu_to_le16(WCN3990_SRC_WR_IDX_OFFSET),
9762306a36Sopenharmony_ci		},
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci		{
10062306a36Sopenharmony_ci			.ce_id = __cpu_to_le16(1),
10162306a36Sopenharmony_ci			.reg_offset = __cpu_to_le16(WCN3990_DST_WR_IDX_OFFSET),
10262306a36Sopenharmony_ci		},
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci		{
10562306a36Sopenharmony_ci			.ce_id = __cpu_to_le16(2),
10662306a36Sopenharmony_ci			.reg_offset =  __cpu_to_le16(WCN3990_DST_WR_IDX_OFFSET),
10762306a36Sopenharmony_ci		},
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci		{
11062306a36Sopenharmony_ci			.ce_id = __cpu_to_le16(7),
11162306a36Sopenharmony_ci			.reg_offset =  __cpu_to_le16(WCN3990_DST_WR_IDX_OFFSET),
11262306a36Sopenharmony_ci		},
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci		{
11562306a36Sopenharmony_ci			.ce_id = __cpu_to_le16(8),
11662306a36Sopenharmony_ci			.reg_offset =  __cpu_to_le16(WCN3990_DST_WR_IDX_OFFSET),
11762306a36Sopenharmony_ci		},
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci		{
12062306a36Sopenharmony_ci			.ce_id = __cpu_to_le16(9),
12162306a36Sopenharmony_ci			.reg_offset = __cpu_to_le16(WCN3990_DST_WR_IDX_OFFSET),
12262306a36Sopenharmony_ci		},
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci		{
12562306a36Sopenharmony_ci			.ce_id = __cpu_to_le16(10),
12662306a36Sopenharmony_ci			.reg_offset =  __cpu_to_le16(WCN3990_DST_WR_IDX_OFFSET),
12762306a36Sopenharmony_ci		},
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci		{
13062306a36Sopenharmony_ci			.ce_id = __cpu_to_le16(11),
13162306a36Sopenharmony_ci			.reg_offset = __cpu_to_le16(WCN3990_DST_WR_IDX_OFFSET),
13262306a36Sopenharmony_ci		},
13362306a36Sopenharmony_ci};
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_cistatic struct ce_attr host_ce_config_wlan[] = {
13662306a36Sopenharmony_ci	/* CE0: host->target HTC control streams */
13762306a36Sopenharmony_ci	{
13862306a36Sopenharmony_ci		.flags = CE_ATTR_FLAGS,
13962306a36Sopenharmony_ci		.src_nentries = 16,
14062306a36Sopenharmony_ci		.src_sz_max = 2048,
14162306a36Sopenharmony_ci		.dest_nentries = 0,
14262306a36Sopenharmony_ci		.send_cb = ath10k_snoc_htc_tx_cb,
14362306a36Sopenharmony_ci	},
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	/* CE1: target->host HTT + HTC control */
14662306a36Sopenharmony_ci	{
14762306a36Sopenharmony_ci		.flags = CE_ATTR_FLAGS,
14862306a36Sopenharmony_ci		.src_nentries = 0,
14962306a36Sopenharmony_ci		.src_sz_max = 2048,
15062306a36Sopenharmony_ci		.dest_nentries = 512,
15162306a36Sopenharmony_ci		.recv_cb = ath10k_snoc_htt_htc_rx_cb,
15262306a36Sopenharmony_ci	},
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	/* CE2: target->host WMI */
15562306a36Sopenharmony_ci	{
15662306a36Sopenharmony_ci		.flags = CE_ATTR_FLAGS,
15762306a36Sopenharmony_ci		.src_nentries = 0,
15862306a36Sopenharmony_ci		.src_sz_max = 2048,
15962306a36Sopenharmony_ci		.dest_nentries = 64,
16062306a36Sopenharmony_ci		.recv_cb = ath10k_snoc_htc_rx_cb,
16162306a36Sopenharmony_ci	},
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci	/* CE3: host->target WMI */
16462306a36Sopenharmony_ci	{
16562306a36Sopenharmony_ci		.flags = CE_ATTR_FLAGS,
16662306a36Sopenharmony_ci		.src_nentries = 32,
16762306a36Sopenharmony_ci		.src_sz_max = 2048,
16862306a36Sopenharmony_ci		.dest_nentries = 0,
16962306a36Sopenharmony_ci		.send_cb = ath10k_snoc_htc_tx_cb,
17062306a36Sopenharmony_ci	},
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	/* CE4: host->target HTT */
17362306a36Sopenharmony_ci	{
17462306a36Sopenharmony_ci		.flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR,
17562306a36Sopenharmony_ci		.src_nentries = 2048,
17662306a36Sopenharmony_ci		.src_sz_max = 256,
17762306a36Sopenharmony_ci		.dest_nentries = 0,
17862306a36Sopenharmony_ci		.send_cb = ath10k_snoc_htt_tx_cb,
17962306a36Sopenharmony_ci	},
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	/* CE5: target->host HTT (ipa_uc->target ) */
18262306a36Sopenharmony_ci	{
18362306a36Sopenharmony_ci		.flags = CE_ATTR_FLAGS,
18462306a36Sopenharmony_ci		.src_nentries = 0,
18562306a36Sopenharmony_ci		.src_sz_max = 512,
18662306a36Sopenharmony_ci		.dest_nentries = 512,
18762306a36Sopenharmony_ci		.recv_cb = ath10k_snoc_htt_rx_cb,
18862306a36Sopenharmony_ci	},
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci	/* CE6: target autonomous hif_memcpy */
19162306a36Sopenharmony_ci	{
19262306a36Sopenharmony_ci		.flags = CE_ATTR_FLAGS,
19362306a36Sopenharmony_ci		.src_nentries = 0,
19462306a36Sopenharmony_ci		.src_sz_max = 0,
19562306a36Sopenharmony_ci		.dest_nentries = 0,
19662306a36Sopenharmony_ci	},
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	/* CE7: ce_diag, the Diagnostic Window */
19962306a36Sopenharmony_ci	{
20062306a36Sopenharmony_ci		.flags = CE_ATTR_FLAGS,
20162306a36Sopenharmony_ci		.src_nentries = 2,
20262306a36Sopenharmony_ci		.src_sz_max = 2048,
20362306a36Sopenharmony_ci		.dest_nentries = 2,
20462306a36Sopenharmony_ci	},
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	/* CE8: Target to uMC */
20762306a36Sopenharmony_ci	{
20862306a36Sopenharmony_ci		.flags = CE_ATTR_FLAGS,
20962306a36Sopenharmony_ci		.src_nentries = 0,
21062306a36Sopenharmony_ci		.src_sz_max = 2048,
21162306a36Sopenharmony_ci		.dest_nentries = 128,
21262306a36Sopenharmony_ci	},
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	/* CE9 target->host HTT */
21562306a36Sopenharmony_ci	{
21662306a36Sopenharmony_ci		.flags = CE_ATTR_FLAGS,
21762306a36Sopenharmony_ci		.src_nentries = 0,
21862306a36Sopenharmony_ci		.src_sz_max = 2048,
21962306a36Sopenharmony_ci		.dest_nentries = 512,
22062306a36Sopenharmony_ci		.recv_cb = ath10k_snoc_htt_htc_rx_cb,
22162306a36Sopenharmony_ci	},
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci	/* CE10: target->host HTT */
22462306a36Sopenharmony_ci	{
22562306a36Sopenharmony_ci		.flags = CE_ATTR_FLAGS,
22662306a36Sopenharmony_ci		.src_nentries = 0,
22762306a36Sopenharmony_ci		.src_sz_max = 2048,
22862306a36Sopenharmony_ci		.dest_nentries = 512,
22962306a36Sopenharmony_ci		.recv_cb = ath10k_snoc_htt_htc_rx_cb,
23062306a36Sopenharmony_ci	},
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	/* CE11: target -> host PKTLOG */
23362306a36Sopenharmony_ci	{
23462306a36Sopenharmony_ci		.flags = CE_ATTR_FLAGS,
23562306a36Sopenharmony_ci		.src_nentries = 0,
23662306a36Sopenharmony_ci		.src_sz_max = 2048,
23762306a36Sopenharmony_ci		.dest_nentries = 512,
23862306a36Sopenharmony_ci		.recv_cb = ath10k_snoc_pktlog_rx_cb,
23962306a36Sopenharmony_ci	},
24062306a36Sopenharmony_ci};
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_cistatic struct ce_pipe_config target_ce_config_wlan[] = {
24362306a36Sopenharmony_ci	/* CE0: host->target HTC control and raw streams */
24462306a36Sopenharmony_ci	{
24562306a36Sopenharmony_ci		.pipenum = __cpu_to_le32(0),
24662306a36Sopenharmony_ci		.pipedir = __cpu_to_le32(PIPEDIR_OUT),
24762306a36Sopenharmony_ci		.nentries = __cpu_to_le32(32),
24862306a36Sopenharmony_ci		.nbytes_max = __cpu_to_le32(2048),
24962306a36Sopenharmony_ci		.flags = __cpu_to_le32(CE_ATTR_FLAGS),
25062306a36Sopenharmony_ci		.reserved = __cpu_to_le32(0),
25162306a36Sopenharmony_ci	},
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	/* CE1: target->host HTT + HTC control */
25462306a36Sopenharmony_ci	{
25562306a36Sopenharmony_ci		.pipenum = __cpu_to_le32(1),
25662306a36Sopenharmony_ci		.pipedir = __cpu_to_le32(PIPEDIR_IN),
25762306a36Sopenharmony_ci		.nentries = __cpu_to_le32(32),
25862306a36Sopenharmony_ci		.nbytes_max = __cpu_to_le32(2048),
25962306a36Sopenharmony_ci		.flags = __cpu_to_le32(CE_ATTR_FLAGS),
26062306a36Sopenharmony_ci		.reserved = __cpu_to_le32(0),
26162306a36Sopenharmony_ci	},
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	/* CE2: target->host WMI */
26462306a36Sopenharmony_ci	{
26562306a36Sopenharmony_ci		.pipenum = __cpu_to_le32(2),
26662306a36Sopenharmony_ci		.pipedir = __cpu_to_le32(PIPEDIR_IN),
26762306a36Sopenharmony_ci		.nentries = __cpu_to_le32(64),
26862306a36Sopenharmony_ci		.nbytes_max = __cpu_to_le32(2048),
26962306a36Sopenharmony_ci		.flags = __cpu_to_le32(CE_ATTR_FLAGS),
27062306a36Sopenharmony_ci		.reserved = __cpu_to_le32(0),
27162306a36Sopenharmony_ci	},
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	/* CE3: host->target WMI */
27462306a36Sopenharmony_ci	{
27562306a36Sopenharmony_ci		.pipenum = __cpu_to_le32(3),
27662306a36Sopenharmony_ci		.pipedir = __cpu_to_le32(PIPEDIR_OUT),
27762306a36Sopenharmony_ci		.nentries = __cpu_to_le32(32),
27862306a36Sopenharmony_ci		.nbytes_max = __cpu_to_le32(2048),
27962306a36Sopenharmony_ci		.flags = __cpu_to_le32(CE_ATTR_FLAGS),
28062306a36Sopenharmony_ci		.reserved = __cpu_to_le32(0),
28162306a36Sopenharmony_ci	},
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci	/* CE4: host->target HTT */
28462306a36Sopenharmony_ci	{
28562306a36Sopenharmony_ci		.pipenum = __cpu_to_le32(4),
28662306a36Sopenharmony_ci		.pipedir = __cpu_to_le32(PIPEDIR_OUT),
28762306a36Sopenharmony_ci		.nentries = __cpu_to_le32(256),
28862306a36Sopenharmony_ci		.nbytes_max = __cpu_to_le32(256),
28962306a36Sopenharmony_ci		.flags = __cpu_to_le32(CE_ATTR_FLAGS | CE_ATTR_DIS_INTR),
29062306a36Sopenharmony_ci		.reserved = __cpu_to_le32(0),
29162306a36Sopenharmony_ci	},
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci	/* CE5: target->host HTT (HIF->HTT) */
29462306a36Sopenharmony_ci	{
29562306a36Sopenharmony_ci		.pipenum = __cpu_to_le32(5),
29662306a36Sopenharmony_ci		.pipedir = __cpu_to_le32(PIPEDIR_OUT),
29762306a36Sopenharmony_ci		.nentries = __cpu_to_le32(1024),
29862306a36Sopenharmony_ci		.nbytes_max = __cpu_to_le32(64),
29962306a36Sopenharmony_ci		.flags = __cpu_to_le32(CE_ATTR_FLAGS | CE_ATTR_DIS_INTR),
30062306a36Sopenharmony_ci		.reserved = __cpu_to_le32(0),
30162306a36Sopenharmony_ci	},
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	/* CE6: Reserved for target autonomous hif_memcpy */
30462306a36Sopenharmony_ci	{
30562306a36Sopenharmony_ci		.pipenum = __cpu_to_le32(6),
30662306a36Sopenharmony_ci		.pipedir = __cpu_to_le32(PIPEDIR_INOUT),
30762306a36Sopenharmony_ci		.nentries = __cpu_to_le32(32),
30862306a36Sopenharmony_ci		.nbytes_max = __cpu_to_le32(16384),
30962306a36Sopenharmony_ci		.flags = __cpu_to_le32(CE_ATTR_FLAGS),
31062306a36Sopenharmony_ci		.reserved = __cpu_to_le32(0),
31162306a36Sopenharmony_ci	},
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci	/* CE7 used only by Host */
31462306a36Sopenharmony_ci	{
31562306a36Sopenharmony_ci		.pipenum = __cpu_to_le32(7),
31662306a36Sopenharmony_ci		.pipedir = __cpu_to_le32(4),
31762306a36Sopenharmony_ci		.nentries = __cpu_to_le32(0),
31862306a36Sopenharmony_ci		.nbytes_max = __cpu_to_le32(0),
31962306a36Sopenharmony_ci		.flags = __cpu_to_le32(CE_ATTR_FLAGS | CE_ATTR_DIS_INTR),
32062306a36Sopenharmony_ci		.reserved = __cpu_to_le32(0),
32162306a36Sopenharmony_ci	},
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci	/* CE8 Target to uMC */
32462306a36Sopenharmony_ci	{
32562306a36Sopenharmony_ci		.pipenum = __cpu_to_le32(8),
32662306a36Sopenharmony_ci		.pipedir = __cpu_to_le32(PIPEDIR_IN),
32762306a36Sopenharmony_ci		.nentries = __cpu_to_le32(32),
32862306a36Sopenharmony_ci		.nbytes_max = __cpu_to_le32(2048),
32962306a36Sopenharmony_ci		.flags = __cpu_to_le32(0),
33062306a36Sopenharmony_ci		.reserved = __cpu_to_le32(0),
33162306a36Sopenharmony_ci	},
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci	/* CE9 target->host HTT */
33462306a36Sopenharmony_ci	{
33562306a36Sopenharmony_ci		.pipenum = __cpu_to_le32(9),
33662306a36Sopenharmony_ci		.pipedir = __cpu_to_le32(PIPEDIR_IN),
33762306a36Sopenharmony_ci		.nentries = __cpu_to_le32(32),
33862306a36Sopenharmony_ci		.nbytes_max = __cpu_to_le32(2048),
33962306a36Sopenharmony_ci		.flags = __cpu_to_le32(CE_ATTR_FLAGS),
34062306a36Sopenharmony_ci		.reserved = __cpu_to_le32(0),
34162306a36Sopenharmony_ci	},
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	/* CE10 target->host HTT */
34462306a36Sopenharmony_ci	{
34562306a36Sopenharmony_ci		.pipenum = __cpu_to_le32(10),
34662306a36Sopenharmony_ci		.pipedir = __cpu_to_le32(PIPEDIR_IN),
34762306a36Sopenharmony_ci		.nentries = __cpu_to_le32(32),
34862306a36Sopenharmony_ci		.nbytes_max = __cpu_to_le32(2048),
34962306a36Sopenharmony_ci		.flags = __cpu_to_le32(CE_ATTR_FLAGS),
35062306a36Sopenharmony_ci		.reserved = __cpu_to_le32(0),
35162306a36Sopenharmony_ci	},
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	/* CE11 target autonomous qcache memcpy */
35462306a36Sopenharmony_ci	{
35562306a36Sopenharmony_ci		.pipenum = __cpu_to_le32(11),
35662306a36Sopenharmony_ci		.pipedir = __cpu_to_le32(PIPEDIR_IN),
35762306a36Sopenharmony_ci		.nentries = __cpu_to_le32(32),
35862306a36Sopenharmony_ci		.nbytes_max = __cpu_to_le32(2048),
35962306a36Sopenharmony_ci		.flags = __cpu_to_le32(CE_ATTR_FLAGS),
36062306a36Sopenharmony_ci		.reserved = __cpu_to_le32(0),
36162306a36Sopenharmony_ci	},
36262306a36Sopenharmony_ci};
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_cistatic struct ce_service_to_pipe target_service_to_ce_map_wlan[] = {
36562306a36Sopenharmony_ci	{
36662306a36Sopenharmony_ci		__cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_VO),
36762306a36Sopenharmony_ci		__cpu_to_le32(PIPEDIR_OUT),	/* out = UL = host -> target */
36862306a36Sopenharmony_ci		__cpu_to_le32(3),
36962306a36Sopenharmony_ci	},
37062306a36Sopenharmony_ci	{
37162306a36Sopenharmony_ci		__cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_VO),
37262306a36Sopenharmony_ci		__cpu_to_le32(PIPEDIR_IN),	/* in = DL = target -> host */
37362306a36Sopenharmony_ci		__cpu_to_le32(2),
37462306a36Sopenharmony_ci	},
37562306a36Sopenharmony_ci	{
37662306a36Sopenharmony_ci		__cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_BK),
37762306a36Sopenharmony_ci		__cpu_to_le32(PIPEDIR_OUT),	/* out = UL = host -> target */
37862306a36Sopenharmony_ci		__cpu_to_le32(3),
37962306a36Sopenharmony_ci	},
38062306a36Sopenharmony_ci	{
38162306a36Sopenharmony_ci		__cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_BK),
38262306a36Sopenharmony_ci		__cpu_to_le32(PIPEDIR_IN),	/* in = DL = target -> host */
38362306a36Sopenharmony_ci		__cpu_to_le32(2),
38462306a36Sopenharmony_ci	},
38562306a36Sopenharmony_ci	{
38662306a36Sopenharmony_ci		__cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_BE),
38762306a36Sopenharmony_ci		__cpu_to_le32(PIPEDIR_OUT),	/* out = UL = host -> target */
38862306a36Sopenharmony_ci		__cpu_to_le32(3),
38962306a36Sopenharmony_ci	},
39062306a36Sopenharmony_ci	{
39162306a36Sopenharmony_ci		__cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_BE),
39262306a36Sopenharmony_ci		__cpu_to_le32(PIPEDIR_IN),	/* in = DL = target -> host */
39362306a36Sopenharmony_ci		__cpu_to_le32(2),
39462306a36Sopenharmony_ci	},
39562306a36Sopenharmony_ci	{
39662306a36Sopenharmony_ci		__cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_VI),
39762306a36Sopenharmony_ci		__cpu_to_le32(PIPEDIR_OUT),	/* out = UL = host -> target */
39862306a36Sopenharmony_ci		__cpu_to_le32(3),
39962306a36Sopenharmony_ci	},
40062306a36Sopenharmony_ci	{
40162306a36Sopenharmony_ci		__cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_VI),
40262306a36Sopenharmony_ci		__cpu_to_le32(PIPEDIR_IN),	/* in = DL = target -> host */
40362306a36Sopenharmony_ci		__cpu_to_le32(2),
40462306a36Sopenharmony_ci	},
40562306a36Sopenharmony_ci	{
40662306a36Sopenharmony_ci		__cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_CONTROL),
40762306a36Sopenharmony_ci		__cpu_to_le32(PIPEDIR_OUT),	/* out = UL = host -> target */
40862306a36Sopenharmony_ci		__cpu_to_le32(3),
40962306a36Sopenharmony_ci	},
41062306a36Sopenharmony_ci	{
41162306a36Sopenharmony_ci		__cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_CONTROL),
41262306a36Sopenharmony_ci		__cpu_to_le32(PIPEDIR_IN),	/* in = DL = target -> host */
41362306a36Sopenharmony_ci		__cpu_to_le32(2),
41462306a36Sopenharmony_ci	},
41562306a36Sopenharmony_ci	{
41662306a36Sopenharmony_ci		__cpu_to_le32(ATH10K_HTC_SVC_ID_RSVD_CTRL),
41762306a36Sopenharmony_ci		__cpu_to_le32(PIPEDIR_OUT),	/* out = UL = host -> target */
41862306a36Sopenharmony_ci		__cpu_to_le32(0),
41962306a36Sopenharmony_ci	},
42062306a36Sopenharmony_ci	{
42162306a36Sopenharmony_ci		__cpu_to_le32(ATH10K_HTC_SVC_ID_RSVD_CTRL),
42262306a36Sopenharmony_ci		__cpu_to_le32(PIPEDIR_IN),	/* in = DL = target -> host */
42362306a36Sopenharmony_ci		__cpu_to_le32(2),
42462306a36Sopenharmony_ci	},
42562306a36Sopenharmony_ci	{ /* not used */
42662306a36Sopenharmony_ci		__cpu_to_le32(ATH10K_HTC_SVC_ID_TEST_RAW_STREAMS),
42762306a36Sopenharmony_ci		__cpu_to_le32(PIPEDIR_OUT),	/* out = UL = host -> target */
42862306a36Sopenharmony_ci		__cpu_to_le32(0),
42962306a36Sopenharmony_ci	},
43062306a36Sopenharmony_ci	{ /* not used */
43162306a36Sopenharmony_ci		__cpu_to_le32(ATH10K_HTC_SVC_ID_TEST_RAW_STREAMS),
43262306a36Sopenharmony_ci		__cpu_to_le32(PIPEDIR_IN),	/* in = DL = target -> host */
43362306a36Sopenharmony_ci		__cpu_to_le32(2),
43462306a36Sopenharmony_ci	},
43562306a36Sopenharmony_ci	{
43662306a36Sopenharmony_ci		__cpu_to_le32(ATH10K_HTC_SVC_ID_HTT_DATA_MSG),
43762306a36Sopenharmony_ci		__cpu_to_le32(PIPEDIR_OUT),	/* out = UL = host -> target */
43862306a36Sopenharmony_ci		__cpu_to_le32(4),
43962306a36Sopenharmony_ci	},
44062306a36Sopenharmony_ci	{
44162306a36Sopenharmony_ci		__cpu_to_le32(ATH10K_HTC_SVC_ID_HTT_DATA_MSG),
44262306a36Sopenharmony_ci		__cpu_to_le32(PIPEDIR_IN),	/* in = DL = target -> host */
44362306a36Sopenharmony_ci		__cpu_to_le32(1),
44462306a36Sopenharmony_ci	},
44562306a36Sopenharmony_ci	{ /* not used */
44662306a36Sopenharmony_ci		__cpu_to_le32(ATH10K_HTC_SVC_ID_TEST_RAW_STREAMS),
44762306a36Sopenharmony_ci		__cpu_to_le32(PIPEDIR_OUT),
44862306a36Sopenharmony_ci		__cpu_to_le32(5),
44962306a36Sopenharmony_ci	},
45062306a36Sopenharmony_ci	{ /* in = DL = target -> host */
45162306a36Sopenharmony_ci		__cpu_to_le32(ATH10K_HTC_SVC_ID_HTT_DATA2_MSG),
45262306a36Sopenharmony_ci		__cpu_to_le32(PIPEDIR_IN),	/* in = DL = target -> host */
45362306a36Sopenharmony_ci		__cpu_to_le32(9),
45462306a36Sopenharmony_ci	},
45562306a36Sopenharmony_ci	{ /* in = DL = target -> host */
45662306a36Sopenharmony_ci		__cpu_to_le32(ATH10K_HTC_SVC_ID_HTT_DATA3_MSG),
45762306a36Sopenharmony_ci		__cpu_to_le32(PIPEDIR_IN),	/* in = DL = target -> host */
45862306a36Sopenharmony_ci		__cpu_to_le32(10),
45962306a36Sopenharmony_ci	},
46062306a36Sopenharmony_ci	{ /* in = DL = target -> host pktlog */
46162306a36Sopenharmony_ci		__cpu_to_le32(ATH10K_HTC_SVC_ID_HTT_LOG_MSG),
46262306a36Sopenharmony_ci		__cpu_to_le32(PIPEDIR_IN),	/* in = DL = target -> host */
46362306a36Sopenharmony_ci		__cpu_to_le32(11),
46462306a36Sopenharmony_ci	},
46562306a36Sopenharmony_ci	/* (Additions here) */
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci	{ /* must be last */
46862306a36Sopenharmony_ci		__cpu_to_le32(0),
46962306a36Sopenharmony_ci		__cpu_to_le32(0),
47062306a36Sopenharmony_ci		__cpu_to_le32(0),
47162306a36Sopenharmony_ci	},
47262306a36Sopenharmony_ci};
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_cistatic void ath10k_snoc_write32(struct ath10k *ar, u32 offset, u32 value)
47562306a36Sopenharmony_ci{
47662306a36Sopenharmony_ci	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci	iowrite32(value, ar_snoc->mem + offset);
47962306a36Sopenharmony_ci}
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_cistatic u32 ath10k_snoc_read32(struct ath10k *ar, u32 offset)
48262306a36Sopenharmony_ci{
48362306a36Sopenharmony_ci	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
48462306a36Sopenharmony_ci	u32 val;
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci	val = ioread32(ar_snoc->mem + offset);
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_ci	return val;
48962306a36Sopenharmony_ci}
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_cistatic int __ath10k_snoc_rx_post_buf(struct ath10k_snoc_pipe *pipe)
49262306a36Sopenharmony_ci{
49362306a36Sopenharmony_ci	struct ath10k_ce_pipe *ce_pipe = pipe->ce_hdl;
49462306a36Sopenharmony_ci	struct ath10k *ar = pipe->hif_ce_state;
49562306a36Sopenharmony_ci	struct ath10k_ce *ce = ath10k_ce_priv(ar);
49662306a36Sopenharmony_ci	struct sk_buff *skb;
49762306a36Sopenharmony_ci	dma_addr_t paddr;
49862306a36Sopenharmony_ci	int ret;
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci	skb = dev_alloc_skb(pipe->buf_sz);
50162306a36Sopenharmony_ci	if (!skb)
50262306a36Sopenharmony_ci		return -ENOMEM;
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci	WARN_ONCE((unsigned long)skb->data & 3, "unaligned skb");
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci	paddr = dma_map_single(ar->dev, skb->data,
50762306a36Sopenharmony_ci			       skb->len + skb_tailroom(skb),
50862306a36Sopenharmony_ci			       DMA_FROM_DEVICE);
50962306a36Sopenharmony_ci	if (unlikely(dma_mapping_error(ar->dev, paddr))) {
51062306a36Sopenharmony_ci		ath10k_warn(ar, "failed to dma map snoc rx buf\n");
51162306a36Sopenharmony_ci		dev_kfree_skb_any(skb);
51262306a36Sopenharmony_ci		return -EIO;
51362306a36Sopenharmony_ci	}
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci	ATH10K_SKB_RXCB(skb)->paddr = paddr;
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci	spin_lock_bh(&ce->ce_lock);
51862306a36Sopenharmony_ci	ret = ce_pipe->ops->ce_rx_post_buf(ce_pipe, skb, paddr);
51962306a36Sopenharmony_ci	spin_unlock_bh(&ce->ce_lock);
52062306a36Sopenharmony_ci	if (ret) {
52162306a36Sopenharmony_ci		dma_unmap_single(ar->dev, paddr, skb->len + skb_tailroom(skb),
52262306a36Sopenharmony_ci				 DMA_FROM_DEVICE);
52362306a36Sopenharmony_ci		dev_kfree_skb_any(skb);
52462306a36Sopenharmony_ci		return ret;
52562306a36Sopenharmony_ci	}
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci	return 0;
52862306a36Sopenharmony_ci}
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_cistatic void ath10k_snoc_rx_post_pipe(struct ath10k_snoc_pipe *pipe)
53162306a36Sopenharmony_ci{
53262306a36Sopenharmony_ci	struct ath10k *ar = pipe->hif_ce_state;
53362306a36Sopenharmony_ci	struct ath10k_ce *ce = ath10k_ce_priv(ar);
53462306a36Sopenharmony_ci	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
53562306a36Sopenharmony_ci	struct ath10k_ce_pipe *ce_pipe = pipe->ce_hdl;
53662306a36Sopenharmony_ci	int ret, num;
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci	if (pipe->buf_sz == 0)
53962306a36Sopenharmony_ci		return;
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_ci	if (!ce_pipe->dest_ring)
54262306a36Sopenharmony_ci		return;
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_ci	spin_lock_bh(&ce->ce_lock);
54562306a36Sopenharmony_ci	num = __ath10k_ce_rx_num_free_bufs(ce_pipe);
54662306a36Sopenharmony_ci	spin_unlock_bh(&ce->ce_lock);
54762306a36Sopenharmony_ci	while (num--) {
54862306a36Sopenharmony_ci		ret = __ath10k_snoc_rx_post_buf(pipe);
54962306a36Sopenharmony_ci		if (ret) {
55062306a36Sopenharmony_ci			if (ret == -ENOSPC)
55162306a36Sopenharmony_ci				break;
55262306a36Sopenharmony_ci			ath10k_warn(ar, "failed to post rx buf: %d\n", ret);
55362306a36Sopenharmony_ci			mod_timer(&ar_snoc->rx_post_retry, jiffies +
55462306a36Sopenharmony_ci				  ATH10K_SNOC_RX_POST_RETRY_MS);
55562306a36Sopenharmony_ci			break;
55662306a36Sopenharmony_ci		}
55762306a36Sopenharmony_ci	}
55862306a36Sopenharmony_ci}
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_cistatic void ath10k_snoc_rx_post(struct ath10k *ar)
56162306a36Sopenharmony_ci{
56262306a36Sopenharmony_ci	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
56362306a36Sopenharmony_ci	int i;
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci	for (i = 0; i < CE_COUNT; i++)
56662306a36Sopenharmony_ci		ath10k_snoc_rx_post_pipe(&ar_snoc->pipe_info[i]);
56762306a36Sopenharmony_ci}
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_cistatic void ath10k_snoc_process_rx_cb(struct ath10k_ce_pipe *ce_state,
57062306a36Sopenharmony_ci				      void (*callback)(struct ath10k *ar,
57162306a36Sopenharmony_ci						       struct sk_buff *skb))
57262306a36Sopenharmony_ci{
57362306a36Sopenharmony_ci	struct ath10k *ar = ce_state->ar;
57462306a36Sopenharmony_ci	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
57562306a36Sopenharmony_ci	struct ath10k_snoc_pipe *pipe_info =  &ar_snoc->pipe_info[ce_state->id];
57662306a36Sopenharmony_ci	struct sk_buff *skb;
57762306a36Sopenharmony_ci	struct sk_buff_head list;
57862306a36Sopenharmony_ci	void *transfer_context;
57962306a36Sopenharmony_ci	unsigned int nbytes, max_nbytes;
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ci	__skb_queue_head_init(&list);
58262306a36Sopenharmony_ci	while (ath10k_ce_completed_recv_next(ce_state, &transfer_context,
58362306a36Sopenharmony_ci					     &nbytes) == 0) {
58462306a36Sopenharmony_ci		skb = transfer_context;
58562306a36Sopenharmony_ci		max_nbytes = skb->len + skb_tailroom(skb);
58662306a36Sopenharmony_ci		dma_unmap_single(ar->dev, ATH10K_SKB_RXCB(skb)->paddr,
58762306a36Sopenharmony_ci				 max_nbytes, DMA_FROM_DEVICE);
58862306a36Sopenharmony_ci
58962306a36Sopenharmony_ci		if (unlikely(max_nbytes < nbytes)) {
59062306a36Sopenharmony_ci			ath10k_warn(ar, "rxed more than expected (nbytes %d, max %d)\n",
59162306a36Sopenharmony_ci				    nbytes, max_nbytes);
59262306a36Sopenharmony_ci			dev_kfree_skb_any(skb);
59362306a36Sopenharmony_ci			continue;
59462306a36Sopenharmony_ci		}
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ci		skb_put(skb, nbytes);
59762306a36Sopenharmony_ci		__skb_queue_tail(&list, skb);
59862306a36Sopenharmony_ci	}
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_ci	while ((skb = __skb_dequeue(&list))) {
60162306a36Sopenharmony_ci		ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc rx ce pipe %d len %d\n",
60262306a36Sopenharmony_ci			   ce_state->id, skb->len);
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_ci		callback(ar, skb);
60562306a36Sopenharmony_ci	}
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_ci	ath10k_snoc_rx_post_pipe(pipe_info);
60862306a36Sopenharmony_ci}
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_cistatic void ath10k_snoc_htc_rx_cb(struct ath10k_ce_pipe *ce_state)
61162306a36Sopenharmony_ci{
61262306a36Sopenharmony_ci	ath10k_snoc_process_rx_cb(ce_state, ath10k_htc_rx_completion_handler);
61362306a36Sopenharmony_ci}
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_cistatic void ath10k_snoc_htt_htc_rx_cb(struct ath10k_ce_pipe *ce_state)
61662306a36Sopenharmony_ci{
61762306a36Sopenharmony_ci	/* CE4 polling needs to be done whenever CE pipe which transports
61862306a36Sopenharmony_ci	 * HTT Rx (target->host) is processed.
61962306a36Sopenharmony_ci	 */
62062306a36Sopenharmony_ci	ath10k_ce_per_engine_service(ce_state->ar, CE_POLL_PIPE);
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci	ath10k_snoc_process_rx_cb(ce_state, ath10k_htc_rx_completion_handler);
62362306a36Sopenharmony_ci}
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_ci/* Called by lower (CE) layer when data is received from the Target.
62662306a36Sopenharmony_ci * WCN3990 firmware uses separate CE(CE11) to transfer pktlog data.
62762306a36Sopenharmony_ci */
62862306a36Sopenharmony_cistatic void ath10k_snoc_pktlog_rx_cb(struct ath10k_ce_pipe *ce_state)
62962306a36Sopenharmony_ci{
63062306a36Sopenharmony_ci	ath10k_snoc_process_rx_cb(ce_state, ath10k_htc_rx_completion_handler);
63162306a36Sopenharmony_ci}
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_cistatic void ath10k_snoc_htt_rx_deliver(struct ath10k *ar, struct sk_buff *skb)
63462306a36Sopenharmony_ci{
63562306a36Sopenharmony_ci	skb_pull(skb, sizeof(struct ath10k_htc_hdr));
63662306a36Sopenharmony_ci	ath10k_htt_t2h_msg_handler(ar, skb);
63762306a36Sopenharmony_ci}
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_cistatic void ath10k_snoc_htt_rx_cb(struct ath10k_ce_pipe *ce_state)
64062306a36Sopenharmony_ci{
64162306a36Sopenharmony_ci	ath10k_ce_per_engine_service(ce_state->ar, CE_POLL_PIPE);
64262306a36Sopenharmony_ci	ath10k_snoc_process_rx_cb(ce_state, ath10k_snoc_htt_rx_deliver);
64362306a36Sopenharmony_ci}
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_cistatic void ath10k_snoc_rx_replenish_retry(struct timer_list *t)
64662306a36Sopenharmony_ci{
64762306a36Sopenharmony_ci	struct ath10k_snoc *ar_snoc = from_timer(ar_snoc, t, rx_post_retry);
64862306a36Sopenharmony_ci	struct ath10k *ar = ar_snoc->ar;
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ci	ath10k_snoc_rx_post(ar);
65162306a36Sopenharmony_ci}
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_cistatic void ath10k_snoc_htc_tx_cb(struct ath10k_ce_pipe *ce_state)
65462306a36Sopenharmony_ci{
65562306a36Sopenharmony_ci	struct ath10k *ar = ce_state->ar;
65662306a36Sopenharmony_ci	struct sk_buff_head list;
65762306a36Sopenharmony_ci	struct sk_buff *skb;
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_ci	__skb_queue_head_init(&list);
66062306a36Sopenharmony_ci	while (ath10k_ce_completed_send_next(ce_state, (void **)&skb) == 0) {
66162306a36Sopenharmony_ci		if (!skb)
66262306a36Sopenharmony_ci			continue;
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci		__skb_queue_tail(&list, skb);
66562306a36Sopenharmony_ci	}
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_ci	while ((skb = __skb_dequeue(&list)))
66862306a36Sopenharmony_ci		ath10k_htc_tx_completion_handler(ar, skb);
66962306a36Sopenharmony_ci}
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_cistatic void ath10k_snoc_htt_tx_cb(struct ath10k_ce_pipe *ce_state)
67262306a36Sopenharmony_ci{
67362306a36Sopenharmony_ci	struct ath10k *ar = ce_state->ar;
67462306a36Sopenharmony_ci	struct sk_buff *skb;
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci	while (ath10k_ce_completed_send_next(ce_state, (void **)&skb) == 0) {
67762306a36Sopenharmony_ci		if (!skb)
67862306a36Sopenharmony_ci			continue;
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci		dma_unmap_single(ar->dev, ATH10K_SKB_CB(skb)->paddr,
68162306a36Sopenharmony_ci				 skb->len, DMA_TO_DEVICE);
68262306a36Sopenharmony_ci		ath10k_htt_hif_tx_complete(ar, skb);
68362306a36Sopenharmony_ci	}
68462306a36Sopenharmony_ci}
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_cistatic int ath10k_snoc_hif_tx_sg(struct ath10k *ar, u8 pipe_id,
68762306a36Sopenharmony_ci				 struct ath10k_hif_sg_item *items, int n_items)
68862306a36Sopenharmony_ci{
68962306a36Sopenharmony_ci	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
69062306a36Sopenharmony_ci	struct ath10k_ce *ce = ath10k_ce_priv(ar);
69162306a36Sopenharmony_ci	struct ath10k_snoc_pipe *snoc_pipe;
69262306a36Sopenharmony_ci	struct ath10k_ce_pipe *ce_pipe;
69362306a36Sopenharmony_ci	int err, i = 0;
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_ci	snoc_pipe = &ar_snoc->pipe_info[pipe_id];
69662306a36Sopenharmony_ci	ce_pipe = snoc_pipe->ce_hdl;
69762306a36Sopenharmony_ci	spin_lock_bh(&ce->ce_lock);
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_ci	for (i = 0; i < n_items - 1; i++) {
70062306a36Sopenharmony_ci		ath10k_dbg(ar, ATH10K_DBG_SNOC,
70162306a36Sopenharmony_ci			   "snoc tx item %d paddr %pad len %d n_items %d\n",
70262306a36Sopenharmony_ci			   i, &items[i].paddr, items[i].len, n_items);
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_ci		err = ath10k_ce_send_nolock(ce_pipe,
70562306a36Sopenharmony_ci					    items[i].transfer_context,
70662306a36Sopenharmony_ci					    items[i].paddr,
70762306a36Sopenharmony_ci					    items[i].len,
70862306a36Sopenharmony_ci					    items[i].transfer_id,
70962306a36Sopenharmony_ci					    CE_SEND_FLAG_GATHER);
71062306a36Sopenharmony_ci		if (err)
71162306a36Sopenharmony_ci			goto err;
71262306a36Sopenharmony_ci	}
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_ci	ath10k_dbg(ar, ATH10K_DBG_SNOC,
71562306a36Sopenharmony_ci		   "snoc tx item %d paddr %pad len %d n_items %d\n",
71662306a36Sopenharmony_ci		   i, &items[i].paddr, items[i].len, n_items);
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_ci	err = ath10k_ce_send_nolock(ce_pipe,
71962306a36Sopenharmony_ci				    items[i].transfer_context,
72062306a36Sopenharmony_ci				    items[i].paddr,
72162306a36Sopenharmony_ci				    items[i].len,
72262306a36Sopenharmony_ci				    items[i].transfer_id,
72362306a36Sopenharmony_ci				    0);
72462306a36Sopenharmony_ci	if (err)
72562306a36Sopenharmony_ci		goto err;
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_ci	spin_unlock_bh(&ce->ce_lock);
72862306a36Sopenharmony_ci
72962306a36Sopenharmony_ci	return 0;
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_cierr:
73262306a36Sopenharmony_ci	for (; i > 0; i--)
73362306a36Sopenharmony_ci		__ath10k_ce_send_revert(ce_pipe);
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_ci	spin_unlock_bh(&ce->ce_lock);
73662306a36Sopenharmony_ci	return err;
73762306a36Sopenharmony_ci}
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_cistatic int ath10k_snoc_hif_get_target_info(struct ath10k *ar,
74062306a36Sopenharmony_ci					   struct bmi_target_info *target_info)
74162306a36Sopenharmony_ci{
74262306a36Sopenharmony_ci	target_info->version = ATH10K_HW_WCN3990;
74362306a36Sopenharmony_ci	target_info->type = ATH10K_HW_WCN3990;
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_ci	return 0;
74662306a36Sopenharmony_ci}
74762306a36Sopenharmony_ci
74862306a36Sopenharmony_cistatic u16 ath10k_snoc_hif_get_free_queue_number(struct ath10k *ar, u8 pipe)
74962306a36Sopenharmony_ci{
75062306a36Sopenharmony_ci	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
75162306a36Sopenharmony_ci
75262306a36Sopenharmony_ci	ath10k_dbg(ar, ATH10K_DBG_SNOC, "hif get free queue number\n");
75362306a36Sopenharmony_ci
75462306a36Sopenharmony_ci	return ath10k_ce_num_free_src_entries(ar_snoc->pipe_info[pipe].ce_hdl);
75562306a36Sopenharmony_ci}
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_cistatic void ath10k_snoc_hif_send_complete_check(struct ath10k *ar, u8 pipe,
75862306a36Sopenharmony_ci						int force)
75962306a36Sopenharmony_ci{
76062306a36Sopenharmony_ci	int resources;
76162306a36Sopenharmony_ci
76262306a36Sopenharmony_ci	ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc hif send complete check\n");
76362306a36Sopenharmony_ci
76462306a36Sopenharmony_ci	if (!force) {
76562306a36Sopenharmony_ci		resources = ath10k_snoc_hif_get_free_queue_number(ar, pipe);
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_ci		if (resources > (host_ce_config_wlan[pipe].src_nentries >> 1))
76862306a36Sopenharmony_ci			return;
76962306a36Sopenharmony_ci	}
77062306a36Sopenharmony_ci	ath10k_ce_per_engine_service(ar, pipe);
77162306a36Sopenharmony_ci}
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_cistatic int ath10k_snoc_hif_map_service_to_pipe(struct ath10k *ar,
77462306a36Sopenharmony_ci					       u16 service_id,
77562306a36Sopenharmony_ci					       u8 *ul_pipe, u8 *dl_pipe)
77662306a36Sopenharmony_ci{
77762306a36Sopenharmony_ci	const struct ce_service_to_pipe *entry;
77862306a36Sopenharmony_ci	bool ul_set = false, dl_set = false;
77962306a36Sopenharmony_ci	int i;
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_ci	ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc hif map service\n");
78262306a36Sopenharmony_ci
78362306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(target_service_to_ce_map_wlan); i++) {
78462306a36Sopenharmony_ci		entry = &target_service_to_ce_map_wlan[i];
78562306a36Sopenharmony_ci
78662306a36Sopenharmony_ci		if (__le32_to_cpu(entry->service_id) != service_id)
78762306a36Sopenharmony_ci			continue;
78862306a36Sopenharmony_ci
78962306a36Sopenharmony_ci		switch (__le32_to_cpu(entry->pipedir)) {
79062306a36Sopenharmony_ci		case PIPEDIR_NONE:
79162306a36Sopenharmony_ci			break;
79262306a36Sopenharmony_ci		case PIPEDIR_IN:
79362306a36Sopenharmony_ci			WARN_ON(dl_set);
79462306a36Sopenharmony_ci			*dl_pipe = __le32_to_cpu(entry->pipenum);
79562306a36Sopenharmony_ci			dl_set = true;
79662306a36Sopenharmony_ci			break;
79762306a36Sopenharmony_ci		case PIPEDIR_OUT:
79862306a36Sopenharmony_ci			WARN_ON(ul_set);
79962306a36Sopenharmony_ci			*ul_pipe = __le32_to_cpu(entry->pipenum);
80062306a36Sopenharmony_ci			ul_set = true;
80162306a36Sopenharmony_ci			break;
80262306a36Sopenharmony_ci		case PIPEDIR_INOUT:
80362306a36Sopenharmony_ci			WARN_ON(dl_set);
80462306a36Sopenharmony_ci			WARN_ON(ul_set);
80562306a36Sopenharmony_ci			*dl_pipe = __le32_to_cpu(entry->pipenum);
80662306a36Sopenharmony_ci			*ul_pipe = __le32_to_cpu(entry->pipenum);
80762306a36Sopenharmony_ci			dl_set = true;
80862306a36Sopenharmony_ci			ul_set = true;
80962306a36Sopenharmony_ci			break;
81062306a36Sopenharmony_ci		}
81162306a36Sopenharmony_ci	}
81262306a36Sopenharmony_ci
81362306a36Sopenharmony_ci	if (!ul_set || !dl_set)
81462306a36Sopenharmony_ci		return -ENOENT;
81562306a36Sopenharmony_ci
81662306a36Sopenharmony_ci	return 0;
81762306a36Sopenharmony_ci}
81862306a36Sopenharmony_ci
81962306a36Sopenharmony_cistatic void ath10k_snoc_hif_get_default_pipe(struct ath10k *ar,
82062306a36Sopenharmony_ci					     u8 *ul_pipe, u8 *dl_pipe)
82162306a36Sopenharmony_ci{
82262306a36Sopenharmony_ci	ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc hif get default pipe\n");
82362306a36Sopenharmony_ci
82462306a36Sopenharmony_ci	(void)ath10k_snoc_hif_map_service_to_pipe(ar,
82562306a36Sopenharmony_ci						 ATH10K_HTC_SVC_ID_RSVD_CTRL,
82662306a36Sopenharmony_ci						 ul_pipe, dl_pipe);
82762306a36Sopenharmony_ci}
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_cistatic inline void ath10k_snoc_irq_disable(struct ath10k *ar)
83062306a36Sopenharmony_ci{
83162306a36Sopenharmony_ci	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
83262306a36Sopenharmony_ci	int id;
83362306a36Sopenharmony_ci
83462306a36Sopenharmony_ci	for (id = 0; id < CE_COUNT_MAX; id++)
83562306a36Sopenharmony_ci		disable_irq(ar_snoc->ce_irqs[id].irq_line);
83662306a36Sopenharmony_ci}
83762306a36Sopenharmony_ci
83862306a36Sopenharmony_cistatic inline void ath10k_snoc_irq_enable(struct ath10k *ar)
83962306a36Sopenharmony_ci{
84062306a36Sopenharmony_ci	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
84162306a36Sopenharmony_ci	int id;
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_ci	for (id = 0; id < CE_COUNT_MAX; id++)
84462306a36Sopenharmony_ci		enable_irq(ar_snoc->ce_irqs[id].irq_line);
84562306a36Sopenharmony_ci}
84662306a36Sopenharmony_ci
84762306a36Sopenharmony_cistatic void ath10k_snoc_rx_pipe_cleanup(struct ath10k_snoc_pipe *snoc_pipe)
84862306a36Sopenharmony_ci{
84962306a36Sopenharmony_ci	struct ath10k_ce_pipe *ce_pipe;
85062306a36Sopenharmony_ci	struct ath10k_ce_ring *ce_ring;
85162306a36Sopenharmony_ci	struct sk_buff *skb;
85262306a36Sopenharmony_ci	struct ath10k *ar;
85362306a36Sopenharmony_ci	int i;
85462306a36Sopenharmony_ci
85562306a36Sopenharmony_ci	ar = snoc_pipe->hif_ce_state;
85662306a36Sopenharmony_ci	ce_pipe = snoc_pipe->ce_hdl;
85762306a36Sopenharmony_ci	ce_ring = ce_pipe->dest_ring;
85862306a36Sopenharmony_ci
85962306a36Sopenharmony_ci	if (!ce_ring)
86062306a36Sopenharmony_ci		return;
86162306a36Sopenharmony_ci
86262306a36Sopenharmony_ci	if (!snoc_pipe->buf_sz)
86362306a36Sopenharmony_ci		return;
86462306a36Sopenharmony_ci
86562306a36Sopenharmony_ci	for (i = 0; i < ce_ring->nentries; i++) {
86662306a36Sopenharmony_ci		skb = ce_ring->per_transfer_context[i];
86762306a36Sopenharmony_ci		if (!skb)
86862306a36Sopenharmony_ci			continue;
86962306a36Sopenharmony_ci
87062306a36Sopenharmony_ci		ce_ring->per_transfer_context[i] = NULL;
87162306a36Sopenharmony_ci
87262306a36Sopenharmony_ci		dma_unmap_single(ar->dev, ATH10K_SKB_RXCB(skb)->paddr,
87362306a36Sopenharmony_ci				 skb->len + skb_tailroom(skb),
87462306a36Sopenharmony_ci				 DMA_FROM_DEVICE);
87562306a36Sopenharmony_ci		dev_kfree_skb_any(skb);
87662306a36Sopenharmony_ci	}
87762306a36Sopenharmony_ci}
87862306a36Sopenharmony_ci
87962306a36Sopenharmony_cistatic void ath10k_snoc_tx_pipe_cleanup(struct ath10k_snoc_pipe *snoc_pipe)
88062306a36Sopenharmony_ci{
88162306a36Sopenharmony_ci	struct ath10k_ce_pipe *ce_pipe;
88262306a36Sopenharmony_ci	struct ath10k_ce_ring *ce_ring;
88362306a36Sopenharmony_ci	struct sk_buff *skb;
88462306a36Sopenharmony_ci	struct ath10k *ar;
88562306a36Sopenharmony_ci	int i;
88662306a36Sopenharmony_ci
88762306a36Sopenharmony_ci	ar = snoc_pipe->hif_ce_state;
88862306a36Sopenharmony_ci	ce_pipe = snoc_pipe->ce_hdl;
88962306a36Sopenharmony_ci	ce_ring = ce_pipe->src_ring;
89062306a36Sopenharmony_ci
89162306a36Sopenharmony_ci	if (!ce_ring)
89262306a36Sopenharmony_ci		return;
89362306a36Sopenharmony_ci
89462306a36Sopenharmony_ci	if (!snoc_pipe->buf_sz)
89562306a36Sopenharmony_ci		return;
89662306a36Sopenharmony_ci
89762306a36Sopenharmony_ci	for (i = 0; i < ce_ring->nentries; i++) {
89862306a36Sopenharmony_ci		skb = ce_ring->per_transfer_context[i];
89962306a36Sopenharmony_ci		if (!skb)
90062306a36Sopenharmony_ci			continue;
90162306a36Sopenharmony_ci
90262306a36Sopenharmony_ci		ce_ring->per_transfer_context[i] = NULL;
90362306a36Sopenharmony_ci
90462306a36Sopenharmony_ci		ath10k_htc_tx_completion_handler(ar, skb);
90562306a36Sopenharmony_ci	}
90662306a36Sopenharmony_ci}
90762306a36Sopenharmony_ci
90862306a36Sopenharmony_cistatic void ath10k_snoc_buffer_cleanup(struct ath10k *ar)
90962306a36Sopenharmony_ci{
91062306a36Sopenharmony_ci	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
91162306a36Sopenharmony_ci	struct ath10k_snoc_pipe *pipe_info;
91262306a36Sopenharmony_ci	int pipe_num;
91362306a36Sopenharmony_ci
91462306a36Sopenharmony_ci	del_timer_sync(&ar_snoc->rx_post_retry);
91562306a36Sopenharmony_ci	for (pipe_num = 0; pipe_num < CE_COUNT; pipe_num++) {
91662306a36Sopenharmony_ci		pipe_info = &ar_snoc->pipe_info[pipe_num];
91762306a36Sopenharmony_ci		ath10k_snoc_rx_pipe_cleanup(pipe_info);
91862306a36Sopenharmony_ci		ath10k_snoc_tx_pipe_cleanup(pipe_info);
91962306a36Sopenharmony_ci	}
92062306a36Sopenharmony_ci}
92162306a36Sopenharmony_ci
92262306a36Sopenharmony_cistatic void ath10k_snoc_hif_stop(struct ath10k *ar)
92362306a36Sopenharmony_ci{
92462306a36Sopenharmony_ci	if (!test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags))
92562306a36Sopenharmony_ci		ath10k_snoc_irq_disable(ar);
92662306a36Sopenharmony_ci
92762306a36Sopenharmony_ci	ath10k_core_napi_sync_disable(ar);
92862306a36Sopenharmony_ci	ath10k_snoc_buffer_cleanup(ar);
92962306a36Sopenharmony_ci	ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif stop\n");
93062306a36Sopenharmony_ci}
93162306a36Sopenharmony_ci
93262306a36Sopenharmony_cistatic int ath10k_snoc_hif_start(struct ath10k *ar)
93362306a36Sopenharmony_ci{
93462306a36Sopenharmony_ci	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
93562306a36Sopenharmony_ci
93662306a36Sopenharmony_ci	bitmap_clear(ar_snoc->pending_ce_irqs, 0, CE_COUNT_MAX);
93762306a36Sopenharmony_ci
93862306a36Sopenharmony_ci	dev_set_threaded(&ar->napi_dev, true);
93962306a36Sopenharmony_ci	ath10k_core_napi_enable(ar);
94062306a36Sopenharmony_ci	ath10k_snoc_irq_enable(ar);
94162306a36Sopenharmony_ci	ath10k_snoc_rx_post(ar);
94262306a36Sopenharmony_ci
94362306a36Sopenharmony_ci	clear_bit(ATH10K_SNOC_FLAG_RECOVERY, &ar_snoc->flags);
94462306a36Sopenharmony_ci
94562306a36Sopenharmony_ci	ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif start\n");
94662306a36Sopenharmony_ci
94762306a36Sopenharmony_ci	return 0;
94862306a36Sopenharmony_ci}
94962306a36Sopenharmony_ci
95062306a36Sopenharmony_cistatic int ath10k_snoc_init_pipes(struct ath10k *ar)
95162306a36Sopenharmony_ci{
95262306a36Sopenharmony_ci	int i, ret;
95362306a36Sopenharmony_ci
95462306a36Sopenharmony_ci	for (i = 0; i < CE_COUNT; i++) {
95562306a36Sopenharmony_ci		ret = ath10k_ce_init_pipe(ar, i, &host_ce_config_wlan[i]);
95662306a36Sopenharmony_ci		if (ret) {
95762306a36Sopenharmony_ci			ath10k_err(ar, "failed to initialize copy engine pipe %d: %d\n",
95862306a36Sopenharmony_ci				   i, ret);
95962306a36Sopenharmony_ci			return ret;
96062306a36Sopenharmony_ci		}
96162306a36Sopenharmony_ci	}
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_ci	return 0;
96462306a36Sopenharmony_ci}
96562306a36Sopenharmony_ci
96662306a36Sopenharmony_cistatic int ath10k_snoc_wlan_enable(struct ath10k *ar,
96762306a36Sopenharmony_ci				   enum ath10k_firmware_mode fw_mode)
96862306a36Sopenharmony_ci{
96962306a36Sopenharmony_ci	struct ath10k_tgt_pipe_cfg tgt_cfg[CE_COUNT_MAX];
97062306a36Sopenharmony_ci	struct ath10k_qmi_wlan_enable_cfg cfg;
97162306a36Sopenharmony_ci	enum wlfw_driver_mode_enum_v01 mode;
97262306a36Sopenharmony_ci	int pipe_num;
97362306a36Sopenharmony_ci
97462306a36Sopenharmony_ci	for (pipe_num = 0; pipe_num < CE_COUNT_MAX; pipe_num++) {
97562306a36Sopenharmony_ci		tgt_cfg[pipe_num].pipe_num =
97662306a36Sopenharmony_ci				target_ce_config_wlan[pipe_num].pipenum;
97762306a36Sopenharmony_ci		tgt_cfg[pipe_num].pipe_dir =
97862306a36Sopenharmony_ci				target_ce_config_wlan[pipe_num].pipedir;
97962306a36Sopenharmony_ci		tgt_cfg[pipe_num].nentries =
98062306a36Sopenharmony_ci				target_ce_config_wlan[pipe_num].nentries;
98162306a36Sopenharmony_ci		tgt_cfg[pipe_num].nbytes_max =
98262306a36Sopenharmony_ci				target_ce_config_wlan[pipe_num].nbytes_max;
98362306a36Sopenharmony_ci		tgt_cfg[pipe_num].flags =
98462306a36Sopenharmony_ci				target_ce_config_wlan[pipe_num].flags;
98562306a36Sopenharmony_ci		tgt_cfg[pipe_num].reserved = 0;
98662306a36Sopenharmony_ci	}
98762306a36Sopenharmony_ci
98862306a36Sopenharmony_ci	cfg.num_ce_tgt_cfg = sizeof(target_ce_config_wlan) /
98962306a36Sopenharmony_ci				sizeof(struct ath10k_tgt_pipe_cfg);
99062306a36Sopenharmony_ci	cfg.ce_tgt_cfg = (struct ath10k_tgt_pipe_cfg *)
99162306a36Sopenharmony_ci		&tgt_cfg;
99262306a36Sopenharmony_ci	cfg.num_ce_svc_pipe_cfg = sizeof(target_service_to_ce_map_wlan) /
99362306a36Sopenharmony_ci				  sizeof(struct ath10k_svc_pipe_cfg);
99462306a36Sopenharmony_ci	cfg.ce_svc_cfg = (struct ath10k_svc_pipe_cfg *)
99562306a36Sopenharmony_ci		&target_service_to_ce_map_wlan;
99662306a36Sopenharmony_ci	cfg.num_shadow_reg_cfg = ARRAY_SIZE(target_shadow_reg_cfg_map);
99762306a36Sopenharmony_ci	cfg.shadow_reg_cfg = (struct ath10k_shadow_reg_cfg *)
99862306a36Sopenharmony_ci		&target_shadow_reg_cfg_map;
99962306a36Sopenharmony_ci
100062306a36Sopenharmony_ci	switch (fw_mode) {
100162306a36Sopenharmony_ci	case ATH10K_FIRMWARE_MODE_NORMAL:
100262306a36Sopenharmony_ci		mode = QMI_WLFW_MISSION_V01;
100362306a36Sopenharmony_ci		break;
100462306a36Sopenharmony_ci	case ATH10K_FIRMWARE_MODE_UTF:
100562306a36Sopenharmony_ci		mode = QMI_WLFW_FTM_V01;
100662306a36Sopenharmony_ci		break;
100762306a36Sopenharmony_ci	default:
100862306a36Sopenharmony_ci		ath10k_err(ar, "invalid firmware mode %d\n", fw_mode);
100962306a36Sopenharmony_ci		return -EINVAL;
101062306a36Sopenharmony_ci	}
101162306a36Sopenharmony_ci
101262306a36Sopenharmony_ci	return ath10k_qmi_wlan_enable(ar, &cfg, mode,
101362306a36Sopenharmony_ci				       NULL);
101462306a36Sopenharmony_ci}
101562306a36Sopenharmony_ci
101662306a36Sopenharmony_cistatic int ath10k_hw_power_on(struct ath10k *ar)
101762306a36Sopenharmony_ci{
101862306a36Sopenharmony_ci	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
101962306a36Sopenharmony_ci	int ret;
102062306a36Sopenharmony_ci
102162306a36Sopenharmony_ci	ath10k_dbg(ar, ATH10K_DBG_SNOC, "soc power on\n");
102262306a36Sopenharmony_ci
102362306a36Sopenharmony_ci	ret = regulator_bulk_enable(ar_snoc->num_vregs, ar_snoc->vregs);
102462306a36Sopenharmony_ci	if (ret)
102562306a36Sopenharmony_ci		return ret;
102662306a36Sopenharmony_ci
102762306a36Sopenharmony_ci	ret = clk_bulk_prepare_enable(ar_snoc->num_clks, ar_snoc->clks);
102862306a36Sopenharmony_ci	if (ret)
102962306a36Sopenharmony_ci		goto vreg_off;
103062306a36Sopenharmony_ci
103162306a36Sopenharmony_ci	return ret;
103262306a36Sopenharmony_ci
103362306a36Sopenharmony_civreg_off:
103462306a36Sopenharmony_ci	regulator_bulk_disable(ar_snoc->num_vregs, ar_snoc->vregs);
103562306a36Sopenharmony_ci	return ret;
103662306a36Sopenharmony_ci}
103762306a36Sopenharmony_ci
103862306a36Sopenharmony_cistatic int ath10k_hw_power_off(struct ath10k *ar)
103962306a36Sopenharmony_ci{
104062306a36Sopenharmony_ci	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
104162306a36Sopenharmony_ci
104262306a36Sopenharmony_ci	ath10k_dbg(ar, ATH10K_DBG_SNOC, "soc power off\n");
104362306a36Sopenharmony_ci
104462306a36Sopenharmony_ci	clk_bulk_disable_unprepare(ar_snoc->num_clks, ar_snoc->clks);
104562306a36Sopenharmony_ci
104662306a36Sopenharmony_ci	return regulator_bulk_disable(ar_snoc->num_vregs, ar_snoc->vregs);
104762306a36Sopenharmony_ci}
104862306a36Sopenharmony_ci
104962306a36Sopenharmony_cistatic void ath10k_snoc_wlan_disable(struct ath10k *ar)
105062306a36Sopenharmony_ci{
105162306a36Sopenharmony_ci	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
105262306a36Sopenharmony_ci
105362306a36Sopenharmony_ci	/* If both ATH10K_FLAG_CRASH_FLUSH and ATH10K_SNOC_FLAG_RECOVERY
105462306a36Sopenharmony_ci	 * flags are not set, it means that the driver has restarted
105562306a36Sopenharmony_ci	 * due to a crash inject via debugfs. In this case, the driver
105662306a36Sopenharmony_ci	 * needs to restart the firmware and hence send qmi wlan disable,
105762306a36Sopenharmony_ci	 * during the driver restart sequence.
105862306a36Sopenharmony_ci	 */
105962306a36Sopenharmony_ci	if (!test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags) ||
106062306a36Sopenharmony_ci	    !test_bit(ATH10K_SNOC_FLAG_RECOVERY, &ar_snoc->flags))
106162306a36Sopenharmony_ci		ath10k_qmi_wlan_disable(ar);
106262306a36Sopenharmony_ci}
106362306a36Sopenharmony_ci
106462306a36Sopenharmony_cistatic void ath10k_snoc_hif_power_down(struct ath10k *ar)
106562306a36Sopenharmony_ci{
106662306a36Sopenharmony_ci	ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif power down\n");
106762306a36Sopenharmony_ci
106862306a36Sopenharmony_ci	ath10k_snoc_wlan_disable(ar);
106962306a36Sopenharmony_ci	ath10k_ce_free_rri(ar);
107062306a36Sopenharmony_ci	ath10k_hw_power_off(ar);
107162306a36Sopenharmony_ci}
107262306a36Sopenharmony_ci
107362306a36Sopenharmony_cistatic int ath10k_snoc_hif_power_up(struct ath10k *ar,
107462306a36Sopenharmony_ci				    enum ath10k_firmware_mode fw_mode)
107562306a36Sopenharmony_ci{
107662306a36Sopenharmony_ci	int ret;
107762306a36Sopenharmony_ci
107862306a36Sopenharmony_ci	ath10k_dbg(ar, ATH10K_DBG_SNOC, "%s:WCN3990 driver state = %d\n",
107962306a36Sopenharmony_ci		   __func__, ar->state);
108062306a36Sopenharmony_ci
108162306a36Sopenharmony_ci	ret = ath10k_hw_power_on(ar);
108262306a36Sopenharmony_ci	if (ret) {
108362306a36Sopenharmony_ci		ath10k_err(ar, "failed to power on device: %d\n", ret);
108462306a36Sopenharmony_ci		return ret;
108562306a36Sopenharmony_ci	}
108662306a36Sopenharmony_ci
108762306a36Sopenharmony_ci	ret = ath10k_snoc_wlan_enable(ar, fw_mode);
108862306a36Sopenharmony_ci	if (ret) {
108962306a36Sopenharmony_ci		ath10k_err(ar, "failed to enable wcn3990: %d\n", ret);
109062306a36Sopenharmony_ci		goto err_hw_power_off;
109162306a36Sopenharmony_ci	}
109262306a36Sopenharmony_ci
109362306a36Sopenharmony_ci	ath10k_ce_alloc_rri(ar);
109462306a36Sopenharmony_ci
109562306a36Sopenharmony_ci	ret = ath10k_snoc_init_pipes(ar);
109662306a36Sopenharmony_ci	if (ret) {
109762306a36Sopenharmony_ci		ath10k_err(ar, "failed to initialize CE: %d\n", ret);
109862306a36Sopenharmony_ci		goto err_free_rri;
109962306a36Sopenharmony_ci	}
110062306a36Sopenharmony_ci
110162306a36Sopenharmony_ci	ath10k_ce_enable_interrupts(ar);
110262306a36Sopenharmony_ci
110362306a36Sopenharmony_ci	return 0;
110462306a36Sopenharmony_ci
110562306a36Sopenharmony_cierr_free_rri:
110662306a36Sopenharmony_ci	ath10k_ce_free_rri(ar);
110762306a36Sopenharmony_ci	ath10k_snoc_wlan_disable(ar);
110862306a36Sopenharmony_ci
110962306a36Sopenharmony_cierr_hw_power_off:
111062306a36Sopenharmony_ci	ath10k_hw_power_off(ar);
111162306a36Sopenharmony_ci
111262306a36Sopenharmony_ci	return ret;
111362306a36Sopenharmony_ci}
111462306a36Sopenharmony_ci
111562306a36Sopenharmony_cistatic int ath10k_snoc_hif_set_target_log_mode(struct ath10k *ar,
111662306a36Sopenharmony_ci					       u8 fw_log_mode)
111762306a36Sopenharmony_ci{
111862306a36Sopenharmony_ci	u8 fw_dbg_mode;
111962306a36Sopenharmony_ci
112062306a36Sopenharmony_ci	if (fw_log_mode)
112162306a36Sopenharmony_ci		fw_dbg_mode = ATH10K_ENABLE_FW_LOG_CE;
112262306a36Sopenharmony_ci	else
112362306a36Sopenharmony_ci		fw_dbg_mode = ATH10K_ENABLE_FW_LOG_DIAG;
112462306a36Sopenharmony_ci
112562306a36Sopenharmony_ci	return ath10k_qmi_set_fw_log_mode(ar, fw_dbg_mode);
112662306a36Sopenharmony_ci}
112762306a36Sopenharmony_ci
112862306a36Sopenharmony_ci#ifdef CONFIG_PM
112962306a36Sopenharmony_cistatic int ath10k_snoc_hif_suspend(struct ath10k *ar)
113062306a36Sopenharmony_ci{
113162306a36Sopenharmony_ci	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
113262306a36Sopenharmony_ci	int ret;
113362306a36Sopenharmony_ci
113462306a36Sopenharmony_ci	if (!device_may_wakeup(ar->dev))
113562306a36Sopenharmony_ci		return -EPERM;
113662306a36Sopenharmony_ci
113762306a36Sopenharmony_ci	ret = enable_irq_wake(ar_snoc->ce_irqs[ATH10K_SNOC_WAKE_IRQ].irq_line);
113862306a36Sopenharmony_ci	if (ret) {
113962306a36Sopenharmony_ci		ath10k_err(ar, "failed to enable wakeup irq :%d\n", ret);
114062306a36Sopenharmony_ci		return ret;
114162306a36Sopenharmony_ci	}
114262306a36Sopenharmony_ci
114362306a36Sopenharmony_ci	ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc device suspended\n");
114462306a36Sopenharmony_ci
114562306a36Sopenharmony_ci	return ret;
114662306a36Sopenharmony_ci}
114762306a36Sopenharmony_ci
114862306a36Sopenharmony_cistatic int ath10k_snoc_hif_resume(struct ath10k *ar)
114962306a36Sopenharmony_ci{
115062306a36Sopenharmony_ci	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
115162306a36Sopenharmony_ci	int ret;
115262306a36Sopenharmony_ci
115362306a36Sopenharmony_ci	if (!device_may_wakeup(ar->dev))
115462306a36Sopenharmony_ci		return -EPERM;
115562306a36Sopenharmony_ci
115662306a36Sopenharmony_ci	ret = disable_irq_wake(ar_snoc->ce_irqs[ATH10K_SNOC_WAKE_IRQ].irq_line);
115762306a36Sopenharmony_ci	if (ret) {
115862306a36Sopenharmony_ci		ath10k_err(ar, "failed to disable wakeup irq: %d\n", ret);
115962306a36Sopenharmony_ci		return ret;
116062306a36Sopenharmony_ci	}
116162306a36Sopenharmony_ci
116262306a36Sopenharmony_ci	ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc device resumed\n");
116362306a36Sopenharmony_ci
116462306a36Sopenharmony_ci	return ret;
116562306a36Sopenharmony_ci}
116662306a36Sopenharmony_ci#endif
116762306a36Sopenharmony_ci
116862306a36Sopenharmony_cistatic const struct ath10k_hif_ops ath10k_snoc_hif_ops = {
116962306a36Sopenharmony_ci	.read32		= ath10k_snoc_read32,
117062306a36Sopenharmony_ci	.write32	= ath10k_snoc_write32,
117162306a36Sopenharmony_ci	.start		= ath10k_snoc_hif_start,
117262306a36Sopenharmony_ci	.stop		= ath10k_snoc_hif_stop,
117362306a36Sopenharmony_ci	.map_service_to_pipe	= ath10k_snoc_hif_map_service_to_pipe,
117462306a36Sopenharmony_ci	.get_default_pipe	= ath10k_snoc_hif_get_default_pipe,
117562306a36Sopenharmony_ci	.power_up		= ath10k_snoc_hif_power_up,
117662306a36Sopenharmony_ci	.power_down		= ath10k_snoc_hif_power_down,
117762306a36Sopenharmony_ci	.tx_sg			= ath10k_snoc_hif_tx_sg,
117862306a36Sopenharmony_ci	.send_complete_check	= ath10k_snoc_hif_send_complete_check,
117962306a36Sopenharmony_ci	.get_free_queue_number	= ath10k_snoc_hif_get_free_queue_number,
118062306a36Sopenharmony_ci	.get_target_info	= ath10k_snoc_hif_get_target_info,
118162306a36Sopenharmony_ci	.set_target_log_mode    = ath10k_snoc_hif_set_target_log_mode,
118262306a36Sopenharmony_ci
118362306a36Sopenharmony_ci#ifdef CONFIG_PM
118462306a36Sopenharmony_ci	.suspend                = ath10k_snoc_hif_suspend,
118562306a36Sopenharmony_ci	.resume                 = ath10k_snoc_hif_resume,
118662306a36Sopenharmony_ci#endif
118762306a36Sopenharmony_ci};
118862306a36Sopenharmony_ci
118962306a36Sopenharmony_cistatic const struct ath10k_bus_ops ath10k_snoc_bus_ops = {
119062306a36Sopenharmony_ci	.read32		= ath10k_snoc_read32,
119162306a36Sopenharmony_ci	.write32	= ath10k_snoc_write32,
119262306a36Sopenharmony_ci};
119362306a36Sopenharmony_ci
119462306a36Sopenharmony_cistatic int ath10k_snoc_get_ce_id_from_irq(struct ath10k *ar, int irq)
119562306a36Sopenharmony_ci{
119662306a36Sopenharmony_ci	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
119762306a36Sopenharmony_ci	int i;
119862306a36Sopenharmony_ci
119962306a36Sopenharmony_ci	for (i = 0; i < CE_COUNT_MAX; i++) {
120062306a36Sopenharmony_ci		if (ar_snoc->ce_irqs[i].irq_line == irq)
120162306a36Sopenharmony_ci			return i;
120262306a36Sopenharmony_ci	}
120362306a36Sopenharmony_ci	ath10k_err(ar, "No matching CE id for irq %d\n", irq);
120462306a36Sopenharmony_ci
120562306a36Sopenharmony_ci	return -EINVAL;
120662306a36Sopenharmony_ci}
120762306a36Sopenharmony_ci
120862306a36Sopenharmony_cistatic irqreturn_t ath10k_snoc_per_engine_handler(int irq, void *arg)
120962306a36Sopenharmony_ci{
121062306a36Sopenharmony_ci	struct ath10k *ar = arg;
121162306a36Sopenharmony_ci	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
121262306a36Sopenharmony_ci	int ce_id = ath10k_snoc_get_ce_id_from_irq(ar, irq);
121362306a36Sopenharmony_ci
121462306a36Sopenharmony_ci	if (ce_id < 0 || ce_id >= ARRAY_SIZE(ar_snoc->pipe_info)) {
121562306a36Sopenharmony_ci		ath10k_warn(ar, "unexpected/invalid irq %d ce_id %d\n", irq,
121662306a36Sopenharmony_ci			    ce_id);
121762306a36Sopenharmony_ci		return IRQ_HANDLED;
121862306a36Sopenharmony_ci	}
121962306a36Sopenharmony_ci
122062306a36Sopenharmony_ci	ath10k_ce_disable_interrupt(ar, ce_id);
122162306a36Sopenharmony_ci	set_bit(ce_id, ar_snoc->pending_ce_irqs);
122262306a36Sopenharmony_ci
122362306a36Sopenharmony_ci	napi_schedule(&ar->napi);
122462306a36Sopenharmony_ci
122562306a36Sopenharmony_ci	return IRQ_HANDLED;
122662306a36Sopenharmony_ci}
122762306a36Sopenharmony_ci
122862306a36Sopenharmony_cistatic int ath10k_snoc_napi_poll(struct napi_struct *ctx, int budget)
122962306a36Sopenharmony_ci{
123062306a36Sopenharmony_ci	struct ath10k *ar = container_of(ctx, struct ath10k, napi);
123162306a36Sopenharmony_ci	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
123262306a36Sopenharmony_ci	int done = 0;
123362306a36Sopenharmony_ci	int ce_id;
123462306a36Sopenharmony_ci
123562306a36Sopenharmony_ci	if (test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags)) {
123662306a36Sopenharmony_ci		napi_complete(ctx);
123762306a36Sopenharmony_ci		return done;
123862306a36Sopenharmony_ci	}
123962306a36Sopenharmony_ci
124062306a36Sopenharmony_ci	for (ce_id = 0; ce_id < CE_COUNT; ce_id++)
124162306a36Sopenharmony_ci		if (test_and_clear_bit(ce_id, ar_snoc->pending_ce_irqs)) {
124262306a36Sopenharmony_ci			ath10k_ce_per_engine_service(ar, ce_id);
124362306a36Sopenharmony_ci			ath10k_ce_enable_interrupt(ar, ce_id);
124462306a36Sopenharmony_ci		}
124562306a36Sopenharmony_ci
124662306a36Sopenharmony_ci	done = ath10k_htt_txrx_compl_task(ar, budget);
124762306a36Sopenharmony_ci
124862306a36Sopenharmony_ci	if (done < budget)
124962306a36Sopenharmony_ci		napi_complete(ctx);
125062306a36Sopenharmony_ci
125162306a36Sopenharmony_ci	return done;
125262306a36Sopenharmony_ci}
125362306a36Sopenharmony_ci
125462306a36Sopenharmony_cistatic void ath10k_snoc_init_napi(struct ath10k *ar)
125562306a36Sopenharmony_ci{
125662306a36Sopenharmony_ci	netif_napi_add(&ar->napi_dev, &ar->napi, ath10k_snoc_napi_poll);
125762306a36Sopenharmony_ci}
125862306a36Sopenharmony_ci
125962306a36Sopenharmony_cistatic int ath10k_snoc_request_irq(struct ath10k *ar)
126062306a36Sopenharmony_ci{
126162306a36Sopenharmony_ci	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
126262306a36Sopenharmony_ci	int ret, id;
126362306a36Sopenharmony_ci
126462306a36Sopenharmony_ci	for (id = 0; id < CE_COUNT_MAX; id++) {
126562306a36Sopenharmony_ci		ret = request_irq(ar_snoc->ce_irqs[id].irq_line,
126662306a36Sopenharmony_ci				  ath10k_snoc_per_engine_handler,
126762306a36Sopenharmony_ci				  IRQF_NO_AUTOEN, ce_name[id], ar);
126862306a36Sopenharmony_ci		if (ret) {
126962306a36Sopenharmony_ci			ath10k_err(ar,
127062306a36Sopenharmony_ci				   "failed to register IRQ handler for CE %d: %d\n",
127162306a36Sopenharmony_ci				   id, ret);
127262306a36Sopenharmony_ci			goto err_irq;
127362306a36Sopenharmony_ci		}
127462306a36Sopenharmony_ci	}
127562306a36Sopenharmony_ci
127662306a36Sopenharmony_ci	return 0;
127762306a36Sopenharmony_ci
127862306a36Sopenharmony_cierr_irq:
127962306a36Sopenharmony_ci	for (id -= 1; id >= 0; id--)
128062306a36Sopenharmony_ci		free_irq(ar_snoc->ce_irqs[id].irq_line, ar);
128162306a36Sopenharmony_ci
128262306a36Sopenharmony_ci	return ret;
128362306a36Sopenharmony_ci}
128462306a36Sopenharmony_ci
128562306a36Sopenharmony_cistatic void ath10k_snoc_free_irq(struct ath10k *ar)
128662306a36Sopenharmony_ci{
128762306a36Sopenharmony_ci	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
128862306a36Sopenharmony_ci	int id;
128962306a36Sopenharmony_ci
129062306a36Sopenharmony_ci	for (id = 0; id < CE_COUNT_MAX; id++)
129162306a36Sopenharmony_ci		free_irq(ar_snoc->ce_irqs[id].irq_line, ar);
129262306a36Sopenharmony_ci}
129362306a36Sopenharmony_ci
129462306a36Sopenharmony_cistatic int ath10k_snoc_resource_init(struct ath10k *ar)
129562306a36Sopenharmony_ci{
129662306a36Sopenharmony_ci	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
129762306a36Sopenharmony_ci	struct platform_device *pdev;
129862306a36Sopenharmony_ci	struct resource *res;
129962306a36Sopenharmony_ci	int i, ret = 0;
130062306a36Sopenharmony_ci
130162306a36Sopenharmony_ci	pdev = ar_snoc->dev;
130262306a36Sopenharmony_ci	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "membase");
130362306a36Sopenharmony_ci	if (!res) {
130462306a36Sopenharmony_ci		ath10k_err(ar, "Memory base not found in DT\n");
130562306a36Sopenharmony_ci		return -EINVAL;
130662306a36Sopenharmony_ci	}
130762306a36Sopenharmony_ci
130862306a36Sopenharmony_ci	ar_snoc->mem_pa = res->start;
130962306a36Sopenharmony_ci	ar_snoc->mem = devm_ioremap(&pdev->dev, ar_snoc->mem_pa,
131062306a36Sopenharmony_ci				    resource_size(res));
131162306a36Sopenharmony_ci	if (!ar_snoc->mem) {
131262306a36Sopenharmony_ci		ath10k_err(ar, "Memory base ioremap failed with physical address %pa\n",
131362306a36Sopenharmony_ci			   &ar_snoc->mem_pa);
131462306a36Sopenharmony_ci		return -EINVAL;
131562306a36Sopenharmony_ci	}
131662306a36Sopenharmony_ci
131762306a36Sopenharmony_ci	for (i = 0; i < CE_COUNT; i++) {
131862306a36Sopenharmony_ci		ret = platform_get_irq(ar_snoc->dev, i);
131962306a36Sopenharmony_ci		if (ret < 0)
132062306a36Sopenharmony_ci			return ret;
132162306a36Sopenharmony_ci		ar_snoc->ce_irqs[i].irq_line = ret;
132262306a36Sopenharmony_ci	}
132362306a36Sopenharmony_ci
132462306a36Sopenharmony_ci	ret = device_property_read_u32(&pdev->dev, "qcom,xo-cal-data",
132562306a36Sopenharmony_ci				       &ar_snoc->xo_cal_data);
132662306a36Sopenharmony_ci	ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc xo-cal-data return %d\n", ret);
132762306a36Sopenharmony_ci	if (ret == 0) {
132862306a36Sopenharmony_ci		ar_snoc->xo_cal_supported = true;
132962306a36Sopenharmony_ci		ath10k_dbg(ar, ATH10K_DBG_SNOC, "xo cal data %x\n",
133062306a36Sopenharmony_ci			   ar_snoc->xo_cal_data);
133162306a36Sopenharmony_ci	}
133262306a36Sopenharmony_ci
133362306a36Sopenharmony_ci	return 0;
133462306a36Sopenharmony_ci}
133562306a36Sopenharmony_ci
133662306a36Sopenharmony_cistatic void ath10k_snoc_quirks_init(struct ath10k *ar)
133762306a36Sopenharmony_ci{
133862306a36Sopenharmony_ci	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
133962306a36Sopenharmony_ci	struct device *dev = &ar_snoc->dev->dev;
134062306a36Sopenharmony_ci
134162306a36Sopenharmony_ci	if (of_property_read_bool(dev->of_node, "qcom,snoc-host-cap-8bit-quirk"))
134262306a36Sopenharmony_ci		set_bit(ATH10K_SNOC_FLAG_8BIT_HOST_CAP_QUIRK, &ar_snoc->flags);
134362306a36Sopenharmony_ci}
134462306a36Sopenharmony_ci
134562306a36Sopenharmony_ciint ath10k_snoc_fw_indication(struct ath10k *ar, u64 type)
134662306a36Sopenharmony_ci{
134762306a36Sopenharmony_ci	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
134862306a36Sopenharmony_ci	struct ath10k_bus_params bus_params = {};
134962306a36Sopenharmony_ci	int ret;
135062306a36Sopenharmony_ci
135162306a36Sopenharmony_ci	if (test_bit(ATH10K_SNOC_FLAG_UNREGISTERING, &ar_snoc->flags))
135262306a36Sopenharmony_ci		return 0;
135362306a36Sopenharmony_ci
135462306a36Sopenharmony_ci	switch (type) {
135562306a36Sopenharmony_ci	case ATH10K_QMI_EVENT_FW_READY_IND:
135662306a36Sopenharmony_ci		if (test_bit(ATH10K_SNOC_FLAG_REGISTERED, &ar_snoc->flags)) {
135762306a36Sopenharmony_ci			ath10k_core_start_recovery(ar);
135862306a36Sopenharmony_ci			break;
135962306a36Sopenharmony_ci		}
136062306a36Sopenharmony_ci
136162306a36Sopenharmony_ci		bus_params.dev_type = ATH10K_DEV_TYPE_LL;
136262306a36Sopenharmony_ci		bus_params.chip_id = ar_snoc->target_info.soc_version;
136362306a36Sopenharmony_ci		ret = ath10k_core_register(ar, &bus_params);
136462306a36Sopenharmony_ci		if (ret) {
136562306a36Sopenharmony_ci			ath10k_err(ar, "Failed to register driver core: %d\n",
136662306a36Sopenharmony_ci				   ret);
136762306a36Sopenharmony_ci			return ret;
136862306a36Sopenharmony_ci		}
136962306a36Sopenharmony_ci		set_bit(ATH10K_SNOC_FLAG_REGISTERED, &ar_snoc->flags);
137062306a36Sopenharmony_ci		break;
137162306a36Sopenharmony_ci	case ATH10K_QMI_EVENT_FW_DOWN_IND:
137262306a36Sopenharmony_ci		set_bit(ATH10K_SNOC_FLAG_RECOVERY, &ar_snoc->flags);
137362306a36Sopenharmony_ci		set_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags);
137462306a36Sopenharmony_ci		break;
137562306a36Sopenharmony_ci	default:
137662306a36Sopenharmony_ci		ath10k_err(ar, "invalid fw indication: %llx\n", type);
137762306a36Sopenharmony_ci		return -EINVAL;
137862306a36Sopenharmony_ci	}
137962306a36Sopenharmony_ci
138062306a36Sopenharmony_ci	return 0;
138162306a36Sopenharmony_ci}
138262306a36Sopenharmony_ci
138362306a36Sopenharmony_cistatic int ath10k_snoc_setup_resource(struct ath10k *ar)
138462306a36Sopenharmony_ci{
138562306a36Sopenharmony_ci	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
138662306a36Sopenharmony_ci	struct ath10k_ce *ce = ath10k_ce_priv(ar);
138762306a36Sopenharmony_ci	struct ath10k_snoc_pipe *pipe;
138862306a36Sopenharmony_ci	int i, ret;
138962306a36Sopenharmony_ci
139062306a36Sopenharmony_ci	timer_setup(&ar_snoc->rx_post_retry, ath10k_snoc_rx_replenish_retry, 0);
139162306a36Sopenharmony_ci	spin_lock_init(&ce->ce_lock);
139262306a36Sopenharmony_ci	for (i = 0; i < CE_COUNT; i++) {
139362306a36Sopenharmony_ci		pipe = &ar_snoc->pipe_info[i];
139462306a36Sopenharmony_ci		pipe->ce_hdl = &ce->ce_states[i];
139562306a36Sopenharmony_ci		pipe->pipe_num = i;
139662306a36Sopenharmony_ci		pipe->hif_ce_state = ar;
139762306a36Sopenharmony_ci
139862306a36Sopenharmony_ci		ret = ath10k_ce_alloc_pipe(ar, i, &host_ce_config_wlan[i]);
139962306a36Sopenharmony_ci		if (ret) {
140062306a36Sopenharmony_ci			ath10k_err(ar, "failed to allocate copy engine pipe %d: %d\n",
140162306a36Sopenharmony_ci				   i, ret);
140262306a36Sopenharmony_ci			return ret;
140362306a36Sopenharmony_ci		}
140462306a36Sopenharmony_ci
140562306a36Sopenharmony_ci		pipe->buf_sz = host_ce_config_wlan[i].src_sz_max;
140662306a36Sopenharmony_ci	}
140762306a36Sopenharmony_ci	ath10k_snoc_init_napi(ar);
140862306a36Sopenharmony_ci
140962306a36Sopenharmony_ci	return 0;
141062306a36Sopenharmony_ci}
141162306a36Sopenharmony_ci
141262306a36Sopenharmony_cistatic void ath10k_snoc_release_resource(struct ath10k *ar)
141362306a36Sopenharmony_ci{
141462306a36Sopenharmony_ci	int i;
141562306a36Sopenharmony_ci
141662306a36Sopenharmony_ci	netif_napi_del(&ar->napi);
141762306a36Sopenharmony_ci	for (i = 0; i < CE_COUNT; i++)
141862306a36Sopenharmony_ci		ath10k_ce_free_pipe(ar, i);
141962306a36Sopenharmony_ci}
142062306a36Sopenharmony_ci
142162306a36Sopenharmony_cistatic void ath10k_msa_dump_memory(struct ath10k *ar,
142262306a36Sopenharmony_ci				   struct ath10k_fw_crash_data *crash_data)
142362306a36Sopenharmony_ci{
142462306a36Sopenharmony_ci	const struct ath10k_hw_mem_layout *mem_layout;
142562306a36Sopenharmony_ci	const struct ath10k_mem_region *current_region;
142662306a36Sopenharmony_ci	struct ath10k_dump_ram_data_hdr *hdr;
142762306a36Sopenharmony_ci	size_t buf_len;
142862306a36Sopenharmony_ci	u8 *buf;
142962306a36Sopenharmony_ci
143062306a36Sopenharmony_ci	if (!crash_data || !crash_data->ramdump_buf)
143162306a36Sopenharmony_ci		return;
143262306a36Sopenharmony_ci
143362306a36Sopenharmony_ci	mem_layout = ath10k_coredump_get_mem_layout(ar);
143462306a36Sopenharmony_ci	if (!mem_layout)
143562306a36Sopenharmony_ci		return;
143662306a36Sopenharmony_ci
143762306a36Sopenharmony_ci	current_region = &mem_layout->region_table.regions[0];
143862306a36Sopenharmony_ci
143962306a36Sopenharmony_ci	buf = crash_data->ramdump_buf;
144062306a36Sopenharmony_ci	buf_len = crash_data->ramdump_buf_len;
144162306a36Sopenharmony_ci	memset(buf, 0, buf_len);
144262306a36Sopenharmony_ci
144362306a36Sopenharmony_ci	/* Reserve space for the header. */
144462306a36Sopenharmony_ci	hdr = (void *)buf;
144562306a36Sopenharmony_ci	buf += sizeof(*hdr);
144662306a36Sopenharmony_ci	buf_len -= sizeof(*hdr);
144762306a36Sopenharmony_ci
144862306a36Sopenharmony_ci	hdr->region_type = cpu_to_le32(current_region->type);
144962306a36Sopenharmony_ci	hdr->start = cpu_to_le32((unsigned long)ar->msa.vaddr);
145062306a36Sopenharmony_ci	hdr->length = cpu_to_le32(ar->msa.mem_size);
145162306a36Sopenharmony_ci
145262306a36Sopenharmony_ci	if (current_region->len < ar->msa.mem_size) {
145362306a36Sopenharmony_ci		memcpy(buf, ar->msa.vaddr, current_region->len);
145462306a36Sopenharmony_ci		ath10k_warn(ar, "msa dump length is less than msa size %x, %x\n",
145562306a36Sopenharmony_ci			    current_region->len, ar->msa.mem_size);
145662306a36Sopenharmony_ci	} else {
145762306a36Sopenharmony_ci		memcpy(buf, ar->msa.vaddr, ar->msa.mem_size);
145862306a36Sopenharmony_ci	}
145962306a36Sopenharmony_ci}
146062306a36Sopenharmony_ci
146162306a36Sopenharmony_civoid ath10k_snoc_fw_crashed_dump(struct ath10k *ar)
146262306a36Sopenharmony_ci{
146362306a36Sopenharmony_ci	struct ath10k_fw_crash_data *crash_data;
146462306a36Sopenharmony_ci	char guid[UUID_STRING_LEN + 1];
146562306a36Sopenharmony_ci
146662306a36Sopenharmony_ci	mutex_lock(&ar->dump_mutex);
146762306a36Sopenharmony_ci
146862306a36Sopenharmony_ci	spin_lock_bh(&ar->data_lock);
146962306a36Sopenharmony_ci	ar->stats.fw_crash_counter++;
147062306a36Sopenharmony_ci	spin_unlock_bh(&ar->data_lock);
147162306a36Sopenharmony_ci
147262306a36Sopenharmony_ci	crash_data = ath10k_coredump_new(ar);
147362306a36Sopenharmony_ci
147462306a36Sopenharmony_ci	if (crash_data)
147562306a36Sopenharmony_ci		scnprintf(guid, sizeof(guid), "%pUl", &crash_data->guid);
147662306a36Sopenharmony_ci	else
147762306a36Sopenharmony_ci		scnprintf(guid, sizeof(guid), "n/a");
147862306a36Sopenharmony_ci
147962306a36Sopenharmony_ci	ath10k_err(ar, "firmware crashed! (guid %s)\n", guid);
148062306a36Sopenharmony_ci	ath10k_print_driver_info(ar);
148162306a36Sopenharmony_ci	ath10k_msa_dump_memory(ar, crash_data);
148262306a36Sopenharmony_ci	mutex_unlock(&ar->dump_mutex);
148362306a36Sopenharmony_ci}
148462306a36Sopenharmony_ci
148562306a36Sopenharmony_cistatic int ath10k_snoc_modem_notify(struct notifier_block *nb, unsigned long action,
148662306a36Sopenharmony_ci				    void *data)
148762306a36Sopenharmony_ci{
148862306a36Sopenharmony_ci	struct ath10k_snoc *ar_snoc = container_of(nb, struct ath10k_snoc, nb);
148962306a36Sopenharmony_ci	struct ath10k *ar = ar_snoc->ar;
149062306a36Sopenharmony_ci	struct qcom_ssr_notify_data *notify_data = data;
149162306a36Sopenharmony_ci
149262306a36Sopenharmony_ci	switch (action) {
149362306a36Sopenharmony_ci	case QCOM_SSR_BEFORE_POWERUP:
149462306a36Sopenharmony_ci		ath10k_dbg(ar, ATH10K_DBG_SNOC, "received modem starting event\n");
149562306a36Sopenharmony_ci		clear_bit(ATH10K_SNOC_FLAG_MODEM_STOPPED, &ar_snoc->flags);
149662306a36Sopenharmony_ci		break;
149762306a36Sopenharmony_ci
149862306a36Sopenharmony_ci	case QCOM_SSR_AFTER_POWERUP:
149962306a36Sopenharmony_ci		ath10k_dbg(ar, ATH10K_DBG_SNOC, "received modem running event\n");
150062306a36Sopenharmony_ci		break;
150162306a36Sopenharmony_ci
150262306a36Sopenharmony_ci	case QCOM_SSR_BEFORE_SHUTDOWN:
150362306a36Sopenharmony_ci		ath10k_dbg(ar, ATH10K_DBG_SNOC, "received modem %s event\n",
150462306a36Sopenharmony_ci			   notify_data->crashed ? "crashed" : "stopping");
150562306a36Sopenharmony_ci		if (!notify_data->crashed)
150662306a36Sopenharmony_ci			set_bit(ATH10K_SNOC_FLAG_MODEM_STOPPED, &ar_snoc->flags);
150762306a36Sopenharmony_ci		else
150862306a36Sopenharmony_ci			clear_bit(ATH10K_SNOC_FLAG_MODEM_STOPPED, &ar_snoc->flags);
150962306a36Sopenharmony_ci		break;
151062306a36Sopenharmony_ci
151162306a36Sopenharmony_ci	case QCOM_SSR_AFTER_SHUTDOWN:
151262306a36Sopenharmony_ci		ath10k_dbg(ar, ATH10K_DBG_SNOC, "received modem offline event\n");
151362306a36Sopenharmony_ci		break;
151462306a36Sopenharmony_ci
151562306a36Sopenharmony_ci	default:
151662306a36Sopenharmony_ci		ath10k_err(ar, "received unrecognized event %lu\n", action);
151762306a36Sopenharmony_ci		break;
151862306a36Sopenharmony_ci	}
151962306a36Sopenharmony_ci
152062306a36Sopenharmony_ci	return NOTIFY_OK;
152162306a36Sopenharmony_ci}
152262306a36Sopenharmony_ci
152362306a36Sopenharmony_cistatic int ath10k_modem_init(struct ath10k *ar)
152462306a36Sopenharmony_ci{
152562306a36Sopenharmony_ci	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
152662306a36Sopenharmony_ci	void *notifier;
152762306a36Sopenharmony_ci	int ret;
152862306a36Sopenharmony_ci
152962306a36Sopenharmony_ci	ar_snoc->nb.notifier_call = ath10k_snoc_modem_notify;
153062306a36Sopenharmony_ci
153162306a36Sopenharmony_ci	notifier = qcom_register_ssr_notifier("mpss", &ar_snoc->nb);
153262306a36Sopenharmony_ci	if (IS_ERR(notifier)) {
153362306a36Sopenharmony_ci		ret = PTR_ERR(notifier);
153462306a36Sopenharmony_ci		ath10k_err(ar, "failed to initialize modem notifier: %d\n", ret);
153562306a36Sopenharmony_ci		return ret;
153662306a36Sopenharmony_ci	}
153762306a36Sopenharmony_ci
153862306a36Sopenharmony_ci	ar_snoc->notifier = notifier;
153962306a36Sopenharmony_ci
154062306a36Sopenharmony_ci	return 0;
154162306a36Sopenharmony_ci}
154262306a36Sopenharmony_ci
154362306a36Sopenharmony_cistatic void ath10k_modem_deinit(struct ath10k *ar)
154462306a36Sopenharmony_ci{
154562306a36Sopenharmony_ci	int ret;
154662306a36Sopenharmony_ci	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
154762306a36Sopenharmony_ci
154862306a36Sopenharmony_ci	ret = qcom_unregister_ssr_notifier(ar_snoc->notifier, &ar_snoc->nb);
154962306a36Sopenharmony_ci	if (ret)
155062306a36Sopenharmony_ci		ath10k_err(ar, "error %d unregistering notifier\n", ret);
155162306a36Sopenharmony_ci}
155262306a36Sopenharmony_ci
155362306a36Sopenharmony_cistatic int ath10k_setup_msa_resources(struct ath10k *ar, u32 msa_size)
155462306a36Sopenharmony_ci{
155562306a36Sopenharmony_ci	struct device *dev = ar->dev;
155662306a36Sopenharmony_ci	struct device_node *node;
155762306a36Sopenharmony_ci	struct resource r;
155862306a36Sopenharmony_ci	int ret;
155962306a36Sopenharmony_ci
156062306a36Sopenharmony_ci	node = of_parse_phandle(dev->of_node, "memory-region", 0);
156162306a36Sopenharmony_ci	if (node) {
156262306a36Sopenharmony_ci		ret = of_address_to_resource(node, 0, &r);
156362306a36Sopenharmony_ci		of_node_put(node);
156462306a36Sopenharmony_ci		if (ret) {
156562306a36Sopenharmony_ci			dev_err(dev, "failed to resolve msa fixed region\n");
156662306a36Sopenharmony_ci			return ret;
156762306a36Sopenharmony_ci		}
156862306a36Sopenharmony_ci
156962306a36Sopenharmony_ci		ar->msa.paddr = r.start;
157062306a36Sopenharmony_ci		ar->msa.mem_size = resource_size(&r);
157162306a36Sopenharmony_ci		ar->msa.vaddr = devm_memremap(dev, ar->msa.paddr,
157262306a36Sopenharmony_ci					      ar->msa.mem_size,
157362306a36Sopenharmony_ci					      MEMREMAP_WT);
157462306a36Sopenharmony_ci		if (IS_ERR(ar->msa.vaddr)) {
157562306a36Sopenharmony_ci			dev_err(dev, "failed to map memory region: %pa\n",
157662306a36Sopenharmony_ci				&r.start);
157762306a36Sopenharmony_ci			return PTR_ERR(ar->msa.vaddr);
157862306a36Sopenharmony_ci		}
157962306a36Sopenharmony_ci	} else {
158062306a36Sopenharmony_ci		ar->msa.vaddr = dmam_alloc_coherent(dev, msa_size,
158162306a36Sopenharmony_ci						    &ar->msa.paddr,
158262306a36Sopenharmony_ci						    GFP_KERNEL);
158362306a36Sopenharmony_ci		if (!ar->msa.vaddr) {
158462306a36Sopenharmony_ci			ath10k_err(ar, "failed to allocate dma memory for msa region\n");
158562306a36Sopenharmony_ci			return -ENOMEM;
158662306a36Sopenharmony_ci		}
158762306a36Sopenharmony_ci		ar->msa.mem_size = msa_size;
158862306a36Sopenharmony_ci	}
158962306a36Sopenharmony_ci
159062306a36Sopenharmony_ci	ath10k_dbg(ar, ATH10K_DBG_QMI, "qmi msa.paddr: %pad , msa.vaddr: 0x%p\n",
159162306a36Sopenharmony_ci		   &ar->msa.paddr,
159262306a36Sopenharmony_ci		   ar->msa.vaddr);
159362306a36Sopenharmony_ci
159462306a36Sopenharmony_ci	return 0;
159562306a36Sopenharmony_ci}
159662306a36Sopenharmony_ci
159762306a36Sopenharmony_cistatic int ath10k_fw_init(struct ath10k *ar)
159862306a36Sopenharmony_ci{
159962306a36Sopenharmony_ci	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
160062306a36Sopenharmony_ci	struct device *host_dev = &ar_snoc->dev->dev;
160162306a36Sopenharmony_ci	struct platform_device_info info;
160262306a36Sopenharmony_ci	struct iommu_domain *iommu_dom;
160362306a36Sopenharmony_ci	struct platform_device *pdev;
160462306a36Sopenharmony_ci	struct device_node *node;
160562306a36Sopenharmony_ci	int ret;
160662306a36Sopenharmony_ci
160762306a36Sopenharmony_ci	node = of_get_child_by_name(host_dev->of_node, "wifi-firmware");
160862306a36Sopenharmony_ci	if (!node) {
160962306a36Sopenharmony_ci		ar_snoc->use_tz = true;
161062306a36Sopenharmony_ci		return 0;
161162306a36Sopenharmony_ci	}
161262306a36Sopenharmony_ci
161362306a36Sopenharmony_ci	memset(&info, 0, sizeof(info));
161462306a36Sopenharmony_ci	info.fwnode = &node->fwnode;
161562306a36Sopenharmony_ci	info.parent = host_dev;
161662306a36Sopenharmony_ci	info.name = node->name;
161762306a36Sopenharmony_ci	info.dma_mask = DMA_BIT_MASK(32);
161862306a36Sopenharmony_ci
161962306a36Sopenharmony_ci	pdev = platform_device_register_full(&info);
162062306a36Sopenharmony_ci	if (IS_ERR(pdev)) {
162162306a36Sopenharmony_ci		of_node_put(node);
162262306a36Sopenharmony_ci		return PTR_ERR(pdev);
162362306a36Sopenharmony_ci	}
162462306a36Sopenharmony_ci
162562306a36Sopenharmony_ci	pdev->dev.of_node = node;
162662306a36Sopenharmony_ci
162762306a36Sopenharmony_ci	ret = of_dma_configure(&pdev->dev, node, true);
162862306a36Sopenharmony_ci	if (ret) {
162962306a36Sopenharmony_ci		ath10k_err(ar, "dma configure fail: %d\n", ret);
163062306a36Sopenharmony_ci		goto err_unregister;
163162306a36Sopenharmony_ci	}
163262306a36Sopenharmony_ci
163362306a36Sopenharmony_ci	ar_snoc->fw.dev = &pdev->dev;
163462306a36Sopenharmony_ci
163562306a36Sopenharmony_ci	iommu_dom = iommu_domain_alloc(&platform_bus_type);
163662306a36Sopenharmony_ci	if (!iommu_dom) {
163762306a36Sopenharmony_ci		ath10k_err(ar, "failed to allocate iommu domain\n");
163862306a36Sopenharmony_ci		ret = -ENOMEM;
163962306a36Sopenharmony_ci		goto err_unregister;
164062306a36Sopenharmony_ci	}
164162306a36Sopenharmony_ci
164262306a36Sopenharmony_ci	ret = iommu_attach_device(iommu_dom, ar_snoc->fw.dev);
164362306a36Sopenharmony_ci	if (ret) {
164462306a36Sopenharmony_ci		ath10k_err(ar, "could not attach device: %d\n", ret);
164562306a36Sopenharmony_ci		goto err_iommu_free;
164662306a36Sopenharmony_ci	}
164762306a36Sopenharmony_ci
164862306a36Sopenharmony_ci	ar_snoc->fw.iommu_domain = iommu_dom;
164962306a36Sopenharmony_ci	ar_snoc->fw.fw_start_addr = ar->msa.paddr;
165062306a36Sopenharmony_ci
165162306a36Sopenharmony_ci	ret = iommu_map(iommu_dom, ar_snoc->fw.fw_start_addr,
165262306a36Sopenharmony_ci			ar->msa.paddr, ar->msa.mem_size,
165362306a36Sopenharmony_ci			IOMMU_READ | IOMMU_WRITE, GFP_KERNEL);
165462306a36Sopenharmony_ci	if (ret) {
165562306a36Sopenharmony_ci		ath10k_err(ar, "failed to map firmware region: %d\n", ret);
165662306a36Sopenharmony_ci		goto err_iommu_detach;
165762306a36Sopenharmony_ci	}
165862306a36Sopenharmony_ci
165962306a36Sopenharmony_ci	of_node_put(node);
166062306a36Sopenharmony_ci
166162306a36Sopenharmony_ci	return 0;
166262306a36Sopenharmony_ci
166362306a36Sopenharmony_cierr_iommu_detach:
166462306a36Sopenharmony_ci	iommu_detach_device(iommu_dom, ar_snoc->fw.dev);
166562306a36Sopenharmony_ci
166662306a36Sopenharmony_cierr_iommu_free:
166762306a36Sopenharmony_ci	iommu_domain_free(iommu_dom);
166862306a36Sopenharmony_ci
166962306a36Sopenharmony_cierr_unregister:
167062306a36Sopenharmony_ci	platform_device_unregister(pdev);
167162306a36Sopenharmony_ci	of_node_put(node);
167262306a36Sopenharmony_ci
167362306a36Sopenharmony_ci	return ret;
167462306a36Sopenharmony_ci}
167562306a36Sopenharmony_ci
167662306a36Sopenharmony_cistatic int ath10k_fw_deinit(struct ath10k *ar)
167762306a36Sopenharmony_ci{
167862306a36Sopenharmony_ci	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
167962306a36Sopenharmony_ci	const size_t mapped_size = ar_snoc->fw.mapped_mem_size;
168062306a36Sopenharmony_ci	struct iommu_domain *iommu;
168162306a36Sopenharmony_ci	size_t unmapped_size;
168262306a36Sopenharmony_ci
168362306a36Sopenharmony_ci	if (ar_snoc->use_tz)
168462306a36Sopenharmony_ci		return 0;
168562306a36Sopenharmony_ci
168662306a36Sopenharmony_ci	iommu = ar_snoc->fw.iommu_domain;
168762306a36Sopenharmony_ci
168862306a36Sopenharmony_ci	unmapped_size = iommu_unmap(iommu, ar_snoc->fw.fw_start_addr,
168962306a36Sopenharmony_ci				    mapped_size);
169062306a36Sopenharmony_ci	if (unmapped_size != mapped_size)
169162306a36Sopenharmony_ci		ath10k_err(ar, "failed to unmap firmware: %zu\n",
169262306a36Sopenharmony_ci			   unmapped_size);
169362306a36Sopenharmony_ci
169462306a36Sopenharmony_ci	iommu_detach_device(iommu, ar_snoc->fw.dev);
169562306a36Sopenharmony_ci	iommu_domain_free(iommu);
169662306a36Sopenharmony_ci
169762306a36Sopenharmony_ci	platform_device_unregister(to_platform_device(ar_snoc->fw.dev));
169862306a36Sopenharmony_ci
169962306a36Sopenharmony_ci	return 0;
170062306a36Sopenharmony_ci}
170162306a36Sopenharmony_ci
170262306a36Sopenharmony_cistatic const struct of_device_id ath10k_snoc_dt_match[] = {
170362306a36Sopenharmony_ci	{ .compatible = "qcom,wcn3990-wifi",
170462306a36Sopenharmony_ci	 .data = &drv_priv,
170562306a36Sopenharmony_ci	},
170662306a36Sopenharmony_ci	{ }
170762306a36Sopenharmony_ci};
170862306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, ath10k_snoc_dt_match);
170962306a36Sopenharmony_ci
171062306a36Sopenharmony_cistatic int ath10k_snoc_probe(struct platform_device *pdev)
171162306a36Sopenharmony_ci{
171262306a36Sopenharmony_ci	const struct ath10k_snoc_drv_priv *drv_data;
171362306a36Sopenharmony_ci	struct ath10k_snoc *ar_snoc;
171462306a36Sopenharmony_ci	struct device *dev;
171562306a36Sopenharmony_ci	struct ath10k *ar;
171662306a36Sopenharmony_ci	u32 msa_size;
171762306a36Sopenharmony_ci	int ret;
171862306a36Sopenharmony_ci	u32 i;
171962306a36Sopenharmony_ci
172062306a36Sopenharmony_ci	dev = &pdev->dev;
172162306a36Sopenharmony_ci	drv_data = device_get_match_data(dev);
172262306a36Sopenharmony_ci	if (!drv_data) {
172362306a36Sopenharmony_ci		dev_err(dev, "failed to find matching device tree id\n");
172462306a36Sopenharmony_ci		return -EINVAL;
172562306a36Sopenharmony_ci	}
172662306a36Sopenharmony_ci
172762306a36Sopenharmony_ci	ret = dma_set_mask_and_coherent(dev, drv_data->dma_mask);
172862306a36Sopenharmony_ci	if (ret) {
172962306a36Sopenharmony_ci		dev_err(dev, "failed to set dma mask: %d\n", ret);
173062306a36Sopenharmony_ci		return ret;
173162306a36Sopenharmony_ci	}
173262306a36Sopenharmony_ci
173362306a36Sopenharmony_ci	ar = ath10k_core_create(sizeof(*ar_snoc), dev, ATH10K_BUS_SNOC,
173462306a36Sopenharmony_ci				drv_data->hw_rev, &ath10k_snoc_hif_ops);
173562306a36Sopenharmony_ci	if (!ar) {
173662306a36Sopenharmony_ci		dev_err(dev, "failed to allocate core\n");
173762306a36Sopenharmony_ci		return -ENOMEM;
173862306a36Sopenharmony_ci	}
173962306a36Sopenharmony_ci
174062306a36Sopenharmony_ci	ar_snoc = ath10k_snoc_priv(ar);
174162306a36Sopenharmony_ci	ar_snoc->dev = pdev;
174262306a36Sopenharmony_ci	platform_set_drvdata(pdev, ar);
174362306a36Sopenharmony_ci	ar_snoc->ar = ar;
174462306a36Sopenharmony_ci	ar_snoc->ce.bus_ops = &ath10k_snoc_bus_ops;
174562306a36Sopenharmony_ci	ar->ce_priv = &ar_snoc->ce;
174662306a36Sopenharmony_ci	msa_size = drv_data->msa_size;
174762306a36Sopenharmony_ci
174862306a36Sopenharmony_ci	ath10k_snoc_quirks_init(ar);
174962306a36Sopenharmony_ci
175062306a36Sopenharmony_ci	ret = ath10k_snoc_resource_init(ar);
175162306a36Sopenharmony_ci	if (ret) {
175262306a36Sopenharmony_ci		ath10k_warn(ar, "failed to initialize resource: %d\n", ret);
175362306a36Sopenharmony_ci		goto err_core_destroy;
175462306a36Sopenharmony_ci	}
175562306a36Sopenharmony_ci
175662306a36Sopenharmony_ci	ret = ath10k_snoc_setup_resource(ar);
175762306a36Sopenharmony_ci	if (ret) {
175862306a36Sopenharmony_ci		ath10k_warn(ar, "failed to setup resource: %d\n", ret);
175962306a36Sopenharmony_ci		goto err_core_destroy;
176062306a36Sopenharmony_ci	}
176162306a36Sopenharmony_ci	ret = ath10k_snoc_request_irq(ar);
176262306a36Sopenharmony_ci	if (ret) {
176362306a36Sopenharmony_ci		ath10k_warn(ar, "failed to request irqs: %d\n", ret);
176462306a36Sopenharmony_ci		goto err_release_resource;
176562306a36Sopenharmony_ci	}
176662306a36Sopenharmony_ci
176762306a36Sopenharmony_ci	ar_snoc->num_vregs = ARRAY_SIZE(ath10k_regulators);
176862306a36Sopenharmony_ci	ar_snoc->vregs = devm_kcalloc(&pdev->dev, ar_snoc->num_vregs,
176962306a36Sopenharmony_ci				      sizeof(*ar_snoc->vregs), GFP_KERNEL);
177062306a36Sopenharmony_ci	if (!ar_snoc->vregs) {
177162306a36Sopenharmony_ci		ret = -ENOMEM;
177262306a36Sopenharmony_ci		goto err_free_irq;
177362306a36Sopenharmony_ci	}
177462306a36Sopenharmony_ci	for (i = 0; i < ar_snoc->num_vregs; i++)
177562306a36Sopenharmony_ci		ar_snoc->vregs[i].supply = ath10k_regulators[i];
177662306a36Sopenharmony_ci
177762306a36Sopenharmony_ci	ret = devm_regulator_bulk_get(&pdev->dev, ar_snoc->num_vregs,
177862306a36Sopenharmony_ci				      ar_snoc->vregs);
177962306a36Sopenharmony_ci	if (ret < 0)
178062306a36Sopenharmony_ci		goto err_free_irq;
178162306a36Sopenharmony_ci
178262306a36Sopenharmony_ci	ar_snoc->num_clks = ARRAY_SIZE(ath10k_clocks);
178362306a36Sopenharmony_ci	ar_snoc->clks = devm_kcalloc(&pdev->dev, ar_snoc->num_clks,
178462306a36Sopenharmony_ci				     sizeof(*ar_snoc->clks), GFP_KERNEL);
178562306a36Sopenharmony_ci	if (!ar_snoc->clks) {
178662306a36Sopenharmony_ci		ret = -ENOMEM;
178762306a36Sopenharmony_ci		goto err_free_irq;
178862306a36Sopenharmony_ci	}
178962306a36Sopenharmony_ci
179062306a36Sopenharmony_ci	for (i = 0; i < ar_snoc->num_clks; i++)
179162306a36Sopenharmony_ci		ar_snoc->clks[i].id = ath10k_clocks[i];
179262306a36Sopenharmony_ci
179362306a36Sopenharmony_ci	ret = devm_clk_bulk_get_optional(&pdev->dev, ar_snoc->num_clks,
179462306a36Sopenharmony_ci					 ar_snoc->clks);
179562306a36Sopenharmony_ci	if (ret)
179662306a36Sopenharmony_ci		goto err_free_irq;
179762306a36Sopenharmony_ci
179862306a36Sopenharmony_ci	ret = ath10k_setup_msa_resources(ar, msa_size);
179962306a36Sopenharmony_ci	if (ret) {
180062306a36Sopenharmony_ci		ath10k_warn(ar, "failed to setup msa resources: %d\n", ret);
180162306a36Sopenharmony_ci		goto err_free_irq;
180262306a36Sopenharmony_ci	}
180362306a36Sopenharmony_ci
180462306a36Sopenharmony_ci	ret = ath10k_fw_init(ar);
180562306a36Sopenharmony_ci	if (ret) {
180662306a36Sopenharmony_ci		ath10k_err(ar, "failed to initialize firmware: %d\n", ret);
180762306a36Sopenharmony_ci		goto err_free_irq;
180862306a36Sopenharmony_ci	}
180962306a36Sopenharmony_ci
181062306a36Sopenharmony_ci	ret = ath10k_qmi_init(ar, msa_size);
181162306a36Sopenharmony_ci	if (ret) {
181262306a36Sopenharmony_ci		ath10k_warn(ar, "failed to register wlfw qmi client: %d\n", ret);
181362306a36Sopenharmony_ci		goto err_fw_deinit;
181462306a36Sopenharmony_ci	}
181562306a36Sopenharmony_ci
181662306a36Sopenharmony_ci	ret = ath10k_modem_init(ar);
181762306a36Sopenharmony_ci	if (ret)
181862306a36Sopenharmony_ci		goto err_qmi_deinit;
181962306a36Sopenharmony_ci
182062306a36Sopenharmony_ci	ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc probe\n");
182162306a36Sopenharmony_ci
182262306a36Sopenharmony_ci	return 0;
182362306a36Sopenharmony_ci
182462306a36Sopenharmony_cierr_qmi_deinit:
182562306a36Sopenharmony_ci	ath10k_qmi_deinit(ar);
182662306a36Sopenharmony_ci
182762306a36Sopenharmony_cierr_fw_deinit:
182862306a36Sopenharmony_ci	ath10k_fw_deinit(ar);
182962306a36Sopenharmony_ci
183062306a36Sopenharmony_cierr_free_irq:
183162306a36Sopenharmony_ci	ath10k_snoc_free_irq(ar);
183262306a36Sopenharmony_ci
183362306a36Sopenharmony_cierr_release_resource:
183462306a36Sopenharmony_ci	ath10k_snoc_release_resource(ar);
183562306a36Sopenharmony_ci
183662306a36Sopenharmony_cierr_core_destroy:
183762306a36Sopenharmony_ci	ath10k_core_destroy(ar);
183862306a36Sopenharmony_ci
183962306a36Sopenharmony_ci	return ret;
184062306a36Sopenharmony_ci}
184162306a36Sopenharmony_ci
184262306a36Sopenharmony_cistatic int ath10k_snoc_free_resources(struct ath10k *ar)
184362306a36Sopenharmony_ci{
184462306a36Sopenharmony_ci	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
184562306a36Sopenharmony_ci
184662306a36Sopenharmony_ci	ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc free resources\n");
184762306a36Sopenharmony_ci
184862306a36Sopenharmony_ci	set_bit(ATH10K_SNOC_FLAG_UNREGISTERING, &ar_snoc->flags);
184962306a36Sopenharmony_ci
185062306a36Sopenharmony_ci	ath10k_core_unregister(ar);
185162306a36Sopenharmony_ci	ath10k_fw_deinit(ar);
185262306a36Sopenharmony_ci	ath10k_snoc_free_irq(ar);
185362306a36Sopenharmony_ci	ath10k_snoc_release_resource(ar);
185462306a36Sopenharmony_ci	ath10k_modem_deinit(ar);
185562306a36Sopenharmony_ci	ath10k_qmi_deinit(ar);
185662306a36Sopenharmony_ci	ath10k_core_destroy(ar);
185762306a36Sopenharmony_ci
185862306a36Sopenharmony_ci	return 0;
185962306a36Sopenharmony_ci}
186062306a36Sopenharmony_ci
186162306a36Sopenharmony_cistatic void ath10k_snoc_remove(struct platform_device *pdev)
186262306a36Sopenharmony_ci{
186362306a36Sopenharmony_ci	struct ath10k *ar = platform_get_drvdata(pdev);
186462306a36Sopenharmony_ci	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
186562306a36Sopenharmony_ci
186662306a36Sopenharmony_ci	ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc remove\n");
186762306a36Sopenharmony_ci
186862306a36Sopenharmony_ci	reinit_completion(&ar->driver_recovery);
186962306a36Sopenharmony_ci
187062306a36Sopenharmony_ci	if (test_bit(ATH10K_SNOC_FLAG_RECOVERY, &ar_snoc->flags))
187162306a36Sopenharmony_ci		wait_for_completion_timeout(&ar->driver_recovery, 3 * HZ);
187262306a36Sopenharmony_ci
187362306a36Sopenharmony_ci	ath10k_snoc_free_resources(ar);
187462306a36Sopenharmony_ci}
187562306a36Sopenharmony_ci
187662306a36Sopenharmony_cistatic void ath10k_snoc_shutdown(struct platform_device *pdev)
187762306a36Sopenharmony_ci{
187862306a36Sopenharmony_ci	struct ath10k *ar = platform_get_drvdata(pdev);
187962306a36Sopenharmony_ci
188062306a36Sopenharmony_ci	ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc shutdown\n");
188162306a36Sopenharmony_ci	ath10k_snoc_free_resources(ar);
188262306a36Sopenharmony_ci}
188362306a36Sopenharmony_ci
188462306a36Sopenharmony_cistatic struct platform_driver ath10k_snoc_driver = {
188562306a36Sopenharmony_ci	.probe  = ath10k_snoc_probe,
188662306a36Sopenharmony_ci	.remove_new = ath10k_snoc_remove,
188762306a36Sopenharmony_ci	.shutdown = ath10k_snoc_shutdown,
188862306a36Sopenharmony_ci	.driver = {
188962306a36Sopenharmony_ci		.name   = "ath10k_snoc",
189062306a36Sopenharmony_ci		.of_match_table = ath10k_snoc_dt_match,
189162306a36Sopenharmony_ci	},
189262306a36Sopenharmony_ci};
189362306a36Sopenharmony_cimodule_platform_driver(ath10k_snoc_driver);
189462306a36Sopenharmony_ci
189562306a36Sopenharmony_ciMODULE_AUTHOR("Qualcomm");
189662306a36Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL");
189762306a36Sopenharmony_ciMODULE_DESCRIPTION("Driver support for Atheros WCN3990 SNOC devices");
1898