162306a36Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause-Clear 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 2020-2021 The Linux Foundation. All rights reserved. 462306a36Sopenharmony_ci * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/msi.h> 862306a36Sopenharmony_ci#include <linux/pci.h> 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include "core.h" 1162306a36Sopenharmony_ci#include "debug.h" 1262306a36Sopenharmony_ci#include "mhi.h" 1362306a36Sopenharmony_ci#include "pci.h" 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#define MHI_TIMEOUT_DEFAULT_MS 90000 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_cistatic const struct mhi_channel_config ath12k_mhi_channels_qcn9274[] = { 1862306a36Sopenharmony_ci { 1962306a36Sopenharmony_ci .num = 0, 2062306a36Sopenharmony_ci .name = "LOOPBACK", 2162306a36Sopenharmony_ci .num_elements = 32, 2262306a36Sopenharmony_ci .event_ring = 1, 2362306a36Sopenharmony_ci .dir = DMA_TO_DEVICE, 2462306a36Sopenharmony_ci .ee_mask = 0x4, 2562306a36Sopenharmony_ci .pollcfg = 0, 2662306a36Sopenharmony_ci .doorbell = MHI_DB_BRST_DISABLE, 2762306a36Sopenharmony_ci .lpm_notify = false, 2862306a36Sopenharmony_ci .offload_channel = false, 2962306a36Sopenharmony_ci .doorbell_mode_switch = false, 3062306a36Sopenharmony_ci .auto_queue = false, 3162306a36Sopenharmony_ci }, 3262306a36Sopenharmony_ci { 3362306a36Sopenharmony_ci .num = 1, 3462306a36Sopenharmony_ci .name = "LOOPBACK", 3562306a36Sopenharmony_ci .num_elements = 32, 3662306a36Sopenharmony_ci .event_ring = 1, 3762306a36Sopenharmony_ci .dir = DMA_FROM_DEVICE, 3862306a36Sopenharmony_ci .ee_mask = 0x4, 3962306a36Sopenharmony_ci .pollcfg = 0, 4062306a36Sopenharmony_ci .doorbell = MHI_DB_BRST_DISABLE, 4162306a36Sopenharmony_ci .lpm_notify = false, 4262306a36Sopenharmony_ci .offload_channel = false, 4362306a36Sopenharmony_ci .doorbell_mode_switch = false, 4462306a36Sopenharmony_ci .auto_queue = false, 4562306a36Sopenharmony_ci }, 4662306a36Sopenharmony_ci { 4762306a36Sopenharmony_ci .num = 20, 4862306a36Sopenharmony_ci .name = "IPCR", 4962306a36Sopenharmony_ci .num_elements = 32, 5062306a36Sopenharmony_ci .event_ring = 1, 5162306a36Sopenharmony_ci .dir = DMA_TO_DEVICE, 5262306a36Sopenharmony_ci .ee_mask = 0x4, 5362306a36Sopenharmony_ci .pollcfg = 0, 5462306a36Sopenharmony_ci .doorbell = MHI_DB_BRST_DISABLE, 5562306a36Sopenharmony_ci .lpm_notify = false, 5662306a36Sopenharmony_ci .offload_channel = false, 5762306a36Sopenharmony_ci .doorbell_mode_switch = false, 5862306a36Sopenharmony_ci .auto_queue = false, 5962306a36Sopenharmony_ci }, 6062306a36Sopenharmony_ci { 6162306a36Sopenharmony_ci .num = 21, 6262306a36Sopenharmony_ci .name = "IPCR", 6362306a36Sopenharmony_ci .num_elements = 32, 6462306a36Sopenharmony_ci .event_ring = 1, 6562306a36Sopenharmony_ci .dir = DMA_FROM_DEVICE, 6662306a36Sopenharmony_ci .ee_mask = 0x4, 6762306a36Sopenharmony_ci .pollcfg = 0, 6862306a36Sopenharmony_ci .doorbell = MHI_DB_BRST_DISABLE, 6962306a36Sopenharmony_ci .lpm_notify = false, 7062306a36Sopenharmony_ci .offload_channel = false, 7162306a36Sopenharmony_ci .doorbell_mode_switch = false, 7262306a36Sopenharmony_ci .auto_queue = true, 7362306a36Sopenharmony_ci }, 7462306a36Sopenharmony_ci}; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_cistatic struct mhi_event_config ath12k_mhi_events_qcn9274[] = { 7762306a36Sopenharmony_ci { 7862306a36Sopenharmony_ci .num_elements = 32, 7962306a36Sopenharmony_ci .irq_moderation_ms = 0, 8062306a36Sopenharmony_ci .irq = 1, 8162306a36Sopenharmony_ci .data_type = MHI_ER_CTRL, 8262306a36Sopenharmony_ci .mode = MHI_DB_BRST_DISABLE, 8362306a36Sopenharmony_ci .hardware_event = false, 8462306a36Sopenharmony_ci .client_managed = false, 8562306a36Sopenharmony_ci .offload_channel = false, 8662306a36Sopenharmony_ci }, 8762306a36Sopenharmony_ci { 8862306a36Sopenharmony_ci .num_elements = 256, 8962306a36Sopenharmony_ci .irq_moderation_ms = 1, 9062306a36Sopenharmony_ci .irq = 2, 9162306a36Sopenharmony_ci .mode = MHI_DB_BRST_DISABLE, 9262306a36Sopenharmony_ci .priority = 1, 9362306a36Sopenharmony_ci .hardware_event = false, 9462306a36Sopenharmony_ci .client_managed = false, 9562306a36Sopenharmony_ci .offload_channel = false, 9662306a36Sopenharmony_ci }, 9762306a36Sopenharmony_ci}; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ciconst struct mhi_controller_config ath12k_mhi_config_qcn9274 = { 10062306a36Sopenharmony_ci .max_channels = 30, 10162306a36Sopenharmony_ci .timeout_ms = 10000, 10262306a36Sopenharmony_ci .use_bounce_buf = false, 10362306a36Sopenharmony_ci .buf_len = 0, 10462306a36Sopenharmony_ci .num_channels = ARRAY_SIZE(ath12k_mhi_channels_qcn9274), 10562306a36Sopenharmony_ci .ch_cfg = ath12k_mhi_channels_qcn9274, 10662306a36Sopenharmony_ci .num_events = ARRAY_SIZE(ath12k_mhi_events_qcn9274), 10762306a36Sopenharmony_ci .event_cfg = ath12k_mhi_events_qcn9274, 10862306a36Sopenharmony_ci}; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_cistatic const struct mhi_channel_config ath12k_mhi_channels_wcn7850[] = { 11162306a36Sopenharmony_ci { 11262306a36Sopenharmony_ci .num = 0, 11362306a36Sopenharmony_ci .name = "LOOPBACK", 11462306a36Sopenharmony_ci .num_elements = 32, 11562306a36Sopenharmony_ci .event_ring = 0, 11662306a36Sopenharmony_ci .dir = DMA_TO_DEVICE, 11762306a36Sopenharmony_ci .ee_mask = 0x4, 11862306a36Sopenharmony_ci .pollcfg = 0, 11962306a36Sopenharmony_ci .doorbell = MHI_DB_BRST_DISABLE, 12062306a36Sopenharmony_ci .lpm_notify = false, 12162306a36Sopenharmony_ci .offload_channel = false, 12262306a36Sopenharmony_ci .doorbell_mode_switch = false, 12362306a36Sopenharmony_ci .auto_queue = false, 12462306a36Sopenharmony_ci }, 12562306a36Sopenharmony_ci { 12662306a36Sopenharmony_ci .num = 1, 12762306a36Sopenharmony_ci .name = "LOOPBACK", 12862306a36Sopenharmony_ci .num_elements = 32, 12962306a36Sopenharmony_ci .event_ring = 0, 13062306a36Sopenharmony_ci .dir = DMA_FROM_DEVICE, 13162306a36Sopenharmony_ci .ee_mask = 0x4, 13262306a36Sopenharmony_ci .pollcfg = 0, 13362306a36Sopenharmony_ci .doorbell = MHI_DB_BRST_DISABLE, 13462306a36Sopenharmony_ci .lpm_notify = false, 13562306a36Sopenharmony_ci .offload_channel = false, 13662306a36Sopenharmony_ci .doorbell_mode_switch = false, 13762306a36Sopenharmony_ci .auto_queue = false, 13862306a36Sopenharmony_ci }, 13962306a36Sopenharmony_ci { 14062306a36Sopenharmony_ci .num = 20, 14162306a36Sopenharmony_ci .name = "IPCR", 14262306a36Sopenharmony_ci .num_elements = 64, 14362306a36Sopenharmony_ci .event_ring = 1, 14462306a36Sopenharmony_ci .dir = DMA_TO_DEVICE, 14562306a36Sopenharmony_ci .ee_mask = 0x4, 14662306a36Sopenharmony_ci .pollcfg = 0, 14762306a36Sopenharmony_ci .doorbell = MHI_DB_BRST_DISABLE, 14862306a36Sopenharmony_ci .lpm_notify = false, 14962306a36Sopenharmony_ci .offload_channel = false, 15062306a36Sopenharmony_ci .doorbell_mode_switch = false, 15162306a36Sopenharmony_ci .auto_queue = false, 15262306a36Sopenharmony_ci }, 15362306a36Sopenharmony_ci { 15462306a36Sopenharmony_ci .num = 21, 15562306a36Sopenharmony_ci .name = "IPCR", 15662306a36Sopenharmony_ci .num_elements = 64, 15762306a36Sopenharmony_ci .event_ring = 1, 15862306a36Sopenharmony_ci .dir = DMA_FROM_DEVICE, 15962306a36Sopenharmony_ci .ee_mask = 0x4, 16062306a36Sopenharmony_ci .pollcfg = 0, 16162306a36Sopenharmony_ci .doorbell = MHI_DB_BRST_DISABLE, 16262306a36Sopenharmony_ci .lpm_notify = false, 16362306a36Sopenharmony_ci .offload_channel = false, 16462306a36Sopenharmony_ci .doorbell_mode_switch = false, 16562306a36Sopenharmony_ci .auto_queue = true, 16662306a36Sopenharmony_ci }, 16762306a36Sopenharmony_ci}; 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_cistatic struct mhi_event_config ath12k_mhi_events_wcn7850[] = { 17062306a36Sopenharmony_ci { 17162306a36Sopenharmony_ci .num_elements = 32, 17262306a36Sopenharmony_ci .irq_moderation_ms = 0, 17362306a36Sopenharmony_ci .irq = 1, 17462306a36Sopenharmony_ci .mode = MHI_DB_BRST_DISABLE, 17562306a36Sopenharmony_ci .data_type = MHI_ER_CTRL, 17662306a36Sopenharmony_ci .hardware_event = false, 17762306a36Sopenharmony_ci .client_managed = false, 17862306a36Sopenharmony_ci .offload_channel = false, 17962306a36Sopenharmony_ci }, 18062306a36Sopenharmony_ci { 18162306a36Sopenharmony_ci .num_elements = 256, 18262306a36Sopenharmony_ci .irq_moderation_ms = 1, 18362306a36Sopenharmony_ci .irq = 2, 18462306a36Sopenharmony_ci .mode = MHI_DB_BRST_DISABLE, 18562306a36Sopenharmony_ci .priority = 1, 18662306a36Sopenharmony_ci .hardware_event = false, 18762306a36Sopenharmony_ci .client_managed = false, 18862306a36Sopenharmony_ci .offload_channel = false, 18962306a36Sopenharmony_ci }, 19062306a36Sopenharmony_ci}; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ciconst struct mhi_controller_config ath12k_mhi_config_wcn7850 = { 19362306a36Sopenharmony_ci .max_channels = 128, 19462306a36Sopenharmony_ci .timeout_ms = 2000, 19562306a36Sopenharmony_ci .use_bounce_buf = false, 19662306a36Sopenharmony_ci .buf_len = 0, 19762306a36Sopenharmony_ci .num_channels = ARRAY_SIZE(ath12k_mhi_channels_wcn7850), 19862306a36Sopenharmony_ci .ch_cfg = ath12k_mhi_channels_wcn7850, 19962306a36Sopenharmony_ci .num_events = ARRAY_SIZE(ath12k_mhi_events_wcn7850), 20062306a36Sopenharmony_ci .event_cfg = ath12k_mhi_events_wcn7850, 20162306a36Sopenharmony_ci}; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_civoid ath12k_mhi_set_mhictrl_reset(struct ath12k_base *ab) 20462306a36Sopenharmony_ci{ 20562306a36Sopenharmony_ci u32 val; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci val = ath12k_pci_read32(ab, MHISTATUS); 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci ath12k_dbg(ab, ATH12K_DBG_PCI, "MHISTATUS 0x%x\n", val); 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci /* Observed on some targets that after SOC_GLOBAL_RESET, MHISTATUS 21262306a36Sopenharmony_ci * has SYSERR bit set and thus need to set MHICTRL_RESET 21362306a36Sopenharmony_ci * to clear SYSERR. 21462306a36Sopenharmony_ci */ 21562306a36Sopenharmony_ci ath12k_pci_write32(ab, MHICTRL, MHICTRL_RESET_MASK); 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci mdelay(10); 21862306a36Sopenharmony_ci} 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_cistatic void ath12k_mhi_reset_txvecdb(struct ath12k_base *ab) 22162306a36Sopenharmony_ci{ 22262306a36Sopenharmony_ci ath12k_pci_write32(ab, PCIE_TXVECDB, 0); 22362306a36Sopenharmony_ci} 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_cistatic void ath12k_mhi_reset_txvecstatus(struct ath12k_base *ab) 22662306a36Sopenharmony_ci{ 22762306a36Sopenharmony_ci ath12k_pci_write32(ab, PCIE_TXVECSTATUS, 0); 22862306a36Sopenharmony_ci} 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_cistatic void ath12k_mhi_reset_rxvecdb(struct ath12k_base *ab) 23162306a36Sopenharmony_ci{ 23262306a36Sopenharmony_ci ath12k_pci_write32(ab, PCIE_RXVECDB, 0); 23362306a36Sopenharmony_ci} 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_cistatic void ath12k_mhi_reset_rxvecstatus(struct ath12k_base *ab) 23662306a36Sopenharmony_ci{ 23762306a36Sopenharmony_ci ath12k_pci_write32(ab, PCIE_RXVECSTATUS, 0); 23862306a36Sopenharmony_ci} 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_civoid ath12k_mhi_clear_vector(struct ath12k_base *ab) 24162306a36Sopenharmony_ci{ 24262306a36Sopenharmony_ci ath12k_mhi_reset_txvecdb(ab); 24362306a36Sopenharmony_ci ath12k_mhi_reset_txvecstatus(ab); 24462306a36Sopenharmony_ci ath12k_mhi_reset_rxvecdb(ab); 24562306a36Sopenharmony_ci ath12k_mhi_reset_rxvecstatus(ab); 24662306a36Sopenharmony_ci} 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_cistatic int ath12k_mhi_get_msi(struct ath12k_pci *ab_pci) 24962306a36Sopenharmony_ci{ 25062306a36Sopenharmony_ci struct ath12k_base *ab = ab_pci->ab; 25162306a36Sopenharmony_ci u32 user_base_data, base_vector; 25262306a36Sopenharmony_ci int ret, num_vectors, i; 25362306a36Sopenharmony_ci int *irq; 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci ret = ath12k_pci_get_user_msi_assignment(ab, 25662306a36Sopenharmony_ci "MHI", &num_vectors, 25762306a36Sopenharmony_ci &user_base_data, &base_vector); 25862306a36Sopenharmony_ci if (ret) 25962306a36Sopenharmony_ci return ret; 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci ath12k_dbg(ab, ATH12K_DBG_PCI, "Number of assigned MSI for MHI is %d, base vector is %d\n", 26262306a36Sopenharmony_ci num_vectors, base_vector); 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci irq = kcalloc(num_vectors, sizeof(*irq), GFP_KERNEL); 26562306a36Sopenharmony_ci if (!irq) 26662306a36Sopenharmony_ci return -ENOMEM; 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci for (i = 0; i < num_vectors; i++) 26962306a36Sopenharmony_ci irq[i] = ath12k_pci_get_msi_irq(ab->dev, 27062306a36Sopenharmony_ci base_vector + i); 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci ab_pci->mhi_ctrl->irq = irq; 27362306a36Sopenharmony_ci ab_pci->mhi_ctrl->nr_irqs = num_vectors; 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci return 0; 27662306a36Sopenharmony_ci} 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_cistatic int ath12k_mhi_op_runtime_get(struct mhi_controller *mhi_cntrl) 27962306a36Sopenharmony_ci{ 28062306a36Sopenharmony_ci return 0; 28162306a36Sopenharmony_ci} 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_cistatic void ath12k_mhi_op_runtime_put(struct mhi_controller *mhi_cntrl) 28462306a36Sopenharmony_ci{ 28562306a36Sopenharmony_ci} 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_cistatic char *ath12k_mhi_op_callback_to_str(enum mhi_callback reason) 28862306a36Sopenharmony_ci{ 28962306a36Sopenharmony_ci switch (reason) { 29062306a36Sopenharmony_ci case MHI_CB_IDLE: 29162306a36Sopenharmony_ci return "MHI_CB_IDLE"; 29262306a36Sopenharmony_ci case MHI_CB_PENDING_DATA: 29362306a36Sopenharmony_ci return "MHI_CB_PENDING_DATA"; 29462306a36Sopenharmony_ci case MHI_CB_LPM_ENTER: 29562306a36Sopenharmony_ci return "MHI_CB_LPM_ENTER"; 29662306a36Sopenharmony_ci case MHI_CB_LPM_EXIT: 29762306a36Sopenharmony_ci return "MHI_CB_LPM_EXIT"; 29862306a36Sopenharmony_ci case MHI_CB_EE_RDDM: 29962306a36Sopenharmony_ci return "MHI_CB_EE_RDDM"; 30062306a36Sopenharmony_ci case MHI_CB_EE_MISSION_MODE: 30162306a36Sopenharmony_ci return "MHI_CB_EE_MISSION_MODE"; 30262306a36Sopenharmony_ci case MHI_CB_SYS_ERROR: 30362306a36Sopenharmony_ci return "MHI_CB_SYS_ERROR"; 30462306a36Sopenharmony_ci case MHI_CB_FATAL_ERROR: 30562306a36Sopenharmony_ci return "MHI_CB_FATAL_ERROR"; 30662306a36Sopenharmony_ci case MHI_CB_BW_REQ: 30762306a36Sopenharmony_ci return "MHI_CB_BW_REQ"; 30862306a36Sopenharmony_ci default: 30962306a36Sopenharmony_ci return "UNKNOWN"; 31062306a36Sopenharmony_ci } 31162306a36Sopenharmony_ci} 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_cistatic void ath12k_mhi_op_status_cb(struct mhi_controller *mhi_cntrl, 31462306a36Sopenharmony_ci enum mhi_callback cb) 31562306a36Sopenharmony_ci{ 31662306a36Sopenharmony_ci struct ath12k_base *ab = dev_get_drvdata(mhi_cntrl->cntrl_dev); 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci ath12k_dbg(ab, ATH12K_DBG_BOOT, "mhi notify status reason %s\n", 31962306a36Sopenharmony_ci ath12k_mhi_op_callback_to_str(cb)); 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci switch (cb) { 32262306a36Sopenharmony_ci case MHI_CB_SYS_ERROR: 32362306a36Sopenharmony_ci ath12k_warn(ab, "firmware crashed: MHI_CB_SYS_ERROR\n"); 32462306a36Sopenharmony_ci break; 32562306a36Sopenharmony_ci case MHI_CB_EE_RDDM: 32662306a36Sopenharmony_ci if (!(test_bit(ATH12K_FLAG_UNREGISTERING, &ab->dev_flags))) 32762306a36Sopenharmony_ci queue_work(ab->workqueue_aux, &ab->reset_work); 32862306a36Sopenharmony_ci break; 32962306a36Sopenharmony_ci default: 33062306a36Sopenharmony_ci break; 33162306a36Sopenharmony_ci } 33262306a36Sopenharmony_ci} 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_cistatic int ath12k_mhi_op_read_reg(struct mhi_controller *mhi_cntrl, 33562306a36Sopenharmony_ci void __iomem *addr, 33662306a36Sopenharmony_ci u32 *out) 33762306a36Sopenharmony_ci{ 33862306a36Sopenharmony_ci *out = readl(addr); 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci return 0; 34162306a36Sopenharmony_ci} 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_cistatic void ath12k_mhi_op_write_reg(struct mhi_controller *mhi_cntrl, 34462306a36Sopenharmony_ci void __iomem *addr, 34562306a36Sopenharmony_ci u32 val) 34662306a36Sopenharmony_ci{ 34762306a36Sopenharmony_ci writel(val, addr); 34862306a36Sopenharmony_ci} 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ciint ath12k_mhi_register(struct ath12k_pci *ab_pci) 35162306a36Sopenharmony_ci{ 35262306a36Sopenharmony_ci struct ath12k_base *ab = ab_pci->ab; 35362306a36Sopenharmony_ci struct mhi_controller *mhi_ctrl; 35462306a36Sopenharmony_ci int ret; 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci mhi_ctrl = mhi_alloc_controller(); 35762306a36Sopenharmony_ci if (!mhi_ctrl) 35862306a36Sopenharmony_ci return -ENOMEM; 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci ath12k_core_create_firmware_path(ab, ATH12K_AMSS_FILE, 36162306a36Sopenharmony_ci ab_pci->amss_path, 36262306a36Sopenharmony_ci sizeof(ab_pci->amss_path)); 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci ab_pci->mhi_ctrl = mhi_ctrl; 36562306a36Sopenharmony_ci mhi_ctrl->cntrl_dev = ab->dev; 36662306a36Sopenharmony_ci mhi_ctrl->fw_image = ab_pci->amss_path; 36762306a36Sopenharmony_ci mhi_ctrl->regs = ab->mem; 36862306a36Sopenharmony_ci mhi_ctrl->reg_len = ab->mem_len; 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci ret = ath12k_mhi_get_msi(ab_pci); 37162306a36Sopenharmony_ci if (ret) { 37262306a36Sopenharmony_ci ath12k_err(ab, "failed to get msi for mhi\n"); 37362306a36Sopenharmony_ci goto free_controller; 37462306a36Sopenharmony_ci } 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci mhi_ctrl->iova_start = 0; 37762306a36Sopenharmony_ci mhi_ctrl->iova_stop = 0xffffffff; 37862306a36Sopenharmony_ci mhi_ctrl->sbl_size = SZ_512K; 37962306a36Sopenharmony_ci mhi_ctrl->seg_len = SZ_512K; 38062306a36Sopenharmony_ci mhi_ctrl->fbc_download = true; 38162306a36Sopenharmony_ci mhi_ctrl->runtime_get = ath12k_mhi_op_runtime_get; 38262306a36Sopenharmony_ci mhi_ctrl->runtime_put = ath12k_mhi_op_runtime_put; 38362306a36Sopenharmony_ci mhi_ctrl->status_cb = ath12k_mhi_op_status_cb; 38462306a36Sopenharmony_ci mhi_ctrl->read_reg = ath12k_mhi_op_read_reg; 38562306a36Sopenharmony_ci mhi_ctrl->write_reg = ath12k_mhi_op_write_reg; 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci ret = mhi_register_controller(mhi_ctrl, ab->hw_params->mhi_config); 38862306a36Sopenharmony_ci if (ret) { 38962306a36Sopenharmony_ci ath12k_err(ab, "failed to register to mhi bus, err = %d\n", ret); 39062306a36Sopenharmony_ci goto free_controller; 39162306a36Sopenharmony_ci } 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci return 0; 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_cifree_controller: 39662306a36Sopenharmony_ci mhi_free_controller(mhi_ctrl); 39762306a36Sopenharmony_ci ab_pci->mhi_ctrl = NULL; 39862306a36Sopenharmony_ci return ret; 39962306a36Sopenharmony_ci} 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_civoid ath12k_mhi_unregister(struct ath12k_pci *ab_pci) 40262306a36Sopenharmony_ci{ 40362306a36Sopenharmony_ci struct mhi_controller *mhi_ctrl = ab_pci->mhi_ctrl; 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci mhi_unregister_controller(mhi_ctrl); 40662306a36Sopenharmony_ci kfree(mhi_ctrl->irq); 40762306a36Sopenharmony_ci mhi_free_controller(mhi_ctrl); 40862306a36Sopenharmony_ci ab_pci->mhi_ctrl = NULL; 40962306a36Sopenharmony_ci} 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_cistatic char *ath12k_mhi_state_to_str(enum ath12k_mhi_state mhi_state) 41262306a36Sopenharmony_ci{ 41362306a36Sopenharmony_ci switch (mhi_state) { 41462306a36Sopenharmony_ci case ATH12K_MHI_INIT: 41562306a36Sopenharmony_ci return "INIT"; 41662306a36Sopenharmony_ci case ATH12K_MHI_DEINIT: 41762306a36Sopenharmony_ci return "DEINIT"; 41862306a36Sopenharmony_ci case ATH12K_MHI_POWER_ON: 41962306a36Sopenharmony_ci return "POWER_ON"; 42062306a36Sopenharmony_ci case ATH12K_MHI_POWER_OFF: 42162306a36Sopenharmony_ci return "POWER_OFF"; 42262306a36Sopenharmony_ci case ATH12K_MHI_FORCE_POWER_OFF: 42362306a36Sopenharmony_ci return "FORCE_POWER_OFF"; 42462306a36Sopenharmony_ci case ATH12K_MHI_SUSPEND: 42562306a36Sopenharmony_ci return "SUSPEND"; 42662306a36Sopenharmony_ci case ATH12K_MHI_RESUME: 42762306a36Sopenharmony_ci return "RESUME"; 42862306a36Sopenharmony_ci case ATH12K_MHI_TRIGGER_RDDM: 42962306a36Sopenharmony_ci return "TRIGGER_RDDM"; 43062306a36Sopenharmony_ci case ATH12K_MHI_RDDM_DONE: 43162306a36Sopenharmony_ci return "RDDM_DONE"; 43262306a36Sopenharmony_ci default: 43362306a36Sopenharmony_ci return "UNKNOWN"; 43462306a36Sopenharmony_ci } 43562306a36Sopenharmony_ci}; 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_cistatic void ath12k_mhi_set_state_bit(struct ath12k_pci *ab_pci, 43862306a36Sopenharmony_ci enum ath12k_mhi_state mhi_state) 43962306a36Sopenharmony_ci{ 44062306a36Sopenharmony_ci struct ath12k_base *ab = ab_pci->ab; 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci switch (mhi_state) { 44362306a36Sopenharmony_ci case ATH12K_MHI_INIT: 44462306a36Sopenharmony_ci set_bit(ATH12K_MHI_INIT, &ab_pci->mhi_state); 44562306a36Sopenharmony_ci break; 44662306a36Sopenharmony_ci case ATH12K_MHI_DEINIT: 44762306a36Sopenharmony_ci clear_bit(ATH12K_MHI_INIT, &ab_pci->mhi_state); 44862306a36Sopenharmony_ci break; 44962306a36Sopenharmony_ci case ATH12K_MHI_POWER_ON: 45062306a36Sopenharmony_ci set_bit(ATH12K_MHI_POWER_ON, &ab_pci->mhi_state); 45162306a36Sopenharmony_ci break; 45262306a36Sopenharmony_ci case ATH12K_MHI_POWER_OFF: 45362306a36Sopenharmony_ci case ATH12K_MHI_FORCE_POWER_OFF: 45462306a36Sopenharmony_ci clear_bit(ATH12K_MHI_POWER_ON, &ab_pci->mhi_state); 45562306a36Sopenharmony_ci clear_bit(ATH12K_MHI_TRIGGER_RDDM, &ab_pci->mhi_state); 45662306a36Sopenharmony_ci clear_bit(ATH12K_MHI_RDDM_DONE, &ab_pci->mhi_state); 45762306a36Sopenharmony_ci break; 45862306a36Sopenharmony_ci case ATH12K_MHI_SUSPEND: 45962306a36Sopenharmony_ci set_bit(ATH12K_MHI_SUSPEND, &ab_pci->mhi_state); 46062306a36Sopenharmony_ci break; 46162306a36Sopenharmony_ci case ATH12K_MHI_RESUME: 46262306a36Sopenharmony_ci clear_bit(ATH12K_MHI_SUSPEND, &ab_pci->mhi_state); 46362306a36Sopenharmony_ci break; 46462306a36Sopenharmony_ci case ATH12K_MHI_TRIGGER_RDDM: 46562306a36Sopenharmony_ci set_bit(ATH12K_MHI_TRIGGER_RDDM, &ab_pci->mhi_state); 46662306a36Sopenharmony_ci break; 46762306a36Sopenharmony_ci case ATH12K_MHI_RDDM_DONE: 46862306a36Sopenharmony_ci set_bit(ATH12K_MHI_RDDM_DONE, &ab_pci->mhi_state); 46962306a36Sopenharmony_ci break; 47062306a36Sopenharmony_ci default: 47162306a36Sopenharmony_ci ath12k_err(ab, "unhandled mhi state (%d)\n", mhi_state); 47262306a36Sopenharmony_ci } 47362306a36Sopenharmony_ci} 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_cistatic int ath12k_mhi_check_state_bit(struct ath12k_pci *ab_pci, 47662306a36Sopenharmony_ci enum ath12k_mhi_state mhi_state) 47762306a36Sopenharmony_ci{ 47862306a36Sopenharmony_ci struct ath12k_base *ab = ab_pci->ab; 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci switch (mhi_state) { 48162306a36Sopenharmony_ci case ATH12K_MHI_INIT: 48262306a36Sopenharmony_ci if (!test_bit(ATH12K_MHI_INIT, &ab_pci->mhi_state)) 48362306a36Sopenharmony_ci return 0; 48462306a36Sopenharmony_ci break; 48562306a36Sopenharmony_ci case ATH12K_MHI_DEINIT: 48662306a36Sopenharmony_ci case ATH12K_MHI_POWER_ON: 48762306a36Sopenharmony_ci if (test_bit(ATH12K_MHI_INIT, &ab_pci->mhi_state) && 48862306a36Sopenharmony_ci !test_bit(ATH12K_MHI_POWER_ON, &ab_pci->mhi_state)) 48962306a36Sopenharmony_ci return 0; 49062306a36Sopenharmony_ci break; 49162306a36Sopenharmony_ci case ATH12K_MHI_FORCE_POWER_OFF: 49262306a36Sopenharmony_ci if (test_bit(ATH12K_MHI_POWER_ON, &ab_pci->mhi_state)) 49362306a36Sopenharmony_ci return 0; 49462306a36Sopenharmony_ci break; 49562306a36Sopenharmony_ci case ATH12K_MHI_POWER_OFF: 49662306a36Sopenharmony_ci case ATH12K_MHI_SUSPEND: 49762306a36Sopenharmony_ci if (test_bit(ATH12K_MHI_POWER_ON, &ab_pci->mhi_state) && 49862306a36Sopenharmony_ci !test_bit(ATH12K_MHI_SUSPEND, &ab_pci->mhi_state)) 49962306a36Sopenharmony_ci return 0; 50062306a36Sopenharmony_ci break; 50162306a36Sopenharmony_ci case ATH12K_MHI_RESUME: 50262306a36Sopenharmony_ci if (test_bit(ATH12K_MHI_SUSPEND, &ab_pci->mhi_state)) 50362306a36Sopenharmony_ci return 0; 50462306a36Sopenharmony_ci break; 50562306a36Sopenharmony_ci case ATH12K_MHI_TRIGGER_RDDM: 50662306a36Sopenharmony_ci if (test_bit(ATH12K_MHI_POWER_ON, &ab_pci->mhi_state) && 50762306a36Sopenharmony_ci !test_bit(ATH12K_MHI_TRIGGER_RDDM, &ab_pci->mhi_state)) 50862306a36Sopenharmony_ci return 0; 50962306a36Sopenharmony_ci break; 51062306a36Sopenharmony_ci case ATH12K_MHI_RDDM_DONE: 51162306a36Sopenharmony_ci return 0; 51262306a36Sopenharmony_ci default: 51362306a36Sopenharmony_ci ath12k_err(ab, "unhandled mhi state: %s(%d)\n", 51462306a36Sopenharmony_ci ath12k_mhi_state_to_str(mhi_state), mhi_state); 51562306a36Sopenharmony_ci } 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci ath12k_err(ab, "failed to set mhi state %s(%d) in current mhi state (0x%lx)\n", 51862306a36Sopenharmony_ci ath12k_mhi_state_to_str(mhi_state), mhi_state, 51962306a36Sopenharmony_ci ab_pci->mhi_state); 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci return -EINVAL; 52262306a36Sopenharmony_ci} 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_cistatic int ath12k_mhi_set_state(struct ath12k_pci *ab_pci, 52562306a36Sopenharmony_ci enum ath12k_mhi_state mhi_state) 52662306a36Sopenharmony_ci{ 52762306a36Sopenharmony_ci struct ath12k_base *ab = ab_pci->ab; 52862306a36Sopenharmony_ci int ret; 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci ret = ath12k_mhi_check_state_bit(ab_pci, mhi_state); 53162306a36Sopenharmony_ci if (ret) 53262306a36Sopenharmony_ci goto out; 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci ath12k_dbg(ab, ATH12K_DBG_PCI, "setting mhi state: %s(%d)\n", 53562306a36Sopenharmony_ci ath12k_mhi_state_to_str(mhi_state), mhi_state); 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci switch (mhi_state) { 53862306a36Sopenharmony_ci case ATH12K_MHI_INIT: 53962306a36Sopenharmony_ci ret = mhi_prepare_for_power_up(ab_pci->mhi_ctrl); 54062306a36Sopenharmony_ci break; 54162306a36Sopenharmony_ci case ATH12K_MHI_DEINIT: 54262306a36Sopenharmony_ci mhi_unprepare_after_power_down(ab_pci->mhi_ctrl); 54362306a36Sopenharmony_ci ret = 0; 54462306a36Sopenharmony_ci break; 54562306a36Sopenharmony_ci case ATH12K_MHI_POWER_ON: 54662306a36Sopenharmony_ci ret = mhi_async_power_up(ab_pci->mhi_ctrl); 54762306a36Sopenharmony_ci break; 54862306a36Sopenharmony_ci case ATH12K_MHI_POWER_OFF: 54962306a36Sopenharmony_ci mhi_power_down(ab_pci->mhi_ctrl, true); 55062306a36Sopenharmony_ci ret = 0; 55162306a36Sopenharmony_ci break; 55262306a36Sopenharmony_ci case ATH12K_MHI_FORCE_POWER_OFF: 55362306a36Sopenharmony_ci mhi_power_down(ab_pci->mhi_ctrl, false); 55462306a36Sopenharmony_ci ret = 0; 55562306a36Sopenharmony_ci break; 55662306a36Sopenharmony_ci case ATH12K_MHI_SUSPEND: 55762306a36Sopenharmony_ci ret = mhi_pm_suspend(ab_pci->mhi_ctrl); 55862306a36Sopenharmony_ci break; 55962306a36Sopenharmony_ci case ATH12K_MHI_RESUME: 56062306a36Sopenharmony_ci ret = mhi_pm_resume(ab_pci->mhi_ctrl); 56162306a36Sopenharmony_ci break; 56262306a36Sopenharmony_ci case ATH12K_MHI_TRIGGER_RDDM: 56362306a36Sopenharmony_ci ret = mhi_force_rddm_mode(ab_pci->mhi_ctrl); 56462306a36Sopenharmony_ci break; 56562306a36Sopenharmony_ci case ATH12K_MHI_RDDM_DONE: 56662306a36Sopenharmony_ci break; 56762306a36Sopenharmony_ci default: 56862306a36Sopenharmony_ci ath12k_err(ab, "unhandled MHI state (%d)\n", mhi_state); 56962306a36Sopenharmony_ci ret = -EINVAL; 57062306a36Sopenharmony_ci } 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci if (ret) 57362306a36Sopenharmony_ci goto out; 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci ath12k_mhi_set_state_bit(ab_pci, mhi_state); 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci return 0; 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ciout: 58062306a36Sopenharmony_ci ath12k_err(ab, "failed to set mhi state: %s(%d)\n", 58162306a36Sopenharmony_ci ath12k_mhi_state_to_str(mhi_state), mhi_state); 58262306a36Sopenharmony_ci return ret; 58362306a36Sopenharmony_ci} 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ciint ath12k_mhi_start(struct ath12k_pci *ab_pci) 58662306a36Sopenharmony_ci{ 58762306a36Sopenharmony_ci int ret; 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci ab_pci->mhi_ctrl->timeout_ms = MHI_TIMEOUT_DEFAULT_MS; 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci ret = ath12k_mhi_set_state(ab_pci, ATH12K_MHI_INIT); 59262306a36Sopenharmony_ci if (ret) 59362306a36Sopenharmony_ci goto out; 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci ret = ath12k_mhi_set_state(ab_pci, ATH12K_MHI_POWER_ON); 59662306a36Sopenharmony_ci if (ret) 59762306a36Sopenharmony_ci goto out; 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci return 0; 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ciout: 60262306a36Sopenharmony_ci return ret; 60362306a36Sopenharmony_ci} 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_civoid ath12k_mhi_stop(struct ath12k_pci *ab_pci) 60662306a36Sopenharmony_ci{ 60762306a36Sopenharmony_ci ath12k_mhi_set_state(ab_pci, ATH12K_MHI_POWER_OFF); 60862306a36Sopenharmony_ci ath12k_mhi_set_state(ab_pci, ATH12K_MHI_DEINIT); 60962306a36Sopenharmony_ci} 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_civoid ath12k_mhi_suspend(struct ath12k_pci *ab_pci) 61262306a36Sopenharmony_ci{ 61362306a36Sopenharmony_ci ath12k_mhi_set_state(ab_pci, ATH12K_MHI_SUSPEND); 61462306a36Sopenharmony_ci} 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_civoid ath12k_mhi_resume(struct ath12k_pci *ab_pci) 61762306a36Sopenharmony_ci{ 61862306a36Sopenharmony_ci ath12k_mhi_set_state(ab_pci, ATH12K_MHI_RESUME); 61962306a36Sopenharmony_ci} 620