xref: /openbmc/linux/drivers/net/wireless/ath/ath11k/pci.c (revision 332c656289388887b2cd39a3f53fc05dcc65e310)
16e0355afSGovind Singh // SPDX-License-Identifier: BSD-3-Clause-Clear
26e0355afSGovind Singh /*
36e0355afSGovind Singh  * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved.
4b43310e4SGovindaraj Saminathan  * Copyright (c) 2021-2023 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 
395b32b6ddSManikanta Pubbisetty static int ath11k_pci_bus_wake_up(struct ath11k_base *ab)
405b32b6ddSManikanta Pubbisetty {
415b32b6ddSManikanta Pubbisetty 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
425b32b6ddSManikanta Pubbisetty 
435b32b6ddSManikanta Pubbisetty 	return mhi_device_get_sync(ab_pci->mhi_ctrl->mhi_dev);
445b32b6ddSManikanta Pubbisetty }
455b32b6ddSManikanta Pubbisetty 
465b32b6ddSManikanta Pubbisetty static void ath11k_pci_bus_release(struct ath11k_base *ab)
475b32b6ddSManikanta Pubbisetty {
485b32b6ddSManikanta Pubbisetty 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
495b32b6ddSManikanta Pubbisetty 
505b32b6ddSManikanta Pubbisetty 	mhi_device_put(ab_pci->mhi_ctrl->mhi_dev);
515b32b6ddSManikanta Pubbisetty }
525b32b6ddSManikanta Pubbisetty 
53867f4eeeSManikanta Pubbisetty static u32 ath11k_pci_get_window_start(struct ath11k_base *ab, u32 offset)
54867f4eeeSManikanta Pubbisetty {
55867f4eeeSManikanta Pubbisetty 	if (!ab->hw_params.static_window_map)
56867f4eeeSManikanta Pubbisetty 		return ATH11K_PCI_WINDOW_START;
57867f4eeeSManikanta Pubbisetty 
58867f4eeeSManikanta Pubbisetty 	if ((offset ^ HAL_SEQ_WCSS_UMAC_OFFSET) < ATH11K_PCI_WINDOW_RANGE_MASK)
59867f4eeeSManikanta Pubbisetty 		/* if offset lies within DP register range, use 3rd window */
60867f4eeeSManikanta Pubbisetty 		return 3 * ATH11K_PCI_WINDOW_START;
61867f4eeeSManikanta Pubbisetty 	else if ((offset ^ HAL_SEQ_WCSS_UMAC_CE0_SRC_REG(ab)) <
62867f4eeeSManikanta Pubbisetty 		 ATH11K_PCI_WINDOW_RANGE_MASK)
63867f4eeeSManikanta Pubbisetty 		 /* if offset lies within CE register range, use 2nd window */
64867f4eeeSManikanta Pubbisetty 		return 2 * ATH11K_PCI_WINDOW_START;
65867f4eeeSManikanta Pubbisetty 	else
66867f4eeeSManikanta Pubbisetty 		return ATH11K_PCI_WINDOW_START;
67867f4eeeSManikanta Pubbisetty }
68867f4eeeSManikanta Pubbisetty 
695b32b6ddSManikanta Pubbisetty static inline void ath11k_pci_select_window(struct ath11k_pci *ab_pci, u32 offset)
705b32b6ddSManikanta Pubbisetty {
715b32b6ddSManikanta Pubbisetty 	struct ath11k_base *ab = ab_pci->ab;
725b32b6ddSManikanta Pubbisetty 
735b32b6ddSManikanta Pubbisetty 	u32 window = FIELD_GET(ATH11K_PCI_WINDOW_VALUE_MASK, offset);
745b32b6ddSManikanta Pubbisetty 
755b32b6ddSManikanta Pubbisetty 	lockdep_assert_held(&ab_pci->window_lock);
765b32b6ddSManikanta Pubbisetty 
775b32b6ddSManikanta Pubbisetty 	if (window != ab_pci->register_window) {
785b32b6ddSManikanta Pubbisetty 		iowrite32(ATH11K_PCI_WINDOW_ENABLE_BIT | window,
795b32b6ddSManikanta Pubbisetty 			  ab->mem + ATH11K_PCI_WINDOW_REG_ADDRESS);
805b32b6ddSManikanta Pubbisetty 		ioread32(ab->mem + ATH11K_PCI_WINDOW_REG_ADDRESS);
815b32b6ddSManikanta Pubbisetty 		ab_pci->register_window = window;
825b32b6ddSManikanta Pubbisetty 	}
835b32b6ddSManikanta Pubbisetty }
845b32b6ddSManikanta Pubbisetty 
855b32b6ddSManikanta Pubbisetty static void
865b32b6ddSManikanta Pubbisetty ath11k_pci_window_write32(struct ath11k_base *ab, u32 offset, u32 value)
875b32b6ddSManikanta Pubbisetty {
885b32b6ddSManikanta Pubbisetty 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
89867f4eeeSManikanta Pubbisetty 	u32 window_start;
905b32b6ddSManikanta Pubbisetty 
91867f4eeeSManikanta Pubbisetty 	window_start = ath11k_pci_get_window_start(ab, offset);
92867f4eeeSManikanta Pubbisetty 
93867f4eeeSManikanta Pubbisetty 	if (window_start == ATH11K_PCI_WINDOW_START) {
945b32b6ddSManikanta Pubbisetty 		spin_lock_bh(&ab_pci->window_lock);
955b32b6ddSManikanta Pubbisetty 		ath11k_pci_select_window(ab_pci, offset);
965b32b6ddSManikanta Pubbisetty 		iowrite32(value, ab->mem + window_start +
975b32b6ddSManikanta Pubbisetty 			  (offset & ATH11K_PCI_WINDOW_RANGE_MASK));
985b32b6ddSManikanta Pubbisetty 		spin_unlock_bh(&ab_pci->window_lock);
99867f4eeeSManikanta Pubbisetty 	} else {
100867f4eeeSManikanta Pubbisetty 		iowrite32(value, ab->mem + window_start +
101867f4eeeSManikanta Pubbisetty 			  (offset & ATH11K_PCI_WINDOW_RANGE_MASK));
102867f4eeeSManikanta Pubbisetty 	}
1035b32b6ddSManikanta Pubbisetty }
1045b32b6ddSManikanta Pubbisetty 
1055b32b6ddSManikanta Pubbisetty static u32 ath11k_pci_window_read32(struct ath11k_base *ab, u32 offset)
1065b32b6ddSManikanta Pubbisetty {
1075b32b6ddSManikanta Pubbisetty 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
108867f4eeeSManikanta Pubbisetty 	u32 window_start, val;
1095b32b6ddSManikanta Pubbisetty 
110867f4eeeSManikanta Pubbisetty 	window_start = ath11k_pci_get_window_start(ab, offset);
111867f4eeeSManikanta Pubbisetty 
112867f4eeeSManikanta Pubbisetty 	if (window_start == ATH11K_PCI_WINDOW_START) {
1135b32b6ddSManikanta Pubbisetty 		spin_lock_bh(&ab_pci->window_lock);
1145b32b6ddSManikanta Pubbisetty 		ath11k_pci_select_window(ab_pci, offset);
1155b32b6ddSManikanta Pubbisetty 		val = ioread32(ab->mem + window_start +
1165b32b6ddSManikanta Pubbisetty 			       (offset & ATH11K_PCI_WINDOW_RANGE_MASK));
1175b32b6ddSManikanta Pubbisetty 		spin_unlock_bh(&ab_pci->window_lock);
118867f4eeeSManikanta Pubbisetty 	} else {
119867f4eeeSManikanta Pubbisetty 		val = ioread32(ab->mem + window_start +
120867f4eeeSManikanta Pubbisetty 			       (offset & ATH11K_PCI_WINDOW_RANGE_MASK));
121867f4eeeSManikanta Pubbisetty 	}
1225b32b6ddSManikanta Pubbisetty 
1235b32b6ddSManikanta Pubbisetty 	return val;
1245b32b6ddSManikanta Pubbisetty }
1255b32b6ddSManikanta Pubbisetty 
1265b32b6ddSManikanta Pubbisetty int ath11k_pci_get_msi_irq(struct ath11k_base *ab, unsigned int vector)
1275b32b6ddSManikanta Pubbisetty {
1285b32b6ddSManikanta Pubbisetty 	struct pci_dev *pci_dev = to_pci_dev(ab->dev);
1295b32b6ddSManikanta Pubbisetty 
1305b32b6ddSManikanta Pubbisetty 	return pci_irq_vector(pci_dev, vector);
1315b32b6ddSManikanta Pubbisetty }
1325b32b6ddSManikanta Pubbisetty 
1335b32b6ddSManikanta Pubbisetty static const struct ath11k_pci_ops ath11k_pci_ops_qca6390 = {
1345b32b6ddSManikanta Pubbisetty 	.wakeup = ath11k_pci_bus_wake_up,
1355b32b6ddSManikanta Pubbisetty 	.release = ath11k_pci_bus_release,
1365b32b6ddSManikanta Pubbisetty 	.get_msi_irq = ath11k_pci_get_msi_irq,
1375b32b6ddSManikanta Pubbisetty 	.window_write32 = ath11k_pci_window_write32,
1385b32b6ddSManikanta Pubbisetty 	.window_read32 = ath11k_pci_window_read32,
1395b32b6ddSManikanta Pubbisetty };
1405b32b6ddSManikanta Pubbisetty 
1415b32b6ddSManikanta Pubbisetty static const struct ath11k_pci_ops ath11k_pci_ops_qcn9074 = {
142867f4eeeSManikanta Pubbisetty 	.wakeup = NULL,
143867f4eeeSManikanta Pubbisetty 	.release = NULL,
1445b32b6ddSManikanta Pubbisetty 	.get_msi_irq = ath11k_pci_get_msi_irq,
1455b32b6ddSManikanta Pubbisetty 	.window_write32 = ath11k_pci_window_write32,
1465b32b6ddSManikanta Pubbisetty 	.window_read32 = ath11k_pci_window_read32,
1475b32b6ddSManikanta Pubbisetty };
1485b32b6ddSManikanta Pubbisetty 
149ac6e7348SCarl Huang static const struct ath11k_msi_config msi_config_one_msi = {
150ac6e7348SCarl Huang 	.total_vectors = 1,
151ac6e7348SCarl Huang 	.total_users = 4,
152ac6e7348SCarl Huang 	.users = (struct ath11k_msi_user[]) {
153ac6e7348SCarl Huang 		{ .name = "MHI", .num_vectors = 3, .base_vector = 0 },
154ac6e7348SCarl Huang 		{ .name = "CE", .num_vectors = 1, .base_vector = 0 },
155ac6e7348SCarl Huang 		{ .name = "WAKE", .num_vectors = 1, .base_vector = 0 },
156ac6e7348SCarl Huang 		{ .name = "DP", .num_vectors = 1, .base_vector = 0 },
157ac6e7348SCarl Huang 	},
158ac6e7348SCarl Huang };
159ac6e7348SCarl Huang 
160480a7361SKarthikeyan Periyasamy static inline void ath11k_pci_select_static_window(struct ath11k_pci *ab_pci)
161480a7361SKarthikeyan Periyasamy {
162948171b5SManikanta Pubbisetty 	u32 umac_window;
163948171b5SManikanta Pubbisetty 	u32 ce_window;
164480a7361SKarthikeyan Periyasamy 	u32 window;
165480a7361SKarthikeyan Periyasamy 
166948171b5SManikanta Pubbisetty 	umac_window = FIELD_GET(ATH11K_PCI_WINDOW_VALUE_MASK, HAL_SEQ_WCSS_UMAC_OFFSET);
167948171b5SManikanta Pubbisetty 	ce_window = FIELD_GET(ATH11K_PCI_WINDOW_VALUE_MASK, HAL_CE_WFSS_CE_REG_BASE);
168480a7361SKarthikeyan Periyasamy 	window = (umac_window << 12) | (ce_window << 6);
169480a7361SKarthikeyan Periyasamy 
170948171b5SManikanta Pubbisetty 	iowrite32(ATH11K_PCI_WINDOW_ENABLE_BIT | window,
171948171b5SManikanta Pubbisetty 		  ab_pci->ab->mem + ATH11K_PCI_WINDOW_REG_ADDRESS);
172480a7361SKarthikeyan Periyasamy }
173480a7361SKarthikeyan Periyasamy 
174f3c603d4SCarl Huang static void ath11k_pci_soc_global_reset(struct ath11k_base *ab)
175f3c603d4SCarl Huang {
176f3c603d4SCarl Huang 	u32 val, delay;
177f3c603d4SCarl Huang 
178bbfdc5a7SManikanta Pubbisetty 	val = ath11k_pcic_read32(ab, PCIE_SOC_GLOBAL_RESET);
179f3c603d4SCarl Huang 
180f3c603d4SCarl Huang 	val |= PCIE_SOC_GLOBAL_RESET_V;
181f3c603d4SCarl Huang 
182bbfdc5a7SManikanta Pubbisetty 	ath11k_pcic_write32(ab, PCIE_SOC_GLOBAL_RESET, val);
183f3c603d4SCarl Huang 
184f3c603d4SCarl Huang 	/* TODO: exact time to sleep is uncertain */
185f3c603d4SCarl Huang 	delay = 10;
186f3c603d4SCarl Huang 	mdelay(delay);
187f3c603d4SCarl Huang 
188f3c603d4SCarl Huang 	/* Need to toggle V bit back otherwise stuck in reset status */
189f3c603d4SCarl Huang 	val &= ~PCIE_SOC_GLOBAL_RESET_V;
190f3c603d4SCarl Huang 
191bbfdc5a7SManikanta Pubbisetty 	ath11k_pcic_write32(ab, PCIE_SOC_GLOBAL_RESET, val);
192f3c603d4SCarl Huang 
193f3c603d4SCarl Huang 	mdelay(delay);
194f3c603d4SCarl Huang 
195bbfdc5a7SManikanta Pubbisetty 	val = ath11k_pcic_read32(ab, PCIE_SOC_GLOBAL_RESET);
196f3c603d4SCarl Huang 	if (val == 0xffffffff)
197f3c603d4SCarl Huang 		ath11k_warn(ab, "link down error during global reset\n");
198f3c603d4SCarl Huang }
199f3c603d4SCarl Huang 
200f3c603d4SCarl Huang static void ath11k_pci_clear_dbg_registers(struct ath11k_base *ab)
201f3c603d4SCarl Huang {
202f3c603d4SCarl Huang 	u32 val;
203f3c603d4SCarl Huang 
204f3c603d4SCarl Huang 	/* read cookie */
205bbfdc5a7SManikanta Pubbisetty 	val = ath11k_pcic_read32(ab, PCIE_Q6_COOKIE_ADDR);
206*332c6562SKalle Valo 	ath11k_dbg(ab, ATH11K_DBG_PCI, "pcie_q6_cookie_addr 0x%x\n", val);
207f3c603d4SCarl Huang 
208bbfdc5a7SManikanta Pubbisetty 	val = ath11k_pcic_read32(ab, WLAON_WARM_SW_ENTRY);
209*332c6562SKalle Valo 	ath11k_dbg(ab, ATH11K_DBG_PCI, "wlaon_warm_sw_entry 0x%x\n", val);
210f3c603d4SCarl Huang 
211f3c603d4SCarl Huang 	/* TODO: exact time to sleep is uncertain */
212f3c603d4SCarl Huang 	mdelay(10);
213f3c603d4SCarl Huang 
214f3c603d4SCarl Huang 	/* write 0 to WLAON_WARM_SW_ENTRY to prevent Q6 from
215f3c603d4SCarl Huang 	 * continuing warm path and entering dead loop.
216f3c603d4SCarl Huang 	 */
217bbfdc5a7SManikanta Pubbisetty 	ath11k_pcic_write32(ab, WLAON_WARM_SW_ENTRY, 0);
218f3c603d4SCarl Huang 	mdelay(10);
219f3c603d4SCarl Huang 
220bbfdc5a7SManikanta Pubbisetty 	val = ath11k_pcic_read32(ab, WLAON_WARM_SW_ENTRY);
221*332c6562SKalle Valo 	ath11k_dbg(ab, ATH11K_DBG_PCI, "wlaon_warm_sw_entry 0x%x\n", val);
222f3c603d4SCarl Huang 
223f3c603d4SCarl Huang 	/* A read clear register. clear the register to prevent
224f3c603d4SCarl Huang 	 * Q6 from entering wrong code path.
225f3c603d4SCarl Huang 	 */
226bbfdc5a7SManikanta Pubbisetty 	val = ath11k_pcic_read32(ab, WLAON_SOC_RESET_CAUSE_REG);
227*332c6562SKalle Valo 	ath11k_dbg(ab, ATH11K_DBG_PCI, "soc reset cause %d\n", val);
228f3c603d4SCarl Huang }
229f3c603d4SCarl Huang 
23006999407SCarl Huang static int ath11k_pci_set_link_reg(struct ath11k_base *ab,
23106999407SCarl Huang 				   u32 offset, u32 value, u32 mask)
23206999407SCarl Huang {
23306999407SCarl Huang 	u32 v;
23406999407SCarl Huang 	int i;
23506999407SCarl Huang 
236bbfdc5a7SManikanta Pubbisetty 	v = ath11k_pcic_read32(ab, offset);
23706999407SCarl Huang 	if ((v & mask) == value)
23806999407SCarl Huang 		return 0;
23906999407SCarl Huang 
24006999407SCarl Huang 	for (i = 0; i < 10; i++) {
241bbfdc5a7SManikanta Pubbisetty 		ath11k_pcic_write32(ab, offset, (v & ~mask) | value);
24206999407SCarl Huang 
243bbfdc5a7SManikanta Pubbisetty 		v = ath11k_pcic_read32(ab, offset);
24406999407SCarl Huang 		if ((v & mask) == value)
24506999407SCarl Huang 			return 0;
24606999407SCarl Huang 
24706999407SCarl Huang 		mdelay(2);
24806999407SCarl Huang 	}
24906999407SCarl Huang 
25006999407SCarl Huang 	ath11k_warn(ab, "failed to set pcie link register 0x%08x: 0x%08x != 0x%08x\n",
25106999407SCarl Huang 		    offset, v & mask, value);
25206999407SCarl Huang 
25306999407SCarl Huang 	return -ETIMEDOUT;
25406999407SCarl Huang }
25506999407SCarl Huang 
25606999407SCarl Huang static int ath11k_pci_fix_l1ss(struct ath11k_base *ab)
25706999407SCarl Huang {
25806999407SCarl Huang 	int ret;
25906999407SCarl Huang 
26006999407SCarl Huang 	ret = ath11k_pci_set_link_reg(ab,
2616fe6f68fSKarthikeyan Periyasamy 				      PCIE_QSERDES_COM_SYSCLK_EN_SEL_REG(ab),
26206999407SCarl Huang 				      PCIE_QSERDES_COM_SYSCLK_EN_SEL_VAL,
26306999407SCarl Huang 				      PCIE_QSERDES_COM_SYSCLK_EN_SEL_MSK);
26430d08503SDan Carpenter 	if (ret) {
26506999407SCarl Huang 		ath11k_warn(ab, "failed to set sysclk: %d\n", ret);
26606999407SCarl Huang 		return ret;
26706999407SCarl Huang 	}
26806999407SCarl Huang 
26906999407SCarl Huang 	ret = ath11k_pci_set_link_reg(ab,
2706fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG1_REG(ab),
2716fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG1_VAL,
2726fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG_MSK);
27330d08503SDan Carpenter 	if (ret) {
27406999407SCarl Huang 		ath11k_warn(ab, "failed to set dtct config1 error: %d\n", ret);
27506999407SCarl Huang 		return ret;
27606999407SCarl Huang 	}
27706999407SCarl Huang 
27806999407SCarl Huang 	ret = ath11k_pci_set_link_reg(ab,
2796fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG2_REG(ab),
2806fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG2_VAL,
2816fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG_MSK);
28230d08503SDan Carpenter 	if (ret) {
28306999407SCarl Huang 		ath11k_warn(ab, "failed to set dtct config2: %d\n", ret);
28406999407SCarl Huang 		return ret;
28506999407SCarl Huang 	}
28606999407SCarl Huang 
28706999407SCarl Huang 	ret = ath11k_pci_set_link_reg(ab,
2886fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG4_REG(ab),
2896fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG4_VAL,
2906fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG_MSK);
29130d08503SDan Carpenter 	if (ret) {
29206999407SCarl Huang 		ath11k_warn(ab, "failed to set dtct config4: %d\n", ret);
29306999407SCarl Huang 		return ret;
29406999407SCarl Huang 	}
29506999407SCarl Huang 
29606999407SCarl Huang 	return 0;
29706999407SCarl Huang }
29806999407SCarl Huang 
299babb0cedSCarl Huang static void ath11k_pci_enable_ltssm(struct ath11k_base *ab)
300babb0cedSCarl Huang {
301babb0cedSCarl Huang 	u32 val;
302babb0cedSCarl Huang 	int i;
303babb0cedSCarl Huang 
304bbfdc5a7SManikanta Pubbisetty 	val = ath11k_pcic_read32(ab, PCIE_PCIE_PARF_LTSSM);
305babb0cedSCarl Huang 
306babb0cedSCarl Huang 	/* PCIE link seems very unstable after the Hot Reset*/
307babb0cedSCarl Huang 	for (i = 0; val != PARM_LTSSM_VALUE && i < 5; i++) {
308babb0cedSCarl Huang 		if (val == 0xffffffff)
309babb0cedSCarl Huang 			mdelay(5);
310babb0cedSCarl Huang 
311bbfdc5a7SManikanta Pubbisetty 		ath11k_pcic_write32(ab, PCIE_PCIE_PARF_LTSSM, PARM_LTSSM_VALUE);
312bbfdc5a7SManikanta Pubbisetty 		val = ath11k_pcic_read32(ab, PCIE_PCIE_PARF_LTSSM);
313babb0cedSCarl Huang 	}
314babb0cedSCarl Huang 
315fc3b984aSKalle Valo 	ath11k_dbg(ab, ATH11K_DBG_PCI, "ltssm 0x%x\n", val);
316babb0cedSCarl Huang 
317bbfdc5a7SManikanta Pubbisetty 	val = ath11k_pcic_read32(ab, GCC_GCC_PCIE_HOT_RST);
318562934adSKalle Valo 	val |= GCC_GCC_PCIE_HOT_RST_VAL;
319bbfdc5a7SManikanta Pubbisetty 	ath11k_pcic_write32(ab, GCC_GCC_PCIE_HOT_RST, val);
320bbfdc5a7SManikanta Pubbisetty 	val = ath11k_pcic_read32(ab, GCC_GCC_PCIE_HOT_RST);
321babb0cedSCarl Huang 
322fc3b984aSKalle Valo 	ath11k_dbg(ab, ATH11K_DBG_PCI, "pcie_hot_rst 0x%x\n", val);
323babb0cedSCarl Huang 
324babb0cedSCarl Huang 	mdelay(5);
325babb0cedSCarl Huang }
326babb0cedSCarl Huang 
327babb0cedSCarl Huang static void ath11k_pci_clear_all_intrs(struct ath11k_base *ab)
328babb0cedSCarl Huang {
329babb0cedSCarl Huang 	/* This is a WAR for PCIE Hotreset.
330babb0cedSCarl Huang 	 * When target receive Hotreset, but will set the interrupt.
331babb0cedSCarl Huang 	 * So when download SBL again, SBL will open Interrupt and
332babb0cedSCarl Huang 	 * receive it, and crash immediately.
333babb0cedSCarl Huang 	 */
334bbfdc5a7SManikanta Pubbisetty 	ath11k_pcic_write32(ab, PCIE_PCIE_INT_ALL_CLEAR, PCIE_INT_CLEAR_ALL);
335babb0cedSCarl Huang }
336babb0cedSCarl Huang 
3370ccdf439SCarl Huang static void ath11k_pci_set_wlaon_pwr_ctrl(struct ath11k_base *ab)
3380ccdf439SCarl Huang {
3390ccdf439SCarl Huang 	u32 val;
3400ccdf439SCarl Huang 
341bbfdc5a7SManikanta Pubbisetty 	val = ath11k_pcic_read32(ab, WLAON_QFPROM_PWR_CTRL_REG);
3420ccdf439SCarl Huang 	val &= ~QFPROM_PWR_CTRL_VDD4BLOW_MASK;
343bbfdc5a7SManikanta Pubbisetty 	ath11k_pcic_write32(ab, WLAON_QFPROM_PWR_CTRL_REG, val);
3440ccdf439SCarl Huang }
3450ccdf439SCarl Huang 
346f3c603d4SCarl Huang static void ath11k_pci_force_wake(struct ath11k_base *ab)
347f3c603d4SCarl Huang {
348bbfdc5a7SManikanta Pubbisetty 	ath11k_pcic_write32(ab, PCIE_SOC_WAKE_PCIE_LOCAL_REG, 1);
349f3c603d4SCarl Huang 	mdelay(5);
350f3c603d4SCarl Huang }
351f3c603d4SCarl Huang 
352babb0cedSCarl Huang static void ath11k_pci_sw_reset(struct ath11k_base *ab, bool power_on)
353f3c603d4SCarl Huang {
3548a0b899fSBaochen Qiang 	mdelay(100);
3558a0b899fSBaochen Qiang 
356babb0cedSCarl Huang 	if (power_on) {
357babb0cedSCarl Huang 		ath11k_pci_enable_ltssm(ab);
358babb0cedSCarl Huang 		ath11k_pci_clear_all_intrs(ab);
3590ccdf439SCarl Huang 		ath11k_pci_set_wlaon_pwr_ctrl(ab);
3605088df05SBaochen Qiang 		if (ab->hw_params.fix_l1ss)
36106999407SCarl Huang 			ath11k_pci_fix_l1ss(ab);
362babb0cedSCarl Huang 	}
363babb0cedSCarl Huang 
364f3c603d4SCarl Huang 	ath11k_mhi_clear_vector(ab);
3658a0b899fSBaochen Qiang 	ath11k_pci_clear_dbg_registers(ab);
366f3c603d4SCarl Huang 	ath11k_pci_soc_global_reset(ab);
367f3c603d4SCarl Huang 	ath11k_mhi_set_mhictrl_reset(ab);
368f3c603d4SCarl Huang }
369f3c603d4SCarl Huang 
3707f4beda2SGovind Singh static void ath11k_pci_init_qmi_ce_config(struct ath11k_base *ab)
3717f4beda2SGovind Singh {
3727f4beda2SGovind Singh 	struct ath11k_qmi_ce_cfg *cfg = &ab->qmi.ce_cfg;
3737f4beda2SGovind Singh 
374967c1d11SAnilkumar Kolli 	cfg->tgt_ce = ab->hw_params.target_ce_config;
375967c1d11SAnilkumar Kolli 	cfg->tgt_ce_len = ab->hw_params.target_ce_count;
3767f4beda2SGovind Singh 
377967c1d11SAnilkumar Kolli 	cfg->svc_to_ce_map = ab->hw_params.svc_to_ce_map;
378967c1d11SAnilkumar Kolli 	cfg->svc_to_ce_map_len = ab->hw_params.svc_to_ce_map_len;
37916001e4bSAnilkumar Kolli 	ab->qmi.service_ins_id = ab->hw_params.qmi_service_ins_id;
380e838c14aSCarl Huang 
381e838c14aSCarl Huang 	ath11k_ce_get_shadow_config(ab, &cfg->shadow_reg_v2,
382e838c14aSCarl Huang 				    &cfg->shadow_reg_v2_len);
3837f4beda2SGovind Singh }
3847f4beda2SGovind Singh 
38596527d52SBaochen Qiang static void ath11k_pci_msi_config(struct ath11k_pci *ab_pci, bool enable)
38696527d52SBaochen Qiang {
38796527d52SBaochen Qiang 	struct pci_dev *dev = ab_pci->pdev;
38896527d52SBaochen Qiang 	u16 control;
38996527d52SBaochen Qiang 
39096527d52SBaochen Qiang 	pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &control);
39196527d52SBaochen Qiang 
39296527d52SBaochen Qiang 	if (enable)
39396527d52SBaochen Qiang 		control |= PCI_MSI_FLAGS_ENABLE;
39496527d52SBaochen Qiang 	else
39596527d52SBaochen Qiang 		control &= ~PCI_MSI_FLAGS_ENABLE;
39696527d52SBaochen Qiang 
39796527d52SBaochen Qiang 	pci_write_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, control);
39896527d52SBaochen Qiang }
39996527d52SBaochen Qiang 
40096527d52SBaochen Qiang static void ath11k_pci_msi_enable(struct ath11k_pci *ab_pci)
40196527d52SBaochen Qiang {
40296527d52SBaochen Qiang 	ath11k_pci_msi_config(ab_pci, true);
40396527d52SBaochen Qiang }
40496527d52SBaochen Qiang 
40596527d52SBaochen Qiang static void ath11k_pci_msi_disable(struct ath11k_pci *ab_pci)
40696527d52SBaochen Qiang {
40796527d52SBaochen Qiang 	ath11k_pci_msi_config(ab_pci, false);
40896527d52SBaochen Qiang }
40996527d52SBaochen Qiang 
41096527d52SBaochen Qiang static int ath11k_pci_alloc_msi(struct ath11k_pci *ab_pci)
4115697a564SGovind Singh {
4125697a564SGovind Singh 	struct ath11k_base *ab = ab_pci->ab;
4130cfaf224SManikanta Pubbisetty 	const struct ath11k_msi_config *msi_config = ab->pci.msi.config;
4140cfaf224SManikanta Pubbisetty 	struct pci_dev *pci_dev = ab_pci->pdev;
4155697a564SGovind Singh 	struct msi_desc *msi_desc;
4165697a564SGovind Singh 	int num_vectors;
4175697a564SGovind Singh 	int ret;
4185697a564SGovind Singh 
4190cfaf224SManikanta Pubbisetty 	num_vectors = pci_alloc_irq_vectors(pci_dev,
4207a3aed0cSAnilkumar Kolli 					    msi_config->total_vectors,
4217a3aed0cSAnilkumar Kolli 					    msi_config->total_vectors,
4225697a564SGovind Singh 					    PCI_IRQ_MSI);
423ac6e7348SCarl Huang 	if (num_vectors == msi_config->total_vectors) {
4245b32b6ddSManikanta Pubbisetty 		set_bit(ATH11K_FLAG_MULTI_MSI_VECTORS, &ab->dev_flags);
425ac6e7348SCarl Huang 	} else {
426ac6e7348SCarl Huang 		num_vectors = pci_alloc_irq_vectors(ab_pci->pdev,
427ac6e7348SCarl Huang 						    1,
428ac6e7348SCarl Huang 						    1,
429ac6e7348SCarl Huang 						    PCI_IRQ_MSI);
430ac6e7348SCarl Huang 		if (num_vectors < 0) {
431ac6e7348SCarl Huang 			ret = -EINVAL;
432ac6e7348SCarl Huang 			goto reset_msi_config;
4335697a564SGovind Singh 		}
4345b32b6ddSManikanta Pubbisetty 		clear_bit(ATH11K_FLAG_MULTI_MSI_VECTORS, &ab->dev_flags);
4350cfaf224SManikanta Pubbisetty 		ab->pci.msi.config = &msi_config_one_msi;
436*332c6562SKalle Valo 		ath11k_dbg(ab, ATH11K_DBG_PCI, "request one msi vector\n");
437ac6e7348SCarl Huang 	}
438ac6e7348SCarl Huang 	ath11k_info(ab, "MSI vectors: %d\n", num_vectors);
439ac6e7348SCarl Huang 
44096527d52SBaochen Qiang 	ath11k_pci_msi_disable(ab_pci);
4415697a564SGovind Singh 
4425697a564SGovind Singh 	msi_desc = irq_get_msi_desc(ab_pci->pdev->irq);
4435697a564SGovind Singh 	if (!msi_desc) {
4445697a564SGovind Singh 		ath11k_err(ab, "msi_desc is NULL!\n");
4455697a564SGovind Singh 		ret = -EINVAL;
4465697a564SGovind Singh 		goto free_msi_vector;
4475697a564SGovind Singh 	}
4485697a564SGovind Singh 
4490cfaf224SManikanta Pubbisetty 	ab->pci.msi.ep_base_data = msi_desc->msg.data;
4505697a564SGovind Singh 
4510cfaf224SManikanta Pubbisetty 	pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_LO,
4520cfaf224SManikanta Pubbisetty 			      &ab->pci.msi.addr_lo);
4530cfaf224SManikanta Pubbisetty 
4540cfaf224SManikanta Pubbisetty 	if (msi_desc->pci.msi_attrib.is_64) {
4550cfaf224SManikanta Pubbisetty 		pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_HI,
4560cfaf224SManikanta Pubbisetty 				      &ab->pci.msi.addr_hi);
4570cfaf224SManikanta Pubbisetty 	} else {
4580cfaf224SManikanta Pubbisetty 		ab->pci.msi.addr_hi = 0;
4590cfaf224SManikanta Pubbisetty 	}
4600cfaf224SManikanta Pubbisetty 
4610cfaf224SManikanta Pubbisetty 	ath11k_dbg(ab, ATH11K_DBG_PCI, "msi base data is %d\n", ab->pci.msi.ep_base_data);
4625697a564SGovind Singh 
4635697a564SGovind Singh 	return 0;
4645697a564SGovind Singh 
4655697a564SGovind Singh free_msi_vector:
4665697a564SGovind Singh 	pci_free_irq_vectors(ab_pci->pdev);
4675697a564SGovind Singh 
468ac6e7348SCarl Huang reset_msi_config:
4695697a564SGovind Singh 	return ret;
4705697a564SGovind Singh }
4715697a564SGovind Singh 
47296527d52SBaochen Qiang static void ath11k_pci_free_msi(struct ath11k_pci *ab_pci)
4735697a564SGovind Singh {
4745697a564SGovind Singh 	pci_free_irq_vectors(ab_pci->pdev);
4755697a564SGovind Singh }
4765697a564SGovind Singh 
47787b4072dSCarl Huang static int ath11k_pci_config_msi_data(struct ath11k_pci *ab_pci)
47887b4072dSCarl Huang {
47987b4072dSCarl Huang 	struct msi_desc *msi_desc;
48087b4072dSCarl Huang 
48187b4072dSCarl Huang 	msi_desc = irq_get_msi_desc(ab_pci->pdev->irq);
48287b4072dSCarl Huang 	if (!msi_desc) {
48387b4072dSCarl Huang 		ath11k_err(ab_pci->ab, "msi_desc is NULL!\n");
48487b4072dSCarl Huang 		pci_free_irq_vectors(ab_pci->pdev);
48587b4072dSCarl Huang 		return -EINVAL;
48687b4072dSCarl Huang 	}
48787b4072dSCarl Huang 
4880cfaf224SManikanta Pubbisetty 	ab_pci->ab->pci.msi.ep_base_data = msi_desc->msg.data;
48987b4072dSCarl Huang 
490fc3b984aSKalle Valo 	ath11k_dbg(ab_pci->ab, ATH11K_DBG_PCI, "after request_irq msi_ep_base_data %d\n",
4910cfaf224SManikanta Pubbisetty 		   ab_pci->ab->pci.msi.ep_base_data);
49287b4072dSCarl Huang 
49387b4072dSCarl Huang 	return 0;
49487b4072dSCarl Huang }
49587b4072dSCarl Huang 
4965762613eSGovind Singh static int ath11k_pci_claim(struct ath11k_pci *ab_pci, struct pci_dev *pdev)
4975762613eSGovind Singh {
4985762613eSGovind Singh 	struct ath11k_base *ab = ab_pci->ab;
4995762613eSGovind Singh 	u16 device_id;
5005762613eSGovind Singh 	int ret = 0;
5015762613eSGovind Singh 
5025762613eSGovind Singh 	pci_read_config_word(pdev, PCI_DEVICE_ID, &device_id);
5035762613eSGovind Singh 	if (device_id != ab_pci->dev_id)  {
5045762613eSGovind Singh 		ath11k_err(ab, "pci device id mismatch: 0x%x 0x%x\n",
5055762613eSGovind Singh 			   device_id, ab_pci->dev_id);
5065762613eSGovind Singh 		ret = -EIO;
5075762613eSGovind Singh 		goto out;
5085762613eSGovind Singh 	}
5095762613eSGovind Singh 
5105762613eSGovind Singh 	ret = pci_assign_resource(pdev, ATH11K_PCI_BAR_NUM);
5115762613eSGovind Singh 	if (ret) {
5125762613eSGovind Singh 		ath11k_err(ab, "failed to assign pci resource: %d\n", ret);
5135762613eSGovind Singh 		goto out;
5145762613eSGovind Singh 	}
5155762613eSGovind Singh 
5165762613eSGovind Singh 	ret = pci_enable_device(pdev);
5175762613eSGovind Singh 	if (ret) {
5185762613eSGovind Singh 		ath11k_err(ab, "failed to enable pci device: %d\n", ret);
5195762613eSGovind Singh 		goto out;
5205762613eSGovind Singh 	}
5215762613eSGovind Singh 
5225762613eSGovind Singh 	ret = pci_request_region(pdev, ATH11K_PCI_BAR_NUM, "ath11k_pci");
5235762613eSGovind Singh 	if (ret) {
5245762613eSGovind Singh 		ath11k_err(ab, "failed to request pci region: %d\n", ret);
5255762613eSGovind Singh 		goto disable_device;
5265762613eSGovind Singh 	}
5275762613eSGovind Singh 
528923a1346SChristophe JAILLET 	ret = dma_set_mask_and_coherent(&pdev->dev,
529923a1346SChristophe JAILLET 					DMA_BIT_MASK(ATH11K_PCI_DMA_MASK));
5305762613eSGovind Singh 	if (ret) {
5315762613eSGovind Singh 		ath11k_err(ab, "failed to set pci dma mask to %d: %d\n",
5325762613eSGovind Singh 			   ATH11K_PCI_DMA_MASK, ret);
5335762613eSGovind Singh 		goto release_region;
5345762613eSGovind Singh 	}
5355762613eSGovind Singh 
5365762613eSGovind Singh 	pci_set_master(pdev);
5375762613eSGovind Singh 
5385762613eSGovind Singh 	ab->mem_len = pci_resource_len(pdev, ATH11K_PCI_BAR_NUM);
5395762613eSGovind Singh 	ab->mem = pci_iomap(pdev, ATH11K_PCI_BAR_NUM, 0);
5405762613eSGovind Singh 	if (!ab->mem) {
5415762613eSGovind Singh 		ath11k_err(ab, "failed to map pci bar %d\n", ATH11K_PCI_BAR_NUM);
5425762613eSGovind Singh 		ret = -EIO;
543f812e2a9SCai Huoqing 		goto release_region;
5445762613eSGovind Singh 	}
5455762613eSGovind Singh 
546b42b3678SSriram R 	ab->mem_ce = ab->mem;
547b42b3678SSriram R 
548fc3b984aSKalle Valo 	ath11k_dbg(ab, ATH11K_DBG_BOOT, "pci_mem 0x%pK\n", ab->mem);
5495762613eSGovind Singh 	return 0;
5505762613eSGovind Singh 
5515762613eSGovind Singh release_region:
5525762613eSGovind Singh 	pci_release_region(pdev, ATH11K_PCI_BAR_NUM);
5535762613eSGovind Singh disable_device:
5545762613eSGovind Singh 	pci_disable_device(pdev);
5555762613eSGovind Singh out:
5565762613eSGovind Singh 	return ret;
5575762613eSGovind Singh }
5585762613eSGovind Singh 
5595762613eSGovind Singh static void ath11k_pci_free_region(struct ath11k_pci *ab_pci)
5605762613eSGovind Singh {
5615762613eSGovind Singh 	struct ath11k_base *ab = ab_pci->ab;
5625762613eSGovind Singh 	struct pci_dev *pci_dev = ab_pci->pdev;
5635762613eSGovind Singh 
5645762613eSGovind Singh 	pci_iounmap(pci_dev, ab->mem);
5655762613eSGovind Singh 	ab->mem = NULL;
5665762613eSGovind Singh 	pci_release_region(pci_dev, ATH11K_PCI_BAR_NUM);
5675762613eSGovind Singh 	if (pci_is_enabled(pci_dev))
5685762613eSGovind Singh 		pci_disable_device(pci_dev);
5695762613eSGovind Singh }
5705762613eSGovind Singh 
571e9603f4bSCarl Huang static void ath11k_pci_aspm_disable(struct ath11k_pci *ab_pci)
572e9603f4bSCarl Huang {
573e9603f4bSCarl Huang 	struct ath11k_base *ab = ab_pci->ab;
574e9603f4bSCarl Huang 
575e9603f4bSCarl Huang 	pcie_capability_read_word(ab_pci->pdev, PCI_EXP_LNKCTL,
576e9603f4bSCarl Huang 				  &ab_pci->link_ctl);
577e9603f4bSCarl Huang 
578fc3b984aSKalle Valo 	ath11k_dbg(ab, ATH11K_DBG_PCI, "link_ctl 0x%04x L0s %d L1 %d\n",
579e9603f4bSCarl Huang 		   ab_pci->link_ctl,
580e9603f4bSCarl Huang 		   u16_get_bits(ab_pci->link_ctl, PCI_EXP_LNKCTL_ASPM_L0S),
581e9603f4bSCarl Huang 		   u16_get_bits(ab_pci->link_ctl, PCI_EXP_LNKCTL_ASPM_L1));
582e9603f4bSCarl Huang 
583e9603f4bSCarl Huang 	/* disable L0s and L1 */
584e9603f4bSCarl Huang 	pcie_capability_write_word(ab_pci->pdev, PCI_EXP_LNKCTL,
585e9603f4bSCarl Huang 				   ab_pci->link_ctl & ~PCI_EXP_LNKCTL_ASPMC);
586e9603f4bSCarl Huang 
587e9603f4bSCarl Huang 	set_bit(ATH11K_PCI_ASPM_RESTORE, &ab_pci->flags);
588e9603f4bSCarl Huang }
589e9603f4bSCarl Huang 
5905b32b6ddSManikanta Pubbisetty static void ath11k_pci_aspm_restore(struct ath11k_pci *ab_pci)
5915b32b6ddSManikanta Pubbisetty {
5925b32b6ddSManikanta Pubbisetty 	if (test_and_clear_bit(ATH11K_PCI_ASPM_RESTORE, &ab_pci->flags))
5935b32b6ddSManikanta Pubbisetty 		pcie_capability_write_word(ab_pci->pdev, PCI_EXP_LNKCTL,
5945b32b6ddSManikanta Pubbisetty 					   ab_pci->link_ctl);
5955b32b6ddSManikanta Pubbisetty }
5965b32b6ddSManikanta Pubbisetty 
5971399fb87SGovind Singh static int ath11k_pci_power_up(struct ath11k_base *ab)
5981399fb87SGovind Singh {
5991399fb87SGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
6001399fb87SGovind Singh 	int ret;
6011399fb87SGovind Singh 
602a05bd851SCarl Huang 	ab_pci->register_window = 0;
6035b32b6ddSManikanta Pubbisetty 	clear_bit(ATH11K_FLAG_DEVICE_INIT_DONE, &ab->dev_flags);
604babb0cedSCarl Huang 	ath11k_pci_sw_reset(ab_pci->ab, true);
605f3c603d4SCarl Huang 
606e9603f4bSCarl Huang 	/* Disable ASPM during firmware download due to problems switching
607e9603f4bSCarl Huang 	 * to AMSS state.
608e9603f4bSCarl Huang 	 */
609e9603f4bSCarl Huang 	ath11k_pci_aspm_disable(ab_pci);
610e9603f4bSCarl Huang 
61196527d52SBaochen Qiang 	ath11k_pci_msi_enable(ab_pci);
61296527d52SBaochen Qiang 
6131399fb87SGovind Singh 	ret = ath11k_mhi_start(ab_pci);
6141399fb87SGovind Singh 	if (ret) {
6151399fb87SGovind Singh 		ath11k_err(ab, "failed to start mhi: %d\n", ret);
6161399fb87SGovind Singh 		return ret;
6171399fb87SGovind Singh 	}
6181399fb87SGovind Singh 
61992c1858eSManikanta Pubbisetty 	if (ab->hw_params.static_window_map)
620480a7361SKarthikeyan Periyasamy 		ath11k_pci_select_static_window(ab_pci);
621480a7361SKarthikeyan Periyasamy 
6221399fb87SGovind Singh 	return 0;
6231399fb87SGovind Singh }
6241399fb87SGovind Singh 
6251399fb87SGovind Singh static void ath11k_pci_power_down(struct ath11k_base *ab)
6261399fb87SGovind Singh {
6271399fb87SGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
6281399fb87SGovind Singh 
629e9603f4bSCarl Huang 	/* restore aspm in case firmware bootup fails */
6305b32b6ddSManikanta Pubbisetty 	ath11k_pci_aspm_restore(ab_pci);
631e9603f4bSCarl Huang 
632babb0cedSCarl Huang 	ath11k_pci_force_wake(ab_pci->ab);
63396527d52SBaochen Qiang 
63496527d52SBaochen Qiang 	ath11k_pci_msi_disable(ab_pci);
63596527d52SBaochen Qiang 
6361399fb87SGovind Singh 	ath11k_mhi_stop(ab_pci);
6375b32b6ddSManikanta Pubbisetty 	clear_bit(ATH11K_FLAG_DEVICE_INIT_DONE, &ab->dev_flags);
638babb0cedSCarl Huang 	ath11k_pci_sw_reset(ab_pci->ab, false);
6391399fb87SGovind Singh }
6401399fb87SGovind Singh 
641fa5917e4SCarl Huang static int ath11k_pci_hif_suspend(struct ath11k_base *ab)
642fa5917e4SCarl Huang {
643fa5917e4SCarl Huang 	struct ath11k_pci *ar_pci = ath11k_pci_priv(ab);
644fa5917e4SCarl Huang 
6453e80fcbcSKalle Valo 	return ath11k_mhi_suspend(ar_pci);
646fa5917e4SCarl Huang }
647fa5917e4SCarl Huang 
648fa5917e4SCarl Huang static int ath11k_pci_hif_resume(struct ath11k_base *ab)
649fa5917e4SCarl Huang {
650fa5917e4SCarl Huang 	struct ath11k_pci *ar_pci = ath11k_pci_priv(ab);
651fa5917e4SCarl Huang 
6523e80fcbcSKalle Valo 	return ath11k_mhi_resume(ar_pci);
653fa5917e4SCarl Huang }
654fa5917e4SCarl Huang 
655d578ec2aSCarl Huang static void ath11k_pci_hif_ce_irq_enable(struct ath11k_base *ab)
656d578ec2aSCarl Huang {
657bbfdc5a7SManikanta Pubbisetty 	ath11k_pcic_ce_irqs_enable(ab);
658d578ec2aSCarl Huang }
659d578ec2aSCarl Huang 
660d578ec2aSCarl Huang static void ath11k_pci_hif_ce_irq_disable(struct ath11k_base *ab)
661d578ec2aSCarl Huang {
662bbfdc5a7SManikanta Pubbisetty 	ath11k_pcic_ce_irq_disable_sync(ab);
6637f4beda2SGovind Singh }
6647f4beda2SGovind Singh 
6655b32b6ddSManikanta Pubbisetty static int ath11k_pci_start(struct ath11k_base *ab)
6665b32b6ddSManikanta Pubbisetty {
6675b32b6ddSManikanta Pubbisetty 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
6685b32b6ddSManikanta Pubbisetty 
6695b32b6ddSManikanta Pubbisetty 	/* TODO: for now don't restore ASPM in case of single MSI
6705b32b6ddSManikanta Pubbisetty 	 * vector as MHI register reading in M2 causes system hang.
6715b32b6ddSManikanta Pubbisetty 	 */
6725b32b6ddSManikanta Pubbisetty 	if (test_bit(ATH11K_FLAG_MULTI_MSI_VECTORS, &ab->dev_flags))
6735b32b6ddSManikanta Pubbisetty 		ath11k_pci_aspm_restore(ab_pci);
6745b32b6ddSManikanta Pubbisetty 	else
6755b32b6ddSManikanta Pubbisetty 		ath11k_info(ab, "leaving PCI ASPM disabled to avoid MHI M2 problems\n");
6765b32b6ddSManikanta Pubbisetty 
6775b32b6ddSManikanta Pubbisetty 	ath11k_pcic_start(ab);
6785b32b6ddSManikanta Pubbisetty 
6795b32b6ddSManikanta Pubbisetty 	return 0;
6805b32b6ddSManikanta Pubbisetty }
6815b32b6ddSManikanta Pubbisetty 
6827f4beda2SGovind Singh static const struct ath11k_hif_ops ath11k_pci_hif_ops = {
6835b32b6ddSManikanta Pubbisetty 	.start = ath11k_pci_start,
684bbfdc5a7SManikanta Pubbisetty 	.stop = ath11k_pcic_stop,
685bbfdc5a7SManikanta Pubbisetty 	.read32 = ath11k_pcic_read32,
686bbfdc5a7SManikanta Pubbisetty 	.write32 = ath11k_pcic_write32,
687876eb848SBaochen Qiang 	.read = ath11k_pcic_read,
6881399fb87SGovind Singh 	.power_down = ath11k_pci_power_down,
6891399fb87SGovind Singh 	.power_up = ath11k_pci_power_up,
690fa5917e4SCarl Huang 	.suspend = ath11k_pci_hif_suspend,
691fa5917e4SCarl Huang 	.resume = ath11k_pci_hif_resume,
692bbfdc5a7SManikanta Pubbisetty 	.irq_enable = ath11k_pcic_ext_irq_enable,
693bbfdc5a7SManikanta Pubbisetty 	.irq_disable = ath11k_pcic_ext_irq_disable,
694bbfdc5a7SManikanta Pubbisetty 	.get_msi_address =  ath11k_pcic_get_msi_address,
6950cfaf224SManikanta Pubbisetty 	.get_user_msi_vector = ath11k_pcic_get_user_msi_assignment,
696bbfdc5a7SManikanta Pubbisetty 	.map_service_to_pipe = ath11k_pcic_map_service_to_pipe,
697d578ec2aSCarl Huang 	.ce_irq_enable = ath11k_pci_hif_ce_irq_enable,
698d578ec2aSCarl Huang 	.ce_irq_disable = ath11k_pci_hif_ce_irq_disable,
699bbfdc5a7SManikanta Pubbisetty 	.get_ce_msi_idx = ath11k_pcic_get_ce_msi_idx,
7001399fb87SGovind Singh };
7011399fb87SGovind Singh 
7020fbf1957SBaochen Qiang static void ath11k_pci_read_hw_version(struct ath11k_base *ab, u32 *major, u32 *minor)
7030fbf1957SBaochen Qiang {
7040fbf1957SBaochen Qiang 	u32 soc_hw_version;
7050fbf1957SBaochen Qiang 
706bbfdc5a7SManikanta Pubbisetty 	soc_hw_version = ath11k_pcic_read32(ab, TCSR_SOC_HW_VERSION);
7070fbf1957SBaochen Qiang 	*major = FIELD_GET(TCSR_SOC_HW_VERSION_MAJOR_MASK,
7080fbf1957SBaochen Qiang 			   soc_hw_version);
7090fbf1957SBaochen Qiang 	*minor = FIELD_GET(TCSR_SOC_HW_VERSION_MINOR_MASK,
7100fbf1957SBaochen Qiang 			   soc_hw_version);
7110fbf1957SBaochen Qiang 
712fc3b984aSKalle Valo 	ath11k_dbg(ab, ATH11K_DBG_PCI, "tcsr_soc_hw_version major %d minor %d\n",
7130fbf1957SBaochen Qiang 		   *major, *minor);
7140fbf1957SBaochen Qiang }
7150fbf1957SBaochen Qiang 
7165b32b6ddSManikanta Pubbisetty static int ath11k_pci_set_irq_affinity_hint(struct ath11k_pci *ab_pci,
7175b32b6ddSManikanta Pubbisetty 					    const struct cpumask *m)
7185b32b6ddSManikanta Pubbisetty {
7195b32b6ddSManikanta Pubbisetty 	if (test_bit(ATH11K_FLAG_MULTI_MSI_VECTORS, &ab_pci->ab->dev_flags))
7205b32b6ddSManikanta Pubbisetty 		return 0;
7215b32b6ddSManikanta Pubbisetty 
7225b32b6ddSManikanta Pubbisetty 	return irq_set_affinity_hint(ab_pci->pdev->irq, m);
7235b32b6ddSManikanta Pubbisetty }
7245b32b6ddSManikanta Pubbisetty 
7256e0355afSGovind Singh static int ath11k_pci_probe(struct pci_dev *pdev,
7266e0355afSGovind Singh 			    const struct pci_device_id *pci_dev)
7276e0355afSGovind Singh {
7286e0355afSGovind Singh 	struct ath11k_base *ab;
7295762613eSGovind Singh 	struct ath11k_pci *ab_pci;
7306ac04bdcSAnilkumar Kolli 	u32 soc_hw_version_major, soc_hw_version_minor, addr;
731867f4eeeSManikanta Pubbisetty 	const struct ath11k_pci_ops *pci_ops;
7325762613eSGovind Singh 	int ret;
7336e0355afSGovind Singh 
73492c1858eSManikanta Pubbisetty 	ab = ath11k_core_alloc(&pdev->dev, sizeof(*ab_pci), ATH11K_BUS_PCI);
73592c1858eSManikanta Pubbisetty 
7366e0355afSGovind Singh 	if (!ab) {
7376e0355afSGovind Singh 		dev_err(&pdev->dev, "failed to allocate ath11k base\n");
7386e0355afSGovind Singh 		return -ENOMEM;
7396e0355afSGovind Singh 	}
7406e0355afSGovind Singh 
7416e0355afSGovind Singh 	ab->dev = &pdev->dev;
7426e0355afSGovind Singh 	pci_set_drvdata(pdev, ab);
7435762613eSGovind Singh 	ab_pci = ath11k_pci_priv(ab);
7445762613eSGovind Singh 	ab_pci->dev_id = pci_dev->device;
7455762613eSGovind Singh 	ab_pci->ab = ab;
7465697a564SGovind Singh 	ab_pci->pdev = pdev;
7477f4beda2SGovind Singh 	ab->hif.ops = &ath11k_pci_hif_ops;
748b43310e4SGovindaraj Saminathan 	ab->fw_mode = ATH11K_FIRMWARE_MODE_NORMAL;
7495762613eSGovind Singh 	pci_set_drvdata(pdev, ab);
750654e959aSGovind Singh 	spin_lock_init(&ab_pci->window_lock);
7515762613eSGovind Singh 
7526ac04bdcSAnilkumar Kolli 	/* Set fixed_mem_region to true for platforms support reserved memory
7536ac04bdcSAnilkumar Kolli 	 * from DT. If memory is reserved from DT for FW, ath11k driver need not
7546ac04bdcSAnilkumar Kolli 	 * allocate memory.
7556ac04bdcSAnilkumar Kolli 	 */
7566ac04bdcSAnilkumar Kolli 	ret = of_property_read_u32(ab->dev->of_node, "memory-region", &addr);
7576ac04bdcSAnilkumar Kolli 	if (!ret)
7586ac04bdcSAnilkumar Kolli 		set_bit(ATH11K_FLAG_FIXED_MEM_RGN, &ab->dev_flags);
7596ac04bdcSAnilkumar Kolli 
7605762613eSGovind Singh 	ret = ath11k_pci_claim(ab_pci, pdev);
7615762613eSGovind Singh 	if (ret) {
7625762613eSGovind Singh 		ath11k_err(ab, "failed to claim device: %d\n", ret);
7635762613eSGovind Singh 		goto err_free_core;
7645762613eSGovind Singh 	}
7656e0355afSGovind Singh 
766fc95d10aSWen Gong 	ath11k_dbg(ab, ATH11K_DBG_BOOT, "pci probe %04x:%04x %04x:%04x\n",
767fc95d10aSWen Gong 		   pdev->vendor, pdev->device,
768fc95d10aSWen Gong 		   pdev->subsystem_vendor, pdev->subsystem_device);
769fc95d10aSWen Gong 
770fc95d10aSWen Gong 	ab->id.vendor = pdev->vendor;
771fc95d10aSWen Gong 	ab->id.device = pdev->device;
772fc95d10aSWen Gong 	ab->id.subsystem_vendor = pdev->subsystem_vendor;
773fc95d10aSWen Gong 	ab->id.subsystem_device = pdev->subsystem_device;
774fc95d10aSWen Gong 
77518ac1665SKalle Valo 	switch (pci_dev->device) {
77618ac1665SKalle Valo 	case QCA6390_DEVICE_ID:
7770fbf1957SBaochen Qiang 		ath11k_pci_read_hw_version(ab, &soc_hw_version_major,
7780fbf1957SBaochen Qiang 					   &soc_hw_version_minor);
77918ac1665SKalle Valo 		switch (soc_hw_version_major) {
78018ac1665SKalle Valo 		case 2:
78118ac1665SKalle Valo 			ab->hw_rev = ATH11K_HW_QCA6390_HW20;
78218ac1665SKalle Valo 			break;
78318ac1665SKalle Valo 		default:
78418ac1665SKalle Valo 			dev_err(&pdev->dev, "Unsupported QCA6390 SOC hardware version: %d %d\n",
78518ac1665SKalle Valo 				soc_hw_version_major, soc_hw_version_minor);
78618ac1665SKalle Valo 			ret = -EOPNOTSUPP;
78718ac1665SKalle Valo 			goto err_pci_free_region;
78818ac1665SKalle Valo 		}
7895b32b6ddSManikanta Pubbisetty 
790867f4eeeSManikanta Pubbisetty 		pci_ops = &ath11k_pci_ops_qca6390;
7914e809461SAnilkumar Kolli 		break;
7924e809461SAnilkumar Kolli 	case QCN9074_DEVICE_ID:
793867f4eeeSManikanta Pubbisetty 		pci_ops = &ath11k_pci_ops_qcn9074;
7944e809461SAnilkumar Kolli 		ab->hw_rev = ATH11K_HW_QCN9074_HW10;
79518ac1665SKalle Valo 		break;
7960fbf1957SBaochen Qiang 	case WCN6855_DEVICE_ID:
797fc95d10aSWen Gong 		ab->id.bdf_search = ATH11K_BDF_SEARCH_BUS_AND_BOARD;
7980fbf1957SBaochen Qiang 		ath11k_pci_read_hw_version(ab, &soc_hw_version_major,
7990fbf1957SBaochen Qiang 					   &soc_hw_version_minor);
8000fbf1957SBaochen Qiang 		switch (soc_hw_version_major) {
8010fbf1957SBaochen Qiang 		case 2:
802d1147a31SBaochen Qiang 			switch (soc_hw_version_minor) {
803d1147a31SBaochen Qiang 			case 0x00:
804d1147a31SBaochen Qiang 			case 0x01:
8050fbf1957SBaochen Qiang 				ab->hw_rev = ATH11K_HW_WCN6855_HW20;
8060fbf1957SBaochen Qiang 				break;
807d1147a31SBaochen Qiang 			case 0x10:
808d1147a31SBaochen Qiang 			case 0x11:
809d1147a31SBaochen Qiang 				ab->hw_rev = ATH11K_HW_WCN6855_HW21;
810d1147a31SBaochen Qiang 				break;
8110fbf1957SBaochen Qiang 			default:
812d1147a31SBaochen Qiang 				goto unsupported_wcn6855_soc;
813d1147a31SBaochen Qiang 			}
814d1147a31SBaochen Qiang 			break;
815d1147a31SBaochen Qiang 		default:
816d1147a31SBaochen Qiang unsupported_wcn6855_soc:
8170fbf1957SBaochen Qiang 			dev_err(&pdev->dev, "Unsupported WCN6855 SOC hardware version: %d %d\n",
8180fbf1957SBaochen Qiang 				soc_hw_version_major, soc_hw_version_minor);
8190fbf1957SBaochen Qiang 			ret = -EOPNOTSUPP;
8200fbf1957SBaochen Qiang 			goto err_pci_free_region;
8210fbf1957SBaochen Qiang 		}
8225b32b6ddSManikanta Pubbisetty 
823867f4eeeSManikanta Pubbisetty 		pci_ops = &ath11k_pci_ops_qca6390;
8240fbf1957SBaochen Qiang 		break;
82518ac1665SKalle Valo 	default:
82618ac1665SKalle Valo 		dev_err(&pdev->dev, "Unknown PCI device found: 0x%x\n",
82718ac1665SKalle Valo 			pci_dev->device);
82818ac1665SKalle Valo 		ret = -EOPNOTSUPP;
82918ac1665SKalle Valo 		goto err_pci_free_region;
83018ac1665SKalle Valo 	}
83118ac1665SKalle Valo 
832867f4eeeSManikanta Pubbisetty 	ret = ath11k_pcic_register_pci_ops(ab, pci_ops);
833867f4eeeSManikanta Pubbisetty 	if (ret) {
834867f4eeeSManikanta Pubbisetty 		ath11k_err(ab, "failed to register PCI ops: %d\n", ret);
835867f4eeeSManikanta Pubbisetty 		goto err_pci_free_region;
836867f4eeeSManikanta Pubbisetty 	}
837867f4eeeSManikanta Pubbisetty 
8388d06b802SManikanta Pubbisetty 	ret = ath11k_pcic_init_msi_config(ab);
8398d06b802SManikanta Pubbisetty 	if (ret) {
8408d06b802SManikanta Pubbisetty 		ath11k_err(ab, "failed to init msi config: %d\n", ret);
8418d06b802SManikanta Pubbisetty 		goto err_pci_free_region;
8428d06b802SManikanta Pubbisetty 	}
8438d06b802SManikanta Pubbisetty 
84496527d52SBaochen Qiang 	ret = ath11k_pci_alloc_msi(ab_pci);
8455697a564SGovind Singh 	if (ret) {
8465697a564SGovind Singh 		ath11k_err(ab, "failed to enable msi: %d\n", ret);
8475697a564SGovind Singh 		goto err_pci_free_region;
8485697a564SGovind Singh 	}
8495697a564SGovind Singh 
850b8246f88SKalle Valo 	ret = ath11k_core_pre_init(ab);
851b8246f88SKalle Valo 	if (ret)
852b8246f88SKalle Valo 		goto err_pci_disable_msi;
853b8246f88SKalle Valo 
8541399fb87SGovind Singh 	ret = ath11k_mhi_register(ab_pci);
8551399fb87SGovind Singh 	if (ret) {
8561399fb87SGovind Singh 		ath11k_err(ab, "failed to register mhi: %d\n", ret);
8571399fb87SGovind Singh 		goto err_pci_disable_msi;
8581399fb87SGovind Singh 	}
8591399fb87SGovind Singh 
8607f4beda2SGovind Singh 	ret = ath11k_hal_srng_init(ab);
8617f4beda2SGovind Singh 	if (ret)
8627f4beda2SGovind Singh 		goto err_mhi_unregister;
8637f4beda2SGovind Singh 
8647f4beda2SGovind Singh 	ret = ath11k_ce_alloc_pipes(ab);
8657f4beda2SGovind Singh 	if (ret) {
8667f4beda2SGovind Singh 		ath11k_err(ab, "failed to allocate ce pipes: %d\n", ret);
8677f4beda2SGovind Singh 		goto err_hal_srng_deinit;
8687f4beda2SGovind Singh 	}
8697f4beda2SGovind Singh 
8707f4beda2SGovind Singh 	ath11k_pci_init_qmi_ce_config(ab);
8717f4beda2SGovind Singh 
872bbfdc5a7SManikanta Pubbisetty 	ret = ath11k_pcic_config_irq(ab);
8737f4beda2SGovind Singh 	if (ret) {
8747f4beda2SGovind Singh 		ath11k_err(ab, "failed to config irq: %d\n", ret);
8757f4beda2SGovind Singh 		goto err_ce_free;
8767f4beda2SGovind Singh 	}
8777f4beda2SGovind Singh 
8785b32b6ddSManikanta Pubbisetty 	ret = ath11k_pci_set_irq_affinity_hint(ab_pci, cpumask_of(0));
8795b32b6ddSManikanta Pubbisetty 	if (ret) {
8805b32b6ddSManikanta Pubbisetty 		ath11k_err(ab, "failed to set irq affinity %d\n", ret);
8815b32b6ddSManikanta Pubbisetty 		goto err_free_irq;
8825b32b6ddSManikanta Pubbisetty 	}
8835b32b6ddSManikanta Pubbisetty 
88487b4072dSCarl Huang 	/* kernel may allocate a dummy vector before request_irq and
88587b4072dSCarl Huang 	 * then allocate a real vector when request_irq is called.
88687b4072dSCarl Huang 	 * So get msi_data here again to avoid spurious interrupt
88787b4072dSCarl Huang 	 * as msi_data will configured to srngs.
88887b4072dSCarl Huang 	 */
88987b4072dSCarl Huang 	ret = ath11k_pci_config_msi_data(ab_pci);
89087b4072dSCarl Huang 	if (ret) {
89187b4072dSCarl Huang 		ath11k_err(ab, "failed to config msi_data: %d\n", ret);
8925b32b6ddSManikanta Pubbisetty 		goto err_irq_affinity_cleanup;
89387b4072dSCarl Huang 	}
89487b4072dSCarl Huang 
8957f4beda2SGovind Singh 	ret = ath11k_core_init(ab);
8967f4beda2SGovind Singh 	if (ret) {
8977f4beda2SGovind Singh 		ath11k_err(ab, "failed to init core: %d\n", ret);
8985b32b6ddSManikanta Pubbisetty 		goto err_irq_affinity_cleanup;
8997f4beda2SGovind Singh 	}
9006e0355afSGovind Singh 	return 0;
9015762613eSGovind Singh 
9025b32b6ddSManikanta Pubbisetty err_irq_affinity_cleanup:
9035b32b6ddSManikanta Pubbisetty 	ath11k_pci_set_irq_affinity_hint(ab_pci, NULL);
9045b32b6ddSManikanta Pubbisetty 
9057f4beda2SGovind Singh err_free_irq:
906bbfdc5a7SManikanta Pubbisetty 	ath11k_pcic_free_irq(ab);
9077f4beda2SGovind Singh 
9087f4beda2SGovind Singh err_ce_free:
9097f4beda2SGovind Singh 	ath11k_ce_free_pipes(ab);
9107f4beda2SGovind Singh 
9117f4beda2SGovind Singh err_hal_srng_deinit:
9127f4beda2SGovind Singh 	ath11k_hal_srng_deinit(ab);
9137f4beda2SGovind Singh 
9147f4beda2SGovind Singh err_mhi_unregister:
9157f4beda2SGovind Singh 	ath11k_mhi_unregister(ab_pci);
9167f4beda2SGovind Singh 
917b8246f88SKalle Valo err_pci_disable_msi:
91896527d52SBaochen Qiang 	ath11k_pci_free_msi(ab_pci);
919b8246f88SKalle Valo 
9205697a564SGovind Singh err_pci_free_region:
9215697a564SGovind Singh 	ath11k_pci_free_region(ab_pci);
9225697a564SGovind Singh 
9235762613eSGovind Singh err_free_core:
9245762613eSGovind Singh 	ath11k_core_free(ab);
9255697a564SGovind Singh 
9265762613eSGovind Singh 	return ret;
9276e0355afSGovind Singh }
9286e0355afSGovind Singh 
9296e0355afSGovind Singh static void ath11k_pci_remove(struct pci_dev *pdev)
9306e0355afSGovind Singh {
9316e0355afSGovind Singh 	struct ath11k_base *ab = pci_get_drvdata(pdev);
9325762613eSGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
9336e0355afSGovind Singh 
9345b32b6ddSManikanta Pubbisetty 	ath11k_pci_set_irq_affinity_hint(ab_pci, NULL);
935e94b0749SBaochen Qiang 
93661a57e51SAnilkumar Kolli 	if (test_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags)) {
93761a57e51SAnilkumar Kolli 		ath11k_pci_power_down(ab);
93861a57e51SAnilkumar Kolli 		ath11k_debugfs_soc_destroy(ab);
93961a57e51SAnilkumar Kolli 		ath11k_qmi_deinit_service(ab);
94061a57e51SAnilkumar Kolli 		goto qmi_fail;
94161a57e51SAnilkumar Kolli 	}
94261a57e51SAnilkumar Kolli 
9436e0355afSGovind Singh 	set_bit(ATH11K_FLAG_UNREGISTERING, &ab->dev_flags);
9446fbd8898SCarl Huang 
9456fbd8898SCarl Huang 	ath11k_core_deinit(ab);
9466fbd8898SCarl Huang 
94761a57e51SAnilkumar Kolli qmi_fail:
9481399fb87SGovind Singh 	ath11k_mhi_unregister(ab_pci);
9496fbd8898SCarl Huang 
950bbfdc5a7SManikanta Pubbisetty 	ath11k_pcic_free_irq(ab);
95196527d52SBaochen Qiang 	ath11k_pci_free_msi(ab_pci);
9525762613eSGovind Singh 	ath11k_pci_free_region(ab_pci);
9536fbd8898SCarl Huang 
9546fbd8898SCarl Huang 	ath11k_hal_srng_deinit(ab);
9556fbd8898SCarl Huang 	ath11k_ce_free_pipes(ab);
9566e0355afSGovind Singh 	ath11k_core_free(ab);
9576e0355afSGovind Singh }
9586e0355afSGovind Singh 
9591399fb87SGovind Singh static void ath11k_pci_shutdown(struct pci_dev *pdev)
9601399fb87SGovind Singh {
9611399fb87SGovind Singh 	struct ath11k_base *ab = pci_get_drvdata(pdev);
9623bd0c696SJohan Hovold 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
9631399fb87SGovind Singh 
9643bd0c696SJohan Hovold 	ath11k_pci_set_irq_affinity_hint(ab_pci, NULL);
9651399fb87SGovind Singh 	ath11k_pci_power_down(ab);
9661399fb87SGovind Singh }
9671399fb87SGovind Singh 
968d1b0c338SCarl Huang static __maybe_unused int ath11k_pci_pm_suspend(struct device *dev)
969d1b0c338SCarl Huang {
970d1b0c338SCarl Huang 	struct ath11k_base *ab = dev_get_drvdata(dev);
971d1b0c338SCarl Huang 	int ret;
972d1b0c338SCarl Huang 
973b4f4c564SKalle Valo 	if (test_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags)) {
974b4f4c564SKalle Valo 		ath11k_dbg(ab, ATH11K_DBG_BOOT, "boot skipping pci suspend as qmi is not initialised\n");
975b4f4c564SKalle Valo 		return 0;
976b4f4c564SKalle Valo 	}
977b4f4c564SKalle Valo 
978d1b0c338SCarl Huang 	ret = ath11k_core_suspend(ab);
979d1b0c338SCarl Huang 	if (ret)
980d1b0c338SCarl Huang 		ath11k_warn(ab, "failed to suspend core: %d\n", ret);
981d1b0c338SCarl Huang 
9827c154308SLen Brown 	return 0;
983d1b0c338SCarl Huang }
984d1b0c338SCarl Huang 
985d1b0c338SCarl Huang static __maybe_unused int ath11k_pci_pm_resume(struct device *dev)
986d1b0c338SCarl Huang {
987d1b0c338SCarl Huang 	struct ath11k_base *ab = dev_get_drvdata(dev);
988d1b0c338SCarl Huang 	int ret;
989d1b0c338SCarl Huang 
990b4f4c564SKalle Valo 	if (test_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags)) {
991b4f4c564SKalle Valo 		ath11k_dbg(ab, ATH11K_DBG_BOOT, "boot skipping pci resume as qmi is not initialised\n");
992b4f4c564SKalle Valo 		return 0;
993b4f4c564SKalle Valo 	}
994b4f4c564SKalle Valo 
995d1b0c338SCarl Huang 	ret = ath11k_core_resume(ab);
996d1b0c338SCarl Huang 	if (ret)
997d1b0c338SCarl Huang 		ath11k_warn(ab, "failed to resume core: %d\n", ret);
998d1b0c338SCarl Huang 
999d1b0c338SCarl Huang 	return ret;
1000d1b0c338SCarl Huang }
1001d1b0c338SCarl Huang 
1002d1b0c338SCarl Huang static SIMPLE_DEV_PM_OPS(ath11k_pci_pm_ops,
1003d1b0c338SCarl Huang 			 ath11k_pci_pm_suspend,
1004d1b0c338SCarl Huang 			 ath11k_pci_pm_resume);
1005d1b0c338SCarl Huang 
10066e0355afSGovind Singh static struct pci_driver ath11k_pci_driver = {
10076e0355afSGovind Singh 	.name = "ath11k_pci",
10086e0355afSGovind Singh 	.id_table = ath11k_pci_id_table,
10096e0355afSGovind Singh 	.probe = ath11k_pci_probe,
10106e0355afSGovind Singh 	.remove = ath11k_pci_remove,
10111399fb87SGovind Singh 	.shutdown = ath11k_pci_shutdown,
1012d1b0c338SCarl Huang #ifdef CONFIG_PM
1013d1b0c338SCarl Huang 	.driver.pm = &ath11k_pci_pm_ops,
1014d1b0c338SCarl Huang #endif
10156e0355afSGovind Singh };
10166e0355afSGovind Singh 
10176e0355afSGovind Singh static int ath11k_pci_init(void)
10186e0355afSGovind Singh {
10196e0355afSGovind Singh 	int ret;
10206e0355afSGovind Singh 
10216e0355afSGovind Singh 	ret = pci_register_driver(&ath11k_pci_driver);
10226e0355afSGovind Singh 	if (ret)
10236e0355afSGovind Singh 		pr_err("failed to register ath11k pci driver: %d\n",
10246e0355afSGovind Singh 		       ret);
10256e0355afSGovind Singh 
10266e0355afSGovind Singh 	return ret;
10276e0355afSGovind Singh }
10286e0355afSGovind Singh module_init(ath11k_pci_init);
10296e0355afSGovind Singh 
10306e0355afSGovind Singh static void ath11k_pci_exit(void)
10316e0355afSGovind Singh {
10326e0355afSGovind Singh 	pci_unregister_driver(&ath11k_pci_driver);
10336e0355afSGovind Singh }
10346e0355afSGovind Singh 
10356e0355afSGovind Singh module_exit(ath11k_pci_exit);
10366e0355afSGovind Singh 
10376e0355afSGovind Singh MODULE_DESCRIPTION("Driver support for Qualcomm Technologies 802.11ax WLAN PCIe devices");
10386e0355afSGovind Singh MODULE_LICENSE("Dual BSD/GPL");
10393dbd7fe7SDevin Bayer 
104006c58473STakashi Iwai /* firmware files */
104106c58473STakashi Iwai MODULE_FIRMWARE(ATH11K_FW_DIR "/QCA6390/hw2.0/*");
104206c58473STakashi Iwai MODULE_FIRMWARE(ATH11K_FW_DIR "/QCN9074/hw1.0/*");
104306c58473STakashi Iwai MODULE_FIRMWARE(ATH11K_FW_DIR "/WCN6855/hw2.0/*");
104406c58473STakashi Iwai MODULE_FIRMWARE(ATH11K_FW_DIR "/WCN6855/hw2.1/*");
1045