brintos

brintos / linux-shallow public Read only

0
0
Text · 11.1 KiB · 6974a55 Raw
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