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