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 118ac6e7348SCarl Huang static const struct ath11k_msi_config msi_config_one_msi = { 119ac6e7348SCarl Huang .total_vectors = 1, 120ac6e7348SCarl Huang .total_users = 4, 121ac6e7348SCarl Huang .users = (struct ath11k_msi_user[]) { 122ac6e7348SCarl Huang { .name = "MHI", .num_vectors = 3, .base_vector = 0 }, 123ac6e7348SCarl Huang { .name = "CE", .num_vectors = 1, .base_vector = 0 }, 124ac6e7348SCarl Huang { .name = "WAKE", .num_vectors = 1, .base_vector = 0 }, 125ac6e7348SCarl Huang { .name = "DP", .num_vectors = 1, .base_vector = 0 }, 126ac6e7348SCarl Huang }, 127ac6e7348SCarl Huang }; 128ac6e7348SCarl Huang 129480a7361SKarthikeyan Periyasamy static inline void ath11k_pci_select_static_window(struct ath11k_pci *ab_pci) 130480a7361SKarthikeyan Periyasamy { 131948171b5SManikanta Pubbisetty u32 umac_window; 132948171b5SManikanta Pubbisetty u32 ce_window; 133480a7361SKarthikeyan Periyasamy u32 window; 134480a7361SKarthikeyan Periyasamy 135948171b5SManikanta Pubbisetty umac_window = FIELD_GET(ATH11K_PCI_WINDOW_VALUE_MASK, HAL_SEQ_WCSS_UMAC_OFFSET); 136948171b5SManikanta Pubbisetty ce_window = FIELD_GET(ATH11K_PCI_WINDOW_VALUE_MASK, HAL_CE_WFSS_CE_REG_BASE); 137480a7361SKarthikeyan Periyasamy window = (umac_window << 12) | (ce_window << 6); 138480a7361SKarthikeyan Periyasamy 139948171b5SManikanta Pubbisetty iowrite32(ATH11K_PCI_WINDOW_ENABLE_BIT | window, 140948171b5SManikanta Pubbisetty ab_pci->ab->mem + ATH11K_PCI_WINDOW_REG_ADDRESS); 141480a7361SKarthikeyan Periyasamy } 142480a7361SKarthikeyan Periyasamy 143f3c603d4SCarl Huang static void ath11k_pci_soc_global_reset(struct ath11k_base *ab) 144f3c603d4SCarl Huang { 145f3c603d4SCarl Huang u32 val, delay; 146f3c603d4SCarl Huang 147bbfdc5a7SManikanta Pubbisetty val = ath11k_pcic_read32(ab, PCIE_SOC_GLOBAL_RESET); 148f3c603d4SCarl Huang 149f3c603d4SCarl Huang val |= PCIE_SOC_GLOBAL_RESET_V; 150f3c603d4SCarl Huang 151bbfdc5a7SManikanta Pubbisetty ath11k_pcic_write32(ab, PCIE_SOC_GLOBAL_RESET, val); 152f3c603d4SCarl Huang 153f3c603d4SCarl Huang /* TODO: exact time to sleep is uncertain */ 154f3c603d4SCarl Huang delay = 10; 155f3c603d4SCarl Huang mdelay(delay); 156f3c603d4SCarl Huang 157f3c603d4SCarl Huang /* Need to toggle V bit back otherwise stuck in reset status */ 158f3c603d4SCarl Huang val &= ~PCIE_SOC_GLOBAL_RESET_V; 159f3c603d4SCarl Huang 160bbfdc5a7SManikanta Pubbisetty ath11k_pcic_write32(ab, PCIE_SOC_GLOBAL_RESET, val); 161f3c603d4SCarl Huang 162f3c603d4SCarl Huang mdelay(delay); 163f3c603d4SCarl Huang 164bbfdc5a7SManikanta Pubbisetty val = ath11k_pcic_read32(ab, PCIE_SOC_GLOBAL_RESET); 165f3c603d4SCarl Huang if (val == 0xffffffff) 166f3c603d4SCarl Huang ath11k_warn(ab, "link down error during global reset\n"); 167f3c603d4SCarl Huang } 168f3c603d4SCarl Huang 169f3c603d4SCarl Huang static void ath11k_pci_clear_dbg_registers(struct ath11k_base *ab) 170f3c603d4SCarl Huang { 171f3c603d4SCarl Huang u32 val; 172f3c603d4SCarl Huang 173f3c603d4SCarl Huang /* read cookie */ 174bbfdc5a7SManikanta Pubbisetty val = ath11k_pcic_read32(ab, PCIE_Q6_COOKIE_ADDR); 175f3c603d4SCarl Huang ath11k_dbg(ab, ATH11K_DBG_PCI, "cookie:0x%x\n", val); 176f3c603d4SCarl Huang 177bbfdc5a7SManikanta Pubbisetty val = ath11k_pcic_read32(ab, WLAON_WARM_SW_ENTRY); 178f3c603d4SCarl Huang ath11k_dbg(ab, ATH11K_DBG_PCI, "WLAON_WARM_SW_ENTRY 0x%x\n", val); 179f3c603d4SCarl Huang 180f3c603d4SCarl Huang /* TODO: exact time to sleep is uncertain */ 181f3c603d4SCarl Huang mdelay(10); 182f3c603d4SCarl Huang 183f3c603d4SCarl Huang /* write 0 to WLAON_WARM_SW_ENTRY to prevent Q6 from 184f3c603d4SCarl Huang * continuing warm path and entering dead loop. 185f3c603d4SCarl Huang */ 186bbfdc5a7SManikanta Pubbisetty ath11k_pcic_write32(ab, WLAON_WARM_SW_ENTRY, 0); 187f3c603d4SCarl Huang mdelay(10); 188f3c603d4SCarl Huang 189bbfdc5a7SManikanta Pubbisetty val = ath11k_pcic_read32(ab, WLAON_WARM_SW_ENTRY); 190f3c603d4SCarl Huang ath11k_dbg(ab, ATH11K_DBG_PCI, "WLAON_WARM_SW_ENTRY 0x%x\n", val); 191f3c603d4SCarl Huang 192f3c603d4SCarl Huang /* A read clear register. clear the register to prevent 193f3c603d4SCarl Huang * Q6 from entering wrong code path. 194f3c603d4SCarl Huang */ 195bbfdc5a7SManikanta Pubbisetty val = ath11k_pcic_read32(ab, WLAON_SOC_RESET_CAUSE_REG); 196f3c603d4SCarl Huang ath11k_dbg(ab, ATH11K_DBG_PCI, "soc reset cause:%d\n", val); 197f3c603d4SCarl Huang } 198f3c603d4SCarl Huang 19906999407SCarl Huang static int ath11k_pci_set_link_reg(struct ath11k_base *ab, 20006999407SCarl Huang u32 offset, u32 value, u32 mask) 20106999407SCarl Huang { 20206999407SCarl Huang u32 v; 20306999407SCarl Huang int i; 20406999407SCarl Huang 205bbfdc5a7SManikanta Pubbisetty v = ath11k_pcic_read32(ab, offset); 20606999407SCarl Huang if ((v & mask) == value) 20706999407SCarl Huang return 0; 20806999407SCarl Huang 20906999407SCarl Huang for (i = 0; i < 10; i++) { 210bbfdc5a7SManikanta Pubbisetty ath11k_pcic_write32(ab, offset, (v & ~mask) | value); 21106999407SCarl Huang 212bbfdc5a7SManikanta Pubbisetty v = ath11k_pcic_read32(ab, offset); 21306999407SCarl Huang if ((v & mask) == value) 21406999407SCarl Huang return 0; 21506999407SCarl Huang 21606999407SCarl Huang mdelay(2); 21706999407SCarl Huang } 21806999407SCarl Huang 21906999407SCarl Huang ath11k_warn(ab, "failed to set pcie link register 0x%08x: 0x%08x != 0x%08x\n", 22006999407SCarl Huang offset, v & mask, value); 22106999407SCarl Huang 22206999407SCarl Huang return -ETIMEDOUT; 22306999407SCarl Huang } 22406999407SCarl Huang 22506999407SCarl Huang static int ath11k_pci_fix_l1ss(struct ath11k_base *ab) 22606999407SCarl Huang { 22706999407SCarl Huang int ret; 22806999407SCarl Huang 22906999407SCarl Huang ret = ath11k_pci_set_link_reg(ab, 2306fe6f68fSKarthikeyan Periyasamy PCIE_QSERDES_COM_SYSCLK_EN_SEL_REG(ab), 23106999407SCarl Huang PCIE_QSERDES_COM_SYSCLK_EN_SEL_VAL, 23206999407SCarl Huang PCIE_QSERDES_COM_SYSCLK_EN_SEL_MSK); 23330d08503SDan Carpenter if (ret) { 23406999407SCarl Huang ath11k_warn(ab, "failed to set sysclk: %d\n", ret); 23506999407SCarl Huang return ret; 23606999407SCarl Huang } 23706999407SCarl Huang 23806999407SCarl Huang ret = ath11k_pci_set_link_reg(ab, 2396fe6f68fSKarthikeyan Periyasamy PCIE_PCS_OSC_DTCT_CONFIG1_REG(ab), 2406fe6f68fSKarthikeyan Periyasamy PCIE_PCS_OSC_DTCT_CONFIG1_VAL, 2416fe6f68fSKarthikeyan Periyasamy PCIE_PCS_OSC_DTCT_CONFIG_MSK); 24230d08503SDan Carpenter if (ret) { 24306999407SCarl Huang ath11k_warn(ab, "failed to set dtct config1 error: %d\n", ret); 24406999407SCarl Huang return ret; 24506999407SCarl Huang } 24606999407SCarl Huang 24706999407SCarl Huang ret = ath11k_pci_set_link_reg(ab, 2486fe6f68fSKarthikeyan Periyasamy PCIE_PCS_OSC_DTCT_CONFIG2_REG(ab), 2496fe6f68fSKarthikeyan Periyasamy PCIE_PCS_OSC_DTCT_CONFIG2_VAL, 2506fe6f68fSKarthikeyan Periyasamy PCIE_PCS_OSC_DTCT_CONFIG_MSK); 25130d08503SDan Carpenter if (ret) { 25206999407SCarl Huang ath11k_warn(ab, "failed to set dtct config2: %d\n", ret); 25306999407SCarl Huang return ret; 25406999407SCarl Huang } 25506999407SCarl Huang 25606999407SCarl Huang ret = ath11k_pci_set_link_reg(ab, 2576fe6f68fSKarthikeyan Periyasamy PCIE_PCS_OSC_DTCT_CONFIG4_REG(ab), 2586fe6f68fSKarthikeyan Periyasamy PCIE_PCS_OSC_DTCT_CONFIG4_VAL, 2596fe6f68fSKarthikeyan Periyasamy PCIE_PCS_OSC_DTCT_CONFIG_MSK); 26030d08503SDan Carpenter if (ret) { 26106999407SCarl Huang ath11k_warn(ab, "failed to set dtct config4: %d\n", ret); 26206999407SCarl Huang return ret; 26306999407SCarl Huang } 26406999407SCarl Huang 26506999407SCarl Huang return 0; 26606999407SCarl Huang } 26706999407SCarl Huang 268babb0cedSCarl Huang static void ath11k_pci_enable_ltssm(struct ath11k_base *ab) 269babb0cedSCarl Huang { 270babb0cedSCarl Huang u32 val; 271babb0cedSCarl Huang int i; 272babb0cedSCarl Huang 273bbfdc5a7SManikanta Pubbisetty val = ath11k_pcic_read32(ab, PCIE_PCIE_PARF_LTSSM); 274babb0cedSCarl Huang 275babb0cedSCarl Huang /* PCIE link seems very unstable after the Hot Reset*/ 276babb0cedSCarl Huang for (i = 0; val != PARM_LTSSM_VALUE && i < 5; i++) { 277babb0cedSCarl Huang if (val == 0xffffffff) 278babb0cedSCarl Huang mdelay(5); 279babb0cedSCarl Huang 280bbfdc5a7SManikanta Pubbisetty ath11k_pcic_write32(ab, PCIE_PCIE_PARF_LTSSM, PARM_LTSSM_VALUE); 281bbfdc5a7SManikanta Pubbisetty val = ath11k_pcic_read32(ab, PCIE_PCIE_PARF_LTSSM); 282babb0cedSCarl Huang } 283babb0cedSCarl Huang 284babb0cedSCarl Huang ath11k_dbg(ab, ATH11K_DBG_PCI, "pci ltssm 0x%x\n", val); 285babb0cedSCarl Huang 286bbfdc5a7SManikanta Pubbisetty val = ath11k_pcic_read32(ab, GCC_GCC_PCIE_HOT_RST); 287562934adSKalle Valo val |= GCC_GCC_PCIE_HOT_RST_VAL; 288bbfdc5a7SManikanta Pubbisetty ath11k_pcic_write32(ab, GCC_GCC_PCIE_HOT_RST, val); 289bbfdc5a7SManikanta Pubbisetty val = ath11k_pcic_read32(ab, GCC_GCC_PCIE_HOT_RST); 290babb0cedSCarl Huang 291babb0cedSCarl Huang ath11k_dbg(ab, ATH11K_DBG_PCI, "pci pcie_hot_rst 0x%x\n", val); 292babb0cedSCarl Huang 293babb0cedSCarl Huang mdelay(5); 294babb0cedSCarl Huang } 295babb0cedSCarl Huang 296babb0cedSCarl Huang static void ath11k_pci_clear_all_intrs(struct ath11k_base *ab) 297babb0cedSCarl Huang { 298babb0cedSCarl Huang /* This is a WAR for PCIE Hotreset. 299babb0cedSCarl Huang * When target receive Hotreset, but will set the interrupt. 300babb0cedSCarl Huang * So when download SBL again, SBL will open Interrupt and 301babb0cedSCarl Huang * receive it, and crash immediately. 302babb0cedSCarl Huang */ 303bbfdc5a7SManikanta Pubbisetty ath11k_pcic_write32(ab, PCIE_PCIE_INT_ALL_CLEAR, PCIE_INT_CLEAR_ALL); 304babb0cedSCarl Huang } 305babb0cedSCarl Huang 3060ccdf439SCarl Huang static void ath11k_pci_set_wlaon_pwr_ctrl(struct ath11k_base *ab) 3070ccdf439SCarl Huang { 3080ccdf439SCarl Huang u32 val; 3090ccdf439SCarl Huang 310bbfdc5a7SManikanta Pubbisetty val = ath11k_pcic_read32(ab, WLAON_QFPROM_PWR_CTRL_REG); 3110ccdf439SCarl Huang val &= ~QFPROM_PWR_CTRL_VDD4BLOW_MASK; 312bbfdc5a7SManikanta Pubbisetty ath11k_pcic_write32(ab, WLAON_QFPROM_PWR_CTRL_REG, val); 3130ccdf439SCarl Huang } 3140ccdf439SCarl Huang 315f3c603d4SCarl Huang static void ath11k_pci_force_wake(struct ath11k_base *ab) 316f3c603d4SCarl Huang { 317bbfdc5a7SManikanta Pubbisetty ath11k_pcic_write32(ab, PCIE_SOC_WAKE_PCIE_LOCAL_REG, 1); 318f3c603d4SCarl Huang mdelay(5); 319f3c603d4SCarl Huang } 320f3c603d4SCarl Huang 321babb0cedSCarl Huang static void ath11k_pci_sw_reset(struct ath11k_base *ab, bool power_on) 322f3c603d4SCarl Huang { 3238a0b899fSBaochen Qiang mdelay(100); 3248a0b899fSBaochen Qiang 325babb0cedSCarl Huang if (power_on) { 326babb0cedSCarl Huang ath11k_pci_enable_ltssm(ab); 327babb0cedSCarl Huang ath11k_pci_clear_all_intrs(ab); 3280ccdf439SCarl Huang ath11k_pci_set_wlaon_pwr_ctrl(ab); 3295088df05SBaochen Qiang if (ab->hw_params.fix_l1ss) 33006999407SCarl Huang ath11k_pci_fix_l1ss(ab); 331babb0cedSCarl Huang } 332babb0cedSCarl Huang 333f3c603d4SCarl Huang ath11k_mhi_clear_vector(ab); 3348a0b899fSBaochen Qiang ath11k_pci_clear_dbg_registers(ab); 335f3c603d4SCarl Huang ath11k_pci_soc_global_reset(ab); 336f3c603d4SCarl Huang ath11k_mhi_set_mhictrl_reset(ab); 337f3c603d4SCarl Huang } 338f3c603d4SCarl Huang 3397f4beda2SGovind Singh static void ath11k_pci_init_qmi_ce_config(struct ath11k_base *ab) 3407f4beda2SGovind Singh { 3417f4beda2SGovind Singh struct ath11k_qmi_ce_cfg *cfg = &ab->qmi.ce_cfg; 3427f4beda2SGovind Singh 343967c1d11SAnilkumar Kolli cfg->tgt_ce = ab->hw_params.target_ce_config; 344967c1d11SAnilkumar Kolli cfg->tgt_ce_len = ab->hw_params.target_ce_count; 3457f4beda2SGovind Singh 346967c1d11SAnilkumar Kolli cfg->svc_to_ce_map = ab->hw_params.svc_to_ce_map; 347967c1d11SAnilkumar Kolli cfg->svc_to_ce_map_len = ab->hw_params.svc_to_ce_map_len; 34816001e4bSAnilkumar Kolli ab->qmi.service_ins_id = ab->hw_params.qmi_service_ins_id; 349e838c14aSCarl Huang 350e838c14aSCarl Huang ath11k_ce_get_shadow_config(ab, &cfg->shadow_reg_v2, 351e838c14aSCarl Huang &cfg->shadow_reg_v2_len); 3527f4beda2SGovind Singh } 3537f4beda2SGovind Singh 35496527d52SBaochen Qiang static void ath11k_pci_msi_config(struct ath11k_pci *ab_pci, bool enable) 35596527d52SBaochen Qiang { 35696527d52SBaochen Qiang struct pci_dev *dev = ab_pci->pdev; 35796527d52SBaochen Qiang u16 control; 35896527d52SBaochen Qiang 35996527d52SBaochen Qiang pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &control); 36096527d52SBaochen Qiang 36196527d52SBaochen Qiang if (enable) 36296527d52SBaochen Qiang control |= PCI_MSI_FLAGS_ENABLE; 36396527d52SBaochen Qiang else 36496527d52SBaochen Qiang control &= ~PCI_MSI_FLAGS_ENABLE; 36596527d52SBaochen Qiang 36696527d52SBaochen Qiang pci_write_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, control); 36796527d52SBaochen Qiang } 36896527d52SBaochen Qiang 36996527d52SBaochen Qiang static void ath11k_pci_msi_enable(struct ath11k_pci *ab_pci) 37096527d52SBaochen Qiang { 37196527d52SBaochen Qiang ath11k_pci_msi_config(ab_pci, true); 37296527d52SBaochen Qiang } 37396527d52SBaochen Qiang 37496527d52SBaochen Qiang static void ath11k_pci_msi_disable(struct ath11k_pci *ab_pci) 37596527d52SBaochen Qiang { 37696527d52SBaochen Qiang ath11k_pci_msi_config(ab_pci, false); 37796527d52SBaochen Qiang } 37896527d52SBaochen Qiang 37996527d52SBaochen Qiang static int ath11k_pci_alloc_msi(struct ath11k_pci *ab_pci) 3805697a564SGovind Singh { 3815697a564SGovind Singh struct ath11k_base *ab = ab_pci->ab; 3820cfaf224SManikanta Pubbisetty const struct ath11k_msi_config *msi_config = ab->pci.msi.config; 3830cfaf224SManikanta Pubbisetty struct pci_dev *pci_dev = ab_pci->pdev; 3845697a564SGovind Singh struct msi_desc *msi_desc; 3855697a564SGovind Singh int num_vectors; 3865697a564SGovind Singh int ret; 3875697a564SGovind Singh 3880cfaf224SManikanta Pubbisetty num_vectors = pci_alloc_irq_vectors(pci_dev, 3897a3aed0cSAnilkumar Kolli msi_config->total_vectors, 3907a3aed0cSAnilkumar Kolli msi_config->total_vectors, 3915697a564SGovind Singh PCI_IRQ_MSI); 392ac6e7348SCarl Huang if (num_vectors == msi_config->total_vectors) { 3935b32b6ddSManikanta Pubbisetty set_bit(ATH11K_FLAG_MULTI_MSI_VECTORS, &ab->dev_flags); 394ac6e7348SCarl Huang } else { 395ac6e7348SCarl Huang num_vectors = pci_alloc_irq_vectors(ab_pci->pdev, 396ac6e7348SCarl Huang 1, 397ac6e7348SCarl Huang 1, 398ac6e7348SCarl Huang PCI_IRQ_MSI); 399ac6e7348SCarl Huang if (num_vectors < 0) { 400ac6e7348SCarl Huang ret = -EINVAL; 401ac6e7348SCarl Huang goto reset_msi_config; 4025697a564SGovind Singh } 4035b32b6ddSManikanta Pubbisetty clear_bit(ATH11K_FLAG_MULTI_MSI_VECTORS, &ab->dev_flags); 4040cfaf224SManikanta Pubbisetty ab->pci.msi.config = &msi_config_one_msi; 405ac6e7348SCarl Huang ath11k_dbg(ab, ATH11K_DBG_PCI, "request MSI one vector\n"); 406ac6e7348SCarl Huang } 407ac6e7348SCarl Huang ath11k_info(ab, "MSI vectors: %d\n", num_vectors); 408ac6e7348SCarl Huang 40996527d52SBaochen Qiang ath11k_pci_msi_disable(ab_pci); 4105697a564SGovind Singh 4115697a564SGovind Singh msi_desc = irq_get_msi_desc(ab_pci->pdev->irq); 4125697a564SGovind Singh if (!msi_desc) { 4135697a564SGovind Singh ath11k_err(ab, "msi_desc is NULL!\n"); 4145697a564SGovind Singh ret = -EINVAL; 4155697a564SGovind Singh goto free_msi_vector; 4165697a564SGovind Singh } 4175697a564SGovind Singh 4180cfaf224SManikanta Pubbisetty ab->pci.msi.ep_base_data = msi_desc->msg.data; 4195697a564SGovind Singh 4200cfaf224SManikanta Pubbisetty pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_LO, 4210cfaf224SManikanta Pubbisetty &ab->pci.msi.addr_lo); 4220cfaf224SManikanta Pubbisetty 4230cfaf224SManikanta Pubbisetty if (msi_desc->pci.msi_attrib.is_64) { 4240cfaf224SManikanta Pubbisetty pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_HI, 4250cfaf224SManikanta Pubbisetty &ab->pci.msi.addr_hi); 4260cfaf224SManikanta Pubbisetty } else { 4270cfaf224SManikanta Pubbisetty ab->pci.msi.addr_hi = 0; 4280cfaf224SManikanta Pubbisetty } 4290cfaf224SManikanta Pubbisetty 4300cfaf224SManikanta Pubbisetty ath11k_dbg(ab, ATH11K_DBG_PCI, "msi base data is %d\n", ab->pci.msi.ep_base_data); 4315697a564SGovind Singh 4325697a564SGovind Singh return 0; 4335697a564SGovind Singh 4345697a564SGovind Singh free_msi_vector: 4355697a564SGovind Singh pci_free_irq_vectors(ab_pci->pdev); 4365697a564SGovind Singh 437ac6e7348SCarl Huang reset_msi_config: 4385697a564SGovind Singh return ret; 4395697a564SGovind Singh } 4405697a564SGovind Singh 44196527d52SBaochen Qiang static void ath11k_pci_free_msi(struct ath11k_pci *ab_pci) 4425697a564SGovind Singh { 4435697a564SGovind Singh pci_free_irq_vectors(ab_pci->pdev); 4445697a564SGovind Singh } 4455697a564SGovind Singh 44687b4072dSCarl Huang static int ath11k_pci_config_msi_data(struct ath11k_pci *ab_pci) 44787b4072dSCarl Huang { 44887b4072dSCarl Huang struct msi_desc *msi_desc; 44987b4072dSCarl Huang 45087b4072dSCarl Huang msi_desc = irq_get_msi_desc(ab_pci->pdev->irq); 45187b4072dSCarl Huang if (!msi_desc) { 45287b4072dSCarl Huang ath11k_err(ab_pci->ab, "msi_desc is NULL!\n"); 45387b4072dSCarl Huang pci_free_irq_vectors(ab_pci->pdev); 45487b4072dSCarl Huang return -EINVAL; 45587b4072dSCarl Huang } 45687b4072dSCarl Huang 4570cfaf224SManikanta Pubbisetty ab_pci->ab->pci.msi.ep_base_data = msi_desc->msg.data; 45887b4072dSCarl Huang 45987b4072dSCarl Huang ath11k_dbg(ab_pci->ab, ATH11K_DBG_PCI, "pci after request_irq msi_ep_base_data %d\n", 4600cfaf224SManikanta Pubbisetty ab_pci->ab->pci.msi.ep_base_data); 46187b4072dSCarl Huang 46287b4072dSCarl Huang return 0; 46387b4072dSCarl Huang } 46487b4072dSCarl Huang 4655762613eSGovind Singh static int ath11k_pci_claim(struct ath11k_pci *ab_pci, struct pci_dev *pdev) 4665762613eSGovind Singh { 4675762613eSGovind Singh struct ath11k_base *ab = ab_pci->ab; 4685762613eSGovind Singh u16 device_id; 4695762613eSGovind Singh int ret = 0; 4705762613eSGovind Singh 4715762613eSGovind Singh pci_read_config_word(pdev, PCI_DEVICE_ID, &device_id); 4725762613eSGovind Singh if (device_id != ab_pci->dev_id) { 4735762613eSGovind Singh ath11k_err(ab, "pci device id mismatch: 0x%x 0x%x\n", 4745762613eSGovind Singh device_id, ab_pci->dev_id); 4755762613eSGovind Singh ret = -EIO; 4765762613eSGovind Singh goto out; 4775762613eSGovind Singh } 4785762613eSGovind Singh 4795762613eSGovind Singh ret = pci_assign_resource(pdev, ATH11K_PCI_BAR_NUM); 4805762613eSGovind Singh if (ret) { 4815762613eSGovind Singh ath11k_err(ab, "failed to assign pci resource: %d\n", ret); 4825762613eSGovind Singh goto out; 4835762613eSGovind Singh } 4845762613eSGovind Singh 4855762613eSGovind Singh ret = pci_enable_device(pdev); 4865762613eSGovind Singh if (ret) { 4875762613eSGovind Singh ath11k_err(ab, "failed to enable pci device: %d\n", ret); 4885762613eSGovind Singh goto out; 4895762613eSGovind Singh } 4905762613eSGovind Singh 4915762613eSGovind Singh ret = pci_request_region(pdev, ATH11K_PCI_BAR_NUM, "ath11k_pci"); 4925762613eSGovind Singh if (ret) { 4935762613eSGovind Singh ath11k_err(ab, "failed to request pci region: %d\n", ret); 4945762613eSGovind Singh goto disable_device; 4955762613eSGovind Singh } 4965762613eSGovind Singh 497923a1346SChristophe JAILLET ret = dma_set_mask_and_coherent(&pdev->dev, 498923a1346SChristophe JAILLET DMA_BIT_MASK(ATH11K_PCI_DMA_MASK)); 4995762613eSGovind Singh if (ret) { 5005762613eSGovind Singh ath11k_err(ab, "failed to set pci dma mask to %d: %d\n", 5015762613eSGovind Singh ATH11K_PCI_DMA_MASK, ret); 5025762613eSGovind Singh goto release_region; 5035762613eSGovind Singh } 5045762613eSGovind Singh 5055762613eSGovind Singh pci_set_master(pdev); 5065762613eSGovind Singh 5075762613eSGovind Singh ab->mem_len = pci_resource_len(pdev, ATH11K_PCI_BAR_NUM); 5085762613eSGovind Singh ab->mem = pci_iomap(pdev, ATH11K_PCI_BAR_NUM, 0); 5095762613eSGovind Singh if (!ab->mem) { 5105762613eSGovind Singh ath11k_err(ab, "failed to map pci bar %d\n", ATH11K_PCI_BAR_NUM); 5115762613eSGovind Singh ret = -EIO; 5125762613eSGovind Singh goto clear_master; 5135762613eSGovind Singh } 5145762613eSGovind Singh 5155762613eSGovind Singh ath11k_dbg(ab, ATH11K_DBG_BOOT, "boot pci_mem 0x%pK\n", ab->mem); 5165762613eSGovind Singh return 0; 5175762613eSGovind Singh 5185762613eSGovind Singh clear_master: 5195762613eSGovind Singh pci_clear_master(pdev); 5205762613eSGovind Singh release_region: 5215762613eSGovind Singh pci_release_region(pdev, ATH11K_PCI_BAR_NUM); 5225762613eSGovind Singh disable_device: 5235762613eSGovind Singh pci_disable_device(pdev); 5245762613eSGovind Singh out: 5255762613eSGovind Singh return ret; 5265762613eSGovind Singh } 5275762613eSGovind Singh 5285762613eSGovind Singh static void ath11k_pci_free_region(struct ath11k_pci *ab_pci) 5295762613eSGovind Singh { 5305762613eSGovind Singh struct ath11k_base *ab = ab_pci->ab; 5315762613eSGovind Singh struct pci_dev *pci_dev = ab_pci->pdev; 5325762613eSGovind Singh 5335762613eSGovind Singh pci_iounmap(pci_dev, ab->mem); 5345762613eSGovind Singh ab->mem = NULL; 5355762613eSGovind Singh pci_clear_master(pci_dev); 5365762613eSGovind Singh pci_release_region(pci_dev, ATH11K_PCI_BAR_NUM); 5375762613eSGovind Singh if (pci_is_enabled(pci_dev)) 5385762613eSGovind Singh pci_disable_device(pci_dev); 5395762613eSGovind Singh } 5405762613eSGovind Singh 541e9603f4bSCarl Huang static void ath11k_pci_aspm_disable(struct ath11k_pci *ab_pci) 542e9603f4bSCarl Huang { 543e9603f4bSCarl Huang struct ath11k_base *ab = ab_pci->ab; 544e9603f4bSCarl Huang 545e9603f4bSCarl Huang pcie_capability_read_word(ab_pci->pdev, PCI_EXP_LNKCTL, 546e9603f4bSCarl Huang &ab_pci->link_ctl); 547e9603f4bSCarl Huang 548e9603f4bSCarl Huang ath11k_dbg(ab, ATH11K_DBG_PCI, "pci link_ctl 0x%04x L0s %d L1 %d\n", 549e9603f4bSCarl Huang ab_pci->link_ctl, 550e9603f4bSCarl Huang u16_get_bits(ab_pci->link_ctl, PCI_EXP_LNKCTL_ASPM_L0S), 551e9603f4bSCarl Huang u16_get_bits(ab_pci->link_ctl, PCI_EXP_LNKCTL_ASPM_L1)); 552e9603f4bSCarl Huang 553e9603f4bSCarl Huang /* disable L0s and L1 */ 554e9603f4bSCarl Huang pcie_capability_write_word(ab_pci->pdev, PCI_EXP_LNKCTL, 555e9603f4bSCarl Huang ab_pci->link_ctl & ~PCI_EXP_LNKCTL_ASPMC); 556e9603f4bSCarl Huang 557e9603f4bSCarl Huang set_bit(ATH11K_PCI_ASPM_RESTORE, &ab_pci->flags); 558e9603f4bSCarl Huang } 559e9603f4bSCarl Huang 5605b32b6ddSManikanta Pubbisetty static void ath11k_pci_aspm_restore(struct ath11k_pci *ab_pci) 5615b32b6ddSManikanta Pubbisetty { 5625b32b6ddSManikanta Pubbisetty if (test_and_clear_bit(ATH11K_PCI_ASPM_RESTORE, &ab_pci->flags)) 5635b32b6ddSManikanta Pubbisetty pcie_capability_write_word(ab_pci->pdev, PCI_EXP_LNKCTL, 5645b32b6ddSManikanta Pubbisetty ab_pci->link_ctl); 5655b32b6ddSManikanta Pubbisetty } 5665b32b6ddSManikanta Pubbisetty 5671399fb87SGovind Singh static int ath11k_pci_power_up(struct ath11k_base *ab) 5681399fb87SGovind Singh { 5691399fb87SGovind Singh struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 5701399fb87SGovind Singh int ret; 5711399fb87SGovind Singh 572a05bd851SCarl Huang ab_pci->register_window = 0; 5735b32b6ddSManikanta Pubbisetty clear_bit(ATH11K_FLAG_DEVICE_INIT_DONE, &ab->dev_flags); 574babb0cedSCarl Huang ath11k_pci_sw_reset(ab_pci->ab, true); 575f3c603d4SCarl Huang 576e9603f4bSCarl Huang /* Disable ASPM during firmware download due to problems switching 577e9603f4bSCarl Huang * to AMSS state. 578e9603f4bSCarl Huang */ 579e9603f4bSCarl Huang ath11k_pci_aspm_disable(ab_pci); 580e9603f4bSCarl Huang 58196527d52SBaochen Qiang ath11k_pci_msi_enable(ab_pci); 58296527d52SBaochen Qiang 5831399fb87SGovind Singh ret = ath11k_mhi_start(ab_pci); 5841399fb87SGovind Singh if (ret) { 5851399fb87SGovind Singh ath11k_err(ab, "failed to start mhi: %d\n", ret); 5861399fb87SGovind Singh return ret; 5871399fb87SGovind Singh } 5881399fb87SGovind Singh 589*92c1858eSManikanta Pubbisetty if (ab->hw_params.static_window_map) 590480a7361SKarthikeyan Periyasamy ath11k_pci_select_static_window(ab_pci); 591480a7361SKarthikeyan Periyasamy 5921399fb87SGovind Singh return 0; 5931399fb87SGovind Singh } 5941399fb87SGovind Singh 5951399fb87SGovind Singh static void ath11k_pci_power_down(struct ath11k_base *ab) 5961399fb87SGovind Singh { 5971399fb87SGovind Singh struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 5981399fb87SGovind Singh 599e9603f4bSCarl Huang /* restore aspm in case firmware bootup fails */ 6005b32b6ddSManikanta Pubbisetty ath11k_pci_aspm_restore(ab_pci); 601e9603f4bSCarl Huang 602babb0cedSCarl Huang ath11k_pci_force_wake(ab_pci->ab); 60396527d52SBaochen Qiang 60496527d52SBaochen Qiang ath11k_pci_msi_disable(ab_pci); 60596527d52SBaochen Qiang 6061399fb87SGovind Singh ath11k_mhi_stop(ab_pci); 6075b32b6ddSManikanta Pubbisetty clear_bit(ATH11K_FLAG_DEVICE_INIT_DONE, &ab->dev_flags); 608babb0cedSCarl Huang ath11k_pci_sw_reset(ab_pci->ab, false); 6091399fb87SGovind Singh } 6101399fb87SGovind Singh 611fa5917e4SCarl Huang static int ath11k_pci_hif_suspend(struct ath11k_base *ab) 612fa5917e4SCarl Huang { 613fa5917e4SCarl Huang struct ath11k_pci *ar_pci = ath11k_pci_priv(ab); 614fa5917e4SCarl Huang 6153e80fcbcSKalle Valo return ath11k_mhi_suspend(ar_pci); 616fa5917e4SCarl Huang } 617fa5917e4SCarl Huang 618fa5917e4SCarl Huang static int ath11k_pci_hif_resume(struct ath11k_base *ab) 619fa5917e4SCarl Huang { 620fa5917e4SCarl Huang struct ath11k_pci *ar_pci = ath11k_pci_priv(ab); 621fa5917e4SCarl Huang 6223e80fcbcSKalle Valo return ath11k_mhi_resume(ar_pci); 623fa5917e4SCarl Huang } 624fa5917e4SCarl Huang 625d578ec2aSCarl Huang static void ath11k_pci_hif_ce_irq_enable(struct ath11k_base *ab) 626d578ec2aSCarl Huang { 627bbfdc5a7SManikanta Pubbisetty ath11k_pcic_ce_irqs_enable(ab); 628d578ec2aSCarl Huang } 629d578ec2aSCarl Huang 630d578ec2aSCarl Huang static void ath11k_pci_hif_ce_irq_disable(struct ath11k_base *ab) 631d578ec2aSCarl Huang { 632bbfdc5a7SManikanta Pubbisetty ath11k_pcic_ce_irq_disable_sync(ab); 6337f4beda2SGovind Singh } 6347f4beda2SGovind Singh 6355b32b6ddSManikanta Pubbisetty static int ath11k_pci_start(struct ath11k_base *ab) 6365b32b6ddSManikanta Pubbisetty { 6375b32b6ddSManikanta Pubbisetty struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 6385b32b6ddSManikanta Pubbisetty 6395b32b6ddSManikanta Pubbisetty /* TODO: for now don't restore ASPM in case of single MSI 6405b32b6ddSManikanta Pubbisetty * vector as MHI register reading in M2 causes system hang. 6415b32b6ddSManikanta Pubbisetty */ 6425b32b6ddSManikanta Pubbisetty if (test_bit(ATH11K_FLAG_MULTI_MSI_VECTORS, &ab->dev_flags)) 6435b32b6ddSManikanta Pubbisetty ath11k_pci_aspm_restore(ab_pci); 6445b32b6ddSManikanta Pubbisetty else 6455b32b6ddSManikanta Pubbisetty ath11k_info(ab, "leaving PCI ASPM disabled to avoid MHI M2 problems\n"); 6465b32b6ddSManikanta Pubbisetty 6475b32b6ddSManikanta Pubbisetty ath11k_pcic_start(ab); 6485b32b6ddSManikanta Pubbisetty 6495b32b6ddSManikanta Pubbisetty return 0; 6505b32b6ddSManikanta Pubbisetty } 6515b32b6ddSManikanta Pubbisetty 6527f4beda2SGovind Singh static const struct ath11k_hif_ops ath11k_pci_hif_ops = { 6535b32b6ddSManikanta Pubbisetty .start = ath11k_pci_start, 654bbfdc5a7SManikanta Pubbisetty .stop = ath11k_pcic_stop, 655bbfdc5a7SManikanta Pubbisetty .read32 = ath11k_pcic_read32, 656bbfdc5a7SManikanta Pubbisetty .write32 = ath11k_pcic_write32, 6571399fb87SGovind Singh .power_down = ath11k_pci_power_down, 6581399fb87SGovind Singh .power_up = ath11k_pci_power_up, 659fa5917e4SCarl Huang .suspend = ath11k_pci_hif_suspend, 660fa5917e4SCarl Huang .resume = ath11k_pci_hif_resume, 661bbfdc5a7SManikanta Pubbisetty .irq_enable = ath11k_pcic_ext_irq_enable, 662bbfdc5a7SManikanta Pubbisetty .irq_disable = ath11k_pcic_ext_irq_disable, 663bbfdc5a7SManikanta Pubbisetty .get_msi_address = ath11k_pcic_get_msi_address, 6640cfaf224SManikanta Pubbisetty .get_user_msi_vector = ath11k_pcic_get_user_msi_assignment, 665bbfdc5a7SManikanta Pubbisetty .map_service_to_pipe = ath11k_pcic_map_service_to_pipe, 666d578ec2aSCarl Huang .ce_irq_enable = ath11k_pci_hif_ce_irq_enable, 667d578ec2aSCarl Huang .ce_irq_disable = ath11k_pci_hif_ce_irq_disable, 668bbfdc5a7SManikanta Pubbisetty .get_ce_msi_idx = ath11k_pcic_get_ce_msi_idx, 6691399fb87SGovind Singh }; 6701399fb87SGovind Singh 6710fbf1957SBaochen Qiang static void ath11k_pci_read_hw_version(struct ath11k_base *ab, u32 *major, u32 *minor) 6720fbf1957SBaochen Qiang { 6730fbf1957SBaochen Qiang u32 soc_hw_version; 6740fbf1957SBaochen Qiang 675bbfdc5a7SManikanta Pubbisetty soc_hw_version = ath11k_pcic_read32(ab, TCSR_SOC_HW_VERSION); 6760fbf1957SBaochen Qiang *major = FIELD_GET(TCSR_SOC_HW_VERSION_MAJOR_MASK, 6770fbf1957SBaochen Qiang soc_hw_version); 6780fbf1957SBaochen Qiang *minor = FIELD_GET(TCSR_SOC_HW_VERSION_MINOR_MASK, 6790fbf1957SBaochen Qiang soc_hw_version); 6800fbf1957SBaochen Qiang 6810fbf1957SBaochen Qiang ath11k_dbg(ab, ATH11K_DBG_PCI, "pci tcsr_soc_hw_version major %d minor %d\n", 6820fbf1957SBaochen Qiang *major, *minor); 6830fbf1957SBaochen Qiang } 6840fbf1957SBaochen Qiang 6855b32b6ddSManikanta Pubbisetty static int ath11k_pci_set_irq_affinity_hint(struct ath11k_pci *ab_pci, 6865b32b6ddSManikanta Pubbisetty const struct cpumask *m) 6875b32b6ddSManikanta Pubbisetty { 6885b32b6ddSManikanta Pubbisetty if (test_bit(ATH11K_FLAG_MULTI_MSI_VECTORS, &ab_pci->ab->dev_flags)) 6895b32b6ddSManikanta Pubbisetty return 0; 6905b32b6ddSManikanta Pubbisetty 6915b32b6ddSManikanta Pubbisetty return irq_set_affinity_hint(ab_pci->pdev->irq, m); 6925b32b6ddSManikanta Pubbisetty } 6935b32b6ddSManikanta Pubbisetty 6946e0355afSGovind Singh static int ath11k_pci_probe(struct pci_dev *pdev, 6956e0355afSGovind Singh const struct pci_device_id *pci_dev) 6966e0355afSGovind Singh { 6976e0355afSGovind Singh struct ath11k_base *ab; 6985762613eSGovind Singh struct ath11k_pci *ab_pci; 6996ac04bdcSAnilkumar Kolli u32 soc_hw_version_major, soc_hw_version_minor, addr; 7005762613eSGovind Singh int ret; 7016e0355afSGovind Singh 702*92c1858eSManikanta Pubbisetty ab = ath11k_core_alloc(&pdev->dev, sizeof(*ab_pci), ATH11K_BUS_PCI); 703*92c1858eSManikanta Pubbisetty 7046e0355afSGovind Singh if (!ab) { 7056e0355afSGovind Singh dev_err(&pdev->dev, "failed to allocate ath11k base\n"); 7066e0355afSGovind Singh return -ENOMEM; 7076e0355afSGovind Singh } 7086e0355afSGovind Singh 7096e0355afSGovind Singh ab->dev = &pdev->dev; 7106e0355afSGovind Singh pci_set_drvdata(pdev, ab); 7115762613eSGovind Singh ab_pci = ath11k_pci_priv(ab); 7125762613eSGovind Singh ab_pci->dev_id = pci_dev->device; 7135762613eSGovind Singh ab_pci->ab = ab; 7145697a564SGovind Singh ab_pci->pdev = pdev; 7157f4beda2SGovind Singh ab->hif.ops = &ath11k_pci_hif_ops; 7165762613eSGovind Singh pci_set_drvdata(pdev, ab); 717654e959aSGovind Singh spin_lock_init(&ab_pci->window_lock); 7185762613eSGovind Singh 7196ac04bdcSAnilkumar Kolli /* Set fixed_mem_region to true for platforms support reserved memory 7206ac04bdcSAnilkumar Kolli * from DT. If memory is reserved from DT for FW, ath11k driver need not 7216ac04bdcSAnilkumar Kolli * allocate memory. 7226ac04bdcSAnilkumar Kolli */ 7236ac04bdcSAnilkumar Kolli ret = of_property_read_u32(ab->dev->of_node, "memory-region", &addr); 7246ac04bdcSAnilkumar Kolli if (!ret) 7256ac04bdcSAnilkumar Kolli set_bit(ATH11K_FLAG_FIXED_MEM_RGN, &ab->dev_flags); 7266ac04bdcSAnilkumar Kolli 7275762613eSGovind Singh ret = ath11k_pci_claim(ab_pci, pdev); 7285762613eSGovind Singh if (ret) { 7295762613eSGovind Singh ath11k_err(ab, "failed to claim device: %d\n", ret); 7305762613eSGovind Singh goto err_free_core; 7315762613eSGovind Singh } 7326e0355afSGovind Singh 733fc95d10aSWen Gong ath11k_dbg(ab, ATH11K_DBG_BOOT, "pci probe %04x:%04x %04x:%04x\n", 734fc95d10aSWen Gong pdev->vendor, pdev->device, 735fc95d10aSWen Gong pdev->subsystem_vendor, pdev->subsystem_device); 736fc95d10aSWen Gong 737fc95d10aSWen Gong ab->id.vendor = pdev->vendor; 738fc95d10aSWen Gong ab->id.device = pdev->device; 739fc95d10aSWen Gong ab->id.subsystem_vendor = pdev->subsystem_vendor; 740fc95d10aSWen Gong ab->id.subsystem_device = pdev->subsystem_device; 741fc95d10aSWen Gong 74218ac1665SKalle Valo switch (pci_dev->device) { 74318ac1665SKalle Valo case QCA6390_DEVICE_ID: 7440fbf1957SBaochen Qiang ath11k_pci_read_hw_version(ab, &soc_hw_version_major, 7450fbf1957SBaochen Qiang &soc_hw_version_minor); 74618ac1665SKalle Valo switch (soc_hw_version_major) { 74718ac1665SKalle Valo case 2: 74818ac1665SKalle Valo ab->hw_rev = ATH11K_HW_QCA6390_HW20; 74918ac1665SKalle Valo break; 75018ac1665SKalle Valo default: 75118ac1665SKalle Valo dev_err(&pdev->dev, "Unsupported QCA6390 SOC hardware version: %d %d\n", 75218ac1665SKalle Valo soc_hw_version_major, soc_hw_version_minor); 75318ac1665SKalle Valo ret = -EOPNOTSUPP; 75418ac1665SKalle Valo goto err_pci_free_region; 75518ac1665SKalle Valo } 7565b32b6ddSManikanta Pubbisetty 7575b32b6ddSManikanta Pubbisetty ab->pci.ops = &ath11k_pci_ops_qca6390; 7584e809461SAnilkumar Kolli break; 7594e809461SAnilkumar Kolli case QCN9074_DEVICE_ID: 7605b32b6ddSManikanta Pubbisetty ab->pci.ops = &ath11k_pci_ops_qcn9074; 7614e809461SAnilkumar Kolli ab->hw_rev = ATH11K_HW_QCN9074_HW10; 76218ac1665SKalle Valo break; 7630fbf1957SBaochen Qiang case WCN6855_DEVICE_ID: 764fc95d10aSWen Gong ab->id.bdf_search = ATH11K_BDF_SEARCH_BUS_AND_BOARD; 7650fbf1957SBaochen Qiang ath11k_pci_read_hw_version(ab, &soc_hw_version_major, 7660fbf1957SBaochen Qiang &soc_hw_version_minor); 7670fbf1957SBaochen Qiang switch (soc_hw_version_major) { 7680fbf1957SBaochen Qiang case 2: 769d1147a31SBaochen Qiang switch (soc_hw_version_minor) { 770d1147a31SBaochen Qiang case 0x00: 771d1147a31SBaochen Qiang case 0x01: 7720fbf1957SBaochen Qiang ab->hw_rev = ATH11K_HW_WCN6855_HW20; 7730fbf1957SBaochen Qiang break; 774d1147a31SBaochen Qiang case 0x10: 775d1147a31SBaochen Qiang case 0x11: 776d1147a31SBaochen Qiang ab->hw_rev = ATH11K_HW_WCN6855_HW21; 777d1147a31SBaochen Qiang break; 7780fbf1957SBaochen Qiang default: 779d1147a31SBaochen Qiang goto unsupported_wcn6855_soc; 780d1147a31SBaochen Qiang } 781d1147a31SBaochen Qiang break; 782d1147a31SBaochen Qiang default: 783d1147a31SBaochen Qiang unsupported_wcn6855_soc: 7840fbf1957SBaochen Qiang dev_err(&pdev->dev, "Unsupported WCN6855 SOC hardware version: %d %d\n", 7850fbf1957SBaochen Qiang soc_hw_version_major, soc_hw_version_minor); 7860fbf1957SBaochen Qiang ret = -EOPNOTSUPP; 7870fbf1957SBaochen Qiang goto err_pci_free_region; 7880fbf1957SBaochen Qiang } 7895b32b6ddSManikanta Pubbisetty 7905b32b6ddSManikanta Pubbisetty ab->pci.ops = &ath11k_pci_ops_qca6390; 7910fbf1957SBaochen Qiang break; 79218ac1665SKalle Valo default: 79318ac1665SKalle Valo dev_err(&pdev->dev, "Unknown PCI device found: 0x%x\n", 79418ac1665SKalle Valo pci_dev->device); 79518ac1665SKalle Valo ret = -EOPNOTSUPP; 79618ac1665SKalle Valo goto err_pci_free_region; 79718ac1665SKalle Valo } 79818ac1665SKalle Valo 7998d06b802SManikanta Pubbisetty ret = ath11k_pcic_init_msi_config(ab); 8008d06b802SManikanta Pubbisetty if (ret) { 8018d06b802SManikanta Pubbisetty ath11k_err(ab, "failed to init msi config: %d\n", ret); 8028d06b802SManikanta Pubbisetty goto err_pci_free_region; 8038d06b802SManikanta Pubbisetty } 8048d06b802SManikanta Pubbisetty 80596527d52SBaochen Qiang ret = ath11k_pci_alloc_msi(ab_pci); 8065697a564SGovind Singh if (ret) { 8075697a564SGovind Singh ath11k_err(ab, "failed to enable msi: %d\n", ret); 8085697a564SGovind Singh goto err_pci_free_region; 8095697a564SGovind Singh } 8105697a564SGovind Singh 811b8246f88SKalle Valo ret = ath11k_core_pre_init(ab); 812b8246f88SKalle Valo if (ret) 813b8246f88SKalle Valo goto err_pci_disable_msi; 814b8246f88SKalle Valo 8151399fb87SGovind Singh ret = ath11k_mhi_register(ab_pci); 8161399fb87SGovind Singh if (ret) { 8171399fb87SGovind Singh ath11k_err(ab, "failed to register mhi: %d\n", ret); 8181399fb87SGovind Singh goto err_pci_disable_msi; 8191399fb87SGovind Singh } 8201399fb87SGovind Singh 8217f4beda2SGovind Singh ret = ath11k_hal_srng_init(ab); 8227f4beda2SGovind Singh if (ret) 8237f4beda2SGovind Singh goto err_mhi_unregister; 8247f4beda2SGovind Singh 8257f4beda2SGovind Singh ret = ath11k_ce_alloc_pipes(ab); 8267f4beda2SGovind Singh if (ret) { 8277f4beda2SGovind Singh ath11k_err(ab, "failed to allocate ce pipes: %d\n", ret); 8287f4beda2SGovind Singh goto err_hal_srng_deinit; 8297f4beda2SGovind Singh } 8307f4beda2SGovind Singh 8317f4beda2SGovind Singh ath11k_pci_init_qmi_ce_config(ab); 8327f4beda2SGovind Singh 833bbfdc5a7SManikanta Pubbisetty ret = ath11k_pcic_config_irq(ab); 8347f4beda2SGovind Singh if (ret) { 8357f4beda2SGovind Singh ath11k_err(ab, "failed to config irq: %d\n", ret); 8367f4beda2SGovind Singh goto err_ce_free; 8377f4beda2SGovind Singh } 8387f4beda2SGovind Singh 8395b32b6ddSManikanta Pubbisetty ret = ath11k_pci_set_irq_affinity_hint(ab_pci, cpumask_of(0)); 8405b32b6ddSManikanta Pubbisetty if (ret) { 8415b32b6ddSManikanta Pubbisetty ath11k_err(ab, "failed to set irq affinity %d\n", ret); 8425b32b6ddSManikanta Pubbisetty goto err_free_irq; 8435b32b6ddSManikanta Pubbisetty } 8445b32b6ddSManikanta Pubbisetty 84587b4072dSCarl Huang /* kernel may allocate a dummy vector before request_irq and 84687b4072dSCarl Huang * then allocate a real vector when request_irq is called. 84787b4072dSCarl Huang * So get msi_data here again to avoid spurious interrupt 84887b4072dSCarl Huang * as msi_data will configured to srngs. 84987b4072dSCarl Huang */ 85087b4072dSCarl Huang ret = ath11k_pci_config_msi_data(ab_pci); 85187b4072dSCarl Huang if (ret) { 85287b4072dSCarl Huang ath11k_err(ab, "failed to config msi_data: %d\n", ret); 8535b32b6ddSManikanta Pubbisetty goto err_irq_affinity_cleanup; 85487b4072dSCarl Huang } 85587b4072dSCarl Huang 8567f4beda2SGovind Singh ret = ath11k_core_init(ab); 8577f4beda2SGovind Singh if (ret) { 8587f4beda2SGovind Singh ath11k_err(ab, "failed to init core: %d\n", ret); 8595b32b6ddSManikanta Pubbisetty goto err_irq_affinity_cleanup; 8607f4beda2SGovind Singh } 8616e0355afSGovind Singh return 0; 8625762613eSGovind Singh 8635b32b6ddSManikanta Pubbisetty err_irq_affinity_cleanup: 8645b32b6ddSManikanta Pubbisetty ath11k_pci_set_irq_affinity_hint(ab_pci, NULL); 8655b32b6ddSManikanta Pubbisetty 8667f4beda2SGovind Singh err_free_irq: 867bbfdc5a7SManikanta Pubbisetty ath11k_pcic_free_irq(ab); 8687f4beda2SGovind Singh 8697f4beda2SGovind Singh err_ce_free: 8707f4beda2SGovind Singh ath11k_ce_free_pipes(ab); 8717f4beda2SGovind Singh 8727f4beda2SGovind Singh err_hal_srng_deinit: 8737f4beda2SGovind Singh ath11k_hal_srng_deinit(ab); 8747f4beda2SGovind Singh 8757f4beda2SGovind Singh err_mhi_unregister: 8767f4beda2SGovind Singh ath11k_mhi_unregister(ab_pci); 8777f4beda2SGovind Singh 878b8246f88SKalle Valo err_pci_disable_msi: 87996527d52SBaochen Qiang ath11k_pci_free_msi(ab_pci); 880b8246f88SKalle Valo 8815697a564SGovind Singh err_pci_free_region: 8825697a564SGovind Singh ath11k_pci_free_region(ab_pci); 8835697a564SGovind Singh 8845762613eSGovind Singh err_free_core: 8855762613eSGovind Singh ath11k_core_free(ab); 8865697a564SGovind Singh 8875762613eSGovind Singh return ret; 8886e0355afSGovind Singh } 8896e0355afSGovind Singh 8906e0355afSGovind Singh static void ath11k_pci_remove(struct pci_dev *pdev) 8916e0355afSGovind Singh { 8926e0355afSGovind Singh struct ath11k_base *ab = pci_get_drvdata(pdev); 8935762613eSGovind Singh struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 8946e0355afSGovind Singh 8955b32b6ddSManikanta Pubbisetty ath11k_pci_set_irq_affinity_hint(ab_pci, NULL); 896e94b0749SBaochen Qiang 89761a57e51SAnilkumar Kolli if (test_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags)) { 89861a57e51SAnilkumar Kolli ath11k_pci_power_down(ab); 89961a57e51SAnilkumar Kolli ath11k_debugfs_soc_destroy(ab); 90061a57e51SAnilkumar Kolli ath11k_qmi_deinit_service(ab); 90161a57e51SAnilkumar Kolli goto qmi_fail; 90261a57e51SAnilkumar Kolli } 90361a57e51SAnilkumar Kolli 9046e0355afSGovind Singh set_bit(ATH11K_FLAG_UNREGISTERING, &ab->dev_flags); 9056fbd8898SCarl Huang 9066fbd8898SCarl Huang ath11k_core_deinit(ab); 9076fbd8898SCarl Huang 90861a57e51SAnilkumar Kolli qmi_fail: 9091399fb87SGovind Singh ath11k_mhi_unregister(ab_pci); 9106fbd8898SCarl Huang 911bbfdc5a7SManikanta Pubbisetty ath11k_pcic_free_irq(ab); 91296527d52SBaochen Qiang ath11k_pci_free_msi(ab_pci); 9135762613eSGovind Singh ath11k_pci_free_region(ab_pci); 9146fbd8898SCarl Huang 9156fbd8898SCarl Huang ath11k_hal_srng_deinit(ab); 9166fbd8898SCarl Huang ath11k_ce_free_pipes(ab); 9176e0355afSGovind Singh ath11k_core_free(ab); 9186e0355afSGovind Singh } 9196e0355afSGovind Singh 9201399fb87SGovind Singh static void ath11k_pci_shutdown(struct pci_dev *pdev) 9211399fb87SGovind Singh { 9221399fb87SGovind Singh struct ath11k_base *ab = pci_get_drvdata(pdev); 9231399fb87SGovind Singh 9241399fb87SGovind Singh ath11k_pci_power_down(ab); 9251399fb87SGovind Singh } 9261399fb87SGovind Singh 927d1b0c338SCarl Huang static __maybe_unused int ath11k_pci_pm_suspend(struct device *dev) 928d1b0c338SCarl Huang { 929d1b0c338SCarl Huang struct ath11k_base *ab = dev_get_drvdata(dev); 930d1b0c338SCarl Huang int ret; 931d1b0c338SCarl Huang 932b4f4c564SKalle Valo if (test_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags)) { 933b4f4c564SKalle Valo ath11k_dbg(ab, ATH11K_DBG_BOOT, "boot skipping pci suspend as qmi is not initialised\n"); 934b4f4c564SKalle Valo return 0; 935b4f4c564SKalle Valo } 936b4f4c564SKalle Valo 937d1b0c338SCarl Huang ret = ath11k_core_suspend(ab); 938d1b0c338SCarl Huang if (ret) 939d1b0c338SCarl Huang ath11k_warn(ab, "failed to suspend core: %d\n", ret); 940d1b0c338SCarl Huang 941d1b0c338SCarl Huang return ret; 942d1b0c338SCarl Huang } 943d1b0c338SCarl Huang 944d1b0c338SCarl Huang static __maybe_unused int ath11k_pci_pm_resume(struct device *dev) 945d1b0c338SCarl Huang { 946d1b0c338SCarl Huang struct ath11k_base *ab = dev_get_drvdata(dev); 947d1b0c338SCarl Huang int ret; 948d1b0c338SCarl Huang 949b4f4c564SKalle Valo if (test_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags)) { 950b4f4c564SKalle Valo ath11k_dbg(ab, ATH11K_DBG_BOOT, "boot skipping pci resume as qmi is not initialised\n"); 951b4f4c564SKalle Valo return 0; 952b4f4c564SKalle Valo } 953b4f4c564SKalle Valo 954d1b0c338SCarl Huang ret = ath11k_core_resume(ab); 955d1b0c338SCarl Huang if (ret) 956d1b0c338SCarl Huang ath11k_warn(ab, "failed to resume core: %d\n", ret); 957d1b0c338SCarl Huang 958d1b0c338SCarl Huang return ret; 959d1b0c338SCarl Huang } 960d1b0c338SCarl Huang 961d1b0c338SCarl Huang static SIMPLE_DEV_PM_OPS(ath11k_pci_pm_ops, 962d1b0c338SCarl Huang ath11k_pci_pm_suspend, 963d1b0c338SCarl Huang ath11k_pci_pm_resume); 964d1b0c338SCarl Huang 9656e0355afSGovind Singh static struct pci_driver ath11k_pci_driver = { 9666e0355afSGovind Singh .name = "ath11k_pci", 9676e0355afSGovind Singh .id_table = ath11k_pci_id_table, 9686e0355afSGovind Singh .probe = ath11k_pci_probe, 9696e0355afSGovind Singh .remove = ath11k_pci_remove, 9701399fb87SGovind Singh .shutdown = ath11k_pci_shutdown, 971d1b0c338SCarl Huang #ifdef CONFIG_PM 972d1b0c338SCarl Huang .driver.pm = &ath11k_pci_pm_ops, 973d1b0c338SCarl Huang #endif 9746e0355afSGovind Singh }; 9756e0355afSGovind Singh 9766e0355afSGovind Singh static int ath11k_pci_init(void) 9776e0355afSGovind Singh { 9786e0355afSGovind Singh int ret; 9796e0355afSGovind Singh 9806e0355afSGovind Singh ret = pci_register_driver(&ath11k_pci_driver); 9816e0355afSGovind Singh if (ret) 9826e0355afSGovind Singh pr_err("failed to register ath11k pci driver: %d\n", 9836e0355afSGovind Singh ret); 9846e0355afSGovind Singh 9856e0355afSGovind Singh return ret; 9866e0355afSGovind Singh } 9876e0355afSGovind Singh module_init(ath11k_pci_init); 9886e0355afSGovind Singh 9896e0355afSGovind Singh static void ath11k_pci_exit(void) 9906e0355afSGovind Singh { 9916e0355afSGovind Singh pci_unregister_driver(&ath11k_pci_driver); 9926e0355afSGovind Singh } 9936e0355afSGovind Singh 9946e0355afSGovind Singh module_exit(ath11k_pci_exit); 9956e0355afSGovind Singh 9966e0355afSGovind Singh MODULE_DESCRIPTION("Driver support for Qualcomm Technologies 802.11ax WLAN PCIe devices"); 9976e0355afSGovind Singh MODULE_LICENSE("Dual BSD/GPL"); 9983dbd7fe7SDevin Bayer 9993dbd7fe7SDevin Bayer /* QCA639x 2.0 firmware files */ 10003dbd7fe7SDevin Bayer MODULE_FIRMWARE(ATH11K_FW_DIR "/QCA6390/hw2.0/" ATH11K_BOARD_API2_FILE); 10013dbd7fe7SDevin Bayer MODULE_FIRMWARE(ATH11K_FW_DIR "/QCA6390/hw2.0/" ATH11K_AMSS_FILE); 10023dbd7fe7SDevin Bayer MODULE_FIRMWARE(ATH11K_FW_DIR "/QCA6390/hw2.0/" ATH11K_M3_FILE); 1003