xref: /openbmc/linux/drivers/net/wireless/ath/ath11k/pci.c (revision bbfdc5a751a634fcdaae669cc98b3d0e1dc0eedf)
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"
17*bbfdc5a7SManikanta 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 
467a3aed0cSAnilkumar Kolli static const struct ath11k_msi_config ath11k_msi_config[] = {
477a3aed0cSAnilkumar Kolli 	{
485697a564SGovind Singh 		.total_vectors = 32,
495697a564SGovind Singh 		.total_users = 4,
505697a564SGovind Singh 		.users = (struct ath11k_msi_user[]) {
515697a564SGovind Singh 			{ .name = "MHI", .num_vectors = 3, .base_vector = 0 },
525697a564SGovind Singh 			{ .name = "CE", .num_vectors = 10, .base_vector = 3 },
535697a564SGovind Singh 			{ .name = "WAKE", .num_vectors = 1, .base_vector = 13 },
545697a564SGovind Singh 			{ .name = "DP", .num_vectors = 18, .base_vector = 14 },
555697a564SGovind Singh 		},
567a3aed0cSAnilkumar Kolli 	},
574e809461SAnilkumar Kolli 	{
584e809461SAnilkumar Kolli 		.total_vectors = 16,
594e809461SAnilkumar Kolli 		.total_users = 3,
604e809461SAnilkumar Kolli 		.users = (struct ath11k_msi_user[]) {
614e809461SAnilkumar Kolli 			{ .name = "MHI", .num_vectors = 3, .base_vector = 0 },
624e809461SAnilkumar Kolli 			{ .name = "CE", .num_vectors = 5, .base_vector = 3 },
634e809461SAnilkumar Kolli 			{ .name = "DP", .num_vectors = 8, .base_vector = 8 },
644e809461SAnilkumar Kolli 		},
654e809461SAnilkumar Kolli 	},
665697a564SGovind Singh };
675697a564SGovind Singh 
68ac6e7348SCarl Huang static const struct ath11k_msi_config msi_config_one_msi = {
69ac6e7348SCarl Huang 	.total_vectors = 1,
70ac6e7348SCarl Huang 	.total_users = 4,
71ac6e7348SCarl Huang 	.users = (struct ath11k_msi_user[]) {
72ac6e7348SCarl Huang 		{ .name = "MHI", .num_vectors = 3, .base_vector = 0 },
73ac6e7348SCarl Huang 		{ .name = "CE", .num_vectors = 1, .base_vector = 0 },
74ac6e7348SCarl Huang 		{ .name = "WAKE", .num_vectors = 1, .base_vector = 0 },
75ac6e7348SCarl Huang 		{ .name = "DP", .num_vectors = 1, .base_vector = 0 },
76ac6e7348SCarl Huang 	},
77ac6e7348SCarl Huang };
78ac6e7348SCarl Huang 
79480a7361SKarthikeyan Periyasamy static inline void ath11k_pci_select_static_window(struct ath11k_pci *ab_pci)
80480a7361SKarthikeyan Periyasamy {
81948171b5SManikanta Pubbisetty 	u32 umac_window;
82948171b5SManikanta Pubbisetty 	u32 ce_window;
83480a7361SKarthikeyan Periyasamy 	u32 window;
84480a7361SKarthikeyan Periyasamy 
85948171b5SManikanta Pubbisetty 	umac_window = FIELD_GET(ATH11K_PCI_WINDOW_VALUE_MASK, HAL_SEQ_WCSS_UMAC_OFFSET);
86948171b5SManikanta Pubbisetty 	ce_window = FIELD_GET(ATH11K_PCI_WINDOW_VALUE_MASK, HAL_CE_WFSS_CE_REG_BASE);
87480a7361SKarthikeyan Periyasamy 	window = (umac_window << 12) | (ce_window << 6);
88480a7361SKarthikeyan Periyasamy 
89948171b5SManikanta Pubbisetty 	iowrite32(ATH11K_PCI_WINDOW_ENABLE_BIT | window,
90948171b5SManikanta Pubbisetty 		  ab_pci->ab->mem + ATH11K_PCI_WINDOW_REG_ADDRESS);
91480a7361SKarthikeyan Periyasamy }
92480a7361SKarthikeyan Periyasamy 
93f3c603d4SCarl Huang static void ath11k_pci_soc_global_reset(struct ath11k_base *ab)
94f3c603d4SCarl Huang {
95f3c603d4SCarl Huang 	u32 val, delay;
96f3c603d4SCarl Huang 
97*bbfdc5a7SManikanta Pubbisetty 	val = ath11k_pcic_read32(ab, PCIE_SOC_GLOBAL_RESET);
98f3c603d4SCarl Huang 
99f3c603d4SCarl Huang 	val |= PCIE_SOC_GLOBAL_RESET_V;
100f3c603d4SCarl Huang 
101*bbfdc5a7SManikanta Pubbisetty 	ath11k_pcic_write32(ab, PCIE_SOC_GLOBAL_RESET, val);
102f3c603d4SCarl Huang 
103f3c603d4SCarl Huang 	/* TODO: exact time to sleep is uncertain */
104f3c603d4SCarl Huang 	delay = 10;
105f3c603d4SCarl Huang 	mdelay(delay);
106f3c603d4SCarl Huang 
107f3c603d4SCarl Huang 	/* Need to toggle V bit back otherwise stuck in reset status */
108f3c603d4SCarl Huang 	val &= ~PCIE_SOC_GLOBAL_RESET_V;
109f3c603d4SCarl Huang 
110*bbfdc5a7SManikanta Pubbisetty 	ath11k_pcic_write32(ab, PCIE_SOC_GLOBAL_RESET, val);
111f3c603d4SCarl Huang 
112f3c603d4SCarl Huang 	mdelay(delay);
113f3c603d4SCarl Huang 
114*bbfdc5a7SManikanta Pubbisetty 	val = ath11k_pcic_read32(ab, PCIE_SOC_GLOBAL_RESET);
115f3c603d4SCarl Huang 	if (val == 0xffffffff)
116f3c603d4SCarl Huang 		ath11k_warn(ab, "link down error during global reset\n");
117f3c603d4SCarl Huang }
118f3c603d4SCarl Huang 
119f3c603d4SCarl Huang static void ath11k_pci_clear_dbg_registers(struct ath11k_base *ab)
120f3c603d4SCarl Huang {
121f3c603d4SCarl Huang 	u32 val;
122f3c603d4SCarl Huang 
123f3c603d4SCarl Huang 	/* read cookie */
124*bbfdc5a7SManikanta Pubbisetty 	val = ath11k_pcic_read32(ab, PCIE_Q6_COOKIE_ADDR);
125f3c603d4SCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "cookie:0x%x\n", val);
126f3c603d4SCarl Huang 
127*bbfdc5a7SManikanta Pubbisetty 	val = ath11k_pcic_read32(ab, WLAON_WARM_SW_ENTRY);
128f3c603d4SCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "WLAON_WARM_SW_ENTRY 0x%x\n", val);
129f3c603d4SCarl Huang 
130f3c603d4SCarl Huang 	/* TODO: exact time to sleep is uncertain */
131f3c603d4SCarl Huang 	mdelay(10);
132f3c603d4SCarl Huang 
133f3c603d4SCarl Huang 	/* write 0 to WLAON_WARM_SW_ENTRY to prevent Q6 from
134f3c603d4SCarl Huang 	 * continuing warm path and entering dead loop.
135f3c603d4SCarl Huang 	 */
136*bbfdc5a7SManikanta Pubbisetty 	ath11k_pcic_write32(ab, WLAON_WARM_SW_ENTRY, 0);
137f3c603d4SCarl Huang 	mdelay(10);
138f3c603d4SCarl Huang 
139*bbfdc5a7SManikanta Pubbisetty 	val = ath11k_pcic_read32(ab, WLAON_WARM_SW_ENTRY);
140f3c603d4SCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "WLAON_WARM_SW_ENTRY 0x%x\n", val);
141f3c603d4SCarl Huang 
142f3c603d4SCarl Huang 	/* A read clear register. clear the register to prevent
143f3c603d4SCarl Huang 	 * Q6 from entering wrong code path.
144f3c603d4SCarl Huang 	 */
145*bbfdc5a7SManikanta Pubbisetty 	val = ath11k_pcic_read32(ab, WLAON_SOC_RESET_CAUSE_REG);
146f3c603d4SCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "soc reset cause:%d\n", val);
147f3c603d4SCarl Huang }
148f3c603d4SCarl Huang 
14906999407SCarl Huang static int ath11k_pci_set_link_reg(struct ath11k_base *ab,
15006999407SCarl Huang 				   u32 offset, u32 value, u32 mask)
15106999407SCarl Huang {
15206999407SCarl Huang 	u32 v;
15306999407SCarl Huang 	int i;
15406999407SCarl Huang 
155*bbfdc5a7SManikanta Pubbisetty 	v = ath11k_pcic_read32(ab, offset);
15606999407SCarl Huang 	if ((v & mask) == value)
15706999407SCarl Huang 		return 0;
15806999407SCarl Huang 
15906999407SCarl Huang 	for (i = 0; i < 10; i++) {
160*bbfdc5a7SManikanta Pubbisetty 		ath11k_pcic_write32(ab, offset, (v & ~mask) | value);
16106999407SCarl Huang 
162*bbfdc5a7SManikanta Pubbisetty 		v = ath11k_pcic_read32(ab, offset);
16306999407SCarl Huang 		if ((v & mask) == value)
16406999407SCarl Huang 			return 0;
16506999407SCarl Huang 
16606999407SCarl Huang 		mdelay(2);
16706999407SCarl Huang 	}
16806999407SCarl Huang 
16906999407SCarl Huang 	ath11k_warn(ab, "failed to set pcie link register 0x%08x: 0x%08x != 0x%08x\n",
17006999407SCarl Huang 		    offset, v & mask, value);
17106999407SCarl Huang 
17206999407SCarl Huang 	return -ETIMEDOUT;
17306999407SCarl Huang }
17406999407SCarl Huang 
17506999407SCarl Huang static int ath11k_pci_fix_l1ss(struct ath11k_base *ab)
17606999407SCarl Huang {
17706999407SCarl Huang 	int ret;
17806999407SCarl Huang 
17906999407SCarl Huang 	ret = ath11k_pci_set_link_reg(ab,
1806fe6f68fSKarthikeyan Periyasamy 				      PCIE_QSERDES_COM_SYSCLK_EN_SEL_REG(ab),
18106999407SCarl Huang 				      PCIE_QSERDES_COM_SYSCLK_EN_SEL_VAL,
18206999407SCarl Huang 				      PCIE_QSERDES_COM_SYSCLK_EN_SEL_MSK);
18330d08503SDan Carpenter 	if (ret) {
18406999407SCarl Huang 		ath11k_warn(ab, "failed to set sysclk: %d\n", ret);
18506999407SCarl Huang 		return ret;
18606999407SCarl Huang 	}
18706999407SCarl Huang 
18806999407SCarl Huang 	ret = ath11k_pci_set_link_reg(ab,
1896fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG1_REG(ab),
1906fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG1_VAL,
1916fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG_MSK);
19230d08503SDan Carpenter 	if (ret) {
19306999407SCarl Huang 		ath11k_warn(ab, "failed to set dtct config1 error: %d\n", ret);
19406999407SCarl Huang 		return ret;
19506999407SCarl Huang 	}
19606999407SCarl Huang 
19706999407SCarl Huang 	ret = ath11k_pci_set_link_reg(ab,
1986fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG2_REG(ab),
1996fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG2_VAL,
2006fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG_MSK);
20130d08503SDan Carpenter 	if (ret) {
20206999407SCarl Huang 		ath11k_warn(ab, "failed to set dtct config2: %d\n", ret);
20306999407SCarl Huang 		return ret;
20406999407SCarl Huang 	}
20506999407SCarl Huang 
20606999407SCarl Huang 	ret = ath11k_pci_set_link_reg(ab,
2076fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG4_REG(ab),
2086fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG4_VAL,
2096fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG_MSK);
21030d08503SDan Carpenter 	if (ret) {
21106999407SCarl Huang 		ath11k_warn(ab, "failed to set dtct config4: %d\n", ret);
21206999407SCarl Huang 		return ret;
21306999407SCarl Huang 	}
21406999407SCarl Huang 
21506999407SCarl Huang 	return 0;
21606999407SCarl Huang }
21706999407SCarl Huang 
218babb0cedSCarl Huang static void ath11k_pci_enable_ltssm(struct ath11k_base *ab)
219babb0cedSCarl Huang {
220babb0cedSCarl Huang 	u32 val;
221babb0cedSCarl Huang 	int i;
222babb0cedSCarl Huang 
223*bbfdc5a7SManikanta Pubbisetty 	val = ath11k_pcic_read32(ab, PCIE_PCIE_PARF_LTSSM);
224babb0cedSCarl Huang 
225babb0cedSCarl Huang 	/* PCIE link seems very unstable after the Hot Reset*/
226babb0cedSCarl Huang 	for (i = 0; val != PARM_LTSSM_VALUE && i < 5; i++) {
227babb0cedSCarl Huang 		if (val == 0xffffffff)
228babb0cedSCarl Huang 			mdelay(5);
229babb0cedSCarl Huang 
230*bbfdc5a7SManikanta Pubbisetty 		ath11k_pcic_write32(ab, PCIE_PCIE_PARF_LTSSM, PARM_LTSSM_VALUE);
231*bbfdc5a7SManikanta Pubbisetty 		val = ath11k_pcic_read32(ab, PCIE_PCIE_PARF_LTSSM);
232babb0cedSCarl Huang 	}
233babb0cedSCarl Huang 
234babb0cedSCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "pci ltssm 0x%x\n", val);
235babb0cedSCarl Huang 
236*bbfdc5a7SManikanta Pubbisetty 	val = ath11k_pcic_read32(ab, GCC_GCC_PCIE_HOT_RST);
237562934adSKalle Valo 	val |= GCC_GCC_PCIE_HOT_RST_VAL;
238*bbfdc5a7SManikanta Pubbisetty 	ath11k_pcic_write32(ab, GCC_GCC_PCIE_HOT_RST, val);
239*bbfdc5a7SManikanta Pubbisetty 	val = ath11k_pcic_read32(ab, GCC_GCC_PCIE_HOT_RST);
240babb0cedSCarl Huang 
241babb0cedSCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "pci pcie_hot_rst 0x%x\n", val);
242babb0cedSCarl Huang 
243babb0cedSCarl Huang 	mdelay(5);
244babb0cedSCarl Huang }
245babb0cedSCarl Huang 
246babb0cedSCarl Huang static void ath11k_pci_clear_all_intrs(struct ath11k_base *ab)
247babb0cedSCarl Huang {
248babb0cedSCarl Huang 	/* This is a WAR for PCIE Hotreset.
249babb0cedSCarl Huang 	 * When target receive Hotreset, but will set the interrupt.
250babb0cedSCarl Huang 	 * So when download SBL again, SBL will open Interrupt and
251babb0cedSCarl Huang 	 * receive it, and crash immediately.
252babb0cedSCarl Huang 	 */
253*bbfdc5a7SManikanta Pubbisetty 	ath11k_pcic_write32(ab, PCIE_PCIE_INT_ALL_CLEAR, PCIE_INT_CLEAR_ALL);
254babb0cedSCarl Huang }
255babb0cedSCarl Huang 
2560ccdf439SCarl Huang static void ath11k_pci_set_wlaon_pwr_ctrl(struct ath11k_base *ab)
2570ccdf439SCarl Huang {
2580ccdf439SCarl Huang 	u32 val;
2590ccdf439SCarl Huang 
260*bbfdc5a7SManikanta Pubbisetty 	val = ath11k_pcic_read32(ab, WLAON_QFPROM_PWR_CTRL_REG);
2610ccdf439SCarl Huang 	val &= ~QFPROM_PWR_CTRL_VDD4BLOW_MASK;
262*bbfdc5a7SManikanta Pubbisetty 	ath11k_pcic_write32(ab, WLAON_QFPROM_PWR_CTRL_REG, val);
2630ccdf439SCarl Huang }
2640ccdf439SCarl Huang 
265f3c603d4SCarl Huang static void ath11k_pci_force_wake(struct ath11k_base *ab)
266f3c603d4SCarl Huang {
267*bbfdc5a7SManikanta Pubbisetty 	ath11k_pcic_write32(ab, PCIE_SOC_WAKE_PCIE_LOCAL_REG, 1);
268f3c603d4SCarl Huang 	mdelay(5);
269f3c603d4SCarl Huang }
270f3c603d4SCarl Huang 
271babb0cedSCarl Huang static void ath11k_pci_sw_reset(struct ath11k_base *ab, bool power_on)
272f3c603d4SCarl Huang {
2738a0b899fSBaochen Qiang 	mdelay(100);
2748a0b899fSBaochen Qiang 
275babb0cedSCarl Huang 	if (power_on) {
276babb0cedSCarl Huang 		ath11k_pci_enable_ltssm(ab);
277babb0cedSCarl Huang 		ath11k_pci_clear_all_intrs(ab);
2780ccdf439SCarl Huang 		ath11k_pci_set_wlaon_pwr_ctrl(ab);
2795088df05SBaochen Qiang 		if (ab->hw_params.fix_l1ss)
28006999407SCarl Huang 			ath11k_pci_fix_l1ss(ab);
281babb0cedSCarl Huang 	}
282babb0cedSCarl Huang 
283f3c603d4SCarl Huang 	ath11k_mhi_clear_vector(ab);
2848a0b899fSBaochen Qiang 	ath11k_pci_clear_dbg_registers(ab);
285f3c603d4SCarl Huang 	ath11k_pci_soc_global_reset(ab);
286f3c603d4SCarl Huang 	ath11k_mhi_set_mhictrl_reset(ab);
287f3c603d4SCarl Huang }
288f3c603d4SCarl Huang 
2897f4beda2SGovind Singh static void ath11k_pci_init_qmi_ce_config(struct ath11k_base *ab)
2907f4beda2SGovind Singh {
2917f4beda2SGovind Singh 	struct ath11k_qmi_ce_cfg *cfg = &ab->qmi.ce_cfg;
2927f4beda2SGovind Singh 
293967c1d11SAnilkumar Kolli 	cfg->tgt_ce = ab->hw_params.target_ce_config;
294967c1d11SAnilkumar Kolli 	cfg->tgt_ce_len = ab->hw_params.target_ce_count;
2957f4beda2SGovind Singh 
296967c1d11SAnilkumar Kolli 	cfg->svc_to_ce_map = ab->hw_params.svc_to_ce_map;
297967c1d11SAnilkumar Kolli 	cfg->svc_to_ce_map_len = ab->hw_params.svc_to_ce_map_len;
29816001e4bSAnilkumar Kolli 	ab->qmi.service_ins_id = ab->hw_params.qmi_service_ins_id;
299e838c14aSCarl Huang 
300e838c14aSCarl Huang 	ath11k_ce_get_shadow_config(ab, &cfg->shadow_reg_v2,
301e838c14aSCarl Huang 				    &cfg->shadow_reg_v2_len);
3027f4beda2SGovind Singh }
3037f4beda2SGovind Singh 
30496527d52SBaochen Qiang static void ath11k_pci_msi_config(struct ath11k_pci *ab_pci, bool enable)
30596527d52SBaochen Qiang {
30696527d52SBaochen Qiang 	struct pci_dev *dev = ab_pci->pdev;
30796527d52SBaochen Qiang 	u16 control;
30896527d52SBaochen Qiang 
30996527d52SBaochen Qiang 	pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &control);
31096527d52SBaochen Qiang 
31196527d52SBaochen Qiang 	if (enable)
31296527d52SBaochen Qiang 		control |= PCI_MSI_FLAGS_ENABLE;
31396527d52SBaochen Qiang 	else
31496527d52SBaochen Qiang 		control &= ~PCI_MSI_FLAGS_ENABLE;
31596527d52SBaochen Qiang 
31696527d52SBaochen Qiang 	pci_write_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, control);
31796527d52SBaochen Qiang }
31896527d52SBaochen Qiang 
31996527d52SBaochen Qiang static void ath11k_pci_msi_enable(struct ath11k_pci *ab_pci)
32096527d52SBaochen Qiang {
32196527d52SBaochen Qiang 	ath11k_pci_msi_config(ab_pci, true);
32296527d52SBaochen Qiang }
32396527d52SBaochen Qiang 
32496527d52SBaochen Qiang static void ath11k_pci_msi_disable(struct ath11k_pci *ab_pci)
32596527d52SBaochen Qiang {
32696527d52SBaochen Qiang 	ath11k_pci_msi_config(ab_pci, false);
32796527d52SBaochen Qiang }
32896527d52SBaochen Qiang 
32996527d52SBaochen Qiang static int ath11k_pci_alloc_msi(struct ath11k_pci *ab_pci)
3305697a564SGovind Singh {
3315697a564SGovind Singh 	struct ath11k_base *ab = ab_pci->ab;
3327a3aed0cSAnilkumar Kolli 	const struct ath11k_msi_config *msi_config = ab_pci->msi_config;
3335697a564SGovind Singh 	struct msi_desc *msi_desc;
3345697a564SGovind Singh 	int num_vectors;
3355697a564SGovind Singh 	int ret;
3365697a564SGovind Singh 
3375697a564SGovind Singh 	num_vectors = pci_alloc_irq_vectors(ab_pci->pdev,
3387a3aed0cSAnilkumar Kolli 					    msi_config->total_vectors,
3397a3aed0cSAnilkumar Kolli 					    msi_config->total_vectors,
3405697a564SGovind Singh 					    PCI_IRQ_MSI);
341ac6e7348SCarl Huang 	if (num_vectors == msi_config->total_vectors) {
342c41a6700SCarl Huang 		set_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags);
343c41a6700SCarl Huang 		ab_pci->irq_flags = IRQF_SHARED;
344ac6e7348SCarl Huang 	} else {
345ac6e7348SCarl Huang 		num_vectors = pci_alloc_irq_vectors(ab_pci->pdev,
346ac6e7348SCarl Huang 						    1,
347ac6e7348SCarl Huang 						    1,
348ac6e7348SCarl Huang 						    PCI_IRQ_MSI);
349ac6e7348SCarl Huang 		if (num_vectors < 0) {
350ac6e7348SCarl Huang 			ret = -EINVAL;
351ac6e7348SCarl Huang 			goto reset_msi_config;
3525697a564SGovind Singh 		}
353ac6e7348SCarl Huang 		clear_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags);
354ac6e7348SCarl Huang 		ab_pci->msi_config = &msi_config_one_msi;
355ac6e7348SCarl Huang 		ab_pci->irq_flags = IRQF_SHARED | IRQF_NOBALANCING;
356ac6e7348SCarl Huang 		ath11k_dbg(ab, ATH11K_DBG_PCI, "request MSI one vector\n");
357ac6e7348SCarl Huang 	}
358ac6e7348SCarl Huang 	ath11k_info(ab, "MSI vectors: %d\n", num_vectors);
359ac6e7348SCarl Huang 
36096527d52SBaochen Qiang 	ath11k_pci_msi_disable(ab_pci);
3615697a564SGovind Singh 
3625697a564SGovind Singh 	msi_desc = irq_get_msi_desc(ab_pci->pdev->irq);
3635697a564SGovind Singh 	if (!msi_desc) {
3645697a564SGovind Singh 		ath11k_err(ab, "msi_desc is NULL!\n");
3655697a564SGovind Singh 		ret = -EINVAL;
3665697a564SGovind Singh 		goto free_msi_vector;
3675697a564SGovind Singh 	}
3685697a564SGovind Singh 
3695697a564SGovind Singh 	ab_pci->msi_ep_base_data = msi_desc->msg.data;
370e58f2259SThomas Gleixner 	if (msi_desc->pci.msi_attrib.is_64)
371e8e55d89SAnilkumar Kolli 		set_bit(ATH11K_PCI_FLAG_IS_MSI_64, &ab_pci->flags);
3725697a564SGovind Singh 
3735697a564SGovind Singh 	ath11k_dbg(ab, ATH11K_DBG_PCI, "msi base data is %d\n", ab_pci->msi_ep_base_data);
3745697a564SGovind Singh 
3755697a564SGovind Singh 	return 0;
3765697a564SGovind Singh 
3775697a564SGovind Singh free_msi_vector:
3785697a564SGovind Singh 	pci_free_irq_vectors(ab_pci->pdev);
3795697a564SGovind Singh 
380ac6e7348SCarl Huang reset_msi_config:
3815697a564SGovind Singh 	return ret;
3825697a564SGovind Singh }
3835697a564SGovind Singh 
38496527d52SBaochen Qiang static void ath11k_pci_free_msi(struct ath11k_pci *ab_pci)
3855697a564SGovind Singh {
3865697a564SGovind Singh 	pci_free_irq_vectors(ab_pci->pdev);
3875697a564SGovind Singh }
3885697a564SGovind Singh 
38987b4072dSCarl Huang static int ath11k_pci_config_msi_data(struct ath11k_pci *ab_pci)
39087b4072dSCarl Huang {
39187b4072dSCarl Huang 	struct msi_desc *msi_desc;
39287b4072dSCarl Huang 
39387b4072dSCarl Huang 	msi_desc = irq_get_msi_desc(ab_pci->pdev->irq);
39487b4072dSCarl Huang 	if (!msi_desc) {
39587b4072dSCarl Huang 		ath11k_err(ab_pci->ab, "msi_desc is NULL!\n");
39687b4072dSCarl Huang 		pci_free_irq_vectors(ab_pci->pdev);
39787b4072dSCarl Huang 		return -EINVAL;
39887b4072dSCarl Huang 	}
39987b4072dSCarl Huang 
40087b4072dSCarl Huang 	ab_pci->msi_ep_base_data = msi_desc->msg.data;
40187b4072dSCarl Huang 
40287b4072dSCarl Huang 	ath11k_dbg(ab_pci->ab, ATH11K_DBG_PCI, "pci after request_irq msi_ep_base_data %d\n",
40387b4072dSCarl Huang 		   ab_pci->msi_ep_base_data);
40487b4072dSCarl Huang 
40587b4072dSCarl Huang 	return 0;
40687b4072dSCarl Huang }
40787b4072dSCarl Huang 
4085762613eSGovind Singh static int ath11k_pci_claim(struct ath11k_pci *ab_pci, struct pci_dev *pdev)
4095762613eSGovind Singh {
4105762613eSGovind Singh 	struct ath11k_base *ab = ab_pci->ab;
4115762613eSGovind Singh 	u16 device_id;
4125762613eSGovind Singh 	int ret = 0;
4135762613eSGovind Singh 
4145762613eSGovind Singh 	pci_read_config_word(pdev, PCI_DEVICE_ID, &device_id);
4155762613eSGovind Singh 	if (device_id != ab_pci->dev_id)  {
4165762613eSGovind Singh 		ath11k_err(ab, "pci device id mismatch: 0x%x 0x%x\n",
4175762613eSGovind Singh 			   device_id, ab_pci->dev_id);
4185762613eSGovind Singh 		ret = -EIO;
4195762613eSGovind Singh 		goto out;
4205762613eSGovind Singh 	}
4215762613eSGovind Singh 
4225762613eSGovind Singh 	ret = pci_assign_resource(pdev, ATH11K_PCI_BAR_NUM);
4235762613eSGovind Singh 	if (ret) {
4245762613eSGovind Singh 		ath11k_err(ab, "failed to assign pci resource: %d\n", ret);
4255762613eSGovind Singh 		goto out;
4265762613eSGovind Singh 	}
4275762613eSGovind Singh 
4285762613eSGovind Singh 	ret = pci_enable_device(pdev);
4295762613eSGovind Singh 	if (ret) {
4305762613eSGovind Singh 		ath11k_err(ab, "failed to enable pci device: %d\n", ret);
4315762613eSGovind Singh 		goto out;
4325762613eSGovind Singh 	}
4335762613eSGovind Singh 
4345762613eSGovind Singh 	ret = pci_request_region(pdev, ATH11K_PCI_BAR_NUM, "ath11k_pci");
4355762613eSGovind Singh 	if (ret) {
4365762613eSGovind Singh 		ath11k_err(ab, "failed to request pci region: %d\n", ret);
4375762613eSGovind Singh 		goto disable_device;
4385762613eSGovind Singh 	}
4395762613eSGovind Singh 
440923a1346SChristophe JAILLET 	ret = dma_set_mask_and_coherent(&pdev->dev,
441923a1346SChristophe JAILLET 					DMA_BIT_MASK(ATH11K_PCI_DMA_MASK));
4425762613eSGovind Singh 	if (ret) {
4435762613eSGovind Singh 		ath11k_err(ab, "failed to set pci dma mask to %d: %d\n",
4445762613eSGovind Singh 			   ATH11K_PCI_DMA_MASK, ret);
4455762613eSGovind Singh 		goto release_region;
4465762613eSGovind Singh 	}
4475762613eSGovind Singh 
4485762613eSGovind Singh 	pci_set_master(pdev);
4495762613eSGovind Singh 
4505762613eSGovind Singh 	ab->mem_len = pci_resource_len(pdev, ATH11K_PCI_BAR_NUM);
4515762613eSGovind Singh 	ab->mem = pci_iomap(pdev, ATH11K_PCI_BAR_NUM, 0);
4525762613eSGovind Singh 	if (!ab->mem) {
4535762613eSGovind Singh 		ath11k_err(ab, "failed to map pci bar %d\n", ATH11K_PCI_BAR_NUM);
4545762613eSGovind Singh 		ret = -EIO;
4555762613eSGovind Singh 		goto clear_master;
4565762613eSGovind Singh 	}
4575762613eSGovind Singh 
4585762613eSGovind Singh 	ath11k_dbg(ab, ATH11K_DBG_BOOT, "boot pci_mem 0x%pK\n", ab->mem);
4595762613eSGovind Singh 	return 0;
4605762613eSGovind Singh 
4615762613eSGovind Singh clear_master:
4625762613eSGovind Singh 	pci_clear_master(pdev);
4635762613eSGovind Singh release_region:
4645762613eSGovind Singh 	pci_release_region(pdev, ATH11K_PCI_BAR_NUM);
4655762613eSGovind Singh disable_device:
4665762613eSGovind Singh 	pci_disable_device(pdev);
4675762613eSGovind Singh out:
4685762613eSGovind Singh 	return ret;
4695762613eSGovind Singh }
4705762613eSGovind Singh 
4715762613eSGovind Singh static void ath11k_pci_free_region(struct ath11k_pci *ab_pci)
4725762613eSGovind Singh {
4735762613eSGovind Singh 	struct ath11k_base *ab = ab_pci->ab;
4745762613eSGovind Singh 	struct pci_dev *pci_dev = ab_pci->pdev;
4755762613eSGovind Singh 
4765762613eSGovind Singh 	pci_iounmap(pci_dev, ab->mem);
4775762613eSGovind Singh 	ab->mem = NULL;
4785762613eSGovind Singh 	pci_clear_master(pci_dev);
4795762613eSGovind Singh 	pci_release_region(pci_dev, ATH11K_PCI_BAR_NUM);
4805762613eSGovind Singh 	if (pci_is_enabled(pci_dev))
4815762613eSGovind Singh 		pci_disable_device(pci_dev);
4825762613eSGovind Singh }
4835762613eSGovind Singh 
484e9603f4bSCarl Huang static void ath11k_pci_aspm_disable(struct ath11k_pci *ab_pci)
485e9603f4bSCarl Huang {
486e9603f4bSCarl Huang 	struct ath11k_base *ab = ab_pci->ab;
487e9603f4bSCarl Huang 
488e9603f4bSCarl Huang 	pcie_capability_read_word(ab_pci->pdev, PCI_EXP_LNKCTL,
489e9603f4bSCarl Huang 				  &ab_pci->link_ctl);
490e9603f4bSCarl Huang 
491e9603f4bSCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "pci link_ctl 0x%04x L0s %d L1 %d\n",
492e9603f4bSCarl Huang 		   ab_pci->link_ctl,
493e9603f4bSCarl Huang 		   u16_get_bits(ab_pci->link_ctl, PCI_EXP_LNKCTL_ASPM_L0S),
494e9603f4bSCarl Huang 		   u16_get_bits(ab_pci->link_ctl, PCI_EXP_LNKCTL_ASPM_L1));
495e9603f4bSCarl Huang 
496e9603f4bSCarl Huang 	/* disable L0s and L1 */
497e9603f4bSCarl Huang 	pcie_capability_write_word(ab_pci->pdev, PCI_EXP_LNKCTL,
498e9603f4bSCarl Huang 				   ab_pci->link_ctl & ~PCI_EXP_LNKCTL_ASPMC);
499e9603f4bSCarl Huang 
500e9603f4bSCarl Huang 	set_bit(ATH11K_PCI_ASPM_RESTORE, &ab_pci->flags);
501e9603f4bSCarl Huang }
502e9603f4bSCarl Huang 
5031399fb87SGovind Singh static int ath11k_pci_power_up(struct ath11k_base *ab)
5041399fb87SGovind Singh {
5051399fb87SGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
5061399fb87SGovind Singh 	int ret;
5071399fb87SGovind Singh 
508a05bd851SCarl Huang 	ab_pci->register_window = 0;
509a05bd851SCarl Huang 	clear_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags);
510babb0cedSCarl Huang 	ath11k_pci_sw_reset(ab_pci->ab, true);
511f3c603d4SCarl Huang 
512e9603f4bSCarl Huang 	/* Disable ASPM during firmware download due to problems switching
513e9603f4bSCarl Huang 	 * to AMSS state.
514e9603f4bSCarl Huang 	 */
515e9603f4bSCarl Huang 	ath11k_pci_aspm_disable(ab_pci);
516e9603f4bSCarl Huang 
51796527d52SBaochen Qiang 	ath11k_pci_msi_enable(ab_pci);
51896527d52SBaochen Qiang 
5191399fb87SGovind Singh 	ret = ath11k_mhi_start(ab_pci);
5201399fb87SGovind Singh 	if (ret) {
5211399fb87SGovind Singh 		ath11k_err(ab, "failed to start mhi: %d\n", ret);
5221399fb87SGovind Singh 		return ret;
5231399fb87SGovind Singh 	}
5241399fb87SGovind Singh 
525480a7361SKarthikeyan Periyasamy 	if (ab->bus_params.static_window_map)
526480a7361SKarthikeyan Periyasamy 		ath11k_pci_select_static_window(ab_pci);
527480a7361SKarthikeyan Periyasamy 
5281399fb87SGovind Singh 	return 0;
5291399fb87SGovind Singh }
5301399fb87SGovind Singh 
5311399fb87SGovind Singh static void ath11k_pci_power_down(struct ath11k_base *ab)
5321399fb87SGovind Singh {
5331399fb87SGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
5341399fb87SGovind Singh 
535e9603f4bSCarl Huang 	/* restore aspm in case firmware bootup fails */
536*bbfdc5a7SManikanta Pubbisetty 	ath11k_pcic_aspm_restore(ab_pci);
537e9603f4bSCarl Huang 
538babb0cedSCarl Huang 	ath11k_pci_force_wake(ab_pci->ab);
53996527d52SBaochen Qiang 
54096527d52SBaochen Qiang 	ath11k_pci_msi_disable(ab_pci);
54196527d52SBaochen Qiang 
5421399fb87SGovind Singh 	ath11k_mhi_stop(ab_pci);
543a05bd851SCarl Huang 	clear_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags);
544babb0cedSCarl Huang 	ath11k_pci_sw_reset(ab_pci->ab, false);
5451399fb87SGovind Singh }
5461399fb87SGovind Singh 
547fa5917e4SCarl Huang static int ath11k_pci_hif_suspend(struct ath11k_base *ab)
548fa5917e4SCarl Huang {
549fa5917e4SCarl Huang 	struct ath11k_pci *ar_pci = ath11k_pci_priv(ab);
550fa5917e4SCarl Huang 
551fa5917e4SCarl Huang 	ath11k_mhi_suspend(ar_pci);
552fa5917e4SCarl Huang 
553fa5917e4SCarl Huang 	return 0;
554fa5917e4SCarl Huang }
555fa5917e4SCarl Huang 
556fa5917e4SCarl Huang static int ath11k_pci_hif_resume(struct ath11k_base *ab)
557fa5917e4SCarl Huang {
558fa5917e4SCarl Huang 	struct ath11k_pci *ar_pci = ath11k_pci_priv(ab);
559fa5917e4SCarl Huang 
560fa5917e4SCarl Huang 	ath11k_mhi_resume(ar_pci);
561fa5917e4SCarl Huang 
562fa5917e4SCarl Huang 	return 0;
563fa5917e4SCarl Huang }
564fa5917e4SCarl Huang 
565d578ec2aSCarl Huang static void ath11k_pci_hif_ce_irq_enable(struct ath11k_base *ab)
566d578ec2aSCarl Huang {
567*bbfdc5a7SManikanta Pubbisetty 	ath11k_pcic_ce_irqs_enable(ab);
568d578ec2aSCarl Huang }
569d578ec2aSCarl Huang 
570d578ec2aSCarl Huang static void ath11k_pci_hif_ce_irq_disable(struct ath11k_base *ab)
571d578ec2aSCarl Huang {
572*bbfdc5a7SManikanta Pubbisetty 	ath11k_pcic_ce_irq_disable_sync(ab);
5737f4beda2SGovind Singh }
5747f4beda2SGovind Singh 
5757f4beda2SGovind Singh static const struct ath11k_hif_ops ath11k_pci_hif_ops = {
576*bbfdc5a7SManikanta Pubbisetty 	.start = ath11k_pcic_start,
577*bbfdc5a7SManikanta Pubbisetty 	.stop = ath11k_pcic_stop,
578*bbfdc5a7SManikanta Pubbisetty 	.read32 = ath11k_pcic_read32,
579*bbfdc5a7SManikanta Pubbisetty 	.write32 = ath11k_pcic_write32,
5801399fb87SGovind Singh 	.power_down = ath11k_pci_power_down,
5811399fb87SGovind Singh 	.power_up = ath11k_pci_power_up,
582fa5917e4SCarl Huang 	.suspend = ath11k_pci_hif_suspend,
583fa5917e4SCarl Huang 	.resume = ath11k_pci_hif_resume,
584*bbfdc5a7SManikanta Pubbisetty 	.irq_enable = ath11k_pcic_ext_irq_enable,
585*bbfdc5a7SManikanta Pubbisetty 	.irq_disable = ath11k_pcic_ext_irq_disable,
586*bbfdc5a7SManikanta Pubbisetty 	.get_msi_address =  ath11k_pcic_get_msi_address,
587c4eacabeSGovind Singh 	.get_user_msi_vector = ath11k_get_user_msi_assignment,
588*bbfdc5a7SManikanta Pubbisetty 	.map_service_to_pipe = ath11k_pcic_map_service_to_pipe,
589d578ec2aSCarl Huang 	.ce_irq_enable = ath11k_pci_hif_ce_irq_enable,
590d578ec2aSCarl Huang 	.ce_irq_disable = ath11k_pci_hif_ce_irq_disable,
591*bbfdc5a7SManikanta Pubbisetty 	.get_ce_msi_idx = ath11k_pcic_get_ce_msi_idx,
5921399fb87SGovind Singh };
5931399fb87SGovind Singh 
5940fbf1957SBaochen Qiang static void ath11k_pci_read_hw_version(struct ath11k_base *ab, u32 *major, u32 *minor)
5950fbf1957SBaochen Qiang {
5960fbf1957SBaochen Qiang 	u32 soc_hw_version;
5970fbf1957SBaochen Qiang 
598*bbfdc5a7SManikanta Pubbisetty 	soc_hw_version = ath11k_pcic_read32(ab, TCSR_SOC_HW_VERSION);
5990fbf1957SBaochen Qiang 	*major = FIELD_GET(TCSR_SOC_HW_VERSION_MAJOR_MASK,
6000fbf1957SBaochen Qiang 			   soc_hw_version);
6010fbf1957SBaochen Qiang 	*minor = FIELD_GET(TCSR_SOC_HW_VERSION_MINOR_MASK,
6020fbf1957SBaochen Qiang 			   soc_hw_version);
6030fbf1957SBaochen Qiang 
6040fbf1957SBaochen Qiang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "pci tcsr_soc_hw_version major %d minor %d\n",
6050fbf1957SBaochen Qiang 		   *major, *minor);
6060fbf1957SBaochen Qiang }
6070fbf1957SBaochen Qiang 
6086e0355afSGovind Singh static int ath11k_pci_probe(struct pci_dev *pdev,
6096e0355afSGovind Singh 			    const struct pci_device_id *pci_dev)
6106e0355afSGovind Singh {
6116e0355afSGovind Singh 	struct ath11k_base *ab;
6125762613eSGovind Singh 	struct ath11k_pci *ab_pci;
6136ac04bdcSAnilkumar Kolli 	u32 soc_hw_version_major, soc_hw_version_minor, addr;
6145762613eSGovind Singh 	int ret;
6156e0355afSGovind Singh 
6161ff8ed78SGovind Singh 	ab = ath11k_core_alloc(&pdev->dev, sizeof(*ab_pci), ATH11K_BUS_PCI,
6171ff8ed78SGovind Singh 			       &ath11k_pci_bus_params);
6186e0355afSGovind Singh 	if (!ab) {
6196e0355afSGovind Singh 		dev_err(&pdev->dev, "failed to allocate ath11k base\n");
6206e0355afSGovind Singh 		return -ENOMEM;
6216e0355afSGovind Singh 	}
6226e0355afSGovind Singh 
6236e0355afSGovind Singh 	ab->dev = &pdev->dev;
6246e0355afSGovind Singh 	pci_set_drvdata(pdev, ab);
6255762613eSGovind Singh 	ab_pci = ath11k_pci_priv(ab);
6265762613eSGovind Singh 	ab_pci->dev_id = pci_dev->device;
6275762613eSGovind Singh 	ab_pci->ab = ab;
6285697a564SGovind Singh 	ab_pci->pdev = pdev;
6297f4beda2SGovind Singh 	ab->hif.ops = &ath11k_pci_hif_ops;
6305762613eSGovind Singh 	pci_set_drvdata(pdev, ab);
631654e959aSGovind Singh 	spin_lock_init(&ab_pci->window_lock);
6325762613eSGovind Singh 
6336ac04bdcSAnilkumar Kolli 	/* Set fixed_mem_region to true for platforms support reserved memory
6346ac04bdcSAnilkumar Kolli 	 * from DT. If memory is reserved from DT for FW, ath11k driver need not
6356ac04bdcSAnilkumar Kolli 	 * allocate memory.
6366ac04bdcSAnilkumar Kolli 	 */
6376ac04bdcSAnilkumar Kolli 	ret = of_property_read_u32(ab->dev->of_node, "memory-region", &addr);
6386ac04bdcSAnilkumar Kolli 	if (!ret)
6396ac04bdcSAnilkumar Kolli 		set_bit(ATH11K_FLAG_FIXED_MEM_RGN, &ab->dev_flags);
6406ac04bdcSAnilkumar Kolli 
6415762613eSGovind Singh 	ret = ath11k_pci_claim(ab_pci, pdev);
6425762613eSGovind Singh 	if (ret) {
6435762613eSGovind Singh 		ath11k_err(ab, "failed to claim device: %d\n", ret);
6445762613eSGovind Singh 		goto err_free_core;
6455762613eSGovind Singh 	}
6466e0355afSGovind Singh 
647fc95d10aSWen Gong 	ath11k_dbg(ab, ATH11K_DBG_BOOT, "pci probe %04x:%04x %04x:%04x\n",
648fc95d10aSWen Gong 		   pdev->vendor, pdev->device,
649fc95d10aSWen Gong 		   pdev->subsystem_vendor, pdev->subsystem_device);
650fc95d10aSWen Gong 
651fc95d10aSWen Gong 	ab->id.vendor = pdev->vendor;
652fc95d10aSWen Gong 	ab->id.device = pdev->device;
653fc95d10aSWen Gong 	ab->id.subsystem_vendor = pdev->subsystem_vendor;
654fc95d10aSWen Gong 	ab->id.subsystem_device = pdev->subsystem_device;
655fc95d10aSWen Gong 
65618ac1665SKalle Valo 	switch (pci_dev->device) {
65718ac1665SKalle Valo 	case QCA6390_DEVICE_ID:
6580fbf1957SBaochen Qiang 		ath11k_pci_read_hw_version(ab, &soc_hw_version_major,
6590fbf1957SBaochen Qiang 					   &soc_hw_version_minor);
66018ac1665SKalle Valo 		switch (soc_hw_version_major) {
66118ac1665SKalle Valo 		case 2:
66218ac1665SKalle Valo 			ab->hw_rev = ATH11K_HW_QCA6390_HW20;
66318ac1665SKalle Valo 			break;
66418ac1665SKalle Valo 		default:
66518ac1665SKalle Valo 			dev_err(&pdev->dev, "Unsupported QCA6390 SOC hardware version: %d %d\n",
66618ac1665SKalle Valo 				soc_hw_version_major, soc_hw_version_minor);
66718ac1665SKalle Valo 			ret = -EOPNOTSUPP;
66818ac1665SKalle Valo 			goto err_pci_free_region;
66918ac1665SKalle Valo 		}
6704e809461SAnilkumar Kolli 		ab_pci->msi_config = &ath11k_msi_config[0];
6714e809461SAnilkumar Kolli 		break;
6724e809461SAnilkumar Kolli 	case QCN9074_DEVICE_ID:
6734e809461SAnilkumar Kolli 		ab_pci->msi_config = &ath11k_msi_config[1];
6744e809461SAnilkumar Kolli 		ab->bus_params.static_window_map = true;
6754e809461SAnilkumar Kolli 		ab->hw_rev = ATH11K_HW_QCN9074_HW10;
67618ac1665SKalle Valo 		break;
6770fbf1957SBaochen Qiang 	case WCN6855_DEVICE_ID:
678fc95d10aSWen Gong 		ab->id.bdf_search = ATH11K_BDF_SEARCH_BUS_AND_BOARD;
6790fbf1957SBaochen Qiang 		ath11k_pci_read_hw_version(ab, &soc_hw_version_major,
6800fbf1957SBaochen Qiang 					   &soc_hw_version_minor);
6810fbf1957SBaochen Qiang 		switch (soc_hw_version_major) {
6820fbf1957SBaochen Qiang 		case 2:
683d1147a31SBaochen Qiang 			switch (soc_hw_version_minor) {
684d1147a31SBaochen Qiang 			case 0x00:
685d1147a31SBaochen Qiang 			case 0x01:
6860fbf1957SBaochen Qiang 				ab->hw_rev = ATH11K_HW_WCN6855_HW20;
6870fbf1957SBaochen Qiang 				break;
688d1147a31SBaochen Qiang 			case 0x10:
689d1147a31SBaochen Qiang 			case 0x11:
690d1147a31SBaochen Qiang 				ab->hw_rev = ATH11K_HW_WCN6855_HW21;
691d1147a31SBaochen Qiang 				break;
6920fbf1957SBaochen Qiang 			default:
693d1147a31SBaochen Qiang 				goto unsupported_wcn6855_soc;
694d1147a31SBaochen Qiang 			}
695d1147a31SBaochen Qiang 			break;
696d1147a31SBaochen Qiang 		default:
697d1147a31SBaochen Qiang unsupported_wcn6855_soc:
6980fbf1957SBaochen Qiang 			dev_err(&pdev->dev, "Unsupported WCN6855 SOC hardware version: %d %d\n",
6990fbf1957SBaochen Qiang 				soc_hw_version_major, soc_hw_version_minor);
7000fbf1957SBaochen Qiang 			ret = -EOPNOTSUPP;
7010fbf1957SBaochen Qiang 			goto err_pci_free_region;
7020fbf1957SBaochen Qiang 		}
7030fbf1957SBaochen Qiang 		ab_pci->msi_config = &ath11k_msi_config[0];
7040fbf1957SBaochen Qiang 		break;
70518ac1665SKalle Valo 	default:
70618ac1665SKalle Valo 		dev_err(&pdev->dev, "Unknown PCI device found: 0x%x\n",
70718ac1665SKalle Valo 			pci_dev->device);
70818ac1665SKalle Valo 		ret = -EOPNOTSUPP;
70918ac1665SKalle Valo 		goto err_pci_free_region;
71018ac1665SKalle Valo 	}
71118ac1665SKalle Valo 
71296527d52SBaochen Qiang 	ret = ath11k_pci_alloc_msi(ab_pci);
7135697a564SGovind Singh 	if (ret) {
7145697a564SGovind Singh 		ath11k_err(ab, "failed to enable msi: %d\n", ret);
7155697a564SGovind Singh 		goto err_pci_free_region;
7165697a564SGovind Singh 	}
7175697a564SGovind Singh 
718b8246f88SKalle Valo 	ret = ath11k_core_pre_init(ab);
719b8246f88SKalle Valo 	if (ret)
720b8246f88SKalle Valo 		goto err_pci_disable_msi;
721b8246f88SKalle Valo 
7221399fb87SGovind Singh 	ret = ath11k_mhi_register(ab_pci);
7231399fb87SGovind Singh 	if (ret) {
7241399fb87SGovind Singh 		ath11k_err(ab, "failed to register mhi: %d\n", ret);
7251399fb87SGovind Singh 		goto err_pci_disable_msi;
7261399fb87SGovind Singh 	}
7271399fb87SGovind Singh 
7287f4beda2SGovind Singh 	ret = ath11k_hal_srng_init(ab);
7297f4beda2SGovind Singh 	if (ret)
7307f4beda2SGovind Singh 		goto err_mhi_unregister;
7317f4beda2SGovind Singh 
7327f4beda2SGovind Singh 	ret = ath11k_ce_alloc_pipes(ab);
7337f4beda2SGovind Singh 	if (ret) {
7347f4beda2SGovind Singh 		ath11k_err(ab, "failed to allocate ce pipes: %d\n", ret);
7357f4beda2SGovind Singh 		goto err_hal_srng_deinit;
7367f4beda2SGovind Singh 	}
7377f4beda2SGovind Singh 
7387f4beda2SGovind Singh 	ath11k_pci_init_qmi_ce_config(ab);
7397f4beda2SGovind Singh 
740*bbfdc5a7SManikanta Pubbisetty 	ret = ath11k_pcic_config_irq(ab);
7417f4beda2SGovind Singh 	if (ret) {
7427f4beda2SGovind Singh 		ath11k_err(ab, "failed to config irq: %d\n", ret);
7437f4beda2SGovind Singh 		goto err_ce_free;
7447f4beda2SGovind Singh 	}
7457f4beda2SGovind Singh 
74687b4072dSCarl Huang 	/* kernel may allocate a dummy vector before request_irq and
74787b4072dSCarl Huang 	 * then allocate a real vector when request_irq is called.
74887b4072dSCarl Huang 	 * So get msi_data here again to avoid spurious interrupt
74987b4072dSCarl Huang 	 * as msi_data will configured to srngs.
75087b4072dSCarl Huang 	 */
75187b4072dSCarl Huang 	ret = ath11k_pci_config_msi_data(ab_pci);
75287b4072dSCarl Huang 	if (ret) {
75387b4072dSCarl Huang 		ath11k_err(ab, "failed to config msi_data: %d\n", ret);
75487b4072dSCarl Huang 		goto err_free_irq;
75587b4072dSCarl Huang 	}
75687b4072dSCarl Huang 
7577f4beda2SGovind Singh 	ret = ath11k_core_init(ab);
7587f4beda2SGovind Singh 	if (ret) {
7597f4beda2SGovind Singh 		ath11k_err(ab, "failed to init core: %d\n", ret);
7607f4beda2SGovind Singh 		goto err_free_irq;
7617f4beda2SGovind Singh 	}
7626e0355afSGovind Singh 	return 0;
7635762613eSGovind Singh 
7647f4beda2SGovind Singh err_free_irq:
765*bbfdc5a7SManikanta Pubbisetty 	ath11k_pcic_free_irq(ab);
7667f4beda2SGovind Singh 
7677f4beda2SGovind Singh err_ce_free:
7687f4beda2SGovind Singh 	ath11k_ce_free_pipes(ab);
7697f4beda2SGovind Singh 
7707f4beda2SGovind Singh err_hal_srng_deinit:
7717f4beda2SGovind Singh 	ath11k_hal_srng_deinit(ab);
7727f4beda2SGovind Singh 
7737f4beda2SGovind Singh err_mhi_unregister:
7747f4beda2SGovind Singh 	ath11k_mhi_unregister(ab_pci);
7757f4beda2SGovind Singh 
776b8246f88SKalle Valo err_pci_disable_msi:
77796527d52SBaochen Qiang 	ath11k_pci_free_msi(ab_pci);
778b8246f88SKalle Valo 
7795697a564SGovind Singh err_pci_free_region:
7805697a564SGovind Singh 	ath11k_pci_free_region(ab_pci);
7815697a564SGovind Singh 
7825762613eSGovind Singh err_free_core:
7835762613eSGovind Singh 	ath11k_core_free(ab);
7845697a564SGovind Singh 
7855762613eSGovind Singh 	return ret;
7866e0355afSGovind Singh }
7876e0355afSGovind Singh 
7886e0355afSGovind Singh static void ath11k_pci_remove(struct pci_dev *pdev)
7896e0355afSGovind Singh {
7906e0355afSGovind Singh 	struct ath11k_base *ab = pci_get_drvdata(pdev);
7915762613eSGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
7926e0355afSGovind Singh 
793*bbfdc5a7SManikanta Pubbisetty 	ath11k_pcic_set_irq_affinity_hint(ab_pci, NULL);
794e94b0749SBaochen Qiang 
79561a57e51SAnilkumar Kolli 	if (test_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags)) {
79661a57e51SAnilkumar Kolli 		ath11k_pci_power_down(ab);
79761a57e51SAnilkumar Kolli 		ath11k_debugfs_soc_destroy(ab);
79861a57e51SAnilkumar Kolli 		ath11k_qmi_deinit_service(ab);
79961a57e51SAnilkumar Kolli 		goto qmi_fail;
80061a57e51SAnilkumar Kolli 	}
80161a57e51SAnilkumar Kolli 
8026e0355afSGovind Singh 	set_bit(ATH11K_FLAG_UNREGISTERING, &ab->dev_flags);
8036fbd8898SCarl Huang 
8046fbd8898SCarl Huang 	ath11k_core_deinit(ab);
8056fbd8898SCarl Huang 
80661a57e51SAnilkumar Kolli qmi_fail:
8071399fb87SGovind Singh 	ath11k_mhi_unregister(ab_pci);
8086fbd8898SCarl Huang 
809*bbfdc5a7SManikanta Pubbisetty 	ath11k_pcic_free_irq(ab);
81096527d52SBaochen Qiang 	ath11k_pci_free_msi(ab_pci);
8115762613eSGovind Singh 	ath11k_pci_free_region(ab_pci);
8126fbd8898SCarl Huang 
8136fbd8898SCarl Huang 	ath11k_hal_srng_deinit(ab);
8146fbd8898SCarl Huang 	ath11k_ce_free_pipes(ab);
8156e0355afSGovind Singh 	ath11k_core_free(ab);
8166e0355afSGovind Singh }
8176e0355afSGovind Singh 
8181399fb87SGovind Singh static void ath11k_pci_shutdown(struct pci_dev *pdev)
8191399fb87SGovind Singh {
8201399fb87SGovind Singh 	struct ath11k_base *ab = pci_get_drvdata(pdev);
8211399fb87SGovind Singh 
8221399fb87SGovind Singh 	ath11k_pci_power_down(ab);
8231399fb87SGovind Singh }
8241399fb87SGovind Singh 
825d1b0c338SCarl Huang static __maybe_unused int ath11k_pci_pm_suspend(struct device *dev)
826d1b0c338SCarl Huang {
827d1b0c338SCarl Huang 	struct ath11k_base *ab = dev_get_drvdata(dev);
828d1b0c338SCarl Huang 	int ret;
829d1b0c338SCarl Huang 
830b4f4c564SKalle Valo 	if (test_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags)) {
831b4f4c564SKalle Valo 		ath11k_dbg(ab, ATH11K_DBG_BOOT, "boot skipping pci suspend as qmi is not initialised\n");
832b4f4c564SKalle Valo 		return 0;
833b4f4c564SKalle Valo 	}
834b4f4c564SKalle Valo 
835d1b0c338SCarl Huang 	ret = ath11k_core_suspend(ab);
836d1b0c338SCarl Huang 	if (ret)
837d1b0c338SCarl Huang 		ath11k_warn(ab, "failed to suspend core: %d\n", ret);
838d1b0c338SCarl Huang 
839d1b0c338SCarl Huang 	return ret;
840d1b0c338SCarl Huang }
841d1b0c338SCarl Huang 
842d1b0c338SCarl Huang static __maybe_unused int ath11k_pci_pm_resume(struct device *dev)
843d1b0c338SCarl Huang {
844d1b0c338SCarl Huang 	struct ath11k_base *ab = dev_get_drvdata(dev);
845d1b0c338SCarl Huang 	int ret;
846d1b0c338SCarl Huang 
847b4f4c564SKalle Valo 	if (test_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags)) {
848b4f4c564SKalle Valo 		ath11k_dbg(ab, ATH11K_DBG_BOOT, "boot skipping pci resume as qmi is not initialised\n");
849b4f4c564SKalle Valo 		return 0;
850b4f4c564SKalle Valo 	}
851b4f4c564SKalle Valo 
852d1b0c338SCarl Huang 	ret = ath11k_core_resume(ab);
853d1b0c338SCarl Huang 	if (ret)
854d1b0c338SCarl Huang 		ath11k_warn(ab, "failed to resume core: %d\n", ret);
855d1b0c338SCarl Huang 
856d1b0c338SCarl Huang 	return ret;
857d1b0c338SCarl Huang }
858d1b0c338SCarl Huang 
859d1b0c338SCarl Huang static SIMPLE_DEV_PM_OPS(ath11k_pci_pm_ops,
860d1b0c338SCarl Huang 			 ath11k_pci_pm_suspend,
861d1b0c338SCarl Huang 			 ath11k_pci_pm_resume);
862d1b0c338SCarl Huang 
8636e0355afSGovind Singh static struct pci_driver ath11k_pci_driver = {
8646e0355afSGovind Singh 	.name = "ath11k_pci",
8656e0355afSGovind Singh 	.id_table = ath11k_pci_id_table,
8666e0355afSGovind Singh 	.probe = ath11k_pci_probe,
8676e0355afSGovind Singh 	.remove = ath11k_pci_remove,
8681399fb87SGovind Singh 	.shutdown = ath11k_pci_shutdown,
869d1b0c338SCarl Huang #ifdef CONFIG_PM
870d1b0c338SCarl Huang 	.driver.pm = &ath11k_pci_pm_ops,
871d1b0c338SCarl Huang #endif
8726e0355afSGovind Singh };
8736e0355afSGovind Singh 
8746e0355afSGovind Singh static int ath11k_pci_init(void)
8756e0355afSGovind Singh {
8766e0355afSGovind Singh 	int ret;
8776e0355afSGovind Singh 
8786e0355afSGovind Singh 	ret = pci_register_driver(&ath11k_pci_driver);
8796e0355afSGovind Singh 	if (ret)
8806e0355afSGovind Singh 		pr_err("failed to register ath11k pci driver: %d\n",
8816e0355afSGovind Singh 		       ret);
8826e0355afSGovind Singh 
8836e0355afSGovind Singh 	return ret;
8846e0355afSGovind Singh }
8856e0355afSGovind Singh module_init(ath11k_pci_init);
8866e0355afSGovind Singh 
8876e0355afSGovind Singh static void ath11k_pci_exit(void)
8886e0355afSGovind Singh {
8896e0355afSGovind Singh 	pci_unregister_driver(&ath11k_pci_driver);
8906e0355afSGovind Singh }
8916e0355afSGovind Singh 
8926e0355afSGovind Singh module_exit(ath11k_pci_exit);
8936e0355afSGovind Singh 
8946e0355afSGovind Singh MODULE_DESCRIPTION("Driver support for Qualcomm Technologies 802.11ax WLAN PCIe devices");
8956e0355afSGovind Singh MODULE_LICENSE("Dual BSD/GPL");
8963dbd7fe7SDevin Bayer 
8973dbd7fe7SDevin Bayer /* QCA639x 2.0 firmware files */
8983dbd7fe7SDevin Bayer MODULE_FIRMWARE(ATH11K_FW_DIR "/QCA6390/hw2.0/" ATH11K_BOARD_API2_FILE);
8993dbd7fe7SDevin Bayer MODULE_FIRMWARE(ATH11K_FW_DIR "/QCA6390/hw2.0/" ATH11K_AMSS_FILE);
9003dbd7fe7SDevin Bayer MODULE_FIRMWARE(ATH11K_FW_DIR "/QCA6390/hw2.0/" ATH11K_M3_FILE);
901