brintos

brintos / linux-shallow public Read only

0
0
Text · 14.0 KiB · ada9b1e Raw
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