xref: /openbmc/linux/drivers/net/wireless/ath/ath11k/pci.c (revision 0cfaf2243e9eef8ed32cdde6467a7e123a9f915f)
16e0355afSGovind Singh // SPDX-License-Identifier: BSD-3-Clause-Clear
26e0355afSGovind Singh /*
36e0355afSGovind Singh  * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved.
4948171b5SManikanta Pubbisetty  * Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc. All rights reserved.
56e0355afSGovind Singh  */
66e0355afSGovind Singh 
76e0355afSGovind Singh #include <linux/module.h>
85697a564SGovind Singh #include <linux/msi.h>
96e0355afSGovind Singh #include <linux/pci.h>
106ac04bdcSAnilkumar Kolli #include <linux/of.h>
116e0355afSGovind Singh 
125762613eSGovind Singh #include "pci.h"
136e0355afSGovind Singh #include "core.h"
141399fb87SGovind Singh #include "hif.h"
151399fb87SGovind Singh #include "mhi.h"
166e0355afSGovind Singh #include "debug.h"
17bbfdc5a7SManikanta Pubbisetty #include "pcic.h"
186e0355afSGovind Singh 
195762613eSGovind Singh #define ATH11K_PCI_BAR_NUM		0
205762613eSGovind Singh #define ATH11K_PCI_DMA_MASK		32
215762613eSGovind Singh 
2218ac1665SKalle Valo #define TCSR_SOC_HW_VERSION		0x0224
23d1147a31SBaochen Qiang #define TCSR_SOC_HW_VERSION_MAJOR_MASK	GENMASK(11, 8)
2418ac1665SKalle Valo #define TCSR_SOC_HW_VERSION_MINOR_MASK	GENMASK(7, 0)
2518ac1665SKalle Valo 
266e0355afSGovind Singh #define QCA6390_DEVICE_ID		0x1101
274e809461SAnilkumar Kolli #define QCN9074_DEVICE_ID		0x1104
280fbf1957SBaochen Qiang #define WCN6855_DEVICE_ID		0x1103
296e0355afSGovind Singh 
306e0355afSGovind Singh static const struct pci_device_id ath11k_pci_id_table[] = {
316e0355afSGovind Singh 	{ PCI_VDEVICE(QCOM, QCA6390_DEVICE_ID) },
320fbf1957SBaochen Qiang 	{ PCI_VDEVICE(QCOM, WCN6855_DEVICE_ID) },
3349f5b114SAnilkumar Kolli 	{ PCI_VDEVICE(QCOM, QCN9074_DEVICE_ID) },
346e0355afSGovind Singh 	{0}
356e0355afSGovind Singh };
366e0355afSGovind Singh 
376e0355afSGovind Singh MODULE_DEVICE_TABLE(pci, ath11k_pci_id_table);
386e0355afSGovind Singh 
391ff8ed78SGovind Singh static const struct ath11k_bus_params ath11k_pci_bus_params = {
401ff8ed78SGovind Singh 	.mhi_support = true,
4156970454SGovind Singh 	.m3_fw_support = true,
426eb6ea51SGovind Singh 	.fixed_bdf_addr = false,
436eb6ea51SGovind Singh 	.fixed_mem_region = false,
441ff8ed78SGovind Singh };
451ff8ed78SGovind Singh 
46ac6e7348SCarl Huang static const struct ath11k_msi_config msi_config_one_msi = {
47ac6e7348SCarl Huang 	.total_vectors = 1,
48ac6e7348SCarl Huang 	.total_users = 4,
49ac6e7348SCarl Huang 	.users = (struct ath11k_msi_user[]) {
50ac6e7348SCarl Huang 		{ .name = "MHI", .num_vectors = 3, .base_vector = 0 },
51ac6e7348SCarl Huang 		{ .name = "CE", .num_vectors = 1, .base_vector = 0 },
52ac6e7348SCarl Huang 		{ .name = "WAKE", .num_vectors = 1, .base_vector = 0 },
53ac6e7348SCarl Huang 		{ .name = "DP", .num_vectors = 1, .base_vector = 0 },
54ac6e7348SCarl Huang 	},
55ac6e7348SCarl Huang };
56ac6e7348SCarl Huang 
57480a7361SKarthikeyan Periyasamy static inline void ath11k_pci_select_static_window(struct ath11k_pci *ab_pci)
58480a7361SKarthikeyan Periyasamy {
59948171b5SManikanta Pubbisetty 	u32 umac_window;
60948171b5SManikanta Pubbisetty 	u32 ce_window;
61480a7361SKarthikeyan Periyasamy 	u32 window;
62480a7361SKarthikeyan Periyasamy 
63948171b5SManikanta Pubbisetty 	umac_window = FIELD_GET(ATH11K_PCI_WINDOW_VALUE_MASK, HAL_SEQ_WCSS_UMAC_OFFSET);
64948171b5SManikanta Pubbisetty 	ce_window = FIELD_GET(ATH11K_PCI_WINDOW_VALUE_MASK, HAL_CE_WFSS_CE_REG_BASE);
65480a7361SKarthikeyan Periyasamy 	window = (umac_window << 12) | (ce_window << 6);
66480a7361SKarthikeyan Periyasamy 
67948171b5SManikanta Pubbisetty 	iowrite32(ATH11K_PCI_WINDOW_ENABLE_BIT | window,
68948171b5SManikanta Pubbisetty 		  ab_pci->ab->mem + ATH11K_PCI_WINDOW_REG_ADDRESS);
69480a7361SKarthikeyan Periyasamy }
70480a7361SKarthikeyan Periyasamy 
71f3c603d4SCarl Huang static void ath11k_pci_soc_global_reset(struct ath11k_base *ab)
72f3c603d4SCarl Huang {
73f3c603d4SCarl Huang 	u32 val, delay;
74f3c603d4SCarl Huang 
75bbfdc5a7SManikanta Pubbisetty 	val = ath11k_pcic_read32(ab, PCIE_SOC_GLOBAL_RESET);
76f3c603d4SCarl Huang 
77f3c603d4SCarl Huang 	val |= PCIE_SOC_GLOBAL_RESET_V;
78f3c603d4SCarl Huang 
79bbfdc5a7SManikanta Pubbisetty 	ath11k_pcic_write32(ab, PCIE_SOC_GLOBAL_RESET, val);
80f3c603d4SCarl Huang 
81f3c603d4SCarl Huang 	/* TODO: exact time to sleep is uncertain */
82f3c603d4SCarl Huang 	delay = 10;
83f3c603d4SCarl Huang 	mdelay(delay);
84f3c603d4SCarl Huang 
85f3c603d4SCarl Huang 	/* Need to toggle V bit back otherwise stuck in reset status */
86f3c603d4SCarl Huang 	val &= ~PCIE_SOC_GLOBAL_RESET_V;
87f3c603d4SCarl Huang 
88bbfdc5a7SManikanta Pubbisetty 	ath11k_pcic_write32(ab, PCIE_SOC_GLOBAL_RESET, val);
89f3c603d4SCarl Huang 
90f3c603d4SCarl Huang 	mdelay(delay);
91f3c603d4SCarl Huang 
92bbfdc5a7SManikanta Pubbisetty 	val = ath11k_pcic_read32(ab, PCIE_SOC_GLOBAL_RESET);
93f3c603d4SCarl Huang 	if (val == 0xffffffff)
94f3c603d4SCarl Huang 		ath11k_warn(ab, "link down error during global reset\n");
95f3c603d4SCarl Huang }
96f3c603d4SCarl Huang 
97f3c603d4SCarl Huang static void ath11k_pci_clear_dbg_registers(struct ath11k_base *ab)
98f3c603d4SCarl Huang {
99f3c603d4SCarl Huang 	u32 val;
100f3c603d4SCarl Huang 
101f3c603d4SCarl Huang 	/* read cookie */
102bbfdc5a7SManikanta Pubbisetty 	val = ath11k_pcic_read32(ab, PCIE_Q6_COOKIE_ADDR);
103f3c603d4SCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "cookie:0x%x\n", val);
104f3c603d4SCarl Huang 
105bbfdc5a7SManikanta Pubbisetty 	val = ath11k_pcic_read32(ab, WLAON_WARM_SW_ENTRY);
106f3c603d4SCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "WLAON_WARM_SW_ENTRY 0x%x\n", val);
107f3c603d4SCarl Huang 
108f3c603d4SCarl Huang 	/* TODO: exact time to sleep is uncertain */
109f3c603d4SCarl Huang 	mdelay(10);
110f3c603d4SCarl Huang 
111f3c603d4SCarl Huang 	/* write 0 to WLAON_WARM_SW_ENTRY to prevent Q6 from
112f3c603d4SCarl Huang 	 * continuing warm path and entering dead loop.
113f3c603d4SCarl Huang 	 */
114bbfdc5a7SManikanta Pubbisetty 	ath11k_pcic_write32(ab, WLAON_WARM_SW_ENTRY, 0);
115f3c603d4SCarl Huang 	mdelay(10);
116f3c603d4SCarl Huang 
117bbfdc5a7SManikanta Pubbisetty 	val = ath11k_pcic_read32(ab, WLAON_WARM_SW_ENTRY);
118f3c603d4SCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "WLAON_WARM_SW_ENTRY 0x%x\n", val);
119f3c603d4SCarl Huang 
120f3c603d4SCarl Huang 	/* A read clear register. clear the register to prevent
121f3c603d4SCarl Huang 	 * Q6 from entering wrong code path.
122f3c603d4SCarl Huang 	 */
123bbfdc5a7SManikanta Pubbisetty 	val = ath11k_pcic_read32(ab, WLAON_SOC_RESET_CAUSE_REG);
124f3c603d4SCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "soc reset cause:%d\n", val);
125f3c603d4SCarl Huang }
126f3c603d4SCarl Huang 
12706999407SCarl Huang static int ath11k_pci_set_link_reg(struct ath11k_base *ab,
12806999407SCarl Huang 				   u32 offset, u32 value, u32 mask)
12906999407SCarl Huang {
13006999407SCarl Huang 	u32 v;
13106999407SCarl Huang 	int i;
13206999407SCarl Huang 
133bbfdc5a7SManikanta Pubbisetty 	v = ath11k_pcic_read32(ab, offset);
13406999407SCarl Huang 	if ((v & mask) == value)
13506999407SCarl Huang 		return 0;
13606999407SCarl Huang 
13706999407SCarl Huang 	for (i = 0; i < 10; i++) {
138bbfdc5a7SManikanta Pubbisetty 		ath11k_pcic_write32(ab, offset, (v & ~mask) | value);
13906999407SCarl Huang 
140bbfdc5a7SManikanta Pubbisetty 		v = ath11k_pcic_read32(ab, offset);
14106999407SCarl Huang 		if ((v & mask) == value)
14206999407SCarl Huang 			return 0;
14306999407SCarl Huang 
14406999407SCarl Huang 		mdelay(2);
14506999407SCarl Huang 	}
14606999407SCarl Huang 
14706999407SCarl Huang 	ath11k_warn(ab, "failed to set pcie link register 0x%08x: 0x%08x != 0x%08x\n",
14806999407SCarl Huang 		    offset, v & mask, value);
14906999407SCarl Huang 
15006999407SCarl Huang 	return -ETIMEDOUT;
15106999407SCarl Huang }
15206999407SCarl Huang 
15306999407SCarl Huang static int ath11k_pci_fix_l1ss(struct ath11k_base *ab)
15406999407SCarl Huang {
15506999407SCarl Huang 	int ret;
15606999407SCarl Huang 
15706999407SCarl Huang 	ret = ath11k_pci_set_link_reg(ab,
1586fe6f68fSKarthikeyan Periyasamy 				      PCIE_QSERDES_COM_SYSCLK_EN_SEL_REG(ab),
15906999407SCarl Huang 				      PCIE_QSERDES_COM_SYSCLK_EN_SEL_VAL,
16006999407SCarl Huang 				      PCIE_QSERDES_COM_SYSCLK_EN_SEL_MSK);
16130d08503SDan Carpenter 	if (ret) {
16206999407SCarl Huang 		ath11k_warn(ab, "failed to set sysclk: %d\n", ret);
16306999407SCarl Huang 		return ret;
16406999407SCarl Huang 	}
16506999407SCarl Huang 
16606999407SCarl Huang 	ret = ath11k_pci_set_link_reg(ab,
1676fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG1_REG(ab),
1686fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG1_VAL,
1696fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG_MSK);
17030d08503SDan Carpenter 	if (ret) {
17106999407SCarl Huang 		ath11k_warn(ab, "failed to set dtct config1 error: %d\n", ret);
17206999407SCarl Huang 		return ret;
17306999407SCarl Huang 	}
17406999407SCarl Huang 
17506999407SCarl Huang 	ret = ath11k_pci_set_link_reg(ab,
1766fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG2_REG(ab),
1776fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG2_VAL,
1786fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG_MSK);
17930d08503SDan Carpenter 	if (ret) {
18006999407SCarl Huang 		ath11k_warn(ab, "failed to set dtct config2: %d\n", ret);
18106999407SCarl Huang 		return ret;
18206999407SCarl Huang 	}
18306999407SCarl Huang 
18406999407SCarl Huang 	ret = ath11k_pci_set_link_reg(ab,
1856fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG4_REG(ab),
1866fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG4_VAL,
1876fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG_MSK);
18830d08503SDan Carpenter 	if (ret) {
18906999407SCarl Huang 		ath11k_warn(ab, "failed to set dtct config4: %d\n", ret);
19006999407SCarl Huang 		return ret;
19106999407SCarl Huang 	}
19206999407SCarl Huang 
19306999407SCarl Huang 	return 0;
19406999407SCarl Huang }
19506999407SCarl Huang 
196babb0cedSCarl Huang static void ath11k_pci_enable_ltssm(struct ath11k_base *ab)
197babb0cedSCarl Huang {
198babb0cedSCarl Huang 	u32 val;
199babb0cedSCarl Huang 	int i;
200babb0cedSCarl Huang 
201bbfdc5a7SManikanta Pubbisetty 	val = ath11k_pcic_read32(ab, PCIE_PCIE_PARF_LTSSM);
202babb0cedSCarl Huang 
203babb0cedSCarl Huang 	/* PCIE link seems very unstable after the Hot Reset*/
204babb0cedSCarl Huang 	for (i = 0; val != PARM_LTSSM_VALUE && i < 5; i++) {
205babb0cedSCarl Huang 		if (val == 0xffffffff)
206babb0cedSCarl Huang 			mdelay(5);
207babb0cedSCarl Huang 
208bbfdc5a7SManikanta Pubbisetty 		ath11k_pcic_write32(ab, PCIE_PCIE_PARF_LTSSM, PARM_LTSSM_VALUE);
209bbfdc5a7SManikanta Pubbisetty 		val = ath11k_pcic_read32(ab, PCIE_PCIE_PARF_LTSSM);
210babb0cedSCarl Huang 	}
211babb0cedSCarl Huang 
212babb0cedSCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "pci ltssm 0x%x\n", val);
213babb0cedSCarl Huang 
214bbfdc5a7SManikanta Pubbisetty 	val = ath11k_pcic_read32(ab, GCC_GCC_PCIE_HOT_RST);
215562934adSKalle Valo 	val |= GCC_GCC_PCIE_HOT_RST_VAL;
216bbfdc5a7SManikanta Pubbisetty 	ath11k_pcic_write32(ab, GCC_GCC_PCIE_HOT_RST, val);
217bbfdc5a7SManikanta Pubbisetty 	val = ath11k_pcic_read32(ab, GCC_GCC_PCIE_HOT_RST);
218babb0cedSCarl Huang 
219babb0cedSCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "pci pcie_hot_rst 0x%x\n", val);
220babb0cedSCarl Huang 
221babb0cedSCarl Huang 	mdelay(5);
222babb0cedSCarl Huang }
223babb0cedSCarl Huang 
224babb0cedSCarl Huang static void ath11k_pci_clear_all_intrs(struct ath11k_base *ab)
225babb0cedSCarl Huang {
226babb0cedSCarl Huang 	/* This is a WAR for PCIE Hotreset.
227babb0cedSCarl Huang 	 * When target receive Hotreset, but will set the interrupt.
228babb0cedSCarl Huang 	 * So when download SBL again, SBL will open Interrupt and
229babb0cedSCarl Huang 	 * receive it, and crash immediately.
230babb0cedSCarl Huang 	 */
231bbfdc5a7SManikanta Pubbisetty 	ath11k_pcic_write32(ab, PCIE_PCIE_INT_ALL_CLEAR, PCIE_INT_CLEAR_ALL);
232babb0cedSCarl Huang }
233babb0cedSCarl Huang 
2340ccdf439SCarl Huang static void ath11k_pci_set_wlaon_pwr_ctrl(struct ath11k_base *ab)
2350ccdf439SCarl Huang {
2360ccdf439SCarl Huang 	u32 val;
2370ccdf439SCarl Huang 
238bbfdc5a7SManikanta Pubbisetty 	val = ath11k_pcic_read32(ab, WLAON_QFPROM_PWR_CTRL_REG);
2390ccdf439SCarl Huang 	val &= ~QFPROM_PWR_CTRL_VDD4BLOW_MASK;
240bbfdc5a7SManikanta Pubbisetty 	ath11k_pcic_write32(ab, WLAON_QFPROM_PWR_CTRL_REG, val);
2410ccdf439SCarl Huang }
2420ccdf439SCarl Huang 
243f3c603d4SCarl Huang static void ath11k_pci_force_wake(struct ath11k_base *ab)
244f3c603d4SCarl Huang {
245bbfdc5a7SManikanta Pubbisetty 	ath11k_pcic_write32(ab, PCIE_SOC_WAKE_PCIE_LOCAL_REG, 1);
246f3c603d4SCarl Huang 	mdelay(5);
247f3c603d4SCarl Huang }
248f3c603d4SCarl Huang 
249babb0cedSCarl Huang static void ath11k_pci_sw_reset(struct ath11k_base *ab, bool power_on)
250f3c603d4SCarl Huang {
2518a0b899fSBaochen Qiang 	mdelay(100);
2528a0b899fSBaochen Qiang 
253babb0cedSCarl Huang 	if (power_on) {
254babb0cedSCarl Huang 		ath11k_pci_enable_ltssm(ab);
255babb0cedSCarl Huang 		ath11k_pci_clear_all_intrs(ab);
2560ccdf439SCarl Huang 		ath11k_pci_set_wlaon_pwr_ctrl(ab);
2575088df05SBaochen Qiang 		if (ab->hw_params.fix_l1ss)
25806999407SCarl Huang 			ath11k_pci_fix_l1ss(ab);
259babb0cedSCarl Huang 	}
260babb0cedSCarl Huang 
261f3c603d4SCarl Huang 	ath11k_mhi_clear_vector(ab);
2628a0b899fSBaochen Qiang 	ath11k_pci_clear_dbg_registers(ab);
263f3c603d4SCarl Huang 	ath11k_pci_soc_global_reset(ab);
264f3c603d4SCarl Huang 	ath11k_mhi_set_mhictrl_reset(ab);
265f3c603d4SCarl Huang }
266f3c603d4SCarl Huang 
2677f4beda2SGovind Singh static void ath11k_pci_init_qmi_ce_config(struct ath11k_base *ab)
2687f4beda2SGovind Singh {
2697f4beda2SGovind Singh 	struct ath11k_qmi_ce_cfg *cfg = &ab->qmi.ce_cfg;
2707f4beda2SGovind Singh 
271967c1d11SAnilkumar Kolli 	cfg->tgt_ce = ab->hw_params.target_ce_config;
272967c1d11SAnilkumar Kolli 	cfg->tgt_ce_len = ab->hw_params.target_ce_count;
2737f4beda2SGovind Singh 
274967c1d11SAnilkumar Kolli 	cfg->svc_to_ce_map = ab->hw_params.svc_to_ce_map;
275967c1d11SAnilkumar Kolli 	cfg->svc_to_ce_map_len = ab->hw_params.svc_to_ce_map_len;
27616001e4bSAnilkumar Kolli 	ab->qmi.service_ins_id = ab->hw_params.qmi_service_ins_id;
277e838c14aSCarl Huang 
278e838c14aSCarl Huang 	ath11k_ce_get_shadow_config(ab, &cfg->shadow_reg_v2,
279e838c14aSCarl Huang 				    &cfg->shadow_reg_v2_len);
2807f4beda2SGovind Singh }
2817f4beda2SGovind Singh 
28296527d52SBaochen Qiang static void ath11k_pci_msi_config(struct ath11k_pci *ab_pci, bool enable)
28396527d52SBaochen Qiang {
28496527d52SBaochen Qiang 	struct pci_dev *dev = ab_pci->pdev;
28596527d52SBaochen Qiang 	u16 control;
28696527d52SBaochen Qiang 
28796527d52SBaochen Qiang 	pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &control);
28896527d52SBaochen Qiang 
28996527d52SBaochen Qiang 	if (enable)
29096527d52SBaochen Qiang 		control |= PCI_MSI_FLAGS_ENABLE;
29196527d52SBaochen Qiang 	else
29296527d52SBaochen Qiang 		control &= ~PCI_MSI_FLAGS_ENABLE;
29396527d52SBaochen Qiang 
29496527d52SBaochen Qiang 	pci_write_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, control);
29596527d52SBaochen Qiang }
29696527d52SBaochen Qiang 
29796527d52SBaochen Qiang static void ath11k_pci_msi_enable(struct ath11k_pci *ab_pci)
29896527d52SBaochen Qiang {
29996527d52SBaochen Qiang 	ath11k_pci_msi_config(ab_pci, true);
30096527d52SBaochen Qiang }
30196527d52SBaochen Qiang 
30296527d52SBaochen Qiang static void ath11k_pci_msi_disable(struct ath11k_pci *ab_pci)
30396527d52SBaochen Qiang {
30496527d52SBaochen Qiang 	ath11k_pci_msi_config(ab_pci, false);
30596527d52SBaochen Qiang }
30696527d52SBaochen Qiang 
30796527d52SBaochen Qiang static int ath11k_pci_alloc_msi(struct ath11k_pci *ab_pci)
3085697a564SGovind Singh {
3095697a564SGovind Singh 	struct ath11k_base *ab = ab_pci->ab;
310*0cfaf224SManikanta Pubbisetty 	const struct ath11k_msi_config *msi_config = ab->pci.msi.config;
311*0cfaf224SManikanta Pubbisetty 	struct pci_dev *pci_dev = ab_pci->pdev;
3125697a564SGovind Singh 	struct msi_desc *msi_desc;
3135697a564SGovind Singh 	int num_vectors;
3145697a564SGovind Singh 	int ret;
3155697a564SGovind Singh 
316*0cfaf224SManikanta Pubbisetty 	num_vectors = pci_alloc_irq_vectors(pci_dev,
3177a3aed0cSAnilkumar Kolli 					    msi_config->total_vectors,
3187a3aed0cSAnilkumar Kolli 					    msi_config->total_vectors,
3195697a564SGovind Singh 					    PCI_IRQ_MSI);
320ac6e7348SCarl Huang 	if (num_vectors == msi_config->total_vectors) {
321c41a6700SCarl Huang 		set_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags);
322c41a6700SCarl Huang 		ab_pci->irq_flags = IRQF_SHARED;
323ac6e7348SCarl Huang 	} else {
324ac6e7348SCarl Huang 		num_vectors = pci_alloc_irq_vectors(ab_pci->pdev,
325ac6e7348SCarl Huang 						    1,
326ac6e7348SCarl Huang 						    1,
327ac6e7348SCarl Huang 						    PCI_IRQ_MSI);
328ac6e7348SCarl Huang 		if (num_vectors < 0) {
329ac6e7348SCarl Huang 			ret = -EINVAL;
330ac6e7348SCarl Huang 			goto reset_msi_config;
3315697a564SGovind Singh 		}
332ac6e7348SCarl Huang 		clear_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags);
333*0cfaf224SManikanta Pubbisetty 		ab->pci.msi.config = &msi_config_one_msi;
334ac6e7348SCarl Huang 		ab_pci->irq_flags = IRQF_SHARED | IRQF_NOBALANCING;
335ac6e7348SCarl Huang 		ath11k_dbg(ab, ATH11K_DBG_PCI, "request MSI one vector\n");
336ac6e7348SCarl Huang 	}
337ac6e7348SCarl Huang 	ath11k_info(ab, "MSI vectors: %d\n", num_vectors);
338ac6e7348SCarl Huang 
33996527d52SBaochen Qiang 	ath11k_pci_msi_disable(ab_pci);
3405697a564SGovind Singh 
3415697a564SGovind Singh 	msi_desc = irq_get_msi_desc(ab_pci->pdev->irq);
3425697a564SGovind Singh 	if (!msi_desc) {
3435697a564SGovind Singh 		ath11k_err(ab, "msi_desc is NULL!\n");
3445697a564SGovind Singh 		ret = -EINVAL;
3455697a564SGovind Singh 		goto free_msi_vector;
3465697a564SGovind Singh 	}
3475697a564SGovind Singh 
348*0cfaf224SManikanta Pubbisetty 	ab->pci.msi.ep_base_data = msi_desc->msg.data;
3495697a564SGovind Singh 
350*0cfaf224SManikanta Pubbisetty 	pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_LO,
351*0cfaf224SManikanta Pubbisetty 			      &ab->pci.msi.addr_lo);
352*0cfaf224SManikanta Pubbisetty 
353*0cfaf224SManikanta Pubbisetty 	if (msi_desc->pci.msi_attrib.is_64) {
354*0cfaf224SManikanta Pubbisetty 		pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_HI,
355*0cfaf224SManikanta Pubbisetty 				      &ab->pci.msi.addr_hi);
356*0cfaf224SManikanta Pubbisetty 	} else {
357*0cfaf224SManikanta Pubbisetty 		ab->pci.msi.addr_hi = 0;
358*0cfaf224SManikanta Pubbisetty 	}
359*0cfaf224SManikanta Pubbisetty 
360*0cfaf224SManikanta Pubbisetty 	ath11k_dbg(ab, ATH11K_DBG_PCI, "msi base data is %d\n", ab->pci.msi.ep_base_data);
3615697a564SGovind Singh 
3625697a564SGovind Singh 	return 0;
3635697a564SGovind Singh 
3645697a564SGovind Singh free_msi_vector:
3655697a564SGovind Singh 	pci_free_irq_vectors(ab_pci->pdev);
3665697a564SGovind Singh 
367ac6e7348SCarl Huang reset_msi_config:
3685697a564SGovind Singh 	return ret;
3695697a564SGovind Singh }
3705697a564SGovind Singh 
37196527d52SBaochen Qiang static void ath11k_pci_free_msi(struct ath11k_pci *ab_pci)
3725697a564SGovind Singh {
3735697a564SGovind Singh 	pci_free_irq_vectors(ab_pci->pdev);
3745697a564SGovind Singh }
3755697a564SGovind Singh 
37687b4072dSCarl Huang static int ath11k_pci_config_msi_data(struct ath11k_pci *ab_pci)
37787b4072dSCarl Huang {
37887b4072dSCarl Huang 	struct msi_desc *msi_desc;
37987b4072dSCarl Huang 
38087b4072dSCarl Huang 	msi_desc = irq_get_msi_desc(ab_pci->pdev->irq);
38187b4072dSCarl Huang 	if (!msi_desc) {
38287b4072dSCarl Huang 		ath11k_err(ab_pci->ab, "msi_desc is NULL!\n");
38387b4072dSCarl Huang 		pci_free_irq_vectors(ab_pci->pdev);
38487b4072dSCarl Huang 		return -EINVAL;
38587b4072dSCarl Huang 	}
38687b4072dSCarl Huang 
387*0cfaf224SManikanta Pubbisetty 	ab_pci->ab->pci.msi.ep_base_data = msi_desc->msg.data;
38887b4072dSCarl Huang 
38987b4072dSCarl Huang 	ath11k_dbg(ab_pci->ab, ATH11K_DBG_PCI, "pci after request_irq msi_ep_base_data %d\n",
390*0cfaf224SManikanta Pubbisetty 		   ab_pci->ab->pci.msi.ep_base_data);
39187b4072dSCarl Huang 
39287b4072dSCarl Huang 	return 0;
39387b4072dSCarl Huang }
39487b4072dSCarl Huang 
3955762613eSGovind Singh static int ath11k_pci_claim(struct ath11k_pci *ab_pci, struct pci_dev *pdev)
3965762613eSGovind Singh {
3975762613eSGovind Singh 	struct ath11k_base *ab = ab_pci->ab;
3985762613eSGovind Singh 	u16 device_id;
3995762613eSGovind Singh 	int ret = 0;
4005762613eSGovind Singh 
4015762613eSGovind Singh 	pci_read_config_word(pdev, PCI_DEVICE_ID, &device_id);
4025762613eSGovind Singh 	if (device_id != ab_pci->dev_id)  {
4035762613eSGovind Singh 		ath11k_err(ab, "pci device id mismatch: 0x%x 0x%x\n",
4045762613eSGovind Singh 			   device_id, ab_pci->dev_id);
4055762613eSGovind Singh 		ret = -EIO;
4065762613eSGovind Singh 		goto out;
4075762613eSGovind Singh 	}
4085762613eSGovind Singh 
4095762613eSGovind Singh 	ret = pci_assign_resource(pdev, ATH11K_PCI_BAR_NUM);
4105762613eSGovind Singh 	if (ret) {
4115762613eSGovind Singh 		ath11k_err(ab, "failed to assign pci resource: %d\n", ret);
4125762613eSGovind Singh 		goto out;
4135762613eSGovind Singh 	}
4145762613eSGovind Singh 
4155762613eSGovind Singh 	ret = pci_enable_device(pdev);
4165762613eSGovind Singh 	if (ret) {
4175762613eSGovind Singh 		ath11k_err(ab, "failed to enable pci device: %d\n", ret);
4185762613eSGovind Singh 		goto out;
4195762613eSGovind Singh 	}
4205762613eSGovind Singh 
4215762613eSGovind Singh 	ret = pci_request_region(pdev, ATH11K_PCI_BAR_NUM, "ath11k_pci");
4225762613eSGovind Singh 	if (ret) {
4235762613eSGovind Singh 		ath11k_err(ab, "failed to request pci region: %d\n", ret);
4245762613eSGovind Singh 		goto disable_device;
4255762613eSGovind Singh 	}
4265762613eSGovind Singh 
427923a1346SChristophe JAILLET 	ret = dma_set_mask_and_coherent(&pdev->dev,
428923a1346SChristophe JAILLET 					DMA_BIT_MASK(ATH11K_PCI_DMA_MASK));
4295762613eSGovind Singh 	if (ret) {
4305762613eSGovind Singh 		ath11k_err(ab, "failed to set pci dma mask to %d: %d\n",
4315762613eSGovind Singh 			   ATH11K_PCI_DMA_MASK, ret);
4325762613eSGovind Singh 		goto release_region;
4335762613eSGovind Singh 	}
4345762613eSGovind Singh 
4355762613eSGovind Singh 	pci_set_master(pdev);
4365762613eSGovind Singh 
4375762613eSGovind Singh 	ab->mem_len = pci_resource_len(pdev, ATH11K_PCI_BAR_NUM);
4385762613eSGovind Singh 	ab->mem = pci_iomap(pdev, ATH11K_PCI_BAR_NUM, 0);
4395762613eSGovind Singh 	if (!ab->mem) {
4405762613eSGovind Singh 		ath11k_err(ab, "failed to map pci bar %d\n", ATH11K_PCI_BAR_NUM);
4415762613eSGovind Singh 		ret = -EIO;
4425762613eSGovind Singh 		goto clear_master;
4435762613eSGovind Singh 	}
4445762613eSGovind Singh 
4455762613eSGovind Singh 	ath11k_dbg(ab, ATH11K_DBG_BOOT, "boot pci_mem 0x%pK\n", ab->mem);
4465762613eSGovind Singh 	return 0;
4475762613eSGovind Singh 
4485762613eSGovind Singh clear_master:
4495762613eSGovind Singh 	pci_clear_master(pdev);
4505762613eSGovind Singh release_region:
4515762613eSGovind Singh 	pci_release_region(pdev, ATH11K_PCI_BAR_NUM);
4525762613eSGovind Singh disable_device:
4535762613eSGovind Singh 	pci_disable_device(pdev);
4545762613eSGovind Singh out:
4555762613eSGovind Singh 	return ret;
4565762613eSGovind Singh }
4575762613eSGovind Singh 
4585762613eSGovind Singh static void ath11k_pci_free_region(struct ath11k_pci *ab_pci)
4595762613eSGovind Singh {
4605762613eSGovind Singh 	struct ath11k_base *ab = ab_pci->ab;
4615762613eSGovind Singh 	struct pci_dev *pci_dev = ab_pci->pdev;
4625762613eSGovind Singh 
4635762613eSGovind Singh 	pci_iounmap(pci_dev, ab->mem);
4645762613eSGovind Singh 	ab->mem = NULL;
4655762613eSGovind Singh 	pci_clear_master(pci_dev);
4665762613eSGovind Singh 	pci_release_region(pci_dev, ATH11K_PCI_BAR_NUM);
4675762613eSGovind Singh 	if (pci_is_enabled(pci_dev))
4685762613eSGovind Singh 		pci_disable_device(pci_dev);
4695762613eSGovind Singh }
4705762613eSGovind Singh 
471e9603f4bSCarl Huang static void ath11k_pci_aspm_disable(struct ath11k_pci *ab_pci)
472e9603f4bSCarl Huang {
473e9603f4bSCarl Huang 	struct ath11k_base *ab = ab_pci->ab;
474e9603f4bSCarl Huang 
475e9603f4bSCarl Huang 	pcie_capability_read_word(ab_pci->pdev, PCI_EXP_LNKCTL,
476e9603f4bSCarl Huang 				  &ab_pci->link_ctl);
477e9603f4bSCarl Huang 
478e9603f4bSCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "pci link_ctl 0x%04x L0s %d L1 %d\n",
479e9603f4bSCarl Huang 		   ab_pci->link_ctl,
480e9603f4bSCarl Huang 		   u16_get_bits(ab_pci->link_ctl, PCI_EXP_LNKCTL_ASPM_L0S),
481e9603f4bSCarl Huang 		   u16_get_bits(ab_pci->link_ctl, PCI_EXP_LNKCTL_ASPM_L1));
482e9603f4bSCarl Huang 
483e9603f4bSCarl Huang 	/* disable L0s and L1 */
484e9603f4bSCarl Huang 	pcie_capability_write_word(ab_pci->pdev, PCI_EXP_LNKCTL,
485e9603f4bSCarl Huang 				   ab_pci->link_ctl & ~PCI_EXP_LNKCTL_ASPMC);
486e9603f4bSCarl Huang 
487e9603f4bSCarl Huang 	set_bit(ATH11K_PCI_ASPM_RESTORE, &ab_pci->flags);
488e9603f4bSCarl Huang }
489e9603f4bSCarl Huang 
4901399fb87SGovind Singh static int ath11k_pci_power_up(struct ath11k_base *ab)
4911399fb87SGovind Singh {
4921399fb87SGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
4931399fb87SGovind Singh 	int ret;
4941399fb87SGovind Singh 
495a05bd851SCarl Huang 	ab_pci->register_window = 0;
496a05bd851SCarl Huang 	clear_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags);
497babb0cedSCarl Huang 	ath11k_pci_sw_reset(ab_pci->ab, true);
498f3c603d4SCarl Huang 
499e9603f4bSCarl Huang 	/* Disable ASPM during firmware download due to problems switching
500e9603f4bSCarl Huang 	 * to AMSS state.
501e9603f4bSCarl Huang 	 */
502e9603f4bSCarl Huang 	ath11k_pci_aspm_disable(ab_pci);
503e9603f4bSCarl Huang 
50496527d52SBaochen Qiang 	ath11k_pci_msi_enable(ab_pci);
50596527d52SBaochen Qiang 
5061399fb87SGovind Singh 	ret = ath11k_mhi_start(ab_pci);
5071399fb87SGovind Singh 	if (ret) {
5081399fb87SGovind Singh 		ath11k_err(ab, "failed to start mhi: %d\n", ret);
5091399fb87SGovind Singh 		return ret;
5101399fb87SGovind Singh 	}
5111399fb87SGovind Singh 
512480a7361SKarthikeyan Periyasamy 	if (ab->bus_params.static_window_map)
513480a7361SKarthikeyan Periyasamy 		ath11k_pci_select_static_window(ab_pci);
514480a7361SKarthikeyan Periyasamy 
5151399fb87SGovind Singh 	return 0;
5161399fb87SGovind Singh }
5171399fb87SGovind Singh 
5181399fb87SGovind Singh static void ath11k_pci_power_down(struct ath11k_base *ab)
5191399fb87SGovind Singh {
5201399fb87SGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
5211399fb87SGovind Singh 
522e9603f4bSCarl Huang 	/* restore aspm in case firmware bootup fails */
523bbfdc5a7SManikanta Pubbisetty 	ath11k_pcic_aspm_restore(ab_pci);
524e9603f4bSCarl Huang 
525babb0cedSCarl Huang 	ath11k_pci_force_wake(ab_pci->ab);
52696527d52SBaochen Qiang 
52796527d52SBaochen Qiang 	ath11k_pci_msi_disable(ab_pci);
52896527d52SBaochen Qiang 
5291399fb87SGovind Singh 	ath11k_mhi_stop(ab_pci);
530a05bd851SCarl Huang 	clear_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags);
531babb0cedSCarl Huang 	ath11k_pci_sw_reset(ab_pci->ab, false);
5321399fb87SGovind Singh }
5331399fb87SGovind Singh 
534fa5917e4SCarl Huang static int ath11k_pci_hif_suspend(struct ath11k_base *ab)
535fa5917e4SCarl Huang {
536fa5917e4SCarl Huang 	struct ath11k_pci *ar_pci = ath11k_pci_priv(ab);
537fa5917e4SCarl Huang 
538fa5917e4SCarl Huang 	ath11k_mhi_suspend(ar_pci);
539fa5917e4SCarl Huang 
540fa5917e4SCarl Huang 	return 0;
541fa5917e4SCarl Huang }
542fa5917e4SCarl Huang 
543fa5917e4SCarl Huang static int ath11k_pci_hif_resume(struct ath11k_base *ab)
544fa5917e4SCarl Huang {
545fa5917e4SCarl Huang 	struct ath11k_pci *ar_pci = ath11k_pci_priv(ab);
546fa5917e4SCarl Huang 
547fa5917e4SCarl Huang 	ath11k_mhi_resume(ar_pci);
548fa5917e4SCarl Huang 
549fa5917e4SCarl Huang 	return 0;
550fa5917e4SCarl Huang }
551fa5917e4SCarl Huang 
552d578ec2aSCarl Huang static void ath11k_pci_hif_ce_irq_enable(struct ath11k_base *ab)
553d578ec2aSCarl Huang {
554bbfdc5a7SManikanta Pubbisetty 	ath11k_pcic_ce_irqs_enable(ab);
555d578ec2aSCarl Huang }
556d578ec2aSCarl Huang 
557d578ec2aSCarl Huang static void ath11k_pci_hif_ce_irq_disable(struct ath11k_base *ab)
558d578ec2aSCarl Huang {
559bbfdc5a7SManikanta Pubbisetty 	ath11k_pcic_ce_irq_disable_sync(ab);
5607f4beda2SGovind Singh }
5617f4beda2SGovind Singh 
5627f4beda2SGovind Singh static const struct ath11k_hif_ops ath11k_pci_hif_ops = {
563bbfdc5a7SManikanta Pubbisetty 	.start = ath11k_pcic_start,
564bbfdc5a7SManikanta Pubbisetty 	.stop = ath11k_pcic_stop,
565bbfdc5a7SManikanta Pubbisetty 	.read32 = ath11k_pcic_read32,
566bbfdc5a7SManikanta Pubbisetty 	.write32 = ath11k_pcic_write32,
5671399fb87SGovind Singh 	.power_down = ath11k_pci_power_down,
5681399fb87SGovind Singh 	.power_up = ath11k_pci_power_up,
569fa5917e4SCarl Huang 	.suspend = ath11k_pci_hif_suspend,
570fa5917e4SCarl Huang 	.resume = ath11k_pci_hif_resume,
571bbfdc5a7SManikanta Pubbisetty 	.irq_enable = ath11k_pcic_ext_irq_enable,
572bbfdc5a7SManikanta Pubbisetty 	.irq_disable = ath11k_pcic_ext_irq_disable,
573bbfdc5a7SManikanta Pubbisetty 	.get_msi_address =  ath11k_pcic_get_msi_address,
574*0cfaf224SManikanta Pubbisetty 	.get_user_msi_vector = ath11k_pcic_get_user_msi_assignment,
575bbfdc5a7SManikanta Pubbisetty 	.map_service_to_pipe = ath11k_pcic_map_service_to_pipe,
576d578ec2aSCarl Huang 	.ce_irq_enable = ath11k_pci_hif_ce_irq_enable,
577d578ec2aSCarl Huang 	.ce_irq_disable = ath11k_pci_hif_ce_irq_disable,
578bbfdc5a7SManikanta Pubbisetty 	.get_ce_msi_idx = ath11k_pcic_get_ce_msi_idx,
5791399fb87SGovind Singh };
5801399fb87SGovind Singh 
5810fbf1957SBaochen Qiang static void ath11k_pci_read_hw_version(struct ath11k_base *ab, u32 *major, u32 *minor)
5820fbf1957SBaochen Qiang {
5830fbf1957SBaochen Qiang 	u32 soc_hw_version;
5840fbf1957SBaochen Qiang 
585bbfdc5a7SManikanta Pubbisetty 	soc_hw_version = ath11k_pcic_read32(ab, TCSR_SOC_HW_VERSION);
5860fbf1957SBaochen Qiang 	*major = FIELD_GET(TCSR_SOC_HW_VERSION_MAJOR_MASK,
5870fbf1957SBaochen Qiang 			   soc_hw_version);
5880fbf1957SBaochen Qiang 	*minor = FIELD_GET(TCSR_SOC_HW_VERSION_MINOR_MASK,
5890fbf1957SBaochen Qiang 			   soc_hw_version);
5900fbf1957SBaochen Qiang 
5910fbf1957SBaochen Qiang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "pci tcsr_soc_hw_version major %d minor %d\n",
5920fbf1957SBaochen Qiang 		   *major, *minor);
5930fbf1957SBaochen Qiang }
5940fbf1957SBaochen Qiang 
5956e0355afSGovind Singh static int ath11k_pci_probe(struct pci_dev *pdev,
5966e0355afSGovind Singh 			    const struct pci_device_id *pci_dev)
5976e0355afSGovind Singh {
5986e0355afSGovind Singh 	struct ath11k_base *ab;
5995762613eSGovind Singh 	struct ath11k_pci *ab_pci;
6006ac04bdcSAnilkumar Kolli 	u32 soc_hw_version_major, soc_hw_version_minor, addr;
6015762613eSGovind Singh 	int ret;
6026e0355afSGovind Singh 
6031ff8ed78SGovind Singh 	ab = ath11k_core_alloc(&pdev->dev, sizeof(*ab_pci), ATH11K_BUS_PCI,
6041ff8ed78SGovind Singh 			       &ath11k_pci_bus_params);
6056e0355afSGovind Singh 	if (!ab) {
6066e0355afSGovind Singh 		dev_err(&pdev->dev, "failed to allocate ath11k base\n");
6076e0355afSGovind Singh 		return -ENOMEM;
6086e0355afSGovind Singh 	}
6096e0355afSGovind Singh 
6106e0355afSGovind Singh 	ab->dev = &pdev->dev;
6116e0355afSGovind Singh 	pci_set_drvdata(pdev, ab);
6125762613eSGovind Singh 	ab_pci = ath11k_pci_priv(ab);
6135762613eSGovind Singh 	ab_pci->dev_id = pci_dev->device;
6145762613eSGovind Singh 	ab_pci->ab = ab;
6155697a564SGovind Singh 	ab_pci->pdev = pdev;
6167f4beda2SGovind Singh 	ab->hif.ops = &ath11k_pci_hif_ops;
6175762613eSGovind Singh 	pci_set_drvdata(pdev, ab);
618654e959aSGovind Singh 	spin_lock_init(&ab_pci->window_lock);
6195762613eSGovind Singh 
6206ac04bdcSAnilkumar Kolli 	/* Set fixed_mem_region to true for platforms support reserved memory
6216ac04bdcSAnilkumar Kolli 	 * from DT. If memory is reserved from DT for FW, ath11k driver need not
6226ac04bdcSAnilkumar Kolli 	 * allocate memory.
6236ac04bdcSAnilkumar Kolli 	 */
6246ac04bdcSAnilkumar Kolli 	ret = of_property_read_u32(ab->dev->of_node, "memory-region", &addr);
6256ac04bdcSAnilkumar Kolli 	if (!ret)
6266ac04bdcSAnilkumar Kolli 		set_bit(ATH11K_FLAG_FIXED_MEM_RGN, &ab->dev_flags);
6276ac04bdcSAnilkumar Kolli 
6285762613eSGovind Singh 	ret = ath11k_pci_claim(ab_pci, pdev);
6295762613eSGovind Singh 	if (ret) {
6305762613eSGovind Singh 		ath11k_err(ab, "failed to claim device: %d\n", ret);
6315762613eSGovind Singh 		goto err_free_core;
6325762613eSGovind Singh 	}
6336e0355afSGovind Singh 
634fc95d10aSWen Gong 	ath11k_dbg(ab, ATH11K_DBG_BOOT, "pci probe %04x:%04x %04x:%04x\n",
635fc95d10aSWen Gong 		   pdev->vendor, pdev->device,
636fc95d10aSWen Gong 		   pdev->subsystem_vendor, pdev->subsystem_device);
637fc95d10aSWen Gong 
638fc95d10aSWen Gong 	ab->id.vendor = pdev->vendor;
639fc95d10aSWen Gong 	ab->id.device = pdev->device;
640fc95d10aSWen Gong 	ab->id.subsystem_vendor = pdev->subsystem_vendor;
641fc95d10aSWen Gong 	ab->id.subsystem_device = pdev->subsystem_device;
642fc95d10aSWen Gong 
64318ac1665SKalle Valo 	switch (pci_dev->device) {
64418ac1665SKalle Valo 	case QCA6390_DEVICE_ID:
6450fbf1957SBaochen Qiang 		ath11k_pci_read_hw_version(ab, &soc_hw_version_major,
6460fbf1957SBaochen Qiang 					   &soc_hw_version_minor);
64718ac1665SKalle Valo 		switch (soc_hw_version_major) {
64818ac1665SKalle Valo 		case 2:
64918ac1665SKalle Valo 			ab->hw_rev = ATH11K_HW_QCA6390_HW20;
65018ac1665SKalle Valo 			break;
65118ac1665SKalle Valo 		default:
65218ac1665SKalle Valo 			dev_err(&pdev->dev, "Unsupported QCA6390 SOC hardware version: %d %d\n",
65318ac1665SKalle Valo 				soc_hw_version_major, soc_hw_version_minor);
65418ac1665SKalle Valo 			ret = -EOPNOTSUPP;
65518ac1665SKalle Valo 			goto err_pci_free_region;
65618ac1665SKalle Valo 		}
6574e809461SAnilkumar Kolli 		break;
6584e809461SAnilkumar Kolli 	case QCN9074_DEVICE_ID:
6594e809461SAnilkumar Kolli 		ab->bus_params.static_window_map = true;
6604e809461SAnilkumar Kolli 		ab->hw_rev = ATH11K_HW_QCN9074_HW10;
66118ac1665SKalle Valo 		break;
6620fbf1957SBaochen Qiang 	case WCN6855_DEVICE_ID:
663fc95d10aSWen Gong 		ab->id.bdf_search = ATH11K_BDF_SEARCH_BUS_AND_BOARD;
6640fbf1957SBaochen Qiang 		ath11k_pci_read_hw_version(ab, &soc_hw_version_major,
6650fbf1957SBaochen Qiang 					   &soc_hw_version_minor);
6660fbf1957SBaochen Qiang 		switch (soc_hw_version_major) {
6670fbf1957SBaochen Qiang 		case 2:
668d1147a31SBaochen Qiang 			switch (soc_hw_version_minor) {
669d1147a31SBaochen Qiang 			case 0x00:
670d1147a31SBaochen Qiang 			case 0x01:
6710fbf1957SBaochen Qiang 				ab->hw_rev = ATH11K_HW_WCN6855_HW20;
6720fbf1957SBaochen Qiang 				break;
673d1147a31SBaochen Qiang 			case 0x10:
674d1147a31SBaochen Qiang 			case 0x11:
675d1147a31SBaochen Qiang 				ab->hw_rev = ATH11K_HW_WCN6855_HW21;
676d1147a31SBaochen Qiang 				break;
6770fbf1957SBaochen Qiang 			default:
678d1147a31SBaochen Qiang 				goto unsupported_wcn6855_soc;
679d1147a31SBaochen Qiang 			}
680d1147a31SBaochen Qiang 			break;
681d1147a31SBaochen Qiang 		default:
682d1147a31SBaochen Qiang unsupported_wcn6855_soc:
6830fbf1957SBaochen Qiang 			dev_err(&pdev->dev, "Unsupported WCN6855 SOC hardware version: %d %d\n",
6840fbf1957SBaochen Qiang 				soc_hw_version_major, soc_hw_version_minor);
6850fbf1957SBaochen Qiang 			ret = -EOPNOTSUPP;
6860fbf1957SBaochen Qiang 			goto err_pci_free_region;
6870fbf1957SBaochen Qiang 		}
6880fbf1957SBaochen Qiang 		break;
68918ac1665SKalle Valo 	default:
69018ac1665SKalle Valo 		dev_err(&pdev->dev, "Unknown PCI device found: 0x%x\n",
69118ac1665SKalle Valo 			pci_dev->device);
69218ac1665SKalle Valo 		ret = -EOPNOTSUPP;
69318ac1665SKalle Valo 		goto err_pci_free_region;
69418ac1665SKalle Valo 	}
69518ac1665SKalle Valo 
6968d06b802SManikanta Pubbisetty 	ret = ath11k_pcic_init_msi_config(ab);
6978d06b802SManikanta Pubbisetty 	if (ret) {
6988d06b802SManikanta Pubbisetty 		ath11k_err(ab, "failed to init msi config: %d\n", ret);
6998d06b802SManikanta Pubbisetty 		goto err_pci_free_region;
7008d06b802SManikanta Pubbisetty 	}
7018d06b802SManikanta Pubbisetty 
70296527d52SBaochen Qiang 	ret = ath11k_pci_alloc_msi(ab_pci);
7035697a564SGovind Singh 	if (ret) {
7045697a564SGovind Singh 		ath11k_err(ab, "failed to enable msi: %d\n", ret);
7055697a564SGovind Singh 		goto err_pci_free_region;
7065697a564SGovind Singh 	}
7075697a564SGovind Singh 
708b8246f88SKalle Valo 	ret = ath11k_core_pre_init(ab);
709b8246f88SKalle Valo 	if (ret)
710b8246f88SKalle Valo 		goto err_pci_disable_msi;
711b8246f88SKalle Valo 
7121399fb87SGovind Singh 	ret = ath11k_mhi_register(ab_pci);
7131399fb87SGovind Singh 	if (ret) {
7141399fb87SGovind Singh 		ath11k_err(ab, "failed to register mhi: %d\n", ret);
7151399fb87SGovind Singh 		goto err_pci_disable_msi;
7161399fb87SGovind Singh 	}
7171399fb87SGovind Singh 
7187f4beda2SGovind Singh 	ret = ath11k_hal_srng_init(ab);
7197f4beda2SGovind Singh 	if (ret)
7207f4beda2SGovind Singh 		goto err_mhi_unregister;
7217f4beda2SGovind Singh 
7227f4beda2SGovind Singh 	ret = ath11k_ce_alloc_pipes(ab);
7237f4beda2SGovind Singh 	if (ret) {
7247f4beda2SGovind Singh 		ath11k_err(ab, "failed to allocate ce pipes: %d\n", ret);
7257f4beda2SGovind Singh 		goto err_hal_srng_deinit;
7267f4beda2SGovind Singh 	}
7277f4beda2SGovind Singh 
7287f4beda2SGovind Singh 	ath11k_pci_init_qmi_ce_config(ab);
7297f4beda2SGovind Singh 
730bbfdc5a7SManikanta Pubbisetty 	ret = ath11k_pcic_config_irq(ab);
7317f4beda2SGovind Singh 	if (ret) {
7327f4beda2SGovind Singh 		ath11k_err(ab, "failed to config irq: %d\n", ret);
7337f4beda2SGovind Singh 		goto err_ce_free;
7347f4beda2SGovind Singh 	}
7357f4beda2SGovind Singh 
73687b4072dSCarl Huang 	/* kernel may allocate a dummy vector before request_irq and
73787b4072dSCarl Huang 	 * then allocate a real vector when request_irq is called.
73887b4072dSCarl Huang 	 * So get msi_data here again to avoid spurious interrupt
73987b4072dSCarl Huang 	 * as msi_data will configured to srngs.
74087b4072dSCarl Huang 	 */
74187b4072dSCarl Huang 	ret = ath11k_pci_config_msi_data(ab_pci);
74287b4072dSCarl Huang 	if (ret) {
74387b4072dSCarl Huang 		ath11k_err(ab, "failed to config msi_data: %d\n", ret);
74487b4072dSCarl Huang 		goto err_free_irq;
74587b4072dSCarl Huang 	}
74687b4072dSCarl Huang 
7477f4beda2SGovind Singh 	ret = ath11k_core_init(ab);
7487f4beda2SGovind Singh 	if (ret) {
7497f4beda2SGovind Singh 		ath11k_err(ab, "failed to init core: %d\n", ret);
7507f4beda2SGovind Singh 		goto err_free_irq;
7517f4beda2SGovind Singh 	}
7526e0355afSGovind Singh 	return 0;
7535762613eSGovind Singh 
7547f4beda2SGovind Singh err_free_irq:
755bbfdc5a7SManikanta Pubbisetty 	ath11k_pcic_free_irq(ab);
7567f4beda2SGovind Singh 
7577f4beda2SGovind Singh err_ce_free:
7587f4beda2SGovind Singh 	ath11k_ce_free_pipes(ab);
7597f4beda2SGovind Singh 
7607f4beda2SGovind Singh err_hal_srng_deinit:
7617f4beda2SGovind Singh 	ath11k_hal_srng_deinit(ab);
7627f4beda2SGovind Singh 
7637f4beda2SGovind Singh err_mhi_unregister:
7647f4beda2SGovind Singh 	ath11k_mhi_unregister(ab_pci);
7657f4beda2SGovind Singh 
766b8246f88SKalle Valo err_pci_disable_msi:
76796527d52SBaochen Qiang 	ath11k_pci_free_msi(ab_pci);
768b8246f88SKalle Valo 
7695697a564SGovind Singh err_pci_free_region:
7705697a564SGovind Singh 	ath11k_pci_free_region(ab_pci);
7715697a564SGovind Singh 
7725762613eSGovind Singh err_free_core:
7735762613eSGovind Singh 	ath11k_core_free(ab);
7745697a564SGovind Singh 
7755762613eSGovind Singh 	return ret;
7766e0355afSGovind Singh }
7776e0355afSGovind Singh 
7786e0355afSGovind Singh static void ath11k_pci_remove(struct pci_dev *pdev)
7796e0355afSGovind Singh {
7806e0355afSGovind Singh 	struct ath11k_base *ab = pci_get_drvdata(pdev);
7815762613eSGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
7826e0355afSGovind Singh 
783bbfdc5a7SManikanta Pubbisetty 	ath11k_pcic_set_irq_affinity_hint(ab_pci, NULL);
784e94b0749SBaochen Qiang 
78561a57e51SAnilkumar Kolli 	if (test_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags)) {
78661a57e51SAnilkumar Kolli 		ath11k_pci_power_down(ab);
78761a57e51SAnilkumar Kolli 		ath11k_debugfs_soc_destroy(ab);
78861a57e51SAnilkumar Kolli 		ath11k_qmi_deinit_service(ab);
78961a57e51SAnilkumar Kolli 		goto qmi_fail;
79061a57e51SAnilkumar Kolli 	}
79161a57e51SAnilkumar Kolli 
7926e0355afSGovind Singh 	set_bit(ATH11K_FLAG_UNREGISTERING, &ab->dev_flags);
7936fbd8898SCarl Huang 
7946fbd8898SCarl Huang 	ath11k_core_deinit(ab);
7956fbd8898SCarl Huang 
79661a57e51SAnilkumar Kolli qmi_fail:
7971399fb87SGovind Singh 	ath11k_mhi_unregister(ab_pci);
7986fbd8898SCarl Huang 
799bbfdc5a7SManikanta Pubbisetty 	ath11k_pcic_free_irq(ab);
80096527d52SBaochen Qiang 	ath11k_pci_free_msi(ab_pci);
8015762613eSGovind Singh 	ath11k_pci_free_region(ab_pci);
8026fbd8898SCarl Huang 
8036fbd8898SCarl Huang 	ath11k_hal_srng_deinit(ab);
8046fbd8898SCarl Huang 	ath11k_ce_free_pipes(ab);
8056e0355afSGovind Singh 	ath11k_core_free(ab);
8066e0355afSGovind Singh }
8076e0355afSGovind Singh 
8081399fb87SGovind Singh static void ath11k_pci_shutdown(struct pci_dev *pdev)
8091399fb87SGovind Singh {
8101399fb87SGovind Singh 	struct ath11k_base *ab = pci_get_drvdata(pdev);
8111399fb87SGovind Singh 
8121399fb87SGovind Singh 	ath11k_pci_power_down(ab);
8131399fb87SGovind Singh }
8141399fb87SGovind Singh 
815d1b0c338SCarl Huang static __maybe_unused int ath11k_pci_pm_suspend(struct device *dev)
816d1b0c338SCarl Huang {
817d1b0c338SCarl Huang 	struct ath11k_base *ab = dev_get_drvdata(dev);
818d1b0c338SCarl Huang 	int ret;
819d1b0c338SCarl Huang 
820b4f4c564SKalle Valo 	if (test_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags)) {
821b4f4c564SKalle Valo 		ath11k_dbg(ab, ATH11K_DBG_BOOT, "boot skipping pci suspend as qmi is not initialised\n");
822b4f4c564SKalle Valo 		return 0;
823b4f4c564SKalle Valo 	}
824b4f4c564SKalle Valo 
825d1b0c338SCarl Huang 	ret = ath11k_core_suspend(ab);
826d1b0c338SCarl Huang 	if (ret)
827d1b0c338SCarl Huang 		ath11k_warn(ab, "failed to suspend core: %d\n", ret);
828d1b0c338SCarl Huang 
829d1b0c338SCarl Huang 	return ret;
830d1b0c338SCarl Huang }
831d1b0c338SCarl Huang 
832d1b0c338SCarl Huang static __maybe_unused int ath11k_pci_pm_resume(struct device *dev)
833d1b0c338SCarl Huang {
834d1b0c338SCarl Huang 	struct ath11k_base *ab = dev_get_drvdata(dev);
835d1b0c338SCarl Huang 	int ret;
836d1b0c338SCarl Huang 
837b4f4c564SKalle Valo 	if (test_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags)) {
838b4f4c564SKalle Valo 		ath11k_dbg(ab, ATH11K_DBG_BOOT, "boot skipping pci resume as qmi is not initialised\n");
839b4f4c564SKalle Valo 		return 0;
840b4f4c564SKalle Valo 	}
841b4f4c564SKalle Valo 
842d1b0c338SCarl Huang 	ret = ath11k_core_resume(ab);
843d1b0c338SCarl Huang 	if (ret)
844d1b0c338SCarl Huang 		ath11k_warn(ab, "failed to resume core: %d\n", ret);
845d1b0c338SCarl Huang 
846d1b0c338SCarl Huang 	return ret;
847d1b0c338SCarl Huang }
848d1b0c338SCarl Huang 
849d1b0c338SCarl Huang static SIMPLE_DEV_PM_OPS(ath11k_pci_pm_ops,
850d1b0c338SCarl Huang 			 ath11k_pci_pm_suspend,
851d1b0c338SCarl Huang 			 ath11k_pci_pm_resume);
852d1b0c338SCarl Huang 
8536e0355afSGovind Singh static struct pci_driver ath11k_pci_driver = {
8546e0355afSGovind Singh 	.name = "ath11k_pci",
8556e0355afSGovind Singh 	.id_table = ath11k_pci_id_table,
8566e0355afSGovind Singh 	.probe = ath11k_pci_probe,
8576e0355afSGovind Singh 	.remove = ath11k_pci_remove,
8581399fb87SGovind Singh 	.shutdown = ath11k_pci_shutdown,
859d1b0c338SCarl Huang #ifdef CONFIG_PM
860d1b0c338SCarl Huang 	.driver.pm = &ath11k_pci_pm_ops,
861d1b0c338SCarl Huang #endif
8626e0355afSGovind Singh };
8636e0355afSGovind Singh 
8646e0355afSGovind Singh static int ath11k_pci_init(void)
8656e0355afSGovind Singh {
8666e0355afSGovind Singh 	int ret;
8676e0355afSGovind Singh 
8686e0355afSGovind Singh 	ret = pci_register_driver(&ath11k_pci_driver);
8696e0355afSGovind Singh 	if (ret)
8706e0355afSGovind Singh 		pr_err("failed to register ath11k pci driver: %d\n",
8716e0355afSGovind Singh 		       ret);
8726e0355afSGovind Singh 
8736e0355afSGovind Singh 	return ret;
8746e0355afSGovind Singh }
8756e0355afSGovind Singh module_init(ath11k_pci_init);
8766e0355afSGovind Singh 
8776e0355afSGovind Singh static void ath11k_pci_exit(void)
8786e0355afSGovind Singh {
8796e0355afSGovind Singh 	pci_unregister_driver(&ath11k_pci_driver);
8806e0355afSGovind Singh }
8816e0355afSGovind Singh 
8826e0355afSGovind Singh module_exit(ath11k_pci_exit);
8836e0355afSGovind Singh 
8846e0355afSGovind Singh MODULE_DESCRIPTION("Driver support for Qualcomm Technologies 802.11ax WLAN PCIe devices");
8856e0355afSGovind Singh MODULE_LICENSE("Dual BSD/GPL");
8863dbd7fe7SDevin Bayer 
8873dbd7fe7SDevin Bayer /* QCA639x 2.0 firmware files */
8883dbd7fe7SDevin Bayer MODULE_FIRMWARE(ATH11K_FW_DIR "/QCA6390/hw2.0/" ATH11K_BOARD_API2_FILE);
8893dbd7fe7SDevin Bayer MODULE_FIRMWARE(ATH11K_FW_DIR "/QCA6390/hw2.0/" ATH11K_AMSS_FILE);
8903dbd7fe7SDevin Bayer MODULE_FIRMWARE(ATH11K_FW_DIR "/QCA6390/hw2.0/" ATH11K_M3_FILE);
891