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 sm8150_adsp_resource = {
817		.crash_reason_smem = 423,
818		.firmware_name = "adsp.mdt",
819		.pas_id = 1,
820		.auto_boot = true,
821		.proxy_pd_names = (char*[]){
822			"cx",
823			NULL
824		},
825		.load_state = "adsp",
826		.ssr_name = "lpass",
827		.sysmon_name = "adsp",
828		.ssctl_id = 0x14,
829};
830
831static const struct adsp_data sm8250_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		"lcx",
838		"lmx",
839		NULL
840	},
841	.load_state = "adsp",
842	.ssr_name = "lpass",
843	.sysmon_name = "adsp",
844	.ssctl_id = 0x14,
845};
846
847static const struct adsp_data sm8350_adsp_resource = {
848	.crash_reason_smem = 423,
849	.firmware_name = "adsp.mdt",
850	.pas_id = 1,
851	.auto_boot = true,
852	.proxy_pd_names = (char*[]){
853		"lcx",
854		"lmx",
855		NULL
856	},
857	.load_state = "adsp",
858	.ssr_name = "lpass",
859	.sysmon_name = "adsp",
860	.ssctl_id = 0x14,
861};
862
863static const struct adsp_data msm8996_adsp_resource = {
864		.crash_reason_smem = 423,
865		.firmware_name = "adsp.mdt",
866		.pas_id = 1,
867		.auto_boot = true,
868		.proxy_pd_names = (char*[]){
869			"cx",
870			NULL
871		},
872		.ssr_name = "lpass",
873		.sysmon_name = "adsp",
874		.ssctl_id = 0x14,
875};
876
877static const struct adsp_data cdsp_resource_init = {
878	.crash_reason_smem = 601,
879	.firmware_name = "cdsp.mdt",
880	.pas_id = 18,
881	.auto_boot = true,
882	.ssr_name = "cdsp",
883	.sysmon_name = "cdsp",
884	.ssctl_id = 0x17,
885};
886
887static const struct adsp_data sdm845_cdsp_resource_init = {
888	.crash_reason_smem = 601,
889	.firmware_name = "cdsp.mdt",
890	.pas_id = 18,
891	.auto_boot = true,
892	.load_state = "cdsp",
893	.ssr_name = "cdsp",
894	.sysmon_name = "cdsp",
895	.ssctl_id = 0x17,
896};
897
898static const struct adsp_data sm6350_cdsp_resource = {
899	.crash_reason_smem = 601,
900	.firmware_name = "cdsp.mdt",
901	.pas_id = 18,
902	.auto_boot = true,
903	.proxy_pd_names = (char*[]){
904		"cx",
905		"mx",
906		NULL
907	},
908	.load_state = "cdsp",
909	.ssr_name = "cdsp",
910	.sysmon_name = "cdsp",
911	.ssctl_id = 0x17,
912};
913
914static const struct adsp_data sm8150_cdsp_resource = {
915	.crash_reason_smem = 601,
916	.firmware_name = "cdsp.mdt",
917	.pas_id = 18,
918	.auto_boot = true,
919	.proxy_pd_names = (char*[]){
920		"cx",
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 sm8250_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 sc8280xp_nsp0_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		"nsp",
951		NULL
952	},
953	.ssr_name = "cdsp0",
954	.sysmon_name = "cdsp",
955	.ssctl_id = 0x17,
956};
957
958static const struct adsp_data sc8280xp_nsp1_resource = {
959	.crash_reason_smem = 633,
960	.firmware_name = "cdsp.mdt",
961	.pas_id = 30,
962	.auto_boot = true,
963	.proxy_pd_names = (char*[]){
964		"nsp",
965		NULL
966	},
967	.ssr_name = "cdsp1",
968	.sysmon_name = "cdsp1",
969	.ssctl_id = 0x20,
970};
971
972static const struct adsp_data sm8350_cdsp_resource = {
973	.crash_reason_smem = 601,
974	.firmware_name = "cdsp.mdt",
975	.pas_id = 18,
976	.auto_boot = true,
977	.proxy_pd_names = (char*[]){
978		"cx",
979		"mxc",
980		NULL
981	},
982	.load_state = "cdsp",
983	.ssr_name = "cdsp",
984	.sysmon_name = "cdsp",
985	.ssctl_id = 0x17,
986};
987
988static const struct adsp_data mpss_resource_init = {
989	.crash_reason_smem = 421,
990	.firmware_name = "modem.mdt",
991	.pas_id = 4,
992	.minidump_id = 3,
993	.auto_boot = false,
994	.proxy_pd_names = (char*[]){
995		"cx",
996		"mss",
997		NULL
998	},
999	.load_state = "modem",
1000	.ssr_name = "mpss",
1001	.sysmon_name = "modem",
1002	.ssctl_id = 0x12,
1003};
1004
1005static const struct adsp_data sc8180x_mpss_resource = {
1006	.crash_reason_smem = 421,
1007	.firmware_name = "modem.mdt",
1008	.pas_id = 4,
1009	.auto_boot = false,
1010	.proxy_pd_names = (char*[]){
1011		"cx",
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 msm8996_slpi_resource_init = {
1021		.crash_reason_smem = 424,
1022		.firmware_name = "slpi.mdt",
1023		.pas_id = 12,
1024		.auto_boot = true,
1025		.proxy_pd_names = (char*[]){
1026			"ssc_cx",
1027			NULL
1028		},
1029		.ssr_name = "dsps",
1030		.sysmon_name = "slpi",
1031		.ssctl_id = 0x16,
1032};
1033
1034static const struct adsp_data sdm845_slpi_resource_init = {
1035		.crash_reason_smem = 424,
1036		.firmware_name = "slpi.mdt",
1037		.pas_id = 12,
1038		.auto_boot = true,
1039		.proxy_pd_names = (char*[]){
1040			"lcx",
1041			"lmx",
1042			NULL
1043		},
1044		.load_state = "slpi",
1045		.ssr_name = "dsps",
1046		.sysmon_name = "slpi",
1047		.ssctl_id = 0x16,
1048};
1049
1050static const struct adsp_data wcss_resource_init = {
1051	.crash_reason_smem = 421,
1052	.firmware_name = "wcnss.mdt",
1053	.pas_id = 6,
1054	.auto_boot = true,
1055	.ssr_name = "mpss",
1056	.sysmon_name = "wcnss",
1057	.ssctl_id = 0x12,
1058};
1059
1060static const struct adsp_data sdx55_mpss_resource = {
1061	.crash_reason_smem = 421,
1062	.firmware_name = "modem.mdt",
1063	.pas_id = 4,
1064	.auto_boot = true,
1065	.proxy_pd_names = (char*[]){
1066		"cx",
1067		"mss",
1068		NULL
1069	},
1070	.ssr_name = "mpss",
1071	.sysmon_name = "modem",
1072	.ssctl_id = 0x22,
1073};
1074
1075static const struct adsp_data sm8450_mpss_resource = {
1076	.crash_reason_smem = 421,
1077	.firmware_name = "modem.mdt",
1078	.pas_id = 4,
1079	.minidump_id = 3,
1080	.auto_boot = false,
1081	.decrypt_shutdown = true,
1082	.proxy_pd_names = (char*[]){
1083		"cx",
1084		"mss",
1085		NULL
1086	},
1087	.load_state = "modem",
1088	.ssr_name = "mpss",
1089	.sysmon_name = "modem",
1090	.ssctl_id = 0x12,
1091};
1092
1093static const struct adsp_data sm8550_adsp_resource = {
1094	.crash_reason_smem = 423,
1095	.firmware_name = "adsp.mdt",
1096	.dtb_firmware_name = "adsp_dtb.mdt",
1097	.pas_id = 1,
1098	.dtb_pas_id = 0x24,
1099	.minidump_id = 5,
1100	.auto_boot = true,
1101	.proxy_pd_names = (char*[]){
1102		"lcx",
1103		"lmx",
1104		NULL
1105	},
1106	.load_state = "adsp",
1107	.ssr_name = "lpass",
1108	.sysmon_name = "adsp",
1109	.ssctl_id = 0x14,
1110};
1111
1112static const struct adsp_data sm8550_cdsp_resource = {
1113	.crash_reason_smem = 601,
1114	.firmware_name = "cdsp.mdt",
1115	.dtb_firmware_name = "cdsp_dtb.mdt",
1116	.pas_id = 18,
1117	.dtb_pas_id = 0x25,
1118	.minidump_id = 7,
1119	.auto_boot = true,
1120	.proxy_pd_names = (char*[]){
1121		"cx",
1122		"mxc",
1123		"nsp",
1124		NULL
1125	},
1126	.load_state = "cdsp",
1127	.ssr_name = "cdsp",
1128	.sysmon_name = "cdsp",
1129	.ssctl_id = 0x17,
1130};
1131
1132static const struct adsp_data sm8550_mpss_resource = {
1133	.crash_reason_smem = 421,
1134	.firmware_name = "modem.mdt",
1135	.dtb_firmware_name = "modem_dtb.mdt",
1136	.pas_id = 4,
1137	.dtb_pas_id = 0x26,
1138	.minidump_id = 3,
1139	.auto_boot = false,
1140	.decrypt_shutdown = true,
1141	.proxy_pd_names = (char*[]){
1142		"cx",
1143		"mss",
1144		NULL
1145	},
1146	.load_state = "modem",
1147	.ssr_name = "mpss",
1148	.sysmon_name = "modem",
1149	.ssctl_id = 0x12,
1150	.region_assign_idx = 2,
1151};
1152
1153static const struct of_device_id adsp_of_match[] = {
1154	{ .compatible = "qcom,msm8226-adsp-pil", .data = &adsp_resource_init},
1155	{ .compatible = "qcom,msm8953-adsp-pil", .data = &msm8996_adsp_resource},
1156	{ .compatible = "qcom,msm8974-adsp-pil", .data = &adsp_resource_init},
1157	{ .compatible = "qcom,msm8996-adsp-pil", .data = &msm8996_adsp_resource},
1158	{ .compatible = "qcom,msm8996-slpi-pil", .data = &msm8996_slpi_resource_init},
1159	{ .compatible = "qcom,msm8998-adsp-pas", .data = &msm8996_adsp_resource},
1160	{ .compatible = "qcom,msm8998-slpi-pas", .data = &msm8996_slpi_resource_init},
1161	{ .compatible = "qcom,qcs404-adsp-pas", .data = &adsp_resource_init },
1162	{ .compatible = "qcom,qcs404-cdsp-pas", .data = &cdsp_resource_init },
1163	{ .compatible = "qcom,qcs404-wcss-pas", .data = &wcss_resource_init },
1164	{ .compatible = "qcom,sc7180-mpss-pas", .data = &mpss_resource_init},
1165	{ .compatible = "qcom,sc7280-mpss-pas", .data = &mpss_resource_init},
1166	{ .compatible = "qcom,sc8180x-adsp-pas", .data = &sm8150_adsp_resource},
1167	{ .compatible = "qcom,sc8180x-cdsp-pas", .data = &sm8150_cdsp_resource},
1168	{ .compatible = "qcom,sc8180x-mpss-pas", .data = &sc8180x_mpss_resource},
1169	{ .compatible = "qcom,sc8280xp-adsp-pas", .data = &sm8250_adsp_resource},
1170	{ .compatible = "qcom,sc8280xp-nsp0-pas", .data = &sc8280xp_nsp0_resource},
1171	{ .compatible = "qcom,sc8280xp-nsp1-pas", .data = &sc8280xp_nsp1_resource},
1172	{ .compatible = "qcom,sdm660-adsp-pas", .data = &adsp_resource_init},
1173	{ .compatible = "qcom,sdm845-adsp-pas", .data = &sdm845_adsp_resource_init},
1174	{ .compatible = "qcom,sdm845-cdsp-pas", .data = &sdm845_cdsp_resource_init},
1175	{ .compatible = "qcom,sdm845-slpi-pas", .data = &sdm845_slpi_resource_init},
1176	{ .compatible = "qcom,sdx55-mpss-pas", .data = &sdx55_mpss_resource},
1177	{ .compatible = "qcom,sm6115-adsp-pas", .data = &adsp_resource_init},
1178	{ .compatible = "qcom,sm6115-cdsp-pas", .data = &cdsp_resource_init},
1179	{ .compatible = "qcom,sm6115-mpss-pas", .data = &sc8180x_mpss_resource},
1180	{ .compatible = "qcom,sm6350-adsp-pas", .data = &sm6350_adsp_resource},
1181	{ .compatible = "qcom,sm6350-cdsp-pas", .data = &sm6350_cdsp_resource},
1182	{ .compatible = "qcom,sm6350-mpss-pas", .data = &mpss_resource_init},
1183	{ .compatible = "qcom,sm8150-adsp-pas", .data = &sm8150_adsp_resource},
1184	{ .compatible = "qcom,sm8150-cdsp-pas", .data = &sm8150_cdsp_resource},
1185	{ .compatible = "qcom,sm8150-mpss-pas", .data = &mpss_resource_init},
1186	{ .compatible = "qcom,sm8150-slpi-pas", .data = &sdm845_slpi_resource_init},
1187	{ .compatible = "qcom,sm8250-adsp-pas", .data = &sm8250_adsp_resource},
1188	{ .compatible = "qcom,sm8250-cdsp-pas", .data = &sm8250_cdsp_resource},
1189	{ .compatible = "qcom,sm8250-slpi-pas", .data = &sdm845_slpi_resource_init},
1190	{ .compatible = "qcom,sm8350-adsp-pas", .data = &sm8350_adsp_resource},
1191	{ .compatible = "qcom,sm8350-cdsp-pas", .data = &sm8350_cdsp_resource},
1192	{ .compatible = "qcom,sm8350-slpi-pas", .data = &sdm845_slpi_resource_init},
1193	{ .compatible = "qcom,sm8350-mpss-pas", .data = &mpss_resource_init},
1194	{ .compatible = "qcom,sm8450-adsp-pas", .data = &sm8350_adsp_resource},
1195	{ .compatible = "qcom,sm8450-cdsp-pas", .data = &sm8350_cdsp_resource},
1196	{ .compatible = "qcom,sm8450-slpi-pas", .data = &sdm845_slpi_resource_init},
1197	{ .compatible = "qcom,sm8450-mpss-pas", .data = &sm8450_mpss_resource},
1198	{ .compatible = "qcom,sm8550-adsp-pas", .data = &sm8550_adsp_resource},
1199	{ .compatible = "qcom,sm8550-cdsp-pas", .data = &sm8550_cdsp_resource},
1200	{ .compatible = "qcom,sm8550-mpss-pas", .data = &sm8550_mpss_resource},
1201	{ },
1202};
1203MODULE_DEVICE_TABLE(of, adsp_of_match);
1204
1205static struct platform_driver adsp_driver = {
1206	.probe = adsp_probe,
1207	.remove_new = adsp_remove,
1208	.driver = {
1209		.name = "qcom_q6v5_pas",
1210		.of_match_table = adsp_of_match,
1211	},
1212};
1213
1214module_platform_driver(adsp_driver);
1215MODULE_DESCRIPTION("Qualcomm Hexagon v5 Peripheral Authentication Service driver");
1216MODULE_LICENSE("GPL v2");
1217