18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: ISC
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (c) 2018 The Linux Foundation. All rights reserved.
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#include <linux/bits.h>
78c2ecf20Sopenharmony_ci#include <linux/clk.h>
88c2ecf20Sopenharmony_ci#include <linux/kernel.h>
98c2ecf20Sopenharmony_ci#include <linux/module.h>
108c2ecf20Sopenharmony_ci#include <linux/of.h>
118c2ecf20Sopenharmony_ci#include <linux/of_device.h>
128c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
138c2ecf20Sopenharmony_ci#include <linux/property.h>
148c2ecf20Sopenharmony_ci#include <linux/regulator/consumer.h>
158c2ecf20Sopenharmony_ci#include <linux/of_address.h>
168c2ecf20Sopenharmony_ci#include <linux/iommu.h>
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#include "ce.h"
198c2ecf20Sopenharmony_ci#include "coredump.h"
208c2ecf20Sopenharmony_ci#include "debug.h"
218c2ecf20Sopenharmony_ci#include "hif.h"
228c2ecf20Sopenharmony_ci#include "htc.h"
238c2ecf20Sopenharmony_ci#include "snoc.h"
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci#define ATH10K_SNOC_RX_POST_RETRY_MS 50
268c2ecf20Sopenharmony_ci#define CE_POLL_PIPE 4
278c2ecf20Sopenharmony_ci#define ATH10K_SNOC_WAKE_IRQ 2
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_cistatic char *const ce_name[] = {
308c2ecf20Sopenharmony_ci	"WLAN_CE_0",
318c2ecf20Sopenharmony_ci	"WLAN_CE_1",
328c2ecf20Sopenharmony_ci	"WLAN_CE_2",
338c2ecf20Sopenharmony_ci	"WLAN_CE_3",
348c2ecf20Sopenharmony_ci	"WLAN_CE_4",
358c2ecf20Sopenharmony_ci	"WLAN_CE_5",
368c2ecf20Sopenharmony_ci	"WLAN_CE_6",
378c2ecf20Sopenharmony_ci	"WLAN_CE_7",
388c2ecf20Sopenharmony_ci	"WLAN_CE_8",
398c2ecf20Sopenharmony_ci	"WLAN_CE_9",
408c2ecf20Sopenharmony_ci	"WLAN_CE_10",
418c2ecf20Sopenharmony_ci	"WLAN_CE_11",
428c2ecf20Sopenharmony_ci};
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_cistatic const char * const ath10k_regulators[] = {
458c2ecf20Sopenharmony_ci	"vdd-0.8-cx-mx",
468c2ecf20Sopenharmony_ci	"vdd-1.8-xo",
478c2ecf20Sopenharmony_ci	"vdd-1.3-rfa",
488c2ecf20Sopenharmony_ci	"vdd-3.3-ch0",
498c2ecf20Sopenharmony_ci	"vdd-3.3-ch1",
508c2ecf20Sopenharmony_ci};
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_cistatic const char * const ath10k_clocks[] = {
538c2ecf20Sopenharmony_ci	"cxo_ref_clk_pin", "qdss",
548c2ecf20Sopenharmony_ci};
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_cistatic void ath10k_snoc_htc_tx_cb(struct ath10k_ce_pipe *ce_state);
578c2ecf20Sopenharmony_cistatic void ath10k_snoc_htt_tx_cb(struct ath10k_ce_pipe *ce_state);
588c2ecf20Sopenharmony_cistatic void ath10k_snoc_htc_rx_cb(struct ath10k_ce_pipe *ce_state);
598c2ecf20Sopenharmony_cistatic void ath10k_snoc_htt_rx_cb(struct ath10k_ce_pipe *ce_state);
608c2ecf20Sopenharmony_cistatic void ath10k_snoc_htt_htc_rx_cb(struct ath10k_ce_pipe *ce_state);
618c2ecf20Sopenharmony_cistatic void ath10k_snoc_pktlog_rx_cb(struct ath10k_ce_pipe *ce_state);
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_cistatic const struct ath10k_snoc_drv_priv drv_priv = {
648c2ecf20Sopenharmony_ci	.hw_rev = ATH10K_HW_WCN3990,
658c2ecf20Sopenharmony_ci	.dma_mask = DMA_BIT_MASK(35),
668c2ecf20Sopenharmony_ci	.msa_size = 0x100000,
678c2ecf20Sopenharmony_ci};
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci#define WCN3990_SRC_WR_IDX_OFFSET 0x3C
708c2ecf20Sopenharmony_ci#define WCN3990_DST_WR_IDX_OFFSET 0x40
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_cistatic struct ath10k_shadow_reg_cfg target_shadow_reg_cfg_map[] = {
738c2ecf20Sopenharmony_ci		{
748c2ecf20Sopenharmony_ci			.ce_id = __cpu_to_le16(0),
758c2ecf20Sopenharmony_ci			.reg_offset = __cpu_to_le16(WCN3990_SRC_WR_IDX_OFFSET),
768c2ecf20Sopenharmony_ci		},
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci		{
798c2ecf20Sopenharmony_ci			.ce_id = __cpu_to_le16(3),
808c2ecf20Sopenharmony_ci			.reg_offset = __cpu_to_le16(WCN3990_SRC_WR_IDX_OFFSET),
818c2ecf20Sopenharmony_ci		},
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci		{
848c2ecf20Sopenharmony_ci			.ce_id = __cpu_to_le16(4),
858c2ecf20Sopenharmony_ci			.reg_offset = __cpu_to_le16(WCN3990_SRC_WR_IDX_OFFSET),
868c2ecf20Sopenharmony_ci		},
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci		{
898c2ecf20Sopenharmony_ci			.ce_id = __cpu_to_le16(5),
908c2ecf20Sopenharmony_ci			.reg_offset =  __cpu_to_le16(WCN3990_SRC_WR_IDX_OFFSET),
918c2ecf20Sopenharmony_ci		},
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci		{
948c2ecf20Sopenharmony_ci			.ce_id = __cpu_to_le16(7),
958c2ecf20Sopenharmony_ci			.reg_offset = __cpu_to_le16(WCN3990_SRC_WR_IDX_OFFSET),
968c2ecf20Sopenharmony_ci		},
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci		{
998c2ecf20Sopenharmony_ci			.ce_id = __cpu_to_le16(1),
1008c2ecf20Sopenharmony_ci			.reg_offset = __cpu_to_le16(WCN3990_DST_WR_IDX_OFFSET),
1018c2ecf20Sopenharmony_ci		},
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci		{
1048c2ecf20Sopenharmony_ci			.ce_id = __cpu_to_le16(2),
1058c2ecf20Sopenharmony_ci			.reg_offset =  __cpu_to_le16(WCN3990_DST_WR_IDX_OFFSET),
1068c2ecf20Sopenharmony_ci		},
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci		{
1098c2ecf20Sopenharmony_ci			.ce_id = __cpu_to_le16(7),
1108c2ecf20Sopenharmony_ci			.reg_offset =  __cpu_to_le16(WCN3990_DST_WR_IDX_OFFSET),
1118c2ecf20Sopenharmony_ci		},
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci		{
1148c2ecf20Sopenharmony_ci			.ce_id = __cpu_to_le16(8),
1158c2ecf20Sopenharmony_ci			.reg_offset =  __cpu_to_le16(WCN3990_DST_WR_IDX_OFFSET),
1168c2ecf20Sopenharmony_ci		},
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci		{
1198c2ecf20Sopenharmony_ci			.ce_id = __cpu_to_le16(9),
1208c2ecf20Sopenharmony_ci			.reg_offset = __cpu_to_le16(WCN3990_DST_WR_IDX_OFFSET),
1218c2ecf20Sopenharmony_ci		},
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci		{
1248c2ecf20Sopenharmony_ci			.ce_id = __cpu_to_le16(10),
1258c2ecf20Sopenharmony_ci			.reg_offset =  __cpu_to_le16(WCN3990_DST_WR_IDX_OFFSET),
1268c2ecf20Sopenharmony_ci		},
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci		{
1298c2ecf20Sopenharmony_ci			.ce_id = __cpu_to_le16(11),
1308c2ecf20Sopenharmony_ci			.reg_offset = __cpu_to_le16(WCN3990_DST_WR_IDX_OFFSET),
1318c2ecf20Sopenharmony_ci		},
1328c2ecf20Sopenharmony_ci};
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_cistatic struct ce_attr host_ce_config_wlan[] = {
1358c2ecf20Sopenharmony_ci	/* CE0: host->target HTC control streams */
1368c2ecf20Sopenharmony_ci	{
1378c2ecf20Sopenharmony_ci		.flags = CE_ATTR_FLAGS,
1388c2ecf20Sopenharmony_ci		.src_nentries = 16,
1398c2ecf20Sopenharmony_ci		.src_sz_max = 2048,
1408c2ecf20Sopenharmony_ci		.dest_nentries = 0,
1418c2ecf20Sopenharmony_ci		.send_cb = ath10k_snoc_htc_tx_cb,
1428c2ecf20Sopenharmony_ci	},
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci	/* CE1: target->host HTT + HTC control */
1458c2ecf20Sopenharmony_ci	{
1468c2ecf20Sopenharmony_ci		.flags = CE_ATTR_FLAGS,
1478c2ecf20Sopenharmony_ci		.src_nentries = 0,
1488c2ecf20Sopenharmony_ci		.src_sz_max = 2048,
1498c2ecf20Sopenharmony_ci		.dest_nentries = 512,
1508c2ecf20Sopenharmony_ci		.recv_cb = ath10k_snoc_htt_htc_rx_cb,
1518c2ecf20Sopenharmony_ci	},
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	/* CE2: target->host WMI */
1548c2ecf20Sopenharmony_ci	{
1558c2ecf20Sopenharmony_ci		.flags = CE_ATTR_FLAGS,
1568c2ecf20Sopenharmony_ci		.src_nentries = 0,
1578c2ecf20Sopenharmony_ci		.src_sz_max = 2048,
1588c2ecf20Sopenharmony_ci		.dest_nentries = 64,
1598c2ecf20Sopenharmony_ci		.recv_cb = ath10k_snoc_htc_rx_cb,
1608c2ecf20Sopenharmony_ci	},
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci	/* CE3: host->target WMI */
1638c2ecf20Sopenharmony_ci	{
1648c2ecf20Sopenharmony_ci		.flags = CE_ATTR_FLAGS,
1658c2ecf20Sopenharmony_ci		.src_nentries = 32,
1668c2ecf20Sopenharmony_ci		.src_sz_max = 2048,
1678c2ecf20Sopenharmony_ci		.dest_nentries = 0,
1688c2ecf20Sopenharmony_ci		.send_cb = ath10k_snoc_htc_tx_cb,
1698c2ecf20Sopenharmony_ci	},
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	/* CE4: host->target HTT */
1728c2ecf20Sopenharmony_ci	{
1738c2ecf20Sopenharmony_ci		.flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR,
1748c2ecf20Sopenharmony_ci		.src_nentries = 2048,
1758c2ecf20Sopenharmony_ci		.src_sz_max = 256,
1768c2ecf20Sopenharmony_ci		.dest_nentries = 0,
1778c2ecf20Sopenharmony_ci		.send_cb = ath10k_snoc_htt_tx_cb,
1788c2ecf20Sopenharmony_ci	},
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci	/* CE5: target->host HTT (ipa_uc->target ) */
1818c2ecf20Sopenharmony_ci	{
1828c2ecf20Sopenharmony_ci		.flags = CE_ATTR_FLAGS,
1838c2ecf20Sopenharmony_ci		.src_nentries = 0,
1848c2ecf20Sopenharmony_ci		.src_sz_max = 512,
1858c2ecf20Sopenharmony_ci		.dest_nentries = 512,
1868c2ecf20Sopenharmony_ci		.recv_cb = ath10k_snoc_htt_rx_cb,
1878c2ecf20Sopenharmony_ci	},
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci	/* CE6: target autonomous hif_memcpy */
1908c2ecf20Sopenharmony_ci	{
1918c2ecf20Sopenharmony_ci		.flags = CE_ATTR_FLAGS,
1928c2ecf20Sopenharmony_ci		.src_nentries = 0,
1938c2ecf20Sopenharmony_ci		.src_sz_max = 0,
1948c2ecf20Sopenharmony_ci		.dest_nentries = 0,
1958c2ecf20Sopenharmony_ci	},
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci	/* CE7: ce_diag, the Diagnostic Window */
1988c2ecf20Sopenharmony_ci	{
1998c2ecf20Sopenharmony_ci		.flags = CE_ATTR_FLAGS,
2008c2ecf20Sopenharmony_ci		.src_nentries = 2,
2018c2ecf20Sopenharmony_ci		.src_sz_max = 2048,
2028c2ecf20Sopenharmony_ci		.dest_nentries = 2,
2038c2ecf20Sopenharmony_ci	},
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci	/* CE8: Target to uMC */
2068c2ecf20Sopenharmony_ci	{
2078c2ecf20Sopenharmony_ci		.flags = CE_ATTR_FLAGS,
2088c2ecf20Sopenharmony_ci		.src_nentries = 0,
2098c2ecf20Sopenharmony_ci		.src_sz_max = 2048,
2108c2ecf20Sopenharmony_ci		.dest_nentries = 128,
2118c2ecf20Sopenharmony_ci	},
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci	/* CE9 target->host HTT */
2148c2ecf20Sopenharmony_ci	{
2158c2ecf20Sopenharmony_ci		.flags = CE_ATTR_FLAGS,
2168c2ecf20Sopenharmony_ci		.src_nentries = 0,
2178c2ecf20Sopenharmony_ci		.src_sz_max = 2048,
2188c2ecf20Sopenharmony_ci		.dest_nentries = 512,
2198c2ecf20Sopenharmony_ci		.recv_cb = ath10k_snoc_htt_htc_rx_cb,
2208c2ecf20Sopenharmony_ci	},
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci	/* CE10: target->host HTT */
2238c2ecf20Sopenharmony_ci	{
2248c2ecf20Sopenharmony_ci		.flags = CE_ATTR_FLAGS,
2258c2ecf20Sopenharmony_ci		.src_nentries = 0,
2268c2ecf20Sopenharmony_ci		.src_sz_max = 2048,
2278c2ecf20Sopenharmony_ci		.dest_nentries = 512,
2288c2ecf20Sopenharmony_ci		.recv_cb = ath10k_snoc_htt_htc_rx_cb,
2298c2ecf20Sopenharmony_ci	},
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci	/* CE11: target -> host PKTLOG */
2328c2ecf20Sopenharmony_ci	{
2338c2ecf20Sopenharmony_ci		.flags = CE_ATTR_FLAGS,
2348c2ecf20Sopenharmony_ci		.src_nentries = 0,
2358c2ecf20Sopenharmony_ci		.src_sz_max = 2048,
2368c2ecf20Sopenharmony_ci		.dest_nentries = 512,
2378c2ecf20Sopenharmony_ci		.recv_cb = ath10k_snoc_pktlog_rx_cb,
2388c2ecf20Sopenharmony_ci	},
2398c2ecf20Sopenharmony_ci};
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_cistatic struct ce_pipe_config target_ce_config_wlan[] = {
2428c2ecf20Sopenharmony_ci	/* CE0: host->target HTC control and raw streams */
2438c2ecf20Sopenharmony_ci	{
2448c2ecf20Sopenharmony_ci		.pipenum = __cpu_to_le32(0),
2458c2ecf20Sopenharmony_ci		.pipedir = __cpu_to_le32(PIPEDIR_OUT),
2468c2ecf20Sopenharmony_ci		.nentries = __cpu_to_le32(32),
2478c2ecf20Sopenharmony_ci		.nbytes_max = __cpu_to_le32(2048),
2488c2ecf20Sopenharmony_ci		.flags = __cpu_to_le32(CE_ATTR_FLAGS),
2498c2ecf20Sopenharmony_ci		.reserved = __cpu_to_le32(0),
2508c2ecf20Sopenharmony_ci	},
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci	/* CE1: target->host HTT + HTC control */
2538c2ecf20Sopenharmony_ci	{
2548c2ecf20Sopenharmony_ci		.pipenum = __cpu_to_le32(1),
2558c2ecf20Sopenharmony_ci		.pipedir = __cpu_to_le32(PIPEDIR_IN),
2568c2ecf20Sopenharmony_ci		.nentries = __cpu_to_le32(32),
2578c2ecf20Sopenharmony_ci		.nbytes_max = __cpu_to_le32(2048),
2588c2ecf20Sopenharmony_ci		.flags = __cpu_to_le32(CE_ATTR_FLAGS),
2598c2ecf20Sopenharmony_ci		.reserved = __cpu_to_le32(0),
2608c2ecf20Sopenharmony_ci	},
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci	/* CE2: target->host WMI */
2638c2ecf20Sopenharmony_ci	{
2648c2ecf20Sopenharmony_ci		.pipenum = __cpu_to_le32(2),
2658c2ecf20Sopenharmony_ci		.pipedir = __cpu_to_le32(PIPEDIR_IN),
2668c2ecf20Sopenharmony_ci		.nentries = __cpu_to_le32(64),
2678c2ecf20Sopenharmony_ci		.nbytes_max = __cpu_to_le32(2048),
2688c2ecf20Sopenharmony_ci		.flags = __cpu_to_le32(CE_ATTR_FLAGS),
2698c2ecf20Sopenharmony_ci		.reserved = __cpu_to_le32(0),
2708c2ecf20Sopenharmony_ci	},
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci	/* CE3: host->target WMI */
2738c2ecf20Sopenharmony_ci	{
2748c2ecf20Sopenharmony_ci		.pipenum = __cpu_to_le32(3),
2758c2ecf20Sopenharmony_ci		.pipedir = __cpu_to_le32(PIPEDIR_OUT),
2768c2ecf20Sopenharmony_ci		.nentries = __cpu_to_le32(32),
2778c2ecf20Sopenharmony_ci		.nbytes_max = __cpu_to_le32(2048),
2788c2ecf20Sopenharmony_ci		.flags = __cpu_to_le32(CE_ATTR_FLAGS),
2798c2ecf20Sopenharmony_ci		.reserved = __cpu_to_le32(0),
2808c2ecf20Sopenharmony_ci	},
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci	/* CE4: host->target HTT */
2838c2ecf20Sopenharmony_ci	{
2848c2ecf20Sopenharmony_ci		.pipenum = __cpu_to_le32(4),
2858c2ecf20Sopenharmony_ci		.pipedir = __cpu_to_le32(PIPEDIR_OUT),
2868c2ecf20Sopenharmony_ci		.nentries = __cpu_to_le32(256),
2878c2ecf20Sopenharmony_ci		.nbytes_max = __cpu_to_le32(256),
2888c2ecf20Sopenharmony_ci		.flags = __cpu_to_le32(CE_ATTR_FLAGS | CE_ATTR_DIS_INTR),
2898c2ecf20Sopenharmony_ci		.reserved = __cpu_to_le32(0),
2908c2ecf20Sopenharmony_ci	},
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci	/* CE5: target->host HTT (HIF->HTT) */
2938c2ecf20Sopenharmony_ci	{
2948c2ecf20Sopenharmony_ci		.pipenum = __cpu_to_le32(5),
2958c2ecf20Sopenharmony_ci		.pipedir = __cpu_to_le32(PIPEDIR_OUT),
2968c2ecf20Sopenharmony_ci		.nentries = __cpu_to_le32(1024),
2978c2ecf20Sopenharmony_ci		.nbytes_max = __cpu_to_le32(64),
2988c2ecf20Sopenharmony_ci		.flags = __cpu_to_le32(CE_ATTR_FLAGS | CE_ATTR_DIS_INTR),
2998c2ecf20Sopenharmony_ci		.reserved = __cpu_to_le32(0),
3008c2ecf20Sopenharmony_ci	},
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ci	/* CE6: Reserved for target autonomous hif_memcpy */
3038c2ecf20Sopenharmony_ci	{
3048c2ecf20Sopenharmony_ci		.pipenum = __cpu_to_le32(6),
3058c2ecf20Sopenharmony_ci		.pipedir = __cpu_to_le32(PIPEDIR_INOUT),
3068c2ecf20Sopenharmony_ci		.nentries = __cpu_to_le32(32),
3078c2ecf20Sopenharmony_ci		.nbytes_max = __cpu_to_le32(16384),
3088c2ecf20Sopenharmony_ci		.flags = __cpu_to_le32(CE_ATTR_FLAGS),
3098c2ecf20Sopenharmony_ci		.reserved = __cpu_to_le32(0),
3108c2ecf20Sopenharmony_ci	},
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	/* CE7 used only by Host */
3138c2ecf20Sopenharmony_ci	{
3148c2ecf20Sopenharmony_ci		.pipenum = __cpu_to_le32(7),
3158c2ecf20Sopenharmony_ci		.pipedir = __cpu_to_le32(4),
3168c2ecf20Sopenharmony_ci		.nentries = __cpu_to_le32(0),
3178c2ecf20Sopenharmony_ci		.nbytes_max = __cpu_to_le32(0),
3188c2ecf20Sopenharmony_ci		.flags = __cpu_to_le32(CE_ATTR_FLAGS | CE_ATTR_DIS_INTR),
3198c2ecf20Sopenharmony_ci		.reserved = __cpu_to_le32(0),
3208c2ecf20Sopenharmony_ci	},
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	/* CE8 Target to uMC */
3238c2ecf20Sopenharmony_ci	{
3248c2ecf20Sopenharmony_ci		.pipenum = __cpu_to_le32(8),
3258c2ecf20Sopenharmony_ci		.pipedir = __cpu_to_le32(PIPEDIR_IN),
3268c2ecf20Sopenharmony_ci		.nentries = __cpu_to_le32(32),
3278c2ecf20Sopenharmony_ci		.nbytes_max = __cpu_to_le32(2048),
3288c2ecf20Sopenharmony_ci		.flags = __cpu_to_le32(0),
3298c2ecf20Sopenharmony_ci		.reserved = __cpu_to_le32(0),
3308c2ecf20Sopenharmony_ci	},
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_ci	/* CE9 target->host HTT */
3338c2ecf20Sopenharmony_ci	{
3348c2ecf20Sopenharmony_ci		.pipenum = __cpu_to_le32(9),
3358c2ecf20Sopenharmony_ci		.pipedir = __cpu_to_le32(PIPEDIR_IN),
3368c2ecf20Sopenharmony_ci		.nentries = __cpu_to_le32(32),
3378c2ecf20Sopenharmony_ci		.nbytes_max = __cpu_to_le32(2048),
3388c2ecf20Sopenharmony_ci		.flags = __cpu_to_le32(CE_ATTR_FLAGS),
3398c2ecf20Sopenharmony_ci		.reserved = __cpu_to_le32(0),
3408c2ecf20Sopenharmony_ci	},
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci	/* CE10 target->host HTT */
3438c2ecf20Sopenharmony_ci	{
3448c2ecf20Sopenharmony_ci		.pipenum = __cpu_to_le32(10),
3458c2ecf20Sopenharmony_ci		.pipedir = __cpu_to_le32(PIPEDIR_IN),
3468c2ecf20Sopenharmony_ci		.nentries = __cpu_to_le32(32),
3478c2ecf20Sopenharmony_ci		.nbytes_max = __cpu_to_le32(2048),
3488c2ecf20Sopenharmony_ci		.flags = __cpu_to_le32(CE_ATTR_FLAGS),
3498c2ecf20Sopenharmony_ci		.reserved = __cpu_to_le32(0),
3508c2ecf20Sopenharmony_ci	},
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	/* CE11 target autonomous qcache memcpy */
3538c2ecf20Sopenharmony_ci	{
3548c2ecf20Sopenharmony_ci		.pipenum = __cpu_to_le32(11),
3558c2ecf20Sopenharmony_ci		.pipedir = __cpu_to_le32(PIPEDIR_IN),
3568c2ecf20Sopenharmony_ci		.nentries = __cpu_to_le32(32),
3578c2ecf20Sopenharmony_ci		.nbytes_max = __cpu_to_le32(2048),
3588c2ecf20Sopenharmony_ci		.flags = __cpu_to_le32(CE_ATTR_FLAGS),
3598c2ecf20Sopenharmony_ci		.reserved = __cpu_to_le32(0),
3608c2ecf20Sopenharmony_ci	},
3618c2ecf20Sopenharmony_ci};
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_cistatic struct ce_service_to_pipe target_service_to_ce_map_wlan[] = {
3648c2ecf20Sopenharmony_ci	{
3658c2ecf20Sopenharmony_ci		__cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_VO),
3668c2ecf20Sopenharmony_ci		__cpu_to_le32(PIPEDIR_OUT),	/* out = UL = host -> target */
3678c2ecf20Sopenharmony_ci		__cpu_to_le32(3),
3688c2ecf20Sopenharmony_ci	},
3698c2ecf20Sopenharmony_ci	{
3708c2ecf20Sopenharmony_ci		__cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_VO),
3718c2ecf20Sopenharmony_ci		__cpu_to_le32(PIPEDIR_IN),	/* in = DL = target -> host */
3728c2ecf20Sopenharmony_ci		__cpu_to_le32(2),
3738c2ecf20Sopenharmony_ci	},
3748c2ecf20Sopenharmony_ci	{
3758c2ecf20Sopenharmony_ci		__cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_BK),
3768c2ecf20Sopenharmony_ci		__cpu_to_le32(PIPEDIR_OUT),	/* out = UL = host -> target */
3778c2ecf20Sopenharmony_ci		__cpu_to_le32(3),
3788c2ecf20Sopenharmony_ci	},
3798c2ecf20Sopenharmony_ci	{
3808c2ecf20Sopenharmony_ci		__cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_BK),
3818c2ecf20Sopenharmony_ci		__cpu_to_le32(PIPEDIR_IN),	/* in = DL = target -> host */
3828c2ecf20Sopenharmony_ci		__cpu_to_le32(2),
3838c2ecf20Sopenharmony_ci	},
3848c2ecf20Sopenharmony_ci	{
3858c2ecf20Sopenharmony_ci		__cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_BE),
3868c2ecf20Sopenharmony_ci		__cpu_to_le32(PIPEDIR_OUT),	/* out = UL = host -> target */
3878c2ecf20Sopenharmony_ci		__cpu_to_le32(3),
3888c2ecf20Sopenharmony_ci	},
3898c2ecf20Sopenharmony_ci	{
3908c2ecf20Sopenharmony_ci		__cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_BE),
3918c2ecf20Sopenharmony_ci		__cpu_to_le32(PIPEDIR_IN),	/* in = DL = target -> host */
3928c2ecf20Sopenharmony_ci		__cpu_to_le32(2),
3938c2ecf20Sopenharmony_ci	},
3948c2ecf20Sopenharmony_ci	{
3958c2ecf20Sopenharmony_ci		__cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_VI),
3968c2ecf20Sopenharmony_ci		__cpu_to_le32(PIPEDIR_OUT),	/* out = UL = host -> target */
3978c2ecf20Sopenharmony_ci		__cpu_to_le32(3),
3988c2ecf20Sopenharmony_ci	},
3998c2ecf20Sopenharmony_ci	{
4008c2ecf20Sopenharmony_ci		__cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_VI),
4018c2ecf20Sopenharmony_ci		__cpu_to_le32(PIPEDIR_IN),	/* in = DL = target -> host */
4028c2ecf20Sopenharmony_ci		__cpu_to_le32(2),
4038c2ecf20Sopenharmony_ci	},
4048c2ecf20Sopenharmony_ci	{
4058c2ecf20Sopenharmony_ci		__cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_CONTROL),
4068c2ecf20Sopenharmony_ci		__cpu_to_le32(PIPEDIR_OUT),	/* out = UL = host -> target */
4078c2ecf20Sopenharmony_ci		__cpu_to_le32(3),
4088c2ecf20Sopenharmony_ci	},
4098c2ecf20Sopenharmony_ci	{
4108c2ecf20Sopenharmony_ci		__cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_CONTROL),
4118c2ecf20Sopenharmony_ci		__cpu_to_le32(PIPEDIR_IN),	/* in = DL = target -> host */
4128c2ecf20Sopenharmony_ci		__cpu_to_le32(2),
4138c2ecf20Sopenharmony_ci	},
4148c2ecf20Sopenharmony_ci	{
4158c2ecf20Sopenharmony_ci		__cpu_to_le32(ATH10K_HTC_SVC_ID_RSVD_CTRL),
4168c2ecf20Sopenharmony_ci		__cpu_to_le32(PIPEDIR_OUT),	/* out = UL = host -> target */
4178c2ecf20Sopenharmony_ci		__cpu_to_le32(0),
4188c2ecf20Sopenharmony_ci	},
4198c2ecf20Sopenharmony_ci	{
4208c2ecf20Sopenharmony_ci		__cpu_to_le32(ATH10K_HTC_SVC_ID_RSVD_CTRL),
4218c2ecf20Sopenharmony_ci		__cpu_to_le32(PIPEDIR_IN),	/* in = DL = target -> host */
4228c2ecf20Sopenharmony_ci		__cpu_to_le32(2),
4238c2ecf20Sopenharmony_ci	},
4248c2ecf20Sopenharmony_ci	{ /* not used */
4258c2ecf20Sopenharmony_ci		__cpu_to_le32(ATH10K_HTC_SVC_ID_TEST_RAW_STREAMS),
4268c2ecf20Sopenharmony_ci		__cpu_to_le32(PIPEDIR_OUT),	/* out = UL = host -> target */
4278c2ecf20Sopenharmony_ci		__cpu_to_le32(0),
4288c2ecf20Sopenharmony_ci	},
4298c2ecf20Sopenharmony_ci	{ /* not used */
4308c2ecf20Sopenharmony_ci		__cpu_to_le32(ATH10K_HTC_SVC_ID_TEST_RAW_STREAMS),
4318c2ecf20Sopenharmony_ci		__cpu_to_le32(PIPEDIR_IN),	/* in = DL = target -> host */
4328c2ecf20Sopenharmony_ci		__cpu_to_le32(2),
4338c2ecf20Sopenharmony_ci	},
4348c2ecf20Sopenharmony_ci	{
4358c2ecf20Sopenharmony_ci		__cpu_to_le32(ATH10K_HTC_SVC_ID_HTT_DATA_MSG),
4368c2ecf20Sopenharmony_ci		__cpu_to_le32(PIPEDIR_OUT),	/* out = UL = host -> target */
4378c2ecf20Sopenharmony_ci		__cpu_to_le32(4),
4388c2ecf20Sopenharmony_ci	},
4398c2ecf20Sopenharmony_ci	{
4408c2ecf20Sopenharmony_ci		__cpu_to_le32(ATH10K_HTC_SVC_ID_HTT_DATA_MSG),
4418c2ecf20Sopenharmony_ci		__cpu_to_le32(PIPEDIR_IN),	/* in = DL = target -> host */
4428c2ecf20Sopenharmony_ci		__cpu_to_le32(1),
4438c2ecf20Sopenharmony_ci	},
4448c2ecf20Sopenharmony_ci	{ /* not used */
4458c2ecf20Sopenharmony_ci		__cpu_to_le32(ATH10K_HTC_SVC_ID_TEST_RAW_STREAMS),
4468c2ecf20Sopenharmony_ci		__cpu_to_le32(PIPEDIR_OUT),
4478c2ecf20Sopenharmony_ci		__cpu_to_le32(5),
4488c2ecf20Sopenharmony_ci	},
4498c2ecf20Sopenharmony_ci	{ /* in = DL = target -> host */
4508c2ecf20Sopenharmony_ci		__cpu_to_le32(ATH10K_HTC_SVC_ID_HTT_DATA2_MSG),
4518c2ecf20Sopenharmony_ci		__cpu_to_le32(PIPEDIR_IN),	/* in = DL = target -> host */
4528c2ecf20Sopenharmony_ci		__cpu_to_le32(9),
4538c2ecf20Sopenharmony_ci	},
4548c2ecf20Sopenharmony_ci	{ /* in = DL = target -> host */
4558c2ecf20Sopenharmony_ci		__cpu_to_le32(ATH10K_HTC_SVC_ID_HTT_DATA3_MSG),
4568c2ecf20Sopenharmony_ci		__cpu_to_le32(PIPEDIR_IN),	/* in = DL = target -> host */
4578c2ecf20Sopenharmony_ci		__cpu_to_le32(10),
4588c2ecf20Sopenharmony_ci	},
4598c2ecf20Sopenharmony_ci	{ /* in = DL = target -> host pktlog */
4608c2ecf20Sopenharmony_ci		__cpu_to_le32(ATH10K_HTC_SVC_ID_HTT_LOG_MSG),
4618c2ecf20Sopenharmony_ci		__cpu_to_le32(PIPEDIR_IN),	/* in = DL = target -> host */
4628c2ecf20Sopenharmony_ci		__cpu_to_le32(11),
4638c2ecf20Sopenharmony_ci	},
4648c2ecf20Sopenharmony_ci	/* (Additions here) */
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci	{ /* must be last */
4678c2ecf20Sopenharmony_ci		__cpu_to_le32(0),
4688c2ecf20Sopenharmony_ci		__cpu_to_le32(0),
4698c2ecf20Sopenharmony_ci		__cpu_to_le32(0),
4708c2ecf20Sopenharmony_ci	},
4718c2ecf20Sopenharmony_ci};
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_cistatic void ath10k_snoc_write32(struct ath10k *ar, u32 offset, u32 value)
4748c2ecf20Sopenharmony_ci{
4758c2ecf20Sopenharmony_ci	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_ci	iowrite32(value, ar_snoc->mem + offset);
4788c2ecf20Sopenharmony_ci}
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_cistatic u32 ath10k_snoc_read32(struct ath10k *ar, u32 offset)
4818c2ecf20Sopenharmony_ci{
4828c2ecf20Sopenharmony_ci	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
4838c2ecf20Sopenharmony_ci	u32 val;
4848c2ecf20Sopenharmony_ci
4858c2ecf20Sopenharmony_ci	val = ioread32(ar_snoc->mem + offset);
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_ci	return val;
4888c2ecf20Sopenharmony_ci}
4898c2ecf20Sopenharmony_ci
4908c2ecf20Sopenharmony_cistatic int __ath10k_snoc_rx_post_buf(struct ath10k_snoc_pipe *pipe)
4918c2ecf20Sopenharmony_ci{
4928c2ecf20Sopenharmony_ci	struct ath10k_ce_pipe *ce_pipe = pipe->ce_hdl;
4938c2ecf20Sopenharmony_ci	struct ath10k *ar = pipe->hif_ce_state;
4948c2ecf20Sopenharmony_ci	struct ath10k_ce *ce = ath10k_ce_priv(ar);
4958c2ecf20Sopenharmony_ci	struct sk_buff *skb;
4968c2ecf20Sopenharmony_ci	dma_addr_t paddr;
4978c2ecf20Sopenharmony_ci	int ret;
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_ci	skb = dev_alloc_skb(pipe->buf_sz);
5008c2ecf20Sopenharmony_ci	if (!skb)
5018c2ecf20Sopenharmony_ci		return -ENOMEM;
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_ci	WARN_ONCE((unsigned long)skb->data & 3, "unaligned skb");
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_ci	paddr = dma_map_single(ar->dev, skb->data,
5068c2ecf20Sopenharmony_ci			       skb->len + skb_tailroom(skb),
5078c2ecf20Sopenharmony_ci			       DMA_FROM_DEVICE);
5088c2ecf20Sopenharmony_ci	if (unlikely(dma_mapping_error(ar->dev, paddr))) {
5098c2ecf20Sopenharmony_ci		ath10k_warn(ar, "failed to dma map snoc rx buf\n");
5108c2ecf20Sopenharmony_ci		dev_kfree_skb_any(skb);
5118c2ecf20Sopenharmony_ci		return -EIO;
5128c2ecf20Sopenharmony_ci	}
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_ci	ATH10K_SKB_RXCB(skb)->paddr = paddr;
5158c2ecf20Sopenharmony_ci
5168c2ecf20Sopenharmony_ci	spin_lock_bh(&ce->ce_lock);
5178c2ecf20Sopenharmony_ci	ret = ce_pipe->ops->ce_rx_post_buf(ce_pipe, skb, paddr);
5188c2ecf20Sopenharmony_ci	spin_unlock_bh(&ce->ce_lock);
5198c2ecf20Sopenharmony_ci	if (ret) {
5208c2ecf20Sopenharmony_ci		dma_unmap_single(ar->dev, paddr, skb->len + skb_tailroom(skb),
5218c2ecf20Sopenharmony_ci				 DMA_FROM_DEVICE);
5228c2ecf20Sopenharmony_ci		dev_kfree_skb_any(skb);
5238c2ecf20Sopenharmony_ci		return ret;
5248c2ecf20Sopenharmony_ci	}
5258c2ecf20Sopenharmony_ci
5268c2ecf20Sopenharmony_ci	return 0;
5278c2ecf20Sopenharmony_ci}
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_cistatic void ath10k_snoc_rx_post_pipe(struct ath10k_snoc_pipe *pipe)
5308c2ecf20Sopenharmony_ci{
5318c2ecf20Sopenharmony_ci	struct ath10k *ar = pipe->hif_ce_state;
5328c2ecf20Sopenharmony_ci	struct ath10k_ce *ce = ath10k_ce_priv(ar);
5338c2ecf20Sopenharmony_ci	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
5348c2ecf20Sopenharmony_ci	struct ath10k_ce_pipe *ce_pipe = pipe->ce_hdl;
5358c2ecf20Sopenharmony_ci	int ret, num;
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_ci	if (pipe->buf_sz == 0)
5388c2ecf20Sopenharmony_ci		return;
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_ci	if (!ce_pipe->dest_ring)
5418c2ecf20Sopenharmony_ci		return;
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ci	spin_lock_bh(&ce->ce_lock);
5448c2ecf20Sopenharmony_ci	num = __ath10k_ce_rx_num_free_bufs(ce_pipe);
5458c2ecf20Sopenharmony_ci	spin_unlock_bh(&ce->ce_lock);
5468c2ecf20Sopenharmony_ci	while (num--) {
5478c2ecf20Sopenharmony_ci		ret = __ath10k_snoc_rx_post_buf(pipe);
5488c2ecf20Sopenharmony_ci		if (ret) {
5498c2ecf20Sopenharmony_ci			if (ret == -ENOSPC)
5508c2ecf20Sopenharmony_ci				break;
5518c2ecf20Sopenharmony_ci			ath10k_warn(ar, "failed to post rx buf: %d\n", ret);
5528c2ecf20Sopenharmony_ci			mod_timer(&ar_snoc->rx_post_retry, jiffies +
5538c2ecf20Sopenharmony_ci				  ATH10K_SNOC_RX_POST_RETRY_MS);
5548c2ecf20Sopenharmony_ci			break;
5558c2ecf20Sopenharmony_ci		}
5568c2ecf20Sopenharmony_ci	}
5578c2ecf20Sopenharmony_ci}
5588c2ecf20Sopenharmony_ci
5598c2ecf20Sopenharmony_cistatic void ath10k_snoc_rx_post(struct ath10k *ar)
5608c2ecf20Sopenharmony_ci{
5618c2ecf20Sopenharmony_ci	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
5628c2ecf20Sopenharmony_ci	int i;
5638c2ecf20Sopenharmony_ci
5648c2ecf20Sopenharmony_ci	for (i = 0; i < CE_COUNT; i++)
5658c2ecf20Sopenharmony_ci		ath10k_snoc_rx_post_pipe(&ar_snoc->pipe_info[i]);
5668c2ecf20Sopenharmony_ci}
5678c2ecf20Sopenharmony_ci
5688c2ecf20Sopenharmony_cistatic void ath10k_snoc_process_rx_cb(struct ath10k_ce_pipe *ce_state,
5698c2ecf20Sopenharmony_ci				      void (*callback)(struct ath10k *ar,
5708c2ecf20Sopenharmony_ci						       struct sk_buff *skb))
5718c2ecf20Sopenharmony_ci{
5728c2ecf20Sopenharmony_ci	struct ath10k *ar = ce_state->ar;
5738c2ecf20Sopenharmony_ci	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
5748c2ecf20Sopenharmony_ci	struct ath10k_snoc_pipe *pipe_info =  &ar_snoc->pipe_info[ce_state->id];
5758c2ecf20Sopenharmony_ci	struct sk_buff *skb;
5768c2ecf20Sopenharmony_ci	struct sk_buff_head list;
5778c2ecf20Sopenharmony_ci	void *transfer_context;
5788c2ecf20Sopenharmony_ci	unsigned int nbytes, max_nbytes;
5798c2ecf20Sopenharmony_ci
5808c2ecf20Sopenharmony_ci	__skb_queue_head_init(&list);
5818c2ecf20Sopenharmony_ci	while (ath10k_ce_completed_recv_next(ce_state, &transfer_context,
5828c2ecf20Sopenharmony_ci					     &nbytes) == 0) {
5838c2ecf20Sopenharmony_ci		skb = transfer_context;
5848c2ecf20Sopenharmony_ci		max_nbytes = skb->len + skb_tailroom(skb);
5858c2ecf20Sopenharmony_ci		dma_unmap_single(ar->dev, ATH10K_SKB_RXCB(skb)->paddr,
5868c2ecf20Sopenharmony_ci				 max_nbytes, DMA_FROM_DEVICE);
5878c2ecf20Sopenharmony_ci
5888c2ecf20Sopenharmony_ci		if (unlikely(max_nbytes < nbytes)) {
5898c2ecf20Sopenharmony_ci			ath10k_warn(ar, "rxed more than expected (nbytes %d, max %d)\n",
5908c2ecf20Sopenharmony_ci				    nbytes, max_nbytes);
5918c2ecf20Sopenharmony_ci			dev_kfree_skb_any(skb);
5928c2ecf20Sopenharmony_ci			continue;
5938c2ecf20Sopenharmony_ci		}
5948c2ecf20Sopenharmony_ci
5958c2ecf20Sopenharmony_ci		skb_put(skb, nbytes);
5968c2ecf20Sopenharmony_ci		__skb_queue_tail(&list, skb);
5978c2ecf20Sopenharmony_ci	}
5988c2ecf20Sopenharmony_ci
5998c2ecf20Sopenharmony_ci	while ((skb = __skb_dequeue(&list))) {
6008c2ecf20Sopenharmony_ci		ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc rx ce pipe %d len %d\n",
6018c2ecf20Sopenharmony_ci			   ce_state->id, skb->len);
6028c2ecf20Sopenharmony_ci
6038c2ecf20Sopenharmony_ci		callback(ar, skb);
6048c2ecf20Sopenharmony_ci	}
6058c2ecf20Sopenharmony_ci
6068c2ecf20Sopenharmony_ci	ath10k_snoc_rx_post_pipe(pipe_info);
6078c2ecf20Sopenharmony_ci}
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_cistatic void ath10k_snoc_htc_rx_cb(struct ath10k_ce_pipe *ce_state)
6108c2ecf20Sopenharmony_ci{
6118c2ecf20Sopenharmony_ci	ath10k_snoc_process_rx_cb(ce_state, ath10k_htc_rx_completion_handler);
6128c2ecf20Sopenharmony_ci}
6138c2ecf20Sopenharmony_ci
6148c2ecf20Sopenharmony_cistatic void ath10k_snoc_htt_htc_rx_cb(struct ath10k_ce_pipe *ce_state)
6158c2ecf20Sopenharmony_ci{
6168c2ecf20Sopenharmony_ci	/* CE4 polling needs to be done whenever CE pipe which transports
6178c2ecf20Sopenharmony_ci	 * HTT Rx (target->host) is processed.
6188c2ecf20Sopenharmony_ci	 */
6198c2ecf20Sopenharmony_ci	ath10k_ce_per_engine_service(ce_state->ar, CE_POLL_PIPE);
6208c2ecf20Sopenharmony_ci
6218c2ecf20Sopenharmony_ci	ath10k_snoc_process_rx_cb(ce_state, ath10k_htc_rx_completion_handler);
6228c2ecf20Sopenharmony_ci}
6238c2ecf20Sopenharmony_ci
6248c2ecf20Sopenharmony_ci/* Called by lower (CE) layer when data is received from the Target.
6258c2ecf20Sopenharmony_ci * WCN3990 firmware uses separate CE(CE11) to transfer pktlog data.
6268c2ecf20Sopenharmony_ci */
6278c2ecf20Sopenharmony_cistatic void ath10k_snoc_pktlog_rx_cb(struct ath10k_ce_pipe *ce_state)
6288c2ecf20Sopenharmony_ci{
6298c2ecf20Sopenharmony_ci	ath10k_snoc_process_rx_cb(ce_state, ath10k_htc_rx_completion_handler);
6308c2ecf20Sopenharmony_ci}
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_cistatic void ath10k_snoc_htt_rx_deliver(struct ath10k *ar, struct sk_buff *skb)
6338c2ecf20Sopenharmony_ci{
6348c2ecf20Sopenharmony_ci	skb_pull(skb, sizeof(struct ath10k_htc_hdr));
6358c2ecf20Sopenharmony_ci	ath10k_htt_t2h_msg_handler(ar, skb);
6368c2ecf20Sopenharmony_ci}
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_cistatic void ath10k_snoc_htt_rx_cb(struct ath10k_ce_pipe *ce_state)
6398c2ecf20Sopenharmony_ci{
6408c2ecf20Sopenharmony_ci	ath10k_ce_per_engine_service(ce_state->ar, CE_POLL_PIPE);
6418c2ecf20Sopenharmony_ci	ath10k_snoc_process_rx_cb(ce_state, ath10k_snoc_htt_rx_deliver);
6428c2ecf20Sopenharmony_ci}
6438c2ecf20Sopenharmony_ci
6448c2ecf20Sopenharmony_cistatic void ath10k_snoc_rx_replenish_retry(struct timer_list *t)
6458c2ecf20Sopenharmony_ci{
6468c2ecf20Sopenharmony_ci	struct ath10k_snoc *ar_snoc = from_timer(ar_snoc, t, rx_post_retry);
6478c2ecf20Sopenharmony_ci	struct ath10k *ar = ar_snoc->ar;
6488c2ecf20Sopenharmony_ci
6498c2ecf20Sopenharmony_ci	ath10k_snoc_rx_post(ar);
6508c2ecf20Sopenharmony_ci}
6518c2ecf20Sopenharmony_ci
6528c2ecf20Sopenharmony_cistatic void ath10k_snoc_htc_tx_cb(struct ath10k_ce_pipe *ce_state)
6538c2ecf20Sopenharmony_ci{
6548c2ecf20Sopenharmony_ci	struct ath10k *ar = ce_state->ar;
6558c2ecf20Sopenharmony_ci	struct sk_buff_head list;
6568c2ecf20Sopenharmony_ci	struct sk_buff *skb;
6578c2ecf20Sopenharmony_ci
6588c2ecf20Sopenharmony_ci	__skb_queue_head_init(&list);
6598c2ecf20Sopenharmony_ci	while (ath10k_ce_completed_send_next(ce_state, (void **)&skb) == 0) {
6608c2ecf20Sopenharmony_ci		if (!skb)
6618c2ecf20Sopenharmony_ci			continue;
6628c2ecf20Sopenharmony_ci
6638c2ecf20Sopenharmony_ci		__skb_queue_tail(&list, skb);
6648c2ecf20Sopenharmony_ci	}
6658c2ecf20Sopenharmony_ci
6668c2ecf20Sopenharmony_ci	while ((skb = __skb_dequeue(&list)))
6678c2ecf20Sopenharmony_ci		ath10k_htc_tx_completion_handler(ar, skb);
6688c2ecf20Sopenharmony_ci}
6698c2ecf20Sopenharmony_ci
6708c2ecf20Sopenharmony_cistatic void ath10k_snoc_htt_tx_cb(struct ath10k_ce_pipe *ce_state)
6718c2ecf20Sopenharmony_ci{
6728c2ecf20Sopenharmony_ci	struct ath10k *ar = ce_state->ar;
6738c2ecf20Sopenharmony_ci	struct sk_buff *skb;
6748c2ecf20Sopenharmony_ci
6758c2ecf20Sopenharmony_ci	while (ath10k_ce_completed_send_next(ce_state, (void **)&skb) == 0) {
6768c2ecf20Sopenharmony_ci		if (!skb)
6778c2ecf20Sopenharmony_ci			continue;
6788c2ecf20Sopenharmony_ci
6798c2ecf20Sopenharmony_ci		dma_unmap_single(ar->dev, ATH10K_SKB_CB(skb)->paddr,
6808c2ecf20Sopenharmony_ci				 skb->len, DMA_TO_DEVICE);
6818c2ecf20Sopenharmony_ci		ath10k_htt_hif_tx_complete(ar, skb);
6828c2ecf20Sopenharmony_ci	}
6838c2ecf20Sopenharmony_ci}
6848c2ecf20Sopenharmony_ci
6858c2ecf20Sopenharmony_cistatic int ath10k_snoc_hif_tx_sg(struct ath10k *ar, u8 pipe_id,
6868c2ecf20Sopenharmony_ci				 struct ath10k_hif_sg_item *items, int n_items)
6878c2ecf20Sopenharmony_ci{
6888c2ecf20Sopenharmony_ci	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
6898c2ecf20Sopenharmony_ci	struct ath10k_ce *ce = ath10k_ce_priv(ar);
6908c2ecf20Sopenharmony_ci	struct ath10k_snoc_pipe *snoc_pipe;
6918c2ecf20Sopenharmony_ci	struct ath10k_ce_pipe *ce_pipe;
6928c2ecf20Sopenharmony_ci	int err, i = 0;
6938c2ecf20Sopenharmony_ci
6948c2ecf20Sopenharmony_ci	snoc_pipe = &ar_snoc->pipe_info[pipe_id];
6958c2ecf20Sopenharmony_ci	ce_pipe = snoc_pipe->ce_hdl;
6968c2ecf20Sopenharmony_ci	spin_lock_bh(&ce->ce_lock);
6978c2ecf20Sopenharmony_ci
6988c2ecf20Sopenharmony_ci	for (i = 0; i < n_items - 1; i++) {
6998c2ecf20Sopenharmony_ci		ath10k_dbg(ar, ATH10K_DBG_SNOC,
7008c2ecf20Sopenharmony_ci			   "snoc tx item %d paddr %pad len %d n_items %d\n",
7018c2ecf20Sopenharmony_ci			   i, &items[i].paddr, items[i].len, n_items);
7028c2ecf20Sopenharmony_ci
7038c2ecf20Sopenharmony_ci		err = ath10k_ce_send_nolock(ce_pipe,
7048c2ecf20Sopenharmony_ci					    items[i].transfer_context,
7058c2ecf20Sopenharmony_ci					    items[i].paddr,
7068c2ecf20Sopenharmony_ci					    items[i].len,
7078c2ecf20Sopenharmony_ci					    items[i].transfer_id,
7088c2ecf20Sopenharmony_ci					    CE_SEND_FLAG_GATHER);
7098c2ecf20Sopenharmony_ci		if (err)
7108c2ecf20Sopenharmony_ci			goto err;
7118c2ecf20Sopenharmony_ci	}
7128c2ecf20Sopenharmony_ci
7138c2ecf20Sopenharmony_ci	ath10k_dbg(ar, ATH10K_DBG_SNOC,
7148c2ecf20Sopenharmony_ci		   "snoc tx item %d paddr %pad len %d n_items %d\n",
7158c2ecf20Sopenharmony_ci		   i, &items[i].paddr, items[i].len, n_items);
7168c2ecf20Sopenharmony_ci
7178c2ecf20Sopenharmony_ci	err = ath10k_ce_send_nolock(ce_pipe,
7188c2ecf20Sopenharmony_ci				    items[i].transfer_context,
7198c2ecf20Sopenharmony_ci				    items[i].paddr,
7208c2ecf20Sopenharmony_ci				    items[i].len,
7218c2ecf20Sopenharmony_ci				    items[i].transfer_id,
7228c2ecf20Sopenharmony_ci				    0);
7238c2ecf20Sopenharmony_ci	if (err)
7248c2ecf20Sopenharmony_ci		goto err;
7258c2ecf20Sopenharmony_ci
7268c2ecf20Sopenharmony_ci	spin_unlock_bh(&ce->ce_lock);
7278c2ecf20Sopenharmony_ci
7288c2ecf20Sopenharmony_ci	return 0;
7298c2ecf20Sopenharmony_ci
7308c2ecf20Sopenharmony_cierr:
7318c2ecf20Sopenharmony_ci	for (; i > 0; i--)
7328c2ecf20Sopenharmony_ci		__ath10k_ce_send_revert(ce_pipe);
7338c2ecf20Sopenharmony_ci
7348c2ecf20Sopenharmony_ci	spin_unlock_bh(&ce->ce_lock);
7358c2ecf20Sopenharmony_ci	return err;
7368c2ecf20Sopenharmony_ci}
7378c2ecf20Sopenharmony_ci
7388c2ecf20Sopenharmony_cistatic int ath10k_snoc_hif_get_target_info(struct ath10k *ar,
7398c2ecf20Sopenharmony_ci					   struct bmi_target_info *target_info)
7408c2ecf20Sopenharmony_ci{
7418c2ecf20Sopenharmony_ci	target_info->version = ATH10K_HW_WCN3990;
7428c2ecf20Sopenharmony_ci	target_info->type = ATH10K_HW_WCN3990;
7438c2ecf20Sopenharmony_ci
7448c2ecf20Sopenharmony_ci	return 0;
7458c2ecf20Sopenharmony_ci}
7468c2ecf20Sopenharmony_ci
7478c2ecf20Sopenharmony_cistatic u16 ath10k_snoc_hif_get_free_queue_number(struct ath10k *ar, u8 pipe)
7488c2ecf20Sopenharmony_ci{
7498c2ecf20Sopenharmony_ci	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
7508c2ecf20Sopenharmony_ci
7518c2ecf20Sopenharmony_ci	ath10k_dbg(ar, ATH10K_DBG_SNOC, "hif get free queue number\n");
7528c2ecf20Sopenharmony_ci
7538c2ecf20Sopenharmony_ci	return ath10k_ce_num_free_src_entries(ar_snoc->pipe_info[pipe].ce_hdl);
7548c2ecf20Sopenharmony_ci}
7558c2ecf20Sopenharmony_ci
7568c2ecf20Sopenharmony_cistatic void ath10k_snoc_hif_send_complete_check(struct ath10k *ar, u8 pipe,
7578c2ecf20Sopenharmony_ci						int force)
7588c2ecf20Sopenharmony_ci{
7598c2ecf20Sopenharmony_ci	int resources;
7608c2ecf20Sopenharmony_ci
7618c2ecf20Sopenharmony_ci	ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc hif send complete check\n");
7628c2ecf20Sopenharmony_ci
7638c2ecf20Sopenharmony_ci	if (!force) {
7648c2ecf20Sopenharmony_ci		resources = ath10k_snoc_hif_get_free_queue_number(ar, pipe);
7658c2ecf20Sopenharmony_ci
7668c2ecf20Sopenharmony_ci		if (resources > (host_ce_config_wlan[pipe].src_nentries >> 1))
7678c2ecf20Sopenharmony_ci			return;
7688c2ecf20Sopenharmony_ci	}
7698c2ecf20Sopenharmony_ci	ath10k_ce_per_engine_service(ar, pipe);
7708c2ecf20Sopenharmony_ci}
7718c2ecf20Sopenharmony_ci
7728c2ecf20Sopenharmony_cistatic int ath10k_snoc_hif_map_service_to_pipe(struct ath10k *ar,
7738c2ecf20Sopenharmony_ci					       u16 service_id,
7748c2ecf20Sopenharmony_ci					       u8 *ul_pipe, u8 *dl_pipe)
7758c2ecf20Sopenharmony_ci{
7768c2ecf20Sopenharmony_ci	const struct ce_service_to_pipe *entry;
7778c2ecf20Sopenharmony_ci	bool ul_set = false, dl_set = false;
7788c2ecf20Sopenharmony_ci	int i;
7798c2ecf20Sopenharmony_ci
7808c2ecf20Sopenharmony_ci	ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc hif map service\n");
7818c2ecf20Sopenharmony_ci
7828c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(target_service_to_ce_map_wlan); i++) {
7838c2ecf20Sopenharmony_ci		entry = &target_service_to_ce_map_wlan[i];
7848c2ecf20Sopenharmony_ci
7858c2ecf20Sopenharmony_ci		if (__le32_to_cpu(entry->service_id) != service_id)
7868c2ecf20Sopenharmony_ci			continue;
7878c2ecf20Sopenharmony_ci
7888c2ecf20Sopenharmony_ci		switch (__le32_to_cpu(entry->pipedir)) {
7898c2ecf20Sopenharmony_ci		case PIPEDIR_NONE:
7908c2ecf20Sopenharmony_ci			break;
7918c2ecf20Sopenharmony_ci		case PIPEDIR_IN:
7928c2ecf20Sopenharmony_ci			WARN_ON(dl_set);
7938c2ecf20Sopenharmony_ci			*dl_pipe = __le32_to_cpu(entry->pipenum);
7948c2ecf20Sopenharmony_ci			dl_set = true;
7958c2ecf20Sopenharmony_ci			break;
7968c2ecf20Sopenharmony_ci		case PIPEDIR_OUT:
7978c2ecf20Sopenharmony_ci			WARN_ON(ul_set);
7988c2ecf20Sopenharmony_ci			*ul_pipe = __le32_to_cpu(entry->pipenum);
7998c2ecf20Sopenharmony_ci			ul_set = true;
8008c2ecf20Sopenharmony_ci			break;
8018c2ecf20Sopenharmony_ci		case PIPEDIR_INOUT:
8028c2ecf20Sopenharmony_ci			WARN_ON(dl_set);
8038c2ecf20Sopenharmony_ci			WARN_ON(ul_set);
8048c2ecf20Sopenharmony_ci			*dl_pipe = __le32_to_cpu(entry->pipenum);
8058c2ecf20Sopenharmony_ci			*ul_pipe = __le32_to_cpu(entry->pipenum);
8068c2ecf20Sopenharmony_ci			dl_set = true;
8078c2ecf20Sopenharmony_ci			ul_set = true;
8088c2ecf20Sopenharmony_ci			break;
8098c2ecf20Sopenharmony_ci		}
8108c2ecf20Sopenharmony_ci	}
8118c2ecf20Sopenharmony_ci
8128c2ecf20Sopenharmony_ci	if (!ul_set || !dl_set)
8138c2ecf20Sopenharmony_ci		return -ENOENT;
8148c2ecf20Sopenharmony_ci
8158c2ecf20Sopenharmony_ci	return 0;
8168c2ecf20Sopenharmony_ci}
8178c2ecf20Sopenharmony_ci
8188c2ecf20Sopenharmony_cistatic void ath10k_snoc_hif_get_default_pipe(struct ath10k *ar,
8198c2ecf20Sopenharmony_ci					     u8 *ul_pipe, u8 *dl_pipe)
8208c2ecf20Sopenharmony_ci{
8218c2ecf20Sopenharmony_ci	ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc hif get default pipe\n");
8228c2ecf20Sopenharmony_ci
8238c2ecf20Sopenharmony_ci	(void)ath10k_snoc_hif_map_service_to_pipe(ar,
8248c2ecf20Sopenharmony_ci						 ATH10K_HTC_SVC_ID_RSVD_CTRL,
8258c2ecf20Sopenharmony_ci						 ul_pipe, dl_pipe);
8268c2ecf20Sopenharmony_ci}
8278c2ecf20Sopenharmony_ci
8288c2ecf20Sopenharmony_cistatic inline void ath10k_snoc_irq_disable(struct ath10k *ar)
8298c2ecf20Sopenharmony_ci{
8308c2ecf20Sopenharmony_ci	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
8318c2ecf20Sopenharmony_ci	int id;
8328c2ecf20Sopenharmony_ci
8338c2ecf20Sopenharmony_ci	for (id = 0; id < CE_COUNT_MAX; id++)
8348c2ecf20Sopenharmony_ci		disable_irq(ar_snoc->ce_irqs[id].irq_line);
8358c2ecf20Sopenharmony_ci}
8368c2ecf20Sopenharmony_ci
8378c2ecf20Sopenharmony_cistatic inline void ath10k_snoc_irq_enable(struct ath10k *ar)
8388c2ecf20Sopenharmony_ci{
8398c2ecf20Sopenharmony_ci	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
8408c2ecf20Sopenharmony_ci	int id;
8418c2ecf20Sopenharmony_ci
8428c2ecf20Sopenharmony_ci	for (id = 0; id < CE_COUNT_MAX; id++)
8438c2ecf20Sopenharmony_ci		enable_irq(ar_snoc->ce_irqs[id].irq_line);
8448c2ecf20Sopenharmony_ci}
8458c2ecf20Sopenharmony_ci
8468c2ecf20Sopenharmony_cistatic void ath10k_snoc_rx_pipe_cleanup(struct ath10k_snoc_pipe *snoc_pipe)
8478c2ecf20Sopenharmony_ci{
8488c2ecf20Sopenharmony_ci	struct ath10k_ce_pipe *ce_pipe;
8498c2ecf20Sopenharmony_ci	struct ath10k_ce_ring *ce_ring;
8508c2ecf20Sopenharmony_ci	struct sk_buff *skb;
8518c2ecf20Sopenharmony_ci	struct ath10k *ar;
8528c2ecf20Sopenharmony_ci	int i;
8538c2ecf20Sopenharmony_ci
8548c2ecf20Sopenharmony_ci	ar = snoc_pipe->hif_ce_state;
8558c2ecf20Sopenharmony_ci	ce_pipe = snoc_pipe->ce_hdl;
8568c2ecf20Sopenharmony_ci	ce_ring = ce_pipe->dest_ring;
8578c2ecf20Sopenharmony_ci
8588c2ecf20Sopenharmony_ci	if (!ce_ring)
8598c2ecf20Sopenharmony_ci		return;
8608c2ecf20Sopenharmony_ci
8618c2ecf20Sopenharmony_ci	if (!snoc_pipe->buf_sz)
8628c2ecf20Sopenharmony_ci		return;
8638c2ecf20Sopenharmony_ci
8648c2ecf20Sopenharmony_ci	for (i = 0; i < ce_ring->nentries; i++) {
8658c2ecf20Sopenharmony_ci		skb = ce_ring->per_transfer_context[i];
8668c2ecf20Sopenharmony_ci		if (!skb)
8678c2ecf20Sopenharmony_ci			continue;
8688c2ecf20Sopenharmony_ci
8698c2ecf20Sopenharmony_ci		ce_ring->per_transfer_context[i] = NULL;
8708c2ecf20Sopenharmony_ci
8718c2ecf20Sopenharmony_ci		dma_unmap_single(ar->dev, ATH10K_SKB_RXCB(skb)->paddr,
8728c2ecf20Sopenharmony_ci				 skb->len + skb_tailroom(skb),
8738c2ecf20Sopenharmony_ci				 DMA_FROM_DEVICE);
8748c2ecf20Sopenharmony_ci		dev_kfree_skb_any(skb);
8758c2ecf20Sopenharmony_ci	}
8768c2ecf20Sopenharmony_ci}
8778c2ecf20Sopenharmony_ci
8788c2ecf20Sopenharmony_cistatic void ath10k_snoc_tx_pipe_cleanup(struct ath10k_snoc_pipe *snoc_pipe)
8798c2ecf20Sopenharmony_ci{
8808c2ecf20Sopenharmony_ci	struct ath10k_ce_pipe *ce_pipe;
8818c2ecf20Sopenharmony_ci	struct ath10k_ce_ring *ce_ring;
8828c2ecf20Sopenharmony_ci	struct sk_buff *skb;
8838c2ecf20Sopenharmony_ci	struct ath10k *ar;
8848c2ecf20Sopenharmony_ci	int i;
8858c2ecf20Sopenharmony_ci
8868c2ecf20Sopenharmony_ci	ar = snoc_pipe->hif_ce_state;
8878c2ecf20Sopenharmony_ci	ce_pipe = snoc_pipe->ce_hdl;
8888c2ecf20Sopenharmony_ci	ce_ring = ce_pipe->src_ring;
8898c2ecf20Sopenharmony_ci
8908c2ecf20Sopenharmony_ci	if (!ce_ring)
8918c2ecf20Sopenharmony_ci		return;
8928c2ecf20Sopenharmony_ci
8938c2ecf20Sopenharmony_ci	if (!snoc_pipe->buf_sz)
8948c2ecf20Sopenharmony_ci		return;
8958c2ecf20Sopenharmony_ci
8968c2ecf20Sopenharmony_ci	for (i = 0; i < ce_ring->nentries; i++) {
8978c2ecf20Sopenharmony_ci		skb = ce_ring->per_transfer_context[i];
8988c2ecf20Sopenharmony_ci		if (!skb)
8998c2ecf20Sopenharmony_ci			continue;
9008c2ecf20Sopenharmony_ci
9018c2ecf20Sopenharmony_ci		ce_ring->per_transfer_context[i] = NULL;
9028c2ecf20Sopenharmony_ci
9038c2ecf20Sopenharmony_ci		ath10k_htc_tx_completion_handler(ar, skb);
9048c2ecf20Sopenharmony_ci	}
9058c2ecf20Sopenharmony_ci}
9068c2ecf20Sopenharmony_ci
9078c2ecf20Sopenharmony_cistatic void ath10k_snoc_buffer_cleanup(struct ath10k *ar)
9088c2ecf20Sopenharmony_ci{
9098c2ecf20Sopenharmony_ci	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
9108c2ecf20Sopenharmony_ci	struct ath10k_snoc_pipe *pipe_info;
9118c2ecf20Sopenharmony_ci	int pipe_num;
9128c2ecf20Sopenharmony_ci
9138c2ecf20Sopenharmony_ci	del_timer_sync(&ar_snoc->rx_post_retry);
9148c2ecf20Sopenharmony_ci	for (pipe_num = 0; pipe_num < CE_COUNT; pipe_num++) {
9158c2ecf20Sopenharmony_ci		pipe_info = &ar_snoc->pipe_info[pipe_num];
9168c2ecf20Sopenharmony_ci		ath10k_snoc_rx_pipe_cleanup(pipe_info);
9178c2ecf20Sopenharmony_ci		ath10k_snoc_tx_pipe_cleanup(pipe_info);
9188c2ecf20Sopenharmony_ci	}
9198c2ecf20Sopenharmony_ci}
9208c2ecf20Sopenharmony_ci
9218c2ecf20Sopenharmony_cistatic void ath10k_snoc_hif_stop(struct ath10k *ar)
9228c2ecf20Sopenharmony_ci{
9238c2ecf20Sopenharmony_ci	if (!test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags))
9248c2ecf20Sopenharmony_ci		ath10k_snoc_irq_disable(ar);
9258c2ecf20Sopenharmony_ci
9268c2ecf20Sopenharmony_ci	napi_synchronize(&ar->napi);
9278c2ecf20Sopenharmony_ci	napi_disable(&ar->napi);
9288c2ecf20Sopenharmony_ci	ath10k_snoc_buffer_cleanup(ar);
9298c2ecf20Sopenharmony_ci	ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif stop\n");
9308c2ecf20Sopenharmony_ci}
9318c2ecf20Sopenharmony_ci
9328c2ecf20Sopenharmony_cistatic int ath10k_snoc_hif_start(struct ath10k *ar)
9338c2ecf20Sopenharmony_ci{
9348c2ecf20Sopenharmony_ci	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
9358c2ecf20Sopenharmony_ci
9368c2ecf20Sopenharmony_ci	bitmap_clear(ar_snoc->pending_ce_irqs, 0, CE_COUNT_MAX);
9378c2ecf20Sopenharmony_ci	napi_enable(&ar->napi);
9388c2ecf20Sopenharmony_ci	ath10k_snoc_irq_enable(ar);
9398c2ecf20Sopenharmony_ci	ath10k_snoc_rx_post(ar);
9408c2ecf20Sopenharmony_ci
9418c2ecf20Sopenharmony_ci	clear_bit(ATH10K_SNOC_FLAG_RECOVERY, &ar_snoc->flags);
9428c2ecf20Sopenharmony_ci
9438c2ecf20Sopenharmony_ci	ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif start\n");
9448c2ecf20Sopenharmony_ci
9458c2ecf20Sopenharmony_ci	return 0;
9468c2ecf20Sopenharmony_ci}
9478c2ecf20Sopenharmony_ci
9488c2ecf20Sopenharmony_cistatic int ath10k_snoc_init_pipes(struct ath10k *ar)
9498c2ecf20Sopenharmony_ci{
9508c2ecf20Sopenharmony_ci	int i, ret;
9518c2ecf20Sopenharmony_ci
9528c2ecf20Sopenharmony_ci	for (i = 0; i < CE_COUNT; i++) {
9538c2ecf20Sopenharmony_ci		ret = ath10k_ce_init_pipe(ar, i, &host_ce_config_wlan[i]);
9548c2ecf20Sopenharmony_ci		if (ret) {
9558c2ecf20Sopenharmony_ci			ath10k_err(ar, "failed to initialize copy engine pipe %d: %d\n",
9568c2ecf20Sopenharmony_ci				   i, ret);
9578c2ecf20Sopenharmony_ci			return ret;
9588c2ecf20Sopenharmony_ci		}
9598c2ecf20Sopenharmony_ci	}
9608c2ecf20Sopenharmony_ci
9618c2ecf20Sopenharmony_ci	return 0;
9628c2ecf20Sopenharmony_ci}
9638c2ecf20Sopenharmony_ci
9648c2ecf20Sopenharmony_cistatic int ath10k_snoc_wlan_enable(struct ath10k *ar,
9658c2ecf20Sopenharmony_ci				   enum ath10k_firmware_mode fw_mode)
9668c2ecf20Sopenharmony_ci{
9678c2ecf20Sopenharmony_ci	struct ath10k_tgt_pipe_cfg tgt_cfg[CE_COUNT_MAX];
9688c2ecf20Sopenharmony_ci	struct ath10k_qmi_wlan_enable_cfg cfg;
9698c2ecf20Sopenharmony_ci	enum wlfw_driver_mode_enum_v01 mode;
9708c2ecf20Sopenharmony_ci	int pipe_num;
9718c2ecf20Sopenharmony_ci
9728c2ecf20Sopenharmony_ci	for (pipe_num = 0; pipe_num < CE_COUNT_MAX; pipe_num++) {
9738c2ecf20Sopenharmony_ci		tgt_cfg[pipe_num].pipe_num =
9748c2ecf20Sopenharmony_ci				target_ce_config_wlan[pipe_num].pipenum;
9758c2ecf20Sopenharmony_ci		tgt_cfg[pipe_num].pipe_dir =
9768c2ecf20Sopenharmony_ci				target_ce_config_wlan[pipe_num].pipedir;
9778c2ecf20Sopenharmony_ci		tgt_cfg[pipe_num].nentries =
9788c2ecf20Sopenharmony_ci				target_ce_config_wlan[pipe_num].nentries;
9798c2ecf20Sopenharmony_ci		tgt_cfg[pipe_num].nbytes_max =
9808c2ecf20Sopenharmony_ci				target_ce_config_wlan[pipe_num].nbytes_max;
9818c2ecf20Sopenharmony_ci		tgt_cfg[pipe_num].flags =
9828c2ecf20Sopenharmony_ci				target_ce_config_wlan[pipe_num].flags;
9838c2ecf20Sopenharmony_ci		tgt_cfg[pipe_num].reserved = 0;
9848c2ecf20Sopenharmony_ci	}
9858c2ecf20Sopenharmony_ci
9868c2ecf20Sopenharmony_ci	cfg.num_ce_tgt_cfg = sizeof(target_ce_config_wlan) /
9878c2ecf20Sopenharmony_ci				sizeof(struct ath10k_tgt_pipe_cfg);
9888c2ecf20Sopenharmony_ci	cfg.ce_tgt_cfg = (struct ath10k_tgt_pipe_cfg *)
9898c2ecf20Sopenharmony_ci		&tgt_cfg;
9908c2ecf20Sopenharmony_ci	cfg.num_ce_svc_pipe_cfg = sizeof(target_service_to_ce_map_wlan) /
9918c2ecf20Sopenharmony_ci				  sizeof(struct ath10k_svc_pipe_cfg);
9928c2ecf20Sopenharmony_ci	cfg.ce_svc_cfg = (struct ath10k_svc_pipe_cfg *)
9938c2ecf20Sopenharmony_ci		&target_service_to_ce_map_wlan;
9948c2ecf20Sopenharmony_ci	cfg.num_shadow_reg_cfg = ARRAY_SIZE(target_shadow_reg_cfg_map);
9958c2ecf20Sopenharmony_ci	cfg.shadow_reg_cfg = (struct ath10k_shadow_reg_cfg *)
9968c2ecf20Sopenharmony_ci		&target_shadow_reg_cfg_map;
9978c2ecf20Sopenharmony_ci
9988c2ecf20Sopenharmony_ci	switch (fw_mode) {
9998c2ecf20Sopenharmony_ci	case ATH10K_FIRMWARE_MODE_NORMAL:
10008c2ecf20Sopenharmony_ci		mode = QMI_WLFW_MISSION_V01;
10018c2ecf20Sopenharmony_ci		break;
10028c2ecf20Sopenharmony_ci	case ATH10K_FIRMWARE_MODE_UTF:
10038c2ecf20Sopenharmony_ci		mode = QMI_WLFW_FTM_V01;
10048c2ecf20Sopenharmony_ci		break;
10058c2ecf20Sopenharmony_ci	default:
10068c2ecf20Sopenharmony_ci		ath10k_err(ar, "invalid firmware mode %d\n", fw_mode);
10078c2ecf20Sopenharmony_ci		return -EINVAL;
10088c2ecf20Sopenharmony_ci	}
10098c2ecf20Sopenharmony_ci
10108c2ecf20Sopenharmony_ci	return ath10k_qmi_wlan_enable(ar, &cfg, mode,
10118c2ecf20Sopenharmony_ci				       NULL);
10128c2ecf20Sopenharmony_ci}
10138c2ecf20Sopenharmony_ci
10148c2ecf20Sopenharmony_cistatic void ath10k_snoc_wlan_disable(struct ath10k *ar)
10158c2ecf20Sopenharmony_ci{
10168c2ecf20Sopenharmony_ci	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
10178c2ecf20Sopenharmony_ci
10188c2ecf20Sopenharmony_ci	/* If both ATH10K_FLAG_CRASH_FLUSH and ATH10K_SNOC_FLAG_RECOVERY
10198c2ecf20Sopenharmony_ci	 * flags are not set, it means that the driver has restarted
10208c2ecf20Sopenharmony_ci	 * due to a crash inject via debugfs. In this case, the driver
10218c2ecf20Sopenharmony_ci	 * needs to restart the firmware and hence send qmi wlan disable,
10228c2ecf20Sopenharmony_ci	 * during the driver restart sequence.
10238c2ecf20Sopenharmony_ci	 */
10248c2ecf20Sopenharmony_ci	if (!test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags) ||
10258c2ecf20Sopenharmony_ci	    !test_bit(ATH10K_SNOC_FLAG_RECOVERY, &ar_snoc->flags))
10268c2ecf20Sopenharmony_ci		ath10k_qmi_wlan_disable(ar);
10278c2ecf20Sopenharmony_ci}
10288c2ecf20Sopenharmony_ci
10298c2ecf20Sopenharmony_cistatic void ath10k_snoc_hif_power_down(struct ath10k *ar)
10308c2ecf20Sopenharmony_ci{
10318c2ecf20Sopenharmony_ci	ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif power down\n");
10328c2ecf20Sopenharmony_ci
10338c2ecf20Sopenharmony_ci	ath10k_snoc_wlan_disable(ar);
10348c2ecf20Sopenharmony_ci	ath10k_ce_free_rri(ar);
10358c2ecf20Sopenharmony_ci}
10368c2ecf20Sopenharmony_ci
10378c2ecf20Sopenharmony_cistatic int ath10k_snoc_hif_power_up(struct ath10k *ar,
10388c2ecf20Sopenharmony_ci				    enum ath10k_firmware_mode fw_mode)
10398c2ecf20Sopenharmony_ci{
10408c2ecf20Sopenharmony_ci	int ret;
10418c2ecf20Sopenharmony_ci
10428c2ecf20Sopenharmony_ci	ath10k_dbg(ar, ATH10K_DBG_SNOC, "%s:WCN3990 driver state = %d\n",
10438c2ecf20Sopenharmony_ci		   __func__, ar->state);
10448c2ecf20Sopenharmony_ci
10458c2ecf20Sopenharmony_ci	ret = ath10k_snoc_wlan_enable(ar, fw_mode);
10468c2ecf20Sopenharmony_ci	if (ret) {
10478c2ecf20Sopenharmony_ci		ath10k_err(ar, "failed to enable wcn3990: %d\n", ret);
10488c2ecf20Sopenharmony_ci		return ret;
10498c2ecf20Sopenharmony_ci	}
10508c2ecf20Sopenharmony_ci
10518c2ecf20Sopenharmony_ci	ath10k_ce_alloc_rri(ar);
10528c2ecf20Sopenharmony_ci
10538c2ecf20Sopenharmony_ci	ret = ath10k_snoc_init_pipes(ar);
10548c2ecf20Sopenharmony_ci	if (ret) {
10558c2ecf20Sopenharmony_ci		ath10k_err(ar, "failed to initialize CE: %d\n", ret);
10568c2ecf20Sopenharmony_ci		goto err_free_rri;
10578c2ecf20Sopenharmony_ci	}
10588c2ecf20Sopenharmony_ci
10598c2ecf20Sopenharmony_ci	ath10k_ce_enable_interrupts(ar);
10608c2ecf20Sopenharmony_ci
10618c2ecf20Sopenharmony_ci	return 0;
10628c2ecf20Sopenharmony_ci
10638c2ecf20Sopenharmony_cierr_free_rri:
10648c2ecf20Sopenharmony_ci	ath10k_ce_free_rri(ar);
10658c2ecf20Sopenharmony_ci	ath10k_snoc_wlan_disable(ar);
10668c2ecf20Sopenharmony_ci
10678c2ecf20Sopenharmony_ci	return ret;
10688c2ecf20Sopenharmony_ci}
10698c2ecf20Sopenharmony_ci
10708c2ecf20Sopenharmony_cistatic int ath10k_snoc_hif_set_target_log_mode(struct ath10k *ar,
10718c2ecf20Sopenharmony_ci					       u8 fw_log_mode)
10728c2ecf20Sopenharmony_ci{
10738c2ecf20Sopenharmony_ci	u8 fw_dbg_mode;
10748c2ecf20Sopenharmony_ci
10758c2ecf20Sopenharmony_ci	if (fw_log_mode)
10768c2ecf20Sopenharmony_ci		fw_dbg_mode = ATH10K_ENABLE_FW_LOG_CE;
10778c2ecf20Sopenharmony_ci	else
10788c2ecf20Sopenharmony_ci		fw_dbg_mode = ATH10K_ENABLE_FW_LOG_DIAG;
10798c2ecf20Sopenharmony_ci
10808c2ecf20Sopenharmony_ci	return ath10k_qmi_set_fw_log_mode(ar, fw_dbg_mode);
10818c2ecf20Sopenharmony_ci}
10828c2ecf20Sopenharmony_ci
10838c2ecf20Sopenharmony_ci#ifdef CONFIG_PM
10848c2ecf20Sopenharmony_cistatic int ath10k_snoc_hif_suspend(struct ath10k *ar)
10858c2ecf20Sopenharmony_ci{
10868c2ecf20Sopenharmony_ci	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
10878c2ecf20Sopenharmony_ci	int ret;
10888c2ecf20Sopenharmony_ci
10898c2ecf20Sopenharmony_ci	if (!device_may_wakeup(ar->dev))
10908c2ecf20Sopenharmony_ci		return -EPERM;
10918c2ecf20Sopenharmony_ci
10928c2ecf20Sopenharmony_ci	ret = enable_irq_wake(ar_snoc->ce_irqs[ATH10K_SNOC_WAKE_IRQ].irq_line);
10938c2ecf20Sopenharmony_ci	if (ret) {
10948c2ecf20Sopenharmony_ci		ath10k_err(ar, "failed to enable wakeup irq :%d\n", ret);
10958c2ecf20Sopenharmony_ci		return ret;
10968c2ecf20Sopenharmony_ci	}
10978c2ecf20Sopenharmony_ci
10988c2ecf20Sopenharmony_ci	ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc device suspended\n");
10998c2ecf20Sopenharmony_ci
11008c2ecf20Sopenharmony_ci	return ret;
11018c2ecf20Sopenharmony_ci}
11028c2ecf20Sopenharmony_ci
11038c2ecf20Sopenharmony_cistatic int ath10k_snoc_hif_resume(struct ath10k *ar)
11048c2ecf20Sopenharmony_ci{
11058c2ecf20Sopenharmony_ci	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
11068c2ecf20Sopenharmony_ci	int ret;
11078c2ecf20Sopenharmony_ci
11088c2ecf20Sopenharmony_ci	if (!device_may_wakeup(ar->dev))
11098c2ecf20Sopenharmony_ci		return -EPERM;
11108c2ecf20Sopenharmony_ci
11118c2ecf20Sopenharmony_ci	ret = disable_irq_wake(ar_snoc->ce_irqs[ATH10K_SNOC_WAKE_IRQ].irq_line);
11128c2ecf20Sopenharmony_ci	if (ret) {
11138c2ecf20Sopenharmony_ci		ath10k_err(ar, "failed to disable wakeup irq: %d\n", ret);
11148c2ecf20Sopenharmony_ci		return ret;
11158c2ecf20Sopenharmony_ci	}
11168c2ecf20Sopenharmony_ci
11178c2ecf20Sopenharmony_ci	ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc device resumed\n");
11188c2ecf20Sopenharmony_ci
11198c2ecf20Sopenharmony_ci	return ret;
11208c2ecf20Sopenharmony_ci}
11218c2ecf20Sopenharmony_ci#endif
11228c2ecf20Sopenharmony_ci
11238c2ecf20Sopenharmony_cistatic const struct ath10k_hif_ops ath10k_snoc_hif_ops = {
11248c2ecf20Sopenharmony_ci	.read32		= ath10k_snoc_read32,
11258c2ecf20Sopenharmony_ci	.write32	= ath10k_snoc_write32,
11268c2ecf20Sopenharmony_ci	.start		= ath10k_snoc_hif_start,
11278c2ecf20Sopenharmony_ci	.stop		= ath10k_snoc_hif_stop,
11288c2ecf20Sopenharmony_ci	.map_service_to_pipe	= ath10k_snoc_hif_map_service_to_pipe,
11298c2ecf20Sopenharmony_ci	.get_default_pipe	= ath10k_snoc_hif_get_default_pipe,
11308c2ecf20Sopenharmony_ci	.power_up		= ath10k_snoc_hif_power_up,
11318c2ecf20Sopenharmony_ci	.power_down		= ath10k_snoc_hif_power_down,
11328c2ecf20Sopenharmony_ci	.tx_sg			= ath10k_snoc_hif_tx_sg,
11338c2ecf20Sopenharmony_ci	.send_complete_check	= ath10k_snoc_hif_send_complete_check,
11348c2ecf20Sopenharmony_ci	.get_free_queue_number	= ath10k_snoc_hif_get_free_queue_number,
11358c2ecf20Sopenharmony_ci	.get_target_info	= ath10k_snoc_hif_get_target_info,
11368c2ecf20Sopenharmony_ci	.set_target_log_mode    = ath10k_snoc_hif_set_target_log_mode,
11378c2ecf20Sopenharmony_ci
11388c2ecf20Sopenharmony_ci#ifdef CONFIG_PM
11398c2ecf20Sopenharmony_ci	.suspend                = ath10k_snoc_hif_suspend,
11408c2ecf20Sopenharmony_ci	.resume                 = ath10k_snoc_hif_resume,
11418c2ecf20Sopenharmony_ci#endif
11428c2ecf20Sopenharmony_ci};
11438c2ecf20Sopenharmony_ci
11448c2ecf20Sopenharmony_cistatic const struct ath10k_bus_ops ath10k_snoc_bus_ops = {
11458c2ecf20Sopenharmony_ci	.read32		= ath10k_snoc_read32,
11468c2ecf20Sopenharmony_ci	.write32	= ath10k_snoc_write32,
11478c2ecf20Sopenharmony_ci};
11488c2ecf20Sopenharmony_ci
11498c2ecf20Sopenharmony_cistatic int ath10k_snoc_get_ce_id_from_irq(struct ath10k *ar, int irq)
11508c2ecf20Sopenharmony_ci{
11518c2ecf20Sopenharmony_ci	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
11528c2ecf20Sopenharmony_ci	int i;
11538c2ecf20Sopenharmony_ci
11548c2ecf20Sopenharmony_ci	for (i = 0; i < CE_COUNT_MAX; i++) {
11558c2ecf20Sopenharmony_ci		if (ar_snoc->ce_irqs[i].irq_line == irq)
11568c2ecf20Sopenharmony_ci			return i;
11578c2ecf20Sopenharmony_ci	}
11588c2ecf20Sopenharmony_ci	ath10k_err(ar, "No matching CE id for irq %d\n", irq);
11598c2ecf20Sopenharmony_ci
11608c2ecf20Sopenharmony_ci	return -EINVAL;
11618c2ecf20Sopenharmony_ci}
11628c2ecf20Sopenharmony_ci
11638c2ecf20Sopenharmony_cistatic irqreturn_t ath10k_snoc_per_engine_handler(int irq, void *arg)
11648c2ecf20Sopenharmony_ci{
11658c2ecf20Sopenharmony_ci	struct ath10k *ar = arg;
11668c2ecf20Sopenharmony_ci	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
11678c2ecf20Sopenharmony_ci	int ce_id = ath10k_snoc_get_ce_id_from_irq(ar, irq);
11688c2ecf20Sopenharmony_ci
11698c2ecf20Sopenharmony_ci	if (ce_id < 0 || ce_id >= ARRAY_SIZE(ar_snoc->pipe_info)) {
11708c2ecf20Sopenharmony_ci		ath10k_warn(ar, "unexpected/invalid irq %d ce_id %d\n", irq,
11718c2ecf20Sopenharmony_ci			    ce_id);
11728c2ecf20Sopenharmony_ci		return IRQ_HANDLED;
11738c2ecf20Sopenharmony_ci	}
11748c2ecf20Sopenharmony_ci
11758c2ecf20Sopenharmony_ci	ath10k_ce_disable_interrupt(ar, ce_id);
11768c2ecf20Sopenharmony_ci	set_bit(ce_id, ar_snoc->pending_ce_irqs);
11778c2ecf20Sopenharmony_ci
11788c2ecf20Sopenharmony_ci	napi_schedule(&ar->napi);
11798c2ecf20Sopenharmony_ci
11808c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
11818c2ecf20Sopenharmony_ci}
11828c2ecf20Sopenharmony_ci
11838c2ecf20Sopenharmony_cistatic int ath10k_snoc_napi_poll(struct napi_struct *ctx, int budget)
11848c2ecf20Sopenharmony_ci{
11858c2ecf20Sopenharmony_ci	struct ath10k *ar = container_of(ctx, struct ath10k, napi);
11868c2ecf20Sopenharmony_ci	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
11878c2ecf20Sopenharmony_ci	int done = 0;
11888c2ecf20Sopenharmony_ci	int ce_id;
11898c2ecf20Sopenharmony_ci
11908c2ecf20Sopenharmony_ci	if (test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags)) {
11918c2ecf20Sopenharmony_ci		napi_complete(ctx);
11928c2ecf20Sopenharmony_ci		return done;
11938c2ecf20Sopenharmony_ci	}
11948c2ecf20Sopenharmony_ci
11958c2ecf20Sopenharmony_ci	for (ce_id = 0; ce_id < CE_COUNT; ce_id++)
11968c2ecf20Sopenharmony_ci		if (test_and_clear_bit(ce_id, ar_snoc->pending_ce_irqs)) {
11978c2ecf20Sopenharmony_ci			ath10k_ce_per_engine_service(ar, ce_id);
11988c2ecf20Sopenharmony_ci			ath10k_ce_enable_interrupt(ar, ce_id);
11998c2ecf20Sopenharmony_ci		}
12008c2ecf20Sopenharmony_ci
12018c2ecf20Sopenharmony_ci	done = ath10k_htt_txrx_compl_task(ar, budget);
12028c2ecf20Sopenharmony_ci
12038c2ecf20Sopenharmony_ci	if (done < budget)
12048c2ecf20Sopenharmony_ci		napi_complete(ctx);
12058c2ecf20Sopenharmony_ci
12068c2ecf20Sopenharmony_ci	return done;
12078c2ecf20Sopenharmony_ci}
12088c2ecf20Sopenharmony_ci
12098c2ecf20Sopenharmony_cistatic void ath10k_snoc_init_napi(struct ath10k *ar)
12108c2ecf20Sopenharmony_ci{
12118c2ecf20Sopenharmony_ci	netif_napi_add(&ar->napi_dev, &ar->napi, ath10k_snoc_napi_poll,
12128c2ecf20Sopenharmony_ci		       ATH10K_NAPI_BUDGET);
12138c2ecf20Sopenharmony_ci}
12148c2ecf20Sopenharmony_ci
12158c2ecf20Sopenharmony_cistatic int ath10k_snoc_request_irq(struct ath10k *ar)
12168c2ecf20Sopenharmony_ci{
12178c2ecf20Sopenharmony_ci	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
12188c2ecf20Sopenharmony_ci	int ret, id;
12198c2ecf20Sopenharmony_ci
12208c2ecf20Sopenharmony_ci	for (id = 0; id < CE_COUNT_MAX; id++) {
12218c2ecf20Sopenharmony_ci		ret = request_irq(ar_snoc->ce_irqs[id].irq_line,
12228c2ecf20Sopenharmony_ci				  ath10k_snoc_per_engine_handler,
12238c2ecf20Sopenharmony_ci				  IRQF_NO_AUTOEN, ce_name[id], ar);
12248c2ecf20Sopenharmony_ci		if (ret) {
12258c2ecf20Sopenharmony_ci			ath10k_err(ar,
12268c2ecf20Sopenharmony_ci				   "failed to register IRQ handler for CE %d: %d\n",
12278c2ecf20Sopenharmony_ci				   id, ret);
12288c2ecf20Sopenharmony_ci			goto err_irq;
12298c2ecf20Sopenharmony_ci		}
12308c2ecf20Sopenharmony_ci	}
12318c2ecf20Sopenharmony_ci
12328c2ecf20Sopenharmony_ci	return 0;
12338c2ecf20Sopenharmony_ci
12348c2ecf20Sopenharmony_cierr_irq:
12358c2ecf20Sopenharmony_ci	for (id -= 1; id >= 0; id--)
12368c2ecf20Sopenharmony_ci		free_irq(ar_snoc->ce_irqs[id].irq_line, ar);
12378c2ecf20Sopenharmony_ci
12388c2ecf20Sopenharmony_ci	return ret;
12398c2ecf20Sopenharmony_ci}
12408c2ecf20Sopenharmony_ci
12418c2ecf20Sopenharmony_cistatic void ath10k_snoc_free_irq(struct ath10k *ar)
12428c2ecf20Sopenharmony_ci{
12438c2ecf20Sopenharmony_ci	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
12448c2ecf20Sopenharmony_ci	int id;
12458c2ecf20Sopenharmony_ci
12468c2ecf20Sopenharmony_ci	for (id = 0; id < CE_COUNT_MAX; id++)
12478c2ecf20Sopenharmony_ci		free_irq(ar_snoc->ce_irqs[id].irq_line, ar);
12488c2ecf20Sopenharmony_ci}
12498c2ecf20Sopenharmony_ci
12508c2ecf20Sopenharmony_cistatic int ath10k_snoc_resource_init(struct ath10k *ar)
12518c2ecf20Sopenharmony_ci{
12528c2ecf20Sopenharmony_ci	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
12538c2ecf20Sopenharmony_ci	struct platform_device *pdev;
12548c2ecf20Sopenharmony_ci	struct resource *res;
12558c2ecf20Sopenharmony_ci	int i, ret = 0;
12568c2ecf20Sopenharmony_ci
12578c2ecf20Sopenharmony_ci	pdev = ar_snoc->dev;
12588c2ecf20Sopenharmony_ci	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "membase");
12598c2ecf20Sopenharmony_ci	if (!res) {
12608c2ecf20Sopenharmony_ci		ath10k_err(ar, "Memory base not found in DT\n");
12618c2ecf20Sopenharmony_ci		return -EINVAL;
12628c2ecf20Sopenharmony_ci	}
12638c2ecf20Sopenharmony_ci
12648c2ecf20Sopenharmony_ci	ar_snoc->mem_pa = res->start;
12658c2ecf20Sopenharmony_ci	ar_snoc->mem = devm_ioremap(&pdev->dev, ar_snoc->mem_pa,
12668c2ecf20Sopenharmony_ci				    resource_size(res));
12678c2ecf20Sopenharmony_ci	if (!ar_snoc->mem) {
12688c2ecf20Sopenharmony_ci		ath10k_err(ar, "Memory base ioremap failed with physical address %pa\n",
12698c2ecf20Sopenharmony_ci			   &ar_snoc->mem_pa);
12708c2ecf20Sopenharmony_ci		return -EINVAL;
12718c2ecf20Sopenharmony_ci	}
12728c2ecf20Sopenharmony_ci
12738c2ecf20Sopenharmony_ci	for (i = 0; i < CE_COUNT; i++) {
12748c2ecf20Sopenharmony_ci		res = platform_get_resource(ar_snoc->dev, IORESOURCE_IRQ, i);
12758c2ecf20Sopenharmony_ci		if (!res) {
12768c2ecf20Sopenharmony_ci			ath10k_err(ar, "failed to get IRQ%d\n", i);
12778c2ecf20Sopenharmony_ci			ret = -ENODEV;
12788c2ecf20Sopenharmony_ci			goto out;
12798c2ecf20Sopenharmony_ci		}
12808c2ecf20Sopenharmony_ci		ar_snoc->ce_irqs[i].irq_line = res->start;
12818c2ecf20Sopenharmony_ci	}
12828c2ecf20Sopenharmony_ci
12838c2ecf20Sopenharmony_ci	ret = device_property_read_u32(&pdev->dev, "qcom,xo-cal-data",
12848c2ecf20Sopenharmony_ci				       &ar_snoc->xo_cal_data);
12858c2ecf20Sopenharmony_ci	ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc xo-cal-data return %d\n", ret);
12868c2ecf20Sopenharmony_ci	if (ret == 0) {
12878c2ecf20Sopenharmony_ci		ar_snoc->xo_cal_supported = true;
12888c2ecf20Sopenharmony_ci		ath10k_dbg(ar, ATH10K_DBG_SNOC, "xo cal data %x\n",
12898c2ecf20Sopenharmony_ci			   ar_snoc->xo_cal_data);
12908c2ecf20Sopenharmony_ci	}
12918c2ecf20Sopenharmony_ci	ret = 0;
12928c2ecf20Sopenharmony_ci
12938c2ecf20Sopenharmony_ciout:
12948c2ecf20Sopenharmony_ci	return ret;
12958c2ecf20Sopenharmony_ci}
12968c2ecf20Sopenharmony_ci
12978c2ecf20Sopenharmony_cistatic void ath10k_snoc_quirks_init(struct ath10k *ar)
12988c2ecf20Sopenharmony_ci{
12998c2ecf20Sopenharmony_ci	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
13008c2ecf20Sopenharmony_ci	struct device *dev = &ar_snoc->dev->dev;
13018c2ecf20Sopenharmony_ci
13028c2ecf20Sopenharmony_ci	if (of_property_read_bool(dev->of_node, "qcom,snoc-host-cap-8bit-quirk"))
13038c2ecf20Sopenharmony_ci		set_bit(ATH10K_SNOC_FLAG_8BIT_HOST_CAP_QUIRK, &ar_snoc->flags);
13048c2ecf20Sopenharmony_ci}
13058c2ecf20Sopenharmony_ci
13068c2ecf20Sopenharmony_ciint ath10k_snoc_fw_indication(struct ath10k *ar, u64 type)
13078c2ecf20Sopenharmony_ci{
13088c2ecf20Sopenharmony_ci	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
13098c2ecf20Sopenharmony_ci	struct ath10k_bus_params bus_params = {};
13108c2ecf20Sopenharmony_ci	int ret;
13118c2ecf20Sopenharmony_ci
13128c2ecf20Sopenharmony_ci	if (test_bit(ATH10K_SNOC_FLAG_UNREGISTERING, &ar_snoc->flags))
13138c2ecf20Sopenharmony_ci		return 0;
13148c2ecf20Sopenharmony_ci
13158c2ecf20Sopenharmony_ci	switch (type) {
13168c2ecf20Sopenharmony_ci	case ATH10K_QMI_EVENT_FW_READY_IND:
13178c2ecf20Sopenharmony_ci		if (test_bit(ATH10K_SNOC_FLAG_REGISTERED, &ar_snoc->flags)) {
13188c2ecf20Sopenharmony_ci			queue_work(ar->workqueue, &ar->restart_work);
13198c2ecf20Sopenharmony_ci			break;
13208c2ecf20Sopenharmony_ci		}
13218c2ecf20Sopenharmony_ci
13228c2ecf20Sopenharmony_ci		bus_params.dev_type = ATH10K_DEV_TYPE_LL;
13238c2ecf20Sopenharmony_ci		bus_params.chip_id = ar_snoc->target_info.soc_version;
13248c2ecf20Sopenharmony_ci		ret = ath10k_core_register(ar, &bus_params);
13258c2ecf20Sopenharmony_ci		if (ret) {
13268c2ecf20Sopenharmony_ci			ath10k_err(ar, "Failed to register driver core: %d\n",
13278c2ecf20Sopenharmony_ci				   ret);
13288c2ecf20Sopenharmony_ci			return ret;
13298c2ecf20Sopenharmony_ci		}
13308c2ecf20Sopenharmony_ci		set_bit(ATH10K_SNOC_FLAG_REGISTERED, &ar_snoc->flags);
13318c2ecf20Sopenharmony_ci		break;
13328c2ecf20Sopenharmony_ci	case ATH10K_QMI_EVENT_FW_DOWN_IND:
13338c2ecf20Sopenharmony_ci		set_bit(ATH10K_SNOC_FLAG_RECOVERY, &ar_snoc->flags);
13348c2ecf20Sopenharmony_ci		set_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags);
13358c2ecf20Sopenharmony_ci		break;
13368c2ecf20Sopenharmony_ci	default:
13378c2ecf20Sopenharmony_ci		ath10k_err(ar, "invalid fw indication: %llx\n", type);
13388c2ecf20Sopenharmony_ci		return -EINVAL;
13398c2ecf20Sopenharmony_ci	}
13408c2ecf20Sopenharmony_ci
13418c2ecf20Sopenharmony_ci	return 0;
13428c2ecf20Sopenharmony_ci}
13438c2ecf20Sopenharmony_ci
13448c2ecf20Sopenharmony_cistatic int ath10k_snoc_setup_resource(struct ath10k *ar)
13458c2ecf20Sopenharmony_ci{
13468c2ecf20Sopenharmony_ci	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
13478c2ecf20Sopenharmony_ci	struct ath10k_ce *ce = ath10k_ce_priv(ar);
13488c2ecf20Sopenharmony_ci	struct ath10k_snoc_pipe *pipe;
13498c2ecf20Sopenharmony_ci	int i, ret;
13508c2ecf20Sopenharmony_ci
13518c2ecf20Sopenharmony_ci	timer_setup(&ar_snoc->rx_post_retry, ath10k_snoc_rx_replenish_retry, 0);
13528c2ecf20Sopenharmony_ci	spin_lock_init(&ce->ce_lock);
13538c2ecf20Sopenharmony_ci	for (i = 0; i < CE_COUNT; i++) {
13548c2ecf20Sopenharmony_ci		pipe = &ar_snoc->pipe_info[i];
13558c2ecf20Sopenharmony_ci		pipe->ce_hdl = &ce->ce_states[i];
13568c2ecf20Sopenharmony_ci		pipe->pipe_num = i;
13578c2ecf20Sopenharmony_ci		pipe->hif_ce_state = ar;
13588c2ecf20Sopenharmony_ci
13598c2ecf20Sopenharmony_ci		ret = ath10k_ce_alloc_pipe(ar, i, &host_ce_config_wlan[i]);
13608c2ecf20Sopenharmony_ci		if (ret) {
13618c2ecf20Sopenharmony_ci			ath10k_err(ar, "failed to allocate copy engine pipe %d: %d\n",
13628c2ecf20Sopenharmony_ci				   i, ret);
13638c2ecf20Sopenharmony_ci			return ret;
13648c2ecf20Sopenharmony_ci		}
13658c2ecf20Sopenharmony_ci
13668c2ecf20Sopenharmony_ci		pipe->buf_sz = host_ce_config_wlan[i].src_sz_max;
13678c2ecf20Sopenharmony_ci	}
13688c2ecf20Sopenharmony_ci	ath10k_snoc_init_napi(ar);
13698c2ecf20Sopenharmony_ci
13708c2ecf20Sopenharmony_ci	return 0;
13718c2ecf20Sopenharmony_ci}
13728c2ecf20Sopenharmony_ci
13738c2ecf20Sopenharmony_cistatic void ath10k_snoc_release_resource(struct ath10k *ar)
13748c2ecf20Sopenharmony_ci{
13758c2ecf20Sopenharmony_ci	int i;
13768c2ecf20Sopenharmony_ci
13778c2ecf20Sopenharmony_ci	netif_napi_del(&ar->napi);
13788c2ecf20Sopenharmony_ci	for (i = 0; i < CE_COUNT; i++)
13798c2ecf20Sopenharmony_ci		ath10k_ce_free_pipe(ar, i);
13808c2ecf20Sopenharmony_ci}
13818c2ecf20Sopenharmony_ci
13828c2ecf20Sopenharmony_cistatic int ath10k_hw_power_on(struct ath10k *ar)
13838c2ecf20Sopenharmony_ci{
13848c2ecf20Sopenharmony_ci	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
13858c2ecf20Sopenharmony_ci	int ret;
13868c2ecf20Sopenharmony_ci
13878c2ecf20Sopenharmony_ci	ath10k_dbg(ar, ATH10K_DBG_SNOC, "soc power on\n");
13888c2ecf20Sopenharmony_ci
13898c2ecf20Sopenharmony_ci	ret = regulator_bulk_enable(ar_snoc->num_vregs, ar_snoc->vregs);
13908c2ecf20Sopenharmony_ci	if (ret)
13918c2ecf20Sopenharmony_ci		return ret;
13928c2ecf20Sopenharmony_ci
13938c2ecf20Sopenharmony_ci	ret = clk_bulk_prepare_enable(ar_snoc->num_clks, ar_snoc->clks);
13948c2ecf20Sopenharmony_ci	if (ret)
13958c2ecf20Sopenharmony_ci		goto vreg_off;
13968c2ecf20Sopenharmony_ci
13978c2ecf20Sopenharmony_ci	return ret;
13988c2ecf20Sopenharmony_ci
13998c2ecf20Sopenharmony_civreg_off:
14008c2ecf20Sopenharmony_ci	regulator_bulk_disable(ar_snoc->num_vregs, ar_snoc->vregs);
14018c2ecf20Sopenharmony_ci	return ret;
14028c2ecf20Sopenharmony_ci}
14038c2ecf20Sopenharmony_ci
14048c2ecf20Sopenharmony_cistatic int ath10k_hw_power_off(struct ath10k *ar)
14058c2ecf20Sopenharmony_ci{
14068c2ecf20Sopenharmony_ci	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
14078c2ecf20Sopenharmony_ci
14088c2ecf20Sopenharmony_ci	ath10k_dbg(ar, ATH10K_DBG_SNOC, "soc power off\n");
14098c2ecf20Sopenharmony_ci
14108c2ecf20Sopenharmony_ci	clk_bulk_disable_unprepare(ar_snoc->num_clks, ar_snoc->clks);
14118c2ecf20Sopenharmony_ci
14128c2ecf20Sopenharmony_ci	return regulator_bulk_disable(ar_snoc->num_vregs, ar_snoc->vregs);
14138c2ecf20Sopenharmony_ci}
14148c2ecf20Sopenharmony_ci
14158c2ecf20Sopenharmony_cistatic void ath10k_msa_dump_memory(struct ath10k *ar,
14168c2ecf20Sopenharmony_ci				   struct ath10k_fw_crash_data *crash_data)
14178c2ecf20Sopenharmony_ci{
14188c2ecf20Sopenharmony_ci	const struct ath10k_hw_mem_layout *mem_layout;
14198c2ecf20Sopenharmony_ci	const struct ath10k_mem_region *current_region;
14208c2ecf20Sopenharmony_ci	struct ath10k_dump_ram_data_hdr *hdr;
14218c2ecf20Sopenharmony_ci	size_t buf_len;
14228c2ecf20Sopenharmony_ci	u8 *buf;
14238c2ecf20Sopenharmony_ci
14248c2ecf20Sopenharmony_ci	if (!crash_data || !crash_data->ramdump_buf)
14258c2ecf20Sopenharmony_ci		return;
14268c2ecf20Sopenharmony_ci
14278c2ecf20Sopenharmony_ci	mem_layout = ath10k_coredump_get_mem_layout(ar);
14288c2ecf20Sopenharmony_ci	if (!mem_layout)
14298c2ecf20Sopenharmony_ci		return;
14308c2ecf20Sopenharmony_ci
14318c2ecf20Sopenharmony_ci	current_region = &mem_layout->region_table.regions[0];
14328c2ecf20Sopenharmony_ci
14338c2ecf20Sopenharmony_ci	buf = crash_data->ramdump_buf;
14348c2ecf20Sopenharmony_ci	buf_len = crash_data->ramdump_buf_len;
14358c2ecf20Sopenharmony_ci	memset(buf, 0, buf_len);
14368c2ecf20Sopenharmony_ci
14378c2ecf20Sopenharmony_ci	/* Reserve space for the header. */
14388c2ecf20Sopenharmony_ci	hdr = (void *)buf;
14398c2ecf20Sopenharmony_ci	buf += sizeof(*hdr);
14408c2ecf20Sopenharmony_ci	buf_len -= sizeof(*hdr);
14418c2ecf20Sopenharmony_ci
14428c2ecf20Sopenharmony_ci	hdr->region_type = cpu_to_le32(current_region->type);
14438c2ecf20Sopenharmony_ci	hdr->start = cpu_to_le32((unsigned long)ar->msa.vaddr);
14448c2ecf20Sopenharmony_ci	hdr->length = cpu_to_le32(ar->msa.mem_size);
14458c2ecf20Sopenharmony_ci
14468c2ecf20Sopenharmony_ci	if (current_region->len < ar->msa.mem_size) {
14478c2ecf20Sopenharmony_ci		memcpy(buf, ar->msa.vaddr, current_region->len);
14488c2ecf20Sopenharmony_ci		ath10k_warn(ar, "msa dump length is less than msa size %x, %x\n",
14498c2ecf20Sopenharmony_ci			    current_region->len, ar->msa.mem_size);
14508c2ecf20Sopenharmony_ci	} else {
14518c2ecf20Sopenharmony_ci		memcpy(buf, ar->msa.vaddr, ar->msa.mem_size);
14528c2ecf20Sopenharmony_ci	}
14538c2ecf20Sopenharmony_ci}
14548c2ecf20Sopenharmony_ci
14558c2ecf20Sopenharmony_civoid ath10k_snoc_fw_crashed_dump(struct ath10k *ar)
14568c2ecf20Sopenharmony_ci{
14578c2ecf20Sopenharmony_ci	struct ath10k_fw_crash_data *crash_data;
14588c2ecf20Sopenharmony_ci	char guid[UUID_STRING_LEN + 1];
14598c2ecf20Sopenharmony_ci
14608c2ecf20Sopenharmony_ci	mutex_lock(&ar->dump_mutex);
14618c2ecf20Sopenharmony_ci
14628c2ecf20Sopenharmony_ci	spin_lock_bh(&ar->data_lock);
14638c2ecf20Sopenharmony_ci	ar->stats.fw_crash_counter++;
14648c2ecf20Sopenharmony_ci	spin_unlock_bh(&ar->data_lock);
14658c2ecf20Sopenharmony_ci
14668c2ecf20Sopenharmony_ci	crash_data = ath10k_coredump_new(ar);
14678c2ecf20Sopenharmony_ci
14688c2ecf20Sopenharmony_ci	if (crash_data)
14698c2ecf20Sopenharmony_ci		scnprintf(guid, sizeof(guid), "%pUl", &crash_data->guid);
14708c2ecf20Sopenharmony_ci	else
14718c2ecf20Sopenharmony_ci		scnprintf(guid, sizeof(guid), "n/a");
14728c2ecf20Sopenharmony_ci
14738c2ecf20Sopenharmony_ci	ath10k_err(ar, "firmware crashed! (guid %s)\n", guid);
14748c2ecf20Sopenharmony_ci	ath10k_print_driver_info(ar);
14758c2ecf20Sopenharmony_ci	ath10k_msa_dump_memory(ar, crash_data);
14768c2ecf20Sopenharmony_ci	mutex_unlock(&ar->dump_mutex);
14778c2ecf20Sopenharmony_ci}
14788c2ecf20Sopenharmony_ci
14798c2ecf20Sopenharmony_cistatic int ath10k_setup_msa_resources(struct ath10k *ar, u32 msa_size)
14808c2ecf20Sopenharmony_ci{
14818c2ecf20Sopenharmony_ci	struct device *dev = ar->dev;
14828c2ecf20Sopenharmony_ci	struct device_node *node;
14838c2ecf20Sopenharmony_ci	struct resource r;
14848c2ecf20Sopenharmony_ci	int ret;
14858c2ecf20Sopenharmony_ci
14868c2ecf20Sopenharmony_ci	node = of_parse_phandle(dev->of_node, "memory-region", 0);
14878c2ecf20Sopenharmony_ci	if (node) {
14888c2ecf20Sopenharmony_ci		ret = of_address_to_resource(node, 0, &r);
14898c2ecf20Sopenharmony_ci		of_node_put(node);
14908c2ecf20Sopenharmony_ci		if (ret) {
14918c2ecf20Sopenharmony_ci			dev_err(dev, "failed to resolve msa fixed region\n");
14928c2ecf20Sopenharmony_ci			return ret;
14938c2ecf20Sopenharmony_ci		}
14948c2ecf20Sopenharmony_ci
14958c2ecf20Sopenharmony_ci		ar->msa.paddr = r.start;
14968c2ecf20Sopenharmony_ci		ar->msa.mem_size = resource_size(&r);
14978c2ecf20Sopenharmony_ci		ar->msa.vaddr = devm_memremap(dev, ar->msa.paddr,
14988c2ecf20Sopenharmony_ci					      ar->msa.mem_size,
14998c2ecf20Sopenharmony_ci					      MEMREMAP_WT);
15008c2ecf20Sopenharmony_ci		if (IS_ERR(ar->msa.vaddr)) {
15018c2ecf20Sopenharmony_ci			dev_err(dev, "failed to map memory region: %pa\n",
15028c2ecf20Sopenharmony_ci				&r.start);
15038c2ecf20Sopenharmony_ci			return PTR_ERR(ar->msa.vaddr);
15048c2ecf20Sopenharmony_ci		}
15058c2ecf20Sopenharmony_ci	} else {
15068c2ecf20Sopenharmony_ci		ar->msa.vaddr = dmam_alloc_coherent(dev, msa_size,
15078c2ecf20Sopenharmony_ci						    &ar->msa.paddr,
15088c2ecf20Sopenharmony_ci						    GFP_KERNEL);
15098c2ecf20Sopenharmony_ci		if (!ar->msa.vaddr) {
15108c2ecf20Sopenharmony_ci			ath10k_err(ar, "failed to allocate dma memory for msa region\n");
15118c2ecf20Sopenharmony_ci			return -ENOMEM;
15128c2ecf20Sopenharmony_ci		}
15138c2ecf20Sopenharmony_ci		ar->msa.mem_size = msa_size;
15148c2ecf20Sopenharmony_ci	}
15158c2ecf20Sopenharmony_ci
15168c2ecf20Sopenharmony_ci	ath10k_dbg(ar, ATH10K_DBG_QMI, "qmi msa.paddr: %pad , msa.vaddr: 0x%p\n",
15178c2ecf20Sopenharmony_ci		   &ar->msa.paddr,
15188c2ecf20Sopenharmony_ci		   ar->msa.vaddr);
15198c2ecf20Sopenharmony_ci
15208c2ecf20Sopenharmony_ci	return 0;
15218c2ecf20Sopenharmony_ci}
15228c2ecf20Sopenharmony_ci
15238c2ecf20Sopenharmony_cistatic int ath10k_fw_init(struct ath10k *ar)
15248c2ecf20Sopenharmony_ci{
15258c2ecf20Sopenharmony_ci	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
15268c2ecf20Sopenharmony_ci	struct device *host_dev = &ar_snoc->dev->dev;
15278c2ecf20Sopenharmony_ci	struct platform_device_info info;
15288c2ecf20Sopenharmony_ci	struct iommu_domain *iommu_dom;
15298c2ecf20Sopenharmony_ci	struct platform_device *pdev;
15308c2ecf20Sopenharmony_ci	struct device_node *node;
15318c2ecf20Sopenharmony_ci	int ret;
15328c2ecf20Sopenharmony_ci
15338c2ecf20Sopenharmony_ci	node = of_get_child_by_name(host_dev->of_node, "wifi-firmware");
15348c2ecf20Sopenharmony_ci	if (!node) {
15358c2ecf20Sopenharmony_ci		ar_snoc->use_tz = true;
15368c2ecf20Sopenharmony_ci		return 0;
15378c2ecf20Sopenharmony_ci	}
15388c2ecf20Sopenharmony_ci
15398c2ecf20Sopenharmony_ci	memset(&info, 0, sizeof(info));
15408c2ecf20Sopenharmony_ci	info.fwnode = &node->fwnode;
15418c2ecf20Sopenharmony_ci	info.parent = host_dev;
15428c2ecf20Sopenharmony_ci	info.name = node->name;
15438c2ecf20Sopenharmony_ci	info.dma_mask = DMA_BIT_MASK(32);
15448c2ecf20Sopenharmony_ci
15458c2ecf20Sopenharmony_ci	pdev = platform_device_register_full(&info);
15468c2ecf20Sopenharmony_ci	if (IS_ERR(pdev)) {
15478c2ecf20Sopenharmony_ci		of_node_put(node);
15488c2ecf20Sopenharmony_ci		return PTR_ERR(pdev);
15498c2ecf20Sopenharmony_ci	}
15508c2ecf20Sopenharmony_ci
15518c2ecf20Sopenharmony_ci	pdev->dev.of_node = node;
15528c2ecf20Sopenharmony_ci
15538c2ecf20Sopenharmony_ci	ret = of_dma_configure(&pdev->dev, node, true);
15548c2ecf20Sopenharmony_ci	if (ret) {
15558c2ecf20Sopenharmony_ci		ath10k_err(ar, "dma configure fail: %d\n", ret);
15568c2ecf20Sopenharmony_ci		goto err_unregister;
15578c2ecf20Sopenharmony_ci	}
15588c2ecf20Sopenharmony_ci
15598c2ecf20Sopenharmony_ci	ar_snoc->fw.dev = &pdev->dev;
15608c2ecf20Sopenharmony_ci
15618c2ecf20Sopenharmony_ci	iommu_dom = iommu_domain_alloc(&platform_bus_type);
15628c2ecf20Sopenharmony_ci	if (!iommu_dom) {
15638c2ecf20Sopenharmony_ci		ath10k_err(ar, "failed to allocate iommu domain\n");
15648c2ecf20Sopenharmony_ci		ret = -ENOMEM;
15658c2ecf20Sopenharmony_ci		goto err_unregister;
15668c2ecf20Sopenharmony_ci	}
15678c2ecf20Sopenharmony_ci
15688c2ecf20Sopenharmony_ci	ret = iommu_attach_device(iommu_dom, ar_snoc->fw.dev);
15698c2ecf20Sopenharmony_ci	if (ret) {
15708c2ecf20Sopenharmony_ci		ath10k_err(ar, "could not attach device: %d\n", ret);
15718c2ecf20Sopenharmony_ci		goto err_iommu_free;
15728c2ecf20Sopenharmony_ci	}
15738c2ecf20Sopenharmony_ci
15748c2ecf20Sopenharmony_ci	ar_snoc->fw.iommu_domain = iommu_dom;
15758c2ecf20Sopenharmony_ci	ar_snoc->fw.fw_start_addr = ar->msa.paddr;
15768c2ecf20Sopenharmony_ci
15778c2ecf20Sopenharmony_ci	ret = iommu_map(iommu_dom, ar_snoc->fw.fw_start_addr,
15788c2ecf20Sopenharmony_ci			ar->msa.paddr, ar->msa.mem_size,
15798c2ecf20Sopenharmony_ci			IOMMU_READ | IOMMU_WRITE);
15808c2ecf20Sopenharmony_ci	if (ret) {
15818c2ecf20Sopenharmony_ci		ath10k_err(ar, "failed to map firmware region: %d\n", ret);
15828c2ecf20Sopenharmony_ci		goto err_iommu_detach;
15838c2ecf20Sopenharmony_ci	}
15848c2ecf20Sopenharmony_ci
15858c2ecf20Sopenharmony_ci	of_node_put(node);
15868c2ecf20Sopenharmony_ci
15878c2ecf20Sopenharmony_ci	return 0;
15888c2ecf20Sopenharmony_ci
15898c2ecf20Sopenharmony_cierr_iommu_detach:
15908c2ecf20Sopenharmony_ci	iommu_detach_device(iommu_dom, ar_snoc->fw.dev);
15918c2ecf20Sopenharmony_ci
15928c2ecf20Sopenharmony_cierr_iommu_free:
15938c2ecf20Sopenharmony_ci	iommu_domain_free(iommu_dom);
15948c2ecf20Sopenharmony_ci
15958c2ecf20Sopenharmony_cierr_unregister:
15968c2ecf20Sopenharmony_ci	platform_device_unregister(pdev);
15978c2ecf20Sopenharmony_ci	of_node_put(node);
15988c2ecf20Sopenharmony_ci
15998c2ecf20Sopenharmony_ci	return ret;
16008c2ecf20Sopenharmony_ci}
16018c2ecf20Sopenharmony_ci
16028c2ecf20Sopenharmony_cistatic int ath10k_fw_deinit(struct ath10k *ar)
16038c2ecf20Sopenharmony_ci{
16048c2ecf20Sopenharmony_ci	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
16058c2ecf20Sopenharmony_ci	const size_t mapped_size = ar_snoc->fw.mapped_mem_size;
16068c2ecf20Sopenharmony_ci	struct iommu_domain *iommu;
16078c2ecf20Sopenharmony_ci	size_t unmapped_size;
16088c2ecf20Sopenharmony_ci
16098c2ecf20Sopenharmony_ci	if (ar_snoc->use_tz)
16108c2ecf20Sopenharmony_ci		return 0;
16118c2ecf20Sopenharmony_ci
16128c2ecf20Sopenharmony_ci	iommu = ar_snoc->fw.iommu_domain;
16138c2ecf20Sopenharmony_ci
16148c2ecf20Sopenharmony_ci	unmapped_size = iommu_unmap(iommu, ar_snoc->fw.fw_start_addr,
16158c2ecf20Sopenharmony_ci				    mapped_size);
16168c2ecf20Sopenharmony_ci	if (unmapped_size != mapped_size)
16178c2ecf20Sopenharmony_ci		ath10k_err(ar, "failed to unmap firmware: %zu\n",
16188c2ecf20Sopenharmony_ci			   unmapped_size);
16198c2ecf20Sopenharmony_ci
16208c2ecf20Sopenharmony_ci	iommu_detach_device(iommu, ar_snoc->fw.dev);
16218c2ecf20Sopenharmony_ci	iommu_domain_free(iommu);
16228c2ecf20Sopenharmony_ci
16238c2ecf20Sopenharmony_ci	platform_device_unregister(to_platform_device(ar_snoc->fw.dev));
16248c2ecf20Sopenharmony_ci
16258c2ecf20Sopenharmony_ci	return 0;
16268c2ecf20Sopenharmony_ci}
16278c2ecf20Sopenharmony_ci
16288c2ecf20Sopenharmony_cistatic const struct of_device_id ath10k_snoc_dt_match[] = {
16298c2ecf20Sopenharmony_ci	{ .compatible = "qcom,wcn3990-wifi",
16308c2ecf20Sopenharmony_ci	 .data = &drv_priv,
16318c2ecf20Sopenharmony_ci	},
16328c2ecf20Sopenharmony_ci	{ }
16338c2ecf20Sopenharmony_ci};
16348c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, ath10k_snoc_dt_match);
16358c2ecf20Sopenharmony_ci
16368c2ecf20Sopenharmony_cistatic int ath10k_snoc_probe(struct platform_device *pdev)
16378c2ecf20Sopenharmony_ci{
16388c2ecf20Sopenharmony_ci	const struct ath10k_snoc_drv_priv *drv_data;
16398c2ecf20Sopenharmony_ci	struct ath10k_snoc *ar_snoc;
16408c2ecf20Sopenharmony_ci	struct device *dev;
16418c2ecf20Sopenharmony_ci	struct ath10k *ar;
16428c2ecf20Sopenharmony_ci	u32 msa_size;
16438c2ecf20Sopenharmony_ci	int ret;
16448c2ecf20Sopenharmony_ci	u32 i;
16458c2ecf20Sopenharmony_ci
16468c2ecf20Sopenharmony_ci	dev = &pdev->dev;
16478c2ecf20Sopenharmony_ci	drv_data = device_get_match_data(dev);
16488c2ecf20Sopenharmony_ci	if (!drv_data) {
16498c2ecf20Sopenharmony_ci		dev_err(dev, "failed to find matching device tree id\n");
16508c2ecf20Sopenharmony_ci		return -EINVAL;
16518c2ecf20Sopenharmony_ci	}
16528c2ecf20Sopenharmony_ci
16538c2ecf20Sopenharmony_ci	ret = dma_set_mask_and_coherent(dev, drv_data->dma_mask);
16548c2ecf20Sopenharmony_ci	if (ret) {
16558c2ecf20Sopenharmony_ci		dev_err(dev, "failed to set dma mask: %d\n", ret);
16568c2ecf20Sopenharmony_ci		return ret;
16578c2ecf20Sopenharmony_ci	}
16588c2ecf20Sopenharmony_ci
16598c2ecf20Sopenharmony_ci	ar = ath10k_core_create(sizeof(*ar_snoc), dev, ATH10K_BUS_SNOC,
16608c2ecf20Sopenharmony_ci				drv_data->hw_rev, &ath10k_snoc_hif_ops);
16618c2ecf20Sopenharmony_ci	if (!ar) {
16628c2ecf20Sopenharmony_ci		dev_err(dev, "failed to allocate core\n");
16638c2ecf20Sopenharmony_ci		return -ENOMEM;
16648c2ecf20Sopenharmony_ci	}
16658c2ecf20Sopenharmony_ci
16668c2ecf20Sopenharmony_ci	ar_snoc = ath10k_snoc_priv(ar);
16678c2ecf20Sopenharmony_ci	ar_snoc->dev = pdev;
16688c2ecf20Sopenharmony_ci	platform_set_drvdata(pdev, ar);
16698c2ecf20Sopenharmony_ci	ar_snoc->ar = ar;
16708c2ecf20Sopenharmony_ci	ar_snoc->ce.bus_ops = &ath10k_snoc_bus_ops;
16718c2ecf20Sopenharmony_ci	ar->ce_priv = &ar_snoc->ce;
16728c2ecf20Sopenharmony_ci	msa_size = drv_data->msa_size;
16738c2ecf20Sopenharmony_ci
16748c2ecf20Sopenharmony_ci	ath10k_snoc_quirks_init(ar);
16758c2ecf20Sopenharmony_ci
16768c2ecf20Sopenharmony_ci	ret = ath10k_snoc_resource_init(ar);
16778c2ecf20Sopenharmony_ci	if (ret) {
16788c2ecf20Sopenharmony_ci		ath10k_warn(ar, "failed to initialize resource: %d\n", ret);
16798c2ecf20Sopenharmony_ci		goto err_core_destroy;
16808c2ecf20Sopenharmony_ci	}
16818c2ecf20Sopenharmony_ci
16828c2ecf20Sopenharmony_ci	ret = ath10k_snoc_setup_resource(ar);
16838c2ecf20Sopenharmony_ci	if (ret) {
16848c2ecf20Sopenharmony_ci		ath10k_warn(ar, "failed to setup resource: %d\n", ret);
16858c2ecf20Sopenharmony_ci		goto err_core_destroy;
16868c2ecf20Sopenharmony_ci	}
16878c2ecf20Sopenharmony_ci	ret = ath10k_snoc_request_irq(ar);
16888c2ecf20Sopenharmony_ci	if (ret) {
16898c2ecf20Sopenharmony_ci		ath10k_warn(ar, "failed to request irqs: %d\n", ret);
16908c2ecf20Sopenharmony_ci		goto err_release_resource;
16918c2ecf20Sopenharmony_ci	}
16928c2ecf20Sopenharmony_ci
16938c2ecf20Sopenharmony_ci	ar_snoc->num_vregs = ARRAY_SIZE(ath10k_regulators);
16948c2ecf20Sopenharmony_ci	ar_snoc->vregs = devm_kcalloc(&pdev->dev, ar_snoc->num_vregs,
16958c2ecf20Sopenharmony_ci				      sizeof(*ar_snoc->vregs), GFP_KERNEL);
16968c2ecf20Sopenharmony_ci	if (!ar_snoc->vregs) {
16978c2ecf20Sopenharmony_ci		ret = -ENOMEM;
16988c2ecf20Sopenharmony_ci		goto err_free_irq;
16998c2ecf20Sopenharmony_ci	}
17008c2ecf20Sopenharmony_ci	for (i = 0; i < ar_snoc->num_vregs; i++)
17018c2ecf20Sopenharmony_ci		ar_snoc->vregs[i].supply = ath10k_regulators[i];
17028c2ecf20Sopenharmony_ci
17038c2ecf20Sopenharmony_ci	ret = devm_regulator_bulk_get(&pdev->dev, ar_snoc->num_vregs,
17048c2ecf20Sopenharmony_ci				      ar_snoc->vregs);
17058c2ecf20Sopenharmony_ci	if (ret < 0)
17068c2ecf20Sopenharmony_ci		goto err_free_irq;
17078c2ecf20Sopenharmony_ci
17088c2ecf20Sopenharmony_ci	ar_snoc->num_clks = ARRAY_SIZE(ath10k_clocks);
17098c2ecf20Sopenharmony_ci	ar_snoc->clks = devm_kcalloc(&pdev->dev, ar_snoc->num_clks,
17108c2ecf20Sopenharmony_ci				     sizeof(*ar_snoc->clks), GFP_KERNEL);
17118c2ecf20Sopenharmony_ci	if (!ar_snoc->clks) {
17128c2ecf20Sopenharmony_ci		ret = -ENOMEM;
17138c2ecf20Sopenharmony_ci		goto err_free_irq;
17148c2ecf20Sopenharmony_ci	}
17158c2ecf20Sopenharmony_ci
17168c2ecf20Sopenharmony_ci	for (i = 0; i < ar_snoc->num_clks; i++)
17178c2ecf20Sopenharmony_ci		ar_snoc->clks[i].id = ath10k_clocks[i];
17188c2ecf20Sopenharmony_ci
17198c2ecf20Sopenharmony_ci	ret = devm_clk_bulk_get_optional(&pdev->dev, ar_snoc->num_clks,
17208c2ecf20Sopenharmony_ci					 ar_snoc->clks);
17218c2ecf20Sopenharmony_ci	if (ret)
17228c2ecf20Sopenharmony_ci		goto err_free_irq;
17238c2ecf20Sopenharmony_ci
17248c2ecf20Sopenharmony_ci	ret = ath10k_hw_power_on(ar);
17258c2ecf20Sopenharmony_ci	if (ret) {
17268c2ecf20Sopenharmony_ci		ath10k_err(ar, "failed to power on device: %d\n", ret);
17278c2ecf20Sopenharmony_ci		goto err_free_irq;
17288c2ecf20Sopenharmony_ci	}
17298c2ecf20Sopenharmony_ci
17308c2ecf20Sopenharmony_ci	ret = ath10k_setup_msa_resources(ar, msa_size);
17318c2ecf20Sopenharmony_ci	if (ret) {
17328c2ecf20Sopenharmony_ci		ath10k_warn(ar, "failed to setup msa resources: %d\n", ret);
17338c2ecf20Sopenharmony_ci		goto err_power_off;
17348c2ecf20Sopenharmony_ci	}
17358c2ecf20Sopenharmony_ci
17368c2ecf20Sopenharmony_ci	ret = ath10k_fw_init(ar);
17378c2ecf20Sopenharmony_ci	if (ret) {
17388c2ecf20Sopenharmony_ci		ath10k_err(ar, "failed to initialize firmware: %d\n", ret);
17398c2ecf20Sopenharmony_ci		goto err_power_off;
17408c2ecf20Sopenharmony_ci	}
17418c2ecf20Sopenharmony_ci
17428c2ecf20Sopenharmony_ci	ret = ath10k_qmi_init(ar, msa_size);
17438c2ecf20Sopenharmony_ci	if (ret) {
17448c2ecf20Sopenharmony_ci		ath10k_warn(ar, "failed to register wlfw qmi client: %d\n", ret);
17458c2ecf20Sopenharmony_ci		goto err_fw_deinit;
17468c2ecf20Sopenharmony_ci	}
17478c2ecf20Sopenharmony_ci
17488c2ecf20Sopenharmony_ci	ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc probe\n");
17498c2ecf20Sopenharmony_ci
17508c2ecf20Sopenharmony_ci	return 0;
17518c2ecf20Sopenharmony_ci
17528c2ecf20Sopenharmony_cierr_fw_deinit:
17538c2ecf20Sopenharmony_ci	ath10k_fw_deinit(ar);
17548c2ecf20Sopenharmony_ci
17558c2ecf20Sopenharmony_cierr_power_off:
17568c2ecf20Sopenharmony_ci	ath10k_hw_power_off(ar);
17578c2ecf20Sopenharmony_ci
17588c2ecf20Sopenharmony_cierr_free_irq:
17598c2ecf20Sopenharmony_ci	ath10k_snoc_free_irq(ar);
17608c2ecf20Sopenharmony_ci
17618c2ecf20Sopenharmony_cierr_release_resource:
17628c2ecf20Sopenharmony_ci	ath10k_snoc_release_resource(ar);
17638c2ecf20Sopenharmony_ci
17648c2ecf20Sopenharmony_cierr_core_destroy:
17658c2ecf20Sopenharmony_ci	ath10k_core_destroy(ar);
17668c2ecf20Sopenharmony_ci
17678c2ecf20Sopenharmony_ci	return ret;
17688c2ecf20Sopenharmony_ci}
17698c2ecf20Sopenharmony_ci
17708c2ecf20Sopenharmony_cistatic int ath10k_snoc_remove(struct platform_device *pdev)
17718c2ecf20Sopenharmony_ci{
17728c2ecf20Sopenharmony_ci	struct ath10k *ar = platform_get_drvdata(pdev);
17738c2ecf20Sopenharmony_ci	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
17748c2ecf20Sopenharmony_ci
17758c2ecf20Sopenharmony_ci	ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc remove\n");
17768c2ecf20Sopenharmony_ci
17778c2ecf20Sopenharmony_ci	reinit_completion(&ar->driver_recovery);
17788c2ecf20Sopenharmony_ci
17798c2ecf20Sopenharmony_ci	if (test_bit(ATH10K_SNOC_FLAG_RECOVERY, &ar_snoc->flags))
17808c2ecf20Sopenharmony_ci		wait_for_completion_timeout(&ar->driver_recovery, 3 * HZ);
17818c2ecf20Sopenharmony_ci
17828c2ecf20Sopenharmony_ci	set_bit(ATH10K_SNOC_FLAG_UNREGISTERING, &ar_snoc->flags);
17838c2ecf20Sopenharmony_ci
17848c2ecf20Sopenharmony_ci	ath10k_core_unregister(ar);
17858c2ecf20Sopenharmony_ci	ath10k_hw_power_off(ar);
17868c2ecf20Sopenharmony_ci	ath10k_fw_deinit(ar);
17878c2ecf20Sopenharmony_ci	ath10k_snoc_free_irq(ar);
17888c2ecf20Sopenharmony_ci	ath10k_snoc_release_resource(ar);
17898c2ecf20Sopenharmony_ci	ath10k_qmi_deinit(ar);
17908c2ecf20Sopenharmony_ci	ath10k_core_destroy(ar);
17918c2ecf20Sopenharmony_ci
17928c2ecf20Sopenharmony_ci	return 0;
17938c2ecf20Sopenharmony_ci}
17948c2ecf20Sopenharmony_ci
17958c2ecf20Sopenharmony_cistatic void ath10k_snoc_shutdown(struct platform_device *pdev)
17968c2ecf20Sopenharmony_ci{
17978c2ecf20Sopenharmony_ci	struct ath10k *ar = platform_get_drvdata(pdev);
17988c2ecf20Sopenharmony_ci
17998c2ecf20Sopenharmony_ci	ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc shutdown\n");
18008c2ecf20Sopenharmony_ci	ath10k_snoc_remove(pdev);
18018c2ecf20Sopenharmony_ci}
18028c2ecf20Sopenharmony_ci
18038c2ecf20Sopenharmony_cistatic struct platform_driver ath10k_snoc_driver = {
18048c2ecf20Sopenharmony_ci	.probe  = ath10k_snoc_probe,
18058c2ecf20Sopenharmony_ci	.remove = ath10k_snoc_remove,
18068c2ecf20Sopenharmony_ci	.shutdown =  ath10k_snoc_shutdown,
18078c2ecf20Sopenharmony_ci	.driver = {
18088c2ecf20Sopenharmony_ci		.name   = "ath10k_snoc",
18098c2ecf20Sopenharmony_ci		.of_match_table = ath10k_snoc_dt_match,
18108c2ecf20Sopenharmony_ci	},
18118c2ecf20Sopenharmony_ci};
18128c2ecf20Sopenharmony_cimodule_platform_driver(ath10k_snoc_driver);
18138c2ecf20Sopenharmony_ci
18148c2ecf20Sopenharmony_ciMODULE_AUTHOR("Qualcomm");
18158c2ecf20Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL");
18168c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Driver support for Atheros WCN3990 SNOC devices");
1817