Linux Audio

Check our new training course

Loading...
Note: File does not exist in v4.6.
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Qualcomm ADSP/SLPI Peripheral Image Loader for MSM8974 and MSM8996
   4 *
   5 * Copyright (C) 2016 Linaro Ltd
   6 * Copyright (C) 2014 Sony Mobile Communications AB
   7 * 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/of.h>
  17#include <linux/of_address.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 "qcom_pil_info.h"
  31#include "qcom_q6v5.h"
  32#include "remoteproc_internal.h"
  33
  34#define ADSP_DECRYPT_SHUTDOWN_DELAY_MS	100
  35
  36struct adsp_data {
  37	int crash_reason_smem;
  38	const char *firmware_name;
  39	const char *dtb_firmware_name;
  40	int pas_id;
  41	int dtb_pas_id;
  42	unsigned int minidump_id;
  43	bool auto_boot;
  44	bool decrypt_shutdown;
  45
  46	char **proxy_pd_names;
  47
  48	const char *load_state;
  49	const char *ssr_name;
  50	const char *sysmon_name;
  51	int ssctl_id;
  52
  53	int region_assign_idx;
  54};
  55
  56struct qcom_adsp {
  57	struct device *dev;
  58	struct rproc *rproc;
  59
  60	struct qcom_q6v5 q6v5;
  61
  62	struct clk *xo;
  63	struct clk *aggre2_clk;
  64
  65	struct regulator *cx_supply;
  66	struct regulator *px_supply;
  67
  68	struct device *proxy_pds[3];
  69
  70	int proxy_pd_count;
  71
  72	const char *dtb_firmware_name;
  73	int pas_id;
  74	int dtb_pas_id;
  75	unsigned int minidump_id;
  76	int crash_reason_smem;
  77	bool decrypt_shutdown;
  78	const char *info_name;
  79
  80	const struct firmware *firmware;
  81	const struct firmware *dtb_firmware;
  82
  83	struct completion start_done;
  84	struct completion stop_done;
  85
  86	phys_addr_t mem_phys;
  87	phys_addr_t dtb_mem_phys;
  88	phys_addr_t mem_reloc;
  89	phys_addr_t dtb_mem_reloc;
  90	phys_addr_t region_assign_phys;
  91	void *mem_region;
  92	void *dtb_mem_region;
  93	size_t mem_size;
  94	size_t dtb_mem_size;
  95	size_t region_assign_size;
  96
  97	int region_assign_idx;
  98	u64 region_assign_perms;
  99
 100	struct qcom_rproc_glink glink_subdev;
 101	struct qcom_rproc_subdev smd_subdev;
 102	struct qcom_rproc_ssr ssr_subdev;
 103	struct qcom_sysmon *sysmon;
 104
 105	struct qcom_scm_pas_metadata pas_metadata;
 106	struct qcom_scm_pas_metadata dtb_pas_metadata;
 107};
 108
 109static void adsp_segment_dump(struct rproc *rproc, struct rproc_dump_segment *segment,
 110		       void *dest, size_t offset, size_t size)
 111{
 112	struct qcom_adsp *adsp = rproc->priv;
 113	int total_offset;
 114
 115	total_offset = segment->da + segment->offset + offset - adsp->mem_phys;
 116	if (total_offset < 0 || total_offset + size > adsp->mem_size) {
 117		dev_err(adsp->dev,
 118			"invalid copy request for segment %pad with offset %zu and size %zu)\n",
 119			&segment->da, offset, size);
 120		memset(dest, 0xff, size);
 121		return;
 122	}
 123
 124	memcpy_fromio(dest, adsp->mem_region + total_offset, size);
 125}
 126
 127static void adsp_minidump(struct rproc *rproc)
 128{
 129	struct qcom_adsp *adsp = rproc->priv;
 130
 131	if (rproc->dump_conf == RPROC_COREDUMP_DISABLED)
 132		return;
 133
 134	qcom_minidump(rproc, adsp->minidump_id, adsp_segment_dump);
 135}
 136
 137static int adsp_pds_enable(struct qcom_adsp *adsp, struct device **pds,
 138			   size_t pd_count)
 139{
 140	int ret;
 141	int i;
 142
 143	for (i = 0; i < pd_count; i++) {
 144		dev_pm_genpd_set_performance_state(pds[i], INT_MAX);
 145		ret = pm_runtime_get_sync(pds[i]);
 146		if (ret < 0) {
 147			pm_runtime_put_noidle(pds[i]);
 148			dev_pm_genpd_set_performance_state(pds[i], 0);
 149			goto unroll_pd_votes;
 150		}
 151	}
 152
 153	return 0;
 154
 155unroll_pd_votes:
 156	for (i--; i >= 0; i--) {
 157		dev_pm_genpd_set_performance_state(pds[i], 0);
 158		pm_runtime_put(pds[i]);
 159	}
 160
 161	return ret;
 162};
 163
 164static void adsp_pds_disable(struct qcom_adsp *adsp, struct device **pds,
 165			     size_t pd_count)
 166{
 167	int i;
 168
 169	for (i = 0; i < pd_count; i++) {
 170		dev_pm_genpd_set_performance_state(pds[i], 0);
 171		pm_runtime_put(pds[i]);
 172	}
 173}
 174
 175static int adsp_shutdown_poll_decrypt(struct qcom_adsp *adsp)
 176{
 177	unsigned int retry_num = 50;
 178	int ret;
 179
 180	do {
 181		msleep(ADSP_DECRYPT_SHUTDOWN_DELAY_MS);
 182		ret = qcom_scm_pas_shutdown(adsp->pas_id);
 183	} while (ret == -EINVAL && --retry_num);
 184
 185	return ret;
 186}
 187
 188static int adsp_unprepare(struct rproc *rproc)
 189{
 190	struct qcom_adsp *adsp = rproc->priv;
 191
 192	/*
 193	 * adsp_load() did pass pas_metadata to the SCM driver for storing
 194	 * metadata context. It might have been released already if
 195	 * auth_and_reset() was successful, but in other cases clean it up
 196	 * here.
 197	 */
 198	qcom_scm_pas_metadata_release(&adsp->pas_metadata);
 199	if (adsp->dtb_pas_id)
 200		qcom_scm_pas_metadata_release(&adsp->dtb_pas_metadata);
 201
 202	return 0;
 203}
 204
 205static int adsp_load(struct rproc *rproc, const struct firmware *fw)
 206{
 207	struct qcom_adsp *adsp = rproc->priv;
 208	int ret;
 209
 210	/* Store firmware handle to be used in adsp_start() */
 211	adsp->firmware = fw;
 212
 213	if (adsp->dtb_pas_id) {
 214		ret = request_firmware(&adsp->dtb_firmware, adsp->dtb_firmware_name, adsp->dev);
 215		if (ret) {
 216			dev_err(adsp->dev, "request_firmware failed for %s: %d\n",
 217				adsp->dtb_firmware_name, ret);
 218			return ret;
 219		}
 220
 221		ret = qcom_mdt_pas_init(adsp->dev, adsp->dtb_firmware, adsp->dtb_firmware_name,
 222					adsp->dtb_pas_id, adsp->dtb_mem_phys,
 223					&adsp->dtb_pas_metadata);
 224		if (ret)
 225			goto release_dtb_firmware;
 226
 227		ret = qcom_mdt_load_no_init(adsp->dev, adsp->dtb_firmware, adsp->dtb_firmware_name,
 228					    adsp->dtb_pas_id, adsp->dtb_mem_region,
 229					    adsp->dtb_mem_phys, adsp->dtb_mem_size,
 230					    &adsp->dtb_mem_reloc);
 231		if (ret)
 232			goto release_dtb_metadata;
 233	}
 234
 235	return 0;
 236
 237release_dtb_metadata:
 238	qcom_scm_pas_metadata_release(&adsp->dtb_pas_metadata);
 239
 240release_dtb_firmware:
 241	release_firmware(adsp->dtb_firmware);
 242
 243	return ret;
 244}
 245
 246static int adsp_start(struct rproc *rproc)
 247{
 248	struct qcom_adsp *adsp = rproc->priv;
 249	int ret;
 250
 251	ret = qcom_q6v5_prepare(&adsp->q6v5);
 252	if (ret)
 253		return ret;
 254
 255	ret = adsp_pds_enable(adsp, adsp->proxy_pds, adsp->proxy_pd_count);
 256	if (ret < 0)
 257		goto disable_irqs;
 258
 259	ret = clk_prepare_enable(adsp->xo);
 260	if (ret)
 261		goto disable_proxy_pds;
 262
 263	ret = clk_prepare_enable(adsp->aggre2_clk);
 264	if (ret)
 265		goto disable_xo_clk;
 266
 267	if (adsp->cx_supply) {
 268		ret = regulator_enable(adsp->cx_supply);
 269		if (ret)
 270			goto disable_aggre2_clk;
 271	}
 272
 273	if (adsp->px_supply) {
 274		ret = regulator_enable(adsp->px_supply);
 275		if (ret)
 276			goto disable_cx_supply;
 277	}
 278
 279	if (adsp->dtb_pas_id) {
 280		ret = qcom_scm_pas_auth_and_reset(adsp->dtb_pas_id);
 281		if (ret) {
 282			dev_err(adsp->dev,
 283				"failed to authenticate dtb image and release reset\n");
 284			goto disable_px_supply;
 285		}
 286	}
 287
 288	ret = qcom_mdt_pas_init(adsp->dev, adsp->firmware, rproc->firmware, adsp->pas_id,
 289				adsp->mem_phys, &adsp->pas_metadata);
 290	if (ret)
 291		goto disable_px_supply;
 292
 293	ret = qcom_mdt_load_no_init(adsp->dev, adsp->firmware, rproc->firmware, adsp->pas_id,
 294				    adsp->mem_region, adsp->mem_phys, adsp->mem_size,
 295				    &adsp->mem_reloc);
 296	if (ret)
 297		goto release_pas_metadata;
 298
 299	qcom_pil_info_store(adsp->info_name, adsp->mem_phys, adsp->mem_size);
 300
 301	ret = qcom_scm_pas_auth_and_reset(adsp->pas_id);
 302	if (ret) {
 303		dev_err(adsp->dev,
 304			"failed to authenticate image and release reset\n");
 305		goto release_pas_metadata;
 306	}
 307
 308	ret = qcom_q6v5_wait_for_start(&adsp->q6v5, msecs_to_jiffies(5000));
 309	if (ret == -ETIMEDOUT) {
 310		dev_err(adsp->dev, "start timed out\n");
 311		qcom_scm_pas_shutdown(adsp->pas_id);
 312		goto release_pas_metadata;
 313	}
 314
 315	qcom_scm_pas_metadata_release(&adsp->pas_metadata);
 316	if (adsp->dtb_pas_id)
 317		qcom_scm_pas_metadata_release(&adsp->dtb_pas_metadata);
 318
 319	/* Remove pointer to the loaded firmware, only valid in adsp_load() & adsp_start() */
 320	adsp->firmware = NULL;
 321
 322	return 0;
 323
 324release_pas_metadata:
 325	qcom_scm_pas_metadata_release(&adsp->pas_metadata);
 326	if (adsp->dtb_pas_id)
 327		qcom_scm_pas_metadata_release(&adsp->dtb_pas_metadata);
 328disable_px_supply:
 329	if (adsp->px_supply)
 330		regulator_disable(adsp->px_supply);
 331disable_cx_supply:
 332	if (adsp->cx_supply)
 333		regulator_disable(adsp->cx_supply);
 334disable_aggre2_clk:
 335	clk_disable_unprepare(adsp->aggre2_clk);
 336disable_xo_clk:
 337	clk_disable_unprepare(adsp->xo);
 338disable_proxy_pds:
 339	adsp_pds_disable(adsp, adsp->proxy_pds, adsp->proxy_pd_count);
 340disable_irqs:
 341	qcom_q6v5_unprepare(&adsp->q6v5);
 342
 343	/* Remove pointer to the loaded firmware, only valid in adsp_load() & adsp_start() */
 344	adsp->firmware = NULL;
 345
 346	return ret;
 347}
 348
 349static void qcom_pas_handover(struct qcom_q6v5 *q6v5)
 350{
 351	struct qcom_adsp *adsp = container_of(q6v5, struct qcom_adsp, q6v5);
 352
 353	if (adsp->px_supply)
 354		regulator_disable(adsp->px_supply);
 355	if (adsp->cx_supply)
 356		regulator_disable(adsp->cx_supply);
 357	clk_disable_unprepare(adsp->aggre2_clk);
 358	clk_disable_unprepare(adsp->xo);
 359	adsp_pds_disable(adsp, adsp->proxy_pds, adsp->proxy_pd_count);
 360}
 361
 362static int adsp_stop(struct rproc *rproc)
 363{
 364	struct qcom_adsp *adsp = rproc->priv;
 365	int handover;
 366	int ret;
 367
 368	ret = qcom_q6v5_request_stop(&adsp->q6v5, adsp->sysmon);
 369	if (ret == -ETIMEDOUT)
 370		dev_err(adsp->dev, "timed out on wait\n");
 371
 372	ret = qcom_scm_pas_shutdown(adsp->pas_id);
 373	if (ret && adsp->decrypt_shutdown)
 374		ret = adsp_shutdown_poll_decrypt(adsp);
 375
 376	if (ret)
 377		dev_err(adsp->dev, "failed to shutdown: %d\n", ret);
 378
 379	if (adsp->dtb_pas_id) {
 380		ret = qcom_scm_pas_shutdown(adsp->dtb_pas_id);
 381		if (ret)
 382			dev_err(adsp->dev, "failed to shutdown dtb: %d\n", ret);
 383	}
 384
 385	handover = qcom_q6v5_unprepare(&adsp->q6v5);
 386	if (handover)
 387		qcom_pas_handover(&adsp->q6v5);
 388
 389	return ret;
 390}
 391
 392static void *adsp_da_to_va(struct rproc *rproc, u64 da, size_t len, bool *is_iomem)
 393{
 394	struct qcom_adsp *adsp = rproc->priv;
 395	int offset;
 396
 397	offset = da - adsp->mem_reloc;
 398	if (offset < 0 || offset + len > adsp->mem_size)
 399		return NULL;
 400
 401	if (is_iomem)
 402		*is_iomem = true;
 403
 404	return adsp->mem_region + offset;
 405}
 406
 407static unsigned long adsp_panic(struct rproc *rproc)
 408{
 409	struct qcom_adsp *adsp = rproc->priv;
 410
 411	return qcom_q6v5_panic(&adsp->q6v5);
 412}
 413
 414static const struct rproc_ops adsp_ops = {
 415	.unprepare = adsp_unprepare,
 416	.start = adsp_start,
 417	.stop = adsp_stop,
 418	.da_to_va = adsp_da_to_va,
 419	.parse_fw = qcom_register_dump_segments,
 420	.load = adsp_load,
 421	.panic = adsp_panic,
 422};
 423
 424static const struct rproc_ops adsp_minidump_ops = {
 425	.unprepare = adsp_unprepare,
 426	.start = adsp_start,
 427	.stop = adsp_stop,
 428	.da_to_va = adsp_da_to_va,
 429	.parse_fw = qcom_register_dump_segments,
 430	.load = adsp_load,
 431	.panic = adsp_panic,
 432	.coredump = adsp_minidump,
 433};
 434
 435static int adsp_init_clock(struct qcom_adsp *adsp)
 436{
 437	int ret;
 438
 439	adsp->xo = devm_clk_get(adsp->dev, "xo");
 440	if (IS_ERR(adsp->xo)) {
 441		ret = PTR_ERR(adsp->xo);
 442		if (ret != -EPROBE_DEFER)
 443			dev_err(adsp->dev, "failed to get xo clock");
 444		return ret;
 445	}
 446
 447	adsp->aggre2_clk = devm_clk_get_optional(adsp->dev, "aggre2");
 448	if (IS_ERR(adsp->aggre2_clk)) {
 449		ret = PTR_ERR(adsp->aggre2_clk);
 450		if (ret != -EPROBE_DEFER)
 451			dev_err(adsp->dev,
 452				"failed to get aggre2 clock");
 453		return ret;
 454	}
 455
 456	return 0;
 457}
 458
 459static int adsp_init_regulator(struct qcom_adsp *adsp)
 460{
 461	adsp->cx_supply = devm_regulator_get_optional(adsp->dev, "cx");
 462	if (IS_ERR(adsp->cx_supply)) {
 463		if (PTR_ERR(adsp->cx_supply) == -ENODEV)
 464			adsp->cx_supply = NULL;
 465		else
 466			return PTR_ERR(adsp->cx_supply);
 467	}
 468
 469	if (adsp->cx_supply)
 470		regulator_set_load(adsp->cx_supply, 100000);
 471
 472	adsp->px_supply = devm_regulator_get_optional(adsp->dev, "px");
 473	if (IS_ERR(adsp->px_supply)) {
 474		if (PTR_ERR(adsp->px_supply) == -ENODEV)
 475			adsp->px_supply = NULL;
 476		else
 477			return PTR_ERR(adsp->px_supply);
 478	}
 479
 480	return 0;
 481}
 482
 483static int adsp_pds_attach(struct device *dev, struct device **devs,
 484			   char **pd_names)
 485{
 486	size_t num_pds = 0;
 487	int ret;
 488	int i;
 489
 490	if (!pd_names)
 491		return 0;
 492
 493	/* Handle single power domain */
 494	if (dev->pm_domain) {
 495		devs[0] = dev;
 496		pm_runtime_enable(dev);
 497		return 1;
 498	}
 499
 500	while (pd_names[num_pds])
 501		num_pds++;
 502
 503	for (i = 0; i < num_pds; i++) {
 504		devs[i] = dev_pm_domain_attach_by_name(dev, pd_names[i]);
 505		if (IS_ERR_OR_NULL(devs[i])) {
 506			ret = PTR_ERR(devs[i]) ? : -ENODATA;
 507			goto unroll_attach;
 508		}
 509	}
 510
 511	return num_pds;
 512
 513unroll_attach:
 514	for (i--; i >= 0; i--)
 515		dev_pm_domain_detach(devs[i], false);
 516
 517	return ret;
 518};
 519
 520static void adsp_pds_detach(struct qcom_adsp *adsp, struct device **pds,
 521			    size_t pd_count)
 522{
 523	struct device *dev = adsp->dev;
 524	int i;
 525
 526	/* Handle single power domain */
 527	if (dev->pm_domain && pd_count) {
 528		pm_runtime_disable(dev);
 529		return;
 530	}
 531
 532	for (i = 0; i < pd_count; i++)
 533		dev_pm_domain_detach(pds[i], false);
 534}
 535
 536static int adsp_alloc_memory_region(struct qcom_adsp *adsp)
 537{
 538	struct reserved_mem *rmem;
 539	struct device_node *node;
 540
 541	node = of_parse_phandle(adsp->dev->of_node, "memory-region", 0);
 542	if (!node) {
 543		dev_err(adsp->dev, "no memory-region specified\n");
 544		return -EINVAL;
 545	}
 546
 547	rmem = of_reserved_mem_lookup(node);
 548	of_node_put(node);
 549	if (!rmem) {
 550		dev_err(adsp->dev, "unable to resolve memory-region\n");
 551		return -EINVAL;
 552	}
 553
 554	adsp->mem_phys = adsp->mem_reloc = rmem->base;
 555	adsp->mem_size = rmem->size;
 556	adsp->mem_region = devm_ioremap_wc(adsp->dev, adsp->mem_phys, adsp->mem_size);
 557	if (!adsp->mem_region) {
 558		dev_err(adsp->dev, "unable to map memory region: %pa+%zx\n",
 559			&rmem->base, adsp->mem_size);
 560		return -EBUSY;
 561	}
 562
 563	if (!adsp->dtb_pas_id)
 564		return 0;
 565
 566	node = of_parse_phandle(adsp->dev->of_node, "memory-region", 1);
 567	if (!node) {
 568		dev_err(adsp->dev, "no dtb memory-region specified\n");
 569		return -EINVAL;
 570	}
 571
 572	rmem = of_reserved_mem_lookup(node);
 573	of_node_put(node);
 574	if (!rmem) {
 575		dev_err(adsp->dev, "unable to resolve dtb memory-region\n");
 576		return -EINVAL;
 577	}
 578
 579	adsp->dtb_mem_phys = adsp->dtb_mem_reloc = rmem->base;
 580	adsp->dtb_mem_size = rmem->size;
 581	adsp->dtb_mem_region = devm_ioremap_wc(adsp->dev, adsp->dtb_mem_phys, adsp->dtb_mem_size);
 582	if (!adsp->dtb_mem_region) {
 583		dev_err(adsp->dev, "unable to map dtb memory region: %pa+%zx\n",
 584			&rmem->base, adsp->dtb_mem_size);
 585		return -EBUSY;
 586	}
 587
 588	return 0;
 589}
 590
 591static int adsp_assign_memory_region(struct qcom_adsp *adsp)
 592{
 593	struct reserved_mem *rmem = NULL;
 594	struct qcom_scm_vmperm perm;
 595	struct device_node *node;
 596	int ret;
 597
 598	if (!adsp->region_assign_idx)
 599		return 0;
 600
 601	node = of_parse_phandle(adsp->dev->of_node, "memory-region", adsp->region_assign_idx);
 602	if (node)
 603		rmem = of_reserved_mem_lookup(node);
 604	of_node_put(node);
 605	if (!rmem) {
 606		dev_err(adsp->dev, "unable to resolve shareable memory-region\n");
 607		return -EINVAL;
 608	}
 609
 610	perm.vmid = QCOM_SCM_VMID_MSS_MSA;
 611	perm.perm = QCOM_SCM_PERM_RW;
 612
 613	adsp->region_assign_phys = rmem->base;
 614	adsp->region_assign_size = rmem->size;
 615	adsp->region_assign_perms = BIT(QCOM_SCM_VMID_HLOS);
 616
 617	ret = qcom_scm_assign_mem(adsp->region_assign_phys,
 618				  adsp->region_assign_size,
 619				  &adsp->region_assign_perms,
 620				  &perm, 1);
 621	if (ret < 0) {
 622		dev_err(adsp->dev, "assign memory failed\n");
 623		return ret;
 624	}
 625
 626	return 0;
 627}
 628
 629static void adsp_unassign_memory_region(struct qcom_adsp *adsp)
 630{
 631	struct qcom_scm_vmperm perm;
 632	int ret;
 633
 634	if (!adsp->region_assign_idx)
 635		return;
 636
 637	perm.vmid = QCOM_SCM_VMID_HLOS;
 638	perm.perm = QCOM_SCM_PERM_RW;
 639
 640	ret = qcom_scm_assign_mem(adsp->region_assign_phys,
 641				  adsp->region_assign_size,
 642				  &adsp->region_assign_perms,
 643				  &perm, 1);
 644	if (ret < 0)
 645		dev_err(adsp->dev, "unassign memory failed\n");
 646}
 647
 648static int adsp_probe(struct platform_device *pdev)
 649{
 650	const struct adsp_data *desc;
 651	struct qcom_adsp *adsp;
 652	struct rproc *rproc;
 653	const char *fw_name, *dtb_fw_name = NULL;
 654	const struct rproc_ops *ops = &adsp_ops;
 655	int ret;
 656
 657	desc = of_device_get_match_data(&pdev->dev);
 658	if (!desc)
 659		return -EINVAL;
 660
 661	if (!qcom_scm_is_available())
 662		return -EPROBE_DEFER;
 663
 664	fw_name = desc->firmware_name;
 665	ret = of_property_read_string(pdev->dev.of_node, "firmware-name",
 666				      &fw_name);
 667	if (ret < 0 && ret != -EINVAL)
 668		return ret;
 669
 670	if (desc->dtb_firmware_name) {
 671		dtb_fw_name = desc->dtb_firmware_name;
 672		ret = of_property_read_string_index(pdev->dev.of_node, "firmware-name", 1,
 673						    &dtb_fw_name);
 674		if (ret < 0 && ret != -EINVAL)
 675			return ret;
 676	}
 677
 678	if (desc->minidump_id)
 679		ops = &adsp_minidump_ops;
 680
 681	rproc = rproc_alloc(&pdev->dev, pdev->name, ops, fw_name, sizeof(*adsp));
 682
 683	if (!rproc) {
 684		dev_err(&pdev->dev, "unable to allocate remoteproc\n");
 685		return -ENOMEM;
 686	}
 687
 688	rproc->auto_boot = desc->auto_boot;
 689	rproc_coredump_set_elf_info(rproc, ELFCLASS32, EM_NONE);
 690
 691	adsp = rproc->priv;
 692	adsp->dev = &pdev->dev;
 693	adsp->rproc = rproc;
 694	adsp->minidump_id = desc->minidump_id;
 695	adsp->pas_id = desc->pas_id;
 696	adsp->info_name = desc->sysmon_name;
 697	adsp->decrypt_shutdown = desc->decrypt_shutdown;
 698	adsp->region_assign_idx = desc->region_assign_idx;
 699	if (dtb_fw_name) {
 700		adsp->dtb_firmware_name = dtb_fw_name;
 701		adsp->dtb_pas_id = desc->dtb_pas_id;
 702	}
 703	platform_set_drvdata(pdev, adsp);
 704
 705	ret = device_init_wakeup(adsp->dev, true);
 706	if (ret)
 707		goto free_rproc;
 708
 709	ret = adsp_alloc_memory_region(adsp);
 710	if (ret)
 711		goto free_rproc;
 712
 713	ret = adsp_assign_memory_region(adsp);
 714	if (ret)
 715		goto free_rproc;
 716
 717	ret = adsp_init_clock(adsp);
 718	if (ret)
 719		goto free_rproc;
 720
 721	ret = adsp_init_regulator(adsp);
 722	if (ret)
 723		goto free_rproc;
 724
 725	ret = adsp_pds_attach(&pdev->dev, adsp->proxy_pds,
 726			      desc->proxy_pd_names);
 727	if (ret < 0)
 728		goto free_rproc;
 729	adsp->proxy_pd_count = ret;
 730
 731	ret = qcom_q6v5_init(&adsp->q6v5, pdev, rproc, desc->crash_reason_smem, desc->load_state,
 732			     qcom_pas_handover);
 733	if (ret)
 734		goto detach_proxy_pds;
 735
 736	qcom_add_glink_subdev(rproc, &adsp->glink_subdev, desc->ssr_name);
 737	qcom_add_smd_subdev(rproc, &adsp->smd_subdev);
 738	adsp->sysmon = qcom_add_sysmon_subdev(rproc,
 739					      desc->sysmon_name,
 740					      desc->ssctl_id);
 741	if (IS_ERR(adsp->sysmon)) {
 742		ret = PTR_ERR(adsp->sysmon);
 743		goto detach_proxy_pds;
 744	}
 745
 746	qcom_add_ssr_subdev(rproc, &adsp->ssr_subdev, desc->ssr_name);
 747	ret = rproc_add(rproc);
 748	if (ret)
 749		goto detach_proxy_pds;
 750
 751	return 0;
 752
 753detach_proxy_pds:
 754	adsp_pds_detach(adsp, adsp->proxy_pds, adsp->proxy_pd_count);
 755free_rproc:
 756	device_init_wakeup(adsp->dev, false);
 757	rproc_free(rproc);
 758
 759	return ret;
 760}
 761
 762static void adsp_remove(struct platform_device *pdev)
 763{
 764	struct qcom_adsp *adsp = platform_get_drvdata(pdev);
 765
 766	rproc_del(adsp->rproc);
 767
 768	qcom_q6v5_deinit(&adsp->q6v5);
 769	adsp_unassign_memory_region(adsp);
 770	qcom_remove_glink_subdev(adsp->rproc, &adsp->glink_subdev);
 771	qcom_remove_sysmon_subdev(adsp->sysmon);
 772	qcom_remove_smd_subdev(adsp->rproc, &adsp->smd_subdev);
 773	qcom_remove_ssr_subdev(adsp->rproc, &adsp->ssr_subdev);
 774	adsp_pds_detach(adsp, adsp->proxy_pds, adsp->proxy_pd_count);
 775	device_init_wakeup(adsp->dev, false);
 776	rproc_free(adsp->rproc);
 777}
 778
 779static const struct adsp_data adsp_resource_init = {
 780		.crash_reason_smem = 423,
 781		.firmware_name = "adsp.mdt",
 782		.pas_id = 1,
 783		.auto_boot = true,
 784		.ssr_name = "lpass",
 785		.sysmon_name = "adsp",
 786		.ssctl_id = 0x14,
 787};
 788
 789static const struct adsp_data sdm845_adsp_resource_init = {
 790		.crash_reason_smem = 423,
 791		.firmware_name = "adsp.mdt",
 792		.pas_id = 1,
 793		.auto_boot = true,
 794		.load_state = "adsp",
 795		.ssr_name = "lpass",
 796		.sysmon_name = "adsp",
 797		.ssctl_id = 0x14,
 798};
 799
 800static const struct adsp_data sm6350_adsp_resource = {
 801	.crash_reason_smem = 423,
 802	.firmware_name = "adsp.mdt",
 803	.pas_id = 1,
 804	.auto_boot = true,
 805	.proxy_pd_names = (char*[]){
 806		"lcx",
 807		"lmx",
 808		NULL
 809	},
 810	.load_state = "adsp",
 811	.ssr_name = "lpass",
 812	.sysmon_name = "adsp",
 813	.ssctl_id = 0x14,
 814};
 815
 816static const struct adsp_data sm6375_mpss_resource = {
 817	.crash_reason_smem = 421,
 818	.firmware_name = "modem.mdt",
 819	.pas_id = 4,
 820	.minidump_id = 3,
 821	.auto_boot = false,
 822	.proxy_pd_names = (char*[]){
 823		"cx",
 824		NULL
 825	},
 826	.ssr_name = "mpss",
 827	.sysmon_name = "modem",
 828	.ssctl_id = 0x12,
 829};
 830
 831static const struct adsp_data sm8150_adsp_resource = {
 832		.crash_reason_smem = 423,
 833		.firmware_name = "adsp.mdt",
 834		.pas_id = 1,
 835		.auto_boot = true,
 836		.proxy_pd_names = (char*[]){
 837			"cx",
 838			NULL
 839		},
 840		.load_state = "adsp",
 841		.ssr_name = "lpass",
 842		.sysmon_name = "adsp",
 843		.ssctl_id = 0x14,
 844};
 845
 846static const struct adsp_data sm8250_adsp_resource = {
 847	.crash_reason_smem = 423,
 848	.firmware_name = "adsp.mdt",
 849	.pas_id = 1,
 850	.auto_boot = true,
 851	.proxy_pd_names = (char*[]){
 852		"lcx",
 853		"lmx",
 854		NULL
 855	},
 856	.load_state = "adsp",
 857	.ssr_name = "lpass",
 858	.sysmon_name = "adsp",
 859	.ssctl_id = 0x14,
 860};
 861
 862static const struct adsp_data sm8350_adsp_resource = {
 863	.crash_reason_smem = 423,
 864	.firmware_name = "adsp.mdt",
 865	.pas_id = 1,
 866	.auto_boot = true,
 867	.proxy_pd_names = (char*[]){
 868		"lcx",
 869		"lmx",
 870		NULL
 871	},
 872	.load_state = "adsp",
 873	.ssr_name = "lpass",
 874	.sysmon_name = "adsp",
 875	.ssctl_id = 0x14,
 876};
 877
 878static const struct adsp_data msm8996_adsp_resource = {
 879		.crash_reason_smem = 423,
 880		.firmware_name = "adsp.mdt",
 881		.pas_id = 1,
 882		.auto_boot = true,
 883		.proxy_pd_names = (char*[]){
 884			"cx",
 885			NULL
 886		},
 887		.ssr_name = "lpass",
 888		.sysmon_name = "adsp",
 889		.ssctl_id = 0x14,
 890};
 891
 892static const struct adsp_data cdsp_resource_init = {
 893	.crash_reason_smem = 601,
 894	.firmware_name = "cdsp.mdt",
 895	.pas_id = 18,
 896	.auto_boot = true,
 897	.ssr_name = "cdsp",
 898	.sysmon_name = "cdsp",
 899	.ssctl_id = 0x17,
 900};
 901
 902static const struct adsp_data sdm845_cdsp_resource_init = {
 903	.crash_reason_smem = 601,
 904	.firmware_name = "cdsp.mdt",
 905	.pas_id = 18,
 906	.auto_boot = true,
 907	.load_state = "cdsp",
 908	.ssr_name = "cdsp",
 909	.sysmon_name = "cdsp",
 910	.ssctl_id = 0x17,
 911};
 912
 913static const struct adsp_data sm6350_cdsp_resource = {
 914	.crash_reason_smem = 601,
 915	.firmware_name = "cdsp.mdt",
 916	.pas_id = 18,
 917	.auto_boot = true,
 918	.proxy_pd_names = (char*[]){
 919		"cx",
 920		"mx",
 921		NULL
 922	},
 923	.load_state = "cdsp",
 924	.ssr_name = "cdsp",
 925	.sysmon_name = "cdsp",
 926	.ssctl_id = 0x17,
 927};
 928
 929static const struct adsp_data sm8150_cdsp_resource = {
 930	.crash_reason_smem = 601,
 931	.firmware_name = "cdsp.mdt",
 932	.pas_id = 18,
 933	.auto_boot = true,
 934	.proxy_pd_names = (char*[]){
 935		"cx",
 936		NULL
 937	},
 938	.load_state = "cdsp",
 939	.ssr_name = "cdsp",
 940	.sysmon_name = "cdsp",
 941	.ssctl_id = 0x17,
 942};
 943
 944static const struct adsp_data sm8250_cdsp_resource = {
 945	.crash_reason_smem = 601,
 946	.firmware_name = "cdsp.mdt",
 947	.pas_id = 18,
 948	.auto_boot = true,
 949	.proxy_pd_names = (char*[]){
 950		"cx",
 951		NULL
 952	},
 953	.load_state = "cdsp",
 954	.ssr_name = "cdsp",
 955	.sysmon_name = "cdsp",
 956	.ssctl_id = 0x17,
 957};
 958
 959static const struct adsp_data sc8280xp_nsp0_resource = {
 960	.crash_reason_smem = 601,
 961	.firmware_name = "cdsp.mdt",
 962	.pas_id = 18,
 963	.auto_boot = true,
 964	.proxy_pd_names = (char*[]){
 965		"nsp",
 966		NULL
 967	},
 968	.ssr_name = "cdsp0",
 969	.sysmon_name = "cdsp",
 970	.ssctl_id = 0x17,
 971};
 972
 973static const struct adsp_data sc8280xp_nsp1_resource = {
 974	.crash_reason_smem = 633,
 975	.firmware_name = "cdsp.mdt",
 976	.pas_id = 30,
 977	.auto_boot = true,
 978	.proxy_pd_names = (char*[]){
 979		"nsp",
 980		NULL
 981	},
 982	.ssr_name = "cdsp1",
 983	.sysmon_name = "cdsp1",
 984	.ssctl_id = 0x20,
 985};
 986
 987static const struct adsp_data sm8350_cdsp_resource = {
 988	.crash_reason_smem = 601,
 989	.firmware_name = "cdsp.mdt",
 990	.pas_id = 18,
 991	.auto_boot = true,
 992	.proxy_pd_names = (char*[]){
 993		"cx",
 994		"mxc",
 995		NULL
 996	},
 997	.load_state = "cdsp",
 998	.ssr_name = "cdsp",
 999	.sysmon_name = "cdsp",
1000	.ssctl_id = 0x17,
1001};
1002
1003static const struct adsp_data mpss_resource_init = {
1004	.crash_reason_smem = 421,
1005	.firmware_name = "modem.mdt",
1006	.pas_id = 4,
1007	.minidump_id = 3,
1008	.auto_boot = false,
1009	.proxy_pd_names = (char*[]){
1010		"cx",
1011		"mss",
1012		NULL
1013	},
1014	.load_state = "modem",
1015	.ssr_name = "mpss",
1016	.sysmon_name = "modem",
1017	.ssctl_id = 0x12,
1018};
1019
1020static const struct adsp_data sc8180x_mpss_resource = {
1021	.crash_reason_smem = 421,
1022	.firmware_name = "modem.mdt",
1023	.pas_id = 4,
1024	.auto_boot = false,
1025	.proxy_pd_names = (char*[]){
1026		"cx",
1027		NULL
1028	},
1029	.load_state = "modem",
1030	.ssr_name = "mpss",
1031	.sysmon_name = "modem",
1032	.ssctl_id = 0x12,
1033};
1034
1035static const struct adsp_data msm8996_slpi_resource_init = {
1036		.crash_reason_smem = 424,
1037		.firmware_name = "slpi.mdt",
1038		.pas_id = 12,
1039		.auto_boot = true,
1040		.proxy_pd_names = (char*[]){
1041			"ssc_cx",
1042			NULL
1043		},
1044		.ssr_name = "dsps",
1045		.sysmon_name = "slpi",
1046		.ssctl_id = 0x16,
1047};
1048
1049static const struct adsp_data sdm845_slpi_resource_init = {
1050		.crash_reason_smem = 424,
1051		.firmware_name = "slpi.mdt",
1052		.pas_id = 12,
1053		.auto_boot = true,
1054		.proxy_pd_names = (char*[]){
1055			"lcx",
1056			"lmx",
1057			NULL
1058		},
1059		.load_state = "slpi",
1060		.ssr_name = "dsps",
1061		.sysmon_name = "slpi",
1062		.ssctl_id = 0x16,
1063};
1064
1065static const struct adsp_data wcss_resource_init = {
1066	.crash_reason_smem = 421,
1067	.firmware_name = "wcnss.mdt",
1068	.pas_id = 6,
1069	.auto_boot = true,
1070	.ssr_name = "mpss",
1071	.sysmon_name = "wcnss",
1072	.ssctl_id = 0x12,
1073};
1074
1075static const struct adsp_data sdx55_mpss_resource = {
1076	.crash_reason_smem = 421,
1077	.firmware_name = "modem.mdt",
1078	.pas_id = 4,
1079	.auto_boot = true,
1080	.proxy_pd_names = (char*[]){
1081		"cx",
1082		"mss",
1083		NULL
1084	},
1085	.ssr_name = "mpss",
1086	.sysmon_name = "modem",
1087	.ssctl_id = 0x22,
1088};
1089
1090static const struct adsp_data sm8450_mpss_resource = {
1091	.crash_reason_smem = 421,
1092	.firmware_name = "modem.mdt",
1093	.pas_id = 4,
1094	.minidump_id = 3,
1095	.auto_boot = false,
1096	.decrypt_shutdown = true,
1097	.proxy_pd_names = (char*[]){
1098		"cx",
1099		"mss",
1100		NULL
1101	},
1102	.load_state = "modem",
1103	.ssr_name = "mpss",
1104	.sysmon_name = "modem",
1105	.ssctl_id = 0x12,
1106};
1107
1108static const struct adsp_data sm8550_adsp_resource = {
1109	.crash_reason_smem = 423,
1110	.firmware_name = "adsp.mdt",
1111	.dtb_firmware_name = "adsp_dtb.mdt",
1112	.pas_id = 1,
1113	.dtb_pas_id = 0x24,
1114	.minidump_id = 5,
1115	.auto_boot = true,
1116	.proxy_pd_names = (char*[]){
1117		"lcx",
1118		"lmx",
1119		NULL
1120	},
1121	.load_state = "adsp",
1122	.ssr_name = "lpass",
1123	.sysmon_name = "adsp",
1124	.ssctl_id = 0x14,
1125};
1126
1127static const struct adsp_data sm8550_cdsp_resource = {
1128	.crash_reason_smem = 601,
1129	.firmware_name = "cdsp.mdt",
1130	.dtb_firmware_name = "cdsp_dtb.mdt",
1131	.pas_id = 18,
1132	.dtb_pas_id = 0x25,
1133	.minidump_id = 7,
1134	.auto_boot = true,
1135	.proxy_pd_names = (char*[]){
1136		"cx",
1137		"mxc",
1138		"nsp",
1139		NULL
1140	},
1141	.load_state = "cdsp",
1142	.ssr_name = "cdsp",
1143	.sysmon_name = "cdsp",
1144	.ssctl_id = 0x17,
1145};
1146
1147static const struct adsp_data sm8550_mpss_resource = {
1148	.crash_reason_smem = 421,
1149	.firmware_name = "modem.mdt",
1150	.dtb_firmware_name = "modem_dtb.mdt",
1151	.pas_id = 4,
1152	.dtb_pas_id = 0x26,
1153	.minidump_id = 3,
1154	.auto_boot = false,
1155	.decrypt_shutdown = true,
1156	.proxy_pd_names = (char*[]){
1157		"cx",
1158		"mss",
1159		NULL
1160	},
1161	.load_state = "modem",
1162	.ssr_name = "mpss",
1163	.sysmon_name = "modem",
1164	.ssctl_id = 0x12,
1165	.region_assign_idx = 2,
1166};
1167
1168static const struct adsp_data sc7280_wpss_resource = {
1169	.crash_reason_smem = 626,
1170	.firmware_name = "wpss.mdt",
1171	.pas_id = 6,
1172	.auto_boot = true,
1173	.proxy_pd_names = (char*[]){
1174		"cx",
1175		"mx",
1176		NULL
1177	},
1178	.load_state = "wpss",
1179	.ssr_name = "wpss",
1180	.sysmon_name = "wpss",
1181	.ssctl_id = 0x19,
1182};
1183
1184static const struct of_device_id adsp_of_match[] = {
1185	{ .compatible = "qcom,msm8226-adsp-pil", .data = &adsp_resource_init},
1186	{ .compatible = "qcom,msm8953-adsp-pil", .data = &msm8996_adsp_resource},
1187	{ .compatible = "qcom,msm8974-adsp-pil", .data = &adsp_resource_init},
1188	{ .compatible = "qcom,msm8996-adsp-pil", .data = &msm8996_adsp_resource},
1189	{ .compatible = "qcom,msm8996-slpi-pil", .data = &msm8996_slpi_resource_init},
1190	{ .compatible = "qcom,msm8998-adsp-pas", .data = &msm8996_adsp_resource},
1191	{ .compatible = "qcom,msm8998-slpi-pas", .data = &msm8996_slpi_resource_init},
1192	{ .compatible = "qcom,qcs404-adsp-pas", .data = &adsp_resource_init },
1193	{ .compatible = "qcom,qcs404-cdsp-pas", .data = &cdsp_resource_init },
1194	{ .compatible = "qcom,qcs404-wcss-pas", .data = &wcss_resource_init },
1195	{ .compatible = "qcom,sc7180-adsp-pas", .data = &sm8250_adsp_resource},
1196	{ .compatible = "qcom,sc7180-mpss-pas", .data = &mpss_resource_init},
1197	{ .compatible = "qcom,sc7280-adsp-pas", .data = &sm8350_adsp_resource},
1198	{ .compatible = "qcom,sc7280-cdsp-pas", .data = &sm6350_cdsp_resource},
1199	{ .compatible = "qcom,sc7280-mpss-pas", .data = &mpss_resource_init},
1200	{ .compatible = "qcom,sc7280-wpss-pas", .data = &sc7280_wpss_resource},
1201	{ .compatible = "qcom,sc8180x-adsp-pas", .data = &sm8150_adsp_resource},
1202	{ .compatible = "qcom,sc8180x-cdsp-pas", .data = &sm8150_cdsp_resource},
1203	{ .compatible = "qcom,sc8180x-mpss-pas", .data = &sc8180x_mpss_resource},
1204	{ .compatible = "qcom,sc8280xp-adsp-pas", .data = &sm8250_adsp_resource},
1205	{ .compatible = "qcom,sc8280xp-nsp0-pas", .data = &sc8280xp_nsp0_resource},
1206	{ .compatible = "qcom,sc8280xp-nsp1-pas", .data = &sc8280xp_nsp1_resource},
1207	{ .compatible = "qcom,sdm660-adsp-pas", .data = &adsp_resource_init},
1208	{ .compatible = "qcom,sdm845-adsp-pas", .data = &sdm845_adsp_resource_init},
1209	{ .compatible = "qcom,sdm845-cdsp-pas", .data = &sdm845_cdsp_resource_init},
1210	{ .compatible = "qcom,sdm845-slpi-pas", .data = &sdm845_slpi_resource_init},
1211	{ .compatible = "qcom,sdx55-mpss-pas", .data = &sdx55_mpss_resource},
1212	{ .compatible = "qcom,sm6115-adsp-pas", .data = &adsp_resource_init},
1213	{ .compatible = "qcom,sm6115-cdsp-pas", .data = &cdsp_resource_init},
1214	{ .compatible = "qcom,sm6115-mpss-pas", .data = &sc8180x_mpss_resource},
1215	{ .compatible = "qcom,sm6350-adsp-pas", .data = &sm6350_adsp_resource},
1216	{ .compatible = "qcom,sm6350-cdsp-pas", .data = &sm6350_cdsp_resource},
1217	{ .compatible = "qcom,sm6350-mpss-pas", .data = &mpss_resource_init},
1218	{ .compatible = "qcom,sm6375-adsp-pas", .data = &sm6350_adsp_resource},
1219	{ .compatible = "qcom,sm6375-cdsp-pas", .data = &sm8150_cdsp_resource},
1220	{ .compatible = "qcom,sm6375-mpss-pas", .data = &sm6375_mpss_resource},
1221	{ .compatible = "qcom,sm8150-adsp-pas", .data = &sm8150_adsp_resource},
1222	{ .compatible = "qcom,sm8150-cdsp-pas", .data = &sm8150_cdsp_resource},
1223	{ .compatible = "qcom,sm8150-mpss-pas", .data = &mpss_resource_init},
1224	{ .compatible = "qcom,sm8150-slpi-pas", .data = &sdm845_slpi_resource_init},
1225	{ .compatible = "qcom,sm8250-adsp-pas", .data = &sm8250_adsp_resource},
1226	{ .compatible = "qcom,sm8250-cdsp-pas", .data = &sm8250_cdsp_resource},
1227	{ .compatible = "qcom,sm8250-slpi-pas", .data = &sdm845_slpi_resource_init},
1228	{ .compatible = "qcom,sm8350-adsp-pas", .data = &sm8350_adsp_resource},
1229	{ .compatible = "qcom,sm8350-cdsp-pas", .data = &sm8350_cdsp_resource},
1230	{ .compatible = "qcom,sm8350-slpi-pas", .data = &sdm845_slpi_resource_init},
1231	{ .compatible = "qcom,sm8350-mpss-pas", .data = &mpss_resource_init},
1232	{ .compatible = "qcom,sm8450-adsp-pas", .data = &sm8350_adsp_resource},
1233	{ .compatible = "qcom,sm8450-cdsp-pas", .data = &sm8350_cdsp_resource},
1234	{ .compatible = "qcom,sm8450-slpi-pas", .data = &sdm845_slpi_resource_init},
1235	{ .compatible = "qcom,sm8450-mpss-pas", .data = &sm8450_mpss_resource},
1236	{ .compatible = "qcom,sm8550-adsp-pas", .data = &sm8550_adsp_resource},
1237	{ .compatible = "qcom,sm8550-cdsp-pas", .data = &sm8550_cdsp_resource},
1238	{ .compatible = "qcom,sm8550-mpss-pas", .data = &sm8550_mpss_resource},
1239	{ },
1240};
1241MODULE_DEVICE_TABLE(of, adsp_of_match);
1242
1243static struct platform_driver adsp_driver = {
1244	.probe = adsp_probe,
1245	.remove_new = adsp_remove,
1246	.driver = {
1247		.name = "qcom_q6v5_pas",
1248		.of_match_table = adsp_of_match,
1249	},
1250};
1251
1252module_platform_driver(adsp_driver);
1253MODULE_DESCRIPTION("Qualcomm Hexagon v5 Peripheral Authentication Service driver");
1254MODULE_LICENSE("GPL v2");