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