493 lines · c
1// SPDX-License-Identifier: BSD-3-Clause-Clear2/*3 * Copyright (c) 2020 The Linux Foundation. All rights reserved.4 * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.5 */6 7#include <linux/msi.h>8#include <linux/pci.h>9#include <linux/firmware.h>10#include <linux/of.h>11#include <linux/of_address.h>12#include <linux/ioport.h>13 14#include "core.h"15#include "debug.h"16#include "mhi.h"17#include "pci.h"18#include "pcic.h"19 20#define MHI_TIMEOUT_DEFAULT_MS 2000021#define RDDM_DUMP_SIZE 0x42000022#define MHI_CB_INVALID 0xff23 24static const struct mhi_channel_config ath11k_mhi_channels_qca6390[] = {25 {26 .num = 20,27 .name = "IPCR",28 .num_elements = 64,29 .event_ring = 1,30 .dir = DMA_TO_DEVICE,31 .ee_mask = 0x4,32 .pollcfg = 0,33 .doorbell = MHI_DB_BRST_DISABLE,34 .lpm_notify = false,35 .offload_channel = false,36 .doorbell_mode_switch = false,37 .auto_queue = false,38 },39 {40 .num = 21,41 .name = "IPCR",42 .num_elements = 64,43 .event_ring = 1,44 .dir = DMA_FROM_DEVICE,45 .ee_mask = 0x4,46 .pollcfg = 0,47 .doorbell = MHI_DB_BRST_DISABLE,48 .lpm_notify = false,49 .offload_channel = false,50 .doorbell_mode_switch = false,51 .auto_queue = true,52 },53};54 55static struct mhi_event_config ath11k_mhi_events_qca6390[] = {56 {57 .num_elements = 32,58 .irq_moderation_ms = 0,59 .irq = 1,60 .mode = MHI_DB_BRST_DISABLE,61 .data_type = MHI_ER_CTRL,62 .hardware_event = false,63 .client_managed = false,64 .offload_channel = false,65 },66 {67 .num_elements = 256,68 .irq_moderation_ms = 1,69 .irq = 2,70 .mode = MHI_DB_BRST_DISABLE,71 .priority = 1,72 .hardware_event = false,73 .client_managed = false,74 .offload_channel = false,75 },76};77 78static const struct mhi_controller_config ath11k_mhi_config_qca6390 = {79 .max_channels = 128,80 .timeout_ms = 2000,81 .use_bounce_buf = false,82 .buf_len = 8192,83 .num_channels = ARRAY_SIZE(ath11k_mhi_channels_qca6390),84 .ch_cfg = ath11k_mhi_channels_qca6390,85 .num_events = ARRAY_SIZE(ath11k_mhi_events_qca6390),86 .event_cfg = ath11k_mhi_events_qca6390,87};88 89static const struct mhi_channel_config ath11k_mhi_channels_qcn9074[] = {90 {91 .num = 20,92 .name = "IPCR",93 .num_elements = 32,94 .event_ring = 1,95 .dir = DMA_TO_DEVICE,96 .ee_mask = 0x14,97 .pollcfg = 0,98 .doorbell = MHI_DB_BRST_DISABLE,99 .lpm_notify = false,100 .offload_channel = false,101 .doorbell_mode_switch = false,102 .auto_queue = false,103 },104 {105 .num = 21,106 .name = "IPCR",107 .num_elements = 32,108 .event_ring = 1,109 .dir = DMA_FROM_DEVICE,110 .ee_mask = 0x14,111 .pollcfg = 0,112 .doorbell = MHI_DB_BRST_DISABLE,113 .lpm_notify = false,114 .offload_channel = false,115 .doorbell_mode_switch = false,116 .auto_queue = true,117 },118};119 120static struct mhi_event_config ath11k_mhi_events_qcn9074[] = {121 {122 .num_elements = 32,123 .irq_moderation_ms = 0,124 .irq = 1,125 .data_type = MHI_ER_CTRL,126 .mode = MHI_DB_BRST_DISABLE,127 .hardware_event = false,128 .client_managed = false,129 .offload_channel = false,130 },131 {132 .num_elements = 256,133 .irq_moderation_ms = 1,134 .irq = 2,135 .mode = MHI_DB_BRST_DISABLE,136 .priority = 1,137 .hardware_event = false,138 .client_managed = false,139 .offload_channel = false,140 },141};142 143static const struct mhi_controller_config ath11k_mhi_config_qcn9074 = {144 .max_channels = 30,145 .timeout_ms = 10000,146 .use_bounce_buf = false,147 .buf_len = 0,148 .num_channels = ARRAY_SIZE(ath11k_mhi_channels_qcn9074),149 .ch_cfg = ath11k_mhi_channels_qcn9074,150 .num_events = ARRAY_SIZE(ath11k_mhi_events_qcn9074),151 .event_cfg = ath11k_mhi_events_qcn9074,152};153 154void ath11k_mhi_set_mhictrl_reset(struct ath11k_base *ab)155{156 u32 val;157 158 val = ath11k_pcic_read32(ab, MHISTATUS);159 160 ath11k_dbg(ab, ATH11K_DBG_PCI, "mhistatus 0x%x\n", val);161 162 /* After SOC_GLOBAL_RESET, MHISTATUS may still have SYSERR bit set163 * and thus need to set MHICTRL_RESET to clear SYSERR.164 */165 ath11k_pcic_write32(ab, MHICTRL, MHICTRL_RESET_MASK);166 167 mdelay(10);168}169 170static void ath11k_mhi_reset_txvecdb(struct ath11k_base *ab)171{172 ath11k_pcic_write32(ab, PCIE_TXVECDB, 0);173}174 175static void ath11k_mhi_reset_txvecstatus(struct ath11k_base *ab)176{177 ath11k_pcic_write32(ab, PCIE_TXVECSTATUS, 0);178}179 180static void ath11k_mhi_reset_rxvecdb(struct ath11k_base *ab)181{182 ath11k_pcic_write32(ab, PCIE_RXVECDB, 0);183}184 185static void ath11k_mhi_reset_rxvecstatus(struct ath11k_base *ab)186{187 ath11k_pcic_write32(ab, PCIE_RXVECSTATUS, 0);188}189 190void ath11k_mhi_clear_vector(struct ath11k_base *ab)191{192 ath11k_mhi_reset_txvecdb(ab);193 ath11k_mhi_reset_txvecstatus(ab);194 ath11k_mhi_reset_rxvecdb(ab);195 ath11k_mhi_reset_rxvecstatus(ab);196}197 198static int ath11k_mhi_get_msi(struct ath11k_pci *ab_pci)199{200 struct ath11k_base *ab = ab_pci->ab;201 u32 user_base_data, base_vector;202 int ret, num_vectors, i;203 int *irq;204 unsigned int msi_data;205 206 ret = ath11k_pcic_get_user_msi_assignment(ab, "MHI", &num_vectors,207 &user_base_data, &base_vector);208 if (ret)209 return ret;210 211 ath11k_dbg(ab, ATH11K_DBG_PCI, "num_vectors %d base_vector %d\n",212 num_vectors, base_vector);213 214 irq = kcalloc(num_vectors, sizeof(int), GFP_KERNEL);215 if (!irq)216 return -ENOMEM;217 218 for (i = 0; i < num_vectors; i++) {219 msi_data = base_vector;220 221 if (test_bit(ATH11K_FLAG_MULTI_MSI_VECTORS, &ab->dev_flags))222 msi_data += i;223 224 irq[i] = ath11k_pci_get_msi_irq(ab, msi_data);225 }226 227 ab_pci->mhi_ctrl->irq = irq;228 ab_pci->mhi_ctrl->nr_irqs = num_vectors;229 230 return 0;231}232 233static int ath11k_mhi_op_runtime_get(struct mhi_controller *mhi_cntrl)234{235 return 0;236}237 238static void ath11k_mhi_op_runtime_put(struct mhi_controller *mhi_cntrl)239{240}241 242static char *ath11k_mhi_op_callback_to_str(enum mhi_callback reason)243{244 switch (reason) {245 case MHI_CB_IDLE:246 return "MHI_CB_IDLE";247 case MHI_CB_PENDING_DATA:248 return "MHI_CB_PENDING_DATA";249 case MHI_CB_LPM_ENTER:250 return "MHI_CB_LPM_ENTER";251 case MHI_CB_LPM_EXIT:252 return "MHI_CB_LPM_EXIT";253 case MHI_CB_EE_RDDM:254 return "MHI_CB_EE_RDDM";255 case MHI_CB_EE_MISSION_MODE:256 return "MHI_CB_EE_MISSION_MODE";257 case MHI_CB_SYS_ERROR:258 return "MHI_CB_SYS_ERROR";259 case MHI_CB_FATAL_ERROR:260 return "MHI_CB_FATAL_ERROR";261 case MHI_CB_BW_REQ:262 return "MHI_CB_BW_REQ";263 default:264 return "UNKNOWN";265 }266};267 268static void ath11k_mhi_op_status_cb(struct mhi_controller *mhi_cntrl,269 enum mhi_callback cb)270{271 struct ath11k_base *ab = dev_get_drvdata(mhi_cntrl->cntrl_dev);272 struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);273 274 ath11k_dbg(ab, ATH11K_DBG_BOOT, "notify status reason %s\n",275 ath11k_mhi_op_callback_to_str(cb));276 277 switch (cb) {278 case MHI_CB_SYS_ERROR:279 ath11k_warn(ab, "firmware crashed: MHI_CB_SYS_ERROR\n");280 break;281 case MHI_CB_EE_RDDM:282 ath11k_warn(ab, "firmware crashed: MHI_CB_EE_RDDM\n");283 if (ab_pci->mhi_pre_cb == MHI_CB_EE_RDDM) {284 ath11k_dbg(ab, ATH11K_DBG_BOOT,285 "do not queue again for consecutive RDDM event\n");286 break;287 }288 289 if (!(test_bit(ATH11K_FLAG_UNREGISTERING, &ab->dev_flags)))290 queue_work(ab->workqueue_aux, &ab->reset_work);291 292 break;293 default:294 break;295 }296 297 ab_pci->mhi_pre_cb = cb;298}299 300static int ath11k_mhi_op_read_reg(struct mhi_controller *mhi_cntrl,301 void __iomem *addr,302 u32 *out)303{304 *out = readl(addr);305 306 return 0;307}308 309static void ath11k_mhi_op_write_reg(struct mhi_controller *mhi_cntrl,310 void __iomem *addr,311 u32 val)312{313 writel(val, addr);314}315 316static int ath11k_mhi_read_addr_from_dt(struct mhi_controller *mhi_ctrl)317{318 struct device_node *np;319 struct resource res;320 int ret;321 322 np = of_find_node_by_type(NULL, "memory");323 if (!np)324 return -ENOENT;325 326 ret = of_address_to_resource(np, 0, &res);327 of_node_put(np);328 if (ret)329 return ret;330 331 mhi_ctrl->iova_start = res.start + 0x1000000;332 mhi_ctrl->iova_stop = res.end;333 334 return 0;335}336 337int ath11k_mhi_register(struct ath11k_pci *ab_pci)338{339 struct ath11k_base *ab = ab_pci->ab;340 struct mhi_controller *mhi_ctrl;341 const struct mhi_controller_config *ath11k_mhi_config;342 int ret;343 344 mhi_ctrl = mhi_alloc_controller();345 if (!mhi_ctrl)346 return -ENOMEM;347 348 ab_pci->mhi_ctrl = mhi_ctrl;349 mhi_ctrl->cntrl_dev = ab->dev;350 mhi_ctrl->regs = ab->mem;351 mhi_ctrl->reg_len = ab->mem_len;352 353 if (ab->fw.amss_data && ab->fw.amss_len > 0) {354 /* use MHI firmware file from firmware-N.bin */355 mhi_ctrl->fw_data = ab->fw.amss_data;356 mhi_ctrl->fw_sz = ab->fw.amss_len;357 } else {358 /* use the old separate mhi.bin MHI firmware file */359 ath11k_core_create_firmware_path(ab, ATH11K_AMSS_FILE,360 ab_pci->amss_path,361 sizeof(ab_pci->amss_path));362 mhi_ctrl->fw_image = ab_pci->amss_path;363 }364 365 ret = ath11k_mhi_get_msi(ab_pci);366 if (ret) {367 ath11k_err(ab, "failed to get msi for mhi\n");368 goto free_controller;369 }370 371 if (!test_bit(ATH11K_FLAG_MULTI_MSI_VECTORS, &ab->dev_flags))372 mhi_ctrl->irq_flags = IRQF_SHARED | IRQF_NOBALANCING;373 374 if (test_bit(ATH11K_FLAG_FIXED_MEM_RGN, &ab->dev_flags)) {375 ret = ath11k_mhi_read_addr_from_dt(mhi_ctrl);376 if (ret < 0)377 goto free_controller;378 } else {379 mhi_ctrl->iova_start = 0;380 mhi_ctrl->iova_stop = ab_pci->dma_mask;381 }382 383 mhi_ctrl->rddm_size = RDDM_DUMP_SIZE;384 mhi_ctrl->sbl_size = SZ_512K;385 mhi_ctrl->seg_len = SZ_512K;386 mhi_ctrl->fbc_download = true;387 mhi_ctrl->runtime_get = ath11k_mhi_op_runtime_get;388 mhi_ctrl->runtime_put = ath11k_mhi_op_runtime_put;389 mhi_ctrl->status_cb = ath11k_mhi_op_status_cb;390 mhi_ctrl->read_reg = ath11k_mhi_op_read_reg;391 mhi_ctrl->write_reg = ath11k_mhi_op_write_reg;392 393 switch (ab->hw_rev) {394 case ATH11K_HW_QCN9074_HW10:395 ath11k_mhi_config = &ath11k_mhi_config_qcn9074;396 break;397 case ATH11K_HW_QCA6390_HW20:398 case ATH11K_HW_WCN6855_HW20:399 case ATH11K_HW_WCN6855_HW21:400 case ATH11K_HW_QCA2066_HW21:401 ath11k_mhi_config = &ath11k_mhi_config_qca6390;402 break;403 default:404 ath11k_err(ab, "failed assign mhi_config for unknown hw rev %d\n",405 ab->hw_rev);406 ret = -EINVAL;407 goto free_controller;408 }409 410 ab_pci->mhi_pre_cb = MHI_CB_INVALID;411 ret = mhi_register_controller(mhi_ctrl, ath11k_mhi_config);412 if (ret) {413 ath11k_err(ab, "failed to register to mhi bus, err = %d\n", ret);414 goto free_controller;415 }416 417 return 0;418 419free_controller:420 mhi_free_controller(mhi_ctrl);421 ab_pci->mhi_ctrl = NULL;422 return ret;423}424 425void ath11k_mhi_unregister(struct ath11k_pci *ab_pci)426{427 struct mhi_controller *mhi_ctrl = ab_pci->mhi_ctrl;428 429 mhi_unregister_controller(mhi_ctrl);430 kfree(mhi_ctrl->irq);431 mhi_free_controller(mhi_ctrl);432}433 434int ath11k_mhi_start(struct ath11k_pci *ab_pci)435{436 struct ath11k_base *ab = ab_pci->ab;437 int ret;438 439 ab_pci->mhi_ctrl->timeout_ms = MHI_TIMEOUT_DEFAULT_MS;440 441 ret = mhi_prepare_for_power_up(ab_pci->mhi_ctrl);442 if (ret) {443 ath11k_warn(ab, "failed to prepare mhi: %d", ret);444 return ret;445 }446 447 ret = mhi_sync_power_up(ab_pci->mhi_ctrl);448 if (ret) {449 ath11k_warn(ab, "failed to power up mhi: %d", ret);450 return ret;451 }452 453 return 0;454}455 456void ath11k_mhi_stop(struct ath11k_pci *ab_pci)457{458 mhi_power_down(ab_pci->mhi_ctrl, true);459 mhi_unprepare_after_power_down(ab_pci->mhi_ctrl);460}461 462int ath11k_mhi_suspend(struct ath11k_pci *ab_pci)463{464 struct ath11k_base *ab = ab_pci->ab;465 int ret;466 467 ret = mhi_pm_suspend(ab_pci->mhi_ctrl);468 if (ret) {469 ath11k_warn(ab, "failed to suspend mhi: %d", ret);470 return ret;471 }472 473 return 0;474}475 476int ath11k_mhi_resume(struct ath11k_pci *ab_pci)477{478 struct ath11k_base *ab = ab_pci->ab;479 int ret;480 481 /* Do force MHI resume as some devices like QCA6390, WCN6855482 * are not in M3 state but they are functional. So just ignore483 * the MHI state while resuming.484 */485 ret = mhi_pm_resume_force(ab_pci->mhi_ctrl);486 if (ret) {487 ath11k_warn(ab, "failed to resume mhi: %d", ret);488 return ret;489 }490 491 return 0;492}493