Path: blob/main/sys/contrib/dev/athk/ath12k/mhi.c
107787 views
// SPDX-License-Identifier: BSD-3-Clause-Clear1/*2* Copyright (c) 2020-2021 The Linux Foundation. All rights reserved.3* Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.4*/56#include <linux/msi.h>7#include <linux/pci.h>8#if defined(__FreeBSD__)9#include <linux/delay.h>10#endif1112#include "core.h"13#include "debug.h"14#include "mhi.h"15#include "pci.h"1617#define MHI_TIMEOUT_DEFAULT_MS 900001819static const struct mhi_channel_config ath12k_mhi_channels_qcn9274[] = {20{21.num = 0,22.name = "LOOPBACK",23.num_elements = 32,24.event_ring = 1,25.dir = DMA_TO_DEVICE,26.ee_mask = 0x4,27.pollcfg = 0,28.doorbell = MHI_DB_BRST_DISABLE,29.lpm_notify = false,30.offload_channel = false,31.doorbell_mode_switch = false,32.auto_queue = false,33},34{35.num = 1,36.name = "LOOPBACK",37.num_elements = 32,38.event_ring = 1,39.dir = DMA_FROM_DEVICE,40.ee_mask = 0x4,41.pollcfg = 0,42.doorbell = MHI_DB_BRST_DISABLE,43.lpm_notify = false,44.offload_channel = false,45.doorbell_mode_switch = false,46.auto_queue = false,47},48{49.num = 20,50.name = "IPCR",51.num_elements = 32,52.event_ring = 1,53.dir = DMA_TO_DEVICE,54.ee_mask = 0x4,55.pollcfg = 0,56.doorbell = MHI_DB_BRST_DISABLE,57.lpm_notify = false,58.offload_channel = false,59.doorbell_mode_switch = false,60.auto_queue = false,61},62{63.num = 21,64.name = "IPCR",65.num_elements = 32,66.event_ring = 1,67.dir = DMA_FROM_DEVICE,68.ee_mask = 0x4,69.pollcfg = 0,70.doorbell = MHI_DB_BRST_DISABLE,71.lpm_notify = false,72.offload_channel = false,73.doorbell_mode_switch = false,74.auto_queue = true,75},76};7778static struct mhi_event_config ath12k_mhi_events_qcn9274[] = {79{80.num_elements = 32,81.irq_moderation_ms = 0,82.irq = 1,83.data_type = MHI_ER_CTRL,84.mode = MHI_DB_BRST_DISABLE,85.hardware_event = false,86.client_managed = false,87.offload_channel = false,88},89{90.num_elements = 256,91.irq_moderation_ms = 1,92.irq = 2,93.mode = MHI_DB_BRST_DISABLE,94.priority = 1,95.hardware_event = false,96.client_managed = false,97.offload_channel = false,98},99};100101const struct mhi_controller_config ath12k_mhi_config_qcn9274 = {102.max_channels = 30,103.timeout_ms = 10000,104.use_bounce_buf = false,105.buf_len = 0,106.num_channels = ARRAY_SIZE(ath12k_mhi_channels_qcn9274),107.ch_cfg = ath12k_mhi_channels_qcn9274,108.num_events = ARRAY_SIZE(ath12k_mhi_events_qcn9274),109.event_cfg = ath12k_mhi_events_qcn9274,110};111112static const struct mhi_channel_config ath12k_mhi_channels_wcn7850[] = {113{114.num = 0,115.name = "LOOPBACK",116.num_elements = 32,117.event_ring = 0,118.dir = DMA_TO_DEVICE,119.ee_mask = 0x4,120.pollcfg = 0,121.doorbell = MHI_DB_BRST_DISABLE,122.lpm_notify = false,123.offload_channel = false,124.doorbell_mode_switch = false,125.auto_queue = false,126},127{128.num = 1,129.name = "LOOPBACK",130.num_elements = 32,131.event_ring = 0,132.dir = DMA_FROM_DEVICE,133.ee_mask = 0x4,134.pollcfg = 0,135.doorbell = MHI_DB_BRST_DISABLE,136.lpm_notify = false,137.offload_channel = false,138.doorbell_mode_switch = false,139.auto_queue = false,140},141{142.num = 20,143.name = "IPCR",144.num_elements = 64,145.event_ring = 1,146.dir = DMA_TO_DEVICE,147.ee_mask = 0x4,148.pollcfg = 0,149.doorbell = MHI_DB_BRST_DISABLE,150.lpm_notify = false,151.offload_channel = false,152.doorbell_mode_switch = false,153.auto_queue = false,154},155{156.num = 21,157.name = "IPCR",158.num_elements = 64,159.event_ring = 1,160.dir = DMA_FROM_DEVICE,161.ee_mask = 0x4,162.pollcfg = 0,163.doorbell = MHI_DB_BRST_DISABLE,164.lpm_notify = false,165.offload_channel = false,166.doorbell_mode_switch = false,167.auto_queue = true,168},169};170171static struct mhi_event_config ath12k_mhi_events_wcn7850[] = {172{173.num_elements = 32,174.irq_moderation_ms = 0,175.irq = 1,176.mode = MHI_DB_BRST_DISABLE,177.data_type = MHI_ER_CTRL,178.hardware_event = false,179.client_managed = false,180.offload_channel = false,181},182{183.num_elements = 256,184.irq_moderation_ms = 1,185.irq = 2,186.mode = MHI_DB_BRST_DISABLE,187.priority = 1,188.hardware_event = false,189.client_managed = false,190.offload_channel = false,191},192};193194const struct mhi_controller_config ath12k_mhi_config_wcn7850 = {195.max_channels = 128,196.timeout_ms = 2000,197.use_bounce_buf = false,198.buf_len = 0,199.num_channels = ARRAY_SIZE(ath12k_mhi_channels_wcn7850),200.ch_cfg = ath12k_mhi_channels_wcn7850,201.num_events = ARRAY_SIZE(ath12k_mhi_events_wcn7850),202.event_cfg = ath12k_mhi_events_wcn7850,203};204205void ath12k_mhi_set_mhictrl_reset(struct ath12k_base *ab)206{207u32 val;208209val = ath12k_pci_read32(ab, MHISTATUS);210211ath12k_dbg(ab, ATH12K_DBG_PCI, "MHISTATUS 0x%x\n", val);212213/* Observed on some targets that after SOC_GLOBAL_RESET, MHISTATUS214* has SYSERR bit set and thus need to set MHICTRL_RESET215* to clear SYSERR.216*/217ath12k_pci_write32(ab, MHICTRL, MHICTRL_RESET_MASK);218219mdelay(10);220}221222static void ath12k_mhi_reset_txvecdb(struct ath12k_base *ab)223{224ath12k_pci_write32(ab, PCIE_TXVECDB, 0);225}226227static void ath12k_mhi_reset_txvecstatus(struct ath12k_base *ab)228{229ath12k_pci_write32(ab, PCIE_TXVECSTATUS, 0);230}231232static void ath12k_mhi_reset_rxvecdb(struct ath12k_base *ab)233{234ath12k_pci_write32(ab, PCIE_RXVECDB, 0);235}236237static void ath12k_mhi_reset_rxvecstatus(struct ath12k_base *ab)238{239ath12k_pci_write32(ab, PCIE_RXVECSTATUS, 0);240}241242void ath12k_mhi_clear_vector(struct ath12k_base *ab)243{244ath12k_mhi_reset_txvecdb(ab);245ath12k_mhi_reset_txvecstatus(ab);246ath12k_mhi_reset_rxvecdb(ab);247ath12k_mhi_reset_rxvecstatus(ab);248}249250static int ath12k_mhi_get_msi(struct ath12k_pci *ab_pci)251{252struct ath12k_base *ab = ab_pci->ab;253u32 user_base_data, base_vector;254int ret, num_vectors, i;255int *irq;256257ret = ath12k_pci_get_user_msi_assignment(ab,258"MHI", &num_vectors,259&user_base_data, &base_vector);260if (ret)261return ret;262263ath12k_dbg(ab, ATH12K_DBG_PCI, "Number of assigned MSI for MHI is %d, base vector is %d\n",264num_vectors, base_vector);265266irq = kcalloc(num_vectors, sizeof(*irq), GFP_KERNEL);267if (!irq)268return -ENOMEM;269270for (i = 0; i < num_vectors; i++)271irq[i] = ath12k_pci_get_msi_irq(ab->dev,272base_vector + i);273274ab_pci->mhi_ctrl->irq = irq;275ab_pci->mhi_ctrl->nr_irqs = num_vectors;276277return 0;278}279280static int ath12k_mhi_op_runtime_get(struct mhi_controller *mhi_cntrl)281{282return 0;283}284285static void ath12k_mhi_op_runtime_put(struct mhi_controller *mhi_cntrl)286{287}288289static char *ath12k_mhi_op_callback_to_str(enum mhi_callback reason)290{291switch (reason) {292case MHI_CB_IDLE:293return "MHI_CB_IDLE";294case MHI_CB_PENDING_DATA:295return "MHI_CB_PENDING_DATA";296case MHI_CB_LPM_ENTER:297return "MHI_CB_LPM_ENTER";298case MHI_CB_LPM_EXIT:299return "MHI_CB_LPM_EXIT";300case MHI_CB_EE_RDDM:301return "MHI_CB_EE_RDDM";302case MHI_CB_EE_MISSION_MODE:303return "MHI_CB_EE_MISSION_MODE";304case MHI_CB_SYS_ERROR:305return "MHI_CB_SYS_ERROR";306case MHI_CB_FATAL_ERROR:307return "MHI_CB_FATAL_ERROR";308case MHI_CB_BW_REQ:309return "MHI_CB_BW_REQ";310default:311return "UNKNOWN";312}313}314315static void ath12k_mhi_op_status_cb(struct mhi_controller *mhi_cntrl,316enum mhi_callback cb)317{318struct ath12k_base *ab = dev_get_drvdata(mhi_cntrl->cntrl_dev);319320ath12k_dbg(ab, ATH12K_DBG_BOOT, "mhi notify status reason %s\n",321ath12k_mhi_op_callback_to_str(cb));322323switch (cb) {324case MHI_CB_SYS_ERROR:325ath12k_warn(ab, "firmware crashed: MHI_CB_SYS_ERROR\n");326break;327case MHI_CB_EE_RDDM:328if (!(test_bit(ATH12K_FLAG_UNREGISTERING, &ab->dev_flags)))329queue_work(ab->workqueue_aux, &ab->reset_work);330break;331default:332break;333}334}335336static int ath12k_mhi_op_read_reg(struct mhi_controller *mhi_cntrl,337void __iomem *addr,338u32 *out)339{340*out = readl(addr);341342return 0;343}344345static void ath12k_mhi_op_write_reg(struct mhi_controller *mhi_cntrl,346void __iomem *addr,347u32 val)348{349writel(val, addr);350}351352int ath12k_mhi_register(struct ath12k_pci *ab_pci)353{354struct ath12k_base *ab = ab_pci->ab;355struct mhi_controller *mhi_ctrl;356int ret;357358mhi_ctrl = mhi_alloc_controller();359if (!mhi_ctrl)360return -ENOMEM;361362ath12k_core_create_firmware_path(ab, ATH12K_AMSS_FILE,363ab_pci->amss_path,364sizeof(ab_pci->amss_path));365366ab_pci->mhi_ctrl = mhi_ctrl;367mhi_ctrl->cntrl_dev = ab->dev;368mhi_ctrl->fw_image = ab_pci->amss_path;369mhi_ctrl->regs = ab->mem;370mhi_ctrl->reg_len = ab->mem_len;371372ret = ath12k_mhi_get_msi(ab_pci);373if (ret) {374ath12k_err(ab, "failed to get msi for mhi\n");375mhi_free_controller(mhi_ctrl);376return ret;377}378379mhi_ctrl->iova_start = 0;380mhi_ctrl->iova_stop = 0xffffffff;381mhi_ctrl->sbl_size = SZ_512K;382mhi_ctrl->seg_len = SZ_512K;383mhi_ctrl->fbc_download = true;384mhi_ctrl->runtime_get = ath12k_mhi_op_runtime_get;385mhi_ctrl->runtime_put = ath12k_mhi_op_runtime_put;386mhi_ctrl->status_cb = ath12k_mhi_op_status_cb;387mhi_ctrl->read_reg = ath12k_mhi_op_read_reg;388mhi_ctrl->write_reg = ath12k_mhi_op_write_reg;389390ret = mhi_register_controller(mhi_ctrl, ab->hw_params->mhi_config);391if (ret) {392ath12k_err(ab, "failed to register to mhi bus, err = %d\n", ret);393mhi_free_controller(mhi_ctrl);394return ret;395}396397return 0;398}399400void ath12k_mhi_unregister(struct ath12k_pci *ab_pci)401{402struct mhi_controller *mhi_ctrl = ab_pci->mhi_ctrl;403404mhi_unregister_controller(mhi_ctrl);405kfree(mhi_ctrl->irq);406mhi_free_controller(mhi_ctrl);407ab_pci->mhi_ctrl = NULL;408}409410static char *ath12k_mhi_state_to_str(enum ath12k_mhi_state mhi_state)411{412switch (mhi_state) {413case ATH12K_MHI_INIT:414return "INIT";415case ATH12K_MHI_DEINIT:416return "DEINIT";417case ATH12K_MHI_POWER_ON:418return "POWER_ON";419case ATH12K_MHI_POWER_OFF:420return "POWER_OFF";421case ATH12K_MHI_FORCE_POWER_OFF:422return "FORCE_POWER_OFF";423case ATH12K_MHI_SUSPEND:424return "SUSPEND";425case ATH12K_MHI_RESUME:426return "RESUME";427case ATH12K_MHI_TRIGGER_RDDM:428return "TRIGGER_RDDM";429case ATH12K_MHI_RDDM_DONE:430return "RDDM_DONE";431default:432return "UNKNOWN";433}434};435436static void ath12k_mhi_set_state_bit(struct ath12k_pci *ab_pci,437enum ath12k_mhi_state mhi_state)438{439struct ath12k_base *ab = ab_pci->ab;440441switch (mhi_state) {442case ATH12K_MHI_INIT:443set_bit(ATH12K_MHI_INIT, &ab_pci->mhi_state);444break;445case ATH12K_MHI_DEINIT:446clear_bit(ATH12K_MHI_INIT, &ab_pci->mhi_state);447break;448case ATH12K_MHI_POWER_ON:449set_bit(ATH12K_MHI_POWER_ON, &ab_pci->mhi_state);450break;451case ATH12K_MHI_POWER_OFF:452case ATH12K_MHI_FORCE_POWER_OFF:453clear_bit(ATH12K_MHI_POWER_ON, &ab_pci->mhi_state);454clear_bit(ATH12K_MHI_TRIGGER_RDDM, &ab_pci->mhi_state);455clear_bit(ATH12K_MHI_RDDM_DONE, &ab_pci->mhi_state);456break;457case ATH12K_MHI_SUSPEND:458set_bit(ATH12K_MHI_SUSPEND, &ab_pci->mhi_state);459break;460case ATH12K_MHI_RESUME:461clear_bit(ATH12K_MHI_SUSPEND, &ab_pci->mhi_state);462break;463case ATH12K_MHI_TRIGGER_RDDM:464set_bit(ATH12K_MHI_TRIGGER_RDDM, &ab_pci->mhi_state);465break;466case ATH12K_MHI_RDDM_DONE:467set_bit(ATH12K_MHI_RDDM_DONE, &ab_pci->mhi_state);468break;469default:470ath12k_err(ab, "unhandled mhi state (%d)\n", mhi_state);471}472}473474static int ath12k_mhi_check_state_bit(struct ath12k_pci *ab_pci,475enum ath12k_mhi_state mhi_state)476{477struct ath12k_base *ab = ab_pci->ab;478479switch (mhi_state) {480case ATH12K_MHI_INIT:481if (!test_bit(ATH12K_MHI_INIT, &ab_pci->mhi_state))482return 0;483break;484case ATH12K_MHI_DEINIT:485case ATH12K_MHI_POWER_ON:486if (test_bit(ATH12K_MHI_INIT, &ab_pci->mhi_state) &&487!test_bit(ATH12K_MHI_POWER_ON, &ab_pci->mhi_state))488return 0;489break;490case ATH12K_MHI_FORCE_POWER_OFF:491if (test_bit(ATH12K_MHI_POWER_ON, &ab_pci->mhi_state))492return 0;493break;494case ATH12K_MHI_POWER_OFF:495case ATH12K_MHI_SUSPEND:496if (test_bit(ATH12K_MHI_POWER_ON, &ab_pci->mhi_state) &&497!test_bit(ATH12K_MHI_SUSPEND, &ab_pci->mhi_state))498return 0;499break;500case ATH12K_MHI_RESUME:501if (test_bit(ATH12K_MHI_SUSPEND, &ab_pci->mhi_state))502return 0;503break;504case ATH12K_MHI_TRIGGER_RDDM:505if (test_bit(ATH12K_MHI_POWER_ON, &ab_pci->mhi_state) &&506!test_bit(ATH12K_MHI_TRIGGER_RDDM, &ab_pci->mhi_state))507return 0;508break;509case ATH12K_MHI_RDDM_DONE:510return 0;511default:512ath12k_err(ab, "unhandled mhi state: %s(%d)\n",513ath12k_mhi_state_to_str(mhi_state), mhi_state);514}515516ath12k_err(ab, "failed to set mhi state %s(%d) in current mhi state (0x%lx)\n",517ath12k_mhi_state_to_str(mhi_state), mhi_state,518ab_pci->mhi_state);519520return -EINVAL;521}522523static int ath12k_mhi_set_state(struct ath12k_pci *ab_pci,524enum ath12k_mhi_state mhi_state)525{526struct ath12k_base *ab = ab_pci->ab;527int ret;528529ret = ath12k_mhi_check_state_bit(ab_pci, mhi_state);530if (ret)531goto out;532533ath12k_dbg(ab, ATH12K_DBG_PCI, "setting mhi state: %s(%d)\n",534ath12k_mhi_state_to_str(mhi_state), mhi_state);535536switch (mhi_state) {537case ATH12K_MHI_INIT:538ret = mhi_prepare_for_power_up(ab_pci->mhi_ctrl);539break;540case ATH12K_MHI_DEINIT:541mhi_unprepare_after_power_down(ab_pci->mhi_ctrl);542ret = 0;543break;544case ATH12K_MHI_POWER_ON:545ret = mhi_async_power_up(ab_pci->mhi_ctrl);546break;547case ATH12K_MHI_POWER_OFF:548mhi_power_down(ab_pci->mhi_ctrl, true);549ret = 0;550break;551case ATH12K_MHI_FORCE_POWER_OFF:552mhi_power_down(ab_pci->mhi_ctrl, false);553ret = 0;554break;555case ATH12K_MHI_SUSPEND:556ret = mhi_pm_suspend(ab_pci->mhi_ctrl);557break;558case ATH12K_MHI_RESUME:559ret = mhi_pm_resume(ab_pci->mhi_ctrl);560break;561case ATH12K_MHI_TRIGGER_RDDM:562ret = mhi_force_rddm_mode(ab_pci->mhi_ctrl);563break;564case ATH12K_MHI_RDDM_DONE:565break;566default:567ath12k_err(ab, "unhandled MHI state (%d)\n", mhi_state);568ret = -EINVAL;569}570571if (ret)572goto out;573574ath12k_mhi_set_state_bit(ab_pci, mhi_state);575576return 0;577578out:579ath12k_err(ab, "failed to set mhi state: %s(%d)\n",580ath12k_mhi_state_to_str(mhi_state), mhi_state);581return ret;582}583584int ath12k_mhi_start(struct ath12k_pci *ab_pci)585{586int ret;587588ab_pci->mhi_ctrl->timeout_ms = MHI_TIMEOUT_DEFAULT_MS;589590ret = ath12k_mhi_set_state(ab_pci, ATH12K_MHI_INIT);591if (ret)592goto out;593594ret = ath12k_mhi_set_state(ab_pci, ATH12K_MHI_POWER_ON);595if (ret)596goto out;597598return 0;599600out:601return ret;602}603604void ath12k_mhi_stop(struct ath12k_pci *ab_pci)605{606ath12k_mhi_set_state(ab_pci, ATH12K_MHI_POWER_OFF);607ath12k_mhi_set_state(ab_pci, ATH12K_MHI_DEINIT);608}609610void ath12k_mhi_suspend(struct ath12k_pci *ab_pci)611{612ath12k_mhi_set_state(ab_pci, ATH12K_MHI_SUSPEND);613}614615void ath12k_mhi_resume(struct ath12k_pci *ab_pci)616{617ath12k_mhi_set_state(ab_pci, ATH12K_MHI_RESUME);618}619620621