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