613 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2 3/* Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. */4/* Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */5 6#include <linux/delay.h>7#include <linux/err.h>8#include <linux/memblock.h>9#include <linux/mhi.h>10#include <linux/moduleparam.h>11#include <linux/pci.h>12#include <linux/sizes.h>13 14#include "mhi_controller.h"15#include "qaic.h"16 17#define MAX_RESET_TIME_SEC 2518 19static unsigned int mhi_timeout_ms = 2000; /* 2 sec default */20module_param(mhi_timeout_ms, uint, 0600);21MODULE_PARM_DESC(mhi_timeout_ms, "MHI controller timeout value");22 23static const struct mhi_channel_config aic100_channels[] = {24 {25 .name = "QAIC_LOOPBACK",26 .num = 0,27 .num_elements = 32,28 .local_elements = 0,29 .event_ring = 0,30 .dir = DMA_TO_DEVICE,31 .ee_mask = MHI_CH_EE_AMSS,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 .wake_capable = false,39 },40 {41 .name = "QAIC_LOOPBACK",42 .num = 1,43 .num_elements = 32,44 .local_elements = 0,45 .event_ring = 0,46 .dir = DMA_FROM_DEVICE,47 .ee_mask = MHI_CH_EE_AMSS,48 .pollcfg = 0,49 .doorbell = MHI_DB_BRST_DISABLE,50 .lpm_notify = false,51 .offload_channel = false,52 .doorbell_mode_switch = false,53 .auto_queue = false,54 .wake_capable = false,55 },56 {57 .name = "QAIC_SAHARA",58 .num = 2,59 .num_elements = 32,60 .local_elements = 0,61 .event_ring = 0,62 .dir = DMA_TO_DEVICE,63 .ee_mask = MHI_CH_EE_SBL,64 .pollcfg = 0,65 .doorbell = MHI_DB_BRST_DISABLE,66 .lpm_notify = false,67 .offload_channel = false,68 .doorbell_mode_switch = false,69 .auto_queue = false,70 .wake_capable = false,71 },72 {73 .name = "QAIC_SAHARA",74 .num = 3,75 .num_elements = 32,76 .local_elements = 0,77 .event_ring = 0,78 .dir = DMA_FROM_DEVICE,79 .ee_mask = MHI_CH_EE_SBL,80 .pollcfg = 0,81 .doorbell = MHI_DB_BRST_DISABLE,82 .lpm_notify = false,83 .offload_channel = false,84 .doorbell_mode_switch = false,85 .auto_queue = false,86 .wake_capable = false,87 },88 {89 .name = "QAIC_DIAG",90 .num = 4,91 .num_elements = 32,92 .local_elements = 0,93 .event_ring = 0,94 .dir = DMA_TO_DEVICE,95 .ee_mask = MHI_CH_EE_AMSS,96 .pollcfg = 0,97 .doorbell = MHI_DB_BRST_DISABLE,98 .lpm_notify = false,99 .offload_channel = false,100 .doorbell_mode_switch = false,101 .auto_queue = false,102 .wake_capable = false,103 },104 {105 .name = "QAIC_DIAG",106 .num = 5,107 .num_elements = 32,108 .local_elements = 0,109 .event_ring = 0,110 .dir = DMA_FROM_DEVICE,111 .ee_mask = MHI_CH_EE_AMSS,112 .pollcfg = 0,113 .doorbell = MHI_DB_BRST_DISABLE,114 .lpm_notify = false,115 .offload_channel = false,116 .doorbell_mode_switch = false,117 .auto_queue = false,118 .wake_capable = false,119 },120 {121 .name = "QAIC_SSR",122 .num = 6,123 .num_elements = 32,124 .local_elements = 0,125 .event_ring = 0,126 .dir = DMA_TO_DEVICE,127 .ee_mask = MHI_CH_EE_AMSS,128 .pollcfg = 0,129 .doorbell = MHI_DB_BRST_DISABLE,130 .lpm_notify = false,131 .offload_channel = false,132 .doorbell_mode_switch = false,133 .auto_queue = false,134 .wake_capable = false,135 },136 {137 .name = "QAIC_SSR",138 .num = 7,139 .num_elements = 32,140 .local_elements = 0,141 .event_ring = 0,142 .dir = DMA_FROM_DEVICE,143 .ee_mask = MHI_CH_EE_AMSS,144 .pollcfg = 0,145 .doorbell = MHI_DB_BRST_DISABLE,146 .lpm_notify = false,147 .offload_channel = false,148 .doorbell_mode_switch = false,149 .auto_queue = false,150 .wake_capable = false,151 },152 {153 .name = "QAIC_QDSS",154 .num = 8,155 .num_elements = 32,156 .local_elements = 0,157 .event_ring = 0,158 .dir = DMA_TO_DEVICE,159 .ee_mask = MHI_CH_EE_AMSS,160 .pollcfg = 0,161 .doorbell = MHI_DB_BRST_DISABLE,162 .lpm_notify = false,163 .offload_channel = false,164 .doorbell_mode_switch = false,165 .auto_queue = false,166 .wake_capable = false,167 },168 {169 .name = "QAIC_QDSS",170 .num = 9,171 .num_elements = 32,172 .local_elements = 0,173 .event_ring = 0,174 .dir = DMA_FROM_DEVICE,175 .ee_mask = MHI_CH_EE_AMSS,176 .pollcfg = 0,177 .doorbell = MHI_DB_BRST_DISABLE,178 .lpm_notify = false,179 .offload_channel = false,180 .doorbell_mode_switch = false,181 .auto_queue = false,182 .wake_capable = false,183 },184 {185 .name = "QAIC_CONTROL",186 .num = 10,187 .num_elements = 128,188 .local_elements = 0,189 .event_ring = 0,190 .dir = DMA_TO_DEVICE,191 .ee_mask = MHI_CH_EE_AMSS,192 .pollcfg = 0,193 .doorbell = MHI_DB_BRST_DISABLE,194 .lpm_notify = false,195 .offload_channel = false,196 .doorbell_mode_switch = false,197 .auto_queue = false,198 .wake_capable = false,199 },200 {201 .name = "QAIC_CONTROL",202 .num = 11,203 .num_elements = 128,204 .local_elements = 0,205 .event_ring = 0,206 .dir = DMA_FROM_DEVICE,207 .ee_mask = MHI_CH_EE_AMSS,208 .pollcfg = 0,209 .doorbell = MHI_DB_BRST_DISABLE,210 .lpm_notify = false,211 .offload_channel = false,212 .doorbell_mode_switch = false,213 .auto_queue = false,214 .wake_capable = false,215 },216 {217 .name = "QAIC_LOGGING",218 .num = 12,219 .num_elements = 32,220 .local_elements = 0,221 .event_ring = 0,222 .dir = DMA_TO_DEVICE,223 .ee_mask = MHI_CH_EE_SBL,224 .pollcfg = 0,225 .doorbell = MHI_DB_BRST_DISABLE,226 .lpm_notify = false,227 .offload_channel = false,228 .doorbell_mode_switch = false,229 .auto_queue = false,230 .wake_capable = false,231 },232 {233 .name = "QAIC_LOGGING",234 .num = 13,235 .num_elements = 32,236 .local_elements = 0,237 .event_ring = 0,238 .dir = DMA_FROM_DEVICE,239 .ee_mask = MHI_CH_EE_SBL,240 .pollcfg = 0,241 .doorbell = MHI_DB_BRST_DISABLE,242 .lpm_notify = false,243 .offload_channel = false,244 .doorbell_mode_switch = false,245 .auto_queue = false,246 .wake_capable = false,247 },248 {249 .name = "QAIC_STATUS",250 .num = 14,251 .num_elements = 32,252 .local_elements = 0,253 .event_ring = 0,254 .dir = DMA_TO_DEVICE,255 .ee_mask = MHI_CH_EE_AMSS,256 .pollcfg = 0,257 .doorbell = MHI_DB_BRST_DISABLE,258 .lpm_notify = false,259 .offload_channel = false,260 .doorbell_mode_switch = false,261 .auto_queue = false,262 .wake_capable = false,263 },264 {265 .name = "QAIC_STATUS",266 .num = 15,267 .num_elements = 32,268 .local_elements = 0,269 .event_ring = 0,270 .dir = DMA_FROM_DEVICE,271 .ee_mask = MHI_CH_EE_AMSS,272 .pollcfg = 0,273 .doorbell = MHI_DB_BRST_DISABLE,274 .lpm_notify = false,275 .offload_channel = false,276 .doorbell_mode_switch = false,277 .auto_queue = false,278 .wake_capable = false,279 },280 {281 .name = "QAIC_TELEMETRY",282 .num = 16,283 .num_elements = 32,284 .local_elements = 0,285 .event_ring = 0,286 .dir = DMA_TO_DEVICE,287 .ee_mask = MHI_CH_EE_AMSS,288 .pollcfg = 0,289 .doorbell = MHI_DB_BRST_DISABLE,290 .lpm_notify = false,291 .offload_channel = false,292 .doorbell_mode_switch = false,293 .auto_queue = false,294 .wake_capable = false,295 },296 {297 .name = "QAIC_TELEMETRY",298 .num = 17,299 .num_elements = 32,300 .local_elements = 0,301 .event_ring = 0,302 .dir = DMA_FROM_DEVICE,303 .ee_mask = MHI_CH_EE_AMSS,304 .pollcfg = 0,305 .doorbell = MHI_DB_BRST_DISABLE,306 .lpm_notify = false,307 .offload_channel = false,308 .doorbell_mode_switch = false,309 .auto_queue = false,310 .wake_capable = false,311 },312 {313 .name = "QAIC_DEBUG",314 .num = 18,315 .num_elements = 32,316 .local_elements = 0,317 .event_ring = 0,318 .dir = DMA_TO_DEVICE,319 .ee_mask = MHI_CH_EE_AMSS,320 .pollcfg = 0,321 .doorbell = MHI_DB_BRST_DISABLE,322 .lpm_notify = false,323 .offload_channel = false,324 .doorbell_mode_switch = false,325 .auto_queue = false,326 .wake_capable = false,327 },328 {329 .name = "QAIC_DEBUG",330 .num = 19,331 .num_elements = 32,332 .local_elements = 0,333 .event_ring = 0,334 .dir = DMA_FROM_DEVICE,335 .ee_mask = MHI_CH_EE_AMSS,336 .pollcfg = 0,337 .doorbell = MHI_DB_BRST_DISABLE,338 .lpm_notify = false,339 .offload_channel = false,340 .doorbell_mode_switch = false,341 .auto_queue = false,342 .wake_capable = false,343 },344 {345 .name = "QAIC_TIMESYNC",346 .num = 20,347 .num_elements = 32,348 .local_elements = 0,349 .event_ring = 0,350 .dir = DMA_TO_DEVICE,351 .ee_mask = MHI_CH_EE_SBL,352 .pollcfg = 0,353 .doorbell = MHI_DB_BRST_DISABLE,354 .lpm_notify = false,355 .offload_channel = false,356 .doorbell_mode_switch = false,357 .auto_queue = false,358 .wake_capable = false,359 },360 {361 .name = "QAIC_TIMESYNC",362 .num = 21,363 .num_elements = 32,364 .local_elements = 0,365 .event_ring = 0,366 .dir = DMA_FROM_DEVICE,367 .ee_mask = MHI_CH_EE_SBL,368 .pollcfg = 0,369 .doorbell = MHI_DB_BRST_DISABLE,370 .lpm_notify = false,371 .offload_channel = false,372 .doorbell_mode_switch = false,373 .auto_queue = false,374 .wake_capable = false,375 },376 {377 .name = "QAIC_TIMESYNC_PERIODIC",378 .num = 22,379 .num_elements = 32,380 .local_elements = 0,381 .event_ring = 0,382 .dir = DMA_TO_DEVICE,383 .ee_mask = MHI_CH_EE_AMSS,384 .pollcfg = 0,385 .doorbell = MHI_DB_BRST_DISABLE,386 .lpm_notify = false,387 .offload_channel = false,388 .doorbell_mode_switch = false,389 .auto_queue = false,390 .wake_capable = false,391 },392 {393 .name = "QAIC_TIMESYNC_PERIODIC",394 .num = 23,395 .num_elements = 32,396 .local_elements = 0,397 .event_ring = 0,398 .dir = DMA_FROM_DEVICE,399 .ee_mask = MHI_CH_EE_AMSS,400 .pollcfg = 0,401 .doorbell = MHI_DB_BRST_DISABLE,402 .lpm_notify = false,403 .offload_channel = false,404 .doorbell_mode_switch = false,405 .auto_queue = false,406 .wake_capable = false,407 },408};409 410static struct mhi_event_config aic100_events[] = {411 {412 .num_elements = 32,413 .irq_moderation_ms = 0,414 .irq = 0,415 .channel = U32_MAX,416 .priority = 1,417 .mode = MHI_DB_BRST_DISABLE,418 .data_type = MHI_ER_CTRL,419 .hardware_event = false,420 .client_managed = false,421 .offload_channel = false,422 },423};424 425static struct mhi_controller_config aic100_config = {426 .max_channels = 128,427 .timeout_ms = 0, /* controlled by mhi_timeout */428 .buf_len = 0,429 .num_channels = ARRAY_SIZE(aic100_channels),430 .ch_cfg = aic100_channels,431 .num_events = ARRAY_SIZE(aic100_events),432 .event_cfg = aic100_events,433 .use_bounce_buf = false,434 .m2_no_db = false,435};436 437static int mhi_read_reg(struct mhi_controller *mhi_cntrl, void __iomem *addr, u32 *out)438{439 u32 tmp;440 441 /*442 * SOC_HW_VERSION quirk443 * The SOC_HW_VERSION register (offset 0x224) is not reliable and444 * may contain uninitialized values, including 0xFFFFFFFF. This could445 * cause a false positive link down error. Instead, intercept any446 * reads and provide the correct value of the register.447 */448 if (addr - mhi_cntrl->regs == 0x224) {449 *out = 0x60110200;450 return 0;451 }452 453 tmp = readl_relaxed(addr);454 if (tmp == U32_MAX)455 return -EIO;456 457 *out = tmp;458 459 return 0;460}461 462static void mhi_write_reg(struct mhi_controller *mhi_cntrl, void __iomem *addr, u32 val)463{464 writel_relaxed(val, addr);465}466 467static int mhi_runtime_get(struct mhi_controller *mhi_cntrl)468{469 return 0;470}471 472static void mhi_runtime_put(struct mhi_controller *mhi_cntrl)473{474}475 476static void mhi_status_cb(struct mhi_controller *mhi_cntrl, enum mhi_callback reason)477{478 struct qaic_device *qdev = pci_get_drvdata(to_pci_dev(mhi_cntrl->cntrl_dev));479 480 /* this event occurs in atomic context */481 if (reason == MHI_CB_FATAL_ERROR)482 pci_err(qdev->pdev, "Fatal error received from device. Attempting to recover\n");483 /* this event occurs in non-atomic context */484 if (reason == MHI_CB_SYS_ERROR)485 qaic_dev_reset_clean_local_state(qdev);486}487 488static int mhi_reset_and_async_power_up(struct mhi_controller *mhi_cntrl)489{490 u8 time_sec = 1;491 int current_ee;492 int ret;493 494 /* Reset the device to bring the device in PBL EE */495 mhi_soc_reset(mhi_cntrl);496 497 /*498 * Keep checking the execution environment(EE) after every 1 second499 * interval.500 */501 do {502 msleep(1000);503 current_ee = mhi_get_exec_env(mhi_cntrl);504 } while (current_ee != MHI_EE_PBL && time_sec++ <= MAX_RESET_TIME_SEC);505 506 /* If the device is in PBL EE retry power up */507 if (current_ee == MHI_EE_PBL)508 ret = mhi_async_power_up(mhi_cntrl);509 else510 ret = -EIO;511 512 return ret;513}514 515struct mhi_controller *qaic_mhi_register_controller(struct pci_dev *pci_dev, void __iomem *mhi_bar,516 int mhi_irq, bool shared_msi)517{518 struct mhi_controller *mhi_cntrl;519 int ret;520 521 mhi_cntrl = devm_kzalloc(&pci_dev->dev, sizeof(*mhi_cntrl), GFP_KERNEL);522 if (!mhi_cntrl)523 return ERR_PTR(-ENOMEM);524 525 mhi_cntrl->cntrl_dev = &pci_dev->dev;526 527 /*528 * Covers the entire possible physical ram region. Remote side is529 * going to calculate a size of this range, so subtract 1 to prevent530 * rollover.531 */532 mhi_cntrl->iova_start = 0;533 mhi_cntrl->iova_stop = PHYS_ADDR_MAX - 1;534 mhi_cntrl->status_cb = mhi_status_cb;535 mhi_cntrl->runtime_get = mhi_runtime_get;536 mhi_cntrl->runtime_put = mhi_runtime_put;537 mhi_cntrl->read_reg = mhi_read_reg;538 mhi_cntrl->write_reg = mhi_write_reg;539 mhi_cntrl->regs = mhi_bar;540 mhi_cntrl->reg_len = SZ_4K;541 mhi_cntrl->nr_irqs = 1;542 mhi_cntrl->irq = devm_kmalloc(&pci_dev->dev, sizeof(*mhi_cntrl->irq), GFP_KERNEL);543 544 if (!mhi_cntrl->irq)545 return ERR_PTR(-ENOMEM);546 547 mhi_cntrl->irq[0] = mhi_irq;548 549 if (shared_msi) /* MSI shared with data path, no IRQF_NO_SUSPEND */550 mhi_cntrl->irq_flags = IRQF_SHARED;551 552 mhi_cntrl->fw_image = "qcom/aic100/sbl.bin";553 554 /* use latest configured timeout */555 aic100_config.timeout_ms = mhi_timeout_ms;556 ret = mhi_register_controller(mhi_cntrl, &aic100_config);557 if (ret) {558 pci_err(pci_dev, "mhi_register_controller failed %d\n", ret);559 return ERR_PTR(ret);560 }561 562 ret = mhi_prepare_for_power_up(mhi_cntrl);563 if (ret) {564 pci_err(pci_dev, "mhi_prepare_for_power_up failed %d\n", ret);565 goto prepare_power_up_fail;566 }567 568 ret = mhi_async_power_up(mhi_cntrl);569 /*570 * If EIO is returned it is possible that device is in SBL EE, which is571 * undesired. SOC reset the device and try to power up again.572 */573 if (ret == -EIO && MHI_EE_SBL == mhi_get_exec_env(mhi_cntrl)) {574 pci_err(pci_dev, "Found device in SBL at MHI init. Attempting a reset.\n");575 ret = mhi_reset_and_async_power_up(mhi_cntrl);576 }577 578 if (ret) {579 pci_err(pci_dev, "mhi_async_power_up failed %d\n", ret);580 goto power_up_fail;581 }582 583 return mhi_cntrl;584 585power_up_fail:586 mhi_unprepare_after_power_down(mhi_cntrl);587prepare_power_up_fail:588 mhi_unregister_controller(mhi_cntrl);589 return ERR_PTR(ret);590}591 592void qaic_mhi_free_controller(struct mhi_controller *mhi_cntrl, bool link_up)593{594 mhi_power_down(mhi_cntrl, link_up);595 mhi_unprepare_after_power_down(mhi_cntrl);596 mhi_unregister_controller(mhi_cntrl);597}598 599void qaic_mhi_start_reset(struct mhi_controller *mhi_cntrl)600{601 mhi_power_down(mhi_cntrl, true);602}603 604void qaic_mhi_reset_done(struct mhi_controller *mhi_cntrl)605{606 struct pci_dev *pci_dev = container_of(mhi_cntrl->cntrl_dev, struct pci_dev, dev);607 int ret;608 609 ret = mhi_async_power_up(mhi_cntrl);610 if (ret)611 pci_err(pci_dev, "mhi_async_power_up failed after reset %d\n", ret);612}613