diff options
| author | Sasha Levin <sashal@kernel.org> | 2026-03-12 07:37:08 -0400 |
|---|---|---|
| committer | Sasha Levin <sashal@kernel.org> | 2026-03-12 07:37:08 -0400 |
| commit | acc0d99aca992e5b9a17dbd26a1275f28a959715 (patch) | |
| tree | 878817fe3a3b83448f2622d3760ab9c4cf902da8 /drivers/remoteproc | |
| parent | dbe18f06a43ec3e956879604f2daf85c474a9a06 (diff) | |
| parent | 93ea7e1363fb25c108debc34b9be4a4a036ee6d4 (diff) | |
Merge 6.18.17
Signed-off-by: Sasha Levin <sashal@kernel.org>
Diffstat (limited to 'drivers/remoteproc')
31 files changed, 2359 insertions, 2704 deletions
diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig index 62f8548fb46a..48a0d3a69ed0 100644 --- a/drivers/remoteproc/Kconfig +++ b/drivers/remoteproc/Kconfig @@ -214,7 +214,7 @@ config QCOM_Q6V5_MSS handled by QCOM_Q6V5_PAS driver. config QCOM_Q6V5_PAS - tristate "Qualcomm Hexagon v5 Peripheral Authentication Service support" + tristate "Qualcomm Peripheral Authentication Service support" depends on OF && ARCH_QCOM depends on QCOM_SMEM depends on RPMSG_QCOM_SMD || RPMSG_QCOM_SMD=n @@ -229,11 +229,10 @@ config QCOM_Q6V5_PAS select QCOM_RPROC_COMMON select QCOM_SCM help - Say y here to support the TrustZone based Peripheral Image Loader - for the Qualcomm Hexagon v5 based remote processors. This is commonly - used to control subsystems such as ADSP (Audio DSP), - CDSP (Compute DSP), MPSS (Modem Peripheral SubSystem), and - SLPI (Sensor Low Power Island). + Say y here to support the TrustZone based Peripheral Image Loader for + the Qualcomm remote processors. This is commonly used to control + subsystems such as ADSP (Audio DSP), CDSP (Compute DSP), MPSS (Modem + Peripheral SubSystem), and SLPI (Sensor Low Power Island). config QCOM_Q6V5_WCSS tristate "Qualcomm Hexagon based WCSS Peripheral Image Loader" @@ -329,7 +328,8 @@ config STM32_RPROC config TI_K3_DSP_REMOTEPROC tristate "TI K3 DSP remoteproc support" - depends on ARCH_K3 + depends on ARCH_K3 || COMPILE_TEST + depends on TI_SCI_PROTOCOL || (COMPILE_TEST && TI_SCI_PROTOCOL=n) depends on OMAP2PLUS_MBOX help Say m here to support TI's C66x and C71x DSP remote processor @@ -354,7 +354,8 @@ config TI_K3_M4_REMOTEPROC config TI_K3_R5_REMOTEPROC tristate "TI K3 R5 remoteproc support" - depends on ARCH_K3 + depends on ARCH_K3 || COMPILE_TEST + depends on TI_SCI_PROTOCOL || (COMPILE_TEST && TI_SCI_PROTOCOL=n) depends on OMAP2PLUS_MBOX help Say m here to support TI's R5F remote processor subsystems diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile index 5ff4e2fee4ab..1c7598b8475d 100644 --- a/drivers/remoteproc/Makefile +++ b/drivers/remoteproc/Makefile @@ -36,7 +36,7 @@ obj-$(CONFIG_RCAR_REMOTEPROC) += rcar_rproc.o obj-$(CONFIG_ST_REMOTEPROC) += st_remoteproc.o obj-$(CONFIG_ST_SLIM_REMOTEPROC) += st_slim_rproc.o obj-$(CONFIG_STM32_RPROC) += stm32_rproc.o -obj-$(CONFIG_TI_K3_DSP_REMOTEPROC) += ti_k3_dsp_remoteproc.o -obj-$(CONFIG_TI_K3_M4_REMOTEPROC) += ti_k3_m4_remoteproc.o -obj-$(CONFIG_TI_K3_R5_REMOTEPROC) += ti_k3_r5_remoteproc.o +obj-$(CONFIG_TI_K3_DSP_REMOTEPROC) += ti_k3_dsp_remoteproc.o ti_k3_common.o +obj-$(CONFIG_TI_K3_M4_REMOTEPROC) += ti_k3_m4_remoteproc.o ti_k3_common.o +obj-$(CONFIG_TI_K3_R5_REMOTEPROC) += ti_k3_r5_remoteproc.o ti_k3_common.o obj-$(CONFIG_XLNX_R5_REMOTEPROC) += xlnx_r5_remoteproc.o diff --git a/drivers/remoteproc/da8xx_remoteproc.c b/drivers/remoteproc/da8xx_remoteproc.c index 8770d0cf1255..e418a2bf5d2e 100644 --- a/drivers/remoteproc/da8xx_remoteproc.c +++ b/drivers/remoteproc/da8xx_remoteproc.c @@ -233,6 +233,13 @@ static int da8xx_rproc_get_internal_memories(struct platform_device *pdev, return 0; } +static void da8xx_rproc_mem_release(void *data) +{ + struct device *dev = data; + + of_reserved_mem_device_release(dev); +} + static int da8xx_rproc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -251,10 +258,8 @@ static int da8xx_rproc_probe(struct platform_device *pdev) return irq; irq_data = irq_get_irq_data(irq); - if (!irq_data) { - dev_err(dev, "irq_get_irq_data(%d): NULL\n", irq); - return -EINVAL; - } + if (!irq_data) + return dev_err_probe(dev, -EINVAL, "irq_get_irq_data(%d): NULL\n", irq); bootreg = devm_platform_ioremap_resource_byname(pdev, "host1cfg"); if (IS_ERR(bootreg)) @@ -265,36 +270,24 @@ static int da8xx_rproc_probe(struct platform_device *pdev) return PTR_ERR(chipsig); dsp_clk = devm_clk_get(dev, NULL); - if (IS_ERR(dsp_clk)) { - dev_err(dev, "clk_get error: %ld\n", PTR_ERR(dsp_clk)); - - return PTR_ERR(dsp_clk); - } + if (IS_ERR(dsp_clk)) + return dev_err_probe(dev, PTR_ERR(dsp_clk), "clk_get error\n"); dsp_reset = devm_reset_control_get_exclusive(dev, NULL); - if (IS_ERR(dsp_reset)) { - if (PTR_ERR(dsp_reset) != -EPROBE_DEFER) - dev_err(dev, "unable to get reset control: %ld\n", - PTR_ERR(dsp_reset)); - - return PTR_ERR(dsp_reset); - } + if (IS_ERR(dsp_reset)) + return dev_err_probe(dev, PTR_ERR(dsp_reset), "unable to get reset control\n"); if (dev->of_node) { ret = of_reserved_mem_device_init(dev); - if (ret) { - dev_err(dev, "device does not have specific CMA pool: %d\n", - ret); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "device does not have specific CMA pool\n"); + devm_add_action_or_reset(&pdev->dev, da8xx_rproc_mem_release, &pdev->dev); } - rproc = rproc_alloc(dev, "dsp", &da8xx_rproc_ops, da8xx_fw_name, - sizeof(*drproc)); - if (!rproc) { - ret = -ENOMEM; - goto free_mem; - } + rproc = devm_rproc_alloc(dev, "dsp", &da8xx_rproc_ops, da8xx_fw_name, + sizeof(*drproc)); + if (!rproc) + return -ENOMEM; /* error recovery is not supported at present */ rproc->recovery_disabled = true; @@ -307,9 +300,7 @@ static int da8xx_rproc_probe(struct platform_device *pdev) ret = da8xx_rproc_get_internal_memories(pdev, drproc); if (ret) - goto free_rproc; - - platform_set_drvdata(pdev, rproc); + return ret; /* everything the ISR needs is now setup, so hook it up */ ret = devm_request_threaded_irq(dev, irq, da8xx_rproc_callback, @@ -317,7 +308,7 @@ static int da8xx_rproc_probe(struct platform_device *pdev) rproc); if (ret) { dev_err(dev, "devm_request_threaded_irq error: %d\n", ret); - goto free_rproc; + return ret; } /* @@ -327,7 +318,7 @@ static int da8xx_rproc_probe(struct platform_device *pdev) */ ret = reset_control_assert(dsp_reset); if (ret) - goto free_rproc; + return ret; drproc->chipsig = chipsig; drproc->bootreg = bootreg; @@ -335,39 +326,13 @@ static int da8xx_rproc_probe(struct platform_device *pdev) drproc->irq_data = irq_data; drproc->irq = irq; - ret = rproc_add(rproc); + ret = devm_rproc_add(dev, rproc); if (ret) { dev_err(dev, "rproc_add failed: %d\n", ret); - goto free_rproc; + return ret; } return 0; - -free_rproc: - rproc_free(rproc); -free_mem: - if (dev->of_node) - of_reserved_mem_device_release(dev); - return ret; -} - -static void da8xx_rproc_remove(struct platform_device *pdev) -{ - struct rproc *rproc = platform_get_drvdata(pdev); - struct da8xx_rproc *drproc = rproc->priv; - struct device *dev = &pdev->dev; - - /* - * The devm subsystem might end up releasing things before - * freeing the irq, thus allowing an interrupt to sneak in while - * the device is being removed. This should prevent that. - */ - disable_irq(drproc->irq); - - rproc_del(rproc); - rproc_free(rproc); - if (dev->of_node) - of_reserved_mem_device_release(dev); } static const struct of_device_id davinci_rproc_of_match[] __maybe_unused = { @@ -378,7 +343,6 @@ MODULE_DEVICE_TABLE(of, davinci_rproc_of_match); static struct platform_driver da8xx_rproc_driver = { .probe = da8xx_rproc_probe, - .remove_new = da8xx_rproc_remove, .driver = { .name = "davinci-rproc", .of_match_table = of_match_ptr(davinci_rproc_of_match), diff --git a/drivers/remoteproc/imx_dsp_rproc.c b/drivers/remoteproc/imx_dsp_rproc.c index 713a57200cf0..c0c2bda4964a 100644 --- a/drivers/remoteproc/imx_dsp_rproc.c +++ b/drivers/remoteproc/imx_dsp_rproc.c @@ -19,6 +19,7 @@ #include <linux/pm_runtime.h> #include <linux/regmap.h> #include <linux/remoteproc.h> +#include <linux/reset.h> #include <linux/slab.h> #include "imx_rproc.h" @@ -35,9 +36,18 @@ module_param_named(no_mailboxes, no_mailboxes, int, 0644); MODULE_PARM_DESC(no_mailboxes, "There is no mailbox between cores, so ignore remote proc reply after start, default is 0 (off)."); +/* Flag indicating that the remote is up and running */ #define REMOTE_IS_READY BIT(0) +/* Flag indicating that the host should wait for a firmware-ready response */ +#define WAIT_FW_READY BIT(1) #define REMOTE_READY_WAIT_MAX_RETRIES 500 +/* + * This flag is set in the DSP resource table's features field to indicate + * that the firmware requires the host NOT to wait for a FW_READY response. + */ +#define FEATURE_DONT_WAIT_FW_READY BIT(0) + /* att flags */ /* DSP own area */ #define ATT_OWN BIT(31) @@ -72,6 +82,10 @@ MODULE_PARM_DESC(no_mailboxes, #define IMX8ULP_SIP_HIFI_XRDC 0xc200000e +#define FW_RSC_NXP_S_MAGIC ((uint32_t)'n' << 24 | \ + (uint32_t)'x' << 16 | \ + (uint32_t)'p' << 8 | \ + (uint32_t)'s') /* * enum - Predefined Mailbox Messages * @@ -95,6 +109,7 @@ enum imx_dsp_rp_mbox_messages { /** * struct imx_dsp_rproc - DSP remote processor state * @regmap: regmap handler + * @run_stall: reset control handle used for Run/Stall operation * @rproc: rproc handler * @dsp_dcfg: device configuration pointer * @clks: clocks needed by this device @@ -111,6 +126,7 @@ enum imx_dsp_rp_mbox_messages { */ struct imx_dsp_rproc { struct regmap *regmap; + struct reset_control *run_stall; struct rproc *rproc; const struct imx_dsp_rproc_dcfg *dsp_dcfg; struct clk_bulk_data clks[DSP_RPROC_CLK_MAX]; @@ -136,6 +152,24 @@ struct imx_dsp_rproc_dcfg { int (*reset)(struct imx_dsp_rproc *priv); }; +/** + * struct fw_rsc_imx_dsp - i.MX DSP specific info + * + * @len: length of the resource entry + * @magic_num: 32-bit magic number + * @version: version of data structure + * @features: feature flags supported by the i.MX DSP firmware + * + * This represents a DSP-specific resource in the firmware's + * resource table, providing information on supported features. + */ +struct fw_rsc_imx_dsp { + uint32_t len; + uint32_t magic_num; + uint32_t version; + uint32_t features; +} __packed; + static const struct imx_rproc_att imx_dsp_rproc_att_imx8qm[] = { /* dev addr , sys addr , size , flags */ { 0x596e8000, 0x556e8000, 0x00008000, ATT_OWN }, @@ -192,9 +226,7 @@ static int imx8mp_dsp_reset(struct imx_dsp_rproc *priv) /* Keep reset asserted for 10 cycles */ usleep_range(1, 2); - regmap_update_bits(priv->regmap, IMX8M_AudioDSP_REG2, - IMX8M_AudioDSP_REG2_RUNSTALL, - IMX8M_AudioDSP_REG2_RUNSTALL); + reset_control_assert(priv->run_stall); /* Take the DSP out of reset and keep stalled for FW loading */ pwrctl = readl(dap + IMX8M_DAP_PWRCTL); @@ -231,13 +263,9 @@ static int imx8ulp_dsp_reset(struct imx_dsp_rproc *priv) /* Specific configuration for i.MX8MP */ static const struct imx_rproc_dcfg dsp_rproc_cfg_imx8mp = { - .src_reg = IMX8M_AudioDSP_REG2, - .src_mask = IMX8M_AudioDSP_REG2_RUNSTALL, - .src_start = 0, - .src_stop = IMX8M_AudioDSP_REG2_RUNSTALL, .att = imx_dsp_rproc_att_imx8mp, .att_size = ARRAY_SIZE(imx_dsp_rproc_att_imx8mp), - .method = IMX_RPROC_MMIO, + .method = IMX_RPROC_RESET_CONTROLLER, }; static const struct imx_dsp_rproc_dcfg imx_dsp_rproc_cfg_imx8mp = { @@ -300,6 +328,66 @@ static int imx_dsp_rproc_ready(struct rproc *rproc) return -ETIMEDOUT; } +/** + * imx_dsp_rproc_handle_rsc() - Handle DSP-specific resource table entries + * @rproc: remote processor instance + * @rsc_type: resource type identifier + * @rsc: pointer to the resource entry + * @offset: offset of the resource entry + * @avail: available space in the resource table + * + * Parse the DSP-specific resource entry and update flags accordingly. + * If the WAIT_FW_READY feature is set, the host must wait for the firmware + * to signal readiness before proceeding with execution. + * + * Return: RSC_HANDLED if processed successfully, RSC_IGNORED otherwise. + */ +static int imx_dsp_rproc_handle_rsc(struct rproc *rproc, u32 rsc_type, + void *rsc, int offset, int avail) +{ + struct imx_dsp_rproc *priv = rproc->priv; + struct fw_rsc_imx_dsp *imx_dsp_rsc = rsc; + struct device *dev = rproc->dev.parent; + + if (!imx_dsp_rsc) { + dev_dbg(dev, "Invalid fw_rsc_imx_dsp.\n"); + return RSC_IGNORED; + } + + /* Make sure resource isn't truncated */ + if (sizeof(struct fw_rsc_imx_dsp) > avail || + sizeof(struct fw_rsc_imx_dsp) != imx_dsp_rsc->len) { + dev_dbg(dev, "Resource fw_rsc_imx_dsp is truncated.\n"); + return RSC_IGNORED; + } + + /* + * If FW_RSC_NXP_S_MAGIC number is not found then + * wait for fw_ready reply (default work flow) + */ + if (imx_dsp_rsc->magic_num != FW_RSC_NXP_S_MAGIC) { + dev_dbg(dev, "Invalid resource table magic number.\n"); + return RSC_IGNORED; + } + + /* + * For now, in struct fw_rsc_imx_dsp, version 0, + * only FEATURE_DONT_WAIT_FW_READY is valid. + * + * When adding new features, please upgrade version. + */ + if (imx_dsp_rsc->version > 0) { + dev_warn(dev, "Unexpected fw_rsc_imx_dsp version %d.\n", + imx_dsp_rsc->version); + return RSC_IGNORED; + } + + if (imx_dsp_rsc->features & FEATURE_DONT_WAIT_FW_READY) + priv->flags &= ~WAIT_FW_READY; + + return RSC_HANDLED; +} + /* * Start function for rproc_ops * @@ -329,14 +417,17 @@ static int imx_dsp_rproc_start(struct rproc *rproc) true, rproc->bootaddr); break; + case IMX_RPROC_RESET_CONTROLLER: + ret = reset_control_deassert(priv->run_stall); + break; default: return -EOPNOTSUPP; } if (ret) dev_err(dev, "Failed to enable remote core!\n"); - else - ret = imx_dsp_rproc_ready(rproc); + else if (priv->flags & WAIT_FW_READY) + return imx_dsp_rproc_ready(rproc); return ret; } @@ -369,6 +460,9 @@ static int imx_dsp_rproc_stop(struct rproc *rproc) false, rproc->bootaddr); break; + case IMX_RPROC_RESET_CONTROLLER: + ret = reset_control_assert(priv->run_stall); + break; default: return -EOPNOTSUPP; } @@ -680,7 +774,6 @@ static int imx_dsp_rproc_prepare(struct rproc *rproc) { struct imx_dsp_rproc *priv = rproc->priv; struct device *dev = rproc->dev.parent; - struct rproc_mem_entry *carveout; int ret; ret = imx_dsp_rproc_add_carveout(priv); @@ -691,15 +784,6 @@ static int imx_dsp_rproc_prepare(struct rproc *rproc) pm_runtime_get_sync(dev); - /* - * Clear buffers after pm rumtime for internal ocram is not - * accessible if power and clock are not enabled. - */ - list_for_each_entry(carveout, &rproc->carveouts, node) { - if (carveout->va) - memset(carveout->va, 0, carveout->len); - } - return 0; } @@ -928,14 +1012,43 @@ static int imx_dsp_rproc_parse_fw(struct rproc *rproc, const struct firmware *fw return 0; } +static int imx_dsp_rproc_load(struct rproc *rproc, const struct firmware *fw) +{ + struct imx_dsp_rproc *priv = rproc->priv; + const struct imx_dsp_rproc_dcfg *dsp_dcfg = priv->dsp_dcfg; + struct rproc_mem_entry *carveout; + int ret; + + /* Reset DSP if needed */ + if (dsp_dcfg->reset) + dsp_dcfg->reset(priv); + /* + * Clear buffers after pm rumtime for internal ocram is not + * accessible if power and clock are not enabled. + */ + if (rproc->state == RPROC_OFFLINE) { + list_for_each_entry(carveout, &rproc->carveouts, node) { + if (carveout->va) + memset(carveout->va, 0, carveout->len); + } + } + + ret = imx_dsp_rproc_elf_load_segments(rproc, fw); + if (ret) + return ret; + + return 0; +} + static const struct rproc_ops imx_dsp_rproc_ops = { .prepare = imx_dsp_rproc_prepare, .unprepare = imx_dsp_rproc_unprepare, .start = imx_dsp_rproc_start, .stop = imx_dsp_rproc_stop, .kick = imx_dsp_rproc_kick, - .load = imx_dsp_rproc_elf_load_segments, + .load = imx_dsp_rproc_load, .parse_fw = imx_dsp_rproc_parse_fw, + .handle_rsc = imx_dsp_rproc_handle_rsc, .find_loaded_rsc_table = rproc_elf_find_loaded_rsc_table, .sanity_check = rproc_elf_sanity_check, .get_boot_addr = rproc_elf_get_boot_addr, @@ -995,6 +1108,13 @@ static int imx_dsp_rproc_detect_mode(struct imx_dsp_rproc *priv) priv->regmap = regmap; break; + case IMX_RPROC_RESET_CONTROLLER: + priv->run_stall = devm_reset_control_get_exclusive(dev, "runstall"); + if (IS_ERR(priv->run_stall)) { + dev_err(dev, "Failed to get DSP runstall reset control\n"); + return PTR_ERR(priv->run_stall); + } + break; default: ret = -EOPNOTSUPP; break; @@ -1048,6 +1168,8 @@ static int imx_dsp_rproc_probe(struct platform_device *pdev) priv = rproc->priv; priv->rproc = rproc; priv->dsp_dcfg = dsp_dcfg; + /* By default, host waits for fw_ready reply */ + priv->flags |= WAIT_FW_READY; if (no_mailboxes) imx_dsp_rproc_mbox_init = imx_dsp_rproc_mbox_no_alloc; @@ -1085,6 +1207,8 @@ static int imx_dsp_rproc_probe(struct platform_device *pdev) goto err_detach_domains; } + rproc_coredump_set_elf_info(rproc, ELFCLASS32, EM_XTENSA); + pm_runtime_enable(dev); return 0; @@ -1110,7 +1234,6 @@ static int imx_dsp_runtime_resume(struct device *dev) { struct rproc *rproc = dev_get_drvdata(dev); struct imx_dsp_rproc *priv = rproc->priv; - const struct imx_dsp_rproc_dcfg *dsp_dcfg = priv->dsp_dcfg; int ret; /* @@ -1131,10 +1254,6 @@ static int imx_dsp_runtime_resume(struct device *dev) return ret; } - /* Reset DSP if needed */ - if (dsp_dcfg->reset) - dsp_dcfg->reset(priv); - return 0; } @@ -1267,7 +1386,7 @@ MODULE_DEVICE_TABLE(of, imx_dsp_rproc_of_match); static struct platform_driver imx_dsp_rproc_driver = { .probe = imx_dsp_rproc_probe, - .remove_new = imx_dsp_rproc_remove, + .remove = imx_dsp_rproc_remove, .driver = { .name = "imx-dsp-rproc", .of_match_table = imx_dsp_rproc_of_match, diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c index 2797b7e97142..7ef99eac37f1 100644 --- a/drivers/remoteproc/imx_rproc.c +++ b/drivers/remoteproc/imx_rproc.c @@ -18,6 +18,7 @@ #include <linux/of_reserved_mem.h> #include <linux/platform_device.h> #include <linux/pm_domain.h> +#include <linux/pm_runtime.h> #include <linux/reboot.h> #include <linux/regmap.h> #include <linux/remoteproc.h> @@ -284,161 +285,101 @@ static const struct imx_rproc_att imx_rproc_att_imx6sx[] = { { 0x80000000, 0x80000000, 0x60000000, 0 }, }; -static const struct imx_rproc_dcfg imx_rproc_cfg_imx8mn_mmio = { - .src_reg = IMX7D_SRC_SCR, - .src_mask = IMX7D_M4_RST_MASK, - .src_start = IMX7D_M4_START, - .src_stop = IMX8M_M7_STOP, - .gpr_reg = IMX8M_GPR22, - .gpr_wait = IMX8M_GPR22_CM7_CPUWAIT, - .att = imx_rproc_att_imx8mn, - .att_size = ARRAY_SIZE(imx_rproc_att_imx8mn), - .method = IMX_RPROC_MMIO, -}; - -static const struct imx_rproc_dcfg imx_rproc_cfg_imx8mn = { - .att = imx_rproc_att_imx8mn, - .att_size = ARRAY_SIZE(imx_rproc_att_imx8mn), - .method = IMX_RPROC_SMC, -}; - -static const struct imx_rproc_dcfg imx_rproc_cfg_imx8mq = { - .src_reg = IMX7D_SRC_SCR, - .src_mask = IMX7D_M4_RST_MASK, - .src_start = IMX7D_M4_START, - .src_stop = IMX7D_M4_STOP, - .att = imx_rproc_att_imx8mq, - .att_size = ARRAY_SIZE(imx_rproc_att_imx8mq), - .method = IMX_RPROC_MMIO, -}; +static int imx_rproc_arm_smc_start(struct rproc *rproc) +{ + struct arm_smccc_res res; -static const struct imx_rproc_dcfg imx_rproc_cfg_imx8qm = { - .att = imx_rproc_att_imx8qm, - .att_size = ARRAY_SIZE(imx_rproc_att_imx8qm), - .method = IMX_RPROC_SCU_API, -}; + arm_smccc_smc(IMX_SIP_RPROC, IMX_SIP_RPROC_START, 0, 0, 0, 0, 0, 0, &res); -static const struct imx_rproc_dcfg imx_rproc_cfg_imx8qxp = { - .att = imx_rproc_att_imx8qxp, - .att_size = ARRAY_SIZE(imx_rproc_att_imx8qxp), - .method = IMX_RPROC_SCU_API, -}; + return res.a0; +} -static const struct imx_rproc_dcfg imx_rproc_cfg_imx8ulp = { - .att = imx_rproc_att_imx8ulp, - .att_size = ARRAY_SIZE(imx_rproc_att_imx8ulp), - .method = IMX_RPROC_NONE, -}; +static int imx_rproc_mmio_start(struct rproc *rproc) +{ + struct imx_rproc *priv = rproc->priv; + const struct imx_rproc_dcfg *dcfg = priv->dcfg; -static const struct imx_rproc_dcfg imx_rproc_cfg_imx7ulp = { - .att = imx_rproc_att_imx7ulp, - .att_size = ARRAY_SIZE(imx_rproc_att_imx7ulp), - .method = IMX_RPROC_NONE, - .flags = IMX_RPROC_NEED_SYSTEM_OFF, -}; + if (priv->gpr) + return regmap_clear_bits(priv->gpr, dcfg->gpr_reg, dcfg->gpr_wait); -static const struct imx_rproc_dcfg imx_rproc_cfg_imx7d = { - .src_reg = IMX7D_SRC_SCR, - .src_mask = IMX7D_M4_RST_MASK, - .src_start = IMX7D_M4_START, - .src_stop = IMX7D_M4_STOP, - .att = imx_rproc_att_imx7d, - .att_size = ARRAY_SIZE(imx_rproc_att_imx7d), - .method = IMX_RPROC_MMIO, -}; + return regmap_update_bits(priv->regmap, dcfg->src_reg, dcfg->src_mask, dcfg->src_start); +} -static const struct imx_rproc_dcfg imx_rproc_cfg_imx6sx = { - .src_reg = IMX6SX_SRC_SCR, - .src_mask = IMX6SX_M4_RST_MASK, - .src_start = IMX6SX_M4_START, - .src_stop = IMX6SX_M4_STOP, - .att = imx_rproc_att_imx6sx, - .att_size = ARRAY_SIZE(imx_rproc_att_imx6sx), - .method = IMX_RPROC_MMIO, -}; +static int imx_rproc_scu_api_start(struct rproc *rproc) +{ + struct imx_rproc *priv = rproc->priv; -static const struct imx_rproc_dcfg imx_rproc_cfg_imx93 = { - .att = imx_rproc_att_imx93, - .att_size = ARRAY_SIZE(imx_rproc_att_imx93), - .method = IMX_RPROC_SMC, -}; + return imx_sc_pm_cpu_start(priv->ipc_handle, priv->rsrc_id, true, priv->entry); +} static int imx_rproc_start(struct rproc *rproc) { struct imx_rproc *priv = rproc->priv; const struct imx_rproc_dcfg *dcfg = priv->dcfg; struct device *dev = priv->dev; - struct arm_smccc_res res; int ret; ret = imx_rproc_xtr_mbox_init(rproc, true); if (ret) return ret; - switch (dcfg->method) { - case IMX_RPROC_MMIO: - if (priv->gpr) { - ret = regmap_clear_bits(priv->gpr, dcfg->gpr_reg, - dcfg->gpr_wait); - } else { - ret = regmap_update_bits(priv->regmap, dcfg->src_reg, - dcfg->src_mask, - dcfg->src_start); - } - break; - case IMX_RPROC_SMC: - arm_smccc_smc(IMX_SIP_RPROC, IMX_SIP_RPROC_START, 0, 0, 0, 0, 0, 0, &res); - ret = res.a0; - break; - case IMX_RPROC_SCU_API: - ret = imx_sc_pm_cpu_start(priv->ipc_handle, priv->rsrc_id, true, priv->entry); - break; - default: + if (!dcfg->ops || !dcfg->ops->start) return -EOPNOTSUPP; - } + ret = dcfg->ops->start(rproc); if (ret) dev_err(dev, "Failed to enable remote core!\n"); return ret; } -static int imx_rproc_stop(struct rproc *rproc) +static int imx_rproc_arm_smc_stop(struct rproc *rproc) { struct imx_rproc *priv = rproc->priv; - const struct imx_rproc_dcfg *dcfg = priv->dcfg; - struct device *dev = priv->dev; struct arm_smccc_res res; + + arm_smccc_smc(IMX_SIP_RPROC, IMX_SIP_RPROC_STOP, 0, 0, 0, 0, 0, 0, &res); + if (res.a1) + dev_info(priv->dev, "Not in wfi, force stopped\n"); + + return res.a0; +} + +static int imx_rproc_mmio_stop(struct rproc *rproc) +{ + struct imx_rproc *priv = rproc->priv; + const struct imx_rproc_dcfg *dcfg = priv->dcfg; int ret; - switch (dcfg->method) { - case IMX_RPROC_MMIO: - if (priv->gpr) { - ret = regmap_set_bits(priv->gpr, dcfg->gpr_reg, - dcfg->gpr_wait); - if (ret) { - dev_err(priv->dev, - "Failed to quiescence M4 platform!\n"); - return ret; - } + if (priv->gpr) { + ret = regmap_set_bits(priv->gpr, dcfg->gpr_reg, dcfg->gpr_wait); + if (ret) { + dev_err(priv->dev, "Failed to quiescence M4 platform!\n"); + return ret; } + } - ret = regmap_update_bits(priv->regmap, dcfg->src_reg, dcfg->src_mask, - dcfg->src_stop); - break; - case IMX_RPROC_SMC: - arm_smccc_smc(IMX_SIP_RPROC, IMX_SIP_RPROC_STOP, 0, 0, 0, 0, 0, 0, &res); - ret = res.a0; - if (res.a1) - dev_info(dev, "Not in wfi, force stopped\n"); - break; - case IMX_RPROC_SCU_API: - ret = imx_sc_pm_cpu_start(priv->ipc_handle, priv->rsrc_id, false, priv->entry); - break; - default: + return regmap_update_bits(priv->regmap, dcfg->src_reg, dcfg->src_mask, dcfg->src_stop); +} + +static int imx_rproc_scu_api_stop(struct rproc *rproc) +{ + struct imx_rproc *priv = rproc->priv; + + return imx_sc_pm_cpu_start(priv->ipc_handle, priv->rsrc_id, false, priv->entry); +} + +static int imx_rproc_stop(struct rproc *rproc) +{ + struct imx_rproc *priv = rproc->priv; + const struct imx_rproc_dcfg *dcfg = priv->dcfg; + struct device *dev = priv->dev; + int ret; + + if (!dcfg->ops || !dcfg->ops->stop) return -EOPNOTSUPP; - } + ret = dcfg->ops->stop(rproc); if (ret) dev_err(dev, "Failed to stop remote core\n"); else @@ -894,10 +835,8 @@ static int imx_rproc_partition_notify(struct notifier_block *nb, static int imx_rproc_attach_pd(struct imx_rproc *priv) { struct device *dev = priv->dev; - int ret; - struct dev_pm_domain_attach_data pd_data = { - .pd_flags = PD_FLAG_DEV_LINK_ON, - }; + int ret, i; + bool detached = true; /* * If there is only one power-domain entry, the platform driver framework @@ -906,88 +845,48 @@ static int imx_rproc_attach_pd(struct imx_rproc *priv) if (dev->pm_domain) return 0; - ret = dev_pm_domain_attach_list(dev, &pd_data, &priv->pd_list); - return ret < 0 ? ret : 0; -} - -static int imx_rproc_detect_mode(struct imx_rproc *priv) -{ - struct regmap_config config = { .name = "imx-rproc" }; - const struct imx_rproc_dcfg *dcfg = priv->dcfg; - struct device *dev = priv->dev; - struct regmap *regmap; - struct arm_smccc_res res; - int ret; - u32 val; - u8 pt; - - switch (dcfg->method) { - case IMX_RPROC_NONE: - priv->rproc->state = RPROC_DETACHED; - return 0; - case IMX_RPROC_SMC: - arm_smccc_smc(IMX_SIP_RPROC, IMX_SIP_RPROC_STARTED, 0, 0, 0, 0, 0, 0, &res); - if (res.a0) - priv->rproc->state = RPROC_DETACHED; - return 0; - case IMX_RPROC_SCU_API: - ret = imx_scu_get_handle(&priv->ipc_handle); - if (ret) - return ret; - ret = of_property_read_u32(dev->of_node, "fsl,resource-id", &priv->rsrc_id); - if (ret) { - dev_err(dev, "No fsl,resource-id property\n"); - return ret; - } - - if (priv->rsrc_id == IMX_SC_R_M4_1_PID0) - priv->core_index = 1; - else - priv->core_index = 0; - - /* - * If Mcore resource is not owned by Acore partition, It is kicked by ROM, - * and Linux could only do IPC with Mcore and nothing else. - */ - if (imx_sc_rm_is_resource_owned(priv->ipc_handle, priv->rsrc_id)) { - if (of_property_read_u32(dev->of_node, "fsl,entry-address", &priv->entry)) - return -EINVAL; - - return imx_rproc_attach_pd(priv); + ret = dev_pm_domain_attach_list(dev, NULL, &priv->pd_list); + if (ret < 0) + return ret; + /* + * If all the power domain devices are already turned on, the remote + * core is already powered up and running when the kernel booted (e.g., + * started by U-Boot's bootaux command). In this case attach to it. + */ + for (i = 0; i < ret; i++) { + if (!dev_pm_genpd_is_on(priv->pd_list->pd_devs[i])) { + detached = false; + break; } + } + if (detached) priv->rproc->state = RPROC_DETACHED; - priv->rproc->recovery_disabled = false; - rproc_set_feature(priv->rproc, RPROC_FEAT_ATTACH_ON_RECOVERY); - /* Get partition id and enable irq in SCFW */ - ret = imx_sc_rm_get_resource_owner(priv->ipc_handle, priv->rsrc_id, &pt); - if (ret) { - dev_err(dev, "not able to get resource owner\n"); - return ret; - } + return 0; +} - priv->rproc_pt = pt; - priv->rproc_nb.notifier_call = imx_rproc_partition_notify; +static int imx_rproc_arm_smc_detect_mode(struct rproc *rproc) +{ + struct imx_rproc *priv = rproc->priv; + struct arm_smccc_res res; - ret = imx_scu_irq_register_notifier(&priv->rproc_nb); - if (ret) { - dev_err(dev, "register scu notifier failed, %d\n", ret); - return ret; - } + arm_smccc_smc(IMX_SIP_RPROC, IMX_SIP_RPROC_STARTED, 0, 0, 0, 0, 0, 0, &res); + if (res.a0) + priv->rproc->state = RPROC_DETACHED; - ret = imx_scu_irq_group_enable(IMX_SC_IRQ_GROUP_REBOOTED, BIT(priv->rproc_pt), - true); - if (ret) { - imx_scu_irq_unregister_notifier(&priv->rproc_nb); - dev_err(dev, "Enable irq failed, %d\n", ret); - return ret; - } + return 0; +} - return 0; - default: - break; - } +static int imx_rproc_mmio_detect_mode(struct rproc *rproc) +{ + const struct regmap_config config = { .name = "imx-rproc" }; + struct imx_rproc *priv = rproc->priv; + const struct imx_rproc_dcfg *dcfg = priv->dcfg; + struct device *dev = priv->dev; + struct regmap *regmap; + u32 val; + int ret; priv->gpr = syscon_regmap_lookup_by_phandle(dev->of_node, "fsl,iomuxc-gpr"); if (IS_ERR(priv->gpr)) @@ -1027,6 +926,85 @@ static int imx_rproc_detect_mode(struct imx_rproc *priv) return 0; } +static int imx_rproc_scu_api_detect_mode(struct rproc *rproc) +{ + struct imx_rproc *priv = rproc->priv; + struct device *dev = priv->dev; + int ret; + u8 pt; + + ret = imx_scu_get_handle(&priv->ipc_handle); + if (ret) + return ret; + ret = of_property_read_u32(dev->of_node, "fsl,resource-id", &priv->rsrc_id); + if (ret) { + dev_err(dev, "No fsl,resource-id property\n"); + return ret; + } + + if (priv->rsrc_id == IMX_SC_R_M4_1_PID0) + priv->core_index = 1; + else + priv->core_index = 0; + + /* + * If Mcore resource is not owned by Acore partition, It is kicked by ROM, + * and Linux could only do IPC with Mcore and nothing else. + */ + if (imx_sc_rm_is_resource_owned(priv->ipc_handle, priv->rsrc_id)) { + if (of_property_read_u32(dev->of_node, "fsl,entry-address", &priv->entry)) + return -EINVAL; + + return imx_rproc_attach_pd(priv); + } + + priv->rproc->state = RPROC_DETACHED; + priv->rproc->recovery_disabled = false; + rproc_set_feature(priv->rproc, RPROC_FEAT_ATTACH_ON_RECOVERY); + + /* Get partition id and enable irq in SCFW */ + ret = imx_sc_rm_get_resource_owner(priv->ipc_handle, priv->rsrc_id, &pt); + if (ret) { + dev_err(dev, "not able to get resource owner\n"); + return ret; + } + + priv->rproc_pt = pt; + priv->rproc_nb.notifier_call = imx_rproc_partition_notify; + + ret = imx_scu_irq_register_notifier(&priv->rproc_nb); + if (ret) { + dev_err(dev, "register scu notifier failed, %d\n", ret); + return ret; + } + + ret = imx_scu_irq_group_enable(IMX_SC_IRQ_GROUP_REBOOTED, BIT(priv->rproc_pt), + true); + if (ret) { + imx_scu_irq_unregister_notifier(&priv->rproc_nb); + dev_err(dev, "Enable irq failed, %d\n", ret); + return ret; + } + + return 0; +} + +static int imx_rproc_detect_mode(struct imx_rproc *priv) +{ + const struct imx_rproc_dcfg *dcfg = priv->dcfg; + + /* + * To i.MX{7,8} ULP, Linux is under control of RTOS, no need + * dcfg->ops or dcfg->ops->detect_mode, it is state RPROC_DETACHED. + */ + if (!dcfg->ops || !dcfg->ops->detect_mode) { + priv->rproc->state = RPROC_DETACHED; + return 0; + } + + return dcfg->ops->detect_mode(priv->rproc); +} + static int imx_rproc_clk_enable(struct imx_rproc *priv) { const struct imx_rproc_dcfg *dcfg = priv->dcfg; @@ -1150,14 +1128,28 @@ static int imx_rproc_probe(struct platform_device *pdev) } } + if (dcfg->method == IMX_RPROC_SCU_API) { + pm_runtime_enable(dev); + ret = pm_runtime_resume_and_get(dev); + if (ret) { + dev_err(dev, "pm_runtime get failed: %d\n", ret); + goto err_put_clk; + } + } + ret = rproc_add(rproc); if (ret) { dev_err(dev, "rproc_add failed\n"); - goto err_put_clk; + goto err_put_pm; } return 0; +err_put_pm: + if (dcfg->method == IMX_RPROC_SCU_API) { + pm_runtime_disable(dev); + pm_runtime_put_noidle(dev); + } err_put_clk: clk_disable_unprepare(priv->clk); err_put_scu: @@ -1175,6 +1167,10 @@ static void imx_rproc_remove(struct platform_device *pdev) struct rproc *rproc = platform_get_drvdata(pdev); struct imx_rproc *priv = rproc->priv; + if (priv->dcfg->method == IMX_RPROC_SCU_API) { + pm_runtime_disable(priv->dev); + pm_runtime_put_noidle(priv->dev); + } clk_disable_unprepare(priv->clk); rproc_del(rproc); imx_rproc_put_scu(rproc); @@ -1182,6 +1178,111 @@ static void imx_rproc_remove(struct platform_device *pdev) destroy_workqueue(priv->workqueue); } +static const struct imx_rproc_plat_ops imx_rproc_ops_arm_smc = { + .start = imx_rproc_arm_smc_start, + .stop = imx_rproc_arm_smc_stop, + .detect_mode = imx_rproc_arm_smc_detect_mode, +}; + +static const struct imx_rproc_plat_ops imx_rproc_ops_mmio = { + .start = imx_rproc_mmio_start, + .stop = imx_rproc_mmio_stop, + .detect_mode = imx_rproc_mmio_detect_mode, +}; + +static const struct imx_rproc_plat_ops imx_rproc_ops_scu_api = { + .start = imx_rproc_scu_api_start, + .stop = imx_rproc_scu_api_stop, + .detect_mode = imx_rproc_scu_api_detect_mode, +}; + +static const struct imx_rproc_dcfg imx_rproc_cfg_imx8mn_mmio = { + .src_reg = IMX7D_SRC_SCR, + .src_mask = IMX7D_M4_RST_MASK, + .src_start = IMX7D_M4_START, + .src_stop = IMX8M_M7_STOP, + .gpr_reg = IMX8M_GPR22, + .gpr_wait = IMX8M_GPR22_CM7_CPUWAIT, + .att = imx_rproc_att_imx8mn, + .att_size = ARRAY_SIZE(imx_rproc_att_imx8mn), + .method = IMX_RPROC_MMIO, + .ops = &imx_rproc_ops_mmio, +}; + +static const struct imx_rproc_dcfg imx_rproc_cfg_imx8mn = { + .att = imx_rproc_att_imx8mn, + .att_size = ARRAY_SIZE(imx_rproc_att_imx8mn), + .method = IMX_RPROC_SMC, + .ops = &imx_rproc_ops_arm_smc, +}; + +static const struct imx_rproc_dcfg imx_rproc_cfg_imx8mq = { + .src_reg = IMX7D_SRC_SCR, + .src_mask = IMX7D_M4_RST_MASK, + .src_start = IMX7D_M4_START, + .src_stop = IMX7D_M4_STOP, + .att = imx_rproc_att_imx8mq, + .att_size = ARRAY_SIZE(imx_rproc_att_imx8mq), + .method = IMX_RPROC_MMIO, + .ops = &imx_rproc_ops_mmio, +}; + +static const struct imx_rproc_dcfg imx_rproc_cfg_imx8qm = { + .att = imx_rproc_att_imx8qm, + .att_size = ARRAY_SIZE(imx_rproc_att_imx8qm), + .method = IMX_RPROC_SCU_API, + .ops = &imx_rproc_ops_scu_api, +}; + +static const struct imx_rproc_dcfg imx_rproc_cfg_imx8qxp = { + .att = imx_rproc_att_imx8qxp, + .att_size = ARRAY_SIZE(imx_rproc_att_imx8qxp), + .method = IMX_RPROC_SCU_API, + .ops = &imx_rproc_ops_scu_api, +}; + +static const struct imx_rproc_dcfg imx_rproc_cfg_imx8ulp = { + .att = imx_rproc_att_imx8ulp, + .att_size = ARRAY_SIZE(imx_rproc_att_imx8ulp), + .method = IMX_RPROC_NONE, +}; + +static const struct imx_rproc_dcfg imx_rproc_cfg_imx7ulp = { + .att = imx_rproc_att_imx7ulp, + .att_size = ARRAY_SIZE(imx_rproc_att_imx7ulp), + .method = IMX_RPROC_NONE, + .flags = IMX_RPROC_NEED_SYSTEM_OFF, +}; + +static const struct imx_rproc_dcfg imx_rproc_cfg_imx7d = { + .src_reg = IMX7D_SRC_SCR, + .src_mask = IMX7D_M4_RST_MASK, + .src_start = IMX7D_M4_START, + .src_stop = IMX7D_M4_STOP, + .att = imx_rproc_att_imx7d, + .att_size = ARRAY_SIZE(imx_rproc_att_imx7d), + .method = IMX_RPROC_MMIO, + .ops = &imx_rproc_ops_mmio, +}; + +static const struct imx_rproc_dcfg imx_rproc_cfg_imx6sx = { + .src_reg = IMX6SX_SRC_SCR, + .src_mask = IMX6SX_M4_RST_MASK, + .src_start = IMX6SX_M4_START, + .src_stop = IMX6SX_M4_STOP, + .att = imx_rproc_att_imx6sx, + .att_size = ARRAY_SIZE(imx_rproc_att_imx6sx), + .method = IMX_RPROC_MMIO, + .ops = &imx_rproc_ops_mmio, +}; + +static const struct imx_rproc_dcfg imx_rproc_cfg_imx93 = { + .att = imx_rproc_att_imx93, + .att_size = ARRAY_SIZE(imx_rproc_att_imx93), + .method = IMX_RPROC_SMC, + .ops = &imx_rproc_ops_arm_smc, +}; + static const struct of_device_id imx_rproc_of_match[] = { { .compatible = "fsl,imx7ulp-cm4", .data = &imx_rproc_cfg_imx7ulp }, { .compatible = "fsl,imx7d-cm4", .data = &imx_rproc_cfg_imx7d }, @@ -1202,7 +1303,7 @@ MODULE_DEVICE_TABLE(of, imx_rproc_of_match); static struct platform_driver imx_rproc_driver = { .probe = imx_rproc_probe, - .remove_new = imx_rproc_remove, + .remove = imx_rproc_remove, .driver = { .name = "imx-rproc", .of_match_table = imx_rproc_of_match, diff --git a/drivers/remoteproc/imx_rproc.h b/drivers/remoteproc/imx_rproc.h index 17a7d051c531..3a9adaaf048b 100644 --- a/drivers/remoteproc/imx_rproc.h +++ b/drivers/remoteproc/imx_rproc.h @@ -24,11 +24,19 @@ enum imx_rproc_method { IMX_RPROC_SMC, /* Through System Control Unit API */ IMX_RPROC_SCU_API, + /* Through Reset Controller API */ + IMX_RPROC_RESET_CONTROLLER, }; /* dcfg flags */ #define IMX_RPROC_NEED_SYSTEM_OFF BIT(0) +struct imx_rproc_plat_ops { + int (*start)(struct rproc *rproc); + int (*stop)(struct rproc *rproc); + int (*detect_mode)(struct rproc *rproc); +}; + struct imx_rproc_dcfg { u32 src_reg; u32 src_mask; @@ -40,6 +48,7 @@ struct imx_rproc_dcfg { size_t att_size; enum imx_rproc_method method; u32 flags; + const struct imx_rproc_plat_ops *ops; }; #endif /* _IMX_RPROC_H */ diff --git a/drivers/remoteproc/keystone_remoteproc.c b/drivers/remoteproc/keystone_remoteproc.c index 8f0f7a4cfef2..4d6550b48567 100644 --- a/drivers/remoteproc/keystone_remoteproc.c +++ b/drivers/remoteproc/keystone_remoteproc.c @@ -335,29 +335,34 @@ static int keystone_rproc_of_get_dev_syscon(struct platform_device *pdev, { struct device_node *np = pdev->dev.of_node; struct device *dev = &pdev->dev; - int ret; if (!of_property_read_bool(np, "ti,syscon-dev")) { dev_err(dev, "ti,syscon-dev property is absent\n"); return -EINVAL; } - ksproc->dev_ctrl = - syscon_regmap_lookup_by_phandle(np, "ti,syscon-dev"); - if (IS_ERR(ksproc->dev_ctrl)) { - ret = PTR_ERR(ksproc->dev_ctrl); - return ret; - } - - if (of_property_read_u32_index(np, "ti,syscon-dev", 1, - &ksproc->boot_offset)) { - dev_err(dev, "couldn't read the boot register offset\n"); - return -EINVAL; - } + ksproc->dev_ctrl = syscon_regmap_lookup_by_phandle_args(np, "ti,syscon-dev", + 1, &ksproc->boot_offset); + if (IS_ERR(ksproc->dev_ctrl)) + return PTR_ERR(ksproc->dev_ctrl); return 0; } +static void keystone_rproc_mem_release(void *data) +{ + struct device *dev = data; + + of_reserved_mem_device_release(dev); +} + +static void keystone_rproc_pm_runtime_put(void *data) +{ + struct device *dev = data; + + pm_runtime_put_sync(dev); +} + static int keystone_rproc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -403,80 +408,58 @@ static int keystone_rproc_probe(struct platform_device *pdev) return PTR_ERR(ksproc->reset); /* enable clock for accessing DSP internal memories */ - pm_runtime_enable(dev); + ret = devm_pm_runtime_enable(dev); + if (ret < 0) + return dev_err_probe(dev, ret, "Failed to enable runtime PM\n"); + ret = pm_runtime_resume_and_get(dev); - if (ret < 0) { - dev_err(dev, "failed to enable clock, status = %d\n", ret); - goto disable_rpm; - } + if (ret < 0) + return dev_err_probe(dev, ret, "failed to enable clock\n"); + + ret = devm_add_action_or_reset(dev, keystone_rproc_pm_runtime_put, dev); + if (ret) + return dev_err_probe(dev, ret, "failed to add disable pm devm action\n"); ret = keystone_rproc_of_get_memories(pdev, ksproc); if (ret) - goto disable_clk; + return ret; ksproc->irq_ring = platform_get_irq_byname(pdev, "vring"); - if (ksproc->irq_ring < 0) { - ret = ksproc->irq_ring; - goto disable_clk; - } + if (ksproc->irq_ring < 0) + return ksproc->irq_ring; ksproc->irq_fault = platform_get_irq_byname(pdev, "exception"); - if (ksproc->irq_fault < 0) { - ret = ksproc->irq_fault; - goto disable_clk; - } + if (ksproc->irq_fault < 0) + return ksproc->irq_fault; - ksproc->kick_gpio = gpiod_get(dev, "kick", GPIOD_ASIS); + ksproc->kick_gpio = devm_gpiod_get(dev, "kick", GPIOD_ASIS); ret = PTR_ERR_OR_ZERO(ksproc->kick_gpio); - if (ret) { - dev_err(dev, "failed to get gpio for virtio kicks, status = %d\n", - ret); - goto disable_clk; - } + if (ret) + return dev_err_probe(dev, ret, "failed to get gpio for virtio kicks\n"); - if (of_reserved_mem_device_init(dev)) + ret = of_reserved_mem_device_init(dev); + if (ret) { dev_warn(dev, "device does not have specific CMA pool\n"); + } else { + ret = devm_add_action_or_reset(dev, keystone_rproc_mem_release, dev); + if (ret) + return ret; + } /* ensure the DSP is in reset before loading firmware */ ret = reset_control_status(ksproc->reset); if (ret < 0) { - dev_err(dev, "failed to get reset status, status = %d\n", ret); - goto release_mem; + return dev_err_probe(dev, ret, "failed to get reset status\n"); } else if (ret == 0) { WARN(1, "device is not in reset\n"); keystone_rproc_dsp_reset(ksproc); } - ret = rproc_add(rproc); - if (ret) { - dev_err(dev, "failed to add register device with remoteproc core, status = %d\n", - ret); - goto release_mem; - } - - platform_set_drvdata(pdev, ksproc); + ret = devm_rproc_add(dev, rproc); + if (ret) + return dev_err_probe(dev, ret, "failed to register device with remoteproc core\n"); return 0; - -release_mem: - of_reserved_mem_device_release(dev); - gpiod_put(ksproc->kick_gpio); -disable_clk: - pm_runtime_put_sync(dev); -disable_rpm: - pm_runtime_disable(dev); - return ret; -} - -static void keystone_rproc_remove(struct platform_device *pdev) -{ - struct keystone_rproc *ksproc = platform_get_drvdata(pdev); - - rproc_del(ksproc->rproc); - gpiod_put(ksproc->kick_gpio); - pm_runtime_put_sync(&pdev->dev); - pm_runtime_disable(&pdev->dev); - of_reserved_mem_device_release(&pdev->dev); } static const struct of_device_id keystone_rproc_of_match[] = { @@ -490,7 +473,6 @@ MODULE_DEVICE_TABLE(of, keystone_rproc_of_match); static struct platform_driver keystone_rproc_driver = { .probe = keystone_rproc_probe, - .remove_new = keystone_rproc_remove, .driver = { .name = "keystone-rproc", .of_match_table = keystone_rproc_of_match, diff --git a/drivers/remoteproc/meson_mx_ao_arc.c b/drivers/remoteproc/meson_mx_ao_arc.c index f6744b538323..7dfdf11b0036 100644 --- a/drivers/remoteproc/meson_mx_ao_arc.c +++ b/drivers/remoteproc/meson_mx_ao_arc.c @@ -246,7 +246,7 @@ MODULE_DEVICE_TABLE(of, meson_mx_ao_arc_rproc_match); static struct platform_driver meson_mx_ao_arc_rproc_driver = { .probe = meson_mx_ao_arc_rproc_probe, - .remove_new = meson_mx_ao_arc_rproc_remove, + .remove = meson_mx_ao_arc_rproc_remove, .driver = { .name = "meson-mx-ao-arc-rproc", .of_match_table = meson_mx_ao_arc_rproc_match, diff --git a/drivers/remoteproc/mtk_scp.c b/drivers/remoteproc/mtk_scp.c index ae20d2221c8e..2aeb0ded165c 100644 --- a/drivers/remoteproc/mtk_scp.c +++ b/drivers/remoteproc/mtk_scp.c @@ -1546,7 +1546,7 @@ MODULE_DEVICE_TABLE(of, mtk_scp_of_match); static struct platform_driver mtk_scp_driver = { .probe = scp_probe, - .remove_new = scp_remove, + .remove = scp_remove, .driver = { .name = "mtk-scp", .of_match_table = mtk_scp_of_match, diff --git a/drivers/remoteproc/omap_remoteproc.c b/drivers/remoteproc/omap_remoteproc.c index 3260dd512491..9c9e9c3cf378 100644 --- a/drivers/remoteproc/omap_remoteproc.c +++ b/drivers/remoteproc/omap_remoteproc.c @@ -724,6 +724,7 @@ out: * @rproc: remote processor to apply the address translation for * @da: device address to translate * @len: length of the memory buffer + * @is_iomem: pointer filled in to indicate if @da is iomapped memory * * Custom function implementing the rproc .da_to_va ops to provide address * translation (device address to kernel virtual address) for internal RAMs @@ -1137,7 +1138,6 @@ static int omap_rproc_get_boot_data(struct platform_device *pdev, struct device_node *np = pdev->dev.of_node; struct omap_rproc *oproc = rproc->priv; const struct omap_rproc_dev_data *data; - int ret; data = of_device_get_match_data(&pdev->dev); if (!data) @@ -1153,10 +1153,8 @@ static int omap_rproc_get_boot_data(struct platform_device *pdev, oproc->boot_data->syscon = syscon_regmap_lookup_by_phandle(np, "ti,bootreg"); - if (IS_ERR(oproc->boot_data->syscon)) { - ret = PTR_ERR(oproc->boot_data->syscon); - return ret; - } + if (IS_ERR(oproc->boot_data->syscon)) + return PTR_ERR(oproc->boot_data->syscon); if (of_property_read_u32_index(np, "ti,bootreg", 1, &oproc->boot_data->boot_reg)) { @@ -1213,7 +1211,7 @@ static int omap_rproc_of_get_internal_memories(struct platform_device *pdev, oproc->mem[i].dev_addr = data->mems[i].dev_addr; oproc->mem[i].size = resource_size(res); - dev_dbg(dev, "memory %8s: bus addr %pa size 0x%x va %pK da 0x%x\n", + dev_dbg(dev, "memory %8s: bus addr %pa size 0x%x va %p da 0x%x\n", data->mems[i].name, &oproc->mem[i].bus_addr, oproc->mem[i].size, oproc->mem[i].cpu_addr, oproc->mem[i].dev_addr); diff --git a/drivers/remoteproc/pru_rproc.c b/drivers/remoteproc/pru_rproc.c index 7ffbae209a31..5e3eb7b86a0e 100644 --- a/drivers/remoteproc/pru_rproc.c +++ b/drivers/remoteproc/pru_rproc.c @@ -564,7 +564,7 @@ static int pru_handle_intrmap(struct rproc *rproc) return -ENODEV; } - fwspec.fwnode = of_node_to_fwnode(irq_parent); + fwspec.fwnode = of_fwnode_handle(irq_parent); fwspec.param_count = 3; for (i = 0; i < pru->evt_count; i++) { fwspec.param[0] = rsc->pru_intc_map[i].event; @@ -1056,7 +1056,7 @@ static int pru_rproc_probe(struct platform_device *pdev) pru->mem_regions[i].pa = res->start; pru->mem_regions[i].size = resource_size(res); - dev_dbg(dev, "memory %8s: pa %pa size 0x%zx va %pK\n", + dev_dbg(dev, "memory %8s: pa %pa size 0x%zx va %p\n", mem_names[i], &pru->mem_regions[i].pa, pru->mem_regions[i].size, pru->mem_regions[i].va); } @@ -1133,7 +1133,7 @@ static struct platform_driver pru_rproc_driver = { .suppress_bind_attrs = true, }, .probe = pru_rproc_probe, - .remove_new = pru_rproc_remove, + .remove = pru_rproc_remove, }; module_platform_driver(pru_rproc_driver); diff --git a/drivers/remoteproc/qcom_q6v5_adsp.c b/drivers/remoteproc/qcom_q6v5_adsp.c index 223f6ca0745d..e98b7e03162c 100644 --- a/drivers/remoteproc/qcom_q6v5_adsp.c +++ b/drivers/remoteproc/qcom_q6v5_adsp.c @@ -317,7 +317,7 @@ static int adsp_load(struct rproc *rproc, const struct firmware *fw) struct qcom_adsp *adsp = rproc->priv; int ret; - ret = qcom_mdt_load_no_init(adsp->dev, fw, rproc->firmware, 0, + ret = qcom_mdt_load_no_init(adsp->dev, fw, rproc->firmware, adsp->mem_region, adsp->mem_phys, adsp->mem_size, &adsp->mem_reloc); if (ret) @@ -534,15 +534,11 @@ static const struct rproc_ops adsp_ops = { static int adsp_init_clock(struct qcom_adsp *adsp, const char **clk_ids) { int num_clks = 0; - int i, ret; + int i; adsp->xo = devm_clk_get(adsp->dev, "xo"); - if (IS_ERR(adsp->xo)) { - ret = PTR_ERR(adsp->xo); - if (ret != -EPROBE_DEFER) - dev_err(adsp->dev, "failed to get xo clock"); - return ret; - } + if (IS_ERR(adsp->xo)) + return dev_err_probe(adsp->dev, PTR_ERR(adsp->xo), "failed to get xo clock"); for (i = 0; clk_ids[i]; i++) num_clks++; @@ -708,10 +704,9 @@ static int adsp_probe(struct platform_device *pdev) return ret; ret = qcom_rproc_pds_attach(adsp, desc->pd_names, desc->num_pds); - if (ret < 0) { - dev_err(&pdev->dev, "Failed to attach proxy power domains\n"); - return ret; - } + if (ret < 0) + return dev_err_probe(&pdev->dev, ret, + "Failed to attach proxy power domains\n"); ret = adsp_init_reset(adsp); if (ret) @@ -847,7 +842,7 @@ MODULE_DEVICE_TABLE(of, adsp_of_match); static struct platform_driver adsp_pil_driver = { .probe = adsp_probe, - .remove_new = adsp_remove, + .remove = adsp_remove, .driver = { .name = "qcom_q6v5_adsp", .of_match_table = adsp_of_match, diff --git a/drivers/remoteproc/qcom_q6v5_mss.c b/drivers/remoteproc/qcom_q6v5_mss.c index e19081d53022..3087d895b87f 100644 --- a/drivers/remoteproc/qcom_q6v5_mss.c +++ b/drivers/remoteproc/qcom_q6v5_mss.c @@ -134,6 +134,11 @@ #define BOOT_FSM_TIMEOUT 10000 #define BHS_CHECK_MAX_LOOPS 200 +/* External power block headswitch */ +#define EXTERNAL_BHS_ON BIT(0) +#define EXTERNAL_BHS_STATUS BIT(4) +#define EXTERNAL_BHS_TIMEOUT_US 50 + struct reg_info { struct regulator *reg; int uV; @@ -161,6 +166,7 @@ struct rproc_hexagon_res { bool has_mba_logs; bool has_spare_reg; bool has_qaccept_regs; + bool has_ext_bhs_reg; bool has_ext_cntl_regs; bool has_vq6; }; @@ -180,6 +186,7 @@ struct q6v5 { u32 halt_nc; u32 halt_vq6; u32 conn_box; + u32 ext_bhs; u32 qaccept_mdm; u32 qaccept_cx; @@ -237,6 +244,7 @@ struct q6v5 { bool has_mba_logs; bool has_spare_reg; bool has_qaccept_regs; + bool has_ext_bhs_reg; bool has_ext_cntl_regs; bool has_vq6; u64 mpss_perm; @@ -246,8 +254,10 @@ struct q6v5 { }; enum { + MSS_MSM8226, MSS_MSM8909, MSS_MSM8916, + MSS_MSM8926, MSS_MSM8953, MSS_MSM8974, MSS_MSM8996, @@ -261,7 +271,6 @@ enum { static int q6v5_regulator_init(struct device *dev, struct reg_info *regs, const struct qcom_mss_reg_res *reg_res) { - int rc; int i; if (!reg_res) @@ -269,13 +278,10 @@ static int q6v5_regulator_init(struct device *dev, struct reg_info *regs, for (i = 0; reg_res[i].supply; i++) { regs[i].reg = devm_regulator_get(dev, reg_res[i].supply); - if (IS_ERR(regs[i].reg)) { - rc = PTR_ERR(regs[i].reg); - if (rc != -EPROBE_DEFER) - dev_err(dev, "Failed to get %s\n regulator", - reg_res[i].supply); - return rc; - } + if (IS_ERR(regs[i].reg)) + return dev_err_probe(dev, PTR_ERR(regs[i].reg), + "Failed to get %s\n regulator", + reg_res[i].supply); regs[i].uV = reg_res[i].uV; regs[i].uA = reg_res[i].uA; @@ -419,6 +425,34 @@ static void q6v5_pds_disable(struct q6v5 *qproc, struct device **pds, } } +static int q6v5_external_bhs_enable(struct q6v5 *qproc) +{ + u32 val; + int ret = 0; + + /* + * Enable external power block headswitch and wait for it to + * stabilize + */ + regmap_set_bits(qproc->conn_map, qproc->ext_bhs, EXTERNAL_BHS_ON); + + ret = regmap_read_poll_timeout(qproc->conn_map, qproc->ext_bhs, + val, val & EXTERNAL_BHS_STATUS, + 1, EXTERNAL_BHS_TIMEOUT_US); + + if (ret) { + dev_err(qproc->dev, "External BHS timed out\n"); + ret = -ETIMEDOUT; + } + + return ret; +} + +static void q6v5_external_bhs_disable(struct q6v5 *qproc) +{ + regmap_clear_bits(qproc->conn_map, qproc->ext_bhs, EXTERNAL_BHS_ON); +} + static int q6v5_xfer_mem_ownership(struct q6v5 *qproc, u64 *current_perm, bool local, bool remote, phys_addr_t addr, size_t size) @@ -464,6 +498,8 @@ static void q6v5_debug_policy_load(struct q6v5 *qproc, void *mba_region) release_firmware(dp_fw); } +#define MSM8974_B00_OFFSET 0x1000 + static int q6v5_load(struct rproc *rproc, const struct firmware *fw) { struct q6v5 *qproc = rproc->priv; @@ -482,7 +518,14 @@ static int q6v5_load(struct rproc *rproc, const struct firmware *fw) return -EBUSY; } - memcpy(mba_region, fw->data, fw->size); + if ((qproc->version == MSS_MSM8974 || + qproc->version == MSS_MSM8226 || + qproc->version == MSS_MSM8926) && + fw->size > MSM8974_B00_OFFSET && + !memcmp(fw->data, ELFMAG, SELFMAG)) + memcpy(mba_region, fw->data + MSM8974_B00_OFFSET, fw->size - MSM8974_B00_OFFSET); + else + memcpy(mba_region, fw->data, fw->size); q6v5_debug_policy_load(qproc, mba_region); memunmap(mba_region); @@ -1116,11 +1159,17 @@ static int q6v5_mba_load(struct q6v5 *qproc) goto disable_proxy_clk; } + if (qproc->has_ext_bhs_reg) { + ret = q6v5_external_bhs_enable(qproc); + if (ret < 0) + goto disable_vdd; + } + ret = q6v5_clk_enable(qproc->dev, qproc->reset_clks, qproc->reset_clk_count); if (ret) { dev_err(qproc->dev, "failed to enable reset clocks\n"); - goto disable_vdd; + goto disable_ext_bhs; } ret = q6v5_reset_deassert(qproc); @@ -1218,6 +1267,9 @@ assert_reset: disable_reset_clks: q6v5_clk_disable(qproc->dev, qproc->reset_clks, qproc->reset_clk_count); +disable_ext_bhs: + if (qproc->has_ext_bhs_reg) + q6v5_external_bhs_disable(qproc); disable_vdd: q6v5_regulator_disable(qproc, qproc->active_regs, qproc->active_reg_count); @@ -1285,6 +1337,8 @@ static void q6v5_mba_reclaim(struct q6v5 *qproc) qproc->reset_clk_count); q6v5_clk_disable(qproc->dev, qproc->active_clks, qproc->active_clk_count); + if (qproc->has_ext_bhs_reg) + q6v5_external_bhs_disable(qproc); q6v5_regulator_disable(qproc, qproc->active_regs, qproc->active_reg_count); @@ -1754,6 +1808,23 @@ static int q6v5_init_mem(struct q6v5 *qproc, struct platform_device *pdev) qproc->qaccept_axi = args.args[2]; } + if (qproc->has_ext_bhs_reg) { + ret = of_parse_phandle_with_fixed_args(pdev->dev.of_node, + "qcom,ext-bhs-reg", + 1, 0, &args); + if (ret < 0) { + dev_err(&pdev->dev, "failed to parse ext-bhs-reg index 0\n"); + return -EINVAL; + } + + qproc->conn_map = syscon_node_to_regmap(args.np); + of_node_put(args.np); + if (IS_ERR(qproc->conn_map)) + return PTR_ERR(qproc->conn_map); + + qproc->ext_bhs = args.args[0]; + } + if (qproc->has_ext_cntl_regs) { ret = of_parse_phandle_with_fixed_args(pdev->dev.of_node, "qcom,ext-regs", @@ -1813,14 +1884,10 @@ static int q6v5_init_clocks(struct device *dev, struct clk **clks, for (i = 0; clk_names[i]; i++) { clks[i] = devm_clk_get(dev, clk_names[i]); - if (IS_ERR(clks[i])) { - int rc = PTR_ERR(clks[i]); - - if (rc != -EPROBE_DEFER) - dev_err(dev, "Failed to get %s clock\n", - clk_names[i]); - return rc; - } + if (IS_ERR(clks[i])) + return dev_err_probe(dev, PTR_ERR(clks[i]), + "Failed to get %s clock\n", + clk_names[i]); } return i; @@ -2029,6 +2096,7 @@ static int q6v5_probe(struct platform_device *pdev) platform_set_drvdata(pdev, qproc); qproc->has_qaccept_regs = desc->has_qaccept_regs; + qproc->has_ext_bhs_reg = desc->has_ext_bhs_reg; qproc->has_ext_cntl_regs = desc->has_ext_cntl_regs; qproc->has_vq6 = desc->has_vq6; qproc->has_spare_reg = desc->has_spare_reg; @@ -2042,42 +2110,32 @@ static int q6v5_probe(struct platform_device *pdev) ret = q6v5_init_clocks(&pdev->dev, qproc->proxy_clks, desc->proxy_clk_names); - if (ret < 0) { - dev_err(&pdev->dev, "Failed to get proxy clocks.\n"); + if (ret < 0) return ret; - } qproc->proxy_clk_count = ret; ret = q6v5_init_clocks(&pdev->dev, qproc->reset_clks, desc->reset_clk_names); - if (ret < 0) { - dev_err(&pdev->dev, "Failed to get reset clocks.\n"); + if (ret < 0) return ret; - } qproc->reset_clk_count = ret; ret = q6v5_init_clocks(&pdev->dev, qproc->active_clks, desc->active_clk_names); - if (ret < 0) { - dev_err(&pdev->dev, "Failed to get active clocks.\n"); + if (ret < 0) return ret; - } qproc->active_clk_count = ret; ret = q6v5_regulator_init(&pdev->dev, qproc->proxy_regs, desc->proxy_supply); - if (ret < 0) { - dev_err(&pdev->dev, "Failed to get proxy regulators.\n"); + if (ret < 0) return ret; - } qproc->proxy_reg_count = ret; ret = q6v5_regulator_init(&pdev->dev, qproc->active_regs, desc->active_supply); - if (ret < 0) { - dev_err(&pdev->dev, "Failed to get active regulators.\n"); + if (ret < 0) return ret; - } qproc->active_reg_count = ret; ret = q6v5_pds_attach(&pdev->dev, qproc->proxy_pds, @@ -2087,10 +2145,8 @@ static int q6v5_probe(struct platform_device *pdev) ret = q6v5_regulator_init(&pdev->dev, qproc->fallback_proxy_regs, desc->fallback_proxy_supply); - if (ret < 0) { - dev_err(&pdev->dev, "Failed to get fallback proxy regulators.\n"); + if (ret < 0) return ret; - } qproc->fallback_proxy_reg_count = ret; } else if (ret < 0) { dev_err(&pdev->dev, "Failed to init power domains\n"); @@ -2194,6 +2250,7 @@ static const struct rproc_hexagon_res sc7180_mss = { .has_mba_logs = true, .has_spare_reg = true, .has_qaccept_regs = false, + .has_ext_bhs_reg = false, .has_ext_cntl_regs = false, .has_vq6 = false, .version = MSS_SC7180, @@ -2222,6 +2279,7 @@ static const struct rproc_hexagon_res sc7280_mss = { .has_mba_logs = true, .has_spare_reg = false, .has_qaccept_regs = true, + .has_ext_bhs_reg = false, .has_ext_cntl_regs = true, .has_vq6 = true, .version = MSS_SC7280, @@ -2253,6 +2311,7 @@ static const struct rproc_hexagon_res sdm660_mss = { .has_mba_logs = false, .has_spare_reg = false, .has_qaccept_regs = false, + .has_ext_bhs_reg = false, .has_ext_cntl_regs = false, .has_vq6 = false, .version = MSS_SDM660, @@ -2288,6 +2347,7 @@ static const struct rproc_hexagon_res sdm845_mss = { .has_mba_logs = false, .has_spare_reg = false, .has_qaccept_regs = false, + .has_ext_bhs_reg = false, .has_ext_cntl_regs = false, .has_vq6 = false, .version = MSS_SDM845, @@ -2319,6 +2379,7 @@ static const struct rproc_hexagon_res msm8998_mss = { .has_mba_logs = false, .has_spare_reg = false, .has_qaccept_regs = false, + .has_ext_bhs_reg = false, .has_ext_cntl_regs = false, .has_vq6 = false, .version = MSS_MSM8998, @@ -2357,6 +2418,7 @@ static const struct rproc_hexagon_res msm8996_mss = { .has_mba_logs = false, .has_spare_reg = false, .has_qaccept_regs = false, + .has_ext_bhs_reg = false, .has_ext_cntl_regs = false, .has_vq6 = false, .version = MSS_MSM8996, @@ -2391,6 +2453,7 @@ static const struct rproc_hexagon_res msm8909_mss = { .has_mba_logs = false, .has_spare_reg = false, .has_qaccept_regs = false, + .has_ext_bhs_reg = false, .has_ext_cntl_regs = false, .has_vq6 = false, .version = MSS_MSM8909, @@ -2436,6 +2499,7 @@ static const struct rproc_hexagon_res msm8916_mss = { .has_mba_logs = false, .has_spare_reg = false, .has_qaccept_regs = false, + .has_ext_bhs_reg = false, .has_ext_cntl_regs = false, .has_vq6 = false, .version = MSS_MSM8916, @@ -2471,6 +2535,7 @@ static const struct rproc_hexagon_res msm8953_mss = { .has_mba_logs = false, .has_spare_reg = false, .has_qaccept_regs = false, + .has_ext_bhs_reg = false, .has_ext_cntl_regs = false, .has_vq6 = false, .version = MSS_MSM8953, @@ -2523,15 +2588,102 @@ static const struct rproc_hexagon_res msm8974_mss = { .has_mba_logs = false, .has_spare_reg = false, .has_qaccept_regs = false, + .has_ext_bhs_reg = false, .has_ext_cntl_regs = false, .has_vq6 = false, .version = MSS_MSM8974, }; +static const struct rproc_hexagon_res msm8226_mss = { + .hexagon_mba_image = "mba.b00", + .proxy_supply = (struct qcom_mss_reg_res[]) { + { + .supply = "pll", + .uA = 100000, + }, + { + .supply = "mx", + .uV = 1050000, + }, + {} + }, + .proxy_clk_names = (char*[]){ + "xo", + NULL + }, + .active_clk_names = (char*[]){ + "iface", + "bus", + "mem", + NULL + }, + .proxy_pd_names = (char*[]){ + "cx", + NULL + }, + .need_mem_protection = false, + .has_alt_reset = false, + .has_mba_logs = false, + .has_spare_reg = false, + .has_qaccept_regs = false, + .has_ext_bhs_reg = true, + .has_ext_cntl_regs = false, + .has_vq6 = false, + .version = MSS_MSM8226, +}; + +static const struct rproc_hexagon_res msm8926_mss = { + .hexagon_mba_image = "mba.b00", + .proxy_supply = (struct qcom_mss_reg_res[]) { + { + .supply = "pll", + .uA = 100000, + }, + { + .supply = "mx", + .uV = 1050000, + }, + {} + }, + .active_supply = (struct qcom_mss_reg_res[]) { + { + .supply = "mss", + .uV = 1050000, + .uA = 100000, + }, + {} + }, + .proxy_clk_names = (char*[]){ + "xo", + NULL + }, + .active_clk_names = (char*[]){ + "iface", + "bus", + "mem", + NULL + }, + .proxy_pd_names = (char*[]){ + "cx", + NULL + }, + .need_mem_protection = false, + .has_alt_reset = false, + .has_mba_logs = false, + .has_spare_reg = false, + .has_qaccept_regs = false, + .has_ext_bhs_reg = false, + .has_ext_cntl_regs = false, + .has_vq6 = false, + .version = MSS_MSM8926, +}; + static const struct of_device_id q6v5_of_match[] = { { .compatible = "qcom,q6v5-pil", .data = &msm8916_mss}, + { .compatible = "qcom,msm8226-mss-pil", .data = &msm8226_mss}, { .compatible = "qcom,msm8909-mss-pil", .data = &msm8909_mss}, { .compatible = "qcom,msm8916-mss-pil", .data = &msm8916_mss}, + { .compatible = "qcom,msm8926-mss-pil", .data = &msm8926_mss}, { .compatible = "qcom,msm8953-mss-pil", .data = &msm8953_mss}, { .compatible = "qcom,msm8974-mss-pil", .data = &msm8974_mss}, { .compatible = "qcom,msm8996-mss-pil", .data = &msm8996_mss}, @@ -2546,7 +2698,7 @@ MODULE_DEVICE_TABLE(of, q6v5_of_match); static struct platform_driver q6v5_driver = { .probe = q6v5_probe, - .remove_new = q6v5_remove, + .remove = q6v5_remove, .driver = { .name = "qcom-q6v5-mss", .of_match_table = q6v5_of_match, diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c index ea4a91f37b50..158bcd6cc85c 100644 --- a/drivers/remoteproc/qcom_q6v5_pas.c +++ b/drivers/remoteproc/qcom_q6v5_pas.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Qualcomm ADSP/SLPI Peripheral Image Loader for MSM8974 and MSM8996 + * Qualcomm Peripheral Authentication Service remoteproc driver * * Copyright (C) 2016 Linaro Ltd * Copyright (C) 2014 Sony Mobile Communications AB @@ -31,17 +31,18 @@ #include "qcom_q6v5.h" #include "remoteproc_internal.h" -#define ADSP_DECRYPT_SHUTDOWN_DELAY_MS 100 +#define QCOM_PAS_DECRYPT_SHUTDOWN_DELAY_MS 100 #define MAX_ASSIGN_COUNT 3 -struct adsp_data { +struct qcom_pas_data { int crash_reason_smem; const char *firmware_name; const char *dtb_firmware_name; int pas_id; int dtb_pas_id; int lite_pas_id; + int lite_dtb_pas_id; unsigned int minidump_id; bool auto_boot; bool decrypt_shutdown; @@ -60,7 +61,7 @@ struct adsp_data { int region_assign_vmid; }; -struct qcom_adsp { +struct qcom_pas { struct device *dev; struct rproc *rproc; @@ -80,6 +81,7 @@ struct qcom_adsp { int pas_id; int dtb_pas_id; int lite_pas_id; + int lite_dtb_pas_id; unsigned int minidump_id; int crash_reason_smem; unsigned int smem_host_id; @@ -119,36 +121,37 @@ struct qcom_adsp { struct qcom_scm_pas_metadata dtb_pas_metadata; }; -static void adsp_segment_dump(struct rproc *rproc, struct rproc_dump_segment *segment, - void *dest, size_t offset, size_t size) +static void qcom_pas_segment_dump(struct rproc *rproc, + struct rproc_dump_segment *segment, + void *dest, size_t offset, size_t size) { - struct qcom_adsp *adsp = rproc->priv; + struct qcom_pas *pas = rproc->priv; int total_offset; - total_offset = segment->da + segment->offset + offset - adsp->mem_phys; - if (total_offset < 0 || total_offset + size > adsp->mem_size) { - dev_err(adsp->dev, + total_offset = segment->da + segment->offset + offset - pas->mem_phys; + if (total_offset < 0 || total_offset + size > pas->mem_size) { + dev_err(pas->dev, "invalid copy request for segment %pad with offset %zu and size %zu)\n", &segment->da, offset, size); memset(dest, 0xff, size); return; } - memcpy_fromio(dest, adsp->mem_region + total_offset, size); + memcpy_fromio(dest, pas->mem_region + total_offset, size); } -static void adsp_minidump(struct rproc *rproc) +static void qcom_pas_minidump(struct rproc *rproc) { - struct qcom_adsp *adsp = rproc->priv; + struct qcom_pas *pas = rproc->priv; if (rproc->dump_conf == RPROC_COREDUMP_DISABLED) return; - qcom_minidump(rproc, adsp->minidump_id, adsp_segment_dump); + qcom_minidump(rproc, pas->minidump_id, qcom_pas_segment_dump); } -static int adsp_pds_enable(struct qcom_adsp *adsp, struct device **pds, - size_t pd_count) +static int qcom_pas_pds_enable(struct qcom_pas *pas, struct device **pds, + size_t pd_count) { int ret; int i; @@ -174,8 +177,8 @@ unroll_pd_votes: return ret; }; -static void adsp_pds_disable(struct qcom_adsp *adsp, struct device **pds, - size_t pd_count) +static void qcom_pas_pds_disable(struct qcom_pas *pas, struct device **pds, + size_t pd_count) { int i; @@ -185,65 +188,66 @@ static void adsp_pds_disable(struct qcom_adsp *adsp, struct device **pds, } } -static int adsp_shutdown_poll_decrypt(struct qcom_adsp *adsp) +static int qcom_pas_shutdown_poll_decrypt(struct qcom_pas *pas) { unsigned int retry_num = 50; int ret; do { - msleep(ADSP_DECRYPT_SHUTDOWN_DELAY_MS); - ret = qcom_scm_pas_shutdown(adsp->pas_id); + msleep(QCOM_PAS_DECRYPT_SHUTDOWN_DELAY_MS); + ret = qcom_scm_pas_shutdown(pas->pas_id); } while (ret == -EINVAL && --retry_num); return ret; } -static int adsp_unprepare(struct rproc *rproc) +static int qcom_pas_unprepare(struct rproc *rproc) { - struct qcom_adsp *adsp = rproc->priv; + struct qcom_pas *pas = rproc->priv; /* - * adsp_load() did pass pas_metadata to the SCM driver for storing + * qcom_pas_load() did pass pas_metadata to the SCM driver for storing * metadata context. It might have been released already if * auth_and_reset() was successful, but in other cases clean it up * here. */ - qcom_scm_pas_metadata_release(&adsp->pas_metadata); - if (adsp->dtb_pas_id) - qcom_scm_pas_metadata_release(&adsp->dtb_pas_metadata); + qcom_scm_pas_metadata_release(&pas->pas_metadata); + if (pas->dtb_pas_id) + qcom_scm_pas_metadata_release(&pas->dtb_pas_metadata); return 0; } -static int adsp_load(struct rproc *rproc, const struct firmware *fw) +static int qcom_pas_load(struct rproc *rproc, const struct firmware *fw) { - struct qcom_adsp *adsp = rproc->priv; + struct qcom_pas *pas = rproc->priv; int ret; - /* Store firmware handle to be used in adsp_start() */ - adsp->firmware = fw; + /* Store firmware handle to be used in qcom_pas_start() */ + pas->firmware = fw; - if (adsp->lite_pas_id) - ret = qcom_scm_pas_shutdown(adsp->lite_pas_id); + if (pas->lite_pas_id) + qcom_scm_pas_shutdown(pas->lite_pas_id); + if (pas->lite_dtb_pas_id) + qcom_scm_pas_shutdown(pas->lite_dtb_pas_id); - if (adsp->dtb_pas_id) { - ret = request_firmware(&adsp->dtb_firmware, adsp->dtb_firmware_name, adsp->dev); + if (pas->dtb_pas_id) { + ret = request_firmware(&pas->dtb_firmware, pas->dtb_firmware_name, pas->dev); if (ret) { - dev_err(adsp->dev, "request_firmware failed for %s: %d\n", - adsp->dtb_firmware_name, ret); + dev_err(pas->dev, "request_firmware failed for %s: %d\n", + pas->dtb_firmware_name, ret); return ret; } - ret = qcom_mdt_pas_init(adsp->dev, adsp->dtb_firmware, adsp->dtb_firmware_name, - adsp->dtb_pas_id, adsp->dtb_mem_phys, - &adsp->dtb_pas_metadata); + ret = qcom_mdt_pas_init(pas->dev, pas->dtb_firmware, pas->dtb_firmware_name, + pas->dtb_pas_id, pas->dtb_mem_phys, + &pas->dtb_pas_metadata); if (ret) goto release_dtb_firmware; - ret = qcom_mdt_load_no_init(adsp->dev, adsp->dtb_firmware, adsp->dtb_firmware_name, - adsp->dtb_pas_id, adsp->dtb_mem_region, - adsp->dtb_mem_phys, adsp->dtb_mem_size, - &adsp->dtb_mem_reloc); + ret = qcom_mdt_load_no_init(pas->dev, pas->dtb_firmware, pas->dtb_firmware_name, + pas->dtb_mem_region, pas->dtb_mem_phys, + pas->dtb_mem_size, &pas->dtb_mem_reloc); if (ret) goto release_dtb_metadata; } @@ -251,256 +255,246 @@ static int adsp_load(struct rproc *rproc, const struct firmware *fw) return 0; release_dtb_metadata: - qcom_scm_pas_metadata_release(&adsp->dtb_pas_metadata); + qcom_scm_pas_metadata_release(&pas->dtb_pas_metadata); release_dtb_firmware: - release_firmware(adsp->dtb_firmware); + release_firmware(pas->dtb_firmware); return ret; } -static int adsp_start(struct rproc *rproc) +static int qcom_pas_start(struct rproc *rproc) { - struct qcom_adsp *adsp = rproc->priv; + struct qcom_pas *pas = rproc->priv; int ret; - ret = qcom_q6v5_prepare(&adsp->q6v5); + ret = qcom_q6v5_prepare(&pas->q6v5); if (ret) return ret; - ret = adsp_pds_enable(adsp, adsp->proxy_pds, adsp->proxy_pd_count); + ret = qcom_pas_pds_enable(pas, pas->proxy_pds, pas->proxy_pd_count); if (ret < 0) goto disable_irqs; - ret = clk_prepare_enable(adsp->xo); + ret = clk_prepare_enable(pas->xo); if (ret) goto disable_proxy_pds; - ret = clk_prepare_enable(adsp->aggre2_clk); + ret = clk_prepare_enable(pas->aggre2_clk); if (ret) goto disable_xo_clk; - if (adsp->cx_supply) { - ret = regulator_enable(adsp->cx_supply); + if (pas->cx_supply) { + ret = regulator_enable(pas->cx_supply); if (ret) goto disable_aggre2_clk; } - if (adsp->px_supply) { - ret = regulator_enable(adsp->px_supply); + if (pas->px_supply) { + ret = regulator_enable(pas->px_supply); if (ret) goto disable_cx_supply; } - if (adsp->dtb_pas_id) { - ret = qcom_scm_pas_auth_and_reset(adsp->dtb_pas_id); + if (pas->dtb_pas_id) { + ret = qcom_scm_pas_auth_and_reset(pas->dtb_pas_id); if (ret) { - dev_err(adsp->dev, + dev_err(pas->dev, "failed to authenticate dtb image and release reset\n"); goto disable_px_supply; } } - ret = qcom_mdt_pas_init(adsp->dev, adsp->firmware, rproc->firmware, adsp->pas_id, - adsp->mem_phys, &adsp->pas_metadata); + ret = qcom_mdt_pas_init(pas->dev, pas->firmware, rproc->firmware, pas->pas_id, + pas->mem_phys, &pas->pas_metadata); if (ret) goto disable_px_supply; - ret = qcom_mdt_load_no_init(adsp->dev, adsp->firmware, rproc->firmware, adsp->pas_id, - adsp->mem_region, adsp->mem_phys, adsp->mem_size, - &adsp->mem_reloc); + ret = qcom_mdt_load_no_init(pas->dev, pas->firmware, rproc->firmware, + pas->mem_region, pas->mem_phys, pas->mem_size, + &pas->mem_reloc); if (ret) goto release_pas_metadata; - qcom_pil_info_store(adsp->info_name, adsp->mem_phys, adsp->mem_size); + qcom_pil_info_store(pas->info_name, pas->mem_phys, pas->mem_size); - ret = qcom_scm_pas_auth_and_reset(adsp->pas_id); + ret = qcom_scm_pas_auth_and_reset(pas->pas_id); if (ret) { - dev_err(adsp->dev, + dev_err(pas->dev, "failed to authenticate image and release reset\n"); goto release_pas_metadata; } - ret = qcom_q6v5_wait_for_start(&adsp->q6v5, msecs_to_jiffies(5000)); + ret = qcom_q6v5_wait_for_start(&pas->q6v5, msecs_to_jiffies(5000)); if (ret == -ETIMEDOUT) { - dev_err(adsp->dev, "start timed out\n"); - qcom_scm_pas_shutdown(adsp->pas_id); + dev_err(pas->dev, "start timed out\n"); + qcom_scm_pas_shutdown(pas->pas_id); goto release_pas_metadata; } - qcom_scm_pas_metadata_release(&adsp->pas_metadata); - if (adsp->dtb_pas_id) - qcom_scm_pas_metadata_release(&adsp->dtb_pas_metadata); + qcom_scm_pas_metadata_release(&pas->pas_metadata); + if (pas->dtb_pas_id) + qcom_scm_pas_metadata_release(&pas->dtb_pas_metadata); - /* Remove pointer to the loaded firmware, only valid in adsp_load() & adsp_start() */ - adsp->firmware = NULL; + /* firmware is used to pass reference from qcom_pas_start(), drop it now */ + pas->firmware = NULL; return 0; release_pas_metadata: - qcom_scm_pas_metadata_release(&adsp->pas_metadata); - if (adsp->dtb_pas_id) - qcom_scm_pas_metadata_release(&adsp->dtb_pas_metadata); + qcom_scm_pas_metadata_release(&pas->pas_metadata); + if (pas->dtb_pas_id) + qcom_scm_pas_metadata_release(&pas->dtb_pas_metadata); disable_px_supply: - if (adsp->px_supply) - regulator_disable(adsp->px_supply); + if (pas->px_supply) + regulator_disable(pas->px_supply); disable_cx_supply: - if (adsp->cx_supply) - regulator_disable(adsp->cx_supply); + if (pas->cx_supply) + regulator_disable(pas->cx_supply); disable_aggre2_clk: - clk_disable_unprepare(adsp->aggre2_clk); + clk_disable_unprepare(pas->aggre2_clk); disable_xo_clk: - clk_disable_unprepare(adsp->xo); + clk_disable_unprepare(pas->xo); disable_proxy_pds: - adsp_pds_disable(adsp, adsp->proxy_pds, adsp->proxy_pd_count); + qcom_pas_pds_disable(pas, pas->proxy_pds, pas->proxy_pd_count); disable_irqs: - qcom_q6v5_unprepare(&adsp->q6v5); + qcom_q6v5_unprepare(&pas->q6v5); - /* Remove pointer to the loaded firmware, only valid in adsp_load() & adsp_start() */ - adsp->firmware = NULL; + /* firmware is used to pass reference from qcom_pas_start(), drop it now */ + pas->firmware = NULL; return ret; } static void qcom_pas_handover(struct qcom_q6v5 *q6v5) { - struct qcom_adsp *adsp = container_of(q6v5, struct qcom_adsp, q6v5); - - if (adsp->px_supply) - regulator_disable(adsp->px_supply); - if (adsp->cx_supply) - regulator_disable(adsp->cx_supply); - clk_disable_unprepare(adsp->aggre2_clk); - clk_disable_unprepare(adsp->xo); - adsp_pds_disable(adsp, adsp->proxy_pds, adsp->proxy_pd_count); + struct qcom_pas *pas = container_of(q6v5, struct qcom_pas, q6v5); + + if (pas->px_supply) + regulator_disable(pas->px_supply); + if (pas->cx_supply) + regulator_disable(pas->cx_supply); + clk_disable_unprepare(pas->aggre2_clk); + clk_disable_unprepare(pas->xo); + qcom_pas_pds_disable(pas, pas->proxy_pds, pas->proxy_pd_count); } -static int adsp_stop(struct rproc *rproc) +static int qcom_pas_stop(struct rproc *rproc) { - struct qcom_adsp *adsp = rproc->priv; + struct qcom_pas *pas = rproc->priv; int handover; int ret; - ret = qcom_q6v5_request_stop(&adsp->q6v5, adsp->sysmon); + ret = qcom_q6v5_request_stop(&pas->q6v5, pas->sysmon); if (ret == -ETIMEDOUT) - dev_err(adsp->dev, "timed out on wait\n"); + dev_err(pas->dev, "timed out on wait\n"); - ret = qcom_scm_pas_shutdown(adsp->pas_id); - if (ret && adsp->decrypt_shutdown) - ret = adsp_shutdown_poll_decrypt(adsp); + ret = qcom_scm_pas_shutdown(pas->pas_id); + if (ret && pas->decrypt_shutdown) + ret = qcom_pas_shutdown_poll_decrypt(pas); if (ret) - dev_err(adsp->dev, "failed to shutdown: %d\n", ret); + dev_err(pas->dev, "failed to shutdown: %d\n", ret); - if (adsp->dtb_pas_id) { - ret = qcom_scm_pas_shutdown(adsp->dtb_pas_id); + if (pas->dtb_pas_id) { + ret = qcom_scm_pas_shutdown(pas->dtb_pas_id); if (ret) - dev_err(adsp->dev, "failed to shutdown dtb: %d\n", ret); + dev_err(pas->dev, "failed to shutdown dtb: %d\n", ret); } - handover = qcom_q6v5_unprepare(&adsp->q6v5); + handover = qcom_q6v5_unprepare(&pas->q6v5); if (handover) - qcom_pas_handover(&adsp->q6v5); + qcom_pas_handover(&pas->q6v5); - if (adsp->smem_host_id) - ret = qcom_smem_bust_hwspin_lock_by_host(adsp->smem_host_id); + if (pas->smem_host_id) + ret = qcom_smem_bust_hwspin_lock_by_host(pas->smem_host_id); return ret; } -static void *adsp_da_to_va(struct rproc *rproc, u64 da, size_t len, bool *is_iomem) +static void *qcom_pas_da_to_va(struct rproc *rproc, u64 da, size_t len, bool *is_iomem) { - struct qcom_adsp *adsp = rproc->priv; + struct qcom_pas *pas = rproc->priv; int offset; - offset = da - adsp->mem_reloc; - if (offset < 0 || offset + len > adsp->mem_size) + offset = da - pas->mem_reloc; + if (offset < 0 || offset + len > pas->mem_size) return NULL; if (is_iomem) *is_iomem = true; - return adsp->mem_region + offset; + return pas->mem_region + offset; } -static unsigned long adsp_panic(struct rproc *rproc) +static unsigned long qcom_pas_panic(struct rproc *rproc) { - struct qcom_adsp *adsp = rproc->priv; + struct qcom_pas *pas = rproc->priv; - return qcom_q6v5_panic(&adsp->q6v5); + return qcom_q6v5_panic(&pas->q6v5); } -static const struct rproc_ops adsp_ops = { - .unprepare = adsp_unprepare, - .start = adsp_start, - .stop = adsp_stop, - .da_to_va = adsp_da_to_va, +static const struct rproc_ops qcom_pas_ops = { + .unprepare = qcom_pas_unprepare, + .start = qcom_pas_start, + .stop = qcom_pas_stop, + .da_to_va = qcom_pas_da_to_va, .parse_fw = qcom_register_dump_segments, - .load = adsp_load, - .panic = adsp_panic, + .load = qcom_pas_load, + .panic = qcom_pas_panic, }; -static const struct rproc_ops adsp_minidump_ops = { - .unprepare = adsp_unprepare, - .start = adsp_start, - .stop = adsp_stop, - .da_to_va = adsp_da_to_va, +static const struct rproc_ops qcom_pas_minidump_ops = { + .unprepare = qcom_pas_unprepare, + .start = qcom_pas_start, + .stop = qcom_pas_stop, + .da_to_va = qcom_pas_da_to_va, .parse_fw = qcom_register_dump_segments, - .load = adsp_load, - .panic = adsp_panic, - .coredump = adsp_minidump, + .load = qcom_pas_load, + .panic = qcom_pas_panic, + .coredump = qcom_pas_minidump, }; -static int adsp_init_clock(struct qcom_adsp *adsp) +static int qcom_pas_init_clock(struct qcom_pas *pas) { - int ret; - - adsp->xo = devm_clk_get(adsp->dev, "xo"); - if (IS_ERR(adsp->xo)) { - ret = PTR_ERR(adsp->xo); - if (ret != -EPROBE_DEFER) - dev_err(adsp->dev, "failed to get xo clock"); - return ret; - } + pas->xo = devm_clk_get(pas->dev, "xo"); + if (IS_ERR(pas->xo)) + return dev_err_probe(pas->dev, PTR_ERR(pas->xo), + "failed to get xo clock"); - adsp->aggre2_clk = devm_clk_get_optional(adsp->dev, "aggre2"); - if (IS_ERR(adsp->aggre2_clk)) { - ret = PTR_ERR(adsp->aggre2_clk); - if (ret != -EPROBE_DEFER) - dev_err(adsp->dev, - "failed to get aggre2 clock"); - return ret; - } + pas->aggre2_clk = devm_clk_get_optional(pas->dev, "aggre2"); + if (IS_ERR(pas->aggre2_clk)) + return dev_err_probe(pas->dev, PTR_ERR(pas->aggre2_clk), + "failed to get aggre2 clock"); return 0; } -static int adsp_init_regulator(struct qcom_adsp *adsp) +static int qcom_pas_init_regulator(struct qcom_pas *pas) { - adsp->cx_supply = devm_regulator_get_optional(adsp->dev, "cx"); - if (IS_ERR(adsp->cx_supply)) { - if (PTR_ERR(adsp->cx_supply) == -ENODEV) - adsp->cx_supply = NULL; + pas->cx_supply = devm_regulator_get_optional(pas->dev, "cx"); + if (IS_ERR(pas->cx_supply)) { + if (PTR_ERR(pas->cx_supply) == -ENODEV) + pas->cx_supply = NULL; else - return PTR_ERR(adsp->cx_supply); + return PTR_ERR(pas->cx_supply); } - if (adsp->cx_supply) - regulator_set_load(adsp->cx_supply, 100000); + if (pas->cx_supply) + regulator_set_load(pas->cx_supply, 100000); - adsp->px_supply = devm_regulator_get_optional(adsp->dev, "px"); - if (IS_ERR(adsp->px_supply)) { - if (PTR_ERR(adsp->px_supply) == -ENODEV) - adsp->px_supply = NULL; + pas->px_supply = devm_regulator_get_optional(pas->dev, "px"); + if (IS_ERR(pas->px_supply)) { + if (PTR_ERR(pas->px_supply) == -ENODEV) + pas->px_supply = NULL; else - return PTR_ERR(adsp->px_supply); + return PTR_ERR(pas->px_supply); } return 0; } -static int adsp_pds_attach(struct device *dev, struct device **devs, - char **pd_names) +static int qcom_pas_pds_attach(struct device *dev, struct device **devs, char **pd_names) { size_t num_pds = 0; int ret; @@ -536,10 +530,9 @@ unroll_attach: return ret; }; -static void adsp_pds_detach(struct qcom_adsp *adsp, struct device **pds, - size_t pd_count) +static void qcom_pas_pds_detach(struct qcom_pas *pas, struct device **pds, size_t pd_count) { - struct device *dev = adsp->dev; + struct device *dev = pas->dev; int i; /* Handle single power domain */ @@ -552,62 +545,62 @@ static void adsp_pds_detach(struct qcom_adsp *adsp, struct device **pds, dev_pm_domain_detach(pds[i], false); } -static int adsp_alloc_memory_region(struct qcom_adsp *adsp) +static int qcom_pas_alloc_memory_region(struct qcom_pas *pas) { struct reserved_mem *rmem; struct device_node *node; - node = of_parse_phandle(adsp->dev->of_node, "memory-region", 0); + node = of_parse_phandle(pas->dev->of_node, "memory-region", 0); if (!node) { - dev_err(adsp->dev, "no memory-region specified\n"); + dev_err(pas->dev, "no memory-region specified\n"); return -EINVAL; } rmem = of_reserved_mem_lookup(node); of_node_put(node); if (!rmem) { - dev_err(adsp->dev, "unable to resolve memory-region\n"); + dev_err(pas->dev, "unable to resolve memory-region\n"); return -EINVAL; } - adsp->mem_phys = adsp->mem_reloc = rmem->base; - adsp->mem_size = rmem->size; - adsp->mem_region = devm_ioremap_wc(adsp->dev, adsp->mem_phys, adsp->mem_size); - if (!adsp->mem_region) { - dev_err(adsp->dev, "unable to map memory region: %pa+%zx\n", - &rmem->base, adsp->mem_size); + pas->mem_phys = pas->mem_reloc = rmem->base; + pas->mem_size = rmem->size; + pas->mem_region = devm_ioremap_wc(pas->dev, pas->mem_phys, pas->mem_size); + if (!pas->mem_region) { + dev_err(pas->dev, "unable to map memory region: %pa+%zx\n", + &rmem->base, pas->mem_size); return -EBUSY; } - if (!adsp->dtb_pas_id) + if (!pas->dtb_pas_id) return 0; - node = of_parse_phandle(adsp->dev->of_node, "memory-region", 1); + node = of_parse_phandle(pas->dev->of_node, "memory-region", 1); if (!node) { - dev_err(adsp->dev, "no dtb memory-region specified\n"); + dev_err(pas->dev, "no dtb memory-region specified\n"); return -EINVAL; } rmem = of_reserved_mem_lookup(node); of_node_put(node); if (!rmem) { - dev_err(adsp->dev, "unable to resolve dtb memory-region\n"); + dev_err(pas->dev, "unable to resolve dtb memory-region\n"); return -EINVAL; } - adsp->dtb_mem_phys = adsp->dtb_mem_reloc = rmem->base; - adsp->dtb_mem_size = rmem->size; - adsp->dtb_mem_region = devm_ioremap_wc(adsp->dev, adsp->dtb_mem_phys, adsp->dtb_mem_size); - if (!adsp->dtb_mem_region) { - dev_err(adsp->dev, "unable to map dtb memory region: %pa+%zx\n", - &rmem->base, adsp->dtb_mem_size); + pas->dtb_mem_phys = pas->dtb_mem_reloc = rmem->base; + pas->dtb_mem_size = rmem->size; + pas->dtb_mem_region = devm_ioremap_wc(pas->dev, pas->dtb_mem_phys, pas->dtb_mem_size); + if (!pas->dtb_mem_region) { + dev_err(pas->dev, "unable to map dtb memory region: %pa+%zx\n", + &rmem->base, pas->dtb_mem_size); return -EBUSY; } return 0; } -static int adsp_assign_memory_region(struct qcom_adsp *adsp) +static int qcom_pas_assign_memory_region(struct qcom_pas *pas) { struct qcom_scm_vmperm perm[MAX_ASSIGN_COUNT]; struct device_node *node; @@ -615,45 +608,45 @@ static int adsp_assign_memory_region(struct qcom_adsp *adsp) int offset; int ret; - if (!adsp->region_assign_idx) + if (!pas->region_assign_idx) return 0; - for (offset = 0; offset < adsp->region_assign_count; ++offset) { + for (offset = 0; offset < pas->region_assign_count; ++offset) { struct reserved_mem *rmem = NULL; - node = of_parse_phandle(adsp->dev->of_node, "memory-region", - adsp->region_assign_idx + offset); + node = of_parse_phandle(pas->dev->of_node, "memory-region", + pas->region_assign_idx + offset); if (node) rmem = of_reserved_mem_lookup(node); of_node_put(node); if (!rmem) { - dev_err(adsp->dev, "unable to resolve shareable memory-region index %d\n", + dev_err(pas->dev, "unable to resolve shareable memory-region index %d\n", offset); return -EINVAL; } - if (adsp->region_assign_shared) { + if (pas->region_assign_shared) { perm[0].vmid = QCOM_SCM_VMID_HLOS; perm[0].perm = QCOM_SCM_PERM_RW; - perm[1].vmid = adsp->region_assign_vmid; + perm[1].vmid = pas->region_assign_vmid; perm[1].perm = QCOM_SCM_PERM_RW; perm_size = 2; } else { - perm[0].vmid = adsp->region_assign_vmid; + perm[0].vmid = pas->region_assign_vmid; perm[0].perm = QCOM_SCM_PERM_RW; perm_size = 1; } - adsp->region_assign_phys[offset] = rmem->base; - adsp->region_assign_size[offset] = rmem->size; - adsp->region_assign_owners[offset] = BIT(QCOM_SCM_VMID_HLOS); + pas->region_assign_phys[offset] = rmem->base; + pas->region_assign_size[offset] = rmem->size; + pas->region_assign_owners[offset] = BIT(QCOM_SCM_VMID_HLOS); - ret = qcom_scm_assign_mem(adsp->region_assign_phys[offset], - adsp->region_assign_size[offset], - &adsp->region_assign_owners[offset], + ret = qcom_scm_assign_mem(pas->region_assign_phys[offset], + pas->region_assign_size[offset], + &pas->region_assign_owners[offset], perm, perm_size); if (ret < 0) { - dev_err(adsp->dev, "assign memory %d failed\n", offset); + dev_err(pas->dev, "assign memory %d failed\n", offset); return ret; } } @@ -661,35 +654,35 @@ static int adsp_assign_memory_region(struct qcom_adsp *adsp) return 0; } -static void adsp_unassign_memory_region(struct qcom_adsp *adsp) +static void qcom_pas_unassign_memory_region(struct qcom_pas *pas) { struct qcom_scm_vmperm perm; int offset; int ret; - if (!adsp->region_assign_idx || adsp->region_assign_shared) + if (!pas->region_assign_idx || pas->region_assign_shared) return; - for (offset = 0; offset < adsp->region_assign_count; ++offset) { + for (offset = 0; offset < pas->region_assign_count; ++offset) { perm.vmid = QCOM_SCM_VMID_HLOS; perm.perm = QCOM_SCM_PERM_RW; - ret = qcom_scm_assign_mem(adsp->region_assign_phys[offset], - adsp->region_assign_size[offset], - &adsp->region_assign_owners[offset], + ret = qcom_scm_assign_mem(pas->region_assign_phys[offset], + pas->region_assign_size[offset], + &pas->region_assign_owners[offset], &perm, 1); if (ret < 0) - dev_err(adsp->dev, "unassign memory %d failed\n", offset); + dev_err(pas->dev, "unassign memory %d failed\n", offset); } } -static int adsp_probe(struct platform_device *pdev) +static int qcom_pas_probe(struct platform_device *pdev) { - const struct adsp_data *desc; - struct qcom_adsp *adsp; + const struct qcom_pas_data *desc; + struct qcom_pas *pas; struct rproc *rproc; const char *fw_name, *dtb_fw_name = NULL; - const struct rproc_ops *ops = &adsp_ops; + const struct rproc_ops *ops = &qcom_pas_ops; int ret; desc = of_device_get_match_data(&pdev->dev); @@ -714,9 +707,9 @@ static int adsp_probe(struct platform_device *pdev) } if (desc->minidump_id) - ops = &adsp_minidump_ops; + ops = &qcom_pas_minidump_ops; - rproc = devm_rproc_alloc(&pdev->dev, pdev->name, ops, fw_name, sizeof(*adsp)); + rproc = devm_rproc_alloc(&pdev->dev, desc->sysmon_name, ops, fw_name, sizeof(*pas)); if (!rproc) { dev_err(&pdev->dev, "unable to allocate remoteproc\n"); @@ -726,68 +719,66 @@ static int adsp_probe(struct platform_device *pdev) rproc->auto_boot = desc->auto_boot; rproc_coredump_set_elf_info(rproc, ELFCLASS32, EM_NONE); - adsp = rproc->priv; - adsp->dev = &pdev->dev; - adsp->rproc = rproc; - adsp->minidump_id = desc->minidump_id; - adsp->pas_id = desc->pas_id; - adsp->lite_pas_id = desc->lite_pas_id; - adsp->info_name = desc->sysmon_name; - adsp->smem_host_id = desc->smem_host_id; - adsp->decrypt_shutdown = desc->decrypt_shutdown; - adsp->region_assign_idx = desc->region_assign_idx; - adsp->region_assign_count = min_t(int, MAX_ASSIGN_COUNT, desc->region_assign_count); - adsp->region_assign_vmid = desc->region_assign_vmid; - adsp->region_assign_shared = desc->region_assign_shared; + pas = rproc->priv; + pas->dev = &pdev->dev; + pas->rproc = rproc; + pas->minidump_id = desc->minidump_id; + pas->pas_id = desc->pas_id; + pas->lite_pas_id = desc->lite_pas_id; + pas->lite_dtb_pas_id = desc->lite_dtb_pas_id; + pas->info_name = desc->sysmon_name; + pas->smem_host_id = desc->smem_host_id; + pas->decrypt_shutdown = desc->decrypt_shutdown; + pas->region_assign_idx = desc->region_assign_idx; + pas->region_assign_count = min_t(int, MAX_ASSIGN_COUNT, desc->region_assign_count); + pas->region_assign_vmid = desc->region_assign_vmid; + pas->region_assign_shared = desc->region_assign_shared; if (dtb_fw_name) { - adsp->dtb_firmware_name = dtb_fw_name; - adsp->dtb_pas_id = desc->dtb_pas_id; + pas->dtb_firmware_name = dtb_fw_name; + pas->dtb_pas_id = desc->dtb_pas_id; } - platform_set_drvdata(pdev, adsp); + platform_set_drvdata(pdev, pas); - ret = device_init_wakeup(adsp->dev, true); + ret = device_init_wakeup(pas->dev, true); if (ret) goto free_rproc; - ret = adsp_alloc_memory_region(adsp); + ret = qcom_pas_alloc_memory_region(pas); if (ret) goto free_rproc; - ret = adsp_assign_memory_region(adsp); + ret = qcom_pas_assign_memory_region(pas); if (ret) goto free_rproc; - ret = adsp_init_clock(adsp); + ret = qcom_pas_init_clock(pas); if (ret) goto unassign_mem; - ret = adsp_init_regulator(adsp); + ret = qcom_pas_init_regulator(pas); if (ret) goto unassign_mem; - ret = adsp_pds_attach(&pdev->dev, adsp->proxy_pds, - desc->proxy_pd_names); + ret = qcom_pas_pds_attach(&pdev->dev, pas->proxy_pds, desc->proxy_pd_names); if (ret < 0) goto unassign_mem; - adsp->proxy_pd_count = ret; + pas->proxy_pd_count = ret; - ret = qcom_q6v5_init(&adsp->q6v5, pdev, rproc, desc->crash_reason_smem, desc->load_state, - qcom_pas_handover); + ret = qcom_q6v5_init(&pas->q6v5, pdev, rproc, desc->crash_reason_smem, + desc->load_state, qcom_pas_handover); if (ret) goto detach_proxy_pds; - qcom_add_glink_subdev(rproc, &adsp->glink_subdev, desc->ssr_name); - qcom_add_smd_subdev(rproc, &adsp->smd_subdev); - qcom_add_pdm_subdev(rproc, &adsp->pdm_subdev); - adsp->sysmon = qcom_add_sysmon_subdev(rproc, - desc->sysmon_name, - desc->ssctl_id); - if (IS_ERR(adsp->sysmon)) { - ret = PTR_ERR(adsp->sysmon); + qcom_add_glink_subdev(rproc, &pas->glink_subdev, desc->ssr_name); + qcom_add_smd_subdev(rproc, &pas->smd_subdev); + qcom_add_pdm_subdev(rproc, &pas->pdm_subdev); + pas->sysmon = qcom_add_sysmon_subdev(rproc, desc->sysmon_name, desc->ssctl_id); + if (IS_ERR(pas->sysmon)) { + ret = PTR_ERR(pas->sysmon); goto deinit_remove_pdm_smd_glink; } - qcom_add_ssr_subdev(rproc, &adsp->ssr_subdev, desc->ssr_name); + qcom_add_ssr_subdev(rproc, &pas->ssr_subdev, desc->ssr_name); ret = rproc_add(rproc); if (ret) goto remove_ssr_sysmon; @@ -795,41 +786,41 @@ static int adsp_probe(struct platform_device *pdev) return 0; remove_ssr_sysmon: - qcom_remove_ssr_subdev(rproc, &adsp->ssr_subdev); - qcom_remove_sysmon_subdev(adsp->sysmon); + qcom_remove_ssr_subdev(rproc, &pas->ssr_subdev); + qcom_remove_sysmon_subdev(pas->sysmon); deinit_remove_pdm_smd_glink: - qcom_remove_pdm_subdev(rproc, &adsp->pdm_subdev); - qcom_remove_smd_subdev(rproc, &adsp->smd_subdev); - qcom_remove_glink_subdev(rproc, &adsp->glink_subdev); - qcom_q6v5_deinit(&adsp->q6v5); + qcom_remove_pdm_subdev(rproc, &pas->pdm_subdev); + qcom_remove_smd_subdev(rproc, &pas->smd_subdev); + qcom_remove_glink_subdev(rproc, &pas->glink_subdev); + qcom_q6v5_deinit(&pas->q6v5); detach_proxy_pds: - adsp_pds_detach(adsp, adsp->proxy_pds, adsp->proxy_pd_count); + qcom_pas_pds_detach(pas, pas->proxy_pds, pas->proxy_pd_count); unassign_mem: - adsp_unassign_memory_region(adsp); + qcom_pas_unassign_memory_region(pas); free_rproc: - device_init_wakeup(adsp->dev, false); + device_init_wakeup(pas->dev, false); return ret; } -static void adsp_remove(struct platform_device *pdev) +static void qcom_pas_remove(struct platform_device *pdev) { - struct qcom_adsp *adsp = platform_get_drvdata(pdev); - - rproc_del(adsp->rproc); - - qcom_q6v5_deinit(&adsp->q6v5); - adsp_unassign_memory_region(adsp); - qcom_remove_glink_subdev(adsp->rproc, &adsp->glink_subdev); - qcom_remove_sysmon_subdev(adsp->sysmon); - qcom_remove_smd_subdev(adsp->rproc, &adsp->smd_subdev); - qcom_remove_pdm_subdev(adsp->rproc, &adsp->pdm_subdev); - qcom_remove_ssr_subdev(adsp->rproc, &adsp->ssr_subdev); - adsp_pds_detach(adsp, adsp->proxy_pds, adsp->proxy_pd_count); - device_init_wakeup(adsp->dev, false); + struct qcom_pas *pas = platform_get_drvdata(pdev); + + rproc_del(pas->rproc); + + qcom_q6v5_deinit(&pas->q6v5); + qcom_pas_unassign_memory_region(pas); + qcom_remove_glink_subdev(pas->rproc, &pas->glink_subdev); + qcom_remove_sysmon_subdev(pas->sysmon); + qcom_remove_smd_subdev(pas->rproc, &pas->smd_subdev); + qcom_remove_pdm_subdev(pas->rproc, &pas->pdm_subdev); + qcom_remove_ssr_subdev(pas->rproc, &pas->ssr_subdev); + qcom_pas_pds_detach(pas, pas->proxy_pds, pas->proxy_pd_count); + device_init_wakeup(pas->dev, false); } -static const struct adsp_data adsp_resource_init = { +static const struct qcom_pas_data adsp_resource_init = { .crash_reason_smem = 423, .firmware_name = "adsp.mdt", .pas_id = 1, @@ -839,7 +830,7 @@ static const struct adsp_data adsp_resource_init = { .ssctl_id = 0x14, }; -static const struct adsp_data sa8775p_adsp_resource = { +static const struct qcom_pas_data sa8775p_adsp_resource = { .crash_reason_smem = 423, .firmware_name = "adsp.mbn", .pas_id = 1, @@ -856,7 +847,7 @@ static const struct adsp_data sa8775p_adsp_resource = { .ssctl_id = 0x14, }; -static const struct adsp_data sdm845_adsp_resource_init = { +static const struct qcom_pas_data sdm845_adsp_resource_init = { .crash_reason_smem = 423, .firmware_name = "adsp.mdt", .pas_id = 1, @@ -867,7 +858,7 @@ static const struct adsp_data sdm845_adsp_resource_init = { .ssctl_id = 0x14, }; -static const struct adsp_data sm6350_adsp_resource = { +static const struct qcom_pas_data sm6350_adsp_resource = { .crash_reason_smem = 423, .firmware_name = "adsp.mdt", .pas_id = 1, @@ -883,7 +874,7 @@ static const struct adsp_data sm6350_adsp_resource = { .ssctl_id = 0x14, }; -static const struct adsp_data sm6375_mpss_resource = { +static const struct qcom_pas_data sm6375_mpss_resource = { .crash_reason_smem = 421, .firmware_name = "modem.mdt", .pas_id = 4, @@ -898,7 +889,7 @@ static const struct adsp_data sm6375_mpss_resource = { .ssctl_id = 0x12, }; -static const struct adsp_data sm8150_adsp_resource = { +static const struct qcom_pas_data sm8150_adsp_resource = { .crash_reason_smem = 423, .firmware_name = "adsp.mdt", .pas_id = 1, @@ -913,7 +904,7 @@ static const struct adsp_data sm8150_adsp_resource = { .ssctl_id = 0x14, }; -static const struct adsp_data sm8250_adsp_resource = { +static const struct qcom_pas_data sm8250_adsp_resource = { .crash_reason_smem = 423, .firmware_name = "adsp.mdt", .pas_id = 1, @@ -930,7 +921,7 @@ static const struct adsp_data sm8250_adsp_resource = { .ssctl_id = 0x14, }; -static const struct adsp_data sm8350_adsp_resource = { +static const struct qcom_pas_data sm8350_adsp_resource = { .crash_reason_smem = 423, .firmware_name = "adsp.mdt", .pas_id = 1, @@ -946,7 +937,7 @@ static const struct adsp_data sm8350_adsp_resource = { .ssctl_id = 0x14, }; -static const struct adsp_data msm8996_adsp_resource = { +static const struct qcom_pas_data msm8996_adsp_resource = { .crash_reason_smem = 423, .firmware_name = "adsp.mdt", .pas_id = 1, @@ -960,7 +951,7 @@ static const struct adsp_data msm8996_adsp_resource = { .ssctl_id = 0x14, }; -static const struct adsp_data cdsp_resource_init = { +static const struct qcom_pas_data cdsp_resource_init = { .crash_reason_smem = 601, .firmware_name = "cdsp.mdt", .pas_id = 18, @@ -970,7 +961,7 @@ static const struct adsp_data cdsp_resource_init = { .ssctl_id = 0x17, }; -static const struct adsp_data sa8775p_cdsp0_resource = { +static const struct qcom_pas_data sa8775p_cdsp0_resource = { .crash_reason_smem = 601, .firmware_name = "cdsp0.mbn", .pas_id = 18, @@ -988,7 +979,7 @@ static const struct adsp_data sa8775p_cdsp0_resource = { .ssctl_id = 0x17, }; -static const struct adsp_data sa8775p_cdsp1_resource = { +static const struct qcom_pas_data sa8775p_cdsp1_resource = { .crash_reason_smem = 633, .firmware_name = "cdsp1.mbn", .pas_id = 30, @@ -1006,7 +997,7 @@ static const struct adsp_data sa8775p_cdsp1_resource = { .ssctl_id = 0x20, }; -static const struct adsp_data sdm845_cdsp_resource_init = { +static const struct qcom_pas_data sdm845_cdsp_resource_init = { .crash_reason_smem = 601, .firmware_name = "cdsp.mdt", .pas_id = 18, @@ -1017,7 +1008,7 @@ static const struct adsp_data sdm845_cdsp_resource_init = { .ssctl_id = 0x17, }; -static const struct adsp_data sm6350_cdsp_resource = { +static const struct qcom_pas_data sm6350_cdsp_resource = { .crash_reason_smem = 601, .firmware_name = "cdsp.mdt", .pas_id = 18, @@ -1033,7 +1024,7 @@ static const struct adsp_data sm6350_cdsp_resource = { .ssctl_id = 0x17, }; -static const struct adsp_data sm8150_cdsp_resource = { +static const struct qcom_pas_data sm8150_cdsp_resource = { .crash_reason_smem = 601, .firmware_name = "cdsp.mdt", .pas_id = 18, @@ -1048,7 +1039,7 @@ static const struct adsp_data sm8150_cdsp_resource = { .ssctl_id = 0x17, }; -static const struct adsp_data sm8250_cdsp_resource = { +static const struct qcom_pas_data sm8250_cdsp_resource = { .crash_reason_smem = 601, .firmware_name = "cdsp.mdt", .pas_id = 18, @@ -1063,7 +1054,7 @@ static const struct adsp_data sm8250_cdsp_resource = { .ssctl_id = 0x17, }; -static const struct adsp_data sc8280xp_nsp0_resource = { +static const struct qcom_pas_data sc8280xp_nsp0_resource = { .crash_reason_smem = 601, .firmware_name = "cdsp.mdt", .pas_id = 18, @@ -1077,7 +1068,7 @@ static const struct adsp_data sc8280xp_nsp0_resource = { .ssctl_id = 0x17, }; -static const struct adsp_data sc8280xp_nsp1_resource = { +static const struct qcom_pas_data sc8280xp_nsp1_resource = { .crash_reason_smem = 633, .firmware_name = "cdsp.mdt", .pas_id = 30, @@ -1091,13 +1082,14 @@ static const struct adsp_data sc8280xp_nsp1_resource = { .ssctl_id = 0x20, }; -static const struct adsp_data x1e80100_adsp_resource = { +static const struct qcom_pas_data x1e80100_adsp_resource = { .crash_reason_smem = 423, .firmware_name = "adsp.mdt", .dtb_firmware_name = "adsp_dtb.mdt", .pas_id = 1, .dtb_pas_id = 0x24, .lite_pas_id = 0x1f, + .lite_dtb_pas_id = 0x29, .minidump_id = 5, .auto_boot = true, .proxy_pd_names = (char*[]){ @@ -1111,7 +1103,7 @@ static const struct adsp_data x1e80100_adsp_resource = { .ssctl_id = 0x14, }; -static const struct adsp_data x1e80100_cdsp_resource = { +static const struct qcom_pas_data x1e80100_cdsp_resource = { .crash_reason_smem = 601, .firmware_name = "cdsp.mdt", .dtb_firmware_name = "cdsp_dtb.mdt", @@ -1131,7 +1123,7 @@ static const struct adsp_data x1e80100_cdsp_resource = { .ssctl_id = 0x17, }; -static const struct adsp_data sm8350_cdsp_resource = { +static const struct qcom_pas_data sm8350_cdsp_resource = { .crash_reason_smem = 601, .firmware_name = "cdsp.mdt", .pas_id = 18, @@ -1148,7 +1140,7 @@ static const struct adsp_data sm8350_cdsp_resource = { .ssctl_id = 0x17, }; -static const struct adsp_data sa8775p_gpdsp0_resource = { +static const struct qcom_pas_data sa8775p_gpdsp0_resource = { .crash_reason_smem = 640, .firmware_name = "gpdsp0.mbn", .pas_id = 39, @@ -1165,7 +1157,7 @@ static const struct adsp_data sa8775p_gpdsp0_resource = { .ssctl_id = 0x21, }; -static const struct adsp_data sa8775p_gpdsp1_resource = { +static const struct qcom_pas_data sa8775p_gpdsp1_resource = { .crash_reason_smem = 641, .firmware_name = "gpdsp1.mbn", .pas_id = 40, @@ -1182,7 +1174,7 @@ static const struct adsp_data sa8775p_gpdsp1_resource = { .ssctl_id = 0x22, }; -static const struct adsp_data mpss_resource_init = { +static const struct qcom_pas_data mpss_resource_init = { .crash_reason_smem = 421, .firmware_name = "modem.mdt", .pas_id = 4, @@ -1199,7 +1191,7 @@ static const struct adsp_data mpss_resource_init = { .ssctl_id = 0x12, }; -static const struct adsp_data sc8180x_mpss_resource = { +static const struct qcom_pas_data sc8180x_mpss_resource = { .crash_reason_smem = 421, .firmware_name = "modem.mdt", .pas_id = 4, @@ -1214,7 +1206,7 @@ static const struct adsp_data sc8180x_mpss_resource = { .ssctl_id = 0x12, }; -static const struct adsp_data msm8996_slpi_resource_init = { +static const struct qcom_pas_data msm8996_slpi_resource_init = { .crash_reason_smem = 424, .firmware_name = "slpi.mdt", .pas_id = 12, @@ -1228,7 +1220,7 @@ static const struct adsp_data msm8996_slpi_resource_init = { .ssctl_id = 0x16, }; -static const struct adsp_data sdm845_slpi_resource_init = { +static const struct qcom_pas_data sdm845_slpi_resource_init = { .crash_reason_smem = 424, .firmware_name = "slpi.mdt", .pas_id = 12, @@ -1244,7 +1236,7 @@ static const struct adsp_data sdm845_slpi_resource_init = { .ssctl_id = 0x16, }; -static const struct adsp_data wcss_resource_init = { +static const struct qcom_pas_data wcss_resource_init = { .crash_reason_smem = 421, .firmware_name = "wcnss.mdt", .pas_id = 6, @@ -1254,7 +1246,7 @@ static const struct adsp_data wcss_resource_init = { .ssctl_id = 0x12, }; -static const struct adsp_data sdx55_mpss_resource = { +static const struct qcom_pas_data sdx55_mpss_resource = { .crash_reason_smem = 421, .firmware_name = "modem.mdt", .pas_id = 4, @@ -1269,7 +1261,27 @@ static const struct adsp_data sdx55_mpss_resource = { .ssctl_id = 0x22, }; -static const struct adsp_data sm8450_mpss_resource = { +static const struct qcom_pas_data milos_cdsp_resource = { + .crash_reason_smem = 601, + .firmware_name = "cdsp.mbn", + .dtb_firmware_name = "cdsp_dtb.mbn", + .pas_id = 18, + .dtb_pas_id = 0x25, + .minidump_id = 7, + .auto_boot = true, + .proxy_pd_names = (char*[]){ + "cx", + "mx", + NULL + }, + .load_state = "cdsp", + .ssr_name = "cdsp", + .sysmon_name = "cdsp", + .ssctl_id = 0x17, + .smem_host_id = 5, +}; + +static const struct qcom_pas_data sm8450_mpss_resource = { .crash_reason_smem = 421, .firmware_name = "modem.mdt", .pas_id = 4, @@ -1287,7 +1299,7 @@ static const struct adsp_data sm8450_mpss_resource = { .ssctl_id = 0x12, }; -static const struct adsp_data sm8550_adsp_resource = { +static const struct qcom_pas_data sm8550_adsp_resource = { .crash_reason_smem = 423, .firmware_name = "adsp.mdt", .dtb_firmware_name = "adsp_dtb.mdt", @@ -1307,7 +1319,7 @@ static const struct adsp_data sm8550_adsp_resource = { .smem_host_id = 2, }; -static const struct adsp_data sm8550_cdsp_resource = { +static const struct qcom_pas_data sm8550_cdsp_resource = { .crash_reason_smem = 601, .firmware_name = "cdsp.mdt", .dtb_firmware_name = "cdsp_dtb.mdt", @@ -1328,7 +1340,7 @@ static const struct adsp_data sm8550_cdsp_resource = { .smem_host_id = 5, }; -static const struct adsp_data sm8550_mpss_resource = { +static const struct qcom_pas_data sm8550_mpss_resource = { .crash_reason_smem = 421, .firmware_name = "modem.mdt", .dtb_firmware_name = "modem_dtb.mdt", @@ -1352,7 +1364,7 @@ static const struct adsp_data sm8550_mpss_resource = { .region_assign_vmid = QCOM_SCM_VMID_MSS_MSA, }; -static const struct adsp_data sc7280_wpss_resource = { +static const struct qcom_pas_data sc7280_wpss_resource = { .crash_reason_smem = 626, .firmware_name = "wpss.mdt", .pas_id = 6, @@ -1369,7 +1381,7 @@ static const struct adsp_data sc7280_wpss_resource = { .ssctl_id = 0x19, }; -static const struct adsp_data sm8650_cdsp_resource = { +static const struct qcom_pas_data sm8650_cdsp_resource = { .crash_reason_smem = 601, .firmware_name = "cdsp.mdt", .dtb_firmware_name = "cdsp_dtb.mdt", @@ -1394,7 +1406,7 @@ static const struct adsp_data sm8650_cdsp_resource = { .region_assign_vmid = QCOM_SCM_VMID_CDSP, }; -static const struct adsp_data sm8650_mpss_resource = { +static const struct qcom_pas_data sm8650_mpss_resource = { .crash_reason_smem = 421, .firmware_name = "modem.mdt", .dtb_firmware_name = "modem_dtb.mdt", @@ -1418,7 +1430,35 @@ static const struct adsp_data sm8650_mpss_resource = { .region_assign_vmid = QCOM_SCM_VMID_MSS_MSA, }; -static const struct of_device_id adsp_of_match[] = { +static const struct qcom_pas_data sm8750_mpss_resource = { + .crash_reason_smem = 421, + .firmware_name = "modem.mdt", + .dtb_firmware_name = "modem_dtb.mdt", + .pas_id = 4, + .dtb_pas_id = 0x26, + .minidump_id = 3, + .auto_boot = false, + .decrypt_shutdown = true, + .proxy_pd_names = (char*[]){ + "cx", + "mss", + NULL + }, + .load_state = "modem", + .ssr_name = "mpss", + .sysmon_name = "modem", + .ssctl_id = 0x12, + .smem_host_id = 1, + .region_assign_idx = 2, + .region_assign_count = 2, + .region_assign_vmid = QCOM_SCM_VMID_MSS_MSA, +}; + +static const struct of_device_id qcom_pas_of_match[] = { + { .compatible = "qcom,milos-adsp-pas", .data = &sm8550_adsp_resource}, + { .compatible = "qcom,milos-cdsp-pas", .data = &milos_cdsp_resource}, + { .compatible = "qcom,milos-mpss-pas", .data = &sm8450_mpss_resource}, + { .compatible = "qcom,milos-wpss-pas", .data = &sc7280_wpss_resource}, { .compatible = "qcom,msm8226-adsp-pil", .data = &msm8996_adsp_resource}, { .compatible = "qcom,msm8953-adsp-pil", .data = &msm8996_adsp_resource}, { .compatible = "qcom,msm8974-adsp-pil", .data = &adsp_resource_init}, @@ -1483,21 +1523,22 @@ static const struct of_device_id adsp_of_match[] = { { .compatible = "qcom,sm8650-adsp-pas", .data = &sm8550_adsp_resource}, { .compatible = "qcom,sm8650-cdsp-pas", .data = &sm8650_cdsp_resource}, { .compatible = "qcom,sm8650-mpss-pas", .data = &sm8650_mpss_resource}, + { .compatible = "qcom,sm8750-mpss-pas", .data = &sm8750_mpss_resource}, { .compatible = "qcom,x1e80100-adsp-pas", .data = &x1e80100_adsp_resource}, { .compatible = "qcom,x1e80100-cdsp-pas", .data = &x1e80100_cdsp_resource}, { }, }; -MODULE_DEVICE_TABLE(of, adsp_of_match); +MODULE_DEVICE_TABLE(of, qcom_pas_of_match); -static struct platform_driver adsp_driver = { - .probe = adsp_probe, - .remove_new = adsp_remove, +static struct platform_driver qcom_pas_driver = { + .probe = qcom_pas_probe, + .remove = qcom_pas_remove, .driver = { .name = "qcom_q6v5_pas", - .of_match_table = adsp_of_match, + .of_match_table = qcom_pas_of_match, }, }; -module_platform_driver(adsp_driver); -MODULE_DESCRIPTION("Qualcomm Hexagon v5 Peripheral Authentication Service driver"); +module_platform_driver(qcom_pas_driver); +MODULE_DESCRIPTION("Qualcomm Peripheral Authentication Service remoteproc driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/remoteproc/qcom_q6v5_wcss.c b/drivers/remoteproc/qcom_q6v5_wcss.c index c560b81b7263..23ec87827d4f 100644 --- a/drivers/remoteproc/qcom_q6v5_wcss.c +++ b/drivers/remoteproc/qcom_q6v5_wcss.c @@ -757,7 +757,7 @@ static int q6v5_wcss_load(struct rproc *rproc, const struct firmware *fw) int ret; ret = qcom_mdt_load_no_init(wcss->dev, fw, rproc->firmware, - 0, wcss->mem_region, wcss->mem_phys, + wcss->mem_region, wcss->mem_phys, wcss->mem_size, &wcss->mem_reloc); if (ret) return ret; @@ -902,90 +902,58 @@ static int q6v5_alloc_memory_region(struct q6v5_wcss *wcss) static int q6v5_wcss_init_clock(struct q6v5_wcss *wcss) { - int ret; - wcss->xo = devm_clk_get(wcss->dev, "xo"); - if (IS_ERR(wcss->xo)) { - ret = PTR_ERR(wcss->xo); - if (ret != -EPROBE_DEFER) - dev_err(wcss->dev, "failed to get xo clock"); - return ret; - } + if (IS_ERR(wcss->xo)) + return dev_err_probe(wcss->dev, PTR_ERR(wcss->xo), + "failed to get xo clock"); wcss->gcc_abhs_cbcr = devm_clk_get(wcss->dev, "gcc_abhs_cbcr"); - if (IS_ERR(wcss->gcc_abhs_cbcr)) { - ret = PTR_ERR(wcss->gcc_abhs_cbcr); - if (ret != -EPROBE_DEFER) - dev_err(wcss->dev, "failed to get gcc abhs clock"); - return ret; - } + if (IS_ERR(wcss->gcc_abhs_cbcr)) + return dev_err_probe(wcss->dev, PTR_ERR(wcss->gcc_abhs_cbcr), + "failed to get gcc abhs clock"); wcss->gcc_axim_cbcr = devm_clk_get(wcss->dev, "gcc_axim_cbcr"); - if (IS_ERR(wcss->gcc_axim_cbcr)) { - ret = PTR_ERR(wcss->gcc_axim_cbcr); - if (ret != -EPROBE_DEFER) - dev_err(wcss->dev, "failed to get gcc axim clock\n"); - return ret; - } + if (IS_ERR(wcss->gcc_axim_cbcr)) + return dev_err_probe(wcss->dev, PTR_ERR(wcss->gcc_axim_cbcr), + "failed to get gcc axim clock\n"); wcss->ahbfabric_cbcr_clk = devm_clk_get(wcss->dev, "lcc_ahbfabric_cbc"); - if (IS_ERR(wcss->ahbfabric_cbcr_clk)) { - ret = PTR_ERR(wcss->ahbfabric_cbcr_clk); - if (ret != -EPROBE_DEFER) - dev_err(wcss->dev, "failed to get ahbfabric clock\n"); - return ret; - } + if (IS_ERR(wcss->ahbfabric_cbcr_clk)) + return dev_err_probe(wcss->dev, PTR_ERR(wcss->ahbfabric_cbcr_clk), + "failed to get ahbfabric clock\n"); wcss->lcc_csr_cbcr = devm_clk_get(wcss->dev, "tcsr_lcc_cbc"); - if (IS_ERR(wcss->lcc_csr_cbcr)) { - ret = PTR_ERR(wcss->lcc_csr_cbcr); - if (ret != -EPROBE_DEFER) - dev_err(wcss->dev, "failed to get csr cbcr clk\n"); - return ret; - } + if (IS_ERR(wcss->lcc_csr_cbcr)) + return dev_err_probe(wcss->dev, PTR_ERR(wcss->lcc_csr_cbcr), + "failed to get csr cbcr clk\n"); wcss->ahbs_cbcr = devm_clk_get(wcss->dev, "lcc_abhs_cbc"); - if (IS_ERR(wcss->ahbs_cbcr)) { - ret = PTR_ERR(wcss->ahbs_cbcr); - if (ret != -EPROBE_DEFER) - dev_err(wcss->dev, "failed to get ahbs_cbcr clk\n"); - return ret; - } + if (IS_ERR(wcss->ahbs_cbcr)) + return dev_err_probe(wcss->dev, PTR_ERR(wcss->ahbs_cbcr), + "failed to get ahbs_cbcr clk\n"); wcss->tcm_slave_cbcr = devm_clk_get(wcss->dev, "lcc_tcm_slave_cbc"); - if (IS_ERR(wcss->tcm_slave_cbcr)) { - ret = PTR_ERR(wcss->tcm_slave_cbcr); - if (ret != -EPROBE_DEFER) - dev_err(wcss->dev, "failed to get tcm cbcr clk\n"); - return ret; - } + if (IS_ERR(wcss->tcm_slave_cbcr)) + return dev_err_probe(wcss->dev, PTR_ERR(wcss->tcm_slave_cbcr), + "failed to get tcm cbcr clk\n"); wcss->qdsp6ss_abhm_cbcr = devm_clk_get(wcss->dev, "lcc_abhm_cbc"); - if (IS_ERR(wcss->qdsp6ss_abhm_cbcr)) { - ret = PTR_ERR(wcss->qdsp6ss_abhm_cbcr); - if (ret != -EPROBE_DEFER) - dev_err(wcss->dev, "failed to get abhm cbcr clk\n"); - return ret; - } + if (IS_ERR(wcss->qdsp6ss_abhm_cbcr)) + return dev_err_probe(wcss->dev, PTR_ERR(wcss->qdsp6ss_abhm_cbcr), + "failed to get abhm cbcr clk\n"); wcss->qdsp6ss_axim_cbcr = devm_clk_get(wcss->dev, "lcc_axim_cbc"); - if (IS_ERR(wcss->qdsp6ss_axim_cbcr)) { - ret = PTR_ERR(wcss->qdsp6ss_axim_cbcr); - if (ret != -EPROBE_DEFER) - dev_err(wcss->dev, "failed to get axim cbcr clk\n"); - return ret; - } + if (IS_ERR(wcss->qdsp6ss_axim_cbcr)) + return dev_err_probe(wcss->dev, PTR_ERR(wcss->qdsp6ss_axim_cbcr), + "failed to get axim cbcr clk\n"); wcss->lcc_bcr_sleep = devm_clk_get(wcss->dev, "lcc_bcr_sleep"); - if (IS_ERR(wcss->lcc_bcr_sleep)) { - ret = PTR_ERR(wcss->lcc_bcr_sleep); - if (ret != -EPROBE_DEFER) - dev_err(wcss->dev, "failed to get bcr cbcr clk\n"); - return ret; - } + if (IS_ERR(wcss->lcc_bcr_sleep)) + return dev_err_probe(wcss->dev, PTR_ERR(wcss->lcc_bcr_sleep), + "failed to get bcr cbcr clk\n"); return 0; } @@ -1021,7 +989,6 @@ static int q6v5_wcss_probe(struct platform_device *pdev) wcss = rproc->priv; wcss->dev = &pdev->dev; - wcss->version = desc->version; wcss->version = desc->version; wcss->requires_force_stop = desc->requires_force_stop; @@ -1056,18 +1023,33 @@ static int q6v5_wcss_probe(struct platform_device *pdev) qcom_add_pdm_subdev(rproc, &wcss->pdm_subdev); qcom_add_ssr_subdev(rproc, &wcss->ssr_subdev, "q6wcss"); - if (desc->ssctl_id) + if (desc->ssctl_id) { wcss->sysmon = qcom_add_sysmon_subdev(rproc, desc->sysmon_name, desc->ssctl_id); + if (IS_ERR(wcss->sysmon)) { + ret = PTR_ERR(wcss->sysmon); + goto deinit_remove_subdevs; + } + } ret = rproc_add(rproc); if (ret) - return ret; + goto remove_sysmon_subdev; platform_set_drvdata(pdev, rproc); return 0; + +remove_sysmon_subdev: + if (desc->ssctl_id) + qcom_remove_sysmon_subdev(wcss->sysmon); +deinit_remove_subdevs: + qcom_q6v5_deinit(&wcss->q6v5); + qcom_remove_glink_subdev(rproc, &wcss->glink_subdev); + qcom_remove_pdm_subdev(rproc, &wcss->pdm_subdev); + qcom_remove_ssr_subdev(rproc, &wcss->ssr_subdev); + return ret; } static void q6v5_wcss_remove(struct platform_device *pdev) @@ -1111,7 +1093,7 @@ MODULE_DEVICE_TABLE(of, q6v5_wcss_of_match); static struct platform_driver q6v5_wcss_driver = { .probe = q6v5_wcss_probe, - .remove_new = q6v5_wcss_remove, + .remove = q6v5_wcss_remove, .driver = { .name = "qcom-q6v5-wcss-pil", .of_match_table = q6v5_wcss_of_match, diff --git a/drivers/remoteproc/qcom_sysmon.c b/drivers/remoteproc/qcom_sysmon.c index c24e4a882873..660ac6fc4082 100644 --- a/drivers/remoteproc/qcom_sysmon.c +++ b/drivers/remoteproc/qcom_sysmon.c @@ -619,7 +619,7 @@ static irqreturn_t sysmon_shutdown_interrupt(int irq, void *data) * @name: name of this subdev, to use in SSR * @ssctl_instance: instance id of the ssctl QMI service * - * Return: A new qcom_sysmon object, or NULL on failure + * Return: A new qcom_sysmon object, or an error pointer on failure */ struct qcom_sysmon *qcom_add_sysmon_subdev(struct rproc *rproc, const char *name, diff --git a/drivers/remoteproc/qcom_wcnss.c b/drivers/remoteproc/qcom_wcnss.c index a2ae6adf0053..2c7e519a2254 100644 --- a/drivers/remoteproc/qcom_wcnss.c +++ b/drivers/remoteproc/qcom_wcnss.c @@ -702,7 +702,7 @@ MODULE_DEVICE_TABLE(of, wcnss_of_match); static struct platform_driver wcnss_driver = { .probe = wcnss_probe, - .remove_new = wcnss_remove, + .remove = wcnss_remove, .driver = { .name = "qcom-wcnss-pil", .of_match_table = wcnss_of_match, diff --git a/drivers/remoteproc/qcom_wcnss_iris.c b/drivers/remoteproc/qcom_wcnss_iris.c index 1e197f773474..2b52b403eb3f 100644 --- a/drivers/remoteproc/qcom_wcnss_iris.c +++ b/drivers/remoteproc/qcom_wcnss_iris.c @@ -155,9 +155,8 @@ struct qcom_iris *qcom_iris_probe(struct device *parent, bool *use_48mhz_xo) iris->xo_clk = devm_clk_get(&iris->dev, "xo"); if (IS_ERR(iris->xo_clk)) { - ret = PTR_ERR(iris->xo_clk); - if (ret != -EPROBE_DEFER) - dev_err(&iris->dev, "failed to acquire xo clk\n"); + ret = dev_err_probe(&iris->dev, PTR_ERR(iris->xo_clk), + "failed to acquire xo clk\n"); goto err_device_del; } diff --git a/drivers/remoteproc/rcar_rproc.c b/drivers/remoteproc/rcar_rproc.c index cc17e8421f65..921d853594f4 100644 --- a/drivers/remoteproc/rcar_rproc.c +++ b/drivers/remoteproc/rcar_rproc.c @@ -214,7 +214,7 @@ MODULE_DEVICE_TABLE(of, rcar_rproc_of_match); static struct platform_driver rcar_rproc_driver = { .probe = rcar_rproc_probe, - .remove_new = rcar_rproc_remove, + .remove = rcar_rproc_remove, .driver = { .name = "rcar-rproc", .of_match_table = rcar_rproc_of_match, diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c index b7011eb384a5..825672100528 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c @@ -109,10 +109,10 @@ static int rproc_enable_iommu(struct rproc *rproc) return 0; } - domain = iommu_domain_alloc(dev->bus); - if (!domain) { + domain = iommu_paging_domain_alloc(dev); + if (IS_ERR(domain)) { dev_err(dev, "can't alloc iommu domain\n"); - return -ENOMEM; + return PTR_ERR(domain); } iommu_set_fault_handler(domain, rproc_iommu_fault, rproc); @@ -699,7 +699,7 @@ static int rproc_alloc_carveout(struct rproc *rproc, return -ENOMEM; } - dev_dbg(dev, "carveout va %pK, dma %pad, len 0x%zx\n", + dev_dbg(dev, "carveout va %p, dma %pad, len 0x%zx\n", va, &dma, mem->len); if (mem->da != FW_RSC_ADDR_ANY && !rproc->domain) { @@ -2025,7 +2025,6 @@ int rproc_shutdown(struct rproc *rproc) kfree(rproc->cached_table); rproc->cached_table = NULL; rproc->table_ptr = NULL; - rproc->table_sz = 0; out: mutex_unlock(&rproc->lock); return ret; diff --git a/drivers/remoteproc/remoteproc_virtio.c b/drivers/remoteproc/remoteproc_virtio.c index d3f39009b28e..c5d46a878149 100644 --- a/drivers/remoteproc/remoteproc_virtio.c +++ b/drivers/remoteproc/remoteproc_virtio.c @@ -136,7 +136,7 @@ static struct virtqueue *rp_find_vq(struct virtio_device *vdev, size = vring_size(num, rvring->align); memset(addr, 0, size); - dev_dbg(dev, "vring%d: va %pK qsz %d notifyid %d\n", + dev_dbg(dev, "vring%d: va %p qsz %d notifyid %d\n", id, addr, num, rvring->notifyid); /* @@ -593,7 +593,7 @@ static void rproc_virtio_remove(struct platform_device *pdev) /* Platform driver */ static struct platform_driver rproc_virtio_driver = { .probe = rproc_virtio_probe, - .remove_new = rproc_virtio_remove, + .remove = rproc_virtio_remove, .driver = { .name = "rproc-virtio", }, diff --git a/drivers/remoteproc/st_remoteproc.c b/drivers/remoteproc/st_remoteproc.c index 1340be9d0110..e6566a9839dc 100644 --- a/drivers/remoteproc/st_remoteproc.c +++ b/drivers/remoteproc/st_remoteproc.c @@ -290,26 +290,23 @@ static int st_rproc_parse_dt(struct platform_device *pdev) if (ddata->config->sw_reset) { ddata->sw_reset = devm_reset_control_get_exclusive(dev, "sw_reset"); - if (IS_ERR(ddata->sw_reset)) { - dev_err(dev, "Failed to get S/W Reset\n"); - return PTR_ERR(ddata->sw_reset); - } + if (IS_ERR(ddata->sw_reset)) + return dev_err_probe(dev, PTR_ERR(ddata->sw_reset), + "Failed to get S/W Reset\n"); } if (ddata->config->pwr_reset) { ddata->pwr_reset = devm_reset_control_get_exclusive(dev, "pwr_reset"); - if (IS_ERR(ddata->pwr_reset)) { - dev_err(dev, "Failed to get Power Reset\n"); - return PTR_ERR(ddata->pwr_reset); - } + if (IS_ERR(ddata->pwr_reset)) + return dev_err_probe(dev, PTR_ERR(ddata->pwr_reset), + "Failed to get Power Reset\n"); } ddata->clk = devm_clk_get(dev, NULL); - if (IS_ERR(ddata->clk)) { - dev_err(dev, "Failed to get clock\n"); - return PTR_ERR(ddata->clk); - } + if (IS_ERR(ddata->clk)) + return dev_err_probe(dev, PTR_ERR(ddata->clk), + "Failed to get clock\n"); err = of_property_read_u32(np, "clock-frequency", &ddata->clk_rate); if (err) { @@ -317,18 +314,11 @@ static int st_rproc_parse_dt(struct platform_device *pdev) return err; } - ddata->boot_base = syscon_regmap_lookup_by_phandle(np, "st,syscfg"); - if (IS_ERR(ddata->boot_base)) { - dev_err(dev, "Boot base not found\n"); - return PTR_ERR(ddata->boot_base); - } - - err = of_property_read_u32_index(np, "st,syscfg", 1, - &ddata->boot_offset); - if (err) { - dev_err(dev, "Boot offset not found\n"); - return -EINVAL; - } + ddata->boot_base = syscon_regmap_lookup_by_phandle_args(np, "st,syscfg", + 1, &ddata->boot_offset); + if (IS_ERR(ddata->boot_base)) + return dev_err_probe(dev, PTR_ERR(ddata->boot_base), + "Boot base not found\n"); err = clk_prepare(ddata->clk); if (err) @@ -395,32 +385,32 @@ static int st_rproc_probe(struct platform_device *pdev) */ chan = mbox_request_channel_byname(&ddata->mbox_client_vq0, "vq0_rx"); if (IS_ERR(chan)) { - dev_err(&rproc->dev, "failed to request mbox chan 0\n"); - ret = PTR_ERR(chan); + ret = dev_err_probe(&rproc->dev, PTR_ERR(chan), + "failed to request mbox chan 0\n"); goto free_clk; } ddata->mbox_chan[ST_RPROC_VQ0 * MBOX_MAX + MBOX_RX] = chan; chan = mbox_request_channel_byname(&ddata->mbox_client_vq0, "vq0_tx"); if (IS_ERR(chan)) { - dev_err(&rproc->dev, "failed to request mbox chan 0\n"); - ret = PTR_ERR(chan); + ret = dev_err_probe(&rproc->dev, PTR_ERR(chan), + "failed to request mbox chan 0\n"); goto free_mbox; } ddata->mbox_chan[ST_RPROC_VQ0 * MBOX_MAX + MBOX_TX] = chan; chan = mbox_request_channel_byname(&ddata->mbox_client_vq1, "vq1_rx"); if (IS_ERR(chan)) { - dev_err(&rproc->dev, "failed to request mbox chan 1\n"); - ret = PTR_ERR(chan); + ret = dev_err_probe(&rproc->dev, PTR_ERR(chan), + "failed to request mbox chan 1\n"); goto free_mbox; } ddata->mbox_chan[ST_RPROC_VQ1 * MBOX_MAX + MBOX_RX] = chan; chan = mbox_request_channel_byname(&ddata->mbox_client_vq1, "vq1_tx"); if (IS_ERR(chan)) { - dev_err(&rproc->dev, "failed to request mbox chan 1\n"); - ret = PTR_ERR(chan); + ret = dev_err_probe(&rproc->dev, PTR_ERR(chan), + "failed to request mbox chan 1\n"); goto free_mbox; } ddata->mbox_chan[ST_RPROC_VQ1 * MBOX_MAX + MBOX_TX] = chan; @@ -457,7 +447,7 @@ static void st_rproc_remove(struct platform_device *pdev) static struct platform_driver st_rproc_driver = { .probe = st_rproc_probe, - .remove_new = st_rproc_remove, + .remove = st_rproc_remove, .driver = { .name = "st-rproc", .of_match_table = of_match_ptr(st_rproc_match), diff --git a/drivers/remoteproc/st_slim_rproc.c b/drivers/remoteproc/st_slim_rproc.c index 5412beb0a692..d083ecf02f5c 100644 --- a/drivers/remoteproc/st_slim_rproc.c +++ b/drivers/remoteproc/st_slim_rproc.c @@ -190,7 +190,7 @@ static void *slim_rproc_da_to_va(struct rproc *rproc, u64 da, size_t len, bool * } } - dev_dbg(&rproc->dev, "da = 0x%llx len = 0x%zx va = 0x%pK\n", + dev_dbg(&rproc->dev, "da = 0x%llx len = 0x%zx va = 0x%p\n", da, len, va); return va; diff --git a/drivers/remoteproc/stm32_rproc.c b/drivers/remoteproc/stm32_rproc.c index 8c7f7950b80e..431648607d53 100644 --- a/drivers/remoteproc/stm32_rproc.c +++ b/drivers/remoteproc/stm32_rproc.c @@ -835,6 +835,7 @@ static int stm32_rproc_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct stm32_rproc *ddata; struct device_node *np = dev->of_node; + const char *fw_name; struct rproc *rproc; unsigned int state; int ret; @@ -843,7 +844,12 @@ static int stm32_rproc_probe(struct platform_device *pdev) if (ret) return ret; - rproc = devm_rproc_alloc(dev, np->name, &st_rproc_ops, NULL, sizeof(*ddata)); + /* Look for an optional firmware name */ + ret = rproc_of_parse_firmware(dev, 0, &fw_name); + if (ret < 0 && ret != -EINVAL) + return ret; + + rproc = devm_rproc_alloc(dev, np->name, &st_rproc_ops, fw_name, sizeof(*ddata)); if (!rproc) return -ENOMEM; @@ -946,7 +952,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(stm32_rproc_pm_ops, static struct platform_driver stm32_rproc_driver = { .probe = stm32_rproc_probe, - .remove_new = stm32_rproc_remove, + .remove = stm32_rproc_remove, .driver = { .name = "stm32-rproc", .pm = pm_ptr(&stm32_rproc_pm_ops), diff --git a/drivers/remoteproc/ti_k3_common.c b/drivers/remoteproc/ti_k3_common.c new file mode 100644 index 000000000000..56b71652e449 --- /dev/null +++ b/drivers/remoteproc/ti_k3_common.c @@ -0,0 +1,548 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * TI K3 Remote Processor(s) driver common code + * + * Refactored out of ti_k3_r5_remoteproc.c, ti_k3_dsp_remoteproc.c and + * ti_k3_m4_remoteproc.c. + * + * ti_k3_r5_remoteproc.c: + * Copyright (C) 2017-2022 Texas Instruments Incorporated - https://www.ti.com/ + * Suman Anna <s-anna@ti.com> + * + * ti_k3_dsp_remoteproc.c: + * Copyright (C) 2018-2022 Texas Instruments Incorporated - https://www.ti.com/ + * Suman Anna <s-anna@ti.com> + * + * ti_k3_m4_remoteproc.c: + * Copyright (C) 2021-2024 Texas Instruments Incorporated - https://www.ti.com/ + * Hari Nagalla <hnagalla@ti.com> + */ + +#include <linux/io.h> +#include <linux/mailbox_client.h> +#include <linux/module.h> +#include <linux/of_address.h> +#include <linux/of_device.h> +#include <linux/of_reserved_mem.h> +#include <linux/omap-mailbox.h> +#include <linux/platform_device.h> +#include <linux/remoteproc.h> +#include <linux/reset.h> +#include <linux/slab.h> + +#include "omap_remoteproc.h" +#include "remoteproc_internal.h" +#include "ti_sci_proc.h" +#include "ti_k3_common.h" + +/** + * k3_rproc_mbox_callback() - inbound mailbox message handler + * @client: mailbox client pointer used for requesting the mailbox channel + * @data: mailbox payload + * + * This handler is invoked by the K3 mailbox driver whenever a mailbox + * message is received. Usually, the mailbox payload simply contains + * the index of the virtqueue that is kicked by the remote processor, + * and we let remoteproc core handle it. + * + * In addition to virtqueue indices, we also have some out-of-band values + * that indicate different events. Those values are deliberately very + * large so they don't coincide with virtqueue indices. + */ +void k3_rproc_mbox_callback(struct mbox_client *client, void *data) +{ + struct k3_rproc *kproc = container_of(client, struct k3_rproc, client); + struct device *dev = kproc->rproc->dev.parent; + struct rproc *rproc = kproc->rproc; + u32 msg = (u32)(uintptr_t)(data); + + dev_dbg(dev, "mbox msg: 0x%x\n", msg); + + switch (msg) { + case RP_MBOX_CRASH: + /* + * remoteproc detected an exception, but error recovery is not + * supported. So, just log this for now + */ + dev_err(dev, "K3 rproc %s crashed\n", rproc->name); + break; + case RP_MBOX_ECHO_REPLY: + dev_info(dev, "received echo reply from %s\n", rproc->name); + break; + default: + /* silently handle all other valid messages */ + if (msg >= RP_MBOX_READY && msg < RP_MBOX_END_MSG) + return; + if (msg > rproc->max_notifyid) { + dev_dbg(dev, "dropping unknown message 0x%x", msg); + return; + } + /* msg contains the index of the triggered vring */ + if (rproc_vq_interrupt(rproc, msg) == IRQ_NONE) + dev_dbg(dev, "no message was found in vqid %d\n", msg); + } +} +EXPORT_SYMBOL_GPL(k3_rproc_mbox_callback); + +/* + * Kick the remote processor to notify about pending unprocessed messages. + * The vqid usage is not used and is inconsequential, as the kick is performed + * through a simulated GPIO (a bit in an IPC interrupt-triggering register), + * the remote processor is expected to process both its Tx and Rx virtqueues. + */ +void k3_rproc_kick(struct rproc *rproc, int vqid) +{ + struct k3_rproc *kproc = rproc->priv; + struct device *dev = kproc->dev; + u32 msg = (u32)vqid; + int ret; + + /* + * Send the index of the triggered virtqueue in the mailbox payload. + * NOTE: msg is cast to uintptr_t to prevent compiler warnings when + * void* is 64bit. It is safely cast back to u32 in the mailbox driver. + */ + ret = mbox_send_message(kproc->mbox, (void *)(uintptr_t)msg); + if (ret < 0) + dev_err(dev, "failed to send mailbox message, status = %d\n", + ret); +} +EXPORT_SYMBOL_GPL(k3_rproc_kick); + +/* Put the remote processor into reset */ +int k3_rproc_reset(struct k3_rproc *kproc) +{ + struct device *dev = kproc->dev; + int ret; + + if (kproc->data->uses_lreset) { + ret = reset_control_assert(kproc->reset); + if (ret) + dev_err(dev, "local-reset assert failed (%pe)\n", ERR_PTR(ret)); + } else { + ret = kproc->ti_sci->ops.dev_ops.put_device(kproc->ti_sci, + kproc->ti_sci_id); + if (ret) + dev_err(dev, "module-reset assert failed (%pe)\n", ERR_PTR(ret)); + } + + return ret; +} +EXPORT_SYMBOL_GPL(k3_rproc_reset); + +/* Release the remote processor from reset */ +int k3_rproc_release(struct k3_rproc *kproc) +{ + struct device *dev = kproc->dev; + int ret; + + if (kproc->data->uses_lreset) { + ret = reset_control_deassert(kproc->reset); + if (ret) { + dev_err(dev, "local-reset deassert failed, (%pe)\n", ERR_PTR(ret)); + if (kproc->ti_sci->ops.dev_ops.put_device(kproc->ti_sci, + kproc->ti_sci_id)) + dev_warn(dev, "module-reset assert back failed\n"); + } + } else { + ret = kproc->ti_sci->ops.dev_ops.get_device(kproc->ti_sci, + kproc->ti_sci_id); + if (ret) + dev_err(dev, "module-reset deassert failed (%pe)\n", ERR_PTR(ret)); + } + + return ret; +} +EXPORT_SYMBOL_GPL(k3_rproc_release); + +static void k3_rproc_free_channel(void *data) +{ + struct k3_rproc *kproc = data; + + mbox_free_channel(kproc->mbox); +} + +int k3_rproc_request_mbox(struct rproc *rproc) +{ + struct k3_rproc *kproc = rproc->priv; + struct mbox_client *client = &kproc->client; + struct device *dev = kproc->dev; + int ret; + + client->dev = dev; + client->tx_done = NULL; + client->rx_callback = k3_rproc_mbox_callback; + client->tx_block = false; + client->knows_txdone = false; + + kproc->mbox = mbox_request_channel(client, 0); + if (IS_ERR(kproc->mbox)) + return dev_err_probe(dev, PTR_ERR(kproc->mbox), + "mbox_request_channel failed\n"); + + ret = devm_add_action_or_reset(dev, k3_rproc_free_channel, kproc); + if (ret) + return ret; + + return 0; +} +EXPORT_SYMBOL_GPL(k3_rproc_request_mbox); + +/* + * The K3 DSP and M4 cores have a local reset that affects only the CPU, and a + * generic module reset that powers on the device and allows the internal + * memories to be accessed while the local reset is asserted. This function is + * used to release the global reset on remote cores to allow loading into the + * internal RAMs. The .prepare() ops is invoked by remoteproc core before any + * firmware loading, and is followed by the .start() ops after loading to + * actually let the remote cores to run. + */ +int k3_rproc_prepare(struct rproc *rproc) +{ + struct k3_rproc *kproc = rproc->priv; + struct device *dev = kproc->dev; + int ret; + + /* If the core is running already no need to deassert the module reset */ + if (rproc->state == RPROC_DETACHED) + return 0; + + /* + * Ensure the local reset is asserted so the core doesn't + * execute bogus code when the module reset is released. + */ + if (kproc->data->uses_lreset) { + ret = k3_rproc_reset(kproc); + if (ret) + return ret; + + ret = reset_control_status(kproc->reset); + if (ret <= 0) { + dev_err(dev, "local reset still not asserted\n"); + return ret; + } + } + + ret = kproc->ti_sci->ops.dev_ops.get_device(kproc->ti_sci, + kproc->ti_sci_id); + if (ret) { + dev_err(dev, "could not deassert module-reset for internal RAM loading\n"); + return ret; + } + + return 0; +} +EXPORT_SYMBOL_GPL(k3_rproc_prepare); + +/* + * This function implements the .unprepare() ops and performs the complimentary + * operations to that of the .prepare() ops. The function is used to assert the + * global reset on applicable K3 DSP and M4 cores. This completes the second + * portion of powering down the remote core. The cores themselves are only + * halted in the .stop() callback through the local reset, and the .unprepare() + * ops is invoked by the remoteproc core after the remoteproc is stopped to + * balance the global reset. + */ +int k3_rproc_unprepare(struct rproc *rproc) +{ + struct k3_rproc *kproc = rproc->priv; + struct device *dev = kproc->dev; + int ret; + + /* If the core is going to be detached do not assert the module reset */ + if (rproc->state == RPROC_DETACHED) + return 0; + + ret = kproc->ti_sci->ops.dev_ops.put_device(kproc->ti_sci, + kproc->ti_sci_id); + if (ret) { + dev_err(dev, "module-reset assert failed\n"); + return ret; + } + + return 0; +} +EXPORT_SYMBOL_GPL(k3_rproc_unprepare); + +/* + * Power up the remote processor. + * + * This function will be invoked only after the firmware for this rproc + * was loaded, parsed successfully, and all of its resource requirements + * were met. This callback is invoked only in remoteproc mode. + */ +int k3_rproc_start(struct rproc *rproc) +{ + struct k3_rproc *kproc = rproc->priv; + + return k3_rproc_release(kproc); +} +EXPORT_SYMBOL_GPL(k3_rproc_start); + +/* + * Stop the remote processor. + * + * This function puts the remote processor into reset, and finishes processing + * of any pending messages. This callback is invoked only in remoteproc mode. + */ +int k3_rproc_stop(struct rproc *rproc) +{ + struct k3_rproc *kproc = rproc->priv; + + return k3_rproc_reset(kproc); +} +EXPORT_SYMBOL_GPL(k3_rproc_stop); + +/* + * Attach to a running remote processor (IPC-only mode) + * + * The rproc attach callback is a NOP. The remote processor is already booted, + * and all required resources have been acquired during probe routine, so there + * is no need to issue any TI-SCI commands to boot the remote cores in IPC-only + * mode. This callback is invoked only in IPC-only mode and exists because + * rproc_validate() checks for its existence. + */ +int k3_rproc_attach(struct rproc *rproc) { return 0; } +EXPORT_SYMBOL_GPL(k3_rproc_attach); + +/* + * Detach from a running remote processor (IPC-only mode) + * + * The rproc detach callback is a NOP. The remote processor is not stopped and + * will be left in booted state in IPC-only mode. This callback is invoked only + * in IPC-only mode and exists for sanity sake + */ +int k3_rproc_detach(struct rproc *rproc) { return 0; } +EXPORT_SYMBOL_GPL(k3_rproc_detach); + +/* + * This function implements the .get_loaded_rsc_table() callback and is used + * to provide the resource table for a booted remote processor in IPC-only + * mode. The remote processor firmwares follow a design-by-contract approach + * and are expected to have the resource table at the base of the DDR region + * reserved for firmware usage. This provides flexibility for the remote + * processor to be booted by different bootloaders that may or may not have the + * ability to publish the resource table address and size through a DT + * property. + */ +struct resource_table *k3_get_loaded_rsc_table(struct rproc *rproc, + size_t *rsc_table_sz) +{ + struct k3_rproc *kproc = rproc->priv; + struct device *dev = kproc->dev; + + if (!kproc->rmem[0].cpu_addr) { + dev_err(dev, "memory-region #1 does not exist, loaded rsc table can't be found"); + return ERR_PTR(-ENOMEM); + } + + /* + * NOTE: The resource table size is currently hard-coded to a maximum + * of 256 bytes. The most common resource table usage for K3 firmwares + * is to only have the vdev resource entry and an optional trace entry. + * The exact size could be computed based on resource table address, but + * the hard-coded value suffices to support the IPC-only mode. + */ + *rsc_table_sz = 256; + return (__force struct resource_table *)kproc->rmem[0].cpu_addr; +} +EXPORT_SYMBOL_GPL(k3_get_loaded_rsc_table); + +/* + * Custom function to translate a remote processor device address (internal + * RAMs only) to a kernel virtual address. The remote processors can access + * their RAMs at either an internal address visible only from a remote + * processor, or at the SoC-level bus address. Both these addresses need to be + * looked through for translation. The translated addresses can be used either + * by the remoteproc core for loading (when using kernel remoteproc loader), or + * by any rpmsg bus drivers. + */ +void *k3_rproc_da_to_va(struct rproc *rproc, u64 da, size_t len, bool *is_iomem) +{ + struct k3_rproc *kproc = rproc->priv; + void __iomem *va = NULL; + phys_addr_t bus_addr; + u32 dev_addr, offset; + size_t size; + int i; + + if (len == 0) + return NULL; + + for (i = 0; i < kproc->num_mems; i++) { + bus_addr = kproc->mem[i].bus_addr; + dev_addr = kproc->mem[i].dev_addr; + size = kproc->mem[i].size; + + /* handle rproc-view addresses */ + if (da >= dev_addr && ((da + len) <= (dev_addr + size))) { + offset = da - dev_addr; + va = kproc->mem[i].cpu_addr + offset; + return (__force void *)va; + } + + /* handle SoC-view addresses */ + if (da >= bus_addr && (da + len) <= (bus_addr + size)) { + offset = da - bus_addr; + va = kproc->mem[i].cpu_addr + offset; + return (__force void *)va; + } + } + + /* handle static DDR reserved memory regions */ + for (i = 0; i < kproc->num_rmems; i++) { + dev_addr = kproc->rmem[i].dev_addr; + size = kproc->rmem[i].size; + + if (da >= dev_addr && ((da + len) <= (dev_addr + size))) { + offset = da - dev_addr; + va = kproc->rmem[i].cpu_addr + offset; + return (__force void *)va; + } + } + + return NULL; +} +EXPORT_SYMBOL_GPL(k3_rproc_da_to_va); + +int k3_rproc_of_get_memories(struct platform_device *pdev, + struct k3_rproc *kproc) +{ + const struct k3_rproc_dev_data *data = kproc->data; + struct device *dev = &pdev->dev; + struct resource *res; + int num_mems = 0; + int i; + + num_mems = data->num_mems; + kproc->mem = devm_kcalloc(kproc->dev, num_mems, + sizeof(*kproc->mem), GFP_KERNEL); + if (!kproc->mem) + return -ENOMEM; + + for (i = 0; i < num_mems; i++) { + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + data->mems[i].name); + if (!res) { + dev_err(dev, "found no memory resource for %s\n", + data->mems[i].name); + return -EINVAL; + } + if (!devm_request_mem_region(dev, res->start, + resource_size(res), + dev_name(dev))) { + dev_err(dev, "could not request %s region for resource\n", + data->mems[i].name); + return -EBUSY; + } + + kproc->mem[i].cpu_addr = devm_ioremap_wc(dev, res->start, + resource_size(res)); + if (!kproc->mem[i].cpu_addr) { + dev_err(dev, "failed to map %s memory\n", + data->mems[i].name); + return -ENOMEM; + } + kproc->mem[i].bus_addr = res->start; + kproc->mem[i].dev_addr = data->mems[i].dev_addr; + kproc->mem[i].size = resource_size(res); + + dev_dbg(dev, "memory %8s: bus addr %pa size 0x%zx va %p da 0x%x\n", + data->mems[i].name, &kproc->mem[i].bus_addr, + kproc->mem[i].size, kproc->mem[i].cpu_addr, + kproc->mem[i].dev_addr); + } + kproc->num_mems = num_mems; + + return 0; +} +EXPORT_SYMBOL_GPL(k3_rproc_of_get_memories); + +void k3_mem_release(void *data) +{ + struct device *dev = data; + + of_reserved_mem_device_release(dev); +} +EXPORT_SYMBOL_GPL(k3_mem_release); + +int k3_reserved_mem_init(struct k3_rproc *kproc) +{ + struct device *dev = kproc->dev; + struct device_node *np = dev->of_node; + struct device_node *rmem_np; + struct reserved_mem *rmem; + int num_rmems; + int ret, i; + + num_rmems = of_property_count_elems_of_size(np, "memory-region", + sizeof(phandle)); + if (num_rmems < 0) { + dev_err(dev, "device does not reserved memory regions (%d)\n", + num_rmems); + return -EINVAL; + } + if (num_rmems < 2) { + dev_err(dev, "device needs at least two memory regions to be defined, num = %d\n", + num_rmems); + return -EINVAL; + } + + /* use reserved memory region 0 for vring DMA allocations */ + ret = of_reserved_mem_device_init_by_idx(dev, np, 0); + if (ret) { + dev_err(dev, "device cannot initialize DMA pool (%d)\n", ret); + return ret; + } + ret = devm_add_action_or_reset(dev, k3_mem_release, dev); + if (ret) + return ret; + + num_rmems--; + kproc->rmem = devm_kcalloc(dev, num_rmems, sizeof(*kproc->rmem), GFP_KERNEL); + if (!kproc->rmem) + return -ENOMEM; + + /* use remaining reserved memory regions for static carveouts */ + for (i = 0; i < num_rmems; i++) { + rmem_np = of_parse_phandle(np, "memory-region", i + 1); + if (!rmem_np) + return -EINVAL; + + rmem = of_reserved_mem_lookup(rmem_np); + of_node_put(rmem_np); + if (!rmem) + return -EINVAL; + + kproc->rmem[i].bus_addr = rmem->base; + /* 64-bit address regions currently not supported */ + kproc->rmem[i].dev_addr = (u32)rmem->base; + kproc->rmem[i].size = rmem->size; + kproc->rmem[i].cpu_addr = devm_ioremap_wc(dev, rmem->base, rmem->size); + if (!kproc->rmem[i].cpu_addr) { + dev_err(dev, "failed to map reserved memory#%d at %pa of size %pa\n", + i + 1, &rmem->base, &rmem->size); + return -ENOMEM; + } + + dev_dbg(dev, "reserved memory%d: bus addr %pa size 0x%zx va %p da 0x%x\n", + i + 1, &kproc->rmem[i].bus_addr, + kproc->rmem[i].size, kproc->rmem[i].cpu_addr, + kproc->rmem[i].dev_addr); + } + kproc->num_rmems = num_rmems; + + return 0; +} +EXPORT_SYMBOL_GPL(k3_reserved_mem_init); + +void k3_release_tsp(void *data) +{ + struct ti_sci_proc *tsp = data; + + ti_sci_proc_release(tsp); +} +EXPORT_SYMBOL_GPL(k3_release_tsp); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("TI K3 common Remoteproc code"); diff --git a/drivers/remoteproc/ti_k3_common.h b/drivers/remoteproc/ti_k3_common.h new file mode 100644 index 000000000000..aee3c28dbe51 --- /dev/null +++ b/drivers/remoteproc/ti_k3_common.h @@ -0,0 +1,118 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * TI K3 Remote Processor(s) driver common code + * + * Refactored out of ti_k3_r5_remoteproc.c, ti_k3_dsp_remoteproc.c and + * ti_k3_m4_remoteproc.c. + * + * ti_k3_r5_remoteproc.c: + * Copyright (C) 2017-2022 Texas Instruments Incorporated - https://www.ti.com/ + * Suman Anna <s-anna@ti.com> + * + * ti_k3_dsp_remoteproc.c: + * Copyright (C) 2018-2022 Texas Instruments Incorporated - https://www.ti.com/ + * Suman Anna <s-anna@ti.com> + * + * ti_k3_m4_remoteproc.c: + * Copyright (C) 2021-2024 Texas Instruments Incorporated - https://www.ti.com/ + * Hari Nagalla <hnagalla@ti.com> + */ + +#ifndef REMOTEPROC_TI_K3_COMMON_H +#define REMOTEPROC_TI_K3_COMMON_H + +#define KEYSTONE_RPROC_LOCAL_ADDRESS_MASK (SZ_16M - 1) + +/** + * struct k3_rproc_mem - internal memory structure + * @cpu_addr: MPU virtual address of the memory region + * @bus_addr: Bus address used to access the memory region + * @dev_addr: Device address of the memory region from remote processor view + * @size: Size of the memory region + */ +struct k3_rproc_mem { + void __iomem *cpu_addr; + phys_addr_t bus_addr; + u32 dev_addr; + size_t size; +}; + +/** + * struct k3_rproc_mem_data - memory definitions for a remote processor + * @name: name for this memory entry + * @dev_addr: device address for the memory entry + */ +struct k3_rproc_mem_data { + const char *name; + const u32 dev_addr; +}; + +/** + * struct k3_rproc_dev_data - device data structure for a remote processor + * @mems: pointer to memory definitions for a remote processor + * @num_mems: number of memory regions in @mems + * @boot_align_addr: boot vector address alignment granularity + * @uses_lreset: flag to denote the need for local reset management + */ +struct k3_rproc_dev_data { + const struct k3_rproc_mem_data *mems; + u32 num_mems; + u32 boot_align_addr; + bool uses_lreset; +}; + +/** + * struct k3_rproc - k3 remote processor driver structure + * @dev: cached device pointer + * @rproc: remoteproc device handle + * @mem: internal memory regions data + * @num_mems: number of internal memory regions + * @rmem: reserved memory regions data + * @num_rmems: number of reserved memory regions + * @reset: reset control handle + * @data: pointer to DSP-specific device data + * @tsp: TI-SCI processor control handle + * @ti_sci: TI-SCI handle + * @ti_sci_id: TI-SCI device identifier + * @mbox: mailbox channel handle + * @client: mailbox client to request the mailbox channel + * @priv: void pointer to carry any private data + */ +struct k3_rproc { + struct device *dev; + struct rproc *rproc; + struct k3_rproc_mem *mem; + int num_mems; + struct k3_rproc_mem *rmem; + int num_rmems; + struct reset_control *reset; + const struct k3_rproc_dev_data *data; + struct ti_sci_proc *tsp; + const struct ti_sci_handle *ti_sci; + u32 ti_sci_id; + struct mbox_chan *mbox; + struct mbox_client client; + void *priv; +}; + +void k3_rproc_mbox_callback(struct mbox_client *client, void *data); +void k3_rproc_kick(struct rproc *rproc, int vqid); +int k3_rproc_reset(struct k3_rproc *kproc); +int k3_rproc_release(struct k3_rproc *kproc); +int k3_rproc_request_mbox(struct rproc *rproc); +int k3_rproc_prepare(struct rproc *rproc); +int k3_rproc_unprepare(struct rproc *rproc); +int k3_rproc_start(struct rproc *rproc); +int k3_rproc_stop(struct rproc *rproc); +int k3_rproc_attach(struct rproc *rproc); +int k3_rproc_detach(struct rproc *rproc); +struct resource_table *k3_get_loaded_rsc_table(struct rproc *rproc, + size_t *rsc_table_sz); +void *k3_rproc_da_to_va(struct rproc *rproc, u64 da, size_t len, + bool *is_iomem); +int k3_rproc_of_get_memories(struct platform_device *pdev, + struct k3_rproc *kproc); +void k3_mem_release(void *data); +int k3_reserved_mem_init(struct k3_rproc *kproc); +void k3_release_tsp(void *data); +#endif /* REMOTEPROC_TI_K3_COMMON_H */ diff --git a/drivers/remoteproc/ti_k3_dsp_remoteproc.c b/drivers/remoteproc/ti_k3_dsp_remoteproc.c index 73be3d216791..d6ceea6dc920 100644 --- a/drivers/remoteproc/ti_k3_dsp_remoteproc.c +++ b/drivers/remoteproc/ti_k3_dsp_remoteproc.c @@ -20,283 +20,7 @@ #include "omap_remoteproc.h" #include "remoteproc_internal.h" #include "ti_sci_proc.h" - -#define KEYSTONE_RPROC_LOCAL_ADDRESS_MASK (SZ_16M - 1) - -/** - * struct k3_dsp_mem - internal memory structure - * @cpu_addr: MPU virtual address of the memory region - * @bus_addr: Bus address used to access the memory region - * @dev_addr: Device address of the memory region from DSP view - * @size: Size of the memory region - */ -struct k3_dsp_mem { - void __iomem *cpu_addr; - phys_addr_t bus_addr; - u32 dev_addr; - size_t size; -}; - -/** - * struct k3_dsp_mem_data - memory definitions for a DSP - * @name: name for this memory entry - * @dev_addr: device address for the memory entry - */ -struct k3_dsp_mem_data { - const char *name; - const u32 dev_addr; -}; - -/** - * struct k3_dsp_dev_data - device data structure for a DSP - * @mems: pointer to memory definitions for a DSP - * @num_mems: number of memory regions in @mems - * @boot_align_addr: boot vector address alignment granularity - * @uses_lreset: flag to denote the need for local reset management - */ -struct k3_dsp_dev_data { - const struct k3_dsp_mem_data *mems; - u32 num_mems; - u32 boot_align_addr; - bool uses_lreset; -}; - -/** - * struct k3_dsp_rproc - k3 DSP remote processor driver structure - * @dev: cached device pointer - * @rproc: remoteproc device handle - * @mem: internal memory regions data - * @num_mems: number of internal memory regions - * @rmem: reserved memory regions data - * @num_rmems: number of reserved memory regions - * @reset: reset control handle - * @data: pointer to DSP-specific device data - * @tsp: TI-SCI processor control handle - * @ti_sci: TI-SCI handle - * @ti_sci_id: TI-SCI device identifier - * @mbox: mailbox channel handle - * @client: mailbox client to request the mailbox channel - */ -struct k3_dsp_rproc { - struct device *dev; - struct rproc *rproc; - struct k3_dsp_mem *mem; - int num_mems; - struct k3_dsp_mem *rmem; - int num_rmems; - struct reset_control *reset; - const struct k3_dsp_dev_data *data; - struct ti_sci_proc *tsp; - const struct ti_sci_handle *ti_sci; - u32 ti_sci_id; - struct mbox_chan *mbox; - struct mbox_client client; -}; - -/** - * k3_dsp_rproc_mbox_callback() - inbound mailbox message handler - * @client: mailbox client pointer used for requesting the mailbox channel - * @data: mailbox payload - * - * This handler is invoked by the OMAP mailbox driver whenever a mailbox - * message is received. Usually, the mailbox payload simply contains - * the index of the virtqueue that is kicked by the remote processor, - * and we let remoteproc core handle it. - * - * In addition to virtqueue indices, we also have some out-of-band values - * that indicate different events. Those values are deliberately very - * large so they don't coincide with virtqueue indices. - */ -static void k3_dsp_rproc_mbox_callback(struct mbox_client *client, void *data) -{ - struct k3_dsp_rproc *kproc = container_of(client, struct k3_dsp_rproc, - client); - struct device *dev = kproc->rproc->dev.parent; - const char *name = kproc->rproc->name; - u32 msg = omap_mbox_message(data); - - dev_dbg(dev, "mbox msg: 0x%x\n", msg); - - switch (msg) { - case RP_MBOX_CRASH: - /* - * remoteproc detected an exception, but error recovery is not - * supported. So, just log this for now - */ - dev_err(dev, "K3 DSP rproc %s crashed\n", name); - break; - case RP_MBOX_ECHO_REPLY: - dev_info(dev, "received echo reply from %s\n", name); - break; - default: - /* silently handle all other valid messages */ - if (msg >= RP_MBOX_READY && msg < RP_MBOX_END_MSG) - return; - if (msg > kproc->rproc->max_notifyid) { - dev_dbg(dev, "dropping unknown message 0x%x", msg); - return; - } - /* msg contains the index of the triggered vring */ - if (rproc_vq_interrupt(kproc->rproc, msg) == IRQ_NONE) - dev_dbg(dev, "no message was found in vqid %d\n", msg); - } -} - -/* - * Kick the remote processor to notify about pending unprocessed messages. - * The vqid usage is not used and is inconsequential, as the kick is performed - * through a simulated GPIO (a bit in an IPC interrupt-triggering register), - * the remote processor is expected to process both its Tx and Rx virtqueues. - */ -static void k3_dsp_rproc_kick(struct rproc *rproc, int vqid) -{ - struct k3_dsp_rproc *kproc = rproc->priv; - struct device *dev = rproc->dev.parent; - mbox_msg_t msg = (mbox_msg_t)vqid; - int ret; - - /* send the index of the triggered virtqueue in the mailbox payload */ - ret = mbox_send_message(kproc->mbox, (void *)msg); - if (ret < 0) - dev_err(dev, "failed to send mailbox message (%pe)\n", - ERR_PTR(ret)); -} - -/* Put the DSP processor into reset */ -static int k3_dsp_rproc_reset(struct k3_dsp_rproc *kproc) -{ - struct device *dev = kproc->dev; - int ret; - - ret = reset_control_assert(kproc->reset); - if (ret) { - dev_err(dev, "local-reset assert failed (%pe)\n", ERR_PTR(ret)); - return ret; - } - - if (kproc->data->uses_lreset) - return ret; - - ret = kproc->ti_sci->ops.dev_ops.put_device(kproc->ti_sci, - kproc->ti_sci_id); - if (ret) { - dev_err(dev, "module-reset assert failed (%pe)\n", ERR_PTR(ret)); - if (reset_control_deassert(kproc->reset)) - dev_warn(dev, "local-reset deassert back failed\n"); - } - - return ret; -} - -/* Release the DSP processor from reset */ -static int k3_dsp_rproc_release(struct k3_dsp_rproc *kproc) -{ - struct device *dev = kproc->dev; - int ret; - - if (kproc->data->uses_lreset) - goto lreset; - - ret = kproc->ti_sci->ops.dev_ops.get_device(kproc->ti_sci, - kproc->ti_sci_id); - if (ret) { - dev_err(dev, "module-reset deassert failed (%pe)\n", ERR_PTR(ret)); - return ret; - } - -lreset: - ret = reset_control_deassert(kproc->reset); - if (ret) { - dev_err(dev, "local-reset deassert failed, (%pe)\n", ERR_PTR(ret)); - if (kproc->ti_sci->ops.dev_ops.put_device(kproc->ti_sci, - kproc->ti_sci_id)) - dev_warn(dev, "module-reset assert back failed\n"); - } - - return ret; -} - -static int k3_dsp_rproc_request_mbox(struct rproc *rproc) -{ - struct k3_dsp_rproc *kproc = rproc->priv; - struct mbox_client *client = &kproc->client; - struct device *dev = kproc->dev; - int ret; - - client->dev = dev; - client->tx_done = NULL; - client->rx_callback = k3_dsp_rproc_mbox_callback; - client->tx_block = false; - client->knows_txdone = false; - - kproc->mbox = mbox_request_channel(client, 0); - if (IS_ERR(kproc->mbox)) - return dev_err_probe(dev, PTR_ERR(kproc->mbox), - "mbox_request_channel failed\n"); - - /* - * Ping the remote processor, this is only for sanity-sake for now; - * there is no functional effect whatsoever. - * - * Note that the reply will _not_ arrive immediately: this message - * will wait in the mailbox fifo until the remote processor is booted. - */ - ret = mbox_send_message(kproc->mbox, (void *)RP_MBOX_ECHO_REQUEST); - if (ret < 0) { - dev_err(dev, "mbox_send_message failed (%pe)\n", ERR_PTR(ret)); - mbox_free_channel(kproc->mbox); - return ret; - } - - return 0; -} -/* - * The C66x DSP cores have a local reset that affects only the CPU, and a - * generic module reset that powers on the device and allows the DSP internal - * memories to be accessed while the local reset is asserted. This function is - * used to release the global reset on C66x DSPs to allow loading into the DSP - * internal RAMs. The .prepare() ops is invoked by remoteproc core before any - * firmware loading, and is followed by the .start() ops after loading to - * actually let the C66x DSP cores run. This callback is invoked only in - * remoteproc mode. - */ -static int k3_dsp_rproc_prepare(struct rproc *rproc) -{ - struct k3_dsp_rproc *kproc = rproc->priv; - struct device *dev = kproc->dev; - int ret; - - ret = kproc->ti_sci->ops.dev_ops.get_device(kproc->ti_sci, - kproc->ti_sci_id); - if (ret) - dev_err(dev, "module-reset deassert failed, cannot enable internal RAM loading (%pe)\n", - ERR_PTR(ret)); - - return ret; -} - -/* - * This function implements the .unprepare() ops and performs the complimentary - * operations to that of the .prepare() ops. The function is used to assert the - * global reset on applicable C66x cores. This completes the second portion of - * powering down the C66x DSP cores. The cores themselves are only halted in the - * .stop() callback through the local reset, and the .unprepare() ops is invoked - * by the remoteproc core after the remoteproc is stopped to balance the global - * reset. This callback is invoked only in remoteproc mode. - */ -static int k3_dsp_rproc_unprepare(struct rproc *rproc) -{ - struct k3_dsp_rproc *kproc = rproc->priv; - struct device *dev = kproc->dev; - int ret; - - ret = kproc->ti_sci->ops.dev_ops.put_device(kproc->ti_sci, - kproc->ti_sci_id); - if (ret) - dev_err(dev, "module-reset assert failed (%pe)\n", ERR_PTR(ret)); - - return ret; -} +#include "ti_k3_common.h" /* * Power up the DSP remote processor. @@ -307,7 +31,7 @@ static int k3_dsp_rproc_unprepare(struct rproc *rproc) */ static int k3_dsp_rproc_start(struct rproc *rproc) { - struct k3_dsp_rproc *kproc = rproc->priv; + struct k3_rproc *kproc = rproc->priv; struct device *dev = kproc->dev; u32 boot_addr; int ret; @@ -324,288 +48,30 @@ static int k3_dsp_rproc_start(struct rproc *rproc) if (ret) return ret; - ret = k3_dsp_rproc_release(kproc); + /* Call the K3 common start function after doing DSP specific stuff */ + ret = k3_rproc_start(rproc); if (ret) return ret; return 0; } -/* - * Stop the DSP remote processor. - * - * This function puts the DSP processor into reset, and finishes processing - * of any pending messages. This callback is invoked only in remoteproc mode. - */ -static int k3_dsp_rproc_stop(struct rproc *rproc) -{ - struct k3_dsp_rproc *kproc = rproc->priv; - - k3_dsp_rproc_reset(kproc); - - return 0; -} - -/* - * Attach to a running DSP remote processor (IPC-only mode) - * - * This rproc attach callback is a NOP. The remote processor is already booted, - * and all required resources have been acquired during probe routine, so there - * is no need to issue any TI-SCI commands to boot the DSP core. This callback - * is invoked only in IPC-only mode and exists because rproc_validate() checks - * for its existence. - */ -static int k3_dsp_rproc_attach(struct rproc *rproc) { return 0; } - -/* - * Detach from a running DSP remote processor (IPC-only mode) - * - * This rproc detach callback is a NOP. The DSP core is not stopped and will be - * left to continue to run its booted firmware. This callback is invoked only in - * IPC-only mode and exists for sanity sake. - */ -static int k3_dsp_rproc_detach(struct rproc *rproc) { return 0; } - -/* - * This function implements the .get_loaded_rsc_table() callback and is used - * to provide the resource table for a booted DSP in IPC-only mode. The K3 DSP - * firmwares follow a design-by-contract approach and are expected to have the - * resource table at the base of the DDR region reserved for firmware usage. - * This provides flexibility for the remote processor to be booted by different - * bootloaders that may or may not have the ability to publish the resource table - * address and size through a DT property. This callback is invoked only in - * IPC-only mode. - */ -static struct resource_table *k3_dsp_get_loaded_rsc_table(struct rproc *rproc, - size_t *rsc_table_sz) -{ - struct k3_dsp_rproc *kproc = rproc->priv; - struct device *dev = kproc->dev; - - if (!kproc->rmem[0].cpu_addr) { - dev_err(dev, "memory-region #1 does not exist, loaded rsc table can't be found"); - return ERR_PTR(-ENOMEM); - } - - /* - * NOTE: The resource table size is currently hard-coded to a maximum - * of 256 bytes. The most common resource table usage for K3 firmwares - * is to only have the vdev resource entry and an optional trace entry. - * The exact size could be computed based on resource table address, but - * the hard-coded value suffices to support the IPC-only mode. - */ - *rsc_table_sz = 256; - return (struct resource_table *)kproc->rmem[0].cpu_addr; -} - -/* - * Custom function to translate a DSP device address (internal RAMs only) to a - * kernel virtual address. The DSPs can access their RAMs at either an internal - * address visible only from a DSP, or at the SoC-level bus address. Both these - * addresses need to be looked through for translation. The translated addresses - * can be used either by the remoteproc core for loading (when using kernel - * remoteproc loader), or by any rpmsg bus drivers. - */ -static void *k3_dsp_rproc_da_to_va(struct rproc *rproc, u64 da, size_t len, bool *is_iomem) -{ - struct k3_dsp_rproc *kproc = rproc->priv; - void __iomem *va = NULL; - phys_addr_t bus_addr; - u32 dev_addr, offset; - size_t size; - int i; - - if (len == 0) - return NULL; - - for (i = 0; i < kproc->num_mems; i++) { - bus_addr = kproc->mem[i].bus_addr; - dev_addr = kproc->mem[i].dev_addr; - size = kproc->mem[i].size; - - if (da < KEYSTONE_RPROC_LOCAL_ADDRESS_MASK) { - /* handle DSP-view addresses */ - if (da >= dev_addr && - ((da + len) <= (dev_addr + size))) { - offset = da - dev_addr; - va = kproc->mem[i].cpu_addr + offset; - return (__force void *)va; - } - } else { - /* handle SoC-view addresses */ - if (da >= bus_addr && - (da + len) <= (bus_addr + size)) { - offset = da - bus_addr; - va = kproc->mem[i].cpu_addr + offset; - return (__force void *)va; - } - } - } - - /* handle static DDR reserved memory regions */ - for (i = 0; i < kproc->num_rmems; i++) { - dev_addr = kproc->rmem[i].dev_addr; - size = kproc->rmem[i].size; - - if (da >= dev_addr && ((da + len) <= (dev_addr + size))) { - offset = da - dev_addr; - va = kproc->rmem[i].cpu_addr + offset; - return (__force void *)va; - } - } - - return NULL; -} - static const struct rproc_ops k3_dsp_rproc_ops = { - .start = k3_dsp_rproc_start, - .stop = k3_dsp_rproc_stop, - .kick = k3_dsp_rproc_kick, - .da_to_va = k3_dsp_rproc_da_to_va, + .start = k3_dsp_rproc_start, + .stop = k3_rproc_stop, + .attach = k3_rproc_attach, + .detach = k3_rproc_detach, + .kick = k3_rproc_kick, + .da_to_va = k3_rproc_da_to_va, + .get_loaded_rsc_table = k3_get_loaded_rsc_table, }; -static int k3_dsp_rproc_of_get_memories(struct platform_device *pdev, - struct k3_dsp_rproc *kproc) -{ - const struct k3_dsp_dev_data *data = kproc->data; - struct device *dev = &pdev->dev; - struct resource *res; - int num_mems = 0; - int i; - - num_mems = kproc->data->num_mems; - kproc->mem = devm_kcalloc(kproc->dev, num_mems, - sizeof(*kproc->mem), GFP_KERNEL); - if (!kproc->mem) - return -ENOMEM; - - for (i = 0; i < num_mems; i++) { - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, - data->mems[i].name); - if (!res) { - dev_err(dev, "found no memory resource for %s\n", - data->mems[i].name); - return -EINVAL; - } - if (!devm_request_mem_region(dev, res->start, - resource_size(res), - dev_name(dev))) { - dev_err(dev, "could not request %s region for resource\n", - data->mems[i].name); - return -EBUSY; - } - - kproc->mem[i].cpu_addr = devm_ioremap_wc(dev, res->start, - resource_size(res)); - if (!kproc->mem[i].cpu_addr) { - dev_err(dev, "failed to map %s memory\n", - data->mems[i].name); - return -ENOMEM; - } - kproc->mem[i].bus_addr = res->start; - kproc->mem[i].dev_addr = data->mems[i].dev_addr; - kproc->mem[i].size = resource_size(res); - - dev_dbg(dev, "memory %8s: bus addr %pa size 0x%zx va %pK da 0x%x\n", - data->mems[i].name, &kproc->mem[i].bus_addr, - kproc->mem[i].size, kproc->mem[i].cpu_addr, - kproc->mem[i].dev_addr); - } - kproc->num_mems = num_mems; - - return 0; -} - -static void k3_dsp_mem_release(void *data) -{ - struct device *dev = data; - - of_reserved_mem_device_release(dev); -} - -static int k3_dsp_reserved_mem_init(struct k3_dsp_rproc *kproc) -{ - struct device *dev = kproc->dev; - struct device_node *np = dev->of_node; - struct device_node *rmem_np; - struct reserved_mem *rmem; - int num_rmems; - int ret, i; - - num_rmems = of_property_count_elems_of_size(np, "memory-region", - sizeof(phandle)); - if (num_rmems < 0) { - dev_err(dev, "device does not reserved memory regions (%pe)\n", - ERR_PTR(num_rmems)); - return -EINVAL; - } - if (num_rmems < 2) { - dev_err(dev, "device needs at least two memory regions to be defined, num = %d\n", - num_rmems); - return -EINVAL; - } - - /* use reserved memory region 0 for vring DMA allocations */ - ret = of_reserved_mem_device_init_by_idx(dev, np, 0); - if (ret) { - dev_err(dev, "device cannot initialize DMA pool (%pe)\n", - ERR_PTR(ret)); - return ret; - } - ret = devm_add_action_or_reset(dev, k3_dsp_mem_release, dev); - if (ret) - return ret; - - num_rmems--; - kproc->rmem = devm_kcalloc(dev, num_rmems, sizeof(*kproc->rmem), GFP_KERNEL); - if (!kproc->rmem) - return -ENOMEM; - - /* use remaining reserved memory regions for static carveouts */ - for (i = 0; i < num_rmems; i++) { - rmem_np = of_parse_phandle(np, "memory-region", i + 1); - if (!rmem_np) - return -EINVAL; - - rmem = of_reserved_mem_lookup(rmem_np); - of_node_put(rmem_np); - if (!rmem) - return -EINVAL; - - kproc->rmem[i].bus_addr = rmem->base; - /* 64-bit address regions currently not supported */ - kproc->rmem[i].dev_addr = (u32)rmem->base; - kproc->rmem[i].size = rmem->size; - kproc->rmem[i].cpu_addr = devm_ioremap_wc(dev, rmem->base, rmem->size); - if (!kproc->rmem[i].cpu_addr) { - dev_err(dev, "failed to map reserved memory#%d at %pa of size %pa\n", - i + 1, &rmem->base, &rmem->size); - return -ENOMEM; - } - - dev_dbg(dev, "reserved memory%d: bus addr %pa size 0x%zx va %pK da 0x%x\n", - i + 1, &kproc->rmem[i].bus_addr, - kproc->rmem[i].size, kproc->rmem[i].cpu_addr, - kproc->rmem[i].dev_addr); - } - kproc->num_rmems = num_rmems; - - return 0; -} - -static void k3_dsp_release_tsp(void *data) -{ - struct ti_sci_proc *tsp = data; - - ti_sci_proc_release(tsp); -} - static int k3_dsp_rproc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; - const struct k3_dsp_dev_data *data; - struct k3_dsp_rproc *kproc; + const struct k3_rproc_dev_data *data; + struct k3_rproc *kproc; struct rproc *rproc; const char *fw_name; bool p_state = false; @@ -627,15 +93,15 @@ static int k3_dsp_rproc_probe(struct platform_device *pdev) rproc->has_iommu = false; rproc->recovery_disabled = true; if (data->uses_lreset) { - rproc->ops->prepare = k3_dsp_rproc_prepare; - rproc->ops->unprepare = k3_dsp_rproc_unprepare; + rproc->ops->prepare = k3_rproc_prepare; + rproc->ops->unprepare = k3_rproc_unprepare; } kproc = rproc->priv; kproc->rproc = rproc; kproc->dev = dev; kproc->data = data; - ret = k3_dsp_rproc_request_mbox(rproc); + ret = k3_rproc_request_mbox(rproc); if (ret) return ret; @@ -663,15 +129,15 @@ static int k3_dsp_rproc_probe(struct platform_device *pdev) dev_err_probe(dev, ret, "ti_sci_proc_request failed\n"); return ret; } - ret = devm_add_action_or_reset(dev, k3_dsp_release_tsp, kproc->tsp); + ret = devm_add_action_or_reset(dev, k3_release_tsp, kproc->tsp); if (ret) return ret; - ret = k3_dsp_rproc_of_get_memories(pdev, kproc); + ret = k3_rproc_of_get_memories(pdev, kproc); if (ret) return ret; - ret = k3_dsp_reserved_mem_init(kproc); + ret = k3_reserved_mem_init(kproc); if (ret) return dev_err_probe(dev, ret, "reserved memory init failed\n"); @@ -684,30 +150,8 @@ static int k3_dsp_rproc_probe(struct platform_device *pdev) if (p_state) { dev_info(dev, "configured DSP for IPC-only mode\n"); rproc->state = RPROC_DETACHED; - /* override rproc ops with only required IPC-only mode ops */ - rproc->ops->prepare = NULL; - rproc->ops->unprepare = NULL; - rproc->ops->start = NULL; - rproc->ops->stop = NULL; - rproc->ops->attach = k3_dsp_rproc_attach; - rproc->ops->detach = k3_dsp_rproc_detach; - rproc->ops->get_loaded_rsc_table = k3_dsp_get_loaded_rsc_table; } else { dev_info(dev, "configured DSP for remoteproc mode\n"); - /* - * ensure the DSP local reset is asserted to ensure the DSP - * doesn't execute bogus code in .prepare() when the module - * reset is released. - */ - if (data->uses_lreset) { - ret = reset_control_status(kproc->reset); - if (ret < 0) { - return dev_err_probe(dev, ret, "failed to get reset status\n"); - } else if (ret == 0) { - dev_warn(dev, "local reset is deasserted for device\n"); - k3_dsp_rproc_reset(kproc); - } - } } ret = devm_rproc_add(dev, rproc); @@ -721,7 +165,7 @@ static int k3_dsp_rproc_probe(struct platform_device *pdev) static void k3_dsp_rproc_remove(struct platform_device *pdev) { - struct k3_dsp_rproc *kproc = platform_get_drvdata(pdev); + struct k3_rproc *kproc = platform_get_drvdata(pdev); struct rproc *rproc = kproc->rproc; struct device *dev = &pdev->dev; int ret; @@ -731,41 +175,39 @@ static void k3_dsp_rproc_remove(struct platform_device *pdev) if (ret) dev_err(dev, "failed to detach proc (%pe)\n", ERR_PTR(ret)); } - - mbox_free_channel(kproc->mbox); } -static const struct k3_dsp_mem_data c66_mems[] = { +static const struct k3_rproc_mem_data c66_mems[] = { { .name = "l2sram", .dev_addr = 0x800000 }, { .name = "l1pram", .dev_addr = 0xe00000 }, { .name = "l1dram", .dev_addr = 0xf00000 }, }; /* C71x cores only have a L1P Cache, there are no L1P SRAMs */ -static const struct k3_dsp_mem_data c71_mems[] = { +static const struct k3_rproc_mem_data c71_mems[] = { { .name = "l2sram", .dev_addr = 0x800000 }, { .name = "l1dram", .dev_addr = 0xe00000 }, }; -static const struct k3_dsp_mem_data c7xv_mems[] = { +static const struct k3_rproc_mem_data c7xv_mems[] = { { .name = "l2sram", .dev_addr = 0x800000 }, }; -static const struct k3_dsp_dev_data c66_data = { +static const struct k3_rproc_dev_data c66_data = { .mems = c66_mems, .num_mems = ARRAY_SIZE(c66_mems), .boot_align_addr = SZ_1K, .uses_lreset = true, }; -static const struct k3_dsp_dev_data c71_data = { +static const struct k3_rproc_dev_data c71_data = { .mems = c71_mems, .num_mems = ARRAY_SIZE(c71_mems), .boot_align_addr = SZ_2M, .uses_lreset = false, }; -static const struct k3_dsp_dev_data c7xv_data = { +static const struct k3_rproc_dev_data c7xv_data = { .mems = c7xv_mems, .num_mems = ARRAY_SIZE(c7xv_mems), .boot_align_addr = SZ_2M, @@ -783,7 +225,7 @@ MODULE_DEVICE_TABLE(of, k3_dsp_of_match); static struct platform_driver k3_dsp_rproc_driver = { .probe = k3_dsp_rproc_probe, - .remove_new = k3_dsp_rproc_remove, + .remove = k3_dsp_rproc_remove, .driver = { .name = "k3-dsp-rproc", .of_match_table = k3_dsp_of_match, diff --git a/drivers/remoteproc/ti_k3_m4_remoteproc.c b/drivers/remoteproc/ti_k3_m4_remoteproc.c index 6cd50b16a8e8..3a11fd24eb52 100644 --- a/drivers/remoteproc/ti_k3_m4_remoteproc.c +++ b/drivers/remoteproc/ti_k3_m4_remoteproc.c @@ -19,552 +19,35 @@ #include "omap_remoteproc.h" #include "remoteproc_internal.h" #include "ti_sci_proc.h" - -#define K3_M4_IRAM_DEV_ADDR 0x00000 -#define K3_M4_DRAM_DEV_ADDR 0x30000 - -/** - * struct k3_m4_rproc_mem - internal memory structure - * @cpu_addr: MPU virtual address of the memory region - * @bus_addr: Bus address used to access the memory region - * @dev_addr: Device address of the memory region from remote processor view - * @size: Size of the memory region - */ -struct k3_m4_rproc_mem { - void __iomem *cpu_addr; - phys_addr_t bus_addr; - u32 dev_addr; - size_t size; -}; - -/** - * struct k3_m4_rproc_mem_data - memory definitions for a remote processor - * @name: name for this memory entry - * @dev_addr: device address for the memory entry - */ -struct k3_m4_rproc_mem_data { - const char *name; - const u32 dev_addr; -}; - -/** - * struct k3_m4_rproc - k3 remote processor driver structure - * @dev: cached device pointer - * @mem: internal memory regions data - * @num_mems: number of internal memory regions - * @rmem: reserved memory regions data - * @num_rmems: number of reserved memory regions - * @reset: reset control handle - * @tsp: TI-SCI processor control handle - * @ti_sci: TI-SCI handle - * @ti_sci_id: TI-SCI device identifier - * @mbox: mailbox channel handle - * @client: mailbox client to request the mailbox channel - */ -struct k3_m4_rproc { - struct device *dev; - struct k3_m4_rproc_mem *mem; - int num_mems; - struct k3_m4_rproc_mem *rmem; - int num_rmems; - struct reset_control *reset; - struct ti_sci_proc *tsp; - const struct ti_sci_handle *ti_sci; - u32 ti_sci_id; - struct mbox_chan *mbox; - struct mbox_client client; -}; - -/** - * k3_m4_rproc_mbox_callback() - inbound mailbox message handler - * @client: mailbox client pointer used for requesting the mailbox channel - * @data: mailbox payload - * - * This handler is invoked by the K3 mailbox driver whenever a mailbox - * message is received. Usually, the mailbox payload simply contains - * the index of the virtqueue that is kicked by the remote processor, - * and we let remoteproc core handle it. - * - * In addition to virtqueue indices, we also have some out-of-band values - * that indicate different events. Those values are deliberately very - * large so they don't coincide with virtqueue indices. - */ -static void k3_m4_rproc_mbox_callback(struct mbox_client *client, void *data) -{ - struct device *dev = client->dev; - struct rproc *rproc = dev_get_drvdata(dev); - u32 msg = (u32)(uintptr_t)(data); - - dev_dbg(dev, "mbox msg: 0x%x\n", msg); - - switch (msg) { - case RP_MBOX_CRASH: - /* - * remoteproc detected an exception, but error recovery is not - * supported. So, just log this for now - */ - dev_err(dev, "K3 rproc %s crashed\n", rproc->name); - break; - case RP_MBOX_ECHO_REPLY: - dev_info(dev, "received echo reply from %s\n", rproc->name); - break; - default: - /* silently handle all other valid messages */ - if (msg >= RP_MBOX_READY && msg < RP_MBOX_END_MSG) - return; - if (msg > rproc->max_notifyid) { - dev_dbg(dev, "dropping unknown message 0x%x", msg); - return; - } - /* msg contains the index of the triggered vring */ - if (rproc_vq_interrupt(rproc, msg) == IRQ_NONE) - dev_dbg(dev, "no message was found in vqid %d\n", msg); - } -} - -/* - * Kick the remote processor to notify about pending unprocessed messages. - * The vqid usage is not used and is inconsequential, as the kick is performed - * through a simulated GPIO (a bit in an IPC interrupt-triggering register), - * the remote processor is expected to process both its Tx and Rx virtqueues. - */ -static void k3_m4_rproc_kick(struct rproc *rproc, int vqid) -{ - struct k3_m4_rproc *kproc = rproc->priv; - struct device *dev = kproc->dev; - u32 msg = (u32)vqid; - int ret; - - /* - * Send the index of the triggered virtqueue in the mailbox payload. - * NOTE: msg is cast to uintptr_t to prevent compiler warnings when - * void* is 64bit. It is safely cast back to u32 in the mailbox driver. - */ - ret = mbox_send_message(kproc->mbox, (void *)(uintptr_t)msg); - if (ret < 0) - dev_err(dev, "failed to send mailbox message, status = %d\n", - ret); -} - -static int k3_m4_rproc_ping_mbox(struct k3_m4_rproc *kproc) -{ - struct device *dev = kproc->dev; - int ret; - - /* - * Ping the remote processor, this is only for sanity-sake for now; - * there is no functional effect whatsoever. - * - * Note that the reply will _not_ arrive immediately: this message - * will wait in the mailbox fifo until the remote processor is booted. - */ - ret = mbox_send_message(kproc->mbox, (void *)RP_MBOX_ECHO_REQUEST); - if (ret < 0) { - dev_err(dev, "mbox_send_message failed: %d\n", ret); - return ret; - } - - return 0; -} - -/* - * The M4 cores have a local reset that affects only the CPU, and a - * generic module reset that powers on the device and allows the internal - * memories to be accessed while the local reset is asserted. This function is - * used to release the global reset on remote cores to allow loading into the - * internal RAMs. The .prepare() ops is invoked by remoteproc core before any - * firmware loading, and is followed by the .start() ops after loading to - * actually let the remote cores to run. - */ -static int k3_m4_rproc_prepare(struct rproc *rproc) -{ - struct k3_m4_rproc *kproc = rproc->priv; - struct device *dev = kproc->dev; - int ret; - - /* If the core is running already no need to deassert the module reset */ - if (rproc->state == RPROC_DETACHED) - return 0; - - /* - * Ensure the local reset is asserted so the core doesn't - * execute bogus code when the module reset is released. - */ - ret = reset_control_assert(kproc->reset); - if (ret) { - dev_err(dev, "could not assert local reset\n"); - return ret; - } - - ret = reset_control_status(kproc->reset); - if (ret <= 0) { - dev_err(dev, "local reset still not asserted\n"); - return ret; - } - - ret = kproc->ti_sci->ops.dev_ops.get_device(kproc->ti_sci, - kproc->ti_sci_id); - if (ret) { - dev_err(dev, "could not deassert module-reset for internal RAM loading\n"); - return ret; - } - - return 0; -} - -/* - * This function implements the .unprepare() ops and performs the complimentary - * operations to that of the .prepare() ops. The function is used to assert the - * global reset on applicable cores. This completes the second portion of - * powering down the remote core. The cores themselves are only halted in the - * .stop() callback through the local reset, and the .unprepare() ops is invoked - * by the remoteproc core after the remoteproc is stopped to balance the global - * reset. - */ -static int k3_m4_rproc_unprepare(struct rproc *rproc) -{ - struct k3_m4_rproc *kproc = rproc->priv; - struct device *dev = kproc->dev; - int ret; - - /* If the core is going to be detached do not assert the module reset */ - if (rproc->state == RPROC_DETACHED) - return 0; - - ret = kproc->ti_sci->ops.dev_ops.put_device(kproc->ti_sci, - kproc->ti_sci_id); - if (ret) { - dev_err(dev, "module-reset assert failed\n"); - return ret; - } - - return 0; -} - -/* - * This function implements the .get_loaded_rsc_table() callback and is used - * to provide the resource table for a booted remote processor in IPC-only - * mode. The remote processor firmwares follow a design-by-contract approach - * and are expected to have the resource table at the base of the DDR region - * reserved for firmware usage. This provides flexibility for the remote - * processor to be booted by different bootloaders that may or may not have the - * ability to publish the resource table address and size through a DT - * property. - */ -static struct resource_table *k3_m4_get_loaded_rsc_table(struct rproc *rproc, - size_t *rsc_table_sz) -{ - struct k3_m4_rproc *kproc = rproc->priv; - struct device *dev = kproc->dev; - - if (!kproc->rmem[0].cpu_addr) { - dev_err(dev, "memory-region #1 does not exist, loaded rsc table can't be found"); - return ERR_PTR(-ENOMEM); - } - - /* - * NOTE: The resource table size is currently hard-coded to a maximum - * of 256 bytes. The most common resource table usage for K3 firmwares - * is to only have the vdev resource entry and an optional trace entry. - * The exact size could be computed based on resource table address, but - * the hard-coded value suffices to support the IPC-only mode. - */ - *rsc_table_sz = 256; - return (__force struct resource_table *)kproc->rmem[0].cpu_addr; -} - -/* - * Custom function to translate a remote processor device address (internal - * RAMs only) to a kernel virtual address. The remote processors can access - * their RAMs at either an internal address visible only from a remote - * processor, or at the SoC-level bus address. Both these addresses need to be - * looked through for translation. The translated addresses can be used either - * by the remoteproc core for loading (when using kernel remoteproc loader), or - * by any rpmsg bus drivers. - */ -static void *k3_m4_rproc_da_to_va(struct rproc *rproc, u64 da, size_t len, bool *is_iomem) -{ - struct k3_m4_rproc *kproc = rproc->priv; - void __iomem *va = NULL; - phys_addr_t bus_addr; - u32 dev_addr, offset; - size_t size; - int i; - - if (len == 0) - return NULL; - - for (i = 0; i < kproc->num_mems; i++) { - bus_addr = kproc->mem[i].bus_addr; - dev_addr = kproc->mem[i].dev_addr; - size = kproc->mem[i].size; - - /* handle M4-view addresses */ - if (da >= dev_addr && ((da + len) <= (dev_addr + size))) { - offset = da - dev_addr; - va = kproc->mem[i].cpu_addr + offset; - return (__force void *)va; - } - - /* handle SoC-view addresses */ - if (da >= bus_addr && ((da + len) <= (bus_addr + size))) { - offset = da - bus_addr; - va = kproc->mem[i].cpu_addr + offset; - return (__force void *)va; - } - } - - /* handle static DDR reserved memory regions */ - for (i = 0; i < kproc->num_rmems; i++) { - dev_addr = kproc->rmem[i].dev_addr; - size = kproc->rmem[i].size; - - if (da >= dev_addr && ((da + len) <= (dev_addr + size))) { - offset = da - dev_addr; - va = kproc->rmem[i].cpu_addr + offset; - return (__force void *)va; - } - } - - return NULL; -} - -static int k3_m4_rproc_of_get_memories(struct platform_device *pdev, - struct k3_m4_rproc *kproc) -{ - static const char * const mem_names[] = { "iram", "dram" }; - static const u32 mem_addrs[] = { K3_M4_IRAM_DEV_ADDR, K3_M4_DRAM_DEV_ADDR }; - struct device *dev = &pdev->dev; - struct resource *res; - int num_mems; - int i; - - num_mems = ARRAY_SIZE(mem_names); - kproc->mem = devm_kcalloc(kproc->dev, num_mems, - sizeof(*kproc->mem), GFP_KERNEL); - if (!kproc->mem) - return -ENOMEM; - - for (i = 0; i < num_mems; i++) { - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, - mem_names[i]); - if (!res) { - dev_err(dev, "found no memory resource for %s\n", - mem_names[i]); - return -EINVAL; - } - if (!devm_request_mem_region(dev, res->start, - resource_size(res), - dev_name(dev))) { - dev_err(dev, "could not request %s region for resource\n", - mem_names[i]); - return -EBUSY; - } - - kproc->mem[i].cpu_addr = devm_ioremap_wc(dev, res->start, - resource_size(res)); - if (!kproc->mem[i].cpu_addr) { - dev_err(dev, "failed to map %s memory\n", - mem_names[i]); - return -ENOMEM; - } - kproc->mem[i].bus_addr = res->start; - kproc->mem[i].dev_addr = mem_addrs[i]; - kproc->mem[i].size = resource_size(res); - - dev_dbg(dev, "memory %8s: bus addr %pa size 0x%zx va %pK da 0x%x\n", - mem_names[i], &kproc->mem[i].bus_addr, - kproc->mem[i].size, kproc->mem[i].cpu_addr, - kproc->mem[i].dev_addr); - } - kproc->num_mems = num_mems; - - return 0; -} - -static void k3_m4_rproc_dev_mem_release(void *data) -{ - struct device *dev = data; - - of_reserved_mem_device_release(dev); -} - -static int k3_m4_reserved_mem_init(struct k3_m4_rproc *kproc) -{ - struct device *dev = kproc->dev; - struct device_node *np = dev->of_node; - struct device_node *rmem_np; - struct reserved_mem *rmem; - int num_rmems; - int ret, i; - - num_rmems = of_property_count_elems_of_size(np, "memory-region", - sizeof(phandle)); - if (num_rmems < 0) { - dev_err(dev, "device does not reserved memory regions (%d)\n", - num_rmems); - return -EINVAL; - } - if (num_rmems < 2) { - dev_err(dev, "device needs at least two memory regions to be defined, num = %d\n", - num_rmems); - return -EINVAL; - } - - /* use reserved memory region 0 for vring DMA allocations */ - ret = of_reserved_mem_device_init_by_idx(dev, np, 0); - if (ret) { - dev_err(dev, "device cannot initialize DMA pool (%d)\n", ret); - return ret; - } - ret = devm_add_action_or_reset(dev, k3_m4_rproc_dev_mem_release, dev); - if (ret) - return ret; - - num_rmems--; - kproc->rmem = devm_kcalloc(dev, num_rmems, sizeof(*kproc->rmem), GFP_KERNEL); - if (!kproc->rmem) - return -ENOMEM; - - /* use remaining reserved memory regions for static carveouts */ - for (i = 0; i < num_rmems; i++) { - rmem_np = of_parse_phandle(np, "memory-region", i + 1); - if (!rmem_np) - return -EINVAL; - - rmem = of_reserved_mem_lookup(rmem_np); - of_node_put(rmem_np); - if (!rmem) - return -EINVAL; - - kproc->rmem[i].bus_addr = rmem->base; - /* 64-bit address regions currently not supported */ - kproc->rmem[i].dev_addr = (u32)rmem->base; - kproc->rmem[i].size = rmem->size; - kproc->rmem[i].cpu_addr = devm_ioremap_wc(dev, rmem->base, rmem->size); - if (!kproc->rmem[i].cpu_addr) { - dev_err(dev, "failed to map reserved memory#%d at %pa of size %pa\n", - i + 1, &rmem->base, &rmem->size); - return -ENOMEM; - } - - dev_dbg(dev, "reserved memory%d: bus addr %pa size 0x%zx va %pK da 0x%x\n", - i + 1, &kproc->rmem[i].bus_addr, - kproc->rmem[i].size, kproc->rmem[i].cpu_addr, - kproc->rmem[i].dev_addr); - } - kproc->num_rmems = num_rmems; - - return 0; -} - -static void k3_m4_release_tsp(void *data) -{ - struct ti_sci_proc *tsp = data; - - ti_sci_proc_release(tsp); -} - -/* - * Power up the M4 remote processor. - * - * This function will be invoked only after the firmware for this rproc - * was loaded, parsed successfully, and all of its resource requirements - * were met. This callback is invoked only in remoteproc mode. - */ -static int k3_m4_rproc_start(struct rproc *rproc) -{ - struct k3_m4_rproc *kproc = rproc->priv; - struct device *dev = kproc->dev; - int ret; - - ret = k3_m4_rproc_ping_mbox(kproc); - if (ret) - return ret; - - ret = reset_control_deassert(kproc->reset); - if (ret) { - dev_err(dev, "local-reset deassert failed, ret = %d\n", ret); - return ret; - } - - return 0; -} - -/* - * Stop the M4 remote processor. - * - * This function puts the M4 processor into reset, and finishes processing - * of any pending messages. This callback is invoked only in remoteproc mode. - */ -static int k3_m4_rproc_stop(struct rproc *rproc) -{ - struct k3_m4_rproc *kproc = rproc->priv; - struct device *dev = kproc->dev; - int ret; - - ret = reset_control_assert(kproc->reset); - if (ret) { - dev_err(dev, "local-reset assert failed, ret = %d\n", ret); - return ret; - } - - return 0; -} - -/* - * Attach to a running M4 remote processor (IPC-only mode) - * - * The remote processor is already booted, so there is no need to issue any - * TI-SCI commands to boot the M4 core. This callback is used only in IPC-only - * mode. - */ -static int k3_m4_rproc_attach(struct rproc *rproc) -{ - struct k3_m4_rproc *kproc = rproc->priv; - int ret; - - ret = k3_m4_rproc_ping_mbox(kproc); - if (ret) - return ret; - - return 0; -} - -/* - * Detach from a running M4 remote processor (IPC-only mode) - * - * This rproc detach callback performs the opposite operation to attach - * callback, the M4 core is not stopped and will be left to continue to - * run its booted firmware. This callback is invoked only in IPC-only mode. - */ -static int k3_m4_rproc_detach(struct rproc *rproc) -{ - return 0; -} +#include "ti_k3_common.h" static const struct rproc_ops k3_m4_rproc_ops = { - .prepare = k3_m4_rproc_prepare, - .unprepare = k3_m4_rproc_unprepare, - .start = k3_m4_rproc_start, - .stop = k3_m4_rproc_stop, - .attach = k3_m4_rproc_attach, - .detach = k3_m4_rproc_detach, - .kick = k3_m4_rproc_kick, - .da_to_va = k3_m4_rproc_da_to_va, - .get_loaded_rsc_table = k3_m4_get_loaded_rsc_table, + .prepare = k3_rproc_prepare, + .unprepare = k3_rproc_unprepare, + .start = k3_rproc_start, + .stop = k3_rproc_stop, + .attach = k3_rproc_attach, + .detach = k3_rproc_detach, + .kick = k3_rproc_kick, + .da_to_va = k3_rproc_da_to_va, + .get_loaded_rsc_table = k3_get_loaded_rsc_table, }; static int k3_m4_rproc_probe(struct platform_device *pdev) { + const struct k3_rproc_dev_data *data; struct device *dev = &pdev->dev; - struct k3_m4_rproc *kproc; + struct k3_rproc *kproc; struct rproc *rproc; const char *fw_name; bool r_state = false; bool p_state = false; int ret; + data = of_device_get_match_data(dev); + if (!data) + return -ENODEV; + ret = rproc_of_parse_firmware(dev, 0, &fw_name); if (ret) return dev_err_probe(dev, ret, "failed to parse firmware-name property\n"); @@ -578,6 +61,8 @@ static int k3_m4_rproc_probe(struct platform_device *pdev) rproc->recovery_disabled = true; kproc = rproc->priv; kproc->dev = dev; + kproc->rproc = rproc; + kproc->data = data; platform_set_drvdata(pdev, rproc); kproc->ti_sci = devm_ti_sci_get_by_phandle(dev, "ti,sci"); @@ -601,15 +86,15 @@ static int k3_m4_rproc_probe(struct platform_device *pdev) ret = ti_sci_proc_request(kproc->tsp); if (ret < 0) return dev_err_probe(dev, ret, "ti_sci_proc_request failed\n"); - ret = devm_add_action_or_reset(dev, k3_m4_release_tsp, kproc->tsp); + ret = devm_add_action_or_reset(dev, k3_release_tsp, kproc->tsp); if (ret) return ret; - ret = k3_m4_rproc_of_get_memories(pdev, kproc); + ret = k3_rproc_of_get_memories(pdev, kproc); if (ret) return ret; - ret = k3_m4_reserved_mem_init(kproc); + ret = k3_reserved_mem_init(kproc); if (ret) return dev_err_probe(dev, ret, "reserved memory init failed\n"); @@ -627,15 +112,9 @@ static int k3_m4_rproc_probe(struct platform_device *pdev) dev_info(dev, "configured M4F for remoteproc mode\n"); } - kproc->client.dev = dev; - kproc->client.tx_done = NULL; - kproc->client.rx_callback = k3_m4_rproc_mbox_callback; - kproc->client.tx_block = false; - kproc->client.knows_txdone = false; - kproc->mbox = mbox_request_channel(&kproc->client, 0); - if (IS_ERR(kproc->mbox)) - return dev_err_probe(dev, PTR_ERR(kproc->mbox), - "mbox_request_channel failed\n"); + ret = k3_rproc_request_mbox(rproc); + if (ret) + return ret; ret = devm_rproc_add(dev, rproc); if (ret) @@ -645,8 +124,20 @@ static int k3_m4_rproc_probe(struct platform_device *pdev) return 0; } +static const struct k3_rproc_mem_data am64_m4_mems[] = { + { .name = "iram", .dev_addr = 0x0 }, + { .name = "dram", .dev_addr = 0x30000 }, +}; + +static const struct k3_rproc_dev_data am64_m4_data = { + .mems = am64_m4_mems, + .num_mems = ARRAY_SIZE(am64_m4_mems), + .boot_align_addr = SZ_1K, + .uses_lreset = true, +}; + static const struct of_device_id k3_m4_of_match[] = { - { .compatible = "ti,am64-m4fss", }, + { .compatible = "ti,am64-m4fss", .data = &am64_m4_data, }, { /* sentinel */ }, }; MODULE_DEVICE_TABLE(of, k3_m4_of_match); diff --git a/drivers/remoteproc/ti_k3_r5_remoteproc.c b/drivers/remoteproc/ti_k3_r5_remoteproc.c index 941bb130c85c..04f23295ffc1 100644 --- a/drivers/remoteproc/ti_k3_r5_remoteproc.c +++ b/drivers/remoteproc/ti_k3_r5_remoteproc.c @@ -26,6 +26,7 @@ #include "omap_remoteproc.h" #include "remoteproc_internal.h" #include "ti_sci_proc.h" +#include "ti_k3_common.h" /* This address can either be for ATCM or BTCM with the other at address 0x0 */ #define K3_R5_TCM_DEV_ADDR 0x41010000 @@ -55,20 +56,6 @@ /* Applicable to only AM64x SoCs */ #define PROC_BOOT_STATUS_FLAG_R5_SINGLECORE_ONLY 0x00000200 -/** - * struct k3_r5_mem - internal memory structure - * @cpu_addr: MPU virtual address of the memory region - * @bus_addr: Bus address used to access the memory region - * @dev_addr: Device address from remoteproc view - * @size: Size of the memory region - */ -struct k3_r5_mem { - void __iomem *cpu_addr; - phys_addr_t bus_addr; - u32 dev_addr; - size_t size; -}; - /* * All cluster mode values are not applicable on all SoCs. The following * are the modes supported on various SoCs: @@ -90,12 +77,14 @@ enum cluster_mode { * @tcm_ecc_autoinit: flag to denote the auto-initialization of TCMs for ECC * @single_cpu_mode: flag to denote if SoC/IP supports Single-CPU mode * @is_single_core: flag to denote if SoC/IP has only single core R5 + * @core_data: pointer to R5-core-specific device data */ struct k3_r5_soc_data { bool tcm_is_double; bool tcm_ecc_autoinit; bool single_cpu_mode; bool is_single_core; + const struct k3_rproc_dev_data *core_data; }; /** @@ -118,15 +107,10 @@ struct k3_r5_cluster { * struct k3_r5_core - K3 R5 core structure * @elem: linked list item * @dev: cached device pointer - * @rproc: rproc handle representing this core - * @mem: internal memory regions data + * @kproc: K3 rproc handle representing this core + * @cluster: cached pointer to parent cluster structure * @sram: on-chip SRAM memory regions data - * @num_mems: number of internal memory regions * @num_sram: number of on-chip SRAM memory regions - * @reset: reset control handle - * @tsp: TI-SCI processor control handle - * @ti_sci: TI-SCI handle - * @ti_sci_id: TI-SCI device identifier * @atcm_enable: flag to control ATCM enablement * @btcm_enable: flag to control BTCM enablement * @loczrama: flag to dictate which TCM is at device address 0x0 @@ -135,149 +119,58 @@ struct k3_r5_cluster { struct k3_r5_core { struct list_head elem; struct device *dev; - struct rproc *rproc; - struct k3_r5_mem *mem; - struct k3_r5_mem *sram; - int num_mems; + struct k3_rproc *kproc; + struct k3_r5_cluster *cluster; + struct k3_rproc_mem *sram; int num_sram; - struct reset_control *reset; - struct ti_sci_proc *tsp; - const struct ti_sci_handle *ti_sci; - u32 ti_sci_id; u32 atcm_enable; u32 btcm_enable; u32 loczrama; bool released_from_reset; }; -/** - * struct k3_r5_rproc - K3 remote processor state - * @dev: cached device pointer - * @cluster: cached pointer to parent cluster structure - * @mbox: mailbox channel handle - * @client: mailbox client to request the mailbox channel - * @rproc: rproc handle - * @core: cached pointer to r5 core structure being used - * @rmem: reserved memory regions data - * @num_rmems: number of reserved memory regions - */ -struct k3_r5_rproc { - struct device *dev; - struct k3_r5_cluster *cluster; - struct mbox_chan *mbox; - struct mbox_client client; - struct rproc *rproc; - struct k3_r5_core *core; - struct k3_r5_mem *rmem; - int num_rmems; -}; - -/** - * k3_r5_rproc_mbox_callback() - inbound mailbox message handler - * @client: mailbox client pointer used for requesting the mailbox channel - * @data: mailbox payload - * - * This handler is invoked by the OMAP mailbox driver whenever a mailbox - * message is received. Usually, the mailbox payload simply contains - * the index of the virtqueue that is kicked by the remote processor, - * and we let remoteproc core handle it. - * - * In addition to virtqueue indices, we also have some out-of-band values - * that indicate different events. Those values are deliberately very - * large so they don't coincide with virtqueue indices. - */ -static void k3_r5_rproc_mbox_callback(struct mbox_client *client, void *data) -{ - struct k3_r5_rproc *kproc = container_of(client, struct k3_r5_rproc, - client); - struct device *dev = kproc->rproc->dev.parent; - const char *name = kproc->rproc->name; - u32 msg = omap_mbox_message(data); - - dev_dbg(dev, "mbox msg: 0x%x\n", msg); - - switch (msg) { - case RP_MBOX_CRASH: - /* - * remoteproc detected an exception, but error recovery is not - * supported. So, just log this for now - */ - dev_err(dev, "K3 R5F rproc %s crashed\n", name); - break; - case RP_MBOX_ECHO_REPLY: - dev_info(dev, "received echo reply from %s\n", name); - break; - default: - /* silently handle all other valid messages */ - if (msg >= RP_MBOX_READY && msg < RP_MBOX_END_MSG) - return; - if (msg > kproc->rproc->max_notifyid) { - dev_dbg(dev, "dropping unknown message 0x%x", msg); - return; - } - /* msg contains the index of the triggered vring */ - if (rproc_vq_interrupt(kproc->rproc, msg) == IRQ_NONE) - dev_dbg(dev, "no message was found in vqid %d\n", msg); - } -} - -/* kick a virtqueue */ -static void k3_r5_rproc_kick(struct rproc *rproc, int vqid) -{ - struct k3_r5_rproc *kproc = rproc->priv; - struct device *dev = rproc->dev.parent; - mbox_msg_t msg = (mbox_msg_t)vqid; - int ret; - - /* send the index of the triggered virtqueue in the mailbox payload */ - ret = mbox_send_message(kproc->mbox, (void *)msg); - if (ret < 0) - dev_err(dev, "failed to send mailbox message, status = %d\n", - ret); -} - -static int k3_r5_split_reset(struct k3_r5_core *core) +static int k3_r5_split_reset(struct k3_rproc *kproc) { int ret; - ret = reset_control_assert(core->reset); + ret = reset_control_assert(kproc->reset); if (ret) { - dev_err(core->dev, "local-reset assert failed, ret = %d\n", + dev_err(kproc->dev, "local-reset assert failed, ret = %d\n", ret); return ret; } - ret = core->ti_sci->ops.dev_ops.put_device(core->ti_sci, - core->ti_sci_id); + ret = kproc->ti_sci->ops.dev_ops.put_device(kproc->ti_sci, + kproc->ti_sci_id); if (ret) { - dev_err(core->dev, "module-reset assert failed, ret = %d\n", + dev_err(kproc->dev, "module-reset assert failed, ret = %d\n", ret); - if (reset_control_deassert(core->reset)) - dev_warn(core->dev, "local-reset deassert back failed\n"); + if (reset_control_deassert(kproc->reset)) + dev_warn(kproc->dev, "local-reset deassert back failed\n"); } return ret; } -static int k3_r5_split_release(struct k3_r5_core *core) +static int k3_r5_split_release(struct k3_rproc *kproc) { int ret; - ret = core->ti_sci->ops.dev_ops.get_device(core->ti_sci, - core->ti_sci_id); + ret = kproc->ti_sci->ops.dev_ops.get_device(kproc->ti_sci, + kproc->ti_sci_id); if (ret) { - dev_err(core->dev, "module-reset deassert failed, ret = %d\n", + dev_err(kproc->dev, "module-reset deassert failed, ret = %d\n", ret); return ret; } - ret = reset_control_deassert(core->reset); + ret = reset_control_deassert(kproc->reset); if (ret) { - dev_err(core->dev, "local-reset deassert failed, ret = %d\n", + dev_err(kproc->dev, "local-reset deassert failed, ret = %d\n", ret); - if (core->ti_sci->ops.dev_ops.put_device(core->ti_sci, - core->ti_sci_id)) - dev_warn(core->dev, "module-reset assert back failed\n"); + if (kproc->ti_sci->ops.dev_ops.put_device(kproc->ti_sci, + kproc->ti_sci_id)) + dev_warn(kproc->dev, "module-reset assert back failed\n"); } return ret; @@ -286,11 +179,12 @@ static int k3_r5_split_release(struct k3_r5_core *core) static int k3_r5_lockstep_reset(struct k3_r5_cluster *cluster) { struct k3_r5_core *core; + struct k3_rproc *kproc; int ret; /* assert local reset on all applicable cores */ list_for_each_entry(core, &cluster->cores, elem) { - ret = reset_control_assert(core->reset); + ret = reset_control_assert(core->kproc->reset); if (ret) { dev_err(core->dev, "local-reset assert failed, ret = %d\n", ret); @@ -301,8 +195,9 @@ static int k3_r5_lockstep_reset(struct k3_r5_cluster *cluster) /* disable PSC modules on all applicable cores */ list_for_each_entry(core, &cluster->cores, elem) { - ret = core->ti_sci->ops.dev_ops.put_device(core->ti_sci, - core->ti_sci_id); + kproc = core->kproc; + ret = kproc->ti_sci->ops.dev_ops.put_device(kproc->ti_sci, + kproc->ti_sci_id); if (ret) { dev_err(core->dev, "module-reset assert failed, ret = %d\n", ret); @@ -314,14 +209,15 @@ static int k3_r5_lockstep_reset(struct k3_r5_cluster *cluster) unroll_module_reset: list_for_each_entry_continue_reverse(core, &cluster->cores, elem) { - if (core->ti_sci->ops.dev_ops.put_device(core->ti_sci, - core->ti_sci_id)) + kproc = core->kproc; + if (kproc->ti_sci->ops.dev_ops.put_device(kproc->ti_sci, + kproc->ti_sci_id)) dev_warn(core->dev, "module-reset assert back failed\n"); } core = list_last_entry(&cluster->cores, struct k3_r5_core, elem); unroll_local_reset: list_for_each_entry_from_reverse(core, &cluster->cores, elem) { - if (reset_control_deassert(core->reset)) + if (reset_control_deassert(core->kproc->reset)) dev_warn(core->dev, "local-reset deassert back failed\n"); } @@ -331,12 +227,14 @@ unroll_local_reset: static int k3_r5_lockstep_release(struct k3_r5_cluster *cluster) { struct k3_r5_core *core; + struct k3_rproc *kproc; int ret; /* enable PSC modules on all applicable cores */ list_for_each_entry_reverse(core, &cluster->cores, elem) { - ret = core->ti_sci->ops.dev_ops.get_device(core->ti_sci, - core->ti_sci_id); + kproc = core->kproc; + ret = kproc->ti_sci->ops.dev_ops.get_device(kproc->ti_sci, + kproc->ti_sci_id); if (ret) { dev_err(core->dev, "module-reset deassert failed, ret = %d\n", ret); @@ -347,7 +245,7 @@ static int k3_r5_lockstep_release(struct k3_r5_cluster *cluster) /* deassert local reset on all applicable cores */ list_for_each_entry_reverse(core, &cluster->cores, elem) { - ret = reset_control_deassert(core->reset); + ret = reset_control_deassert(core->kproc->reset); if (ret) { dev_err(core->dev, "module-reset deassert failed, ret = %d\n", ret); @@ -359,67 +257,33 @@ static int k3_r5_lockstep_release(struct k3_r5_cluster *cluster) unroll_local_reset: list_for_each_entry_continue(core, &cluster->cores, elem) { - if (reset_control_assert(core->reset)) + if (reset_control_assert(core->kproc->reset)) dev_warn(core->dev, "local-reset assert back failed\n"); } core = list_first_entry(&cluster->cores, struct k3_r5_core, elem); unroll_module_reset: list_for_each_entry_from(core, &cluster->cores, elem) { - if (core->ti_sci->ops.dev_ops.put_device(core->ti_sci, - core->ti_sci_id)) + kproc = core->kproc; + if (kproc->ti_sci->ops.dev_ops.put_device(kproc->ti_sci, + kproc->ti_sci_id)) dev_warn(core->dev, "module-reset assert back failed\n"); } return ret; } -static inline int k3_r5_core_halt(struct k3_r5_core *core) +static inline int k3_r5_core_halt(struct k3_rproc *kproc) { - return ti_sci_proc_set_control(core->tsp, + return ti_sci_proc_set_control(kproc->tsp, PROC_BOOT_CTRL_FLAG_R5_CORE_HALT, 0); } -static inline int k3_r5_core_run(struct k3_r5_core *core) +static inline int k3_r5_core_run(struct k3_rproc *kproc) { - return ti_sci_proc_set_control(core->tsp, + return ti_sci_proc_set_control(kproc->tsp, 0, PROC_BOOT_CTRL_FLAG_R5_CORE_HALT); } -static int k3_r5_rproc_request_mbox(struct rproc *rproc) -{ - struct k3_r5_rproc *kproc = rproc->priv; - struct mbox_client *client = &kproc->client; - struct device *dev = kproc->dev; - int ret; - - client->dev = dev; - client->tx_done = NULL; - client->rx_callback = k3_r5_rproc_mbox_callback; - client->tx_block = false; - client->knows_txdone = false; - - kproc->mbox = mbox_request_channel(client, 0); - if (IS_ERR(kproc->mbox)) - return dev_err_probe(dev, PTR_ERR(kproc->mbox), - "mbox_request_channel failed\n"); - - /* - * Ping the remote processor, this is only for sanity-sake for now; - * there is no functional effect whatsoever. - * - * Note that the reply will _not_ arrive immediately: this message - * will wait in the mailbox fifo until the remote processor is booted. - */ - ret = mbox_send_message(kproc->mbox, (void *)RP_MBOX_ECHO_REQUEST); - if (ret < 0) { - dev_err(dev, "mbox_send_message failed: %d\n", ret); - mbox_free_channel(kproc->mbox); - return ret; - } - - return 0; -} - /* * The R5F cores have controls for both a reset and a halt/run. The code * execution from DDR requires the initial boot-strapping code to be run @@ -438,9 +302,9 @@ static int k3_r5_rproc_request_mbox(struct rproc *rproc) */ static int k3_r5_rproc_prepare(struct rproc *rproc) { - struct k3_r5_rproc *kproc = rproc->priv; - struct k3_r5_cluster *cluster = kproc->cluster; - struct k3_r5_core *core = kproc->core, *core0, *core1; + struct k3_rproc *kproc = rproc->priv; + struct k3_r5_core *core = kproc->priv, *core0, *core1; + struct k3_r5_cluster *cluster = core->cluster; struct device *dev = kproc->dev; u32 ctrl = 0, cfg = 0, stat = 0; u64 boot_vec = 0; @@ -470,7 +334,7 @@ static int k3_r5_rproc_prepare(struct rproc *rproc) } } - ret = ti_sci_proc_get_status(core->tsp, &boot_vec, &cfg, &ctrl, &stat); + ret = ti_sci_proc_get_status(kproc->tsp, &boot_vec, &cfg, &ctrl, &stat); if (ret < 0) return ret; mem_init_dis = !!(cfg & PROC_BOOT_CFG_FLAG_R5_MEM_INIT_DIS); @@ -478,7 +342,7 @@ static int k3_r5_rproc_prepare(struct rproc *rproc) /* Re-use LockStep-mode reset logic for Single-CPU mode */ ret = (cluster->mode == CLUSTER_MODE_LOCKSTEP || cluster->mode == CLUSTER_MODE_SINGLECPU) ? - k3_r5_lockstep_release(cluster) : k3_r5_split_release(core); + k3_r5_lockstep_release(cluster) : k3_r5_split_release(kproc); if (ret) { dev_err(dev, "unable to enable cores for TCM loading, ret = %d\n", ret); @@ -510,10 +374,10 @@ static int k3_r5_rproc_prepare(struct rproc *rproc) * can be effective on all TCM addresses. */ dev_dbg(dev, "zeroing out ATCM memory\n"); - memset(core->mem[0].cpu_addr, 0x00, core->mem[0].size); + memset_io(kproc->mem[0].cpu_addr, 0x00, kproc->mem[0].size); dev_dbg(dev, "zeroing out BTCM memory\n"); - memset(core->mem[1].cpu_addr, 0x00, core->mem[1].size); + memset_io(kproc->mem[1].cpu_addr, 0x00, kproc->mem[1].size); return 0; } @@ -536,9 +400,9 @@ static int k3_r5_rproc_prepare(struct rproc *rproc) */ static int k3_r5_rproc_unprepare(struct rproc *rproc) { - struct k3_r5_rproc *kproc = rproc->priv; - struct k3_r5_cluster *cluster = kproc->cluster; - struct k3_r5_core *core = kproc->core, *core0, *core1; + struct k3_rproc *kproc = rproc->priv; + struct k3_r5_core *core = kproc->priv, *core0, *core1; + struct k3_r5_cluster *cluster = core->cluster; struct device *dev = kproc->dev; int ret; @@ -565,7 +429,7 @@ static int k3_r5_rproc_unprepare(struct rproc *rproc) /* Re-use LockStep-mode reset logic for Single-CPU mode */ ret = (cluster->mode == CLUSTER_MODE_LOCKSTEP || cluster->mode == CLUSTER_MODE_SINGLECPU) ? - k3_r5_lockstep_reset(cluster) : k3_r5_split_reset(core); + k3_r5_lockstep_reset(cluster) : k3_r5_split_reset(kproc); if (ret) dev_err(dev, "unable to disable cores, ret = %d\n", ret); @@ -599,10 +463,10 @@ static int k3_r5_rproc_unprepare(struct rproc *rproc) */ static int k3_r5_rproc_start(struct rproc *rproc) { - struct k3_r5_rproc *kproc = rproc->priv; - struct k3_r5_cluster *cluster = kproc->cluster; + struct k3_rproc *kproc = rproc->priv; + struct k3_r5_core *core = kproc->priv; + struct k3_r5_cluster *cluster = core->cluster; struct device *dev = kproc->dev; - struct k3_r5_core *core; u32 boot_addr; int ret; @@ -611,20 +475,19 @@ static int k3_r5_rproc_start(struct rproc *rproc) dev_dbg(dev, "booting R5F core using boot addr = 0x%x\n", boot_addr); /* boot vector need not be programmed for Core1 in LockStep mode */ - core = kproc->core; - ret = ti_sci_proc_set_config(core->tsp, boot_addr, 0, 0); + ret = ti_sci_proc_set_config(kproc->tsp, boot_addr, 0, 0); if (ret) return ret; /* unhalt/run all applicable cores */ if (cluster->mode == CLUSTER_MODE_LOCKSTEP) { list_for_each_entry_reverse(core, &cluster->cores, elem) { - ret = k3_r5_core_run(core); + ret = k3_r5_core_run(core->kproc); if (ret) goto unroll_core_run; } } else { - ret = k3_r5_core_run(core); + ret = k3_r5_core_run(core->kproc); if (ret) return ret; } @@ -633,7 +496,7 @@ static int k3_r5_rproc_start(struct rproc *rproc) unroll_core_run: list_for_each_entry_continue(core, &cluster->cores, elem) { - if (k3_r5_core_halt(core)) + if (k3_r5_core_halt(core->kproc)) dev_warn(core->dev, "core halt back failed\n"); } return ret; @@ -665,22 +528,22 @@ unroll_core_run: */ static int k3_r5_rproc_stop(struct rproc *rproc) { - struct k3_r5_rproc *kproc = rproc->priv; - struct k3_r5_cluster *cluster = kproc->cluster; - struct k3_r5_core *core = kproc->core; + struct k3_rproc *kproc = rproc->priv; + struct k3_r5_core *core = kproc->priv; + struct k3_r5_cluster *cluster = core->cluster; int ret; /* halt all applicable cores */ if (cluster->mode == CLUSTER_MODE_LOCKSTEP) { list_for_each_entry(core, &cluster->cores, elem) { - ret = k3_r5_core_halt(core); + ret = k3_r5_core_halt(core->kproc); if (ret) { core = list_prev_entry(core, elem); goto unroll_core_halt; } } } else { - ret = k3_r5_core_halt(core); + ret = k3_r5_core_halt(core->kproc); if (ret) goto out; } @@ -689,7 +552,7 @@ static int k3_r5_rproc_stop(struct rproc *rproc) unroll_core_halt: list_for_each_entry_from_reverse(core, &cluster->cores, elem) { - if (k3_r5_core_run(core)) + if (k3_r5_core_run(core->kproc)) dev_warn(core->dev, "core run back failed\n"); } out: @@ -697,58 +560,6 @@ out: } /* - * Attach to a running R5F remote processor (IPC-only mode) - * - * The R5F attach callback is a NOP. The remote processor is already booted, and - * all required resources have been acquired during probe routine, so there is - * no need to issue any TI-SCI commands to boot the R5F cores in IPC-only mode. - * This callback is invoked only in IPC-only mode and exists because - * rproc_validate() checks for its existence. - */ -static int k3_r5_rproc_attach(struct rproc *rproc) { return 0; } - -/* - * Detach from a running R5F remote processor (IPC-only mode) - * - * The R5F detach callback is a NOP. The R5F cores are not stopped and will be - * left in booted state in IPC-only mode. This callback is invoked only in - * IPC-only mode and exists for sanity sake. - */ -static int k3_r5_rproc_detach(struct rproc *rproc) { return 0; } - -/* - * This function implements the .get_loaded_rsc_table() callback and is used - * to provide the resource table for the booted R5F in IPC-only mode. The K3 R5F - * firmwares follow a design-by-contract approach and are expected to have the - * resource table at the base of the DDR region reserved for firmware usage. - * This provides flexibility for the remote processor to be booted by different - * bootloaders that may or may not have the ability to publish the resource table - * address and size through a DT property. This callback is invoked only in - * IPC-only mode. - */ -static struct resource_table *k3_r5_get_loaded_rsc_table(struct rproc *rproc, - size_t *rsc_table_sz) -{ - struct k3_r5_rproc *kproc = rproc->priv; - struct device *dev = kproc->dev; - - if (!kproc->rmem[0].cpu_addr) { - dev_err(dev, "memory-region #1 does not exist, loaded rsc table can't be found"); - return ERR_PTR(-ENOMEM); - } - - /* - * NOTE: The resource table size is currently hard-coded to a maximum - * of 256 bytes. The most common resource table usage for K3 firmwares - * is to only have the vdev resource entry and an optional trace entry. - * The exact size could be computed based on resource table address, but - * the hard-coded value suffices to support the IPC-only mode. - */ - *rsc_table_sz = 256; - return (struct resource_table *)kproc->rmem[0].cpu_addr; -} - -/* * Internal Memory translation helper * * Custom function implementing the rproc .da_to_va ops to provide address @@ -758,10 +569,9 @@ static struct resource_table *k3_r5_get_loaded_rsc_table(struct rproc *rproc, */ static void *k3_r5_rproc_da_to_va(struct rproc *rproc, u64 da, size_t len, bool *is_iomem) { - struct k3_r5_rproc *kproc = rproc->priv; - struct k3_r5_core *core = kproc->core; + struct k3_rproc *kproc = rproc->priv; + struct k3_r5_core *core = kproc->priv; void __iomem *va = NULL; - phys_addr_t bus_addr; u32 dev_addr, offset; size_t size; int i; @@ -769,27 +579,6 @@ static void *k3_r5_rproc_da_to_va(struct rproc *rproc, u64 da, size_t len, bool if (len == 0) return NULL; - /* handle both R5 and SoC views of ATCM and BTCM */ - for (i = 0; i < core->num_mems; i++) { - bus_addr = core->mem[i].bus_addr; - dev_addr = core->mem[i].dev_addr; - size = core->mem[i].size; - - /* handle R5-view addresses of TCMs */ - if (da >= dev_addr && ((da + len) <= (dev_addr + size))) { - offset = da - dev_addr; - va = core->mem[i].cpu_addr + offset; - return (__force void *)va; - } - - /* handle SoC-view addresses of TCMs */ - if (da >= bus_addr && ((da + len) <= (bus_addr + size))) { - offset = da - bus_addr; - va = core->mem[i].cpu_addr + offset; - return (__force void *)va; - } - } - /* handle any SRAM regions using SoC-view addresses */ for (i = 0; i < core->num_sram; i++) { dev_addr = core->sram[i].dev_addr; @@ -802,19 +591,8 @@ static void *k3_r5_rproc_da_to_va(struct rproc *rproc, u64 da, size_t len, bool } } - /* handle static DDR reserved memory regions */ - for (i = 0; i < kproc->num_rmems; i++) { - dev_addr = kproc->rmem[i].dev_addr; - size = kproc->rmem[i].size; - - if (da >= dev_addr && ((da + len) <= (dev_addr + size))) { - offset = da - dev_addr; - va = kproc->rmem[i].cpu_addr + offset; - return (__force void *)va; - } - } - - return NULL; + /* handle both TCM and DDR memory regions */ + return k3_rproc_da_to_va(rproc, da, len, is_iomem); } static const struct rproc_ops k3_r5_rproc_ops = { @@ -822,7 +600,7 @@ static const struct rproc_ops k3_r5_rproc_ops = { .unprepare = k3_r5_rproc_unprepare, .start = k3_r5_rproc_start, .stop = k3_r5_rproc_stop, - .kick = k3_r5_rproc_kick, + .kick = k3_rproc_kick, .da_to_va = k3_r5_rproc_da_to_va, }; @@ -861,11 +639,11 @@ static const struct rproc_ops k3_r5_rproc_ops = { * both the cores with the same settings, before reconfiguing again for * LockStep mode. */ -static int k3_r5_rproc_configure(struct k3_r5_rproc *kproc) +static int k3_r5_rproc_configure(struct k3_rproc *kproc) { - struct k3_r5_cluster *cluster = kproc->cluster; + struct k3_r5_core *temp, *core0, *core = kproc->priv; + struct k3_r5_cluster *cluster = core->cluster; struct device *dev = kproc->dev; - struct k3_r5_core *core0, *core, *temp; u32 ctrl = 0, cfg = 0, stat = 0; u32 set_cfg = 0, clr_cfg = 0; u64 boot_vec = 0; @@ -879,10 +657,10 @@ static int k3_r5_rproc_configure(struct k3_r5_rproc *kproc) cluster->mode == CLUSTER_MODE_SINGLECORE) { core = core0; } else { - core = kproc->core; + core = kproc->priv; } - ret = ti_sci_proc_get_status(core->tsp, &boot_vec, &cfg, &ctrl, + ret = ti_sci_proc_get_status(core->kproc->tsp, &boot_vec, &cfg, &ctrl, &stat); if (ret < 0) return ret; @@ -952,7 +730,7 @@ static int k3_r5_rproc_configure(struct k3_r5_rproc *kproc) * and TEINIT config is only allowed with Core0. */ list_for_each_entry(temp, &cluster->cores, elem) { - ret = k3_r5_core_halt(temp); + ret = k3_r5_core_halt(temp->kproc); if (ret) goto out; @@ -960,7 +738,7 @@ static int k3_r5_rproc_configure(struct k3_r5_rproc *kproc) clr_cfg &= ~PROC_BOOT_CFG_FLAG_R5_LOCKSTEP; clr_cfg &= ~PROC_BOOT_CFG_FLAG_R5_TEINIT; } - ret = ti_sci_proc_set_config(temp->tsp, boot_vec, + ret = ti_sci_proc_set_config(temp->kproc->tsp, boot_vec, set_cfg, clr_cfg); if (ret) goto out; @@ -968,14 +746,14 @@ static int k3_r5_rproc_configure(struct k3_r5_rproc *kproc) set_cfg = PROC_BOOT_CFG_FLAG_R5_LOCKSTEP; clr_cfg = 0; - ret = ti_sci_proc_set_config(core->tsp, boot_vec, + ret = ti_sci_proc_set_config(core->kproc->tsp, boot_vec, set_cfg, clr_cfg); } else { - ret = k3_r5_core_halt(core); + ret = k3_r5_core_halt(core->kproc); if (ret) goto out; - ret = ti_sci_proc_set_config(core->tsp, boot_vec, + ret = ti_sci_proc_set_config(core->kproc->tsp, boot_vec, set_cfg, clr_cfg); } @@ -983,93 +761,6 @@ out: return ret; } -static void k3_r5_mem_release(void *data) -{ - struct device *dev = data; - - of_reserved_mem_device_release(dev); -} - -static int k3_r5_reserved_mem_init(struct k3_r5_rproc *kproc) -{ - struct device *dev = kproc->dev; - struct device_node *np = dev_of_node(dev); - struct device_node *rmem_np; - struct reserved_mem *rmem; - int num_rmems; - int ret, i; - - num_rmems = of_property_count_elems_of_size(np, "memory-region", - sizeof(phandle)); - if (num_rmems <= 0) { - dev_err(dev, "device does not have reserved memory regions, ret = %d\n", - num_rmems); - return -EINVAL; - } - if (num_rmems < 2) { - dev_err(dev, "device needs at least two memory regions to be defined, num = %d\n", - num_rmems); - return -EINVAL; - } - - /* use reserved memory region 0 for vring DMA allocations */ - ret = of_reserved_mem_device_init_by_idx(dev, np, 0); - if (ret) { - dev_err(dev, "device cannot initialize DMA pool, ret = %d\n", - ret); - return ret; - } - - ret = devm_add_action_or_reset(dev, k3_r5_mem_release, dev); - if (ret) - return ret; - - num_rmems--; - kproc->rmem = devm_kcalloc(dev, num_rmems, sizeof(*kproc->rmem), GFP_KERNEL); - if (!kproc->rmem) - return -ENOMEM; - - /* use remaining reserved memory regions for static carveouts */ - for (i = 0; i < num_rmems; i++) { - rmem_np = of_parse_phandle(np, "memory-region", i + 1); - if (!rmem_np) - return -EINVAL; - - rmem = of_reserved_mem_lookup(rmem_np); - of_node_put(rmem_np); - if (!rmem) - return -EINVAL; - - kproc->rmem[i].bus_addr = rmem->base; - /* - * R5Fs do not have an MMU, but have a Region Address Translator - * (RAT) module that provides a fixed entry translation between - * the 32-bit processor addresses to 64-bit bus addresses. The - * RAT is programmable only by the R5F cores. Support for RAT - * is currently not supported, so 64-bit address regions are not - * supported. The absence of MMUs implies that the R5F device - * addresses/supported memory regions are restricted to 32-bit - * bus addresses, and are identical - */ - kproc->rmem[i].dev_addr = (u32)rmem->base; - kproc->rmem[i].size = rmem->size; - kproc->rmem[i].cpu_addr = devm_ioremap_wc(dev, rmem->base, rmem->size); - if (!kproc->rmem[i].cpu_addr) { - dev_err(dev, "failed to map reserved memory#%d at %pa of size %pa\n", - i + 1, &rmem->base, &rmem->size); - return -ENOMEM; - } - - dev_dbg(dev, "reserved memory%d: bus addr %pa size 0x%zx va %pK da 0x%x\n", - i + 1, &kproc->rmem[i].bus_addr, - kproc->rmem[i].size, kproc->rmem[i].cpu_addr, - kproc->rmem[i].dev_addr); - } - kproc->num_rmems = num_rmems; - - return 0; -} - /* * Each R5F core within a typical R5FSS instance has a total of 64 KB of TCMs, * split equally into two 32 KB banks between ATCM and BTCM. The TCMs from both @@ -1083,12 +774,11 @@ static int k3_r5_reserved_mem_init(struct k3_r5_rproc *kproc) * supported SoCs. The Core0 TCM sizes therefore have to be adjusted to only * half the original size in Split mode. */ -static void k3_r5_adjust_tcm_sizes(struct k3_r5_rproc *kproc) +static void k3_r5_adjust_tcm_sizes(struct k3_rproc *kproc) { - struct k3_r5_cluster *cluster = kproc->cluster; - struct k3_r5_core *core = kproc->core; + struct k3_r5_core *core0, *core = kproc->priv; + struct k3_r5_cluster *cluster = core->cluster; struct device *cdev = core->dev; - struct k3_r5_core *core0; if (cluster->mode == CLUSTER_MODE_LOCKSTEP || cluster->mode == CLUSTER_MODE_SINGLECPU || @@ -1098,14 +788,14 @@ static void k3_r5_adjust_tcm_sizes(struct k3_r5_rproc *kproc) core0 = list_first_entry(&cluster->cores, struct k3_r5_core, elem); if (core == core0) { - WARN_ON(core->mem[0].size != SZ_64K); - WARN_ON(core->mem[1].size != SZ_64K); + WARN_ON(kproc->mem[0].size != SZ_64K); + WARN_ON(kproc->mem[1].size != SZ_64K); - core->mem[0].size /= 2; - core->mem[1].size /= 2; + kproc->mem[0].size /= 2; + kproc->mem[1].size /= 2; dev_dbg(cdev, "adjusted TCM sizes, ATCM = 0x%zx BTCM = 0x%zx\n", - core->mem[0].size, core->mem[1].size); + kproc->mem[0].size, kproc->mem[1].size); } } @@ -1122,24 +812,23 @@ static void k3_r5_adjust_tcm_sizes(struct k3_r5_rproc *kproc) * actual values configured by bootloader. The driver internal device memory * addresses for TCMs are also updated. */ -static int k3_r5_rproc_configure_mode(struct k3_r5_rproc *kproc) +static int k3_r5_rproc_configure_mode(struct k3_rproc *kproc) { - struct k3_r5_cluster *cluster = kproc->cluster; - struct k3_r5_core *core = kproc->core; + struct k3_r5_core *core0, *core = kproc->priv; + struct k3_r5_cluster *cluster = core->cluster; struct device *cdev = core->dev; bool r_state = false, c_state = false, lockstep_en = false, single_cpu = false; u32 ctrl = 0, cfg = 0, stat = 0, halted = 0; u64 boot_vec = 0; u32 atcm_enable, btcm_enable, loczrama; - struct k3_r5_core *core0; enum cluster_mode mode = cluster->mode; int reset_ctrl_status; int ret; core0 = list_first_entry(&cluster->cores, struct k3_r5_core, elem); - ret = core->ti_sci->ops.dev_ops.is_on(core->ti_sci, core->ti_sci_id, - &r_state, &c_state); + ret = kproc->ti_sci->ops.dev_ops.is_on(kproc->ti_sci, kproc->ti_sci_id, + &r_state, &c_state); if (ret) { dev_err(cdev, "failed to get initial state, mode cannot be determined, ret = %d\n", ret); @@ -1150,7 +839,7 @@ static int k3_r5_rproc_configure_mode(struct k3_r5_rproc *kproc) r_state, c_state); } - reset_ctrl_status = reset_control_status(core->reset); + reset_ctrl_status = reset_control_status(kproc->reset); if (reset_ctrl_status < 0) { dev_err(cdev, "failed to get initial local reset status, ret = %d\n", reset_ctrl_status); @@ -1163,7 +852,7 @@ static int k3_r5_rproc_configure_mode(struct k3_r5_rproc *kproc) */ core->released_from_reset = c_state; - ret = ti_sci_proc_get_status(core->tsp, &boot_vec, &cfg, &ctrl, + ret = ti_sci_proc_get_status(kproc->tsp, &boot_vec, &cfg, &ctrl, &stat); if (ret < 0) { dev_err(cdev, "failed to get initial processor status, ret = %d\n", @@ -1198,10 +887,10 @@ static int k3_r5_rproc_configure_mode(struct k3_r5_rproc *kproc) kproc->rproc->ops->unprepare = NULL; kproc->rproc->ops->start = NULL; kproc->rproc->ops->stop = NULL; - kproc->rproc->ops->attach = k3_r5_rproc_attach; - kproc->rproc->ops->detach = k3_r5_rproc_detach; + kproc->rproc->ops->attach = k3_rproc_attach; + kproc->rproc->ops->detach = k3_rproc_detach; kproc->rproc->ops->get_loaded_rsc_table = - k3_r5_get_loaded_rsc_table; + k3_get_loaded_rsc_table; } else if (!c_state) { dev_info(cdev, "configured R5F for remoteproc mode\n"); ret = 0; @@ -1220,19 +909,121 @@ static int k3_r5_rproc_configure_mode(struct k3_r5_rproc *kproc) core->atcm_enable = atcm_enable; core->btcm_enable = btcm_enable; core->loczrama = loczrama; - core->mem[0].dev_addr = loczrama ? 0 : K3_R5_TCM_DEV_ADDR; - core->mem[1].dev_addr = loczrama ? K3_R5_TCM_DEV_ADDR : 0; + kproc->mem[0].dev_addr = loczrama ? 0 : K3_R5_TCM_DEV_ADDR; + kproc->mem[1].dev_addr = loczrama ? K3_R5_TCM_DEV_ADDR : 0; } return ret; } +static int k3_r5_core_of_get_internal_memories(struct platform_device *pdev, + struct k3_rproc *kproc) +{ + const struct k3_rproc_dev_data *data = kproc->data; + struct device *dev = &pdev->dev; + struct k3_r5_core *core = kproc->priv; + int num_mems; + int i, ret; + + num_mems = data->num_mems; + kproc->mem = devm_kcalloc(kproc->dev, num_mems, sizeof(*kproc->mem), + GFP_KERNEL); + if (!kproc->mem) + return -ENOMEM; + + ret = k3_rproc_of_get_memories(pdev, kproc); + if (ret) + return ret; + + for (i = 0; i < num_mems; i++) { + /* + * TODO: + * The R5F cores can place ATCM & BTCM anywhere in its address + * based on the corresponding Region Registers in the System + * Control coprocessor. For now, place ATCM and BTCM at + * addresses 0 and 0x41010000 (same as the bus address on AM65x + * SoCs) based on loczrama setting overriding default assignment + * done by k3_rproc_of_get_memories(). + */ + if (!strcmp(data->mems[i].name, "atcm")) { + kproc->mem[i].dev_addr = core->loczrama ? + 0 : K3_R5_TCM_DEV_ADDR; + } else { + kproc->mem[i].dev_addr = core->loczrama ? + K3_R5_TCM_DEV_ADDR : 0; + } + + dev_dbg(dev, "Updating bus addr %pa of memory %5s\n", + &kproc->mem[i].bus_addr, data->mems[i].name); + } + + return 0; +} + +static int k3_r5_core_of_get_sram_memories(struct platform_device *pdev, + struct k3_r5_core *core) +{ + struct device_node *np = pdev->dev.of_node; + struct device *dev = &pdev->dev; + struct device_node *sram_np; + struct resource res; + int num_sram; + int i, ret; + + num_sram = of_property_count_elems_of_size(np, "sram", sizeof(phandle)); + if (num_sram <= 0) { + dev_dbg(dev, "device does not use reserved on-chip memories, num_sram = %d\n", + num_sram); + return 0; + } + + core->sram = devm_kcalloc(dev, num_sram, sizeof(*core->sram), GFP_KERNEL); + if (!core->sram) + return -ENOMEM; + + for (i = 0; i < num_sram; i++) { + sram_np = of_parse_phandle(np, "sram", i); + if (!sram_np) + return -EINVAL; + + if (!of_device_is_available(sram_np)) { + of_node_put(sram_np); + return -EINVAL; + } + + ret = of_address_to_resource(sram_np, 0, &res); + of_node_put(sram_np); + if (ret) + return -EINVAL; + + core->sram[i].bus_addr = res.start; + core->sram[i].dev_addr = res.start; + core->sram[i].size = resource_size(&res); + core->sram[i].cpu_addr = devm_ioremap_wc(dev, res.start, + resource_size(&res)); + if (!core->sram[i].cpu_addr) { + dev_err(dev, "failed to parse and map sram%d memory at %pad\n", + i, &res.start); + return -ENOMEM; + } + + dev_dbg(dev, "memory sram%d: bus addr %pa size 0x%zx va %p da 0x%x\n", + i, &core->sram[i].bus_addr, + core->sram[i].size, core->sram[i].cpu_addr, + core->sram[i].dev_addr); + } + core->num_sram = num_sram; + + return 0; +} + static int k3_r5_cluster_rproc_init(struct platform_device *pdev) { struct k3_r5_cluster *cluster = platform_get_drvdata(pdev); struct device *dev = &pdev->dev; - struct k3_r5_rproc *kproc; + struct k3_rproc *kproc; struct k3_r5_core *core, *core1; + struct device_node *np; struct device *cdev; const char *fw_name; struct rproc *rproc; @@ -1241,6 +1032,7 @@ static int k3_r5_cluster_rproc_init(struct platform_device *pdev) core1 = list_last_entry(&cluster->cores, struct k3_r5_core, elem); list_for_each_entry(core, &cluster->cores, elem) { cdev = core->dev; + np = dev_of_node(cdev); ret = rproc_of_parse_firmware(cdev, 0, &fw_name); if (ret) { dev_err(dev, "failed to parse firmware-name property, ret = %d\n", @@ -1261,13 +1053,66 @@ static int k3_r5_cluster_rproc_init(struct platform_device *pdev) rproc->recovery_disabled = true; kproc = rproc->priv; - kproc->cluster = cluster; - kproc->core = core; + kproc->priv = core; kproc->dev = cdev; kproc->rproc = rproc; - core->rproc = rproc; + kproc->data = cluster->soc_data->core_data; + core->kproc = kproc; + + kproc->ti_sci = devm_ti_sci_get_by_phandle(cdev, "ti,sci"); + if (IS_ERR(kproc->ti_sci)) { + ret = dev_err_probe(cdev, PTR_ERR(kproc->ti_sci), + "failed to get ti-sci handle\n"); + kproc->ti_sci = NULL; + goto out; + } - ret = k3_r5_rproc_request_mbox(rproc); + ret = of_property_read_u32(np, "ti,sci-dev-id", &kproc->ti_sci_id); + if (ret) { + dev_err(cdev, "missing 'ti,sci-dev-id' property\n"); + goto out; + } + + kproc->reset = devm_reset_control_get_exclusive(cdev, NULL); + if (IS_ERR_OR_NULL(kproc->reset)) { + ret = PTR_ERR_OR_ZERO(kproc->reset); + if (!ret) + ret = -ENODEV; + dev_err_probe(cdev, ret, "failed to get reset handle\n"); + goto out; + } + + kproc->tsp = ti_sci_proc_of_get_tsp(cdev, kproc->ti_sci); + if (IS_ERR(kproc->tsp)) { + ret = dev_err_probe(cdev, PTR_ERR(kproc->tsp), + "failed to construct ti-sci proc control\n"); + goto out; + } + + ret = k3_r5_core_of_get_internal_memories(to_platform_device(cdev), kproc); + if (ret) { + dev_err(cdev, "failed to get internal memories, ret = %d\n", + ret); + goto out; + } + + ret = ti_sci_proc_request(kproc->tsp); + if (ret < 0) { + dev_err(cdev, "ti_sci_proc_request failed, ret = %d\n", ret); + goto out; + } + + ret = devm_add_action_or_reset(cdev, k3_release_tsp, kproc->tsp); + if (ret) + goto out; + } + + list_for_each_entry(core, &cluster->cores, elem) { + cdev = core->dev; + kproc = core->kproc; + rproc = kproc->rproc; + + ret = k3_rproc_request_mbox(rproc); if (ret) return ret; @@ -1279,7 +1124,7 @@ static int k3_r5_cluster_rproc_init(struct platform_device *pdev) ret = k3_r5_rproc_configure(kproc); if (ret) { - dev_err(dev, "initial configure failed, ret = %d\n", + dev_err(cdev, "initial configure failed, ret = %d\n", ret); goto out; } @@ -1287,16 +1132,16 @@ static int k3_r5_cluster_rproc_init(struct platform_device *pdev) init_rmem: k3_r5_adjust_tcm_sizes(kproc); - ret = k3_r5_reserved_mem_init(kproc); + ret = k3_reserved_mem_init(kproc); if (ret) { - dev_err(dev, "reserved memory init failed, ret = %d\n", + dev_err(cdev, "reserved memory init failed, ret = %d\n", ret); goto out; } - ret = devm_rproc_add(dev, rproc); + ret = devm_rproc_add(cdev, rproc); if (ret) { - dev_err_probe(dev, ret, "rproc_add failed\n"); + dev_err_probe(cdev, ret, "rproc_add failed\n"); goto out; } @@ -1325,8 +1170,8 @@ out: /* undo core0 upon any failures on core1 in split-mode */ if (cluster->mode == CLUSTER_MODE_SPLIT && core == core1) { core = list_prev_entry(core, elem); - rproc = core->rproc; - kproc = rproc->priv; + kproc = core->kproc; + rproc = kproc->rproc; goto err_split; } return ret; @@ -1335,7 +1180,7 @@ out: static void k3_r5_cluster_rproc_exit(void *data) { struct k3_r5_cluster *cluster = platform_get_drvdata(data); - struct k3_r5_rproc *kproc; + struct k3_rproc *kproc; struct k3_r5_core *core; struct rproc *rproc; int ret; @@ -1351,8 +1196,8 @@ static void k3_r5_cluster_rproc_exit(void *data) list_last_entry(&cluster->cores, struct k3_r5_core, elem); list_for_each_entry_from_reverse(core, &cluster->cores, elem) { - rproc = core->rproc; - kproc = rproc->priv; + kproc = core->kproc; + rproc = kproc->rproc; if (rproc->state == RPROC_ATTACHED) { ret = rproc_detach(rproc); @@ -1361,138 +1206,7 @@ static void k3_r5_cluster_rproc_exit(void *data) return; } } - - mbox_free_channel(kproc->mbox); - } -} - -static int k3_r5_core_of_get_internal_memories(struct platform_device *pdev, - struct k3_r5_core *core) -{ - static const char * const mem_names[] = {"atcm", "btcm"}; - struct device *dev = &pdev->dev; - struct resource *res; - int num_mems; - int i; - - num_mems = ARRAY_SIZE(mem_names); - core->mem = devm_kcalloc(dev, num_mems, sizeof(*core->mem), GFP_KERNEL); - if (!core->mem) - return -ENOMEM; - - for (i = 0; i < num_mems; i++) { - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, - mem_names[i]); - if (!res) { - dev_err(dev, "found no memory resource for %s\n", - mem_names[i]); - return -EINVAL; - } - if (!devm_request_mem_region(dev, res->start, - resource_size(res), - dev_name(dev))) { - dev_err(dev, "could not request %s region for resource\n", - mem_names[i]); - return -EBUSY; - } - - /* - * TCMs are designed in general to support RAM-like backing - * memories. So, map these as Normal Non-Cached memories. This - * also avoids/fixes any potential alignment faults due to - * unaligned data accesses when using memcpy() or memset() - * functions (normally seen with device type memory). - */ - core->mem[i].cpu_addr = devm_ioremap_wc(dev, res->start, - resource_size(res)); - if (!core->mem[i].cpu_addr) { - dev_err(dev, "failed to map %s memory\n", mem_names[i]); - return -ENOMEM; - } - core->mem[i].bus_addr = res->start; - - /* - * TODO: - * The R5F cores can place ATCM & BTCM anywhere in its address - * based on the corresponding Region Registers in the System - * Control coprocessor. For now, place ATCM and BTCM at - * addresses 0 and 0x41010000 (same as the bus address on AM65x - * SoCs) based on loczrama setting - */ - if (!strcmp(mem_names[i], "atcm")) { - core->mem[i].dev_addr = core->loczrama ? - 0 : K3_R5_TCM_DEV_ADDR; - } else { - core->mem[i].dev_addr = core->loczrama ? - K3_R5_TCM_DEV_ADDR : 0; - } - core->mem[i].size = resource_size(res); - - dev_dbg(dev, "memory %5s: bus addr %pa size 0x%zx va %pK da 0x%x\n", - mem_names[i], &core->mem[i].bus_addr, - core->mem[i].size, core->mem[i].cpu_addr, - core->mem[i].dev_addr); - } - core->num_mems = num_mems; - - return 0; -} - -static int k3_r5_core_of_get_sram_memories(struct platform_device *pdev, - struct k3_r5_core *core) -{ - struct device_node *np = pdev->dev.of_node; - struct device *dev = &pdev->dev; - struct device_node *sram_np; - struct resource res; - int num_sram; - int i, ret; - - num_sram = of_property_count_elems_of_size(np, "sram", sizeof(phandle)); - if (num_sram <= 0) { - dev_dbg(dev, "device does not use reserved on-chip memories, num_sram = %d\n", - num_sram); - return 0; - } - - core->sram = devm_kcalloc(dev, num_sram, sizeof(*core->sram), GFP_KERNEL); - if (!core->sram) - return -ENOMEM; - - for (i = 0; i < num_sram; i++) { - sram_np = of_parse_phandle(np, "sram", i); - if (!sram_np) - return -EINVAL; - - if (!of_device_is_available(sram_np)) { - of_node_put(sram_np); - return -EINVAL; - } - - ret = of_address_to_resource(sram_np, 0, &res); - of_node_put(sram_np); - if (ret) - return -EINVAL; - - core->sram[i].bus_addr = res.start; - core->sram[i].dev_addr = res.start; - core->sram[i].size = resource_size(&res); - core->sram[i].cpu_addr = devm_ioremap_wc(dev, res.start, - resource_size(&res)); - if (!core->sram[i].cpu_addr) { - dev_err(dev, "failed to parse and map sram%d memory at %pad\n", - i, &res.start); - return -ENOMEM; - } - - dev_dbg(dev, "memory sram%d: bus addr %pa size 0x%zx va %pK da 0x%x\n", - i, &core->sram[i].bus_addr, - core->sram[i].size, core->sram[i].cpu_addr, - core->sram[i].dev_addr); } - core->num_sram = num_sram; - - return 0; } static int k3_r5_core_of_init(struct platform_device *pdev) @@ -1540,62 +1254,12 @@ static int k3_r5_core_of_init(struct platform_device *pdev) goto err; } - core->ti_sci = devm_ti_sci_get_by_phandle(dev, "ti,sci"); - if (IS_ERR(core->ti_sci)) { - ret = PTR_ERR(core->ti_sci); - if (ret != -EPROBE_DEFER) { - dev_err(dev, "failed to get ti-sci handle, ret = %d\n", - ret); - } - core->ti_sci = NULL; - goto err; - } - - ret = of_property_read_u32(np, "ti,sci-dev-id", &core->ti_sci_id); - if (ret) { - dev_err(dev, "missing 'ti,sci-dev-id' property\n"); - goto err; - } - - core->reset = devm_reset_control_get_exclusive(dev, NULL); - if (IS_ERR_OR_NULL(core->reset)) { - ret = PTR_ERR_OR_ZERO(core->reset); - if (!ret) - ret = -ENODEV; - if (ret != -EPROBE_DEFER) { - dev_err(dev, "failed to get reset handle, ret = %d\n", - ret); - } - goto err; - } - - core->tsp = ti_sci_proc_of_get_tsp(dev, core->ti_sci); - if (IS_ERR(core->tsp)) { - ret = PTR_ERR(core->tsp); - dev_err(dev, "failed to construct ti-sci proc control, ret = %d\n", - ret); - goto err; - } - - ret = k3_r5_core_of_get_internal_memories(pdev, core); - if (ret) { - dev_err(dev, "failed to get internal memories, ret = %d\n", - ret); - goto err; - } - ret = k3_r5_core_of_get_sram_memories(pdev, core); if (ret) { dev_err(dev, "failed to get sram memories, ret = %d\n", ret); goto err; } - ret = ti_sci_proc_request(core->tsp); - if (ret < 0) { - dev_err(dev, "ti_sci_proc_request failed, ret = %d\n", ret); - goto err; - } - platform_set_drvdata(pdev, core); devres_close_group(dev, k3_r5_core_of_init); @@ -1612,13 +1276,7 @@ err: */ static void k3_r5_core_of_exit(struct platform_device *pdev) { - struct k3_r5_core *core = platform_get_drvdata(pdev); struct device *dev = &pdev->dev; - int ret; - - ret = ti_sci_proc_release(core->tsp); - if (ret) - dev_err(dev, "failed to release proc, ret = %d\n", ret); platform_set_drvdata(pdev, NULL); devres_release_group(dev, k3_r5_core_of_init); @@ -1643,16 +1301,14 @@ static int k3_r5_cluster_of_init(struct platform_device *pdev) struct device *dev = &pdev->dev; struct device_node *np = dev_of_node(dev); struct platform_device *cpdev; - struct device_node *child; struct k3_r5_core *core; int ret; - for_each_available_child_of_node(np, child) { + for_each_available_child_of_node_scoped(np, child) { cpdev = of_find_device_by_node(child); if (!cpdev) { ret = -ENODEV; dev_err(dev, "could not get R5 core platform device\n"); - of_node_put(child); goto fail; } @@ -1661,11 +1317,11 @@ static int k3_r5_cluster_of_init(struct platform_device *pdev) dev_err(dev, "k3_r5_core_of_init failed, ret = %d\n", ret); put_device(&cpdev->dev); - of_node_put(child); goto fail; } core = platform_get_drvdata(cpdev); + core->cluster = cluster; put_device(&cpdev->dev); list_add_tail(&core->elem, &cluster->cores); } @@ -1702,11 +1358,8 @@ static int k3_r5_probe(struct platform_device *pdev) init_waitqueue_head(&cluster->core_transition); ret = of_property_read_u32(np, "ti,cluster-mode", &cluster->mode); - if (ret < 0 && ret != -EINVAL) { - dev_err(dev, "invalid format for ti,cluster-mode, ret = %d\n", - ret); - return ret; - } + if (ret < 0 && ret != -EINVAL) + return dev_err_probe(dev, ret, "invalid format for ti,cluster-mode\n"); if (ret == -EINVAL) { /* @@ -1725,49 +1378,39 @@ static int k3_r5_probe(struct platform_device *pdev) } if ((cluster->mode == CLUSTER_MODE_SINGLECPU && !data->single_cpu_mode) || - (cluster->mode == CLUSTER_MODE_SINGLECORE && !data->is_single_core)) { - dev_err(dev, "Cluster mode = %d is not supported on this SoC\n", cluster->mode); - return -EINVAL; - } + (cluster->mode == CLUSTER_MODE_SINGLECORE && !data->is_single_core)) + return dev_err_probe(dev, -EINVAL, + "Cluster mode = %d is not supported on this SoC\n", + cluster->mode); num_cores = of_get_available_child_count(np); - if (num_cores != 2 && !data->is_single_core) { - dev_err(dev, "MCU cluster requires both R5F cores to be enabled but num_cores is set to = %d\n", - num_cores); - return -ENODEV; - } + if (num_cores != 2 && !data->is_single_core) + return dev_err_probe(dev, -ENODEV, + "MCU cluster requires both R5F cores to be enabled but num_cores is set to = %d\n", + num_cores); - if (num_cores != 1 && data->is_single_core) { - dev_err(dev, "SoC supports only single core R5 but num_cores is set to %d\n", - num_cores); - return -ENODEV; - } + if (num_cores != 1 && data->is_single_core) + return dev_err_probe(dev, -ENODEV, + "SoC supports only single core R5 but num_cores is set to %d\n", + num_cores); platform_set_drvdata(pdev, cluster); ret = devm_of_platform_populate(dev); - if (ret) { - dev_err(dev, "devm_of_platform_populate failed, ret = %d\n", - ret); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "devm_of_platform_populate failed\n"); ret = k3_r5_cluster_of_init(pdev); - if (ret) { - dev_err(dev, "k3_r5_cluster_of_init failed, ret = %d\n", ret); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "k3_r5_cluster_of_init failed\n"); ret = devm_add_action_or_reset(dev, k3_r5_cluster_of_exit, pdev); if (ret) return ret; ret = k3_r5_cluster_rproc_init(pdev); - if (ret) { - dev_err(dev, "k3_r5_cluster_rproc_init failed, ret = %d\n", - ret); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "k3_r5_cluster_rproc_init failed\n"); ret = devm_add_action_or_reset(dev, k3_r5_cluster_rproc_exit, pdev); if (ret) @@ -1776,11 +1419,24 @@ static int k3_r5_probe(struct platform_device *pdev) return 0; } +static const struct k3_rproc_mem_data r5_mems[] = { + { .name = "atcm", .dev_addr = 0x0 }, + { .name = "btcm", .dev_addr = K3_R5_TCM_DEV_ADDR }, +}; + +static const struct k3_rproc_dev_data r5_data = { + .mems = r5_mems, + .num_mems = ARRAY_SIZE(r5_mems), + .boot_align_addr = 0, + .uses_lreset = true, +}; + static const struct k3_r5_soc_data am65_j721e_soc_data = { .tcm_is_double = false, .tcm_ecc_autoinit = false, .single_cpu_mode = false, .is_single_core = false, + .core_data = &r5_data, }; static const struct k3_r5_soc_data j7200_j721s2_soc_data = { @@ -1788,6 +1444,7 @@ static const struct k3_r5_soc_data j7200_j721s2_soc_data = { .tcm_ecc_autoinit = true, .single_cpu_mode = false, .is_single_core = false, + .core_data = &r5_data, }; static const struct k3_r5_soc_data am64_soc_data = { @@ -1795,6 +1452,7 @@ static const struct k3_r5_soc_data am64_soc_data = { .tcm_ecc_autoinit = true, .single_cpu_mode = true, .is_single_core = false, + .core_data = &r5_data, }; static const struct k3_r5_soc_data am62_soc_data = { @@ -1802,6 +1460,7 @@ static const struct k3_r5_soc_data am62_soc_data = { .tcm_ecc_autoinit = true, .single_cpu_mode = false, .is_single_core = true, + .core_data = &r5_data, }; static const struct of_device_id k3_r5_of_match[] = { diff --git a/drivers/remoteproc/wkup_m3_rproc.c b/drivers/remoteproc/wkup_m3_rproc.c index c39bd2bf2c1e..2d5bfbefcacc 100644 --- a/drivers/remoteproc/wkup_m3_rproc.c +++ b/drivers/remoteproc/wkup_m3_rproc.c @@ -125,6 +125,13 @@ static const struct of_device_id wkup_m3_rproc_of_match[] = { }; MODULE_DEVICE_TABLE(of, wkup_m3_rproc_of_match); +static void wkup_m3_rproc_pm_runtime_put(void *data) +{ + struct device *dev = data; + + pm_runtime_put_sync(dev); +} + static int wkup_m3_rproc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -152,17 +159,16 @@ static int wkup_m3_rproc_probe(struct platform_device *pdev) if (ret < 0) return dev_err_probe(dev, ret, "Failed to enable runtime PM\n"); ret = pm_runtime_get_sync(&pdev->dev); - if (ret < 0) { - dev_err(&pdev->dev, "pm_runtime_get_sync() failed\n"); - goto err; - } + if (ret < 0) + return dev_err_probe(dev, ret, "pm_runtime_get_sync() failed\n"); + ret = devm_add_action_or_reset(dev, wkup_m3_rproc_pm_runtime_put, dev); + if (ret) + return dev_err_probe(dev, ret, "failed to add disable pm devm action\n"); - rproc = rproc_alloc(dev, "wkup_m3", &wkup_m3_rproc_ops, - fw_name, sizeof(*wkupm3)); - if (!rproc) { - ret = -ENOMEM; - goto err; - } + rproc = devm_rproc_alloc(dev, "wkup_m3", &wkup_m3_rproc_ops, + fw_name, sizeof(*wkupm3)); + if (!rproc) + return -ENOMEM; rproc->auto_boot = false; rproc->sysfs_read_only = true; @@ -177,9 +183,7 @@ static int wkup_m3_rproc_probe(struct platform_device *pdev) if (!wkupm3->rsts) { if (!(pdata && pdata->deassert_reset && pdata->assert_reset && pdata->reset_name)) { - dev_err(dev, "Platform data missing!\n"); - ret = -ENODEV; - goto err_put_rproc; + return dev_err_probe(dev, -ENODEV, "Platform data missing!\n"); } } @@ -187,12 +191,9 @@ static int wkup_m3_rproc_probe(struct platform_device *pdev) res = platform_get_resource_byname(pdev, IORESOURCE_MEM, mem_names[i]); wkupm3->mem[i].cpu_addr = devm_ioremap_resource(dev, res); - if (IS_ERR(wkupm3->mem[i].cpu_addr)) { - dev_err(&pdev->dev, "devm_ioremap_resource failed for resource %d\n", - i); - ret = PTR_ERR(wkupm3->mem[i].cpu_addr); - goto err_put_rproc; - } + if (IS_ERR(wkupm3->mem[i].cpu_addr)) + return dev_err_probe(dev, PTR_ERR(wkupm3->mem[i].cpu_addr), + "devm_ioremap_resource failed for resource %d\n", i); wkupm3->mem[i].bus_addr = res->start; wkupm3->mem[i].size = resource_size(res); addrp = of_get_address(dev->of_node, i, &size, NULL); @@ -209,28 +210,11 @@ static int wkup_m3_rproc_probe(struct platform_device *pdev) dev_set_drvdata(dev, rproc); - ret = rproc_add(rproc); - if (ret) { - dev_err(dev, "rproc_add failed\n"); - goto err_put_rproc; - } + ret = devm_rproc_add(dev, rproc); + if (ret) + return dev_err_probe(dev, ret, "rproc_add failed\n"); return 0; - -err_put_rproc: - rproc_free(rproc); -err: - pm_runtime_put_noidle(dev); - return ret; -} - -static void wkup_m3_rproc_remove(struct platform_device *pdev) -{ - struct rproc *rproc = platform_get_drvdata(pdev); - - rproc_del(rproc); - rproc_free(rproc); - pm_runtime_put_sync(&pdev->dev); } #ifdef CONFIG_PM @@ -251,7 +235,6 @@ static const struct dev_pm_ops wkup_m3_rproc_pm_ops = { static struct platform_driver wkup_m3_rproc_driver = { .probe = wkup_m3_rproc_probe, - .remove_new = wkup_m3_rproc_remove, .driver = { .name = "wkup_m3_rproc", .of_match_table = wkup_m3_rproc_of_match, diff --git a/drivers/remoteproc/xlnx_r5_remoteproc.c b/drivers/remoteproc/xlnx_r5_remoteproc.c index c165422d0651..0b7b173d0d26 100644 --- a/drivers/remoteproc/xlnx_r5_remoteproc.c +++ b/drivers/remoteproc/xlnx_r5_remoteproc.c @@ -68,7 +68,7 @@ struct zynqmp_sram_bank { }; /** - * struct mbox_info + * struct mbox_info - mailbox channel data * * @rx_mc_buf: to copy data from mailbox rx channel * @tx_mc_buf: to copy data to mailbox tx channel @@ -89,7 +89,7 @@ struct mbox_info { }; /** - * struct rsc_tbl_data + * struct rsc_tbl_data - resource table metadata * * Platform specific data structure used to sync resource table address. * It's important to maintain order and size of each field on remote side. @@ -128,7 +128,7 @@ static const struct mem_bank_data zynqmp_tcm_banks_lockstep[] = { }; /** - * struct zynqmp_r5_core + * struct zynqmp_r5_core - remoteproc core's internal data * * @rsc_tbl_va: resource table virtual address * @sram: Array of sram memories assigned to this core @@ -157,7 +157,7 @@ struct zynqmp_r5_core { }; /** - * struct zynqmp_r5_cluster + * struct zynqmp_r5_cluster - remoteproc cluster's internal data * * @dev: r5f subsystem cluster device node * @mode: cluster mode of type zynqmp_r5_cluster_mode @@ -380,6 +380,18 @@ static int zynqmp_r5_rproc_start(struct rproc *rproc) dev_dbg(r5_core->dev, "RPU boot addr 0x%llx from %s.", rproc->bootaddr, bootmem == PM_RPU_BOOTMEM_HIVEC ? "OCM" : "TCM"); + /* Request node before starting RPU core if new version of API is supported */ + if (zynqmp_pm_feature(PM_REQUEST_NODE) > 1) { + ret = zynqmp_pm_request_node(r5_core->pm_domain_id, + ZYNQMP_PM_CAPABILITY_ACCESS, 0, + ZYNQMP_PM_REQUEST_ACK_BLOCKING); + if (ret < 0) { + dev_err(r5_core->dev, "failed to request 0x%x", + r5_core->pm_domain_id); + return ret; + } + } + ret = zynqmp_pm_request_wake(r5_core->pm_domain_id, 1, bootmem, ZYNQMP_PM_REQUEST_ACK_NO); if (ret) @@ -401,10 +413,30 @@ static int zynqmp_r5_rproc_stop(struct rproc *rproc) struct zynqmp_r5_core *r5_core = rproc->priv; int ret; + /* Use release node API to stop core if new version of API is supported */ + if (zynqmp_pm_feature(PM_RELEASE_NODE) > 1) { + ret = zynqmp_pm_release_node(r5_core->pm_domain_id); + if (ret) + dev_err(r5_core->dev, "failed to stop remoteproc RPU %d\n", ret); + return ret; + } + + /* + * Check expected version of EEMI call before calling it. This avoids + * any error or warning prints from firmware as it is expected that fw + * doesn't support it. + */ + if (zynqmp_pm_feature(PM_FORCE_POWERDOWN) != 1) { + dev_dbg(r5_core->dev, "EEMI interface %d ver 1 not supported\n", + PM_FORCE_POWERDOWN); + return -EOPNOTSUPP; + } + + /* maintain force pwr down for backward compatibility */ ret = zynqmp_pm_force_pwrdwn(r5_core->pm_domain_id, ZYNQMP_PM_REQUEST_ACK_BLOCKING); if (ret) - dev_err(r5_core->dev, "failed to stop remoteproc RPU %d\n", ret); + dev_err(r5_core->dev, "core force power down failed\n"); return ret; } @@ -700,7 +732,7 @@ static int zynqmp_r5_parse_fw(struct rproc *rproc, const struct firmware *fw) } /** - * zynqmp_r5_rproc_prepare() + * zynqmp_r5_rproc_prepare() - prepare core to boot/attach * adds carveouts for TCM bank and reserved memory regions * * @rproc: Device node of each rproc @@ -733,7 +765,7 @@ static int zynqmp_r5_rproc_prepare(struct rproc *rproc) } /** - * zynqmp_r5_rproc_unprepare() + * zynqmp_r5_rproc_unprepare() - programming sequence after stop/detach. * Turns off TCM banks using power-domain id * * @rproc: Device node of each rproc @@ -876,7 +908,7 @@ static const struct rproc_ops zynqmp_r5_rproc_ops = { }; /** - * zynqmp_r5_add_rproc_core() + * zynqmp_r5_add_rproc_core() - Add core data to framework. * Allocate and add struct rproc object for each r5f core * This is called for each individual r5f core * @@ -1112,7 +1144,7 @@ static int zynqmp_r5_get_tcm_node_from_dt(struct zynqmp_r5_cluster *cluster) } /** - * zynqmp_r5_get_tcm_node() + * zynqmp_r5_get_tcm_node() - Get TCM info * Ideally this function should parse tcm node and store information * in r5_core instance. For now, Hardcoded TCM information is used. * This approach is used as TCM bindings for system-dt is being developed @@ -1299,19 +1331,23 @@ static int zynqmp_r5_cluster_init(struct zynqmp_r5_cluster *cluster) /* * Number of cores is decided by number of child nodes of - * r5f subsystem node in dts. If Split mode is used in dts - * 2 child nodes are expected. + * r5f subsystem node in dts. + * In split mode maximum two child nodes are expected. + * However, only single core can be enabled too. + * Driver can handle following configuration in split mode: + * 1) core0 enabled, core1 disabled + * 2) core0 disabled, core1 enabled + * 3) core0 and core1 both are enabled. + * For now, no more than two cores are expected per cluster + * in split mode. * In lockstep mode if two child nodes are available, * only use first child node and consider it as core0 * and ignore core1 dt node. */ core_count = of_get_available_child_count(dev_node); - if (core_count == 0) { + if (core_count == 0 || core_count > 2) { dev_err(dev, "Invalid number of r5 cores %d", core_count); return -EINVAL; - } else if (cluster_mode == SPLIT_MODE && core_count != 2) { - dev_err(dev, "Invalid number of r5 cores for split mode\n"); - return -EINVAL; } else if (cluster_mode == LOCKSTEP_MODE && core_count == 2) { dev_warn(dev, "Only r5 core0 will be used\n"); core_count = 1; @@ -1434,6 +1470,45 @@ static void zynqmp_r5_cluster_exit(void *data) } /* + * zynqmp_r5_remoteproc_shutdown() + * Follow shutdown sequence in case of kexec call. + * + * @pdev: domain platform device for cluster + * + * Return: None. + */ +static void zynqmp_r5_remoteproc_shutdown(struct platform_device *pdev) +{ + const char *rproc_state_str = NULL; + struct zynqmp_r5_cluster *cluster; + struct zynqmp_r5_core *r5_core; + struct rproc *rproc; + int i, ret = 0; + + cluster = platform_get_drvdata(pdev); + + for (i = 0; i < cluster->core_count; i++) { + r5_core = cluster->r5_cores[i]; + rproc = r5_core->rproc; + + if (rproc->state == RPROC_RUNNING) { + ret = rproc_shutdown(rproc); + rproc_state_str = "shutdown"; + } else if (rproc->state == RPROC_ATTACHED) { + ret = rproc_detach(rproc); + rproc_state_str = "detach"; + } else { + ret = 0; + } + + if (ret) { + dev_err(cluster->dev, "failed to %s rproc %d\n", + rproc_state_str, rproc->index); + } + } +} + +/* * zynqmp_r5_remoteproc_probe() * parse device-tree, initialize hardware and allocate required resources * and remoteproc ops @@ -1494,6 +1569,7 @@ static struct platform_driver zynqmp_r5_remoteproc_driver = { .name = "zynqmp_r5_remoteproc", .of_match_table = zynqmp_r5_remoteproc_match, }, + .shutdown = zynqmp_r5_remoteproc_shutdown, }; module_platform_driver(zynqmp_r5_remoteproc_driver); |
