brintos

brintos / linux-shallow public Read only

0
0
Text · 16.1 KiB · a7bb9da Raw
696 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Qualcomm Wireless Connectivity Subsystem Peripheral Image Loader4 *5 * Copyright (C) 2016 Linaro Ltd6 * Copyright (C) 2014 Sony Mobile Communications AB7 * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.8 */9 10#include <linux/clk.h>11#include <linux/delay.h>12#include <linux/firmware.h>13#include <linux/interrupt.h>14#include <linux/kernel.h>15#include <linux/module.h>16#include <linux/io.h>17#include <linux/of.h>18#include <linux/of_reserved_mem.h>19#include <linux/platform_device.h>20#include <linux/pm_domain.h>21#include <linux/pm_runtime.h>22#include <linux/firmware/qcom/qcom_scm.h>23#include <linux/regulator/consumer.h>24#include <linux/remoteproc.h>25#include <linux/soc/qcom/mdt_loader.h>26#include <linux/soc/qcom/smem.h>27#include <linux/soc/qcom/smem_state.h>28 29#include "qcom_common.h"30#include "remoteproc_internal.h"31#include "qcom_pil_info.h"32#include "qcom_wcnss.h"33 34#define WCNSS_CRASH_REASON_SMEM		42235#define WCNSS_FIRMWARE_NAME		"wcnss.mdt"36#define WCNSS_PAS_ID			637#define WCNSS_SSCTL_ID			0x1338 39#define WCNSS_SPARE_NVBIN_DLND		BIT(25)40 41#define WCNSS_PMU_IRIS_XO_CFG		BIT(3)42#define WCNSS_PMU_IRIS_XO_EN		BIT(4)43#define WCNSS_PMU_GC_BUS_MUX_SEL_TOP	BIT(5)44#define WCNSS_PMU_IRIS_XO_CFG_STS	BIT(6) /* 1: in progress, 0: done */45 46#define WCNSS_PMU_IRIS_RESET		BIT(7)47#define WCNSS_PMU_IRIS_RESET_STS	BIT(8) /* 1: in progress, 0: done */48#define WCNSS_PMU_IRIS_XO_READ		BIT(9)49#define WCNSS_PMU_IRIS_XO_READ_STS	BIT(10)50 51#define WCNSS_PMU_XO_MODE_MASK		GENMASK(2, 1)52#define WCNSS_PMU_XO_MODE_19p2		053#define WCNSS_PMU_XO_MODE_48		354 55#define WCNSS_MAX_PDS			256 57struct wcnss_data {58	size_t pmu_offset;59	size_t spare_offset;60 61	const char *pd_names[WCNSS_MAX_PDS];62	const struct wcnss_vreg_info *vregs;63	size_t num_vregs, num_pd_vregs;64};65 66struct qcom_wcnss {67	struct device *dev;68	struct rproc *rproc;69 70	void __iomem *pmu_cfg;71	void __iomem *spare_out;72 73	bool use_48mhz_xo;74 75	int wdog_irq;76	int fatal_irq;77	int ready_irq;78	int handover_irq;79	int stop_ack_irq;80 81	struct qcom_smem_state *state;82	unsigned stop_bit;83 84	struct mutex iris_lock;85	struct qcom_iris *iris;86 87	struct device *pds[WCNSS_MAX_PDS];88	size_t num_pds;89	struct regulator_bulk_data *vregs;90	size_t num_vregs;91 92	struct completion start_done;93	struct completion stop_done;94 95	phys_addr_t mem_phys;96	phys_addr_t mem_reloc;97	void *mem_region;98	size_t mem_size;99 100	struct qcom_rproc_subdev smd_subdev;101	struct qcom_sysmon *sysmon;102};103 104static const struct wcnss_data riva_data = {105	.pmu_offset = 0x28,106	.spare_offset = 0xb4,107 108	.vregs = (struct wcnss_vreg_info[]) {109		{ "vddmx",  1050000, 1150000, 0 },110		{ "vddcx",  1050000, 1150000, 0 },111		{ "vddpx",  1800000, 1800000, 0 },112	},113	.num_vregs = 3,114};115 116static const struct wcnss_data pronto_v1_data = {117	.pmu_offset = 0x1004,118	.spare_offset = 0x1088,119 120	.pd_names = { "mx", "cx" },121	.vregs = (struct wcnss_vreg_info[]) {122		{ "vddmx", 950000, 1150000, 0 },123		{ "vddcx", .super_turbo = true},124		{ "vddpx", 1800000, 1800000, 0 },125	},126	.num_pd_vregs = 2,127	.num_vregs = 1,128};129 130static const struct wcnss_data pronto_v2_data = {131	.pmu_offset = 0x1004,132	.spare_offset = 0x1088,133 134	.pd_names = { "mx", "cx" },135	.vregs = (struct wcnss_vreg_info[]) {136		{ "vddmx", 1287500, 1287500, 0 },137		{ "vddcx", .super_turbo = true },138		{ "vddpx", 1800000, 1800000, 0 },139	},140	.num_pd_vregs = 2,141	.num_vregs = 1,142};143 144static const struct wcnss_data pronto_v3_data = {145	.pmu_offset = 0x1004,146	.spare_offset = 0x1088,147 148	.pd_names = { "mx", "cx" },149	.vregs = (struct wcnss_vreg_info[]) {150		{ "vddpx", 1800000, 1800000, 0 },151	},152	.num_vregs = 1,153};154 155static int wcnss_load(struct rproc *rproc, const struct firmware *fw)156{157	struct qcom_wcnss *wcnss = rproc->priv;158	int ret;159 160	ret = qcom_mdt_load(wcnss->dev, fw, rproc->firmware, WCNSS_PAS_ID,161			    wcnss->mem_region, wcnss->mem_phys,162			    wcnss->mem_size, &wcnss->mem_reloc);163	if (ret)164		return ret;165 166	qcom_pil_info_store("wcnss", wcnss->mem_phys, wcnss->mem_size);167 168	return 0;169}170 171static void wcnss_indicate_nv_download(struct qcom_wcnss *wcnss)172{173	u32 val;174 175	/* Indicate NV download capability */176	val = readl(wcnss->spare_out);177	val |= WCNSS_SPARE_NVBIN_DLND;178	writel(val, wcnss->spare_out);179}180 181static void wcnss_configure_iris(struct qcom_wcnss *wcnss)182{183	u32 val;184 185	/* Clear PMU cfg register */186	writel(0, wcnss->pmu_cfg);187 188	val = WCNSS_PMU_GC_BUS_MUX_SEL_TOP | WCNSS_PMU_IRIS_XO_EN;189	writel(val, wcnss->pmu_cfg);190 191	/* Clear XO_MODE */192	val &= ~WCNSS_PMU_XO_MODE_MASK;193	if (wcnss->use_48mhz_xo)194		val |= WCNSS_PMU_XO_MODE_48 << 1;195	else196		val |= WCNSS_PMU_XO_MODE_19p2 << 1;197	writel(val, wcnss->pmu_cfg);198 199	/* Reset IRIS */200	val |= WCNSS_PMU_IRIS_RESET;201	writel(val, wcnss->pmu_cfg);202 203	/* Wait for PMU.iris_reg_reset_sts */204	while (readl(wcnss->pmu_cfg) & WCNSS_PMU_IRIS_RESET_STS)205		cpu_relax();206 207	/* Clear IRIS reset */208	val &= ~WCNSS_PMU_IRIS_RESET;209	writel(val, wcnss->pmu_cfg);210 211	/* Start IRIS XO configuration */212	val |= WCNSS_PMU_IRIS_XO_CFG;213	writel(val, wcnss->pmu_cfg);214 215	/* Wait for XO configuration to finish */216	while (readl(wcnss->pmu_cfg) & WCNSS_PMU_IRIS_XO_CFG_STS)217		cpu_relax();218 219	/* Stop IRIS XO configuration */220	val &= ~WCNSS_PMU_GC_BUS_MUX_SEL_TOP;221	val &= ~WCNSS_PMU_IRIS_XO_CFG;222	writel(val, wcnss->pmu_cfg);223 224	/* Add some delay for XO to settle */225	msleep(20);226}227 228static int wcnss_start(struct rproc *rproc)229{230	struct qcom_wcnss *wcnss = rproc->priv;231	int ret, i;232 233	mutex_lock(&wcnss->iris_lock);234	if (!wcnss->iris) {235		dev_err(wcnss->dev, "no iris registered\n");236		ret = -EINVAL;237		goto release_iris_lock;238	}239 240	for (i = 0; i < wcnss->num_pds; i++) {241		dev_pm_genpd_set_performance_state(wcnss->pds[i], INT_MAX);242		ret = pm_runtime_get_sync(wcnss->pds[i]);243		if (ret < 0) {244			pm_runtime_put_noidle(wcnss->pds[i]);245			goto disable_pds;246		}247	}248 249	ret = regulator_bulk_enable(wcnss->num_vregs, wcnss->vregs);250	if (ret)251		goto disable_pds;252 253	ret = qcom_iris_enable(wcnss->iris);254	if (ret)255		goto disable_regulators;256 257	wcnss_indicate_nv_download(wcnss);258	wcnss_configure_iris(wcnss);259 260	ret = qcom_scm_pas_auth_and_reset(WCNSS_PAS_ID);261	if (ret) {262		dev_err(wcnss->dev,263			"failed to authenticate image and release reset\n");264		goto disable_iris;265	}266 267	ret = wait_for_completion_timeout(&wcnss->start_done,268					  msecs_to_jiffies(5000));269	if (wcnss->ready_irq > 0 && ret == 0) {270		/* We have a ready_irq, but it didn't fire in time. */271		dev_err(wcnss->dev, "start timed out\n");272		qcom_scm_pas_shutdown(WCNSS_PAS_ID);273		ret = -ETIMEDOUT;274		goto disable_iris;275	}276 277	ret = 0;278 279disable_iris:280	qcom_iris_disable(wcnss->iris);281disable_regulators:282	regulator_bulk_disable(wcnss->num_vregs, wcnss->vregs);283disable_pds:284	for (i--; i >= 0; i--) {285		pm_runtime_put(wcnss->pds[i]);286		dev_pm_genpd_set_performance_state(wcnss->pds[i], 0);287	}288release_iris_lock:289	mutex_unlock(&wcnss->iris_lock);290 291	return ret;292}293 294static int wcnss_stop(struct rproc *rproc)295{296	struct qcom_wcnss *wcnss = rproc->priv;297	int ret;298 299	if (wcnss->state) {300		qcom_smem_state_update_bits(wcnss->state,301					    BIT(wcnss->stop_bit),302					    BIT(wcnss->stop_bit));303 304		ret = wait_for_completion_timeout(&wcnss->stop_done,305						  msecs_to_jiffies(5000));306		if (ret == 0)307			dev_err(wcnss->dev, "timed out on wait\n");308 309		qcom_smem_state_update_bits(wcnss->state,310					    BIT(wcnss->stop_bit),311					    0);312	}313 314	ret = qcom_scm_pas_shutdown(WCNSS_PAS_ID);315	if (ret)316		dev_err(wcnss->dev, "failed to shutdown: %d\n", ret);317 318	return ret;319}320 321static void *wcnss_da_to_va(struct rproc *rproc, u64 da, size_t len, bool *is_iomem)322{323	struct qcom_wcnss *wcnss = rproc->priv;324	int offset;325 326	offset = da - wcnss->mem_reloc;327	if (offset < 0 || offset + len > wcnss->mem_size)328		return NULL;329 330	return wcnss->mem_region + offset;331}332 333static const struct rproc_ops wcnss_ops = {334	.start = wcnss_start,335	.stop = wcnss_stop,336	.da_to_va = wcnss_da_to_va,337	.parse_fw = qcom_register_dump_segments,338	.load = wcnss_load,339};340 341static irqreturn_t wcnss_wdog_interrupt(int irq, void *dev)342{343	struct qcom_wcnss *wcnss = dev;344 345	rproc_report_crash(wcnss->rproc, RPROC_WATCHDOG);346 347	return IRQ_HANDLED;348}349 350static irqreturn_t wcnss_fatal_interrupt(int irq, void *dev)351{352	struct qcom_wcnss *wcnss = dev;353	size_t len;354	char *msg;355 356	msg = qcom_smem_get(QCOM_SMEM_HOST_ANY, WCNSS_CRASH_REASON_SMEM, &len);357	if (!IS_ERR(msg) && len > 0 && msg[0])358		dev_err(wcnss->dev, "fatal error received: %s\n", msg);359 360	rproc_report_crash(wcnss->rproc, RPROC_FATAL_ERROR);361 362	return IRQ_HANDLED;363}364 365static irqreturn_t wcnss_ready_interrupt(int irq, void *dev)366{367	struct qcom_wcnss *wcnss = dev;368 369	complete(&wcnss->start_done);370 371	return IRQ_HANDLED;372}373 374static irqreturn_t wcnss_handover_interrupt(int irq, void *dev)375{376	/*377	 * XXX: At this point we're supposed to release the resources that we378	 * have been holding on behalf of the WCNSS. Unfortunately this379	 * interrupt comes way before the other side seems to be done.380	 *381	 * So we're currently relying on the ready interrupt firing later then382	 * this and we just disable the resources at the end of wcnss_start().383	 */384 385	return IRQ_HANDLED;386}387 388static irqreturn_t wcnss_stop_ack_interrupt(int irq, void *dev)389{390	struct qcom_wcnss *wcnss = dev;391 392	complete(&wcnss->stop_done);393 394	return IRQ_HANDLED;395}396 397static int wcnss_init_pds(struct qcom_wcnss *wcnss,398			  const char * const pd_names[WCNSS_MAX_PDS])399{400	int i, ret;401 402	for (i = 0; i < WCNSS_MAX_PDS; i++) {403		if (!pd_names[i])404			break;405 406		wcnss->pds[i] = dev_pm_domain_attach_by_name(wcnss->dev, pd_names[i]);407		if (IS_ERR_OR_NULL(wcnss->pds[i])) {408			ret = PTR_ERR(wcnss->pds[i]) ? : -ENODATA;409			for (i--; i >= 0; i--)410				dev_pm_domain_detach(wcnss->pds[i], false);411			return ret;412		}413	}414	wcnss->num_pds = i;415 416	return 0;417}418 419static void wcnss_release_pds(struct qcom_wcnss *wcnss)420{421	int i;422 423	for (i = 0; i < wcnss->num_pds; i++)424		dev_pm_domain_detach(wcnss->pds[i], false);425}426 427static int wcnss_init_regulators(struct qcom_wcnss *wcnss,428				 const struct wcnss_vreg_info *info,429				 int num_vregs, int num_pd_vregs)430{431	struct regulator_bulk_data *bulk;432	int ret;433	int i;434 435	/*436	 * If attaching the power domains suceeded we can skip requesting437	 * the regulators for the power domains. For old device trees we need to438	 * reserve extra space to manage them through the regulator interface.439	 */440	if (wcnss->num_pds)441		info += num_pd_vregs;442	else443		num_vregs += num_pd_vregs;444 445	bulk = devm_kcalloc(wcnss->dev,446			    num_vregs, sizeof(struct regulator_bulk_data),447			    GFP_KERNEL);448	if (!bulk)449		return -ENOMEM;450 451	for (i = 0; i < num_vregs; i++)452		bulk[i].supply = info[i].name;453 454	ret = devm_regulator_bulk_get(wcnss->dev, num_vregs, bulk);455	if (ret)456		return ret;457 458	for (i = 0; i < num_vregs; i++) {459		if (info[i].max_voltage)460			regulator_set_voltage(bulk[i].consumer,461					      info[i].min_voltage,462					      info[i].max_voltage);463 464		if (info[i].load_uA)465			regulator_set_load(bulk[i].consumer, info[i].load_uA);466	}467 468	wcnss->vregs = bulk;469	wcnss->num_vregs = num_vregs;470 471	return 0;472}473 474static int wcnss_request_irq(struct qcom_wcnss *wcnss,475			     struct platform_device *pdev,476			     const char *name,477			     bool optional,478			     irq_handler_t thread_fn)479{480	int ret;481	int irq_number;482 483	ret = platform_get_irq_byname(pdev, name);484	if (ret < 0 && optional) {485		dev_dbg(&pdev->dev, "no %s IRQ defined, ignoring\n", name);486		return 0;487	} else if (ret < 0) {488		dev_err(&pdev->dev, "no %s IRQ defined\n", name);489		return ret;490	}491 492	irq_number = ret;493 494	ret = devm_request_threaded_irq(&pdev->dev, ret,495					NULL, thread_fn,496					IRQF_TRIGGER_RISING | IRQF_ONESHOT,497					"wcnss", wcnss);498	if (ret) {499		dev_err(&pdev->dev, "request %s IRQ failed\n", name);500		return ret;501	}502 503	/* Return the IRQ number if the IRQ was successfully acquired */504	return irq_number;505}506 507static int wcnss_alloc_memory_region(struct qcom_wcnss *wcnss)508{509	struct reserved_mem *rmem = NULL;510	struct device_node *node;511 512	node = of_parse_phandle(wcnss->dev->of_node, "memory-region", 0);513	if (node)514		rmem = of_reserved_mem_lookup(node);515	of_node_put(node);516 517	if (!rmem) {518		dev_err(wcnss->dev, "unable to resolve memory-region\n");519		return -EINVAL;520	}521 522	wcnss->mem_phys = wcnss->mem_reloc = rmem->base;523	wcnss->mem_size = rmem->size;524	wcnss->mem_region = devm_ioremap_wc(wcnss->dev, wcnss->mem_phys, wcnss->mem_size);525	if (!wcnss->mem_region) {526		dev_err(wcnss->dev, "unable to map memory region: %pa+%zx\n",527			&rmem->base, wcnss->mem_size);528		return -EBUSY;529	}530 531	return 0;532}533 534static int wcnss_probe(struct platform_device *pdev)535{536	const char *fw_name = WCNSS_FIRMWARE_NAME;537	const struct wcnss_data *data;538	struct qcom_wcnss *wcnss;539	struct rproc *rproc;540	void __iomem *mmio;541	int ret;542 543	data = of_device_get_match_data(&pdev->dev);544 545	if (!qcom_scm_is_available())546		return -EPROBE_DEFER;547 548	if (!qcom_scm_pas_supported(WCNSS_PAS_ID)) {549		dev_err(&pdev->dev, "PAS is not available for WCNSS\n");550		return -ENXIO;551	}552 553	ret = of_property_read_string(pdev->dev.of_node, "firmware-name",554				      &fw_name);555	if (ret < 0 && ret != -EINVAL)556		return ret;557 558	rproc = devm_rproc_alloc(&pdev->dev, pdev->name, &wcnss_ops,559				 fw_name, sizeof(*wcnss));560	if (!rproc) {561		dev_err(&pdev->dev, "unable to allocate remoteproc\n");562		return -ENOMEM;563	}564	rproc_coredump_set_elf_info(rproc, ELFCLASS32, EM_NONE);565 566	wcnss = rproc->priv;567	wcnss->dev = &pdev->dev;568	wcnss->rproc = rproc;569	platform_set_drvdata(pdev, wcnss);570 571	init_completion(&wcnss->start_done);572	init_completion(&wcnss->stop_done);573 574	mutex_init(&wcnss->iris_lock);575 576	mmio = devm_platform_ioremap_resource_byname(pdev, "pmu");577	if (IS_ERR(mmio))578		return PTR_ERR(mmio);579 580	ret = wcnss_alloc_memory_region(wcnss);581	if (ret)582		return ret;583 584	wcnss->pmu_cfg = mmio + data->pmu_offset;585	wcnss->spare_out = mmio + data->spare_offset;586 587	/*588	 * We might need to fallback to regulators instead of power domains589	 * for old device trees. Don't report an error in that case.590	 */591	ret = wcnss_init_pds(wcnss, data->pd_names);592	if (ret && (ret != -ENODATA || !data->num_pd_vregs))593		return ret;594 595	ret = wcnss_init_regulators(wcnss, data->vregs, data->num_vregs,596				    data->num_pd_vregs);597	if (ret)598		goto detach_pds;599 600	ret = wcnss_request_irq(wcnss, pdev, "wdog", false, wcnss_wdog_interrupt);601	if (ret < 0)602		goto detach_pds;603	wcnss->wdog_irq = ret;604 605	ret = wcnss_request_irq(wcnss, pdev, "fatal", false, wcnss_fatal_interrupt);606	if (ret < 0)607		goto detach_pds;608	wcnss->fatal_irq = ret;609 610	ret = wcnss_request_irq(wcnss, pdev, "ready", true, wcnss_ready_interrupt);611	if (ret < 0)612		goto detach_pds;613	wcnss->ready_irq = ret;614 615	ret = wcnss_request_irq(wcnss, pdev, "handover", true, wcnss_handover_interrupt);616	if (ret < 0)617		goto detach_pds;618	wcnss->handover_irq = ret;619 620	ret = wcnss_request_irq(wcnss, pdev, "stop-ack", true, wcnss_stop_ack_interrupt);621	if (ret < 0)622		goto detach_pds;623	wcnss->stop_ack_irq = ret;624 625	if (wcnss->stop_ack_irq) {626		wcnss->state = devm_qcom_smem_state_get(&pdev->dev, "stop",627							&wcnss->stop_bit);628		if (IS_ERR(wcnss->state)) {629			ret = PTR_ERR(wcnss->state);630			goto detach_pds;631		}632	}633 634	qcom_add_smd_subdev(rproc, &wcnss->smd_subdev);635	wcnss->sysmon = qcom_add_sysmon_subdev(rproc, "wcnss", WCNSS_SSCTL_ID);636	if (IS_ERR(wcnss->sysmon)) {637		ret = PTR_ERR(wcnss->sysmon);638		goto detach_pds;639	}640 641	wcnss->iris = qcom_iris_probe(&pdev->dev, &wcnss->use_48mhz_xo);642	if (IS_ERR(wcnss->iris)) {643		ret = PTR_ERR(wcnss->iris);644		goto detach_pds;645	}646 647	ret = rproc_add(rproc);648	if (ret)649		goto remove_iris;650 651	return 0;652 653remove_iris:654	qcom_iris_remove(wcnss->iris);655detach_pds:656	wcnss_release_pds(wcnss);657 658	return ret;659}660 661static void wcnss_remove(struct platform_device *pdev)662{663	struct qcom_wcnss *wcnss = platform_get_drvdata(pdev);664 665	qcom_iris_remove(wcnss->iris);666 667	rproc_del(wcnss->rproc);668 669	qcom_remove_sysmon_subdev(wcnss->sysmon);670	qcom_remove_smd_subdev(wcnss->rproc, &wcnss->smd_subdev);671	wcnss_release_pds(wcnss);672}673 674static const struct of_device_id wcnss_of_match[] = {675	{ .compatible = "qcom,riva-pil", &riva_data },676	{ .compatible = "qcom,pronto-v1-pil", &pronto_v1_data },677	{ .compatible = "qcom,pronto-v2-pil", &pronto_v2_data },678	{ .compatible = "qcom,pronto-v3-pil", &pronto_v3_data },679	{ },680};681MODULE_DEVICE_TABLE(of, wcnss_of_match);682 683static struct platform_driver wcnss_driver = {684	.probe = wcnss_probe,685	.remove_new = wcnss_remove,686	.driver = {687		.name = "qcom-wcnss-pil",688		.of_match_table = wcnss_of_match,689	},690};691 692module_platform_driver(wcnss_driver);693 694MODULE_DESCRIPTION("Qualcomm Peripheral Image Loader for Wireless Subsystem");695MODULE_LICENSE("GPL v2");696