162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Qualcomm Technology Inc. ADSP Peripheral Image Loader for SDM845.
462306a36Sopenharmony_ci * Copyright (c) 2018, The Linux Foundation. All rights reserved.
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include <linux/clk.h>
862306a36Sopenharmony_ci#include <linux/delay.h>
962306a36Sopenharmony_ci#include <linux/firmware.h>
1062306a36Sopenharmony_ci#include <linux/interrupt.h>
1162306a36Sopenharmony_ci#include <linux/io.h>
1262306a36Sopenharmony_ci#include <linux/iommu.h>
1362306a36Sopenharmony_ci#include <linux/iopoll.h>
1462306a36Sopenharmony_ci#include <linux/kernel.h>
1562306a36Sopenharmony_ci#include <linux/mfd/syscon.h>
1662306a36Sopenharmony_ci#include <linux/module.h>
1762306a36Sopenharmony_ci#include <linux/of.h>
1862306a36Sopenharmony_ci#include <linux/of_reserved_mem.h>
1962306a36Sopenharmony_ci#include <linux/platform_device.h>
2062306a36Sopenharmony_ci#include <linux/pm_domain.h>
2162306a36Sopenharmony_ci#include <linux/pm_runtime.h>
2262306a36Sopenharmony_ci#include <linux/regmap.h>
2362306a36Sopenharmony_ci#include <linux/remoteproc.h>
2462306a36Sopenharmony_ci#include <linux/reset.h>
2562306a36Sopenharmony_ci#include <linux/soc/qcom/mdt_loader.h>
2662306a36Sopenharmony_ci#include <linux/soc/qcom/smem.h>
2762306a36Sopenharmony_ci#include <linux/soc/qcom/smem_state.h>
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci#include "qcom_common.h"
3062306a36Sopenharmony_ci#include "qcom_pil_info.h"
3162306a36Sopenharmony_ci#include "qcom_q6v5.h"
3262306a36Sopenharmony_ci#include "remoteproc_internal.h"
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci/* time out value */
3562306a36Sopenharmony_ci#define ACK_TIMEOUT			1000
3662306a36Sopenharmony_ci#define ACK_TIMEOUT_US			1000000
3762306a36Sopenharmony_ci#define BOOT_FSM_TIMEOUT		10000
3862306a36Sopenharmony_ci/* mask values */
3962306a36Sopenharmony_ci#define EVB_MASK			GENMASK(27, 4)
4062306a36Sopenharmony_ci/*QDSP6SS register offsets*/
4162306a36Sopenharmony_ci#define RST_EVB_REG			0x10
4262306a36Sopenharmony_ci#define CORE_START_REG			0x400
4362306a36Sopenharmony_ci#define BOOT_CMD_REG			0x404
4462306a36Sopenharmony_ci#define BOOT_STATUS_REG			0x408
4562306a36Sopenharmony_ci#define RET_CFG_REG			0x1C
4662306a36Sopenharmony_ci/*TCSR register offsets*/
4762306a36Sopenharmony_ci#define LPASS_MASTER_IDLE_REG		0x8
4862306a36Sopenharmony_ci#define LPASS_HALTACK_REG		0x4
4962306a36Sopenharmony_ci#define LPASS_PWR_ON_REG		0x10
5062306a36Sopenharmony_ci#define LPASS_HALTREQ_REG		0x0
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci#define SID_MASK_DEFAULT        0xF
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci#define QDSP6SS_XO_CBCR		0x38
5562306a36Sopenharmony_ci#define QDSP6SS_CORE_CBCR	0x20
5662306a36Sopenharmony_ci#define QDSP6SS_SLEEP_CBCR	0x3c
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci#define QCOM_Q6V5_RPROC_PROXY_PD_MAX	3
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci#define LPASS_BOOT_CORE_START	BIT(0)
6162306a36Sopenharmony_ci#define LPASS_BOOT_CMD_START	BIT(0)
6262306a36Sopenharmony_ci#define LPASS_EFUSE_Q6SS_EVB_SEL 0x0
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_cistruct adsp_pil_data {
6562306a36Sopenharmony_ci	int crash_reason_smem;
6662306a36Sopenharmony_ci	const char *firmware_name;
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci	const char *ssr_name;
6962306a36Sopenharmony_ci	const char *sysmon_name;
7062306a36Sopenharmony_ci	int ssctl_id;
7162306a36Sopenharmony_ci	bool is_wpss;
7262306a36Sopenharmony_ci	bool has_iommu;
7362306a36Sopenharmony_ci	bool auto_boot;
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	const char **clk_ids;
7662306a36Sopenharmony_ci	int num_clks;
7762306a36Sopenharmony_ci	const char **proxy_pd_names;
7862306a36Sopenharmony_ci	const char *load_state;
7962306a36Sopenharmony_ci};
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_cistruct qcom_adsp {
8262306a36Sopenharmony_ci	struct device *dev;
8362306a36Sopenharmony_ci	struct rproc *rproc;
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	struct qcom_q6v5 q6v5;
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	struct clk *xo;
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci	int num_clks;
9062306a36Sopenharmony_ci	struct clk_bulk_data *clks;
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	void __iomem *qdsp6ss_base;
9362306a36Sopenharmony_ci	void __iomem *lpass_efuse;
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci	struct reset_control *pdc_sync_reset;
9662306a36Sopenharmony_ci	struct reset_control *restart;
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	struct regmap *halt_map;
9962306a36Sopenharmony_ci	unsigned int halt_lpass;
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	int crash_reason_smem;
10262306a36Sopenharmony_ci	const char *info_name;
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	struct completion start_done;
10562306a36Sopenharmony_ci	struct completion stop_done;
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	phys_addr_t mem_phys;
10862306a36Sopenharmony_ci	phys_addr_t mem_reloc;
10962306a36Sopenharmony_ci	void *mem_region;
11062306a36Sopenharmony_ci	size_t mem_size;
11162306a36Sopenharmony_ci	bool has_iommu;
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	struct device *proxy_pds[QCOM_Q6V5_RPROC_PROXY_PD_MAX];
11462306a36Sopenharmony_ci	size_t proxy_pd_count;
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	struct qcom_rproc_glink glink_subdev;
11762306a36Sopenharmony_ci	struct qcom_rproc_ssr ssr_subdev;
11862306a36Sopenharmony_ci	struct qcom_sysmon *sysmon;
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	int (*shutdown)(struct qcom_adsp *adsp);
12162306a36Sopenharmony_ci};
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_cistatic int qcom_rproc_pds_attach(struct device *dev, struct qcom_adsp *adsp,
12462306a36Sopenharmony_ci				 const char **pd_names)
12562306a36Sopenharmony_ci{
12662306a36Sopenharmony_ci	struct device **devs = adsp->proxy_pds;
12762306a36Sopenharmony_ci	size_t num_pds = 0;
12862306a36Sopenharmony_ci	int ret;
12962306a36Sopenharmony_ci	int i;
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	if (!pd_names)
13262306a36Sopenharmony_ci		return 0;
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	/* Handle single power domain */
13562306a36Sopenharmony_ci	if (dev->pm_domain) {
13662306a36Sopenharmony_ci		devs[0] = dev;
13762306a36Sopenharmony_ci		pm_runtime_enable(dev);
13862306a36Sopenharmony_ci		return 1;
13962306a36Sopenharmony_ci	}
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	while (pd_names[num_pds])
14262306a36Sopenharmony_ci		num_pds++;
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	if (num_pds > ARRAY_SIZE(adsp->proxy_pds))
14562306a36Sopenharmony_ci		return -E2BIG;
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	for (i = 0; i < num_pds; i++) {
14862306a36Sopenharmony_ci		devs[i] = dev_pm_domain_attach_by_name(dev, pd_names[i]);
14962306a36Sopenharmony_ci		if (IS_ERR_OR_NULL(devs[i])) {
15062306a36Sopenharmony_ci			ret = PTR_ERR(devs[i]) ? : -ENODATA;
15162306a36Sopenharmony_ci			goto unroll_attach;
15262306a36Sopenharmony_ci		}
15362306a36Sopenharmony_ci	}
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	return num_pds;
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ciunroll_attach:
15862306a36Sopenharmony_ci	for (i--; i >= 0; i--)
15962306a36Sopenharmony_ci		dev_pm_domain_detach(devs[i], false);
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci	return ret;
16262306a36Sopenharmony_ci}
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_cistatic void qcom_rproc_pds_detach(struct qcom_adsp *adsp, struct device **pds,
16562306a36Sopenharmony_ci				  size_t pd_count)
16662306a36Sopenharmony_ci{
16762306a36Sopenharmony_ci	struct device *dev = adsp->dev;
16862306a36Sopenharmony_ci	int i;
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	/* Handle single power domain */
17162306a36Sopenharmony_ci	if (dev->pm_domain && pd_count) {
17262306a36Sopenharmony_ci		pm_runtime_disable(dev);
17362306a36Sopenharmony_ci		return;
17462306a36Sopenharmony_ci	}
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci	for (i = 0; i < pd_count; i++)
17762306a36Sopenharmony_ci		dev_pm_domain_detach(pds[i], false);
17862306a36Sopenharmony_ci}
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_cistatic int qcom_rproc_pds_enable(struct qcom_adsp *adsp, struct device **pds,
18162306a36Sopenharmony_ci				 size_t pd_count)
18262306a36Sopenharmony_ci{
18362306a36Sopenharmony_ci	int ret;
18462306a36Sopenharmony_ci	int i;
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	for (i = 0; i < pd_count; i++) {
18762306a36Sopenharmony_ci		dev_pm_genpd_set_performance_state(pds[i], INT_MAX);
18862306a36Sopenharmony_ci		ret = pm_runtime_resume_and_get(pds[i]);
18962306a36Sopenharmony_ci		if (ret < 0) {
19062306a36Sopenharmony_ci			dev_pm_genpd_set_performance_state(pds[i], 0);
19162306a36Sopenharmony_ci			goto unroll_pd_votes;
19262306a36Sopenharmony_ci		}
19362306a36Sopenharmony_ci	}
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	return 0;
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ciunroll_pd_votes:
19862306a36Sopenharmony_ci	for (i--; i >= 0; i--) {
19962306a36Sopenharmony_ci		dev_pm_genpd_set_performance_state(pds[i], 0);
20062306a36Sopenharmony_ci		pm_runtime_put(pds[i]);
20162306a36Sopenharmony_ci	}
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci	return ret;
20462306a36Sopenharmony_ci}
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_cistatic void qcom_rproc_pds_disable(struct qcom_adsp *adsp, struct device **pds,
20762306a36Sopenharmony_ci				   size_t pd_count)
20862306a36Sopenharmony_ci{
20962306a36Sopenharmony_ci	int i;
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	for (i = 0; i < pd_count; i++) {
21262306a36Sopenharmony_ci		dev_pm_genpd_set_performance_state(pds[i], 0);
21362306a36Sopenharmony_ci		pm_runtime_put(pds[i]);
21462306a36Sopenharmony_ci	}
21562306a36Sopenharmony_ci}
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_cistatic int qcom_wpss_shutdown(struct qcom_adsp *adsp)
21862306a36Sopenharmony_ci{
21962306a36Sopenharmony_ci	unsigned int val;
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci	regmap_write(adsp->halt_map, adsp->halt_lpass + LPASS_HALTREQ_REG, 1);
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci	/* Wait for halt ACK from QDSP6 */
22462306a36Sopenharmony_ci	regmap_read_poll_timeout(adsp->halt_map,
22562306a36Sopenharmony_ci				 adsp->halt_lpass + LPASS_HALTACK_REG, val,
22662306a36Sopenharmony_ci				 val, 1000, ACK_TIMEOUT_US);
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci	/* Assert the WPSS PDC Reset */
22962306a36Sopenharmony_ci	reset_control_assert(adsp->pdc_sync_reset);
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	/* Place the WPSS processor into reset */
23262306a36Sopenharmony_ci	reset_control_assert(adsp->restart);
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	/* wait after asserting subsystem restart from AOSS */
23562306a36Sopenharmony_ci	usleep_range(200, 205);
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	/* Remove the WPSS reset */
23862306a36Sopenharmony_ci	reset_control_deassert(adsp->restart);
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	/* De-assert the WPSS PDC Reset */
24162306a36Sopenharmony_ci	reset_control_deassert(adsp->pdc_sync_reset);
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci	usleep_range(100, 105);
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	clk_bulk_disable_unprepare(adsp->num_clks, adsp->clks);
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	regmap_write(adsp->halt_map, adsp->halt_lpass + LPASS_HALTREQ_REG, 0);
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	/* Wait for halt ACK from QDSP6 */
25062306a36Sopenharmony_ci	regmap_read_poll_timeout(adsp->halt_map,
25162306a36Sopenharmony_ci				 adsp->halt_lpass + LPASS_HALTACK_REG, val,
25262306a36Sopenharmony_ci				 !val, 1000, ACK_TIMEOUT_US);
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	return 0;
25562306a36Sopenharmony_ci}
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_cistatic int qcom_adsp_shutdown(struct qcom_adsp *adsp)
25862306a36Sopenharmony_ci{
25962306a36Sopenharmony_ci	unsigned long timeout;
26062306a36Sopenharmony_ci	unsigned int val;
26162306a36Sopenharmony_ci	int ret;
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	/* Reset the retention logic */
26462306a36Sopenharmony_ci	val = readl(adsp->qdsp6ss_base + RET_CFG_REG);
26562306a36Sopenharmony_ci	val |= 0x1;
26662306a36Sopenharmony_ci	writel(val, adsp->qdsp6ss_base + RET_CFG_REG);
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	clk_bulk_disable_unprepare(adsp->num_clks, adsp->clks);
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci	/* QDSP6 master port needs to be explicitly halted */
27162306a36Sopenharmony_ci	ret = regmap_read(adsp->halt_map,
27262306a36Sopenharmony_ci			adsp->halt_lpass + LPASS_PWR_ON_REG, &val);
27362306a36Sopenharmony_ci	if (ret || !val)
27462306a36Sopenharmony_ci		goto reset;
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	ret = regmap_read(adsp->halt_map,
27762306a36Sopenharmony_ci			adsp->halt_lpass + LPASS_MASTER_IDLE_REG,
27862306a36Sopenharmony_ci			&val);
27962306a36Sopenharmony_ci	if (ret || val)
28062306a36Sopenharmony_ci		goto reset;
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	regmap_write(adsp->halt_map,
28362306a36Sopenharmony_ci			adsp->halt_lpass + LPASS_HALTREQ_REG, 1);
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	/* Wait for halt ACK from QDSP6 */
28662306a36Sopenharmony_ci	timeout = jiffies + msecs_to_jiffies(ACK_TIMEOUT);
28762306a36Sopenharmony_ci	for (;;) {
28862306a36Sopenharmony_ci		ret = regmap_read(adsp->halt_map,
28962306a36Sopenharmony_ci			adsp->halt_lpass + LPASS_HALTACK_REG, &val);
29062306a36Sopenharmony_ci		if (ret || val || time_after(jiffies, timeout))
29162306a36Sopenharmony_ci			break;
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci		usleep_range(1000, 1100);
29462306a36Sopenharmony_ci	}
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	ret = regmap_read(adsp->halt_map,
29762306a36Sopenharmony_ci			adsp->halt_lpass + LPASS_MASTER_IDLE_REG, &val);
29862306a36Sopenharmony_ci	if (ret || !val)
29962306a36Sopenharmony_ci		dev_err(adsp->dev, "port failed halt\n");
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_cireset:
30262306a36Sopenharmony_ci	/* Assert the LPASS PDC Reset */
30362306a36Sopenharmony_ci	reset_control_assert(adsp->pdc_sync_reset);
30462306a36Sopenharmony_ci	/* Place the LPASS processor into reset */
30562306a36Sopenharmony_ci	reset_control_assert(adsp->restart);
30662306a36Sopenharmony_ci	/* wait after asserting subsystem restart from AOSS */
30762306a36Sopenharmony_ci	usleep_range(200, 300);
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	/* Clear the halt request for the AXIM and AHBM for Q6 */
31062306a36Sopenharmony_ci	regmap_write(adsp->halt_map, adsp->halt_lpass + LPASS_HALTREQ_REG, 0);
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	/* De-assert the LPASS PDC Reset */
31362306a36Sopenharmony_ci	reset_control_deassert(adsp->pdc_sync_reset);
31462306a36Sopenharmony_ci	/* Remove the LPASS reset */
31562306a36Sopenharmony_ci	reset_control_deassert(adsp->restart);
31662306a36Sopenharmony_ci	/* wait after de-asserting subsystem restart from AOSS */
31762306a36Sopenharmony_ci	usleep_range(200, 300);
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	return 0;
32062306a36Sopenharmony_ci}
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_cistatic int adsp_load(struct rproc *rproc, const struct firmware *fw)
32362306a36Sopenharmony_ci{
32462306a36Sopenharmony_ci	struct qcom_adsp *adsp = rproc->priv;
32562306a36Sopenharmony_ci	int ret;
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	ret = qcom_mdt_load_no_init(adsp->dev, fw, rproc->firmware, 0,
32862306a36Sopenharmony_ci				    adsp->mem_region, adsp->mem_phys,
32962306a36Sopenharmony_ci				    adsp->mem_size, &adsp->mem_reloc);
33062306a36Sopenharmony_ci	if (ret)
33162306a36Sopenharmony_ci		return ret;
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci	qcom_pil_info_store(adsp->info_name, adsp->mem_phys, adsp->mem_size);
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci	return 0;
33662306a36Sopenharmony_ci}
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_cistatic void adsp_unmap_carveout(struct rproc *rproc)
33962306a36Sopenharmony_ci{
34062306a36Sopenharmony_ci	struct qcom_adsp *adsp = rproc->priv;
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci	if (adsp->has_iommu)
34362306a36Sopenharmony_ci		iommu_unmap(rproc->domain, adsp->mem_phys, adsp->mem_size);
34462306a36Sopenharmony_ci}
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_cistatic int adsp_map_carveout(struct rproc *rproc)
34762306a36Sopenharmony_ci{
34862306a36Sopenharmony_ci	struct qcom_adsp *adsp = rproc->priv;
34962306a36Sopenharmony_ci	struct of_phandle_args args;
35062306a36Sopenharmony_ci	long long sid;
35162306a36Sopenharmony_ci	unsigned long iova;
35262306a36Sopenharmony_ci	int ret;
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	if (!adsp->has_iommu)
35562306a36Sopenharmony_ci		return 0;
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci	if (!rproc->domain)
35862306a36Sopenharmony_ci		return -EINVAL;
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci	ret = of_parse_phandle_with_args(adsp->dev->of_node, "iommus", "#iommu-cells", 0, &args);
36162306a36Sopenharmony_ci	if (ret < 0)
36262306a36Sopenharmony_ci		return ret;
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	sid = args.args[0] & SID_MASK_DEFAULT;
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	/* Add SID configuration for ADSP Firmware to SMMU */
36762306a36Sopenharmony_ci	iova =  adsp->mem_phys | (sid << 32);
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci	ret = iommu_map(rproc->domain, iova, adsp->mem_phys,
37062306a36Sopenharmony_ci			adsp->mem_size,	IOMMU_READ | IOMMU_WRITE,
37162306a36Sopenharmony_ci			GFP_KERNEL);
37262306a36Sopenharmony_ci	if (ret) {
37362306a36Sopenharmony_ci		dev_err(adsp->dev, "Unable to map ADSP Physical Memory\n");
37462306a36Sopenharmony_ci		return ret;
37562306a36Sopenharmony_ci	}
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci	return 0;
37862306a36Sopenharmony_ci}
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_cistatic int adsp_start(struct rproc *rproc)
38162306a36Sopenharmony_ci{
38262306a36Sopenharmony_ci	struct qcom_adsp *adsp = rproc->priv;
38362306a36Sopenharmony_ci	int ret;
38462306a36Sopenharmony_ci	unsigned int val;
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci	ret = qcom_q6v5_prepare(&adsp->q6v5);
38762306a36Sopenharmony_ci	if (ret)
38862306a36Sopenharmony_ci		return ret;
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci	ret = adsp_map_carveout(rproc);
39162306a36Sopenharmony_ci	if (ret) {
39262306a36Sopenharmony_ci		dev_err(adsp->dev, "ADSP smmu mapping failed\n");
39362306a36Sopenharmony_ci		goto disable_irqs;
39462306a36Sopenharmony_ci	}
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	ret = clk_prepare_enable(adsp->xo);
39762306a36Sopenharmony_ci	if (ret)
39862306a36Sopenharmony_ci		goto adsp_smmu_unmap;
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci	ret = qcom_rproc_pds_enable(adsp, adsp->proxy_pds,
40162306a36Sopenharmony_ci				    adsp->proxy_pd_count);
40262306a36Sopenharmony_ci	if (ret < 0)
40362306a36Sopenharmony_ci		goto disable_xo_clk;
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	ret = clk_bulk_prepare_enable(adsp->num_clks, adsp->clks);
40662306a36Sopenharmony_ci	if (ret) {
40762306a36Sopenharmony_ci		dev_err(adsp->dev, "adsp clk_enable failed\n");
40862306a36Sopenharmony_ci		goto disable_power_domain;
40962306a36Sopenharmony_ci	}
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	/* Enable the XO clock */
41262306a36Sopenharmony_ci	writel(1, adsp->qdsp6ss_base + QDSP6SS_XO_CBCR);
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci	/* Enable the QDSP6SS sleep clock */
41562306a36Sopenharmony_ci	writel(1, adsp->qdsp6ss_base + QDSP6SS_SLEEP_CBCR);
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci	/* Enable the QDSP6 core clock */
41862306a36Sopenharmony_ci	writel(1, adsp->qdsp6ss_base + QDSP6SS_CORE_CBCR);
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci	/* Program boot address */
42162306a36Sopenharmony_ci	writel(adsp->mem_phys >> 4, adsp->qdsp6ss_base + RST_EVB_REG);
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	if (adsp->lpass_efuse)
42462306a36Sopenharmony_ci		writel(LPASS_EFUSE_Q6SS_EVB_SEL, adsp->lpass_efuse);
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	/* De-assert QDSP6 stop core. QDSP6 will execute after out of reset */
42762306a36Sopenharmony_ci	writel(LPASS_BOOT_CORE_START, adsp->qdsp6ss_base + CORE_START_REG);
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci	/* Trigger boot FSM to start QDSP6 */
43062306a36Sopenharmony_ci	writel(LPASS_BOOT_CMD_START, adsp->qdsp6ss_base + BOOT_CMD_REG);
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci	/* Wait for core to come out of reset */
43362306a36Sopenharmony_ci	ret = readl_poll_timeout(adsp->qdsp6ss_base + BOOT_STATUS_REG,
43462306a36Sopenharmony_ci			val, (val & BIT(0)) != 0, 10, BOOT_FSM_TIMEOUT);
43562306a36Sopenharmony_ci	if (ret) {
43662306a36Sopenharmony_ci		dev_err(adsp->dev, "failed to bootup adsp\n");
43762306a36Sopenharmony_ci		goto disable_adsp_clks;
43862306a36Sopenharmony_ci	}
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci	ret = qcom_q6v5_wait_for_start(&adsp->q6v5, msecs_to_jiffies(5 * HZ));
44162306a36Sopenharmony_ci	if (ret == -ETIMEDOUT) {
44262306a36Sopenharmony_ci		dev_err(adsp->dev, "start timed out\n");
44362306a36Sopenharmony_ci		goto disable_adsp_clks;
44462306a36Sopenharmony_ci	}
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci	return 0;
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_cidisable_adsp_clks:
44962306a36Sopenharmony_ci	clk_bulk_disable_unprepare(adsp->num_clks, adsp->clks);
45062306a36Sopenharmony_cidisable_power_domain:
45162306a36Sopenharmony_ci	qcom_rproc_pds_disable(adsp, adsp->proxy_pds, adsp->proxy_pd_count);
45262306a36Sopenharmony_cidisable_xo_clk:
45362306a36Sopenharmony_ci	clk_disable_unprepare(adsp->xo);
45462306a36Sopenharmony_ciadsp_smmu_unmap:
45562306a36Sopenharmony_ci	adsp_unmap_carveout(rproc);
45662306a36Sopenharmony_cidisable_irqs:
45762306a36Sopenharmony_ci	qcom_q6v5_unprepare(&adsp->q6v5);
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci	return ret;
46062306a36Sopenharmony_ci}
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_cistatic void qcom_adsp_pil_handover(struct qcom_q6v5 *q6v5)
46362306a36Sopenharmony_ci{
46462306a36Sopenharmony_ci	struct qcom_adsp *adsp = container_of(q6v5, struct qcom_adsp, q6v5);
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci	clk_disable_unprepare(adsp->xo);
46762306a36Sopenharmony_ci	qcom_rproc_pds_disable(adsp, adsp->proxy_pds, adsp->proxy_pd_count);
46862306a36Sopenharmony_ci}
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_cistatic int adsp_stop(struct rproc *rproc)
47162306a36Sopenharmony_ci{
47262306a36Sopenharmony_ci	struct qcom_adsp *adsp = rproc->priv;
47362306a36Sopenharmony_ci	int handover;
47462306a36Sopenharmony_ci	int ret;
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci	ret = qcom_q6v5_request_stop(&adsp->q6v5, adsp->sysmon);
47762306a36Sopenharmony_ci	if (ret == -ETIMEDOUT)
47862306a36Sopenharmony_ci		dev_err(adsp->dev, "timed out on wait\n");
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci	ret = adsp->shutdown(adsp);
48162306a36Sopenharmony_ci	if (ret)
48262306a36Sopenharmony_ci		dev_err(adsp->dev, "failed to shutdown: %d\n", ret);
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci	adsp_unmap_carveout(rproc);
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci	handover = qcom_q6v5_unprepare(&adsp->q6v5);
48762306a36Sopenharmony_ci	if (handover)
48862306a36Sopenharmony_ci		qcom_adsp_pil_handover(&adsp->q6v5);
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	return ret;
49162306a36Sopenharmony_ci}
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_cistatic void *adsp_da_to_va(struct rproc *rproc, u64 da, size_t len, bool *is_iomem)
49462306a36Sopenharmony_ci{
49562306a36Sopenharmony_ci	struct qcom_adsp *adsp = rproc->priv;
49662306a36Sopenharmony_ci	int offset;
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci	offset = da - adsp->mem_reloc;
49962306a36Sopenharmony_ci	if (offset < 0 || offset + len > adsp->mem_size)
50062306a36Sopenharmony_ci		return NULL;
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ci	return adsp->mem_region + offset;
50362306a36Sopenharmony_ci}
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_cistatic int adsp_parse_firmware(struct rproc *rproc, const struct firmware *fw)
50662306a36Sopenharmony_ci{
50762306a36Sopenharmony_ci	struct qcom_adsp *adsp = rproc->priv;
50862306a36Sopenharmony_ci	int ret;
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_ci	ret = qcom_register_dump_segments(rproc, fw);
51162306a36Sopenharmony_ci	if (ret) {
51262306a36Sopenharmony_ci		dev_err(&rproc->dev, "Error in registering dump segments\n");
51362306a36Sopenharmony_ci		return ret;
51462306a36Sopenharmony_ci	}
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci	if (adsp->has_iommu) {
51762306a36Sopenharmony_ci		ret = rproc_elf_load_rsc_table(rproc, fw);
51862306a36Sopenharmony_ci		if (ret) {
51962306a36Sopenharmony_ci			dev_err(&rproc->dev, "Error in loading resource table\n");
52062306a36Sopenharmony_ci			return ret;
52162306a36Sopenharmony_ci		}
52262306a36Sopenharmony_ci	}
52362306a36Sopenharmony_ci	return 0;
52462306a36Sopenharmony_ci}
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_cistatic unsigned long adsp_panic(struct rproc *rproc)
52762306a36Sopenharmony_ci{
52862306a36Sopenharmony_ci	struct qcom_adsp *adsp = rproc->priv;
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci	return qcom_q6v5_panic(&adsp->q6v5);
53162306a36Sopenharmony_ci}
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_cistatic const struct rproc_ops adsp_ops = {
53462306a36Sopenharmony_ci	.start = adsp_start,
53562306a36Sopenharmony_ci	.stop = adsp_stop,
53662306a36Sopenharmony_ci	.da_to_va = adsp_da_to_va,
53762306a36Sopenharmony_ci	.parse_fw = adsp_parse_firmware,
53862306a36Sopenharmony_ci	.load = adsp_load,
53962306a36Sopenharmony_ci	.panic = adsp_panic,
54062306a36Sopenharmony_ci};
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_cistatic int adsp_init_clock(struct qcom_adsp *adsp, const char **clk_ids)
54362306a36Sopenharmony_ci{
54462306a36Sopenharmony_ci	int num_clks = 0;
54562306a36Sopenharmony_ci	int i, ret;
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci	adsp->xo = devm_clk_get(adsp->dev, "xo");
54862306a36Sopenharmony_ci	if (IS_ERR(adsp->xo)) {
54962306a36Sopenharmony_ci		ret = PTR_ERR(adsp->xo);
55062306a36Sopenharmony_ci		if (ret != -EPROBE_DEFER)
55162306a36Sopenharmony_ci			dev_err(adsp->dev, "failed to get xo clock");
55262306a36Sopenharmony_ci		return ret;
55362306a36Sopenharmony_ci	}
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci	for (i = 0; clk_ids[i]; i++)
55662306a36Sopenharmony_ci		num_clks++;
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ci	adsp->num_clks = num_clks;
55962306a36Sopenharmony_ci	adsp->clks = devm_kcalloc(adsp->dev, adsp->num_clks,
56062306a36Sopenharmony_ci				sizeof(*adsp->clks), GFP_KERNEL);
56162306a36Sopenharmony_ci	if (!adsp->clks)
56262306a36Sopenharmony_ci		return -ENOMEM;
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_ci	for (i = 0; i < adsp->num_clks; i++)
56562306a36Sopenharmony_ci		adsp->clks[i].id = clk_ids[i];
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ci	return devm_clk_bulk_get(adsp->dev, adsp->num_clks, adsp->clks);
56862306a36Sopenharmony_ci}
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_cistatic int adsp_init_reset(struct qcom_adsp *adsp)
57162306a36Sopenharmony_ci{
57262306a36Sopenharmony_ci	adsp->pdc_sync_reset = devm_reset_control_get_optional_exclusive(adsp->dev,
57362306a36Sopenharmony_ci			"pdc_sync");
57462306a36Sopenharmony_ci	if (IS_ERR(adsp->pdc_sync_reset)) {
57562306a36Sopenharmony_ci		dev_err(adsp->dev, "failed to acquire pdc_sync reset\n");
57662306a36Sopenharmony_ci		return PTR_ERR(adsp->pdc_sync_reset);
57762306a36Sopenharmony_ci	}
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ci	adsp->restart = devm_reset_control_get_optional_exclusive(adsp->dev, "restart");
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ci	/* Fall back to the  old "cc_lpass" if "restart" is absent */
58262306a36Sopenharmony_ci	if (!adsp->restart)
58362306a36Sopenharmony_ci		adsp->restart = devm_reset_control_get_exclusive(adsp->dev, "cc_lpass");
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_ci	if (IS_ERR(adsp->restart)) {
58662306a36Sopenharmony_ci		dev_err(adsp->dev, "failed to acquire restart\n");
58762306a36Sopenharmony_ci		return PTR_ERR(adsp->restart);
58862306a36Sopenharmony_ci	}
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ci	return 0;
59162306a36Sopenharmony_ci}
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_cistatic int adsp_init_mmio(struct qcom_adsp *adsp,
59462306a36Sopenharmony_ci				struct platform_device *pdev)
59562306a36Sopenharmony_ci{
59662306a36Sopenharmony_ci	struct resource *efuse_region;
59762306a36Sopenharmony_ci	struct device_node *syscon;
59862306a36Sopenharmony_ci	int ret;
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_ci	adsp->qdsp6ss_base = devm_platform_ioremap_resource(pdev, 0);
60162306a36Sopenharmony_ci	if (IS_ERR(adsp->qdsp6ss_base)) {
60262306a36Sopenharmony_ci		dev_err(adsp->dev, "failed to map QDSP6SS registers\n");
60362306a36Sopenharmony_ci		return PTR_ERR(adsp->qdsp6ss_base);
60462306a36Sopenharmony_ci	}
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_ci	efuse_region = platform_get_resource(pdev, IORESOURCE_MEM, 1);
60762306a36Sopenharmony_ci	if (!efuse_region) {
60862306a36Sopenharmony_ci		adsp->lpass_efuse = NULL;
60962306a36Sopenharmony_ci		dev_dbg(adsp->dev, "failed to get efuse memory region\n");
61062306a36Sopenharmony_ci	} else {
61162306a36Sopenharmony_ci		adsp->lpass_efuse = devm_ioremap_resource(&pdev->dev, efuse_region);
61262306a36Sopenharmony_ci		if (IS_ERR(adsp->lpass_efuse)) {
61362306a36Sopenharmony_ci			dev_err(adsp->dev, "failed to map efuse registers\n");
61462306a36Sopenharmony_ci			return PTR_ERR(adsp->lpass_efuse);
61562306a36Sopenharmony_ci		}
61662306a36Sopenharmony_ci	}
61762306a36Sopenharmony_ci	syscon = of_parse_phandle(pdev->dev.of_node, "qcom,halt-regs", 0);
61862306a36Sopenharmony_ci	if (!syscon) {
61962306a36Sopenharmony_ci		dev_err(&pdev->dev, "failed to parse qcom,halt-regs\n");
62062306a36Sopenharmony_ci		return -EINVAL;
62162306a36Sopenharmony_ci	}
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ci	adsp->halt_map = syscon_node_to_regmap(syscon);
62462306a36Sopenharmony_ci	of_node_put(syscon);
62562306a36Sopenharmony_ci	if (IS_ERR(adsp->halt_map))
62662306a36Sopenharmony_ci		return PTR_ERR(adsp->halt_map);
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci	ret = of_property_read_u32_index(pdev->dev.of_node, "qcom,halt-regs",
62962306a36Sopenharmony_ci			1, &adsp->halt_lpass);
63062306a36Sopenharmony_ci	if (ret < 0) {
63162306a36Sopenharmony_ci		dev_err(&pdev->dev, "no offset in syscon\n");
63262306a36Sopenharmony_ci		return ret;
63362306a36Sopenharmony_ci	}
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ci	return 0;
63662306a36Sopenharmony_ci}
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_cistatic int adsp_alloc_memory_region(struct qcom_adsp *adsp)
63962306a36Sopenharmony_ci{
64062306a36Sopenharmony_ci	struct reserved_mem *rmem = NULL;
64162306a36Sopenharmony_ci	struct device_node *node;
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci	node = of_parse_phandle(adsp->dev->of_node, "memory-region", 0);
64462306a36Sopenharmony_ci	if (node)
64562306a36Sopenharmony_ci		rmem = of_reserved_mem_lookup(node);
64662306a36Sopenharmony_ci	of_node_put(node);
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_ci	if (!rmem) {
64962306a36Sopenharmony_ci		dev_err(adsp->dev, "unable to resolve memory-region\n");
65062306a36Sopenharmony_ci		return -EINVAL;
65162306a36Sopenharmony_ci	}
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_ci	adsp->mem_phys = adsp->mem_reloc = rmem->base;
65462306a36Sopenharmony_ci	adsp->mem_size = rmem->size;
65562306a36Sopenharmony_ci	adsp->mem_region = devm_ioremap_wc(adsp->dev,
65662306a36Sopenharmony_ci				adsp->mem_phys, adsp->mem_size);
65762306a36Sopenharmony_ci	if (!adsp->mem_region) {
65862306a36Sopenharmony_ci		dev_err(adsp->dev, "unable to map memory region: %pa+%zx\n",
65962306a36Sopenharmony_ci			&rmem->base, adsp->mem_size);
66062306a36Sopenharmony_ci		return -EBUSY;
66162306a36Sopenharmony_ci	}
66262306a36Sopenharmony_ci
66362306a36Sopenharmony_ci	return 0;
66462306a36Sopenharmony_ci}
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_cistatic int adsp_probe(struct platform_device *pdev)
66762306a36Sopenharmony_ci{
66862306a36Sopenharmony_ci	const struct adsp_pil_data *desc;
66962306a36Sopenharmony_ci	const char *firmware_name;
67062306a36Sopenharmony_ci	struct qcom_adsp *adsp;
67162306a36Sopenharmony_ci	struct rproc *rproc;
67262306a36Sopenharmony_ci	int ret;
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_ci	desc = of_device_get_match_data(&pdev->dev);
67562306a36Sopenharmony_ci	if (!desc)
67662306a36Sopenharmony_ci		return -EINVAL;
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_ci	firmware_name = desc->firmware_name;
67962306a36Sopenharmony_ci	ret = of_property_read_string(pdev->dev.of_node, "firmware-name",
68062306a36Sopenharmony_ci				      &firmware_name);
68162306a36Sopenharmony_ci	if (ret < 0 && ret != -EINVAL) {
68262306a36Sopenharmony_ci		dev_err(&pdev->dev, "unable to read firmware-name\n");
68362306a36Sopenharmony_ci		return ret;
68462306a36Sopenharmony_ci	}
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_ci	rproc = rproc_alloc(&pdev->dev, pdev->name, &adsp_ops,
68762306a36Sopenharmony_ci			    firmware_name, sizeof(*adsp));
68862306a36Sopenharmony_ci	if (!rproc) {
68962306a36Sopenharmony_ci		dev_err(&pdev->dev, "unable to allocate remoteproc\n");
69062306a36Sopenharmony_ci		return -ENOMEM;
69162306a36Sopenharmony_ci	}
69262306a36Sopenharmony_ci
69362306a36Sopenharmony_ci	rproc->auto_boot = desc->auto_boot;
69462306a36Sopenharmony_ci	rproc->has_iommu = desc->has_iommu;
69562306a36Sopenharmony_ci	rproc_coredump_set_elf_info(rproc, ELFCLASS32, EM_NONE);
69662306a36Sopenharmony_ci
69762306a36Sopenharmony_ci	adsp = rproc->priv;
69862306a36Sopenharmony_ci	adsp->dev = &pdev->dev;
69962306a36Sopenharmony_ci	adsp->rproc = rproc;
70062306a36Sopenharmony_ci	adsp->info_name = desc->sysmon_name;
70162306a36Sopenharmony_ci	adsp->has_iommu = desc->has_iommu;
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_ci	platform_set_drvdata(pdev, adsp);
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_ci	if (desc->is_wpss)
70662306a36Sopenharmony_ci		adsp->shutdown = qcom_wpss_shutdown;
70762306a36Sopenharmony_ci	else
70862306a36Sopenharmony_ci		adsp->shutdown = qcom_adsp_shutdown;
70962306a36Sopenharmony_ci
71062306a36Sopenharmony_ci	ret = adsp_alloc_memory_region(adsp);
71162306a36Sopenharmony_ci	if (ret)
71262306a36Sopenharmony_ci		goto free_rproc;
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_ci	ret = adsp_init_clock(adsp, desc->clk_ids);
71562306a36Sopenharmony_ci	if (ret)
71662306a36Sopenharmony_ci		goto free_rproc;
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_ci	ret = qcom_rproc_pds_attach(adsp->dev, adsp,
71962306a36Sopenharmony_ci				    desc->proxy_pd_names);
72062306a36Sopenharmony_ci	if (ret < 0) {
72162306a36Sopenharmony_ci		dev_err(&pdev->dev, "Failed to attach proxy power domains\n");
72262306a36Sopenharmony_ci		goto free_rproc;
72362306a36Sopenharmony_ci	}
72462306a36Sopenharmony_ci	adsp->proxy_pd_count = ret;
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_ci	ret = adsp_init_reset(adsp);
72762306a36Sopenharmony_ci	if (ret)
72862306a36Sopenharmony_ci		goto disable_pm;
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_ci	ret = adsp_init_mmio(adsp, pdev);
73162306a36Sopenharmony_ci	if (ret)
73262306a36Sopenharmony_ci		goto disable_pm;
73362306a36Sopenharmony_ci
73462306a36Sopenharmony_ci	ret = qcom_q6v5_init(&adsp->q6v5, pdev, rproc, desc->crash_reason_smem,
73562306a36Sopenharmony_ci			     desc->load_state, qcom_adsp_pil_handover);
73662306a36Sopenharmony_ci	if (ret)
73762306a36Sopenharmony_ci		goto disable_pm;
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_ci	qcom_add_glink_subdev(rproc, &adsp->glink_subdev, desc->ssr_name);
74062306a36Sopenharmony_ci	qcom_add_ssr_subdev(rproc, &adsp->ssr_subdev, desc->ssr_name);
74162306a36Sopenharmony_ci	adsp->sysmon = qcom_add_sysmon_subdev(rproc,
74262306a36Sopenharmony_ci					      desc->sysmon_name,
74362306a36Sopenharmony_ci					      desc->ssctl_id);
74462306a36Sopenharmony_ci	if (IS_ERR(adsp->sysmon)) {
74562306a36Sopenharmony_ci		ret = PTR_ERR(adsp->sysmon);
74662306a36Sopenharmony_ci		goto disable_pm;
74762306a36Sopenharmony_ci	}
74862306a36Sopenharmony_ci
74962306a36Sopenharmony_ci	ret = rproc_add(rproc);
75062306a36Sopenharmony_ci	if (ret)
75162306a36Sopenharmony_ci		goto disable_pm;
75262306a36Sopenharmony_ci
75362306a36Sopenharmony_ci	return 0;
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_cidisable_pm:
75662306a36Sopenharmony_ci	qcom_rproc_pds_detach(adsp, adsp->proxy_pds, adsp->proxy_pd_count);
75762306a36Sopenharmony_ci
75862306a36Sopenharmony_cifree_rproc:
75962306a36Sopenharmony_ci	rproc_free(rproc);
76062306a36Sopenharmony_ci
76162306a36Sopenharmony_ci	return ret;
76262306a36Sopenharmony_ci}
76362306a36Sopenharmony_ci
76462306a36Sopenharmony_cistatic void adsp_remove(struct platform_device *pdev)
76562306a36Sopenharmony_ci{
76662306a36Sopenharmony_ci	struct qcom_adsp *adsp = platform_get_drvdata(pdev);
76762306a36Sopenharmony_ci
76862306a36Sopenharmony_ci	rproc_del(adsp->rproc);
76962306a36Sopenharmony_ci
77062306a36Sopenharmony_ci	qcom_q6v5_deinit(&adsp->q6v5);
77162306a36Sopenharmony_ci	qcom_remove_glink_subdev(adsp->rproc, &adsp->glink_subdev);
77262306a36Sopenharmony_ci	qcom_remove_sysmon_subdev(adsp->sysmon);
77362306a36Sopenharmony_ci	qcom_remove_ssr_subdev(adsp->rproc, &adsp->ssr_subdev);
77462306a36Sopenharmony_ci	qcom_rproc_pds_detach(adsp, adsp->proxy_pds, adsp->proxy_pd_count);
77562306a36Sopenharmony_ci	rproc_free(adsp->rproc);
77662306a36Sopenharmony_ci}
77762306a36Sopenharmony_ci
77862306a36Sopenharmony_cistatic const struct adsp_pil_data adsp_resource_init = {
77962306a36Sopenharmony_ci	.crash_reason_smem = 423,
78062306a36Sopenharmony_ci	.firmware_name = "adsp.mdt",
78162306a36Sopenharmony_ci	.ssr_name = "lpass",
78262306a36Sopenharmony_ci	.sysmon_name = "adsp",
78362306a36Sopenharmony_ci	.ssctl_id = 0x14,
78462306a36Sopenharmony_ci	.is_wpss = false,
78562306a36Sopenharmony_ci	.auto_boot = true,
78662306a36Sopenharmony_ci	.clk_ids = (const char*[]) {
78762306a36Sopenharmony_ci		"sway_cbcr", "lpass_ahbs_aon_cbcr", "lpass_ahbm_aon_cbcr",
78862306a36Sopenharmony_ci		"qdsp6ss_xo", "qdsp6ss_sleep", "qdsp6ss_core", NULL
78962306a36Sopenharmony_ci	},
79062306a36Sopenharmony_ci	.num_clks = 7,
79162306a36Sopenharmony_ci	.proxy_pd_names = (const char*[]) {
79262306a36Sopenharmony_ci		"cx", NULL
79362306a36Sopenharmony_ci	},
79462306a36Sopenharmony_ci};
79562306a36Sopenharmony_ci
79662306a36Sopenharmony_cistatic const struct adsp_pil_data adsp_sc7280_resource_init = {
79762306a36Sopenharmony_ci	.crash_reason_smem = 423,
79862306a36Sopenharmony_ci	.firmware_name = "adsp.pbn",
79962306a36Sopenharmony_ci	.load_state = "adsp",
80062306a36Sopenharmony_ci	.ssr_name = "lpass",
80162306a36Sopenharmony_ci	.sysmon_name = "adsp",
80262306a36Sopenharmony_ci	.ssctl_id = 0x14,
80362306a36Sopenharmony_ci	.has_iommu = true,
80462306a36Sopenharmony_ci	.auto_boot = true,
80562306a36Sopenharmony_ci	.clk_ids = (const char*[]) {
80662306a36Sopenharmony_ci		"gcc_cfg_noc_lpass", NULL
80762306a36Sopenharmony_ci	},
80862306a36Sopenharmony_ci	.num_clks = 1,
80962306a36Sopenharmony_ci};
81062306a36Sopenharmony_ci
81162306a36Sopenharmony_cistatic const struct adsp_pil_data cdsp_resource_init = {
81262306a36Sopenharmony_ci	.crash_reason_smem = 601,
81362306a36Sopenharmony_ci	.firmware_name = "cdsp.mdt",
81462306a36Sopenharmony_ci	.ssr_name = "cdsp",
81562306a36Sopenharmony_ci	.sysmon_name = "cdsp",
81662306a36Sopenharmony_ci	.ssctl_id = 0x17,
81762306a36Sopenharmony_ci	.is_wpss = false,
81862306a36Sopenharmony_ci	.auto_boot = true,
81962306a36Sopenharmony_ci	.clk_ids = (const char*[]) {
82062306a36Sopenharmony_ci		"sway", "tbu", "bimc", "ahb_aon", "q6ss_slave", "q6ss_master",
82162306a36Sopenharmony_ci		"q6_axim", NULL
82262306a36Sopenharmony_ci	},
82362306a36Sopenharmony_ci	.num_clks = 7,
82462306a36Sopenharmony_ci	.proxy_pd_names = (const char*[]) {
82562306a36Sopenharmony_ci		"cx", NULL
82662306a36Sopenharmony_ci	},
82762306a36Sopenharmony_ci};
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_cistatic const struct adsp_pil_data wpss_resource_init = {
83062306a36Sopenharmony_ci	.crash_reason_smem = 626,
83162306a36Sopenharmony_ci	.firmware_name = "wpss.mdt",
83262306a36Sopenharmony_ci	.ssr_name = "wpss",
83362306a36Sopenharmony_ci	.sysmon_name = "wpss",
83462306a36Sopenharmony_ci	.ssctl_id = 0x19,
83562306a36Sopenharmony_ci	.is_wpss = true,
83662306a36Sopenharmony_ci	.auto_boot = false,
83762306a36Sopenharmony_ci	.load_state = "wpss",
83862306a36Sopenharmony_ci	.clk_ids = (const char*[]) {
83962306a36Sopenharmony_ci		"ahb_bdg", "ahb", "rscp", NULL
84062306a36Sopenharmony_ci	},
84162306a36Sopenharmony_ci	.num_clks = 3,
84262306a36Sopenharmony_ci	.proxy_pd_names = (const char*[]) {
84362306a36Sopenharmony_ci		"cx", "mx", NULL
84462306a36Sopenharmony_ci	},
84562306a36Sopenharmony_ci};
84662306a36Sopenharmony_ci
84762306a36Sopenharmony_cistatic const struct of_device_id adsp_of_match[] = {
84862306a36Sopenharmony_ci	{ .compatible = "qcom,qcs404-cdsp-pil", .data = &cdsp_resource_init },
84962306a36Sopenharmony_ci	{ .compatible = "qcom,sc7280-adsp-pil", .data = &adsp_sc7280_resource_init },
85062306a36Sopenharmony_ci	{ .compatible = "qcom,sc7280-wpss-pil", .data = &wpss_resource_init },
85162306a36Sopenharmony_ci	{ .compatible = "qcom,sdm845-adsp-pil", .data = &adsp_resource_init },
85262306a36Sopenharmony_ci	{ },
85362306a36Sopenharmony_ci};
85462306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, adsp_of_match);
85562306a36Sopenharmony_ci
85662306a36Sopenharmony_cistatic struct platform_driver adsp_pil_driver = {
85762306a36Sopenharmony_ci	.probe = adsp_probe,
85862306a36Sopenharmony_ci	.remove_new = adsp_remove,
85962306a36Sopenharmony_ci	.driver = {
86062306a36Sopenharmony_ci		.name = "qcom_q6v5_adsp",
86162306a36Sopenharmony_ci		.of_match_table = adsp_of_match,
86262306a36Sopenharmony_ci	},
86362306a36Sopenharmony_ci};
86462306a36Sopenharmony_ci
86562306a36Sopenharmony_cimodule_platform_driver(adsp_pil_driver);
86662306a36Sopenharmony_ciMODULE_DESCRIPTION("QTI SDM845 ADSP Peripheral Image Loader");
86762306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
868