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 395b32b6ddSManikanta Pubbisetty static int ath11k_pci_bus_wake_up(struct ath11k_base *ab) 405b32b6ddSManikanta Pubbisetty { 415b32b6ddSManikanta Pubbisetty struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 425b32b6ddSManikanta Pubbisetty 435b32b6ddSManikanta Pubbisetty return mhi_device_get_sync(ab_pci->mhi_ctrl->mhi_dev); 445b32b6ddSManikanta Pubbisetty } 455b32b6ddSManikanta Pubbisetty 465b32b6ddSManikanta Pubbisetty static void ath11k_pci_bus_release(struct ath11k_base *ab) 475b32b6ddSManikanta Pubbisetty { 485b32b6ddSManikanta Pubbisetty struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 495b32b6ddSManikanta Pubbisetty 505b32b6ddSManikanta Pubbisetty mhi_device_put(ab_pci->mhi_ctrl->mhi_dev); 515b32b6ddSManikanta Pubbisetty } 525b32b6ddSManikanta Pubbisetty 535b32b6ddSManikanta Pubbisetty static inline void ath11k_pci_select_window(struct ath11k_pci *ab_pci, u32 offset) 545b32b6ddSManikanta Pubbisetty { 555b32b6ddSManikanta Pubbisetty struct ath11k_base *ab = ab_pci->ab; 565b32b6ddSManikanta Pubbisetty 575b32b6ddSManikanta Pubbisetty u32 window = FIELD_GET(ATH11K_PCI_WINDOW_VALUE_MASK, offset); 585b32b6ddSManikanta Pubbisetty 595b32b6ddSManikanta Pubbisetty lockdep_assert_held(&ab_pci->window_lock); 605b32b6ddSManikanta Pubbisetty 615b32b6ddSManikanta Pubbisetty if (window != ab_pci->register_window) { 625b32b6ddSManikanta Pubbisetty iowrite32(ATH11K_PCI_WINDOW_ENABLE_BIT | window, 635b32b6ddSManikanta Pubbisetty ab->mem + ATH11K_PCI_WINDOW_REG_ADDRESS); 645b32b6ddSManikanta Pubbisetty ioread32(ab->mem + ATH11K_PCI_WINDOW_REG_ADDRESS); 655b32b6ddSManikanta Pubbisetty ab_pci->register_window = window; 665b32b6ddSManikanta Pubbisetty } 675b32b6ddSManikanta Pubbisetty } 685b32b6ddSManikanta Pubbisetty 695b32b6ddSManikanta Pubbisetty static void 705b32b6ddSManikanta Pubbisetty ath11k_pci_window_write32(struct ath11k_base *ab, u32 offset, u32 value) 715b32b6ddSManikanta Pubbisetty { 725b32b6ddSManikanta Pubbisetty struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 735b32b6ddSManikanta Pubbisetty u32 window_start = ATH11K_PCI_WINDOW_START; 745b32b6ddSManikanta Pubbisetty 755b32b6ddSManikanta Pubbisetty spin_lock_bh(&ab_pci->window_lock); 765b32b6ddSManikanta Pubbisetty ath11k_pci_select_window(ab_pci, offset); 775b32b6ddSManikanta Pubbisetty iowrite32(value, ab->mem + window_start + 785b32b6ddSManikanta Pubbisetty (offset & ATH11K_PCI_WINDOW_RANGE_MASK)); 795b32b6ddSManikanta Pubbisetty spin_unlock_bh(&ab_pci->window_lock); 805b32b6ddSManikanta Pubbisetty } 815b32b6ddSManikanta Pubbisetty 825b32b6ddSManikanta Pubbisetty static u32 ath11k_pci_window_read32(struct ath11k_base *ab, u32 offset) 835b32b6ddSManikanta Pubbisetty { 845b32b6ddSManikanta Pubbisetty struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 855b32b6ddSManikanta Pubbisetty u32 window_start = ATH11K_PCI_WINDOW_START; 865b32b6ddSManikanta Pubbisetty u32 val; 875b32b6ddSManikanta Pubbisetty 885b32b6ddSManikanta Pubbisetty spin_lock_bh(&ab_pci->window_lock); 895b32b6ddSManikanta Pubbisetty ath11k_pci_select_window(ab_pci, offset); 905b32b6ddSManikanta Pubbisetty val = ioread32(ab->mem + window_start + 915b32b6ddSManikanta Pubbisetty (offset & ATH11K_PCI_WINDOW_RANGE_MASK)); 925b32b6ddSManikanta Pubbisetty spin_unlock_bh(&ab_pci->window_lock); 935b32b6ddSManikanta Pubbisetty 945b32b6ddSManikanta Pubbisetty return val; 955b32b6ddSManikanta Pubbisetty } 965b32b6ddSManikanta Pubbisetty 975b32b6ddSManikanta Pubbisetty int ath11k_pci_get_msi_irq(struct ath11k_base *ab, unsigned int vector) 985b32b6ddSManikanta Pubbisetty { 995b32b6ddSManikanta Pubbisetty struct pci_dev *pci_dev = to_pci_dev(ab->dev); 1005b32b6ddSManikanta Pubbisetty 1015b32b6ddSManikanta Pubbisetty return pci_irq_vector(pci_dev, vector); 1025b32b6ddSManikanta Pubbisetty } 1035b32b6ddSManikanta Pubbisetty 1045b32b6ddSManikanta Pubbisetty static const struct ath11k_pci_ops ath11k_pci_ops_qca6390 = { 1055b32b6ddSManikanta Pubbisetty .wakeup = ath11k_pci_bus_wake_up, 1065b32b6ddSManikanta Pubbisetty .release = ath11k_pci_bus_release, 1075b32b6ddSManikanta Pubbisetty .get_msi_irq = ath11k_pci_get_msi_irq, 1085b32b6ddSManikanta Pubbisetty .window_write32 = ath11k_pci_window_write32, 1095b32b6ddSManikanta Pubbisetty .window_read32 = ath11k_pci_window_read32, 1105b32b6ddSManikanta Pubbisetty }; 1115b32b6ddSManikanta Pubbisetty 1125b32b6ddSManikanta Pubbisetty static const struct ath11k_pci_ops ath11k_pci_ops_qcn9074 = { 1135b32b6ddSManikanta Pubbisetty .get_msi_irq = ath11k_pci_get_msi_irq, 1145b32b6ddSManikanta Pubbisetty .window_write32 = ath11k_pci_window_write32, 1155b32b6ddSManikanta Pubbisetty .window_read32 = ath11k_pci_window_read32, 1165b32b6ddSManikanta Pubbisetty }; 1175b32b6ddSManikanta Pubbisetty 1181ff8ed78SGovind Singh static const struct ath11k_bus_params ath11k_pci_bus_params = { 1191ff8ed78SGovind Singh .mhi_support = true, 12056970454SGovind Singh .m3_fw_support = true, 1216eb6ea51SGovind Singh .fixed_bdf_addr = false, 1226eb6ea51SGovind Singh .fixed_mem_region = false, 1231ff8ed78SGovind Singh }; 1241ff8ed78SGovind Singh 125ac6e7348SCarl Huang static const struct ath11k_msi_config msi_config_one_msi = { 126ac6e7348SCarl Huang .total_vectors = 1, 127ac6e7348SCarl Huang .total_users = 4, 128ac6e7348SCarl Huang .users = (struct ath11k_msi_user[]) { 129ac6e7348SCarl Huang { .name = "MHI", .num_vectors = 3, .base_vector = 0 }, 130ac6e7348SCarl Huang { .name = "CE", .num_vectors = 1, .base_vector = 0 }, 131ac6e7348SCarl Huang { .name = "WAKE", .num_vectors = 1, .base_vector = 0 }, 132ac6e7348SCarl Huang { .name = "DP", .num_vectors = 1, .base_vector = 0 }, 133ac6e7348SCarl Huang }, 134ac6e7348SCarl Huang }; 135ac6e7348SCarl Huang 136480a7361SKarthikeyan Periyasamy static inline void ath11k_pci_select_static_window(struct ath11k_pci *ab_pci) 137480a7361SKarthikeyan Periyasamy { 138948171b5SManikanta Pubbisetty u32 umac_window; 139948171b5SManikanta Pubbisetty u32 ce_window; 140480a7361SKarthikeyan Periyasamy u32 window; 141480a7361SKarthikeyan Periyasamy 142948171b5SManikanta Pubbisetty umac_window = FIELD_GET(ATH11K_PCI_WINDOW_VALUE_MASK, HAL_SEQ_WCSS_UMAC_OFFSET); 143948171b5SManikanta Pubbisetty ce_window = FIELD_GET(ATH11K_PCI_WINDOW_VALUE_MASK, HAL_CE_WFSS_CE_REG_BASE); 144480a7361SKarthikeyan Periyasamy window = (umac_window << 12) | (ce_window << 6); 145480a7361SKarthikeyan Periyasamy 146948171b5SManikanta Pubbisetty iowrite32(ATH11K_PCI_WINDOW_ENABLE_BIT | window, 147948171b5SManikanta Pubbisetty ab_pci->ab->mem + ATH11K_PCI_WINDOW_REG_ADDRESS); 148480a7361SKarthikeyan Periyasamy } 149480a7361SKarthikeyan Periyasamy 150f3c603d4SCarl Huang static void ath11k_pci_soc_global_reset(struct ath11k_base *ab) 151f3c603d4SCarl Huang { 152f3c603d4SCarl Huang u32 val, delay; 153f3c603d4SCarl Huang 154bbfdc5a7SManikanta Pubbisetty val = ath11k_pcic_read32(ab, PCIE_SOC_GLOBAL_RESET); 155f3c603d4SCarl Huang 156f3c603d4SCarl Huang val |= PCIE_SOC_GLOBAL_RESET_V; 157f3c603d4SCarl Huang 158bbfdc5a7SManikanta Pubbisetty ath11k_pcic_write32(ab, PCIE_SOC_GLOBAL_RESET, val); 159f3c603d4SCarl Huang 160f3c603d4SCarl Huang /* TODO: exact time to sleep is uncertain */ 161f3c603d4SCarl Huang delay = 10; 162f3c603d4SCarl Huang mdelay(delay); 163f3c603d4SCarl Huang 164f3c603d4SCarl Huang /* Need to toggle V bit back otherwise stuck in reset status */ 165f3c603d4SCarl Huang val &= ~PCIE_SOC_GLOBAL_RESET_V; 166f3c603d4SCarl Huang 167bbfdc5a7SManikanta Pubbisetty ath11k_pcic_write32(ab, PCIE_SOC_GLOBAL_RESET, val); 168f3c603d4SCarl Huang 169f3c603d4SCarl Huang mdelay(delay); 170f3c603d4SCarl Huang 171bbfdc5a7SManikanta Pubbisetty val = ath11k_pcic_read32(ab, PCIE_SOC_GLOBAL_RESET); 172f3c603d4SCarl Huang if (val == 0xffffffff) 173f3c603d4SCarl Huang ath11k_warn(ab, "link down error during global reset\n"); 174f3c603d4SCarl Huang } 175f3c603d4SCarl Huang 176f3c603d4SCarl Huang static void ath11k_pci_clear_dbg_registers(struct ath11k_base *ab) 177f3c603d4SCarl Huang { 178f3c603d4SCarl Huang u32 val; 179f3c603d4SCarl Huang 180f3c603d4SCarl Huang /* read cookie */ 181bbfdc5a7SManikanta Pubbisetty val = ath11k_pcic_read32(ab, PCIE_Q6_COOKIE_ADDR); 182f3c603d4SCarl Huang ath11k_dbg(ab, ATH11K_DBG_PCI, "cookie:0x%x\n", val); 183f3c603d4SCarl Huang 184bbfdc5a7SManikanta Pubbisetty val = ath11k_pcic_read32(ab, WLAON_WARM_SW_ENTRY); 185f3c603d4SCarl Huang ath11k_dbg(ab, ATH11K_DBG_PCI, "WLAON_WARM_SW_ENTRY 0x%x\n", val); 186f3c603d4SCarl Huang 187f3c603d4SCarl Huang /* TODO: exact time to sleep is uncertain */ 188f3c603d4SCarl Huang mdelay(10); 189f3c603d4SCarl Huang 190f3c603d4SCarl Huang /* write 0 to WLAON_WARM_SW_ENTRY to prevent Q6 from 191f3c603d4SCarl Huang * continuing warm path and entering dead loop. 192f3c603d4SCarl Huang */ 193bbfdc5a7SManikanta Pubbisetty ath11k_pcic_write32(ab, WLAON_WARM_SW_ENTRY, 0); 194f3c603d4SCarl Huang mdelay(10); 195f3c603d4SCarl Huang 196bbfdc5a7SManikanta Pubbisetty val = ath11k_pcic_read32(ab, WLAON_WARM_SW_ENTRY); 197f3c603d4SCarl Huang ath11k_dbg(ab, ATH11K_DBG_PCI, "WLAON_WARM_SW_ENTRY 0x%x\n", val); 198f3c603d4SCarl Huang 199f3c603d4SCarl Huang /* A read clear register. clear the register to prevent 200f3c603d4SCarl Huang * Q6 from entering wrong code path. 201f3c603d4SCarl Huang */ 202bbfdc5a7SManikanta Pubbisetty val = ath11k_pcic_read32(ab, WLAON_SOC_RESET_CAUSE_REG); 203f3c603d4SCarl Huang ath11k_dbg(ab, ATH11K_DBG_PCI, "soc reset cause:%d\n", val); 204f3c603d4SCarl Huang } 205f3c603d4SCarl Huang 20606999407SCarl Huang static int ath11k_pci_set_link_reg(struct ath11k_base *ab, 20706999407SCarl Huang u32 offset, u32 value, u32 mask) 20806999407SCarl Huang { 20906999407SCarl Huang u32 v; 21006999407SCarl Huang int i; 21106999407SCarl Huang 212bbfdc5a7SManikanta Pubbisetty v = ath11k_pcic_read32(ab, offset); 21306999407SCarl Huang if ((v & mask) == value) 21406999407SCarl Huang return 0; 21506999407SCarl Huang 21606999407SCarl Huang for (i = 0; i < 10; i++) { 217bbfdc5a7SManikanta Pubbisetty ath11k_pcic_write32(ab, offset, (v & ~mask) | value); 21806999407SCarl Huang 219bbfdc5a7SManikanta Pubbisetty v = ath11k_pcic_read32(ab, offset); 22006999407SCarl Huang if ((v & mask) == value) 22106999407SCarl Huang return 0; 22206999407SCarl Huang 22306999407SCarl Huang mdelay(2); 22406999407SCarl Huang } 22506999407SCarl Huang 22606999407SCarl Huang ath11k_warn(ab, "failed to set pcie link register 0x%08x: 0x%08x != 0x%08x\n", 22706999407SCarl Huang offset, v & mask, value); 22806999407SCarl Huang 22906999407SCarl Huang return -ETIMEDOUT; 23006999407SCarl Huang } 23106999407SCarl Huang 23206999407SCarl Huang static int ath11k_pci_fix_l1ss(struct ath11k_base *ab) 23306999407SCarl Huang { 23406999407SCarl Huang int ret; 23506999407SCarl Huang 23606999407SCarl Huang ret = ath11k_pci_set_link_reg(ab, 2376fe6f68fSKarthikeyan Periyasamy PCIE_QSERDES_COM_SYSCLK_EN_SEL_REG(ab), 23806999407SCarl Huang PCIE_QSERDES_COM_SYSCLK_EN_SEL_VAL, 23906999407SCarl Huang PCIE_QSERDES_COM_SYSCLK_EN_SEL_MSK); 24030d08503SDan Carpenter if (ret) { 24106999407SCarl Huang ath11k_warn(ab, "failed to set sysclk: %d\n", ret); 24206999407SCarl Huang return ret; 24306999407SCarl Huang } 24406999407SCarl Huang 24506999407SCarl Huang ret = ath11k_pci_set_link_reg(ab, 2466fe6f68fSKarthikeyan Periyasamy PCIE_PCS_OSC_DTCT_CONFIG1_REG(ab), 2476fe6f68fSKarthikeyan Periyasamy PCIE_PCS_OSC_DTCT_CONFIG1_VAL, 2486fe6f68fSKarthikeyan Periyasamy PCIE_PCS_OSC_DTCT_CONFIG_MSK); 24930d08503SDan Carpenter if (ret) { 25006999407SCarl Huang ath11k_warn(ab, "failed to set dtct config1 error: %d\n", ret); 25106999407SCarl Huang return ret; 25206999407SCarl Huang } 25306999407SCarl Huang 25406999407SCarl Huang ret = ath11k_pci_set_link_reg(ab, 2556fe6f68fSKarthikeyan Periyasamy PCIE_PCS_OSC_DTCT_CONFIG2_REG(ab), 2566fe6f68fSKarthikeyan Periyasamy PCIE_PCS_OSC_DTCT_CONFIG2_VAL, 2576fe6f68fSKarthikeyan Periyasamy PCIE_PCS_OSC_DTCT_CONFIG_MSK); 25830d08503SDan Carpenter if (ret) { 25906999407SCarl Huang ath11k_warn(ab, "failed to set dtct config2: %d\n", ret); 26006999407SCarl Huang return ret; 26106999407SCarl Huang } 26206999407SCarl Huang 26306999407SCarl Huang ret = ath11k_pci_set_link_reg(ab, 2646fe6f68fSKarthikeyan Periyasamy PCIE_PCS_OSC_DTCT_CONFIG4_REG(ab), 2656fe6f68fSKarthikeyan Periyasamy PCIE_PCS_OSC_DTCT_CONFIG4_VAL, 2666fe6f68fSKarthikeyan Periyasamy PCIE_PCS_OSC_DTCT_CONFIG_MSK); 26730d08503SDan Carpenter if (ret) { 26806999407SCarl Huang ath11k_warn(ab, "failed to set dtct config4: %d\n", ret); 26906999407SCarl Huang return ret; 27006999407SCarl Huang } 27106999407SCarl Huang 27206999407SCarl Huang return 0; 27306999407SCarl Huang } 27406999407SCarl Huang 275babb0cedSCarl Huang static void ath11k_pci_enable_ltssm(struct ath11k_base *ab) 276babb0cedSCarl Huang { 277babb0cedSCarl Huang u32 val; 278babb0cedSCarl Huang int i; 279babb0cedSCarl Huang 280bbfdc5a7SManikanta Pubbisetty val = ath11k_pcic_read32(ab, PCIE_PCIE_PARF_LTSSM); 281babb0cedSCarl Huang 282babb0cedSCarl Huang /* PCIE link seems very unstable after the Hot Reset*/ 283babb0cedSCarl Huang for (i = 0; val != PARM_LTSSM_VALUE && i < 5; i++) { 284babb0cedSCarl Huang if (val == 0xffffffff) 285babb0cedSCarl Huang mdelay(5); 286babb0cedSCarl Huang 287bbfdc5a7SManikanta Pubbisetty ath11k_pcic_write32(ab, PCIE_PCIE_PARF_LTSSM, PARM_LTSSM_VALUE); 288bbfdc5a7SManikanta Pubbisetty val = ath11k_pcic_read32(ab, PCIE_PCIE_PARF_LTSSM); 289babb0cedSCarl Huang } 290babb0cedSCarl Huang 291babb0cedSCarl Huang ath11k_dbg(ab, ATH11K_DBG_PCI, "pci ltssm 0x%x\n", val); 292babb0cedSCarl Huang 293bbfdc5a7SManikanta Pubbisetty val = ath11k_pcic_read32(ab, GCC_GCC_PCIE_HOT_RST); 294562934adSKalle Valo val |= GCC_GCC_PCIE_HOT_RST_VAL; 295bbfdc5a7SManikanta Pubbisetty ath11k_pcic_write32(ab, GCC_GCC_PCIE_HOT_RST, val); 296bbfdc5a7SManikanta Pubbisetty val = ath11k_pcic_read32(ab, GCC_GCC_PCIE_HOT_RST); 297babb0cedSCarl Huang 298babb0cedSCarl Huang ath11k_dbg(ab, ATH11K_DBG_PCI, "pci pcie_hot_rst 0x%x\n", val); 299babb0cedSCarl Huang 300babb0cedSCarl Huang mdelay(5); 301babb0cedSCarl Huang } 302babb0cedSCarl Huang 303babb0cedSCarl Huang static void ath11k_pci_clear_all_intrs(struct ath11k_base *ab) 304babb0cedSCarl Huang { 305babb0cedSCarl Huang /* This is a WAR for PCIE Hotreset. 306babb0cedSCarl Huang * When target receive Hotreset, but will set the interrupt. 307babb0cedSCarl Huang * So when download SBL again, SBL will open Interrupt and 308babb0cedSCarl Huang * receive it, and crash immediately. 309babb0cedSCarl Huang */ 310bbfdc5a7SManikanta Pubbisetty ath11k_pcic_write32(ab, PCIE_PCIE_INT_ALL_CLEAR, PCIE_INT_CLEAR_ALL); 311babb0cedSCarl Huang } 312babb0cedSCarl Huang 3130ccdf439SCarl Huang static void ath11k_pci_set_wlaon_pwr_ctrl(struct ath11k_base *ab) 3140ccdf439SCarl Huang { 3150ccdf439SCarl Huang u32 val; 3160ccdf439SCarl Huang 317bbfdc5a7SManikanta Pubbisetty val = ath11k_pcic_read32(ab, WLAON_QFPROM_PWR_CTRL_REG); 3180ccdf439SCarl Huang val &= ~QFPROM_PWR_CTRL_VDD4BLOW_MASK; 319bbfdc5a7SManikanta Pubbisetty ath11k_pcic_write32(ab, WLAON_QFPROM_PWR_CTRL_REG, val); 3200ccdf439SCarl Huang } 3210ccdf439SCarl Huang 322f3c603d4SCarl Huang static void ath11k_pci_force_wake(struct ath11k_base *ab) 323f3c603d4SCarl Huang { 324bbfdc5a7SManikanta Pubbisetty ath11k_pcic_write32(ab, PCIE_SOC_WAKE_PCIE_LOCAL_REG, 1); 325f3c603d4SCarl Huang mdelay(5); 326f3c603d4SCarl Huang } 327f3c603d4SCarl Huang 328babb0cedSCarl Huang static void ath11k_pci_sw_reset(struct ath11k_base *ab, bool power_on) 329f3c603d4SCarl Huang { 3308a0b899fSBaochen Qiang mdelay(100); 3318a0b899fSBaochen Qiang 332babb0cedSCarl Huang if (power_on) { 333babb0cedSCarl Huang ath11k_pci_enable_ltssm(ab); 334babb0cedSCarl Huang ath11k_pci_clear_all_intrs(ab); 3350ccdf439SCarl Huang ath11k_pci_set_wlaon_pwr_ctrl(ab); 3365088df05SBaochen Qiang if (ab->hw_params.fix_l1ss) 33706999407SCarl Huang ath11k_pci_fix_l1ss(ab); 338babb0cedSCarl Huang } 339babb0cedSCarl Huang 340f3c603d4SCarl Huang ath11k_mhi_clear_vector(ab); 3418a0b899fSBaochen Qiang ath11k_pci_clear_dbg_registers(ab); 342f3c603d4SCarl Huang ath11k_pci_soc_global_reset(ab); 343f3c603d4SCarl Huang ath11k_mhi_set_mhictrl_reset(ab); 344f3c603d4SCarl Huang } 345f3c603d4SCarl Huang 3467f4beda2SGovind Singh static void ath11k_pci_init_qmi_ce_config(struct ath11k_base *ab) 3477f4beda2SGovind Singh { 3487f4beda2SGovind Singh struct ath11k_qmi_ce_cfg *cfg = &ab->qmi.ce_cfg; 3497f4beda2SGovind Singh 350967c1d11SAnilkumar Kolli cfg->tgt_ce = ab->hw_params.target_ce_config; 351967c1d11SAnilkumar Kolli cfg->tgt_ce_len = ab->hw_params.target_ce_count; 3527f4beda2SGovind Singh 353967c1d11SAnilkumar Kolli cfg->svc_to_ce_map = ab->hw_params.svc_to_ce_map; 354967c1d11SAnilkumar Kolli cfg->svc_to_ce_map_len = ab->hw_params.svc_to_ce_map_len; 35516001e4bSAnilkumar Kolli ab->qmi.service_ins_id = ab->hw_params.qmi_service_ins_id; 356e838c14aSCarl Huang 357e838c14aSCarl Huang ath11k_ce_get_shadow_config(ab, &cfg->shadow_reg_v2, 358e838c14aSCarl Huang &cfg->shadow_reg_v2_len); 3597f4beda2SGovind Singh } 3607f4beda2SGovind Singh 36196527d52SBaochen Qiang static void ath11k_pci_msi_config(struct ath11k_pci *ab_pci, bool enable) 36296527d52SBaochen Qiang { 36396527d52SBaochen Qiang struct pci_dev *dev = ab_pci->pdev; 36496527d52SBaochen Qiang u16 control; 36596527d52SBaochen Qiang 36696527d52SBaochen Qiang pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &control); 36796527d52SBaochen Qiang 36896527d52SBaochen Qiang if (enable) 36996527d52SBaochen Qiang control |= PCI_MSI_FLAGS_ENABLE; 37096527d52SBaochen Qiang else 37196527d52SBaochen Qiang control &= ~PCI_MSI_FLAGS_ENABLE; 37296527d52SBaochen Qiang 37396527d52SBaochen Qiang pci_write_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, control); 37496527d52SBaochen Qiang } 37596527d52SBaochen Qiang 37696527d52SBaochen Qiang static void ath11k_pci_msi_enable(struct ath11k_pci *ab_pci) 37796527d52SBaochen Qiang { 37896527d52SBaochen Qiang ath11k_pci_msi_config(ab_pci, true); 37996527d52SBaochen Qiang } 38096527d52SBaochen Qiang 38196527d52SBaochen Qiang static void ath11k_pci_msi_disable(struct ath11k_pci *ab_pci) 38296527d52SBaochen Qiang { 38396527d52SBaochen Qiang ath11k_pci_msi_config(ab_pci, false); 38496527d52SBaochen Qiang } 38596527d52SBaochen Qiang 38696527d52SBaochen Qiang static int ath11k_pci_alloc_msi(struct ath11k_pci *ab_pci) 3875697a564SGovind Singh { 3885697a564SGovind Singh struct ath11k_base *ab = ab_pci->ab; 3890cfaf224SManikanta Pubbisetty const struct ath11k_msi_config *msi_config = ab->pci.msi.config; 3900cfaf224SManikanta Pubbisetty struct pci_dev *pci_dev = ab_pci->pdev; 3915697a564SGovind Singh struct msi_desc *msi_desc; 3925697a564SGovind Singh int num_vectors; 3935697a564SGovind Singh int ret; 3945697a564SGovind Singh 3950cfaf224SManikanta Pubbisetty num_vectors = pci_alloc_irq_vectors(pci_dev, 3967a3aed0cSAnilkumar Kolli msi_config->total_vectors, 3977a3aed0cSAnilkumar Kolli msi_config->total_vectors, 3985697a564SGovind Singh PCI_IRQ_MSI); 399ac6e7348SCarl Huang if (num_vectors == msi_config->total_vectors) { 4005b32b6ddSManikanta Pubbisetty set_bit(ATH11K_FLAG_MULTI_MSI_VECTORS, &ab->dev_flags); 401ac6e7348SCarl Huang } else { 402ac6e7348SCarl Huang num_vectors = pci_alloc_irq_vectors(ab_pci->pdev, 403ac6e7348SCarl Huang 1, 404ac6e7348SCarl Huang 1, 405ac6e7348SCarl Huang PCI_IRQ_MSI); 406ac6e7348SCarl Huang if (num_vectors < 0) { 407ac6e7348SCarl Huang ret = -EINVAL; 408ac6e7348SCarl Huang goto reset_msi_config; 4095697a564SGovind Singh } 4105b32b6ddSManikanta Pubbisetty clear_bit(ATH11K_FLAG_MULTI_MSI_VECTORS, &ab->dev_flags); 4110cfaf224SManikanta Pubbisetty ab->pci.msi.config = &msi_config_one_msi; 412ac6e7348SCarl Huang ath11k_dbg(ab, ATH11K_DBG_PCI, "request MSI one vector\n"); 413ac6e7348SCarl Huang } 414ac6e7348SCarl Huang ath11k_info(ab, "MSI vectors: %d\n", num_vectors); 415ac6e7348SCarl Huang 41696527d52SBaochen Qiang ath11k_pci_msi_disable(ab_pci); 4175697a564SGovind Singh 4185697a564SGovind Singh msi_desc = irq_get_msi_desc(ab_pci->pdev->irq); 4195697a564SGovind Singh if (!msi_desc) { 4205697a564SGovind Singh ath11k_err(ab, "msi_desc is NULL!\n"); 4215697a564SGovind Singh ret = -EINVAL; 4225697a564SGovind Singh goto free_msi_vector; 4235697a564SGovind Singh } 4245697a564SGovind Singh 4250cfaf224SManikanta Pubbisetty ab->pci.msi.ep_base_data = msi_desc->msg.data; 4265697a564SGovind Singh 4270cfaf224SManikanta Pubbisetty pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_LO, 4280cfaf224SManikanta Pubbisetty &ab->pci.msi.addr_lo); 4290cfaf224SManikanta Pubbisetty 4300cfaf224SManikanta Pubbisetty if (msi_desc->pci.msi_attrib.is_64) { 4310cfaf224SManikanta Pubbisetty pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_HI, 4320cfaf224SManikanta Pubbisetty &ab->pci.msi.addr_hi); 4330cfaf224SManikanta Pubbisetty } else { 4340cfaf224SManikanta Pubbisetty ab->pci.msi.addr_hi = 0; 4350cfaf224SManikanta Pubbisetty } 4360cfaf224SManikanta Pubbisetty 4370cfaf224SManikanta Pubbisetty ath11k_dbg(ab, ATH11K_DBG_PCI, "msi base data is %d\n", ab->pci.msi.ep_base_data); 4385697a564SGovind Singh 4395697a564SGovind Singh return 0; 4405697a564SGovind Singh 4415697a564SGovind Singh free_msi_vector: 4425697a564SGovind Singh pci_free_irq_vectors(ab_pci->pdev); 4435697a564SGovind Singh 444ac6e7348SCarl Huang reset_msi_config: 4455697a564SGovind Singh return ret; 4465697a564SGovind Singh } 4475697a564SGovind Singh 44896527d52SBaochen Qiang static void ath11k_pci_free_msi(struct ath11k_pci *ab_pci) 4495697a564SGovind Singh { 4505697a564SGovind Singh pci_free_irq_vectors(ab_pci->pdev); 4515697a564SGovind Singh } 4525697a564SGovind Singh 45387b4072dSCarl Huang static int ath11k_pci_config_msi_data(struct ath11k_pci *ab_pci) 45487b4072dSCarl Huang { 45587b4072dSCarl Huang struct msi_desc *msi_desc; 45687b4072dSCarl Huang 45787b4072dSCarl Huang msi_desc = irq_get_msi_desc(ab_pci->pdev->irq); 45887b4072dSCarl Huang if (!msi_desc) { 45987b4072dSCarl Huang ath11k_err(ab_pci->ab, "msi_desc is NULL!\n"); 46087b4072dSCarl Huang pci_free_irq_vectors(ab_pci->pdev); 46187b4072dSCarl Huang return -EINVAL; 46287b4072dSCarl Huang } 46387b4072dSCarl Huang 4640cfaf224SManikanta Pubbisetty ab_pci->ab->pci.msi.ep_base_data = msi_desc->msg.data; 46587b4072dSCarl Huang 46687b4072dSCarl Huang ath11k_dbg(ab_pci->ab, ATH11K_DBG_PCI, "pci after request_irq msi_ep_base_data %d\n", 4670cfaf224SManikanta Pubbisetty ab_pci->ab->pci.msi.ep_base_data); 46887b4072dSCarl Huang 46987b4072dSCarl Huang return 0; 47087b4072dSCarl Huang } 47187b4072dSCarl Huang 4725762613eSGovind Singh static int ath11k_pci_claim(struct ath11k_pci *ab_pci, struct pci_dev *pdev) 4735762613eSGovind Singh { 4745762613eSGovind Singh struct ath11k_base *ab = ab_pci->ab; 4755762613eSGovind Singh u16 device_id; 4765762613eSGovind Singh int ret = 0; 4775762613eSGovind Singh 4785762613eSGovind Singh pci_read_config_word(pdev, PCI_DEVICE_ID, &device_id); 4795762613eSGovind Singh if (device_id != ab_pci->dev_id) { 4805762613eSGovind Singh ath11k_err(ab, "pci device id mismatch: 0x%x 0x%x\n", 4815762613eSGovind Singh device_id, ab_pci->dev_id); 4825762613eSGovind Singh ret = -EIO; 4835762613eSGovind Singh goto out; 4845762613eSGovind Singh } 4855762613eSGovind Singh 4865762613eSGovind Singh ret = pci_assign_resource(pdev, ATH11K_PCI_BAR_NUM); 4875762613eSGovind Singh if (ret) { 4885762613eSGovind Singh ath11k_err(ab, "failed to assign pci resource: %d\n", ret); 4895762613eSGovind Singh goto out; 4905762613eSGovind Singh } 4915762613eSGovind Singh 4925762613eSGovind Singh ret = pci_enable_device(pdev); 4935762613eSGovind Singh if (ret) { 4945762613eSGovind Singh ath11k_err(ab, "failed to enable pci device: %d\n", ret); 4955762613eSGovind Singh goto out; 4965762613eSGovind Singh } 4975762613eSGovind Singh 4985762613eSGovind Singh ret = pci_request_region(pdev, ATH11K_PCI_BAR_NUM, "ath11k_pci"); 4995762613eSGovind Singh if (ret) { 5005762613eSGovind Singh ath11k_err(ab, "failed to request pci region: %d\n", ret); 5015762613eSGovind Singh goto disable_device; 5025762613eSGovind Singh } 5035762613eSGovind Singh 504923a1346SChristophe JAILLET ret = dma_set_mask_and_coherent(&pdev->dev, 505923a1346SChristophe JAILLET DMA_BIT_MASK(ATH11K_PCI_DMA_MASK)); 5065762613eSGovind Singh if (ret) { 5075762613eSGovind Singh ath11k_err(ab, "failed to set pci dma mask to %d: %d\n", 5085762613eSGovind Singh ATH11K_PCI_DMA_MASK, ret); 5095762613eSGovind Singh goto release_region; 5105762613eSGovind Singh } 5115762613eSGovind Singh 5125762613eSGovind Singh pci_set_master(pdev); 5135762613eSGovind Singh 5145762613eSGovind Singh ab->mem_len = pci_resource_len(pdev, ATH11K_PCI_BAR_NUM); 5155762613eSGovind Singh ab->mem = pci_iomap(pdev, ATH11K_PCI_BAR_NUM, 0); 5165762613eSGovind Singh if (!ab->mem) { 5175762613eSGovind Singh ath11k_err(ab, "failed to map pci bar %d\n", ATH11K_PCI_BAR_NUM); 5185762613eSGovind Singh ret = -EIO; 5195762613eSGovind Singh goto clear_master; 5205762613eSGovind Singh } 5215762613eSGovind Singh 5225762613eSGovind Singh ath11k_dbg(ab, ATH11K_DBG_BOOT, "boot pci_mem 0x%pK\n", ab->mem); 5235762613eSGovind Singh return 0; 5245762613eSGovind Singh 5255762613eSGovind Singh clear_master: 5265762613eSGovind Singh pci_clear_master(pdev); 5275762613eSGovind Singh release_region: 5285762613eSGovind Singh pci_release_region(pdev, ATH11K_PCI_BAR_NUM); 5295762613eSGovind Singh disable_device: 5305762613eSGovind Singh pci_disable_device(pdev); 5315762613eSGovind Singh out: 5325762613eSGovind Singh return ret; 5335762613eSGovind Singh } 5345762613eSGovind Singh 5355762613eSGovind Singh static void ath11k_pci_free_region(struct ath11k_pci *ab_pci) 5365762613eSGovind Singh { 5375762613eSGovind Singh struct ath11k_base *ab = ab_pci->ab; 5385762613eSGovind Singh struct pci_dev *pci_dev = ab_pci->pdev; 5395762613eSGovind Singh 5405762613eSGovind Singh pci_iounmap(pci_dev, ab->mem); 5415762613eSGovind Singh ab->mem = NULL; 5425762613eSGovind Singh pci_clear_master(pci_dev); 5435762613eSGovind Singh pci_release_region(pci_dev, ATH11K_PCI_BAR_NUM); 5445762613eSGovind Singh if (pci_is_enabled(pci_dev)) 5455762613eSGovind Singh pci_disable_device(pci_dev); 5465762613eSGovind Singh } 5475762613eSGovind Singh 548e9603f4bSCarl Huang static void ath11k_pci_aspm_disable(struct ath11k_pci *ab_pci) 549e9603f4bSCarl Huang { 550e9603f4bSCarl Huang struct ath11k_base *ab = ab_pci->ab; 551e9603f4bSCarl Huang 552e9603f4bSCarl Huang pcie_capability_read_word(ab_pci->pdev, PCI_EXP_LNKCTL, 553e9603f4bSCarl Huang &ab_pci->link_ctl); 554e9603f4bSCarl Huang 555e9603f4bSCarl Huang ath11k_dbg(ab, ATH11K_DBG_PCI, "pci link_ctl 0x%04x L0s %d L1 %d\n", 556e9603f4bSCarl Huang ab_pci->link_ctl, 557e9603f4bSCarl Huang u16_get_bits(ab_pci->link_ctl, PCI_EXP_LNKCTL_ASPM_L0S), 558e9603f4bSCarl Huang u16_get_bits(ab_pci->link_ctl, PCI_EXP_LNKCTL_ASPM_L1)); 559e9603f4bSCarl Huang 560e9603f4bSCarl Huang /* disable L0s and L1 */ 561e9603f4bSCarl Huang pcie_capability_write_word(ab_pci->pdev, PCI_EXP_LNKCTL, 562e9603f4bSCarl Huang ab_pci->link_ctl & ~PCI_EXP_LNKCTL_ASPMC); 563e9603f4bSCarl Huang 564e9603f4bSCarl Huang set_bit(ATH11K_PCI_ASPM_RESTORE, &ab_pci->flags); 565e9603f4bSCarl Huang } 566e9603f4bSCarl Huang 5675b32b6ddSManikanta Pubbisetty static void ath11k_pci_aspm_restore(struct ath11k_pci *ab_pci) 5685b32b6ddSManikanta Pubbisetty { 5695b32b6ddSManikanta Pubbisetty if (test_and_clear_bit(ATH11K_PCI_ASPM_RESTORE, &ab_pci->flags)) 5705b32b6ddSManikanta Pubbisetty pcie_capability_write_word(ab_pci->pdev, PCI_EXP_LNKCTL, 5715b32b6ddSManikanta Pubbisetty ab_pci->link_ctl); 5725b32b6ddSManikanta Pubbisetty } 5735b32b6ddSManikanta Pubbisetty 5741399fb87SGovind Singh static int ath11k_pci_power_up(struct ath11k_base *ab) 5751399fb87SGovind Singh { 5761399fb87SGovind Singh struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 5771399fb87SGovind Singh int ret; 5781399fb87SGovind Singh 579a05bd851SCarl Huang ab_pci->register_window = 0; 5805b32b6ddSManikanta Pubbisetty clear_bit(ATH11K_FLAG_DEVICE_INIT_DONE, &ab->dev_flags); 581babb0cedSCarl Huang ath11k_pci_sw_reset(ab_pci->ab, true); 582f3c603d4SCarl Huang 583e9603f4bSCarl Huang /* Disable ASPM during firmware download due to problems switching 584e9603f4bSCarl Huang * to AMSS state. 585e9603f4bSCarl Huang */ 586e9603f4bSCarl Huang ath11k_pci_aspm_disable(ab_pci); 587e9603f4bSCarl Huang 58896527d52SBaochen Qiang ath11k_pci_msi_enable(ab_pci); 58996527d52SBaochen Qiang 5901399fb87SGovind Singh ret = ath11k_mhi_start(ab_pci); 5911399fb87SGovind Singh if (ret) { 5921399fb87SGovind Singh ath11k_err(ab, "failed to start mhi: %d\n", ret); 5931399fb87SGovind Singh return ret; 5941399fb87SGovind Singh } 5951399fb87SGovind Singh 596480a7361SKarthikeyan Periyasamy if (ab->bus_params.static_window_map) 597480a7361SKarthikeyan Periyasamy ath11k_pci_select_static_window(ab_pci); 598480a7361SKarthikeyan Periyasamy 5991399fb87SGovind Singh return 0; 6001399fb87SGovind Singh } 6011399fb87SGovind Singh 6021399fb87SGovind Singh static void ath11k_pci_power_down(struct ath11k_base *ab) 6031399fb87SGovind Singh { 6041399fb87SGovind Singh struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 6051399fb87SGovind Singh 606e9603f4bSCarl Huang /* restore aspm in case firmware bootup fails */ 6075b32b6ddSManikanta Pubbisetty ath11k_pci_aspm_restore(ab_pci); 608e9603f4bSCarl Huang 609babb0cedSCarl Huang ath11k_pci_force_wake(ab_pci->ab); 61096527d52SBaochen Qiang 61196527d52SBaochen Qiang ath11k_pci_msi_disable(ab_pci); 61296527d52SBaochen Qiang 6131399fb87SGovind Singh ath11k_mhi_stop(ab_pci); 6145b32b6ddSManikanta Pubbisetty clear_bit(ATH11K_FLAG_DEVICE_INIT_DONE, &ab->dev_flags); 615babb0cedSCarl Huang ath11k_pci_sw_reset(ab_pci->ab, false); 6161399fb87SGovind Singh } 6171399fb87SGovind Singh 618fa5917e4SCarl Huang static int ath11k_pci_hif_suspend(struct ath11k_base *ab) 619fa5917e4SCarl Huang { 620fa5917e4SCarl Huang struct ath11k_pci *ar_pci = ath11k_pci_priv(ab); 621fa5917e4SCarl Huang 622*3e80fcbcSKalle Valo return ath11k_mhi_suspend(ar_pci); 623fa5917e4SCarl Huang } 624fa5917e4SCarl Huang 625fa5917e4SCarl Huang static int ath11k_pci_hif_resume(struct ath11k_base *ab) 626fa5917e4SCarl Huang { 627fa5917e4SCarl Huang struct ath11k_pci *ar_pci = ath11k_pci_priv(ab); 628fa5917e4SCarl Huang 629*3e80fcbcSKalle Valo return ath11k_mhi_resume(ar_pci); 630fa5917e4SCarl Huang } 631fa5917e4SCarl Huang 632d578ec2aSCarl Huang static void ath11k_pci_hif_ce_irq_enable(struct ath11k_base *ab) 633d578ec2aSCarl Huang { 634bbfdc5a7SManikanta Pubbisetty ath11k_pcic_ce_irqs_enable(ab); 635d578ec2aSCarl Huang } 636d578ec2aSCarl Huang 637d578ec2aSCarl Huang static void ath11k_pci_hif_ce_irq_disable(struct ath11k_base *ab) 638d578ec2aSCarl Huang { 639bbfdc5a7SManikanta Pubbisetty ath11k_pcic_ce_irq_disable_sync(ab); 6407f4beda2SGovind Singh } 6417f4beda2SGovind Singh 6425b32b6ddSManikanta Pubbisetty static int ath11k_pci_start(struct ath11k_base *ab) 6435b32b6ddSManikanta Pubbisetty { 6445b32b6ddSManikanta Pubbisetty struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 6455b32b6ddSManikanta Pubbisetty 6465b32b6ddSManikanta Pubbisetty /* TODO: for now don't restore ASPM in case of single MSI 6475b32b6ddSManikanta Pubbisetty * vector as MHI register reading in M2 causes system hang. 6485b32b6ddSManikanta Pubbisetty */ 6495b32b6ddSManikanta Pubbisetty if (test_bit(ATH11K_FLAG_MULTI_MSI_VECTORS, &ab->dev_flags)) 6505b32b6ddSManikanta Pubbisetty ath11k_pci_aspm_restore(ab_pci); 6515b32b6ddSManikanta Pubbisetty else 6525b32b6ddSManikanta Pubbisetty ath11k_info(ab, "leaving PCI ASPM disabled to avoid MHI M2 problems\n"); 6535b32b6ddSManikanta Pubbisetty 6545b32b6ddSManikanta Pubbisetty ath11k_pcic_start(ab); 6555b32b6ddSManikanta Pubbisetty 6565b32b6ddSManikanta Pubbisetty return 0; 6575b32b6ddSManikanta Pubbisetty } 6585b32b6ddSManikanta Pubbisetty 6597f4beda2SGovind Singh static const struct ath11k_hif_ops ath11k_pci_hif_ops = { 6605b32b6ddSManikanta Pubbisetty .start = ath11k_pci_start, 661bbfdc5a7SManikanta Pubbisetty .stop = ath11k_pcic_stop, 662bbfdc5a7SManikanta Pubbisetty .read32 = ath11k_pcic_read32, 663bbfdc5a7SManikanta Pubbisetty .write32 = ath11k_pcic_write32, 6641399fb87SGovind Singh .power_down = ath11k_pci_power_down, 6651399fb87SGovind Singh .power_up = ath11k_pci_power_up, 666fa5917e4SCarl Huang .suspend = ath11k_pci_hif_suspend, 667fa5917e4SCarl Huang .resume = ath11k_pci_hif_resume, 668bbfdc5a7SManikanta Pubbisetty .irq_enable = ath11k_pcic_ext_irq_enable, 669bbfdc5a7SManikanta Pubbisetty .irq_disable = ath11k_pcic_ext_irq_disable, 670bbfdc5a7SManikanta Pubbisetty .get_msi_address = ath11k_pcic_get_msi_address, 6710cfaf224SManikanta Pubbisetty .get_user_msi_vector = ath11k_pcic_get_user_msi_assignment, 672bbfdc5a7SManikanta Pubbisetty .map_service_to_pipe = ath11k_pcic_map_service_to_pipe, 673d578ec2aSCarl Huang .ce_irq_enable = ath11k_pci_hif_ce_irq_enable, 674d578ec2aSCarl Huang .ce_irq_disable = ath11k_pci_hif_ce_irq_disable, 675bbfdc5a7SManikanta Pubbisetty .get_ce_msi_idx = ath11k_pcic_get_ce_msi_idx, 6761399fb87SGovind Singh }; 6771399fb87SGovind Singh 6780fbf1957SBaochen Qiang static void ath11k_pci_read_hw_version(struct ath11k_base *ab, u32 *major, u32 *minor) 6790fbf1957SBaochen Qiang { 6800fbf1957SBaochen Qiang u32 soc_hw_version; 6810fbf1957SBaochen Qiang 682bbfdc5a7SManikanta Pubbisetty soc_hw_version = ath11k_pcic_read32(ab, TCSR_SOC_HW_VERSION); 6830fbf1957SBaochen Qiang *major = FIELD_GET(TCSR_SOC_HW_VERSION_MAJOR_MASK, 6840fbf1957SBaochen Qiang soc_hw_version); 6850fbf1957SBaochen Qiang *minor = FIELD_GET(TCSR_SOC_HW_VERSION_MINOR_MASK, 6860fbf1957SBaochen Qiang soc_hw_version); 6870fbf1957SBaochen Qiang 6880fbf1957SBaochen Qiang ath11k_dbg(ab, ATH11K_DBG_PCI, "pci tcsr_soc_hw_version major %d minor %d\n", 6890fbf1957SBaochen Qiang *major, *minor); 6900fbf1957SBaochen Qiang } 6910fbf1957SBaochen Qiang 6925b32b6ddSManikanta Pubbisetty static int ath11k_pci_set_irq_affinity_hint(struct ath11k_pci *ab_pci, 6935b32b6ddSManikanta Pubbisetty const struct cpumask *m) 6945b32b6ddSManikanta Pubbisetty { 6955b32b6ddSManikanta Pubbisetty if (test_bit(ATH11K_FLAG_MULTI_MSI_VECTORS, &ab_pci->ab->dev_flags)) 6965b32b6ddSManikanta Pubbisetty return 0; 6975b32b6ddSManikanta Pubbisetty 6985b32b6ddSManikanta Pubbisetty return irq_set_affinity_hint(ab_pci->pdev->irq, m); 6995b32b6ddSManikanta Pubbisetty } 7005b32b6ddSManikanta Pubbisetty 7016e0355afSGovind Singh static int ath11k_pci_probe(struct pci_dev *pdev, 7026e0355afSGovind Singh const struct pci_device_id *pci_dev) 7036e0355afSGovind Singh { 7046e0355afSGovind Singh struct ath11k_base *ab; 7055762613eSGovind Singh struct ath11k_pci *ab_pci; 7066ac04bdcSAnilkumar Kolli u32 soc_hw_version_major, soc_hw_version_minor, addr; 7075762613eSGovind Singh int ret; 7086e0355afSGovind Singh 7091ff8ed78SGovind Singh ab = ath11k_core_alloc(&pdev->dev, sizeof(*ab_pci), ATH11K_BUS_PCI, 7101ff8ed78SGovind Singh &ath11k_pci_bus_params); 7116e0355afSGovind Singh if (!ab) { 7126e0355afSGovind Singh dev_err(&pdev->dev, "failed to allocate ath11k base\n"); 7136e0355afSGovind Singh return -ENOMEM; 7146e0355afSGovind Singh } 7156e0355afSGovind Singh 7166e0355afSGovind Singh ab->dev = &pdev->dev; 7176e0355afSGovind Singh pci_set_drvdata(pdev, ab); 7185762613eSGovind Singh ab_pci = ath11k_pci_priv(ab); 7195762613eSGovind Singh ab_pci->dev_id = pci_dev->device; 7205762613eSGovind Singh ab_pci->ab = ab; 7215697a564SGovind Singh ab_pci->pdev = pdev; 7227f4beda2SGovind Singh ab->hif.ops = &ath11k_pci_hif_ops; 7235762613eSGovind Singh pci_set_drvdata(pdev, ab); 724654e959aSGovind Singh spin_lock_init(&ab_pci->window_lock); 7255762613eSGovind Singh 7266ac04bdcSAnilkumar Kolli /* Set fixed_mem_region to true for platforms support reserved memory 7276ac04bdcSAnilkumar Kolli * from DT. If memory is reserved from DT for FW, ath11k driver need not 7286ac04bdcSAnilkumar Kolli * allocate memory. 7296ac04bdcSAnilkumar Kolli */ 7306ac04bdcSAnilkumar Kolli ret = of_property_read_u32(ab->dev->of_node, "memory-region", &addr); 7316ac04bdcSAnilkumar Kolli if (!ret) 7326ac04bdcSAnilkumar Kolli set_bit(ATH11K_FLAG_FIXED_MEM_RGN, &ab->dev_flags); 7336ac04bdcSAnilkumar Kolli 7345762613eSGovind Singh ret = ath11k_pci_claim(ab_pci, pdev); 7355762613eSGovind Singh if (ret) { 7365762613eSGovind Singh ath11k_err(ab, "failed to claim device: %d\n", ret); 7375762613eSGovind Singh goto err_free_core; 7385762613eSGovind Singh } 7396e0355afSGovind Singh 740fc95d10aSWen Gong ath11k_dbg(ab, ATH11K_DBG_BOOT, "pci probe %04x:%04x %04x:%04x\n", 741fc95d10aSWen Gong pdev->vendor, pdev->device, 742fc95d10aSWen Gong pdev->subsystem_vendor, pdev->subsystem_device); 743fc95d10aSWen Gong 744fc95d10aSWen Gong ab->id.vendor = pdev->vendor; 745fc95d10aSWen Gong ab->id.device = pdev->device; 746fc95d10aSWen Gong ab->id.subsystem_vendor = pdev->subsystem_vendor; 747fc95d10aSWen Gong ab->id.subsystem_device = pdev->subsystem_device; 748fc95d10aSWen Gong 74918ac1665SKalle Valo switch (pci_dev->device) { 75018ac1665SKalle Valo case QCA6390_DEVICE_ID: 7510fbf1957SBaochen Qiang ath11k_pci_read_hw_version(ab, &soc_hw_version_major, 7520fbf1957SBaochen Qiang &soc_hw_version_minor); 75318ac1665SKalle Valo switch (soc_hw_version_major) { 75418ac1665SKalle Valo case 2: 75518ac1665SKalle Valo ab->hw_rev = ATH11K_HW_QCA6390_HW20; 75618ac1665SKalle Valo break; 75718ac1665SKalle Valo default: 75818ac1665SKalle Valo dev_err(&pdev->dev, "Unsupported QCA6390 SOC hardware version: %d %d\n", 75918ac1665SKalle Valo soc_hw_version_major, soc_hw_version_minor); 76018ac1665SKalle Valo ret = -EOPNOTSUPP; 76118ac1665SKalle Valo goto err_pci_free_region; 76218ac1665SKalle Valo } 7635b32b6ddSManikanta Pubbisetty 7645b32b6ddSManikanta Pubbisetty ab->pci.ops = &ath11k_pci_ops_qca6390; 7654e809461SAnilkumar Kolli break; 7664e809461SAnilkumar Kolli case QCN9074_DEVICE_ID: 7674e809461SAnilkumar Kolli ab->bus_params.static_window_map = true; 7685b32b6ddSManikanta Pubbisetty ab->pci.ops = &ath11k_pci_ops_qcn9074; 7694e809461SAnilkumar Kolli ab->hw_rev = ATH11K_HW_QCN9074_HW10; 77018ac1665SKalle Valo break; 7710fbf1957SBaochen Qiang case WCN6855_DEVICE_ID: 772fc95d10aSWen Gong ab->id.bdf_search = ATH11K_BDF_SEARCH_BUS_AND_BOARD; 7730fbf1957SBaochen Qiang ath11k_pci_read_hw_version(ab, &soc_hw_version_major, 7740fbf1957SBaochen Qiang &soc_hw_version_minor); 7750fbf1957SBaochen Qiang switch (soc_hw_version_major) { 7760fbf1957SBaochen Qiang case 2: 777d1147a31SBaochen Qiang switch (soc_hw_version_minor) { 778d1147a31SBaochen Qiang case 0x00: 779d1147a31SBaochen Qiang case 0x01: 7800fbf1957SBaochen Qiang ab->hw_rev = ATH11K_HW_WCN6855_HW20; 7810fbf1957SBaochen Qiang break; 782d1147a31SBaochen Qiang case 0x10: 783d1147a31SBaochen Qiang case 0x11: 784d1147a31SBaochen Qiang ab->hw_rev = ATH11K_HW_WCN6855_HW21; 785d1147a31SBaochen Qiang break; 7860fbf1957SBaochen Qiang default: 787d1147a31SBaochen Qiang goto unsupported_wcn6855_soc; 788d1147a31SBaochen Qiang } 789d1147a31SBaochen Qiang break; 790d1147a31SBaochen Qiang default: 791d1147a31SBaochen Qiang unsupported_wcn6855_soc: 7920fbf1957SBaochen Qiang dev_err(&pdev->dev, "Unsupported WCN6855 SOC hardware version: %d %d\n", 7930fbf1957SBaochen Qiang soc_hw_version_major, soc_hw_version_minor); 7940fbf1957SBaochen Qiang ret = -EOPNOTSUPP; 7950fbf1957SBaochen Qiang goto err_pci_free_region; 7960fbf1957SBaochen Qiang } 7975b32b6ddSManikanta Pubbisetty 7985b32b6ddSManikanta Pubbisetty ab->pci.ops = &ath11k_pci_ops_qca6390; 7990fbf1957SBaochen Qiang break; 80018ac1665SKalle Valo default: 80118ac1665SKalle Valo dev_err(&pdev->dev, "Unknown PCI device found: 0x%x\n", 80218ac1665SKalle Valo pci_dev->device); 80318ac1665SKalle Valo ret = -EOPNOTSUPP; 80418ac1665SKalle Valo goto err_pci_free_region; 80518ac1665SKalle Valo } 80618ac1665SKalle Valo 8078d06b802SManikanta Pubbisetty ret = ath11k_pcic_init_msi_config(ab); 8088d06b802SManikanta Pubbisetty if (ret) { 8098d06b802SManikanta Pubbisetty ath11k_err(ab, "failed to init msi config: %d\n", ret); 8108d06b802SManikanta Pubbisetty goto err_pci_free_region; 8118d06b802SManikanta Pubbisetty } 8128d06b802SManikanta Pubbisetty 81396527d52SBaochen Qiang ret = ath11k_pci_alloc_msi(ab_pci); 8145697a564SGovind Singh if (ret) { 8155697a564SGovind Singh ath11k_err(ab, "failed to enable msi: %d\n", ret); 8165697a564SGovind Singh goto err_pci_free_region; 8175697a564SGovind Singh } 8185697a564SGovind Singh 819b8246f88SKalle Valo ret = ath11k_core_pre_init(ab); 820b8246f88SKalle Valo if (ret) 821b8246f88SKalle Valo goto err_pci_disable_msi; 822b8246f88SKalle Valo 8231399fb87SGovind Singh ret = ath11k_mhi_register(ab_pci); 8241399fb87SGovind Singh if (ret) { 8251399fb87SGovind Singh ath11k_err(ab, "failed to register mhi: %d\n", ret); 8261399fb87SGovind Singh goto err_pci_disable_msi; 8271399fb87SGovind Singh } 8281399fb87SGovind Singh 8297f4beda2SGovind Singh ret = ath11k_hal_srng_init(ab); 8307f4beda2SGovind Singh if (ret) 8317f4beda2SGovind Singh goto err_mhi_unregister; 8327f4beda2SGovind Singh 8337f4beda2SGovind Singh ret = ath11k_ce_alloc_pipes(ab); 8347f4beda2SGovind Singh if (ret) { 8357f4beda2SGovind Singh ath11k_err(ab, "failed to allocate ce pipes: %d\n", ret); 8367f4beda2SGovind Singh goto err_hal_srng_deinit; 8377f4beda2SGovind Singh } 8387f4beda2SGovind Singh 8397f4beda2SGovind Singh ath11k_pci_init_qmi_ce_config(ab); 8407f4beda2SGovind Singh 841bbfdc5a7SManikanta Pubbisetty ret = ath11k_pcic_config_irq(ab); 8427f4beda2SGovind Singh if (ret) { 8437f4beda2SGovind Singh ath11k_err(ab, "failed to config irq: %d\n", ret); 8447f4beda2SGovind Singh goto err_ce_free; 8457f4beda2SGovind Singh } 8467f4beda2SGovind Singh 8475b32b6ddSManikanta Pubbisetty ret = ath11k_pci_set_irq_affinity_hint(ab_pci, cpumask_of(0)); 8485b32b6ddSManikanta Pubbisetty if (ret) { 8495b32b6ddSManikanta Pubbisetty ath11k_err(ab, "failed to set irq affinity %d\n", ret); 8505b32b6ddSManikanta Pubbisetty goto err_free_irq; 8515b32b6ddSManikanta Pubbisetty } 8525b32b6ddSManikanta Pubbisetty 85387b4072dSCarl Huang /* kernel may allocate a dummy vector before request_irq and 85487b4072dSCarl Huang * then allocate a real vector when request_irq is called. 85587b4072dSCarl Huang * So get msi_data here again to avoid spurious interrupt 85687b4072dSCarl Huang * as msi_data will configured to srngs. 85787b4072dSCarl Huang */ 85887b4072dSCarl Huang ret = ath11k_pci_config_msi_data(ab_pci); 85987b4072dSCarl Huang if (ret) { 86087b4072dSCarl Huang ath11k_err(ab, "failed to config msi_data: %d\n", ret); 8615b32b6ddSManikanta Pubbisetty goto err_irq_affinity_cleanup; 86287b4072dSCarl Huang } 86387b4072dSCarl Huang 8647f4beda2SGovind Singh ret = ath11k_core_init(ab); 8657f4beda2SGovind Singh if (ret) { 8667f4beda2SGovind Singh ath11k_err(ab, "failed to init core: %d\n", ret); 8675b32b6ddSManikanta Pubbisetty goto err_irq_affinity_cleanup; 8687f4beda2SGovind Singh } 8696e0355afSGovind Singh return 0; 8705762613eSGovind Singh 8715b32b6ddSManikanta Pubbisetty err_irq_affinity_cleanup: 8725b32b6ddSManikanta Pubbisetty ath11k_pci_set_irq_affinity_hint(ab_pci, NULL); 8735b32b6ddSManikanta Pubbisetty 8747f4beda2SGovind Singh err_free_irq: 875bbfdc5a7SManikanta Pubbisetty ath11k_pcic_free_irq(ab); 8767f4beda2SGovind Singh 8777f4beda2SGovind Singh err_ce_free: 8787f4beda2SGovind Singh ath11k_ce_free_pipes(ab); 8797f4beda2SGovind Singh 8807f4beda2SGovind Singh err_hal_srng_deinit: 8817f4beda2SGovind Singh ath11k_hal_srng_deinit(ab); 8827f4beda2SGovind Singh 8837f4beda2SGovind Singh err_mhi_unregister: 8847f4beda2SGovind Singh ath11k_mhi_unregister(ab_pci); 8857f4beda2SGovind Singh 886b8246f88SKalle Valo err_pci_disable_msi: 88796527d52SBaochen Qiang ath11k_pci_free_msi(ab_pci); 888b8246f88SKalle Valo 8895697a564SGovind Singh err_pci_free_region: 8905697a564SGovind Singh ath11k_pci_free_region(ab_pci); 8915697a564SGovind Singh 8925762613eSGovind Singh err_free_core: 8935762613eSGovind Singh ath11k_core_free(ab); 8945697a564SGovind Singh 8955762613eSGovind Singh return ret; 8966e0355afSGovind Singh } 8976e0355afSGovind Singh 8986e0355afSGovind Singh static void ath11k_pci_remove(struct pci_dev *pdev) 8996e0355afSGovind Singh { 9006e0355afSGovind Singh struct ath11k_base *ab = pci_get_drvdata(pdev); 9015762613eSGovind Singh struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 9026e0355afSGovind Singh 9035b32b6ddSManikanta Pubbisetty ath11k_pci_set_irq_affinity_hint(ab_pci, NULL); 904e94b0749SBaochen Qiang 90561a57e51SAnilkumar Kolli if (test_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags)) { 90661a57e51SAnilkumar Kolli ath11k_pci_power_down(ab); 90761a57e51SAnilkumar Kolli ath11k_debugfs_soc_destroy(ab); 90861a57e51SAnilkumar Kolli ath11k_qmi_deinit_service(ab); 90961a57e51SAnilkumar Kolli goto qmi_fail; 91061a57e51SAnilkumar Kolli } 91161a57e51SAnilkumar Kolli 9126e0355afSGovind Singh set_bit(ATH11K_FLAG_UNREGISTERING, &ab->dev_flags); 9136fbd8898SCarl Huang 9146fbd8898SCarl Huang ath11k_core_deinit(ab); 9156fbd8898SCarl Huang 91661a57e51SAnilkumar Kolli qmi_fail: 9171399fb87SGovind Singh ath11k_mhi_unregister(ab_pci); 9186fbd8898SCarl Huang 919bbfdc5a7SManikanta Pubbisetty ath11k_pcic_free_irq(ab); 92096527d52SBaochen Qiang ath11k_pci_free_msi(ab_pci); 9215762613eSGovind Singh ath11k_pci_free_region(ab_pci); 9226fbd8898SCarl Huang 9236fbd8898SCarl Huang ath11k_hal_srng_deinit(ab); 9246fbd8898SCarl Huang ath11k_ce_free_pipes(ab); 9256e0355afSGovind Singh ath11k_core_free(ab); 9266e0355afSGovind Singh } 9276e0355afSGovind Singh 9281399fb87SGovind Singh static void ath11k_pci_shutdown(struct pci_dev *pdev) 9291399fb87SGovind Singh { 9301399fb87SGovind Singh struct ath11k_base *ab = pci_get_drvdata(pdev); 9311399fb87SGovind Singh 9321399fb87SGovind Singh ath11k_pci_power_down(ab); 9331399fb87SGovind Singh } 9341399fb87SGovind Singh 935d1b0c338SCarl Huang static __maybe_unused int ath11k_pci_pm_suspend(struct device *dev) 936d1b0c338SCarl Huang { 937d1b0c338SCarl Huang struct ath11k_base *ab = dev_get_drvdata(dev); 938d1b0c338SCarl Huang int ret; 939d1b0c338SCarl Huang 940b4f4c564SKalle Valo if (test_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags)) { 941b4f4c564SKalle Valo ath11k_dbg(ab, ATH11K_DBG_BOOT, "boot skipping pci suspend as qmi is not initialised\n"); 942b4f4c564SKalle Valo return 0; 943b4f4c564SKalle Valo } 944b4f4c564SKalle Valo 945d1b0c338SCarl Huang ret = ath11k_core_suspend(ab); 946d1b0c338SCarl Huang if (ret) 947d1b0c338SCarl Huang ath11k_warn(ab, "failed to suspend core: %d\n", ret); 948d1b0c338SCarl Huang 949d1b0c338SCarl Huang return ret; 950d1b0c338SCarl Huang } 951d1b0c338SCarl Huang 952d1b0c338SCarl Huang static __maybe_unused int ath11k_pci_pm_resume(struct device *dev) 953d1b0c338SCarl Huang { 954d1b0c338SCarl Huang struct ath11k_base *ab = dev_get_drvdata(dev); 955d1b0c338SCarl Huang int ret; 956d1b0c338SCarl Huang 957b4f4c564SKalle Valo if (test_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags)) { 958b4f4c564SKalle Valo ath11k_dbg(ab, ATH11K_DBG_BOOT, "boot skipping pci resume as qmi is not initialised\n"); 959b4f4c564SKalle Valo return 0; 960b4f4c564SKalle Valo } 961b4f4c564SKalle Valo 962d1b0c338SCarl Huang ret = ath11k_core_resume(ab); 963d1b0c338SCarl Huang if (ret) 964d1b0c338SCarl Huang ath11k_warn(ab, "failed to resume core: %d\n", ret); 965d1b0c338SCarl Huang 966d1b0c338SCarl Huang return ret; 967d1b0c338SCarl Huang } 968d1b0c338SCarl Huang 969d1b0c338SCarl Huang static SIMPLE_DEV_PM_OPS(ath11k_pci_pm_ops, 970d1b0c338SCarl Huang ath11k_pci_pm_suspend, 971d1b0c338SCarl Huang ath11k_pci_pm_resume); 972d1b0c338SCarl Huang 9736e0355afSGovind Singh static struct pci_driver ath11k_pci_driver = { 9746e0355afSGovind Singh .name = "ath11k_pci", 9756e0355afSGovind Singh .id_table = ath11k_pci_id_table, 9766e0355afSGovind Singh .probe = ath11k_pci_probe, 9776e0355afSGovind Singh .remove = ath11k_pci_remove, 9781399fb87SGovind Singh .shutdown = ath11k_pci_shutdown, 979d1b0c338SCarl Huang #ifdef CONFIG_PM 980d1b0c338SCarl Huang .driver.pm = &ath11k_pci_pm_ops, 981d1b0c338SCarl Huang #endif 9826e0355afSGovind Singh }; 9836e0355afSGovind Singh 9846e0355afSGovind Singh static int ath11k_pci_init(void) 9856e0355afSGovind Singh { 9866e0355afSGovind Singh int ret; 9876e0355afSGovind Singh 9886e0355afSGovind Singh ret = pci_register_driver(&ath11k_pci_driver); 9896e0355afSGovind Singh if (ret) 9906e0355afSGovind Singh pr_err("failed to register ath11k pci driver: %d\n", 9916e0355afSGovind Singh ret); 9926e0355afSGovind Singh 9936e0355afSGovind Singh return ret; 9946e0355afSGovind Singh } 9956e0355afSGovind Singh module_init(ath11k_pci_init); 9966e0355afSGovind Singh 9976e0355afSGovind Singh static void ath11k_pci_exit(void) 9986e0355afSGovind Singh { 9996e0355afSGovind Singh pci_unregister_driver(&ath11k_pci_driver); 10006e0355afSGovind Singh } 10016e0355afSGovind Singh 10026e0355afSGovind Singh module_exit(ath11k_pci_exit); 10036e0355afSGovind Singh 10046e0355afSGovind Singh MODULE_DESCRIPTION("Driver support for Qualcomm Technologies 802.11ax WLAN PCIe devices"); 10056e0355afSGovind Singh MODULE_LICENSE("Dual BSD/GPL"); 10063dbd7fe7SDevin Bayer 10073dbd7fe7SDevin Bayer /* QCA639x 2.0 firmware files */ 10083dbd7fe7SDevin Bayer MODULE_FIRMWARE(ATH11K_FW_DIR "/QCA6390/hw2.0/" ATH11K_BOARD_API2_FILE); 10093dbd7fe7SDevin Bayer MODULE_FIRMWARE(ATH11K_FW_DIR "/QCA6390/hw2.0/" ATH11K_AMSS_FILE); 10103dbd7fe7SDevin Bayer MODULE_FIRMWARE(ATH11K_FW_DIR "/QCA6390/hw2.0/" ATH11K_M3_FILE); 1011